mirror of https://gitee.com/cf-fz/WebCAD.git
commit
e89c81b590
@ -0,0 +1,45 @@
|
|||||||
|
|
||||||
|
|
||||||
|
webCAD需要将数据存储在云端,并且本地需要要备份的数据以便快速的检索到数据.
|
||||||
|
|
||||||
|
目前暂时需要存储的数据:
|
||||||
|
|
||||||
|
1.纹理(纹理的本质是<图片>)
|
||||||
|
每个用户都可以保存他自己的纹理,用户可以上传新的纹理,我打算将图片存入公共的池中,并且使用md5防止文件重复.
|
||||||
|
需要注意的是,如果用户删除了自身的图片,那么如果该图片没有人在使用,那么应该尝试将其删除.(与云盘工作原理类似.)
|
||||||
|
|
||||||
|
每个用户自身保存的纹理只包含 纹理信息和纹理的文件哈希,如果需要,可以从服务器上检索出图片
|
||||||
|
用户可以存入自己的纹理列表,以供各个图纸导入.
|
||||||
|
|
||||||
|
这里假设文件的校验码为`FileMd5`
|
||||||
|
Texture:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
fileMd5:"xxxxxxxx"
|
||||||
|
....//其他数据
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2.材质.
|
||||||
|
由于最大的数据(图片二进制)已经在纹理中被处理,所有材质列表并不需要保存优化.
|
||||||
|
材质同纹理一样,用户可以存入自己的材质列表,以供各个图纸导入.
|
||||||
|
|
||||||
|
3.外部二进制模型(FBX 等)
|
||||||
|
同网盘工作模式,使用md5检测碰撞,防止文件重复.
|
||||||
|
|
||||||
|
每个图纸文件中,并不会真实的存入fbx的模型信息,而是存入文件校验码,如果需要时,从服务器读取.
|
||||||
|
|
||||||
|
4.模版数据
|
||||||
|
模版数据可以认为是一段数据.可以是json序列化的格式. 数据类型可变,参数个数可变.
|
||||||
|
|
||||||
|
5.图纸数据
|
||||||
|
同模版数据
|
||||||
|
|
||||||
|
6.文件备份.
|
||||||
|
用户在使用应用时,程序会自动尝试备份图纸,并且如有网络资源可以上传到服务器.
|
||||||
|
|
||||||
|
7.配置信息.
|
||||||
|
用户设置的应用配置也应该上传到服务器,保持同步更新.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
|||||||
test("", () =>
|
|
||||||
{
|
|
||||||
|
|
||||||
})
|
|
||||||
// window["t"] = () =>
|
|
||||||
// {
|
|
||||||
|
|
||||||
|
|
||||||
// app.m_Database.StartTransaction();
|
|
||||||
|
|
||||||
// let line = new Line(new THREE.Vector3(Math.random() * 100, Math.random() * 100), new THREE.Vector3(Math.random() * 100, Math.random() * 100))
|
|
||||||
|
|
||||||
// app.m_Database.appendEntity(line);
|
|
||||||
|
|
||||||
// app.m_Database.CommitTransaction();
|
|
||||||
// }
|
|
@ -1,33 +0,0 @@
|
|||||||
import * as mst from 'mobx-state-tree';
|
|
||||||
|
|
||||||
import { EntityData } from '../../src/DatabaseServices/EntityData';
|
|
||||||
|
|
||||||
test("Entity", () =>
|
|
||||||
{
|
|
||||||
let d = EntityData.create({ size: [0, 1, 2] })
|
|
||||||
|
|
||||||
console.log(mst.getSnapshot(d));
|
|
||||||
|
|
||||||
console.log(d.getSize());
|
|
||||||
d.setSize(1, 1, 1000);
|
|
||||||
console.log(d.getSize());
|
|
||||||
|
|
||||||
expect(d.getSize().x).toBe(1);
|
|
||||||
})
|
|
||||||
|
|
||||||
test("not late", () =>
|
|
||||||
{
|
|
||||||
let d = EntityData.create({ size: [0, 1, 2] })
|
|
||||||
|
|
||||||
console.log(mst.getSnapshot(d));
|
|
||||||
|
|
||||||
console.log(d.getSize());
|
|
||||||
d.setSize(1, 1, 1000);
|
|
||||||
console.log(d.getSize());
|
|
||||||
|
|
||||||
expect(d.getSize().x).toBe(1);
|
|
||||||
expect(d.getSize().y).toBe(1);
|
|
||||||
expect(d.getSize().z).toBe(1000);
|
|
||||||
|
|
||||||
console.log(typeof d.getSize());
|
|
||||||
})
|
|
@ -1,98 +0,0 @@
|
|||||||
import * as console from 'console';
|
|
||||||
import { autorun } from 'mobx';
|
|
||||||
import * as mst from 'mobx-state-tree';
|
|
||||||
|
|
||||||
import { EntityData, IEntityData, LineData } from '../src/DatabaseServices/EntityData';
|
|
||||||
|
|
||||||
class E
|
|
||||||
{
|
|
||||||
m_Data: IEntityData;
|
|
||||||
constructor()
|
|
||||||
{
|
|
||||||
this.initData();
|
|
||||||
|
|
||||||
autorun(() =>
|
|
||||||
{
|
|
||||||
this.eraseT(this.m_Data.isErase);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
initData()
|
|
||||||
{
|
|
||||||
this.m_Data = EntityData.create();
|
|
||||||
console.log("hello e");
|
|
||||||
}
|
|
||||||
erase(isErase: boolean)
|
|
||||||
{
|
|
||||||
this.m_Data.setErase(isErase);
|
|
||||||
}
|
|
||||||
private eraseT(isErase: boolean)
|
|
||||||
{
|
|
||||||
console.log(isErase);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class L extends E
|
|
||||||
{
|
|
||||||
constructor()
|
|
||||||
{
|
|
||||||
super()
|
|
||||||
}
|
|
||||||
initData()
|
|
||||||
{
|
|
||||||
this.m_Data = LineData.create();
|
|
||||||
console.log("hello l");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
let l = new L()
|
|
||||||
|
|
||||||
|
|
||||||
let a: (typeof EntityData.SnapshotType) = mst.getSnapshot(l.m_Data);
|
|
||||||
console.log(mst.getSnapshot(l.m_Data));
|
|
||||||
|
|
||||||
let snp = mst.getSnapshot(l.m_Data);
|
|
||||||
|
|
||||||
l.erase(true);
|
|
||||||
l.erase(true);
|
|
||||||
l.erase(true);
|
|
||||||
l.erase(true);
|
|
||||||
l.erase(true);
|
|
||||||
|
|
||||||
console.log(l.m_Data.isErase);
|
|
||||||
|
|
||||||
mst.applySnapshot(l.m_Data, snp);
|
|
||||||
|
|
||||||
console.log(l.m_Data.isErase);
|
|
||||||
}
|
|
||||||
|
|
||||||
function add(a, b)
|
|
||||||
{
|
|
||||||
return a + b;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Remove Path
|
|
||||||
{
|
|
||||||
|
|
||||||
const L = mst.types.model(
|
|
||||||
"Test",
|
|
||||||
{
|
|
||||||
lst: mst.types.array(mst.types.number)
|
|
||||||
})
|
|
||||||
.actions(self =>
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
remove(a)
|
|
||||||
{
|
|
||||||
this.lst.remove(a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
let l = L.create({ lst: [1, 2, 3] })
|
|
||||||
mst.onPatch(l, (p, rp) =>
|
|
||||||
{
|
|
||||||
console.log(p);
|
|
||||||
})
|
|
||||||
l.remove(3);
|
|
||||||
}
|
|
@ -0,0 +1,23 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`changev 1`] = `"[1,2,[\\"BlockTableRecord\\",1,0,1,[\\"Line\\",1,1,2,7,1,[2,3,4],[0,0,0]]],[\\"MaerialTableRecord\\",1,1,0],1,0,1,[\\"CommandHistoryRecord\\",1,\\"\\",2,0,1,[\\"HistorycRecord\\",1,[\\"RemoveObjectData\\",1,0],[\\"CreateObjectData\\",1,[[\\"Line\\",1,1,2,7,1,[0,0,0],[0,0,0]]]],\\"\\"],2,1,[\\"ObjectAllDataHistoryRecord\\",1,1,[\\"AllObjectData\\",1,-1,1,[1,1,2,7,1,[0,0,0],[0,0,0]]],\\"\\",\\"\\",2]]]"`;
|
||||||
|
|
||||||
|
exports[`创建 修改 撤销撤销 重做重做 撤销 重做 1`] = `"[1,2,[\\"BlockTableRecord\\",1,0,1,[\\"Line\\",1,1,2,7,1,[1,2,3],[0,0,0]]],[\\"MaerialTableRecord\\",1,1,0],1,1,2,[\\"CommandHistoryRecord\\",1,\\"\\",1,0,1,[\\"HistorycRecord\\",1,[\\"RemoveObjectData\\",1,0],[\\"CreateObjectData\\",1,[[\\"Line\\",1,1,2,7,1,[0,0,0],[0,0,0]]]],\\"\\"]],[\\"CommandHistoryRecord\\",1,\\"U\\",1,2,1,[\\"ObjectAllDataHistoryRecord\\",1,1,[\\"AllObjectData\\",1,-1,1,[1,1,2,7,1,[0,0,0],[0,0,0]]],[\\"AllObjectData\\",1,-1,1,[1,1,2,7,1,[1,2,3],[0,0,0]]],\\"\\",2]]]"`;
|
||||||
|
|
||||||
|
exports[`创建 修改 撤销撤销 重做重做 撤销 重做 2`] = `"[[\\"HistoricManage\\",1,1,2,[\\"CommandHistoryRecord\\",1,\\"\\",1,0,1,[\\"HistorycRecord\\",1,[\\"RemoveObjectData\\",1,0],[\\"CreateObjectData\\",1,[[\\"Line\\",1,1,2,7,1,[0,0,0],[0,0,0]]]],\\"\\"]],[\\"CommandHistoryRecord\\",1,\\"U\\",1,2,1,[\\"ObjectAllDataHistoryRecord\\",1,1,[\\"AllObjectData\\",1,-1,1,[1,1,2,7,1,[0,0,0],[0,0,0]]],[\\"AllObjectData\\",1,-1,1,[1,1,2,7,1,[1,2,3],[0,0,0]]],\\"\\",2]]]]"`;
|
||||||
|
|
||||||
|
exports[`测试创建 1`] = `"[[\\"AllObjectData\\",1,-1,1,[]]]"`;
|
||||||
|
|
||||||
|
exports[`测试创建 2`] = `"[[\\"BlockTableRecord\\",1,-1,0]]"`;
|
||||||
|
|
||||||
|
exports[`测试创建 3`] = `"[[\\"CommandHistoryRecord\\",1,null,0]]"`;
|
||||||
|
|
||||||
|
exports[`测试创建 4`] = `"[[\\"CreateObjectData\\",1,[]]]"`;
|
||||||
|
|
||||||
|
exports[`测试创建 5`] = `"[[\\"HistorycRecord\\",1,\\"\\",\\"\\",\\"\\"]]"`;
|
||||||
|
|
||||||
|
exports[`测试创建 6`] = `"[[\\"Line\\",1,1,-1,7,1,[0,0,0],[0,0,0]]]"`;
|
||||||
|
|
||||||
|
exports[`测试创建 7`] = `"[[\\"ObjectAllDataHistoryRecord\\",1,1,\\"\\",\\"\\",\\"\\",-1]]"`;
|
||||||
|
|
||||||
|
exports[`测试创建 8`] = `"[[\\"RemoveObjectData\\",1,null]]"`;
|
@ -0,0 +1,187 @@
|
|||||||
|
import * as THREE from 'three';
|
||||||
|
|
||||||
|
import { BlockTableRecord } from '../../src/DatabaseServices/BlockTableRecord';
|
||||||
|
import { CADFactory } from '../../src/DatabaseServices/CADFactory';
|
||||||
|
import { CADFile } from '../../src/DatabaseServices/CADFile';
|
||||||
|
import { CommandHistoryRecord } from '../../src/DatabaseServices/CommandHistoryRecord';
|
||||||
|
import { CreateObjectData } from '../../src/DatabaseServices/CreateObjectData';
|
||||||
|
import { Database } from '../../src/DatabaseServices/Database';
|
||||||
|
import { HistorycRecord } from '../../src/DatabaseServices/HistorycRecord';
|
||||||
|
import { Line } from '../../src/DatabaseServices/Line';
|
||||||
|
import { ObjectAllDataHistoryRecord } from '../../src/DatabaseServices/ObjectAllDataHistoryRecord';
|
||||||
|
import { RemoveObjectData } from '../../src/DatabaseServices/RemoveObjectData';
|
||||||
|
import { CADObject, AllObjectData } from '../../src/DatabaseServices/CADObject';
|
||||||
|
|
||||||
|
function CadObjectToString(obj: CADObject)
|
||||||
|
{
|
||||||
|
let file = new CADFile();
|
||||||
|
file.WriteObject(obj)
|
||||||
|
return file.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
test('测试创建', () =>
|
||||||
|
{
|
||||||
|
for (let C of [AllObjectData,
|
||||||
|
BlockTableRecord,
|
||||||
|
CommandHistoryRecord,
|
||||||
|
CreateObjectData,
|
||||||
|
HistorycRecord,
|
||||||
|
Line,
|
||||||
|
ObjectAllDataHistoryRecord,
|
||||||
|
RemoveObjectData,
|
||||||
|
])
|
||||||
|
{
|
||||||
|
console.log(C);
|
||||||
|
//确保每个对象都被正确的创建
|
||||||
|
let obj = CADFactory.CreateObject(C.name /*?*/);
|
||||||
|
let str = CadObjectToString(obj);
|
||||||
|
console.log(obj.constructor.name);
|
||||||
|
expect(str).toMatchSnapshot();
|
||||||
|
|
||||||
|
//确保对象正确的反序列化
|
||||||
|
let fileNew = new CADFile();
|
||||||
|
fileNew.Data = JSON.parse(str);
|
||||||
|
|
||||||
|
let objNew = CADFactory.CreateObject(C.name);
|
||||||
|
let str2 = CadObjectToString(objNew);
|
||||||
|
|
||||||
|
//确保反序列化之后的数据是正确的
|
||||||
|
expect(str).toBe(str2);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('id分配', () =>
|
||||||
|
{
|
||||||
|
let db = new Database();
|
||||||
|
let line = new Line();
|
||||||
|
|
||||||
|
//对象添加到模型空间 分配id
|
||||||
|
let id = db.ModelSpace.Append(line);
|
||||||
|
|
||||||
|
expect(id != undefined).toBeTruthy();//对象已经被创建,所以id被分配
|
||||||
|
expect(id.Object === line).toBeTruthy();//对象id指向对象
|
||||||
|
|
||||||
|
//撤销添加
|
||||||
|
db.hm.Undo();
|
||||||
|
|
||||||
|
expect(id.IsErase).toBeTruthy(); //对象已经被删除
|
||||||
|
expect(db.ModelSpace.Cout()).toBe(0); //个数应该为0
|
||||||
|
|
||||||
|
//还原对象
|
||||||
|
db.hm.Redo();
|
||||||
|
|
||||||
|
expect(db.ModelSpace.Cout()).toBe(1); //对象还原
|
||||||
|
expect(!id.IsErase).toBeTruthy(); //id指向的对象不被删除
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('clone object', () =>
|
||||||
|
{
|
||||||
|
let db = new Database();
|
||||||
|
let line = new Line();
|
||||||
|
db.ModelSpace.Append(line);
|
||||||
|
line.StartPoint = new THREE.Vector3(9, 9, 8);
|
||||||
|
|
||||||
|
CadObjectToString(line)/*?*/
|
||||||
|
|
||||||
|
let line2 = line.Clone();
|
||||||
|
|
||||||
|
CadObjectToString(line2) /*?*/
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
test('changev', () =>
|
||||||
|
{
|
||||||
|
let db = new Database();
|
||||||
|
let l1 = new Line();
|
||||||
|
|
||||||
|
let id = db.ModelSpace.Append(l1);
|
||||||
|
|
||||||
|
db.hm.Undo();
|
||||||
|
db.hm.Redo();
|
||||||
|
|
||||||
|
expect(id.Object !== l1).toBeTruthy(); //创建对象的撤销和重做后 id指向了新的实体
|
||||||
|
|
||||||
|
(id.Object as Line).StartPoint = new THREE.Vector3(2, 3, 4);
|
||||||
|
let file = db.FileWrite();
|
||||||
|
|
||||||
|
expect(file.ToString()/*?*/).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('xxx', () =>
|
||||||
|
{
|
||||||
|
let db = new Database();
|
||||||
|
db.hm.StartCmd("");
|
||||||
|
let l1 = new Line();
|
||||||
|
let l2 = new Line();
|
||||||
|
let id1 = db.ModelSpace.Append(l1);
|
||||||
|
let in2 = db.ModelSpace.Append(l2);
|
||||||
|
|
||||||
|
db.hm.Undo(); //?
|
||||||
|
db.hm.Redo(); //?
|
||||||
|
|
||||||
|
db.hm.StartCmd("");
|
||||||
|
db.ModelSpace.Remove(db.GetObjectId(1).Object);
|
||||||
|
db.hm.Undo(); //?
|
||||||
|
db.hm.Undo(); //?
|
||||||
|
|
||||||
|
db.hm.Redo(); //?
|
||||||
|
|
||||||
|
// db.hm.StartCmd("");
|
||||||
|
(id1.Object as Line).StartPoint = new THREE.Vector3(10, 4, 2);
|
||||||
|
(id1.Object as Line).EndPoint = new THREE.Vector3(2, 2, 2);
|
||||||
|
let file = db.FileWrite();
|
||||||
|
console.log(file.ToString());
|
||||||
|
|
||||||
|
db.hm.StartCmd("");
|
||||||
|
|
||||||
|
(id1.Object as Line).StartPoint = new THREE.Vector3(100, 300, 400);
|
||||||
|
(id1.Object as Line).EndPoint = new THREE.Vector3(2000, 3000, 4000);
|
||||||
|
|
||||||
|
|
||||||
|
db.hm.Undo();
|
||||||
|
|
||||||
|
db.hm.Redo();
|
||||||
|
|
||||||
|
let f = new CADFile();
|
||||||
|
db.hm.WriteFile(f);
|
||||||
|
|
||||||
|
let db2 = new Database();
|
||||||
|
db2.hm.ReadFile(f);
|
||||||
|
|
||||||
|
let f3 = new CADFile();
|
||||||
|
db2.hm.WriteFile(f3);
|
||||||
|
|
||||||
|
expect(f3.ToString()).toBe(f.ToString());//对象序列化反序列化后 数据应该一样
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
test('创建 修改 撤销撤销 重做重做 撤销 重做', () =>
|
||||||
|
{
|
||||||
|
let db = new Database();
|
||||||
|
|
||||||
|
let line = new Line();
|
||||||
|
let id = db.ModelSpace.Append(line);
|
||||||
|
db.hm.StartCmd("U");
|
||||||
|
line.StartPoint = new THREE.Vector3(1, 2, 3);
|
||||||
|
db.hm.EndCmd();
|
||||||
|
|
||||||
|
db.hm.Undo(); /*?*/
|
||||||
|
db.hm.Undo();/*?*/
|
||||||
|
|
||||||
|
db.hm.Redo();/*?*/
|
||||||
|
db.hm.Redo();/*?*/
|
||||||
|
|
||||||
|
db.hm.Undo();/*?*/
|
||||||
|
|
||||||
|
db.hm.Redo();/*?*/
|
||||||
|
|
||||||
|
expect(db.FileWrite().ToString()).toMatchSnapshot();
|
||||||
|
|
||||||
|
expect(CadObjectToString(db.hm)).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
@ -1,15 +0,0 @@
|
|||||||
import { GeUtils } from '../../src/Geometry/GeUtils';
|
|
||||||
import * as THREE from "three";
|
|
||||||
import { Vector3 } from 'three';
|
|
||||||
test("测试平行", () =>
|
|
||||||
{
|
|
||||||
|
|
||||||
let v1 = new Vector3(0, 0, 1);
|
|
||||||
let v2 = new Vector3(0.0001, 0, 1);
|
|
||||||
expect(GeUtils.isParallelTo(v1, v2)).toBe(false);
|
|
||||||
expect(v1.equals(new THREE.Vector3(0, 0, 1))).toBe(true);
|
|
||||||
expect(v2.equals(new THREE.Vector3(0.0001, 0, 1))).toBe(true);
|
|
||||||
// console.log(v1.isParallelTo(v2));
|
|
||||||
// console.log(v1);
|
|
||||||
// console.log(v2);
|
|
||||||
})
|
|
@ -1,19 +0,0 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`相交测试 1`] = `
|
|
||||||
Vector3 {
|
|
||||||
"x": 0.5,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0,
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`相交测试 2`] = `undefined`;
|
|
||||||
|
|
||||||
exports[`相交测试 3`] = `
|
|
||||||
Vector3 {
|
|
||||||
"x": 0.5,
|
|
||||||
"y": 5,
|
|
||||||
"z": 0,
|
|
||||||
}
|
|
||||||
`;
|
|
@ -1,33 +0,0 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`测试求向量 1`] = `
|
|
||||||
Vector3 {
|
|
||||||
"x": 0,
|
|
||||||
"y": -1,
|
|
||||||
"z": 0,
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`测试求向量 2`] = `
|
|
||||||
Vector3 {
|
|
||||||
"x": 0,
|
|
||||||
"y": -1,
|
|
||||||
"z": 0,
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`测试求向量 3`] = `
|
|
||||||
Vector3 {
|
|
||||||
"x": 0,
|
|
||||||
"y": 1,
|
|
||||||
"z": 0,
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`测试求向量 4`] = `
|
|
||||||
Vector3 {
|
|
||||||
"x": 0.7071067811865475,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0.7071067811865475,
|
|
||||||
}
|
|
||||||
`;
|
|
@ -1,18 +0,0 @@
|
|||||||
import { GeUtils } from "../../src/Geometry/GeUtils";
|
|
||||||
|
|
||||||
test("GeUtils.angle", () =>
|
|
||||||
{
|
|
||||||
let pi2 = Math.PI * 0.5;
|
|
||||||
let pi4 = pi2 * 0.5;
|
|
||||||
|
|
||||||
console.log(GeUtils.fixAngle(0.05, pi2, 0.1)/*?*/ == 0);
|
|
||||||
|
|
||||||
console.log(GeUtils.fixAngle(0.08, pi2, 0.1)/*?*/ == 0);
|
|
||||||
console.log(GeUtils.fixAngle(0.09, pi2, 0.1)/*?*/ == 0);
|
|
||||||
console.log(GeUtils.fixAngle(-0.05, pi2, 0.1)/*?*/ == Math.PI * 2);
|
|
||||||
|
|
||||||
console.log(GeUtils.fixAngle(Math.PI / 2 + 0.01, pi2, 0.1)/*?*/ == Math.PI / 2);
|
|
||||||
|
|
||||||
console.log(GeUtils.fixAngle(0.3, pi2));
|
|
||||||
})
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
|||||||
import * as THREE from 'three';
|
|
||||||
|
|
||||||
import { Intersect } from '../../src/Geometry/GeUtils';
|
|
||||||
|
|
||||||
|
|
||||||
test('相交测试', () =>
|
|
||||||
{
|
|
||||||
let p1 = new THREE.Vector3(0, 0, 0);
|
|
||||||
let p2 = new THREE.Vector3(1, 0, 0);
|
|
||||||
let p3 = new THREE.Vector3(0.5, 0.5, 0);
|
|
||||||
let p4 = new THREE.Vector3(0.5, 1, 0);
|
|
||||||
|
|
||||||
let p5 = new THREE.Vector3(3, 0, 0);
|
|
||||||
let p6 = new THREE.Vector3(6, 0, 0);
|
|
||||||
|
|
||||||
let res = Intersect(p1, p2, p3, p4);/*?*/
|
|
||||||
|
|
||||||
expect(res).toMatchSnapshot();
|
|
||||||
|
|
||||||
res = Intersect(p1, p2, p5, p6);/*?*/
|
|
||||||
expect(res).toMatchSnapshot();
|
|
||||||
|
|
||||||
let ins = Intersect(
|
|
||||||
new THREE.Vector3(0, 5),
|
|
||||||
new THREE.Vector3(5, 5),
|
|
||||||
new THREE.Vector3(0.5, 1),
|
|
||||||
new THREE.Vector3(0.5, 8));
|
|
||||||
|
|
||||||
expect(ins).toMatchSnapshot();
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
@ -1,111 +0,0 @@
|
|||||||
import * as THREE from 'three';
|
|
||||||
|
|
||||||
import { GeUtils } from '../../src/Geometry/GeUtils';
|
|
||||||
import { Orbit } from '../../src/Geometry/Orbit';
|
|
||||||
|
|
||||||
test("", () =>
|
|
||||||
{
|
|
||||||
//构造一个控制类.
|
|
||||||
let orb = new Orbit();
|
|
||||||
|
|
||||||
let dir = new THREE.Vector3(0, 1, 0);
|
|
||||||
|
|
||||||
orb.UpdateRoValue(dir);
|
|
||||||
|
|
||||||
expect(GeUtils.equaln(orb.RoX, 0)).toBe(true);
|
|
||||||
expect(GeUtils.equaln(orb.RoZ, Math.PI * 0.5)).toBe(true);
|
|
||||||
|
|
||||||
//试着还原
|
|
||||||
orb.UpdateDirection(dir);
|
|
||||||
expect(GeUtils.equal(dir, new THREE.Vector3(0, 1, 0))).toBe(true);
|
|
||||||
|
|
||||||
//试试新的
|
|
||||||
dir.set(1, 0, 0);
|
|
||||||
orb.UpdateRoValue(dir);
|
|
||||||
expect(GeUtils.equaln(orb.RoX, 0)).toBe(true);
|
|
||||||
expect(GeUtils.equaln(orb.RoZ, 0)).toBe(true);
|
|
||||||
|
|
||||||
//试着还原
|
|
||||||
orb.UpdateDirection(dir);
|
|
||||||
expect(GeUtils.equal(dir, new THREE.Vector3(1, 0, 0))).toBe(true);
|
|
||||||
|
|
||||||
//试试新的
|
|
||||||
dir.set(0.5, 0.5, 0).normalize();
|
|
||||||
|
|
||||||
let dirc = dir.clone();
|
|
||||||
orb.UpdateRoValue(dir);
|
|
||||||
|
|
||||||
//试着还原
|
|
||||||
orb.UpdateDirection(dir);
|
|
||||||
console.log('dir: ', dir);
|
|
||||||
expect(GeUtils.equal(dir, dirc)).toBe(true);
|
|
||||||
|
|
||||||
//试试新的
|
|
||||||
dir.set(0.5, 0.5, 1).normalize();
|
|
||||||
dirc = dir.clone();
|
|
||||||
orb.UpdateRoValue(dir);
|
|
||||||
|
|
||||||
//试着还原
|
|
||||||
orb.UpdateDirection(dir);
|
|
||||||
console.log('dir: ', dir);
|
|
||||||
expect(GeUtils.equal(dir, dirc)).toBe(true);
|
|
||||||
|
|
||||||
dir.set(0, 0, -1);
|
|
||||||
dirc = dir.clone();
|
|
||||||
orb.UpdateRoValue(dir);
|
|
||||||
|
|
||||||
expect(GeUtils.equaln(orb.RoZ, Math.PI * 0.5)).toBe(true);
|
|
||||||
expect(GeUtils.equaln(orb.RoX, Math.PI * -0.5)).toBe(true);
|
|
||||||
|
|
||||||
//试着还原
|
|
||||||
orb.UpdateDirection(dir);
|
|
||||||
console.log('dir: ', dir);
|
|
||||||
expect(GeUtils.equal(dir, dirc)).toBe(true);
|
|
||||||
|
|
||||||
|
|
||||||
let newDir = orb.UpdateDirection();
|
|
||||||
console.log('newDir: ', newDir);
|
|
||||||
|
|
||||||
|
|
||||||
let up = Orbit.ComputUpDirection(new THREE.Vector3(0, 0, 1));
|
|
||||||
expect(GeUtils.equal(up, new THREE.Vector3(0, -1, 0))).toBe(true);
|
|
||||||
|
|
||||||
Orbit.ComputUpDirection(new THREE.Vector3(0, 0, -1), up);
|
|
||||||
console.log(up);
|
|
||||||
|
|
||||||
Orbit.ComputUpDirection(new THREE.Vector3(0, 0, 1), up);
|
|
||||||
console.log(up);
|
|
||||||
|
|
||||||
Orbit.ComputUpDirection(new THREE.Vector3(1, 0, 0), up);
|
|
||||||
|
|
||||||
let newD = orb.UpdateDirection();
|
|
||||||
console.log(newD);
|
|
||||||
expect(GeUtils.equal(newD, new THREE.Vector3(0, 0, -1))).toBe(true);
|
|
||||||
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
test("测试求向量", () =>
|
|
||||||
{
|
|
||||||
let dir = new THREE.Vector3(0, 0, 1);
|
|
||||||
let up = Orbit.ComputUpDirection(dir);
|
|
||||||
|
|
||||||
console.log(up);
|
|
||||||
expect(up).toMatchSnapshot();
|
|
||||||
|
|
||||||
Orbit.ComputUpDirection(dir, up);
|
|
||||||
console.log(up);
|
|
||||||
expect(up).toMatchSnapshot();
|
|
||||||
|
|
||||||
dir.z = -1;
|
|
||||||
Orbit.ComputUpDirection(dir, up);
|
|
||||||
console.log('up: ', up);
|
|
||||||
expect(up).toMatchSnapshot();
|
|
||||||
|
|
||||||
dir.x = 1;
|
|
||||||
|
|
||||||
Orbit.ComputUpDirection(dir, up);
|
|
||||||
console.log('up: ', up);
|
|
||||||
expect(up).toMatchSnapshot();
|
|
||||||
})
|
|
@ -1,15 +0,0 @@
|
|||||||
import * as THREE from 'three';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
test('should behave...', () =>
|
|
||||||
{
|
|
||||||
let p1 = new THREE.Vector3(0, 0, 0);
|
|
||||||
let p2 = new THREE.Vector3(1, 0, 0);
|
|
||||||
let p3 = new THREE.Vector3(0.5, 0.5, 0);
|
|
||||||
let p4 = new THREE.Vector3(0.5, 1, 0);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
@ -1,63 +1,63 @@
|
|||||||
//绘制板件
|
// //绘制板件
|
||||||
import * as THREE from 'three';
|
// import * as THREE from 'three';
|
||||||
|
|
||||||
import { app } from '../ApplicationServices/Application';
|
// import { app } from '../ApplicationServices/Application';
|
||||||
import { CreateBoardUtil } from '../ApplicationServices/mesh/createBoard';
|
// import { CreateBoardUtil } from '../ApplicationServices/mesh/createBoard';
|
||||||
import { MaterialNeedUpdateKey } from '../DatabaseServices/MaterialDictionary';
|
// import { MaterialNeedUpdateKey } from '../DatabaseServices/MaterialDictionary';
|
||||||
import { Command } from '../Editor/CommandMachine';
|
// import { Command } from '../Editor/CommandMachine';
|
||||||
import { Move } from '../Geometry/GeUtils';
|
// import { Move } from '../Geometry/GeUtils';
|
||||||
|
|
||||||
export class Command_DrawBoard implements Command
|
// export class Command_DrawBoard implements Command
|
||||||
{
|
// {
|
||||||
async exec()
|
// async exec()
|
||||||
{
|
// {
|
||||||
|
|
||||||
let boardMaterial = new THREE.MeshStandardMaterial({
|
// let boardMaterial = new THREE.MeshStandardMaterial({
|
||||||
roughness: 0.3,
|
// roughness: 0.3,
|
||||||
color: 0xffffff,
|
// color: 0xffffff,
|
||||||
metalness: 0.2,
|
// metalness: 0.2,
|
||||||
bumpScale: 0.0005
|
// bumpScale: 0.0005
|
||||||
})
|
// })
|
||||||
|
|
||||||
boardMaterial.name = "板"
|
// boardMaterial.name = "板"
|
||||||
|
|
||||||
|
|
||||||
let textureLoader = new THREE.TextureLoader();
|
// let textureLoader = new THREE.TextureLoader();
|
||||||
textureLoader.load("textures/019.jpg", function (map)
|
// textureLoader.load("textures/019.jpg", function (map)
|
||||||
{
|
// {
|
||||||
map.wrapS = THREE.MirroredRepeatWrapping;
|
// map.wrapS = THREE.MirroredRepeatWrapping;
|
||||||
map.wrapT = THREE.MirroredRepeatWrapping;
|
// map.wrapT = THREE.MirroredRepeatWrapping;
|
||||||
map.anisotropy = 16;
|
// map.anisotropy = 16;
|
||||||
map.repeat.set(1, 1);
|
// map.repeat.set(1, 1);
|
||||||
boardMaterial.map = map;
|
// boardMaterial.map = map;
|
||||||
boardMaterial.needsUpdate = true;
|
// boardMaterial.needsUpdate = true;
|
||||||
boardMaterial[MaterialNeedUpdateKey] = true;
|
// boardMaterial[MaterialNeedUpdateKey] = true;
|
||||||
});
|
// });
|
||||||
|
|
||||||
// let scale = new THREE.Matrix4();
|
// // let scale = new THREE.Matrix4();
|
||||||
// scale.scale(new THREE.Vector3(0.001, 0.001, 0.001));
|
// // scale.scale(new THREE.Vector3(0.001, 0.001, 0.001));
|
||||||
|
|
||||||
let move = Move(new THREE.Vector3(-1, 2.5, 0));
|
// let move = Move(new THREE.Vector3(-1, 2.5, 0));
|
||||||
|
|
||||||
// let mat = move.multiply(scale);
|
// // let mat = move.multiply(scale);
|
||||||
|
|
||||||
app.m_Database.m_MaterialDictionary.addMaterial(boardMaterial);
|
// app.m_Database.m_MaterialDictionary.addMaterial(boardMaterial);
|
||||||
|
|
||||||
for (let i = 0; i < 50; i++)
|
// for (let i = 0; i < 50; i++)
|
||||||
{
|
// {
|
||||||
let boardList = CreateBoardUtil.createTemplateBoard();
|
// let boardList = CreateBoardUtil.createTemplateBoard();
|
||||||
for (let board of boardList)
|
// for (let board of boardList)
|
||||||
{
|
// {
|
||||||
let br = board as THREE.Mesh;
|
// let br = board as THREE.Mesh;
|
||||||
br.applyMatrix(move);
|
// br.applyMatrix(move);
|
||||||
br.material = boardMaterial;
|
// br.material = boardMaterial;
|
||||||
br.castShadow = true;
|
// br.castShadow = true;
|
||||||
br.receiveShadow = true;
|
// br.receiveShadow = true;
|
||||||
app.m_Viewer.m_Scene.add(board);
|
// app.m_Viewer.m_Scene.add(board);
|
||||||
|
|
||||||
let move2 = Move(new THREE.Vector3(i * 1, 0, 0));
|
// let move2 = Move(new THREE.Vector3(i * 1, 0, 0));
|
||||||
br.applyMatrix(move2);
|
// br.applyMatrix(move2);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
@ -1,401 +1,401 @@
|
|||||||
import * as path from 'path';
|
// import * as path from 'path';
|
||||||
import * as THREE from 'three';
|
// import * as THREE from 'three';
|
||||||
|
|
||||||
import { app } from '../ApplicationServices/Application';
|
// import { app } from '../ApplicationServices/Application';
|
||||||
import { Solid3d } from '../DatabaseServices/Entity';
|
// import { Solid3d } from '../DatabaseServices/Entity';
|
||||||
import { Command } from '../Editor/CommandMachine';
|
// import { Command } from '../Editor/CommandMachine';
|
||||||
import { Move } from '../Geometry/GeUtils';
|
// import { Move } from '../Geometry/GeUtils';
|
||||||
import { RenderType } from '../GraphicsSystem/Enum';
|
// import { RenderType } from '../GraphicsSystem/Enum';
|
||||||
|
|
||||||
export class DrawFloor implements Command
|
// export class DrawFloor implements Command
|
||||||
{
|
// {
|
||||||
textureLoader: THREE.TextureLoader;
|
// textureLoader: THREE.TextureLoader;
|
||||||
|
|
||||||
get scene()
|
// get scene()
|
||||||
{
|
// {
|
||||||
return app.m_Viewer.m_Scene;
|
// return app.m_Viewer.m_Scene;
|
||||||
}
|
// }
|
||||||
constructor()
|
// constructor()
|
||||||
{
|
// {
|
||||||
this.textureLoader = new THREE.TextureLoader();
|
// this.textureLoader = new THREE.TextureLoader();
|
||||||
}
|
// }
|
||||||
async exec()
|
// async exec()
|
||||||
{
|
// {
|
||||||
app.m_Viewer.m_Camera.Camera.position.set(0, 0, 2);
|
// app.m_Viewer.m_Camera.Camera.position.set(0, 0, 2);
|
||||||
this.drawFloor();
|
// this.drawFloor();
|
||||||
|
|
||||||
this.drawLight();
|
// this.drawLight();
|
||||||
this.drawHemiLight();
|
// this.drawHemiLight();
|
||||||
|
|
||||||
// this.drawWall();
|
// // this.drawWall();
|
||||||
|
|
||||||
// this.drawBox();
|
// // this.drawBox();
|
||||||
// //绘制一个盒子 带反射
|
// // //绘制一个盒子 带反射
|
||||||
// this.drawBox2();
|
// // this.drawBox2();
|
||||||
|
|
||||||
|
|
||||||
this.loadMaterial();
|
// this.loadMaterial();
|
||||||
|
|
||||||
app.m_Viewer.m_Render.toneMappingExposure = Math.pow(0.68, 5.0); // to allow for very bright scenes.
|
// app.m_Viewer.m_Render.toneMappingExposure = Math.pow(0.68, 5.0); // to allow for very bright scenes.
|
||||||
}
|
// }
|
||||||
|
|
||||||
async loadFbx()
|
// async loadFbx()
|
||||||
{
|
// {
|
||||||
// let obj = await loadFBX("123456.FBX");
|
// // let obj = await loadFBX("123456.FBX");
|
||||||
|
|
||||||
// this.scene.add(obj.object);
|
// // this.scene.add(obj.object);
|
||||||
}
|
// }
|
||||||
|
|
||||||
private drawFloor()
|
// private drawFloor()
|
||||||
{
|
// {
|
||||||
let floorMat = new THREE.MeshStandardMaterial({
|
// let floorMat = new THREE.MeshStandardMaterial({
|
||||||
roughness: 0.8,
|
// roughness: 0.8,
|
||||||
color: 0xffffff,
|
// color: 0xffffff,
|
||||||
metalness: 0.2,
|
// metalness: 0.2,
|
||||||
bumpScale: 0.0005,
|
// bumpScale: 0.0005,
|
||||||
transparent: true,
|
// transparent: true,
|
||||||
opacity: 0.9
|
// opacity: 0.9
|
||||||
});
|
// });
|
||||||
this.materialList.push(floorMat);
|
// this.materialList.push(floorMat);
|
||||||
|
|
||||||
var floorGeometry = new THREE.PlaneBufferGeometry(20, 20);
|
// var floorGeometry = new THREE.PlaneBufferGeometry(20, 20);
|
||||||
var floorMesh = new THREE.Mesh(floorGeometry, floorMat);
|
// var floorMesh = new THREE.Mesh(floorGeometry, floorMat);
|
||||||
floorMesh.receiveShadow = true;
|
// floorMesh.receiveShadow = true;
|
||||||
this.scene.add(floorMesh);
|
// this.scene.add(floorMesh);
|
||||||
|
|
||||||
//使用镜子
|
// //使用镜子
|
||||||
let useRef = false;
|
// let useRef = false;
|
||||||
if (useRef)
|
// if (useRef)
|
||||||
{
|
// {
|
||||||
floorMat.transparent = true;
|
// floorMat.transparent = true;
|
||||||
floorMat.opacity = 0.9
|
// floorMat.opacity = 0.9
|
||||||
|
|
||||||
// let ref = new THREE.Reflector(20, 20, {
|
// // let ref = new THREE.Reflector(20, 20, {
|
||||||
// clipBias: 0.003,
|
// // clipBias: 0.003,
|
||||||
// textureWidth: app.m_Viewer.Width * window.devicePixelRatio,
|
// // textureWidth: app.m_Viewer.Width * window.devicePixelRatio,
|
||||||
// textureHeight: app.m_Viewer.Height * window.devicePixelRatio,
|
// // textureHeight: app.m_Viewer.Height * window.devicePixelRatio,
|
||||||
// color: 0x777777
|
// // color: 0x777777
|
||||||
// });
|
// // });
|
||||||
|
|
||||||
// ref.position.z = -0.1;
|
// // ref.position.z = -0.1;
|
||||||
// this.scene.add(ref);
|
// // this.scene.add(ref);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
materialList = [];
|
// materialList = [];
|
||||||
loadMaterial()
|
// loadMaterial()
|
||||||
{
|
// {
|
||||||
let self = this;
|
// let self = this;
|
||||||
|
|
||||||
this.textureLoader.load("textures/hardwood2_diffuse.jpg", function (map)
|
// this.textureLoader.load("textures/hardwood2_diffuse.jpg", function (map)
|
||||||
{
|
// {
|
||||||
map.wrapS = THREE.RepeatWrapping;
|
// map.wrapS = THREE.RepeatWrapping;
|
||||||
map.wrapT = THREE.RepeatWrapping;
|
// map.wrapT = THREE.RepeatWrapping;
|
||||||
map.anisotropy = 16;
|
// map.anisotropy = 16;
|
||||||
map.repeat.set(10, 24);
|
// map.repeat.set(10, 24);
|
||||||
|
|
||||||
self.materialList.forEach(m =>
|
// self.materialList.forEach(m =>
|
||||||
{
|
// {
|
||||||
m.map = map;
|
// m.map = map;
|
||||||
m.needsUpdate = true;
|
// m.needsUpdate = true;
|
||||||
})
|
// })
|
||||||
});
|
// });
|
||||||
this.textureLoader.load("textures/hardwood2_bump.jpg", function (map)
|
// this.textureLoader.load("textures/hardwood2_bump.jpg", function (map)
|
||||||
{
|
// {
|
||||||
map.wrapS = THREE.RepeatWrapping;
|
// map.wrapS = THREE.RepeatWrapping;
|
||||||
map.wrapT = THREE.RepeatWrapping;
|
// map.wrapT = THREE.RepeatWrapping;
|
||||||
map.anisotropy = 16;
|
// map.anisotropy = 16;
|
||||||
map.repeat.set(10, 24);
|
// map.repeat.set(10, 24);
|
||||||
|
|
||||||
self.materialList.forEach(m =>
|
// self.materialList.forEach(m =>
|
||||||
{
|
// {
|
||||||
(<THREE.MeshStandardMaterial>m).bumpMap = map;
|
// (<THREE.MeshStandardMaterial>m).bumpMap = map;
|
||||||
m.needsUpdate = true;
|
// m.needsUpdate = true;
|
||||||
})
|
// })
|
||||||
});
|
// });
|
||||||
this.textureLoader.load("textures/hardwood2_roughness.jpg", function (map)
|
// this.textureLoader.load("textures/hardwood2_roughness.jpg", function (map)
|
||||||
{
|
// {
|
||||||
map.wrapS = THREE.RepeatWrapping;
|
// map.wrapS = THREE.RepeatWrapping;
|
||||||
map.wrapT = THREE.RepeatWrapping;
|
// map.wrapT = THREE.RepeatWrapping;
|
||||||
map.anisotropy = 16;
|
// map.anisotropy = 16;
|
||||||
map.repeat.set(10, 24);
|
// map.repeat.set(10, 24);
|
||||||
|
|
||||||
self.materialList.forEach(m =>
|
// self.materialList.forEach(m =>
|
||||||
{
|
// {
|
||||||
(<THREE.MeshStandardMaterial>m).roughnessMap = map;
|
// (<THREE.MeshStandardMaterial>m).roughnessMap = map;
|
||||||
m.needsUpdate = true;
|
// m.needsUpdate = true;
|
||||||
})
|
// })
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
drawLight()
|
// drawLight()
|
||||||
{
|
// {
|
||||||
var bulbGeometry = new THREE.SphereGeometry(0.02, 16, 8);
|
// var bulbGeometry = new THREE.SphereGeometry(0.02, 16, 8);
|
||||||
let bulbLight = new THREE.PointLight(0x999999, 1, 100, 2);
|
// let bulbLight = new THREE.PointLight(0x999999, 1, 100, 2);
|
||||||
|
|
||||||
let bulbMat = new THREE.MeshStandardMaterial({
|
// let bulbMat = new THREE.MeshStandardMaterial({
|
||||||
emissive: 0xffffee,
|
// emissive: 0xffffee,
|
||||||
emissiveIntensity: 1,
|
// emissiveIntensity: 1,
|
||||||
color: 0x000000
|
// color: 0x000000
|
||||||
});
|
// });
|
||||||
|
|
||||||
|
|
||||||
bulbLight.add(new THREE.Mesh(bulbGeometry, bulbMat));
|
// bulbLight.add(new THREE.Mesh(bulbGeometry, bulbMat));
|
||||||
bulbLight.position.set(0, 2, 2);
|
// bulbLight.position.set(0, 2, 2);
|
||||||
bulbLight.castShadow = true;
|
// bulbLight.castShadow = true;
|
||||||
|
|
||||||
bulbLight.power = 400;
|
// bulbLight.power = 400;
|
||||||
bulbMat.emissiveIntensity = bulbLight.intensity / Math.pow(0.02, 2.0); // convert from intensity to irradiance at bulb surface
|
// bulbMat.emissiveIntensity = bulbLight.intensity / Math.pow(0.02, 2.0); // convert from intensity to irradiance at bulb surface
|
||||||
this.scene.add(bulbLight);
|
// this.scene.add(bulbLight);
|
||||||
|
|
||||||
let light2 = bulbLight.clone();
|
// let light2 = bulbLight.clone();
|
||||||
|
|
||||||
light2.position.set(-3, -1, 2);
|
// light2.position.set(-3, -1, 2);
|
||||||
this.scene.add(light2);
|
// this.scene.add(light2);
|
||||||
|
|
||||||
|
|
||||||
// var clock = new THREE.Clock();
|
// var clock = new THREE.Clock();
|
||||||
// xaop.begin(app.m_Viewer, app.m_Viewer.StartRender, () =>
|
// // xaop.begin(app.m_Viewer, app.m_Viewer.StartRender, () =>
|
||||||
// {
|
// // {
|
||||||
// var time = Date.now() * 0.0005;
|
// // var time = Date.now() * 0.0005;
|
||||||
// var delta = clock.getDelta();
|
// // var delta = clock.getDelta();
|
||||||
// bulbLight.position.z = Math.cos(time) * 0.75 + 1.25;
|
// // bulbLight.position.z = Math.cos(time) * 0.75 + 1.25;
|
||||||
// app.m_Viewer.m_bNeedUpdate = true;
|
// // app.m_Viewer.m_bNeedUpdate = true;
|
||||||
// })
|
// // })
|
||||||
}
|
// }
|
||||||
private drawHemiLight()
|
// private drawHemiLight()
|
||||||
{
|
// {
|
||||||
//0xddeeff 0x0f0e0d
|
// //0xddeeff 0x0f0e0d
|
||||||
var hemiLight = new THREE.HemisphereLight(0xffffff, 0xffffff, 0.02);
|
// var hemiLight = new THREE.HemisphereLight(0xffffff, 0xffffff, 0.02);
|
||||||
hemiLight.intensity = 3;
|
// hemiLight.intensity = 3;
|
||||||
this.scene.add(hemiLight);
|
// this.scene.add(hemiLight);
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
drawWall()
|
// drawWall()
|
||||||
{
|
// {
|
||||||
let floorMat = new THREE.MeshStandardMaterial({
|
// let floorMat = new THREE.MeshStandardMaterial({
|
||||||
roughness: 0.8,
|
// roughness: 0.8,
|
||||||
color: 0xffffff,
|
// color: 0xffffff,
|
||||||
metalness: 0.2,
|
// metalness: 0.2,
|
||||||
bumpScale: 0.0005
|
// bumpScale: 0.0005
|
||||||
});
|
// });
|
||||||
|
|
||||||
this.textureLoader.load("textures/wallmap.png", function (map)
|
// this.textureLoader.load("textures/wallmap.png", function (map)
|
||||||
{
|
// {
|
||||||
map.wrapS = THREE.RepeatWrapping;
|
// map.wrapS = THREE.RepeatWrapping;
|
||||||
map.wrapT = THREE.RepeatWrapping;
|
// map.wrapT = THREE.RepeatWrapping;
|
||||||
map.anisotropy = 4;
|
// map.anisotropy = 4;
|
||||||
map.repeat.set(10, 24);
|
// map.repeat.set(10, 24);
|
||||||
floorMat.map = map;
|
// floorMat.map = map;
|
||||||
floorMat.needsUpdate = true;
|
// floorMat.needsUpdate = true;
|
||||||
});
|
// });
|
||||||
|
|
||||||
|
|
||||||
let wallFont = new Solid3d(4, 0.12, 2.8);
|
// let wallFont = new Solid3d(4, 0.12, 2.8);
|
||||||
let obj = wallFont.Draw(RenderType.Wireframe) as THREE.Mesh;
|
// let obj = wallFont.Draw(RenderType.Wireframe) as THREE.Mesh;
|
||||||
obj.material = floorMat;
|
// obj.material = floorMat;
|
||||||
|
|
||||||
obj.castShadow = true;
|
// obj.castShadow = true;
|
||||||
obj.receiveShadow = true;
|
// obj.receiveShadow = true;
|
||||||
|
|
||||||
let objLeft = obj.clone();
|
// let objLeft = obj.clone();
|
||||||
let objRight = obj.clone();
|
// let objRight = obj.clone();
|
||||||
|
|
||||||
|
|
||||||
obj.applyMatrix(Move(new THREE.Vector3(-2.1, 4, 0)));
|
// obj.applyMatrix(Move(new THREE.Vector3(-2.1, 4, 0)));
|
||||||
|
|
||||||
let roMatLeft = new THREE.Matrix4();
|
// let roMatLeft = new THREE.Matrix4();
|
||||||
roMatLeft.makeRotationZ(Math.PI / 2);
|
// roMatLeft.makeRotationZ(Math.PI / 2);
|
||||||
objLeft.applyMatrix(roMatLeft);
|
// objLeft.applyMatrix(roMatLeft);
|
||||||
|
|
||||||
let roMatRight = new THREE.Matrix4();
|
// let roMatRight = new THREE.Matrix4();
|
||||||
roMatRight.makeRotationZ(Math.PI / 2);
|
// roMatRight.makeRotationZ(Math.PI / 2);
|
||||||
objRight.applyMatrix(roMatRight);
|
// objRight.applyMatrix(roMatRight);
|
||||||
|
|
||||||
objLeft.applyMatrix(Move(new THREE.Vector3(-2, 0, 0)))
|
// objLeft.applyMatrix(Move(new THREE.Vector3(-2, 0, 0)))
|
||||||
objRight.applyMatrix(Move(new THREE.Vector3(2, 0, 0)))
|
// objRight.applyMatrix(Move(new THREE.Vector3(2, 0, 0)))
|
||||||
|
|
||||||
|
|
||||||
this.scene.add(obj);
|
// this.scene.add(obj);
|
||||||
this.scene.add(objLeft);
|
// this.scene.add(objLeft);
|
||||||
this.scene.add(objRight);
|
// this.scene.add(objRight);
|
||||||
|
|
||||||
|
|
||||||
let skyMaterail = new THREE.MeshStandardMaterial({
|
// let skyMaterail = new THREE.MeshStandardMaterial({
|
||||||
roughness: 0.8,
|
// roughness: 0.8,
|
||||||
color: 0xffffff,
|
// color: 0xffffff,
|
||||||
metalness: 0.2,
|
// metalness: 0.2,
|
||||||
bumpScale: 0.0005
|
// bumpScale: 0.0005
|
||||||
})
|
// })
|
||||||
//天花板.
|
// //天花板.
|
||||||
let skyWall = new Solid3d(4.12, 4, 0.12);
|
// let skyWall = new Solid3d(4.12, 4, 0.12);
|
||||||
let skyObj = skyWall.Draw(RenderType.Wireframe) as THREE.Mesh;
|
// let skyObj = skyWall.Draw(RenderType.Wireframe) as THREE.Mesh;
|
||||||
skyObj.material = skyMaterail;
|
// skyObj.material = skyMaterail;
|
||||||
|
|
||||||
skyObj.applyMatrix(Move(new THREE.Vector3(-2.12, 0, 2.8)));
|
// skyObj.applyMatrix(Move(new THREE.Vector3(-2.12, 0, 2.8)));
|
||||||
|
|
||||||
this.scene.add(skyObj);
|
// this.scene.add(skyObj);
|
||||||
}
|
// }
|
||||||
|
|
||||||
drawBox()
|
// drawBox()
|
||||||
{
|
// {
|
||||||
let solid = new Solid3d(1.2, 0.05, 2.4);
|
// let solid = new Solid3d(1.2, 0.05, 2.4);
|
||||||
|
|
||||||
let obj = solid.Draw(RenderType.Wireframe);
|
// let obj = solid.Draw(RenderType.Wireframe);
|
||||||
|
|
||||||
obj.castShadow = true;
|
// obj.castShadow = true;
|
||||||
|
|
||||||
let mat = new THREE.MeshStandardMaterial({
|
// let mat = new THREE.MeshStandardMaterial({
|
||||||
roughness: 0.8,
|
// roughness: 0.8,
|
||||||
color: 0xffffff,
|
// color: 0xffffff,
|
||||||
metalness: 0.2,
|
// metalness: 0.2,
|
||||||
bumpScale: 0.0005
|
// bumpScale: 0.0005
|
||||||
});
|
// });
|
||||||
|
|
||||||
this.textureLoader.load("textures/door.png", function (map)
|
// this.textureLoader.load("textures/door.png", function (map)
|
||||||
{
|
// {
|
||||||
map.wrapS = THREE.RepeatWrapping;
|
// map.wrapS = THREE.RepeatWrapping;
|
||||||
map.wrapT = THREE.RepeatWrapping;
|
// map.wrapT = THREE.RepeatWrapping;
|
||||||
map.anisotropy = 16;
|
// map.anisotropy = 16;
|
||||||
map.repeat.set(1, 1);
|
// map.repeat.set(1, 1);
|
||||||
mat.map = map;
|
// mat.map = map;
|
||||||
mat.needsUpdate = true;
|
// mat.needsUpdate = true;
|
||||||
});
|
// });
|
||||||
(<THREE.Mesh>obj).material = mat;
|
// (<THREE.Mesh>obj).material = mat;
|
||||||
|
|
||||||
|
|
||||||
this.scene.add(obj);
|
// this.scene.add(obj);
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
cubemap()
|
// cubemap()
|
||||||
{
|
// {
|
||||||
var path = "textures/cube/Park2/";
|
// var path = "textures/cube/Park2/";
|
||||||
var format = '.jpg';
|
// var format = '.jpg';
|
||||||
var urls = [
|
// var urls = [
|
||||||
path + 'posx' + format, path + 'negx' + format,
|
// path + 'posx' + format, path + 'negx' + format,
|
||||||
path + 'posy' + format, path + 'negy' + format,
|
// path + 'posy' + format, path + 'negy' + format,
|
||||||
path + 'posz' + format, path + 'negz' + format
|
// path + 'posz' + format, path + 'negz' + format
|
||||||
];
|
// ];
|
||||||
var textureCube = new THREE.CubeTextureLoader().load(urls);
|
// var textureCube = new THREE.CubeTextureLoader().load(urls);
|
||||||
textureCube.format = THREE.RGBFormat;
|
// textureCube.format = THREE.RGBFormat;
|
||||||
return textureCube;
|
// return textureCube;
|
||||||
};
|
// };
|
||||||
|
|
||||||
drawBox2()
|
// drawBox2()
|
||||||
{
|
// {
|
||||||
let solid = new Solid3d(1, 1, 1);
|
// let solid = new Solid3d(1, 1, 1);
|
||||||
|
|
||||||
let obj = solid.Draw(RenderType.Wireframe);
|
// let obj = solid.Draw(RenderType.Wireframe);
|
||||||
|
|
||||||
// obj = new THREE.Mesh(new THREE.SphereGeometry(1, 32, 32));
|
// // obj = new THREE.Mesh(new THREE.SphereGeometry(1, 32, 32));
|
||||||
obj.position.set(0, 0, 1);
|
// obj.position.set(0, 0, 1);
|
||||||
|
|
||||||
obj.castShadow = true;
|
// obj.castShadow = true;
|
||||||
|
|
||||||
let cubeCamera1 = new THREE.CubeCamera(0.1, 15, 1024);
|
// let cubeCamera1 = new THREE.CubeCamera(0.1, 15, 1024);
|
||||||
let cubeCamera2 = new THREE.CubeCamera(0.1, 15, 1024);
|
// let cubeCamera2 = new THREE.CubeCamera(0.1, 15, 1024);
|
||||||
cubeCamera1.position.set(0, 0, 1);
|
// cubeCamera1.position.set(0, 0, 1);
|
||||||
cubeCamera2.position.set(0, 0, 1);
|
// cubeCamera2.position.set(0, 0, 1);
|
||||||
cubeCamera1.renderTarget.texture.minFilter = THREE.LinearMipMapLinearFilter;
|
// cubeCamera1.renderTarget.texture.minFilter = THREE.LinearMipMapLinearFilter;
|
||||||
cubeCamera2.renderTarget.texture.minFilter = THREE.LinearMipMapLinearFilter;
|
// cubeCamera2.renderTarget.texture.minFilter = THREE.LinearMipMapLinearFilter;
|
||||||
cubeCamera1.renderTarget.texture.anisotropy = 16;
|
// cubeCamera1.renderTarget.texture.anisotropy = 16;
|
||||||
cubeCamera2.renderTarget.texture.anisotropy = 16;
|
// cubeCamera2.renderTarget.texture.anisotropy = 16;
|
||||||
|
|
||||||
|
|
||||||
this.scene.add(cubeCamera1);
|
// this.scene.add(cubeCamera1);
|
||||||
this.scene.add(cubeCamera2);
|
// this.scene.add(cubeCamera2);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let mat = new THREE.MeshStandardMaterial({
|
// let mat = new THREE.MeshStandardMaterial({
|
||||||
roughness: 0.8,
|
// roughness: 0.8,
|
||||||
metalness: 0.8,
|
// metalness: 0.8,
|
||||||
// color: 0xffffff,
|
// // color: 0xffffff,
|
||||||
// emissive: 0x000000,
|
// // emissive: 0x000000,
|
||||||
emissiveIntensity: 0,
|
// emissiveIntensity: 0,
|
||||||
envMap: cubeCamera1.renderTarget.texture,
|
// envMap: cubeCamera1.renderTarget.texture,
|
||||||
envMapIntensity: 1
|
// envMapIntensity: 1
|
||||||
});
|
// });
|
||||||
|
|
||||||
this.textureLoader.load("textures/Metal/130616_header2.jpg", function (map)
|
// this.textureLoader.load("textures/Metal/130616_header2.jpg", function (map)
|
||||||
{
|
// {
|
||||||
map.wrapS = THREE.RepeatWrapping;
|
// map.wrapS = THREE.RepeatWrapping;
|
||||||
map.wrapT = THREE.RepeatWrapping;
|
// map.wrapT = THREE.RepeatWrapping;
|
||||||
map.anisotropy = 16;
|
// map.anisotropy = 16;
|
||||||
map.repeat.set(1, 1);
|
// map.repeat.set(1, 1);
|
||||||
mat.map = map;
|
// mat.map = map;
|
||||||
mat.needsUpdate = true;
|
// mat.needsUpdate = true;
|
||||||
});
|
// });
|
||||||
|
|
||||||
this.textureLoader.load("textures/Metal/Titanium-Scuffed_basecolor.png", function (map)
|
// this.textureLoader.load("textures/Metal/Titanium-Scuffed_basecolor.png", function (map)
|
||||||
{
|
// {
|
||||||
map.wrapS = THREE.RepeatWrapping;
|
// map.wrapS = THREE.RepeatWrapping;
|
||||||
map.wrapT = THREE.RepeatWrapping;
|
// map.wrapT = THREE.RepeatWrapping;
|
||||||
map.anisotropy = 16;
|
// map.anisotropy = 16;
|
||||||
map.repeat.set(1, 1);
|
// map.repeat.set(1, 1);
|
||||||
mat.map = map;
|
// mat.map = map;
|
||||||
mat.needsUpdate = true;
|
// mat.needsUpdate = true;
|
||||||
});
|
// });
|
||||||
this.textureLoader.load("textures/Metal/Titanium-Scuffed_roughness.png", function (map)
|
// this.textureLoader.load("textures/Metal/Titanium-Scuffed_roughness.png", function (map)
|
||||||
{
|
// {
|
||||||
map.wrapS = THREE.RepeatWrapping;
|
// map.wrapS = THREE.RepeatWrapping;
|
||||||
map.wrapT = THREE.RepeatWrapping;
|
// map.wrapT = THREE.RepeatWrapping;
|
||||||
map.anisotropy = 16;
|
// map.anisotropy = 16;
|
||||||
map.repeat.set(1, 1);
|
// map.repeat.set(1, 1);
|
||||||
mat.roughnessMap = map;
|
// mat.roughnessMap = map;
|
||||||
mat.needsUpdate = true;
|
// mat.needsUpdate = true;
|
||||||
});
|
// });
|
||||||
this.textureLoader.load("textures/Metal/Titanium-Scuffed_normal.png", function (map)
|
// this.textureLoader.load("textures/Metal/Titanium-Scuffed_normal.png", function (map)
|
||||||
{
|
// {
|
||||||
map.wrapS = THREE.RepeatWrapping;
|
// map.wrapS = THREE.RepeatWrapping;
|
||||||
map.wrapT = THREE.RepeatWrapping;
|
// map.wrapT = THREE.RepeatWrapping;
|
||||||
map.anisotropy = 16;
|
// map.anisotropy = 16;
|
||||||
map.repeat.set(1, 1);
|
// map.repeat.set(1, 1);
|
||||||
mat.normalMap = map;
|
// mat.normalMap = map;
|
||||||
mat.needsUpdate = true;
|
// mat.needsUpdate = true;
|
||||||
});
|
// });
|
||||||
this.textureLoader.load("textures/Metal/Titanium-Scuffed_metallic.png", function (map)
|
// this.textureLoader.load("textures/Metal/Titanium-Scuffed_metallic.png", function (map)
|
||||||
{
|
// {
|
||||||
map.wrapS = THREE.RepeatWrapping;
|
// map.wrapS = THREE.RepeatWrapping;
|
||||||
map.wrapT = THREE.RepeatWrapping;
|
// map.wrapT = THREE.RepeatWrapping;
|
||||||
map.anisotropy = 16;
|
// map.anisotropy = 16;
|
||||||
map.repeat.set(1, 1);
|
// map.repeat.set(1, 1);
|
||||||
mat.metalnessMap = map;
|
// mat.metalnessMap = map;
|
||||||
mat.needsUpdate = true;
|
// mat.needsUpdate = true;
|
||||||
});
|
// });
|
||||||
|
|
||||||
let isOne = false;
|
// let isOne = false;
|
||||||
// begin(app.m_Viewer, app.m_Viewer.StartRender, () =>
|
// // begin(app.m_Viewer, app.m_Viewer.StartRender, () =>
|
||||||
// {
|
// // {
|
||||||
// obj.visible = false;
|
// // obj.visible = false;
|
||||||
// let render = app.m_Viewer.m_Render;
|
// // let render = app.m_Viewer.m_Render;
|
||||||
// let scene = app.m_Viewer.m_Scene;
|
// // let scene = app.m_Viewer.m_Scene;
|
||||||
|
|
||||||
// render.autoClear = true;
|
// // render.autoClear = true;
|
||||||
// // render.clear();
|
// // // render.clear();
|
||||||
// if (isOne)
|
// // if (isOne)
|
||||||
// {
|
// // {
|
||||||
// mat.envMap = cubeCamera2.renderTarget.texture;
|
// // mat.envMap = cubeCamera2.renderTarget.texture;
|
||||||
// cubeCamera2.position.copy(obj.position);
|
// // cubeCamera2.position.copy(obj.position);
|
||||||
// cubeCamera2.update(render, scene);
|
// // cubeCamera2.update(render, scene);
|
||||||
// }
|
// // }
|
||||||
// else
|
// // else
|
||||||
// {
|
// // {
|
||||||
// mat.envMap = cubeCamera1.renderTarget.texture;
|
// // mat.envMap = cubeCamera1.renderTarget.texture;
|
||||||
// cubeCamera1.position.copy(obj.position);
|
// // cubeCamera1.position.copy(obj.position);
|
||||||
// cubeCamera1.update(render, scene);
|
// // cubeCamera1.update(render, scene);
|
||||||
// }
|
// // }
|
||||||
// obj.visible = true;
|
// // obj.visible = true;
|
||||||
// isOne = !isOne;
|
// // isOne = !isOne;
|
||||||
// });
|
// // });
|
||||||
(<THREE.Mesh>obj).material = mat;
|
// (<THREE.Mesh>obj).material = mat;
|
||||||
this.scene.add(obj);
|
// this.scene.add(obj);
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
loadMaterialNode()
|
// loadMaterialNode()
|
||||||
{
|
// {
|
||||||
}
|
// }
|
||||||
}
|
// }
|
@ -0,0 +1,19 @@
|
|||||||
|
import { Command } from "../Editor/CommandMachine";
|
||||||
|
import { app } from "../ApplicationServices/Application";
|
||||||
|
import { IndexedDbStore, StoreName } from "../IndexedDb/IndexedDbStore";
|
||||||
|
import { CADFile } from "../DatabaseServices/CADFile";
|
||||||
|
|
||||||
|
export class Open implements Command
|
||||||
|
{
|
||||||
|
async exec()
|
||||||
|
{
|
||||||
|
let store = await IndexedDbStore.CADStore();
|
||||||
|
|
||||||
|
let file = await store.Get(StoreName.Dwg, "1");
|
||||||
|
|
||||||
|
let cadF = new CADFile();
|
||||||
|
cadF.Data = file;
|
||||||
|
|
||||||
|
app.m_Database.FileRead(cadF);
|
||||||
|
}
|
||||||
|
}
|
@ -1,70 +0,0 @@
|
|||||||
import * as THREE from 'three';
|
|
||||||
|
|
||||||
import { app } from '../ApplicationServices/Application';
|
|
||||||
import { Line } from '../DatabaseServices/Entity';
|
|
||||||
import { Command } from '../Editor/CommandMachine';
|
|
||||||
import { RenderType } from '../GraphicsSystem/Enum';
|
|
||||||
import { Viewer } from '../GraphicsSystem/Viewer';
|
|
||||||
import { CameraControl } from '../GraphicsSystem/CameraControl';
|
|
||||||
|
|
||||||
|
|
||||||
let bufferTexture: THREE.WebGLRenderTarget;
|
|
||||||
|
|
||||||
let render: THREE.WebGLRenderer;
|
|
||||||
export class SaveTarget implements Command
|
|
||||||
{
|
|
||||||
async exec()
|
|
||||||
{
|
|
||||||
// bufferTexture = new THREE.WebGLRenderTarget(app.m_Viewer.Width, app.m_Viewer.Height);
|
|
||||||
// app.m_Viewer.m_Render.render(app.m_Viewer.m_Scene, app.m_Viewer.m_Camera.m_CurCamera, bufferTexture);
|
|
||||||
|
|
||||||
let el = document.getElementById("Webgl");
|
|
||||||
|
|
||||||
let can = document.createElement("canvas");
|
|
||||||
|
|
||||||
can.style.position = "absolute"
|
|
||||||
can.style.zIndex = "100px";
|
|
||||||
|
|
||||||
can.style.pointerEvents = "none";
|
|
||||||
|
|
||||||
can.style.width = "100%";
|
|
||||||
can.style.height = "100%";
|
|
||||||
|
|
||||||
can.style.left = "0px";
|
|
||||||
can.style.top = "0px";
|
|
||||||
|
|
||||||
el.appendChild(can);
|
|
||||||
|
|
||||||
render = new THREE.WebGLRenderer({ canvas: can, clearColor: 0, alpha: true })
|
|
||||||
|
|
||||||
render.setSize(app.m_Viewer.Width, app.m_Viewer.Height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export class RevTarget implements Command
|
|
||||||
{
|
|
||||||
async exec()
|
|
||||||
{
|
|
||||||
let scene = new THREE.Scene();
|
|
||||||
let line = new Line(new THREE.Vector3(0, 0, 0), new THREE.Vector3(100, 0, 0));
|
|
||||||
scene.add(line.Draw(RenderType.Wireframe));
|
|
||||||
render.render(scene, app.m_Viewer.m_Camera.Camera);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 光标渲染视图
|
|
||||||
*
|
|
||||||
* @class CursorViewer
|
|
||||||
*/
|
|
||||||
class CursorViewer
|
|
||||||
{
|
|
||||||
|
|
||||||
private m_Scene = new THREE.Scene();
|
|
||||||
private m_Camera: CameraControl;
|
|
||||||
constructor(view: Viewer)
|
|
||||||
{
|
|
||||||
this.m_Camera = new CameraControl();
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,15 @@
|
|||||||
|
import { Command } from "../Editor/CommandMachine";
|
||||||
|
import { app } from "../ApplicationServices/Application";
|
||||||
|
import { IndexedDbStore, StoreName } from "../IndexedDb/IndexedDbStore";
|
||||||
|
|
||||||
|
export class Save implements Command
|
||||||
|
{
|
||||||
|
async exec()
|
||||||
|
{
|
||||||
|
let cadFile = app.m_Database.FileWrite();
|
||||||
|
|
||||||
|
let store = await IndexedDbStore.CADStore();
|
||||||
|
|
||||||
|
store.Put(StoreName.Dwg, "1", cadFile.Data);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
import md5 = require("blueimp-md5")
|
||||||
|
|
||||||
|
|
||||||
|
//计算文件的md5值
|
||||||
|
export function blobMd5(blob: Blob): Promise<string>
|
||||||
|
{
|
||||||
|
return new Promise<string>(res =>
|
||||||
|
{
|
||||||
|
let fr = new FileReader();
|
||||||
|
fr.onload = e =>
|
||||||
|
{
|
||||||
|
res(md5(fr.result));
|
||||||
|
}
|
||||||
|
fr.onerror = e =>
|
||||||
|
{
|
||||||
|
res("")
|
||||||
|
}
|
||||||
|
fr.readAsArrayBuffer(blob);
|
||||||
|
})
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
import { Factory } from './CADFactory';
|
||||||
|
import { Entity } from './Entity';
|
||||||
|
import { ObjectCollection } from './ObjectCollection';
|
||||||
|
|
||||||
|
@Factory
|
||||||
|
export class BlockTableRecord extends ObjectCollection<Entity>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
|||||||
|
import { CADObject } from "./CADObject";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CAD对象工厂,通过注册 和暴露的创建方法,动态创建对象
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @class CADFactory
|
||||||
|
*/
|
||||||
|
export class CADFactory
|
||||||
|
{
|
||||||
|
private constructor() { }
|
||||||
|
private objectNameMap = new Map<string, any>();
|
||||||
|
private static factory = new CADFactory();
|
||||||
|
static RegisterObject(C)
|
||||||
|
{
|
||||||
|
this.factory.objectNameMap.set(C.name, C);
|
||||||
|
}
|
||||||
|
static CreateObject(name: string): CADObject
|
||||||
|
{
|
||||||
|
let C = this.factory.objectNameMap.get(name);
|
||||||
|
if (C) return new C();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//可以通过添加装饰器 在类前面(@Factory),自动注册工厂的序列化
|
||||||
|
export function Factory(target: Object)
|
||||||
|
{
|
||||||
|
CADFactory.RegisterObject(target);
|
||||||
|
}
|
@ -0,0 +1,91 @@
|
|||||||
|
import { CADFactory } from './CADFactory';
|
||||||
|
import { CADObject } from './CADObject';
|
||||||
|
import { Database } from './Database';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CAD文件数据
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @class CADFile
|
||||||
|
*/
|
||||||
|
export class CADFile
|
||||||
|
{
|
||||||
|
private readIndex: number = 0;
|
||||||
|
private dataList: any[] = [];
|
||||||
|
|
||||||
|
Destroy()
|
||||||
|
{
|
||||||
|
delete this.dataList;
|
||||||
|
delete this.readIndex;
|
||||||
|
}
|
||||||
|
get Data()
|
||||||
|
{
|
||||||
|
return this.dataList;
|
||||||
|
}
|
||||||
|
set Data(v)
|
||||||
|
{
|
||||||
|
this.dataList = v;
|
||||||
|
this.Reset();
|
||||||
|
}
|
||||||
|
Reset()
|
||||||
|
{
|
||||||
|
this.readIndex = 0;
|
||||||
|
}
|
||||||
|
WriteString(str: string)
|
||||||
|
{
|
||||||
|
this.dataList.push(str);
|
||||||
|
}
|
||||||
|
ReadString(): string
|
||||||
|
{
|
||||||
|
let str = this.dataList[this.readIndex] as string;
|
||||||
|
this.readIndex++;
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
WriteObject(obj: CADObject)
|
||||||
|
{
|
||||||
|
if (!obj)
|
||||||
|
{
|
||||||
|
this.Write("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let tempFile = new CADFile();
|
||||||
|
tempFile.WriteString(obj.constructor.name);
|
||||||
|
obj.WriteFile(tempFile);
|
||||||
|
this.Write(tempFile.Data);
|
||||||
|
tempFile.Destroy();//GC
|
||||||
|
}
|
||||||
|
ReadObject(db: Database, obj?: CADObject): CADObject
|
||||||
|
{
|
||||||
|
let data = this.Read();
|
||||||
|
let tempFile = new CADFile();
|
||||||
|
tempFile.Data = data;
|
||||||
|
|
||||||
|
let className = tempFile.ReadString();
|
||||||
|
if (className)
|
||||||
|
{
|
||||||
|
if (!obj)
|
||||||
|
{
|
||||||
|
obj = CADFactory.CreateObject(className);
|
||||||
|
obj.SetDefaultDb(db);
|
||||||
|
}
|
||||||
|
obj.ReadFile(tempFile);
|
||||||
|
tempFile.Destroy();
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Write(data: any)
|
||||||
|
{
|
||||||
|
this.dataList.push(data);
|
||||||
|
}
|
||||||
|
Read(): any
|
||||||
|
{
|
||||||
|
let data = this.dataList[this.readIndex];
|
||||||
|
this.readIndex++;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
ToString()
|
||||||
|
{
|
||||||
|
return JSON.stringify(this.dataList);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,179 @@
|
|||||||
|
import { Factory } from './CADFactory';
|
||||||
|
import { CADFile } from './CADFile';
|
||||||
|
import { CommandHistoryRecord } from './CommandHistoryRecord';
|
||||||
|
import { Database } from './Database';
|
||||||
|
import { ObjectId } from './ObjectId';
|
||||||
|
|
||||||
|
export abstract class CADObject
|
||||||
|
{
|
||||||
|
//对象被彻底遗弃
|
||||||
|
GoodBye(): any
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------DB-------------------------
|
||||||
|
protected _db: Database;
|
||||||
|
get Db(): Database
|
||||||
|
{
|
||||||
|
return this._db;
|
||||||
|
}
|
||||||
|
|
||||||
|
//对象在加入数据库时,必须指定一个源数据库,否则无法读取引用id.
|
||||||
|
SetDefaultDb(db: Database)
|
||||||
|
{
|
||||||
|
if (!this._db)
|
||||||
|
this._db = db;
|
||||||
|
else
|
||||||
|
console.warn("警告:同一个对象无法重复设置默认db.");
|
||||||
|
}
|
||||||
|
|
||||||
|
//private 私有的方法,暴露给Db的添加对象,方法使用.
|
||||||
|
//只用对象加入到db中,我们才初始化ObjectId.
|
||||||
|
//从db池中分配id给自身使用. 除非你创建对象往db里面加,否则不要调用该方法
|
||||||
|
InitObjectId(db: Database)
|
||||||
|
{
|
||||||
|
if (!this._db)
|
||||||
|
{
|
||||||
|
this._db = db;
|
||||||
|
this.objectId = db.AllocateId(this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
console.warn("同一个对象无法重复设置到数据库中!");
|
||||||
|
}
|
||||||
|
//-------------------------DB End-------------------------
|
||||||
|
|
||||||
|
// -------------------------isErase-------------------------
|
||||||
|
protected _isErase: boolean = false;
|
||||||
|
get IsErase(): boolean
|
||||||
|
{
|
||||||
|
return this._isErase;
|
||||||
|
}
|
||||||
|
Erase(isErase: boolean = true)
|
||||||
|
{
|
||||||
|
this._isErase = isErase;
|
||||||
|
}
|
||||||
|
//-------------------------isErase End-------------------------
|
||||||
|
|
||||||
|
// -------------------------id-------------------------
|
||||||
|
protected objectId: ObjectId;
|
||||||
|
|
||||||
|
get Id(): ObjectId
|
||||||
|
{
|
||||||
|
return this.objectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------id End-------------------------
|
||||||
|
|
||||||
|
// -------------------------File-------------------------
|
||||||
|
|
||||||
|
//对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化
|
||||||
|
//对象从文件中读取数据,初始化自身
|
||||||
|
ReadFile(file: CADFile)
|
||||||
|
{
|
||||||
|
let ver = file.Read();
|
||||||
|
//write Id;
|
||||||
|
this.objectId = this.ReadObjectId(file);
|
||||||
|
if (this.objectId)
|
||||||
|
{
|
||||||
|
this.objectId.Object = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//对象将自身数据写入到文件.
|
||||||
|
WriteFile(file: CADFile)
|
||||||
|
{
|
||||||
|
file.Write(1);
|
||||||
|
this.WriteObjectId(file, this.objectId);
|
||||||
|
}
|
||||||
|
//局部撤销
|
||||||
|
ApplyPartialUndo(undoData: CADObject)
|
||||||
|
{
|
||||||
|
if (undoData instanceof AllObjectData)
|
||||||
|
{
|
||||||
|
undoData.file.Reset();
|
||||||
|
this.ReadFile(undoData.file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//撤销所保存的位置
|
||||||
|
UndoRecord(): CommandHistoryRecord
|
||||||
|
{
|
||||||
|
if (this._db)
|
||||||
|
return this._db.hm.UndoData;
|
||||||
|
}
|
||||||
|
//写入所有的对象数据 以便还原对象
|
||||||
|
protected WriteAllObjectRecord()
|
||||||
|
{
|
||||||
|
let undoData = this.UndoRecord();
|
||||||
|
if (undoData)
|
||||||
|
undoData.CreateObjectHistory(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
//复制出一个实体,所有的关联引用全部失效,如有需要,请重新关联.
|
||||||
|
Clone(): CADObject
|
||||||
|
{
|
||||||
|
let file = new CADFile();
|
||||||
|
file.WriteObject(this);
|
||||||
|
return file.ReadObject(undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------File End-------------------------
|
||||||
|
|
||||||
|
protected WriteObjectId(file: CADFile, id: ObjectId)
|
||||||
|
{
|
||||||
|
if (id)
|
||||||
|
{
|
||||||
|
file.Write(id.Index);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
file.Write(-1);
|
||||||
|
}
|
||||||
|
protected ReadObjectId(file: CADFile): ObjectId
|
||||||
|
{
|
||||||
|
let index = file.Read();
|
||||||
|
if (index >= 0 && this._db)
|
||||||
|
{
|
||||||
|
return ObjectId.Create(this._db, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存对象创建或者修改时的所有数据记录
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @class AllObjectData
|
||||||
|
* @extends {IFileReadWrite}
|
||||||
|
*/
|
||||||
|
@Factory
|
||||||
|
export class AllObjectData extends CADObject
|
||||||
|
{
|
||||||
|
file: CADFile;
|
||||||
|
constructor(obj?: CADObject)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
this.file = new CADFile();
|
||||||
|
if (obj)
|
||||||
|
obj.WriteFile(this.file);
|
||||||
|
}
|
||||||
|
|
||||||
|
//#region -------------------------File-------------------------
|
||||||
|
//对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化
|
||||||
|
|
||||||
|
//对象从文件中读取数据,初始化自身
|
||||||
|
ReadFile(file: CADFile)
|
||||||
|
{
|
||||||
|
super.ReadFile(file);
|
||||||
|
let ver = file.Read();
|
||||||
|
let data = file.Read();
|
||||||
|
this.file.Data = data;
|
||||||
|
}
|
||||||
|
//对象将自身数据写入到文件.
|
||||||
|
WriteFile(file: CADFile)
|
||||||
|
{
|
||||||
|
super.WriteFile(file);
|
||||||
|
file.Write(1);
|
||||||
|
file.Write(this.file.Data);
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,123 @@
|
|||||||
|
import { EllipseCurve, Geometry, Vector3 } from 'three';
|
||||||
|
import * as THREE from 'three';
|
||||||
|
|
||||||
|
import { ColorMaterial } from '../Common/ColorPalette';
|
||||||
|
import { RenderType } from '../GraphicsSystem/Enum';
|
||||||
|
import { Factory } from './CADFactory';
|
||||||
|
import { CADFile } from './CADFile';
|
||||||
|
import { Entity } from './Entity';
|
||||||
|
|
||||||
|
|
||||||
|
@Factory
|
||||||
|
export class Circle extends Entity
|
||||||
|
{
|
||||||
|
constructor(center?: Vector3, radius?: number)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
this.m_Center = center ? center.clone() : new Vector3();
|
||||||
|
this.m_Radius = radius ? radius : 1e-6;
|
||||||
|
}
|
||||||
|
private m_Center: Vector3;
|
||||||
|
private m_Radius: number;
|
||||||
|
get Center()
|
||||||
|
{
|
||||||
|
return this.m_Center.clone();
|
||||||
|
}
|
||||||
|
set Center(v: Vector3)
|
||||||
|
{
|
||||||
|
this.WriteAllObjectRecord();
|
||||||
|
this.m_Center.copy(v);
|
||||||
|
}
|
||||||
|
get Radius()
|
||||||
|
{
|
||||||
|
return this.m_Radius;
|
||||||
|
}
|
||||||
|
set Radius(v: number)
|
||||||
|
{
|
||||||
|
this.WriteAllObjectRecord();
|
||||||
|
this.m_Radius = v;
|
||||||
|
this.Update();
|
||||||
|
}
|
||||||
|
Draw(renderType: RenderType): THREE.Object3D
|
||||||
|
{
|
||||||
|
let obj = super.Draw(renderType);
|
||||||
|
if (obj) return obj;
|
||||||
|
|
||||||
|
let curve = new EllipseCurve(
|
||||||
|
this.m_Center.x, this.m_Center.y, // ax, aY
|
||||||
|
this.m_Radius, this.m_Radius, // xRadius, yRadius
|
||||||
|
0, 2 * Math.PI, // aStartAngle, aEndAngle
|
||||||
|
false, // aClockwise
|
||||||
|
0 // aRotation
|
||||||
|
);
|
||||||
|
let geometry = new Geometry().setFromPoints(curve.getPoints(60));
|
||||||
|
let circleObj = new THREE.Line(geometry, ColorMaterial.GetLineMaterial(this.m_Color));
|
||||||
|
this.m_DrawEntity.set(renderType, circleObj);
|
||||||
|
circleObj.userData = this;
|
||||||
|
return circleObj;
|
||||||
|
}
|
||||||
|
Update()
|
||||||
|
{
|
||||||
|
for (let [, obj] of this.m_DrawEntity)
|
||||||
|
{
|
||||||
|
let geo = obj["geometry"] as Geometry;
|
||||||
|
|
||||||
|
let curve = new EllipseCurve(
|
||||||
|
this.m_Center.x, this.m_Center.y, // ax, aY
|
||||||
|
this.m_Radius, this.m_Radius, // xRadius, yRadius
|
||||||
|
0, 2 * Math.PI, // aStartAngle, aEndAngle
|
||||||
|
false, // aClockwise
|
||||||
|
0 // aRotation
|
||||||
|
);
|
||||||
|
|
||||||
|
geo.setFromPoints(curve.getPoints(60));
|
||||||
|
|
||||||
|
geo.verticesNeedUpdate = true;
|
||||||
|
geo.computeBoundingSphere();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GetStretchPoints(): Array<Vector3>
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
this.m_Center.clone().add(new Vector3(0, this.m_Radius)),
|
||||||
|
this.m_Center.clone().add(new Vector3(0, -this.m_Radius)),
|
||||||
|
this.m_Center.clone().add(new Vector3(-this.m_Radius, 0)),
|
||||||
|
this.m_Center.clone().add(new Vector3(this.m_Radius, 0)),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
MoveStretchPoints(indexList: Array<number>, vec: Vector3)
|
||||||
|
{
|
||||||
|
let pts = this.GetStretchPoints()
|
||||||
|
if (indexList.length > 0)
|
||||||
|
{
|
||||||
|
let p = pts[indexList[0]];
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
p.add(vec);
|
||||||
|
this.Radius = p.distanceTo(this.m_Center);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//#region -------------------------File-------------------------
|
||||||
|
//对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化
|
||||||
|
|
||||||
|
//对象从文件中读取数据,初始化自身
|
||||||
|
ReadFile(file: CADFile)
|
||||||
|
{
|
||||||
|
super.ReadFile(file);
|
||||||
|
let ver = file.Read();
|
||||||
|
this.m_Center.fromArray(file.Read());
|
||||||
|
this.m_Radius = file.Read();
|
||||||
|
}
|
||||||
|
//对象将自身数据写入到文件.
|
||||||
|
WriteFile(file: CADFile)
|
||||||
|
{
|
||||||
|
super.WriteFile(file);
|
||||||
|
file.Write(1);
|
||||||
|
file.Write(this.m_Center.toArray());
|
||||||
|
file.Write(this.m_Radius);
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
}
|
@ -0,0 +1,133 @@
|
|||||||
|
import { Factory } from './CADFactory';
|
||||||
|
import { CADFile } from './CADFile';
|
||||||
|
import { CADObject } from './CADObject';
|
||||||
|
import { HistorycRecord } from './HistorycRecord';
|
||||||
|
import { ObjectAllDataHistoryRecord } from './ObjectAllDataHistoryRecord';
|
||||||
|
import { ObjectId } from './ObjectId';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 命令的历史记录
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @class CommandHistoryRecord
|
||||||
|
* @extends {DbObject}
|
||||||
|
*/
|
||||||
|
@Factory
|
||||||
|
export class CommandHistoryRecord extends CADObject
|
||||||
|
{
|
||||||
|
constructor(cmdName?: string)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
this.commandName = cmdName;
|
||||||
|
}
|
||||||
|
//命令名称
|
||||||
|
private commandName: string;
|
||||||
|
//历史记录表
|
||||||
|
private historyCol = new Map<ObjectId, HistorycRecord[]>();
|
||||||
|
|
||||||
|
get HistoryList(): Map<ObjectId, HistorycRecord[]>
|
||||||
|
{
|
||||||
|
return this.historyCol;
|
||||||
|
}
|
||||||
|
private GetObjectHistoryList(id: ObjectId)
|
||||||
|
{
|
||||||
|
if (!this.historyCol.has(id))
|
||||||
|
{
|
||||||
|
this.historyCol.set(id, []);
|
||||||
|
}
|
||||||
|
return this.historyCol.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
EndCommand()
|
||||||
|
{
|
||||||
|
for (let [id, recs] of this.historyCol)
|
||||||
|
{
|
||||||
|
let rec = this.GetObjectAllDataRecord(recs);
|
||||||
|
if (rec)
|
||||||
|
{
|
||||||
|
rec.WriteRedo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//获得对象的记录
|
||||||
|
GetObjectAllDataRecord(historyList: HistorycRecord[]): ObjectAllDataHistoryRecord
|
||||||
|
{
|
||||||
|
if (historyList.length > 0)
|
||||||
|
{
|
||||||
|
let rec = historyList[historyList.length - 1];
|
||||||
|
if (rec instanceof ObjectAllDataHistoryRecord)
|
||||||
|
{
|
||||||
|
return rec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//对象写入数据
|
||||||
|
WriteObjectHistoryPath(obj: CADObject, history: HistorycRecord)
|
||||||
|
{
|
||||||
|
let his = this.GetObjectHistoryList(obj.Id);
|
||||||
|
if (this.GetObjectAllDataRecord(his))
|
||||||
|
{
|
||||||
|
//console.log("优化掉重复的全部数据");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (history instanceof ObjectAllDataHistoryRecord)
|
||||||
|
{
|
||||||
|
history.WriteUndo();
|
||||||
|
}
|
||||||
|
his.push(history);
|
||||||
|
}
|
||||||
|
CreateObjectHistory(obj: CADObject): ObjectAllDataHistoryRecord
|
||||||
|
{
|
||||||
|
if (!obj.Id)
|
||||||
|
{
|
||||||
|
console.warn("错误!CreateObjectHistory");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let rec = new ObjectAllDataHistoryRecord(obj.Id);
|
||||||
|
this.WriteObjectHistoryPath(obj, rec);
|
||||||
|
return rec;
|
||||||
|
}
|
||||||
|
|
||||||
|
//#region -------------------------File-------------------------
|
||||||
|
//对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化
|
||||||
|
|
||||||
|
|
||||||
|
//对象从文件中读取数据,初始化自身
|
||||||
|
ReadFile(file: CADFile)
|
||||||
|
{
|
||||||
|
let ver = file.Read();
|
||||||
|
this.commandName = file.Read();
|
||||||
|
let cout = file.Read();
|
||||||
|
|
||||||
|
this.historyCol.clear();
|
||||||
|
for (let i = 0; i < cout; i++)
|
||||||
|
{
|
||||||
|
let id = this.ReadObjectId(file);
|
||||||
|
let length = file.Read();
|
||||||
|
let recs = [];
|
||||||
|
this.historyCol.set(id, recs);
|
||||||
|
for (let j = 0; j < length; j++)
|
||||||
|
{
|
||||||
|
let rec = file.ReadObject(this._db);
|
||||||
|
recs.push(rec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//对象将自身数据写入到文件.
|
||||||
|
WriteFile(file: CADFile)
|
||||||
|
{
|
||||||
|
file.Write(1);
|
||||||
|
file.Write(this.commandName);
|
||||||
|
file.Write(this.historyCol.size);
|
||||||
|
for (let [id, recs] of this.historyCol)
|
||||||
|
{
|
||||||
|
file.Write(id.Index);
|
||||||
|
file.Write(recs.length);
|
||||||
|
for (let rec of recs)
|
||||||
|
{
|
||||||
|
file.WriteObject(rec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
import { Factory } from './CADFactory';
|
||||||
|
import { CADFile } from './CADFile';
|
||||||
|
import { CADObject } from './CADObject';
|
||||||
|
import { Database } from './Database';
|
||||||
|
|
||||||
|
@Factory
|
||||||
|
export class CreateObjectData extends CADObject
|
||||||
|
{
|
||||||
|
private cadFile: CADFile;
|
||||||
|
constructor(obj?: CADObject)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
this.cadFile = new CADFile();
|
||||||
|
if (obj)
|
||||||
|
this.cadFile.WriteObject(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
getObject(db: Database): CADObject
|
||||||
|
{
|
||||||
|
this.cadFile.Reset();
|
||||||
|
let obj = this.cadFile.ReadObject(db);
|
||||||
|
this.cadFile.Reset();
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
//#region -----------------------------File-----------------------------
|
||||||
|
//对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化
|
||||||
|
//对象从文件中读取数据,初始化自身
|
||||||
|
ReadFile(file: CADFile)
|
||||||
|
{
|
||||||
|
file.Read();//ver;
|
||||||
|
let data = file.Read();
|
||||||
|
this.cadFile.Data = data;
|
||||||
|
}
|
||||||
|
//对象将自身数据写入到文件.
|
||||||
|
WriteFile(file: CADFile)
|
||||||
|
{
|
||||||
|
file.Write(1);//ver
|
||||||
|
file.Write(this.cadFile.Data);
|
||||||
|
}
|
||||||
|
//#endregion -----------------------------File End-----------------------------
|
||||||
|
}
|
||||||
|
|
@ -1,143 +1,97 @@
|
|||||||
import * as mst from 'mobx-state-tree';
|
import { BlockTableRecord } from './BlockTableRecord';
|
||||||
import { IJsonPatch } from 'mobx-state-tree';
|
import { Factory } from './CADFactory';
|
||||||
|
import { CADFile } from './CADFile';
|
||||||
|
import { CADObject } from './CADObject';
|
||||||
|
import { HistoricManage } from './HistoricManage';
|
||||||
|
import { MaerialTableRecord } from './MaerialTableRecord';
|
||||||
|
import { ObjectId } from './ObjectId';
|
||||||
|
|
||||||
import { ed } from '../ApplicationServices/Application';
|
@Factory
|
||||||
import { Entity } from './Entity';
|
|
||||||
import { DataBaseData, IDataBaseData, ISnapDatabaseData } from './EntityData';
|
|
||||||
import { MaterialDictionary } from './MaterialDictionary';
|
|
||||||
import { Transaction } from './Transaction';
|
|
||||||
|
|
||||||
//材质字典
|
|
||||||
/**
|
|
||||||
* 图形数据集合,一旦图形加入到集合,那么图形由集合控制.
|
|
||||||
* 并且View层可以通过该集合渲染出图形
|
|
||||||
* 集合包括下列数据
|
|
||||||
* -1.图形数据(id列表)只有Id列表.
|
|
||||||
* -2.字典数据(id列表)只有列表
|
|
||||||
* -3.....等.
|
|
||||||
*
|
|
||||||
* @export
|
|
||||||
* @class Database
|
|
||||||
*/
|
|
||||||
export class Database
|
export class Database
|
||||||
{
|
{
|
||||||
m_Data: IDataBaseData
|
id: ObjectId;
|
||||||
//场景
|
hm: HistoricManage;
|
||||||
m_EntityCollection: Map<number, Entity> = new Map<number, Entity>();//图形集合
|
//块表记录
|
||||||
|
blockTableCol: BlockTableRecord[];
|
||||||
|
//模型空间
|
||||||
|
ModelSpace: BlockTableRecord;
|
||||||
|
//材质字典...
|
||||||
|
MaterialDict: MaerialTableRecord;
|
||||||
|
|
||||||
|
private idCout = -1;
|
||||||
|
private idMap = new Map<number, ObjectId>();
|
||||||
|
|
||||||
m_MaterialDictionary: MaterialDictionary;
|
|
||||||
constructor()
|
constructor()
|
||||||
{
|
{
|
||||||
this.initData();
|
this.id = ObjectId.Create(this, -100);
|
||||||
}
|
|
||||||
initData()
|
|
||||||
{
|
|
||||||
this.m_MaterialDictionary = new MaterialDictionary();
|
|
||||||
|
|
||||||
this.m_Data = DataBaseData.create();
|
this.ModelSpace = new BlockTableRecord();
|
||||||
mst.onPatch(this.m_Data, (patch: IJsonPatch, reversePatch: IJsonPatch) =>
|
this.ModelSpace.InitObjectId(this);
|
||||||
{
|
this.MaterialDict = new MaerialTableRecord();
|
||||||
if (patch.op == "add")
|
this.MaterialDict.InitObjectId(this);
|
||||||
{
|
|
||||||
this.addEntityId(patch.value);
|
|
||||||
}
|
|
||||||
else if (patch.op == "remove")
|
|
||||||
{
|
|
||||||
this.removeEntityId(reversePatch.value);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
dataIn(data: ISnapDatabaseData)
|
this.hm = new HistoricManage();
|
||||||
{
|
this.hm.SetDefaultDb(this);
|
||||||
mst.applySnapshot(this.m_Data, data);
|
|
||||||
}
|
|
||||||
dataOut(): ISnapDatabaseData
|
|
||||||
{
|
|
||||||
return mst.getSnapshot(this.m_Data);
|
|
||||||
}
|
|
||||||
|
|
||||||
//添加图元到数据对象
|
|
||||||
appendEntity(ent: Entity)
|
|
||||||
{
|
|
||||||
if (ent.objectId != 0)
|
|
||||||
{
|
|
||||||
console.warn("已经分配ID的图形不允许再次加入数据库!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ent.m_Db = this;
|
|
||||||
ent.objectId = this.m_Data.allocateId();
|
|
||||||
if (ent.objectId != this.m_EntityCollection.size)
|
|
||||||
{
|
|
||||||
for (var id = ent.objectId; id < this.m_EntityCollection.size; id++)
|
|
||||||
{
|
|
||||||
this.disposeEntity(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.m_EntityCollection.set(ent.objectId, ent);
|
|
||||||
this.m_Data.addEntity(ent.objectId);
|
|
||||||
ed.UpdateScreen();
|
|
||||||
}
|
}
|
||||||
getEntity(id: number): Entity
|
Destroy()
|
||||||
{
|
{
|
||||||
if (this.m_EntityCollection.has(id))
|
this.idMap.clear();
|
||||||
{
|
|
||||||
return this.m_EntityCollection.get(id);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addEntityId(id: number)
|
FileWrite(): CADFile
|
||||||
{
|
{
|
||||||
|
let file = new CADFile();
|
||||||
|
file.Write(1);//ver;
|
||||||
|
file.Write(this.idCout);
|
||||||
|
file.WriteObject(this.ModelSpace);
|
||||||
|
file.WriteObject(this.MaterialDict);
|
||||||
|
this.hm.WriteFile(file);
|
||||||
|
return file;
|
||||||
}
|
}
|
||||||
//删除
|
FileRead(file: CADFile)
|
||||||
removeEntityId(ent: number)
|
|
||||||
{
|
{
|
||||||
|
this.Destroy();
|
||||||
|
let ver = file.Read();
|
||||||
|
this.idCout = file.Read();
|
||||||
|
file.ReadObject(this, this.ModelSpace);
|
||||||
|
file.ReadObject(this, this.MaterialDict);
|
||||||
|
this.hm.ReadFile(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
disposeEntity(id: number)
|
//创建一个id,自动递增它的索引号,并且会自动加入到db的id列表中.
|
||||||
|
AllocateId(obj: CADObject): ObjectId
|
||||||
{
|
{
|
||||||
let ent = this.getEntity(id);
|
if (obj.Db.id === this.id)
|
||||||
if (ent)
|
// if (obj.Db === this)
|
||||||
{
|
{
|
||||||
this.m_EntityCollection.delete(id);
|
this.idCout++;
|
||||||
|
let id = ObjectId.Create(this, this.idCout);
|
||||||
|
id.Object = obj;
|
||||||
|
return id;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
console.warn("警告:对象不属于该数据库!");
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
private 请不要调用该方法,只暴露给 ObjectId使用.
|
||||||
|
|
||||||
/**
|
获得指定索引的id, 注意该id可能为空, 如果需要创建, 请使用 ObjectId.Create,如果需要自动分配,请使用,AllocateId
|
||||||
* 返回所有的id列表
|
*/
|
||||||
*
|
GetObjectId(index: number): ObjectId
|
||||||
* @returns {Array<number>}
|
|
||||||
* @memberof Database
|
|
||||||
*/
|
|
||||||
getObjectIdCollection(): Array<number>
|
|
||||||
{
|
{
|
||||||
return this.m_Data.idColl;
|
return this.idMap.get(index);
|
||||||
}
|
|
||||||
getEntityCollection(): Array<Entity>
|
|
||||||
{
|
|
||||||
let res = []
|
|
||||||
this.m_EntityCollection.forEach((ent, id) =>
|
|
||||||
{
|
|
||||||
res.push(ent);
|
|
||||||
})
|
|
||||||
return res;
|
|
||||||
// return this.m_Data.idColl.map(id =>
|
|
||||||
// {
|
|
||||||
// return this.getEntity(id);
|
|
||||||
// }).filter(e =>
|
|
||||||
// {
|
|
||||||
// return e
|
|
||||||
// })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StartTransaction(): Transaction
|
|
||||||
{
|
|
||||||
let ts = new Transaction(this);
|
|
||||||
return ts;
|
|
||||||
}
|
|
||||||
CommitTransaction()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
private 请不要调用该方法,只暴露给 ObjectId使用.
|
||||||
|
|
||||||
|
在id池中加入新建的id. 该方法暴露给 Objectid.Cretes使用.
|
||||||
|
*/
|
||||||
|
SetObjectId(index: number, id: ObjectId)
|
||||||
|
{
|
||||||
|
if (this.idMap.has(index))
|
||||||
|
console.warn("警告:尝试加入已经存在的id!");
|
||||||
|
this.idMap.set(index, id);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,314 +1,101 @@
|
|||||||
import { autorun } from 'mobx';
|
//所有图元的基类
|
||||||
import * as mst from 'mobx-state-tree';
|
|
||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import { Vector3 } from 'three';
|
|
||||||
|
|
||||||
import { Move } from '../Geometry/GeUtils';
|
|
||||||
import { OBB } from '../Geometry/OBB/obb';
|
|
||||||
import { RenderType } from '../GraphicsSystem/Enum';
|
import { RenderType } from '../GraphicsSystem/Enum';
|
||||||
import { Database } from './Database';
|
import { Factory } from './CADFactory';
|
||||||
import { EntityData, IEntityData, ILineData, iSnapshotEntityData, LineData } from './EntityData';
|
import { CADFile } from './CADFile';
|
||||||
|
import { CADObject } from './CADObject';
|
||||||
|
import { ObjectId } from './ObjectId';
|
||||||
|
|
||||||
export class Entity
|
@Factory
|
||||||
|
export class Entity extends CADObject
|
||||||
{
|
{
|
||||||
/**
|
protected m_DrawEntity = new Map<RenderType, THREE.Object3D>();
|
||||||
* 图形所属Db
|
//材质id
|
||||||
*
|
protected m_MaterialId: ObjectId;
|
||||||
* @type {Database}
|
protected m_Color: number = 7;
|
||||||
* @memberof Entity
|
|
||||||
*/
|
|
||||||
m_Db: Database;
|
|
||||||
|
|
||||||
|
set ColorIndex(v: number)
|
||||||
/**
|
|
||||||
* 图形数据
|
|
||||||
*
|
|
||||||
* @protected
|
|
||||||
* @type {IEntityData}
|
|
||||||
* @memberof Entity
|
|
||||||
*/
|
|
||||||
protected m_Data: IEntityData;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 缓存图形集合.
|
|
||||||
*
|
|
||||||
* @protected
|
|
||||||
* @type {Map<RenderType, THREE.Object3D>}
|
|
||||||
* @memberof Entity
|
|
||||||
*/
|
|
||||||
protected m_DrawEntity: Map<RenderType, THREE.Object3D> = new Map<RenderType, THREE.Object3D>();
|
|
||||||
|
|
||||||
constructor()
|
|
||||||
{
|
|
||||||
this.initData();
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param data 快照数据 用于还原
|
|
||||||
*/
|
|
||||||
dataIn(data: iSnapshotEntityData)
|
|
||||||
{
|
|
||||||
mst.applySnapshot(this.m_Data, data);
|
|
||||||
}
|
|
||||||
dataOut(): iSnapshotEntityData
|
|
||||||
{
|
{
|
||||||
return mst.getSnapshot(this.m_Data);
|
this.m_Color = v;
|
||||||
|
this.Update();
|
||||||
}
|
}
|
||||||
|
get ColorIndex(): number
|
||||||
Draw(renderType: RenderType): THREE.Object3D
|
|
||||||
{
|
{
|
||||||
return null;
|
return this.m_Color;
|
||||||
}
|
}
|
||||||
|
|
||||||
get objectId(): number
|
|
||||||
{
|
|
||||||
return this.m_Data.objectId;
|
|
||||||
}
|
|
||||||
set objectId(id: number)
|
|
||||||
{
|
|
||||||
this.m_Data.setObjectId(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
get Size()
|
//绘制一个threeJs对象.
|
||||||
{
|
Draw(renderType: RenderType = RenderType.Wireframe): THREE.Object3D
|
||||||
return this.m_Data.getSize();
|
|
||||||
}
|
|
||||||
set Size(v: THREE.Vector3)
|
|
||||||
{
|
|
||||||
this.m_Data.setSize(v.x, v.y, v.z);
|
|
||||||
}
|
|
||||||
initData()
|
|
||||||
{
|
|
||||||
this.m_Data = EntityData.create();
|
|
||||||
}
|
|
||||||
erase(isErase)
|
|
||||||
{
|
|
||||||
this.m_Data.setErase(isErase);
|
|
||||||
}
|
|
||||||
|
|
||||||
getBox(): THREE.Box3
|
|
||||||
{
|
|
||||||
let box = new THREE.Box3();
|
|
||||||
// box.setFromObject(this.m_ThreeObj);
|
|
||||||
return box;
|
|
||||||
}
|
|
||||||
|
|
||||||
getStretchPoints(): Array<THREE.Vector3>
|
|
||||||
{
|
{
|
||||||
return []
|
if (this.m_DrawEntity && this.m_DrawEntity.has(renderType))
|
||||||
|
{
|
||||||
|
return this.m_DrawEntity.get(renderType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getOBB(): OBB
|
//你必须重载该方法来更新绘制,在撤销重做时会自动调用该方法.
|
||||||
|
Update()
|
||||||
{
|
{
|
||||||
let obb = new OBB();
|
|
||||||
let size = this.Size;
|
|
||||||
// obb.m_CoordinateSystem.copyForm(this.m_ThreeObj.matrix);
|
|
||||||
|
|
||||||
obb.m_CoordinateSystem.m_Postion.sub(obb.m_CoordinateSystem.m_xAxis.clone().multiplyScalar(size.x * 0.5));
|
|
||||||
obb.m_CoordinateSystem.m_Postion.sub(obb.m_CoordinateSystem.m_yAxis.clone().multiplyScalar(size.y * 0.5));
|
|
||||||
obb.m_CoordinateSystem.m_Postion.sub(obb.m_CoordinateSystem.m_zAxis.clone().multiplyScalar(size.z * 0.5));
|
|
||||||
obb.halfSizes.copy(size)
|
|
||||||
return obb;
|
|
||||||
}
|
}
|
||||||
applyMatrix4(mat: THREE.Matrix4)
|
GoodBye()
|
||||||
{
|
{
|
||||||
this.m_DrawEntity.forEach(e =>
|
for (let [, obj] of this.m_DrawEntity)
|
||||||
{
|
{
|
||||||
e.applyMatrix(mat);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
setIsSelct(bool: boolean)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Curve extends Entity
|
let geo = obj['Geometry']
|
||||||
{
|
if (geo && geo instanceof THREE.Geometry)
|
||||||
constructor()
|
{
|
||||||
{
|
geo.dispose();
|
||||||
super();
|
}
|
||||||
}
|
obj.parent.remove(obj);
|
||||||
}
|
|
||||||
|
|
||||||
export class Line extends Curve
|
|
||||||
{
|
|
||||||
|
|
||||||
constructor(startPt?: THREE.Vector3, endPt?: THREE.Vector3)
|
|
||||||
{
|
|
||||||
super();
|
|
||||||
let data = <ILineData>this.m_Data;
|
|
||||||
|
|
||||||
if (startPt)
|
|
||||||
{
|
|
||||||
data.setStartPoint(startPt);
|
|
||||||
if (endPt)
|
|
||||||
data.setEndPoint(endPt);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
initData()
|
Erase(isErase: boolean = true)
|
||||||
{
|
{
|
||||||
this.m_Data = LineData.create();
|
super.Erase(isErase);
|
||||||
}
|
if (isErase)
|
||||||
private getData(): ILineData
|
|
||||||
{
|
|
||||||
return <ILineData>this.m_Data;
|
|
||||||
}
|
|
||||||
Draw(renderType: RenderType): THREE.Object3D
|
|
||||||
{
|
|
||||||
if (this.m_DrawEntity.has(renderType))
|
|
||||||
{
|
{
|
||||||
return this.m_DrawEntity.get(renderType);
|
for (let [, en] of this.m_DrawEntity)
|
||||||
|
{
|
||||||
|
en.visible = !isErase;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//创建几何体
|
|
||||||
var geometry = new THREE.Geometry();
|
|
||||||
let sp = this.getData().StartPoint;
|
|
||||||
let ep = this.getData().EndPoint;
|
|
||||||
geometry.vertices.push(sp);
|
|
||||||
geometry.vertices.push(ep);
|
|
||||||
|
|
||||||
//TODO:创建材质..明显重复的
|
|
||||||
var material = new THREE.LineBasicMaterial();
|
|
||||||
let threeObject: THREE.Object3D = new THREE.Line(geometry, material);
|
|
||||||
|
|
||||||
this.m_DrawEntity.set(renderType, threeObject);
|
|
||||||
|
|
||||||
//事件注入.
|
|
||||||
autorun(() =>
|
|
||||||
{
|
|
||||||
sp.copy(this.getData().StartPoint);
|
|
||||||
ep.copy(this.getData().EndPoint);
|
|
||||||
geometry.verticesNeedUpdate = true;
|
|
||||||
geometry.computeBoundingSphere();
|
|
||||||
})
|
|
||||||
return threeObject;
|
|
||||||
}
|
|
||||||
GetGripPoints(): Array<Vector3>
|
|
||||||
{
|
|
||||||
return [this.StartPoint, this.EndPoint];
|
|
||||||
}
|
|
||||||
getStretchPoints(): Array<THREE.Vector3>
|
|
||||||
{
|
|
||||||
return [this.StartPoint, this.EndPoint];
|
|
||||||
}
|
|
||||||
get StartPoint(): THREE.Vector3
|
|
||||||
{
|
|
||||||
return (<ILineData>this.m_Data).StartPoint;
|
|
||||||
}
|
}
|
||||||
get EndPoint(): THREE.Vector3
|
|
||||||
{
|
|
||||||
return (<ILineData>this.m_Data).EndPoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
//http://jsfiddle.net/hjx3rLmt/1/
|
|
||||||
setStartPoint(pt: THREE.Vector3)
|
|
||||||
{
|
|
||||||
this.getData().setStartPoint(pt);
|
|
||||||
}
|
|
||||||
setEndPoint(pt: THREE.Vector3)
|
|
||||||
{
|
|
||||||
this.getData().setEndPoint(pt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Circle extends Curve
|
GetStretchPoints(): Array<THREE.Vector3>
|
||||||
{
|
|
||||||
m_Radius: number;
|
|
||||||
m_Center: THREE.Vector3;
|
|
||||||
constructor(center: THREE.Vector3, radius: number)
|
|
||||||
{
|
{
|
||||||
super();
|
return []
|
||||||
this.m_Center = center;
|
|
||||||
this.m_Radius = radius;
|
|
||||||
}
|
}
|
||||||
set Center(v: THREE.Vector3)
|
MoveStretchPoints(indexList: Array<number>, vec: THREE.Vector3)
|
||||||
{
|
{
|
||||||
this.m_Center.copy(v);
|
|
||||||
this.m_DrawEntity.forEach(obj =>
|
|
||||||
{
|
|
||||||
let curve = new THREE.EllipseCurve(
|
|
||||||
this.m_Center.x, this.m_Center.y, // ax, aY
|
|
||||||
this.m_Radius, this.m_Radius, // xRadius, yRadius
|
|
||||||
0, 2 * Math.PI, // aStartAngle, aEndAngle
|
|
||||||
false, // aClockwise
|
|
||||||
0 // aRotation
|
|
||||||
);
|
|
||||||
|
|
||||||
let geometry = new THREE.Geometry().setFromPoints(curve.getPoints(50));
|
|
||||||
(<THREE.Line>obj).geometry = geometry;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
set Radius(r: number)
|
|
||||||
{
|
|
||||||
this.m_Radius = r;
|
|
||||||
this.m_DrawEntity.forEach(obj =>
|
|
||||||
{
|
|
||||||
(<THREE.Line>obj).geometry.dispose();
|
|
||||||
let curve = new THREE.EllipseCurve(
|
|
||||||
this.m_Center.x, this.m_Center.y, // ax, aY
|
|
||||||
this.m_Radius, this.m_Radius, // xRadius, yRadius
|
|
||||||
0, 2 * Math.PI, // aStartAngle, aEndAngle
|
|
||||||
false, // aClockwise
|
|
||||||
0 // aRotation
|
|
||||||
);
|
|
||||||
let geometry = new THREE.Geometry().setFromPoints(curve.getPoints(60));
|
|
||||||
(<THREE.Line>obj).geometry = geometry;
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Draw(renderType: RenderType = RenderType.Wireframe): THREE.Object3D
|
//#region -------------------------File-------------------------
|
||||||
{
|
|
||||||
if (this.m_DrawEntity.has(renderType))
|
|
||||||
{
|
|
||||||
return this.m_DrawEntity.get(renderType);
|
|
||||||
}
|
|
||||||
let curve = new THREE.EllipseCurve(
|
|
||||||
this.m_Center.x, this.m_Center.y, // ax, aY
|
|
||||||
this.m_Radius, this.m_Radius, // xRadius, yRadius
|
|
||||||
0, 2 * Math.PI, // aStartAngle, aEndAngle
|
|
||||||
false, // aClockwise
|
|
||||||
0 // aRotation
|
|
||||||
);
|
|
||||||
let geometry = new THREE.Geometry().setFromPoints(curve.getPoints(60));
|
|
||||||
var material = new THREE.LineBasicMaterial({ color: 0xff0000 });
|
|
||||||
var ellipse = new THREE.Line(geometry, material);
|
|
||||||
this.m_DrawEntity.set(renderType, ellipse);
|
|
||||||
return ellipse;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Solid3d extends Entity
|
//对象从文件中读取数据,初始化自身
|
||||||
{
|
ReadFile(file: CADFile)
|
||||||
constructor(len: number, wid: number, hei: number)
|
|
||||||
{
|
{
|
||||||
super();
|
let ver = file.Read();
|
||||||
this.Size = new THREE.Vector3(len, wid, hei);
|
super.ReadFile(file);
|
||||||
|
this.m_Color = file.Read();
|
||||||
}
|
}
|
||||||
applyMatrix4(mat: THREE.Matrix4)
|
//对象将自身数据写入到文件.
|
||||||
|
WriteFile(file: CADFile)
|
||||||
{
|
{
|
||||||
super.applyMatrix4(mat);
|
file.Write(1);
|
||||||
// Entity.prototype.applyMatrix4.call(this,mat)
|
super.WriteFile(file);
|
||||||
|
file.Write(this.m_Color);
|
||||||
}
|
}
|
||||||
Draw(renderType: RenderType): THREE.Object3D
|
//局部撤销
|
||||||
|
ApplyPartialUndo(undoData: CADObject)
|
||||||
{
|
{
|
||||||
if (this.m_DrawEntity.has(renderType))
|
super.ApplyPartialUndo(undoData);
|
||||||
{
|
this.Update();
|
||||||
return this.m_DrawEntity.get(renderType);
|
|
||||||
}
|
|
||||||
let geometry = new THREE.BoxGeometry(this.Size.x, this.Size.y, this.Size.z);
|
|
||||||
let mesh = new THREE.Mesh(geometry, new THREE.MeshNormalMaterial);
|
|
||||||
|
|
||||||
mesh.applyMatrix(Move(this.Size.clone().multiplyScalar(0.5)));
|
|
||||||
this.m_DrawEntity.set(renderType, mesh);
|
|
||||||
return mesh;
|
|
||||||
}
|
}
|
||||||
|
//#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Point extends Entity
|
|
||||||
{
|
|
||||||
m_Postion: THREE.Vector3 = new THREE.Vector3()
|
|
||||||
constructor()
|
|
||||||
{
|
|
||||||
super()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,123 +0,0 @@
|
|||||||
import * as mst from 'mobx-state-tree';
|
|
||||||
import * as THREE from "three";
|
|
||||||
const PointData = mst.types.optional(mst.types.array(mst.types.number), [0, 0, 0]);
|
|
||||||
type IPointData = typeof PointData.Type;
|
|
||||||
|
|
||||||
function toVec3(vec: IPointData): THREE.Vector3
|
|
||||||
{
|
|
||||||
return new THREE.Vector3(vec[0], vec[1], vec[2]);
|
|
||||||
}
|
|
||||||
export const EntityData = mst.types.model(
|
|
||||||
"Entity",
|
|
||||||
{
|
|
||||||
size: PointData,
|
|
||||||
isErase: false,
|
|
||||||
objectId: mst.types.optional(mst.types.number, 0)
|
|
||||||
})
|
|
||||||
.views(self =>
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
getSize(): THREE.Vector3
|
|
||||||
{
|
|
||||||
return toVec3(self.size);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.actions(self =>
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
setSize(x, y, z)
|
|
||||||
{
|
|
||||||
self.size.replace([x, y, z]);
|
|
||||||
},
|
|
||||||
setErase(isErase: boolean)
|
|
||||||
{
|
|
||||||
self.isErase = isErase;
|
|
||||||
},
|
|
||||||
afterCreate()
|
|
||||||
{
|
|
||||||
},
|
|
||||||
setObjectId(id: number)
|
|
||||||
{
|
|
||||||
self.objectId = id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
export type IEntityData = typeof EntityData.Type;
|
|
||||||
export type iSnapshotEntityData = typeof EntityData.SnapshotType;
|
|
||||||
|
|
||||||
|
|
||||||
export const CurveData = EntityData.named("Curve");
|
|
||||||
|
|
||||||
export const LineData = mst.types.compose(
|
|
||||||
CurveData,
|
|
||||||
mst.types.model(
|
|
||||||
{
|
|
||||||
startPoint: PointData,
|
|
||||||
entPoint: PointData
|
|
||||||
})
|
|
||||||
.views(self =>
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
get StartPoint(): THREE.Vector3
|
|
||||||
{
|
|
||||||
return toVec3(self.startPoint);
|
|
||||||
},
|
|
||||||
get EndPoint(): THREE.Vector3
|
|
||||||
{
|
|
||||||
return toVec3(self.entPoint)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.actions(self =>
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
setStartPoint(pt: THREE.Vector3)
|
|
||||||
{
|
|
||||||
self.startPoint.replace(pt.toArray());
|
|
||||||
},
|
|
||||||
setEndPoint(pt: THREE.Vector3)
|
|
||||||
{
|
|
||||||
self.entPoint.replace(pt.toArray());
|
|
||||||
},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
).named("Line");
|
|
||||||
|
|
||||||
export type ILineData = typeof LineData.Type;
|
|
||||||
|
|
||||||
export const DataBaseData = mst.types.model(
|
|
||||||
"Database",
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 图形列表 使用ID存储
|
|
||||||
*/
|
|
||||||
idColl: mst.types.optional(mst.types.array(mst.types.number), []),
|
|
||||||
/**
|
|
||||||
* 当前图元个数
|
|
||||||
*/
|
|
||||||
curLength: mst.types.optional(mst.types.number, 0)
|
|
||||||
})
|
|
||||||
.actions(self =>
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
addEntity(id: number)
|
|
||||||
{
|
|
||||||
self.idColl.push(id);
|
|
||||||
},
|
|
||||||
removeEntity(id: number)
|
|
||||||
{
|
|
||||||
self.idColl.remove(id);
|
|
||||||
},
|
|
||||||
allocateId(): number
|
|
||||||
{
|
|
||||||
self.curLength++;
|
|
||||||
return self.curLength
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
export type IDataBaseData = typeof DataBaseData.Type;
|
|
||||||
export type ISnapDatabaseData = typeof DataBaseData.SnapshotType;
|
|
@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
关于webCAD 文件系统的原型.
|
||||||
|
包括了对象的保存,撤销,还原.
|
||||||
|
|
||||||
|
对象ID更新 引用
|
||||||
|
|
||||||
|
关于对象的撤销和重做设计.
|
||||||
|
|
||||||
|
对象池
|
||||||
|
|
||||||
|
增量保存
|
||||||
|
|
||||||
|
1.应该能够新增和删除图元.
|
||||||
|
2.新增删除图元应该是可以撤销和重做的.
|
||||||
|
3.图元更改是可以撤销和重做的.
|
||||||
|
4.命令事务一致性,事物可以提交也可以取消.
|
||||||
|
5.数据保存和还原
|
||||||
|
6.对象引用应该是可以复制到新图纸的.
|
||||||
|
|
||||||
|
|
||||||
|
创建对象如何撤销和重做?
|
||||||
|
db.AppendEntity(ent);
|
||||||
|
|
||||||
|
当我们删除对象时,尝试只对对象进行标记删除.
|
||||||
|
当历史记录被优化时,我们尝试对删除的对象进行彻底删除
|
||||||
|
|
||||||
|
###关于对象的历史记录信息
|
||||||
|
|
||||||
|
->对象创建
|
||||||
|
....
|
||||||
|
undo:删除该对象,在集合中清除该数据 Remove
|
||||||
|
redo:重新创建该对象.保存完整的数据 A
|
||||||
|
|
||||||
|
->对象删除
|
||||||
|
undo:添加删除标记. P
|
||||||
|
redo:取消删除标记. P
|
||||||
|
|
||||||
|
->对象修改
|
||||||
|
undo:添加补丁. P
|
||||||
|
redo:添加补丁 P
|
||||||
|
|
||||||
|
|
||||||
|
问题:对象完整性保存时,优化重复的保存对象状态(不同命令下)
|
||||||
|
|
||||||
|
R:补丁与完整的对象存储不能优化.
|
||||||
|
假设用A表示完整的对象补丁,P表示局部补丁. 那么以下状态无法被优化.
|
||||||
|
如 A P P P A P P
|
||||||
|
| 这里A部分无法被优化 必须保证拥有旧的和新的全部数据.
|
||||||
|
假设拥有连续的完整补丁.
|
||||||
|
如 A A A A
|
||||||
|
连续的A是可以优化旧数据的.
|
||||||
|
|
||||||
|
结论:不优化.
|
||||||
|
|
||||||
|
|
||||||
|
问题:对象历史记录,完整性保存时优化.(相同命令下)
|
||||||
|
当对象已经尝试完整的保存一个对象时,如果还继续往里面保存一个完整的数据,那么将更新旧的完整数据.
|
||||||
|
比如.
|
||||||
|
A (insert new A).
|
||||||
|
A (update A.redo)
|
||||||
|
|
||||||
|
|
||||||
|
历史记录的数据结构
|
||||||
|
|
||||||
|
cmdName:"Line" //对象的创建命令
|
||||||
|
[
|
||||||
|
Object1:[C]//对象保留的创建的记录
|
||||||
|
]
|
||||||
|
cmdName:"Move" //对象修改命令
|
||||||
|
[
|
||||||
|
Object1:[P],
|
||||||
|
ObjectN:[P],
|
||||||
|
ObjectM:[P],
|
||||||
|
...
|
||||||
|
]
|
||||||
|
cmdName:"Ohther" //假设这个是一个复杂度很高的命令
|
||||||
|
[
|
||||||
|
Object1:[A,P,A,P,A,P,P,P],保存连续的记录.
|
||||||
|
ObjectN:[A,P,A,P,A,P,P,P],
|
||||||
|
ObjectM:[C,P,P,P,P] ,假设C为创建数据
|
||||||
|
...
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
优化A
|
||||||
|
当连续2个命令是A时,优化第二个命令A的undo数据为空
|
||||||
|
当第一个数据为A时,优化后续的P.
|
||||||
|
A写入时,只写入undo信息,并不写入redo信息.当命令结束时,写入redo数据.
|
||||||
|
|
||||||
|
优化C:
|
||||||
|
当第一个数据为C时,优化后续的P.
|
||||||
|
同A 写入时,只写入UNDO,并不写入redo,命令结束时,写入redo数据
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
问题:对象id的更新.
|
||||||
|
跨文档复制时,对象的id和引用的id应该被更新.
|
||||||
|
加入ObjectId类.
|
||||||
|
id只有在一个情况下才会更新.跨文档复制时.
|
||||||
|
|
||||||
|
问题:对象的id如何分配.
|
||||||
|
在加入到图形记录时,分配id.
|
||||||
|
|
||||||
|
撤销创建对象,采用完全撤销模式,删除对象与集合的记录.
|
||||||
|
还原对象时,创建对象,并且加入集合.
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
@ -0,0 +1,124 @@
|
|||||||
|
import { Factory } from './CADFactory';
|
||||||
|
import { CADFile } from './CADFile';
|
||||||
|
import { CADObject } from './CADObject';
|
||||||
|
import { CommandHistoryRecord } from './CommandHistoryRecord';
|
||||||
|
|
||||||
|
//TODO:对于空的新建命令,应该支持不清空后续命令. 比如切换相机或者切换视图.
|
||||||
|
|
||||||
|
//历史记录管理
|
||||||
|
@Factory
|
||||||
|
export class HistoricManage extends CADObject
|
||||||
|
{
|
||||||
|
curIndex: number = -1; //当前执行位置,也就是当前的状态, undo时,撤销当前状态,redo时,应用下一个状态
|
||||||
|
historyRecord: CommandHistoryRecord[] = []; //历史记录
|
||||||
|
private doing: boolean = false;
|
||||||
|
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//对象从文件中读取数据,初始化自身
|
||||||
|
ReadFile(file: CADFile)
|
||||||
|
{
|
||||||
|
let ver = file.Read();
|
||||||
|
this.curIndex = file.Read();
|
||||||
|
let cout = file.Read();
|
||||||
|
this.historyRecord = [];
|
||||||
|
for (let i = 0; i < cout; i++)
|
||||||
|
{
|
||||||
|
this.historyRecord.push(file.ReadObject(this._db) as CommandHistoryRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//对象将自身数据写入到文件.
|
||||||
|
WriteFile(file: CADFile)
|
||||||
|
{
|
||||||
|
file.Write(1);
|
||||||
|
file.Write(this.curIndex);
|
||||||
|
file.Write(this.historyRecord.length);
|
||||||
|
for (let rec of this.historyRecord)
|
||||||
|
{
|
||||||
|
file.WriteObject(rec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//命令正在当前状态
|
||||||
|
get IsNow(): boolean
|
||||||
|
{
|
||||||
|
return this.historyRecord.length !== 0 && this.curIndex === this.historyRecord.length - 1;
|
||||||
|
}
|
||||||
|
get UndoData(): CommandHistoryRecord
|
||||||
|
{
|
||||||
|
if (this.doing)
|
||||||
|
return undefined;
|
||||||
|
if (!this.IsNow)
|
||||||
|
this.StartCmd("");
|
||||||
|
return this.historyRecord[this.historyRecord.length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
StartCmd(cmdName: string)
|
||||||
|
{
|
||||||
|
this.EndCmd();
|
||||||
|
|
||||||
|
//删除当前状态以后的所有状态
|
||||||
|
this.historyRecord.splice(this.curIndex + 1, this.historyRecord.length - (this.curIndex + 1));
|
||||||
|
this.historyRecord.push(new CommandHistoryRecord(cmdName));
|
||||||
|
this.curIndex = this.historyRecord.length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//结束当前的命令.
|
||||||
|
EndCmd()
|
||||||
|
{
|
||||||
|
if (!this.IsNow)
|
||||||
|
return;
|
||||||
|
let lastRec = this.historyRecord[this.curIndex];
|
||||||
|
if (lastRec)
|
||||||
|
{
|
||||||
|
lastRec.EndCommand();
|
||||||
|
if (lastRec.HistoryList.size === 0)
|
||||||
|
{
|
||||||
|
this.historyRecord.pop();
|
||||||
|
this.curIndex--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Undo(): boolean
|
||||||
|
{
|
||||||
|
this.EndCmd();
|
||||||
|
let historyRec = this.historyRecord[this.curIndex];
|
||||||
|
if (!historyRec)
|
||||||
|
return false;
|
||||||
|
this.doing = true;
|
||||||
|
for (let [id, recList] of historyRec.HistoryList)
|
||||||
|
{
|
||||||
|
for (let i = recList.length; i--;)
|
||||||
|
{
|
||||||
|
id.Object.ApplyPartialUndo(recList[i].undoData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.curIndex--;
|
||||||
|
this.doing = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Redo()
|
||||||
|
{
|
||||||
|
let historyRec = this.historyRecord[this.curIndex + 1];
|
||||||
|
if (!historyRec)
|
||||||
|
return false;
|
||||||
|
this.doing = true;
|
||||||
|
for (let [id, recList] of historyRec.HistoryList)
|
||||||
|
{
|
||||||
|
for (let rec of recList)
|
||||||
|
{
|
||||||
|
id.Object.ApplyPartialUndo(rec.redoData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.curIndex++;
|
||||||
|
this.doing = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
import { Factory } from './CADFactory';
|
||||||
|
import { CADFile } from './CADFile';
|
||||||
|
import { CADObject } from './CADObject';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 历史记录,用于撤销和重做的数据.
|
||||||
|
*
|
||||||
|
* @class HistoricRecord
|
||||||
|
* @extends {CADObject}
|
||||||
|
*/
|
||||||
|
@Factory
|
||||||
|
export class HistorycRecord extends CADObject
|
||||||
|
{
|
||||||
|
//指定撤销时所需要的数据
|
||||||
|
undoData: CADObject;
|
||||||
|
//制定重做时所需要的数据
|
||||||
|
redoData: CADObject;
|
||||||
|
userData: CADObject;
|
||||||
|
|
||||||
|
//#region -------------------------File-------------------------
|
||||||
|
//对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化
|
||||||
|
|
||||||
|
//对象从文件中读取数据,初始化自身
|
||||||
|
ReadFile(file: CADFile)
|
||||||
|
{
|
||||||
|
let ver = file.Read();
|
||||||
|
this.undoData = file.ReadObject(this._db);
|
||||||
|
this.redoData = file.ReadObject(this._db);
|
||||||
|
this.userData = file.ReadObject(this._db);
|
||||||
|
}
|
||||||
|
//对象将自身数据写入到文件.
|
||||||
|
WriteFile(file: CADFile)
|
||||||
|
{
|
||||||
|
file.Write(1);
|
||||||
|
file.WriteObject(this.undoData);
|
||||||
|
file.WriteObject(this.redoData);
|
||||||
|
file.WriteObject(this.userData);
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
}
|
@ -0,0 +1,117 @@
|
|||||||
|
//直线对象
|
||||||
|
import { Geometry, Object3D, Vector3 } from 'three';
|
||||||
|
import * as THREE from 'three';
|
||||||
|
|
||||||
|
import { ColorMaterial } from '../Common/ColorPalette';
|
||||||
|
import { RenderType } from '../GraphicsSystem/Enum';
|
||||||
|
import { Factory } from './CADFactory';
|
||||||
|
import { CADFile } from './CADFile';
|
||||||
|
import { Entity } from './Entity';
|
||||||
|
|
||||||
|
@Factory
|
||||||
|
export class Line extends Entity
|
||||||
|
{
|
||||||
|
private startPoint: Vector3;
|
||||||
|
private endPoint: Vector3;
|
||||||
|
constructor(sp?: Vector3, ep?: Vector3)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
this.startPoint = sp || new Vector3(0, 0, 0);
|
||||||
|
this.endPoint = ep || new Vector3(0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Draw(renderType: RenderType): Object3D
|
||||||
|
{
|
||||||
|
let obj = super.Draw(renderType);
|
||||||
|
if (obj) return obj;
|
||||||
|
|
||||||
|
let geo = new Geometry();
|
||||||
|
geo.vertices.push(this.StartPoint, this.EndPoint);
|
||||||
|
obj = new THREE.Line(geo, ColorMaterial.GetLineMaterial(this.m_Color));
|
||||||
|
this.m_DrawEntity.set(renderType, obj);
|
||||||
|
obj.userData = this;
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
Update()
|
||||||
|
{
|
||||||
|
for (let [, obj] of this.m_DrawEntity)
|
||||||
|
{
|
||||||
|
let lineObj = (<THREE.Line>obj);
|
||||||
|
|
||||||
|
lineObj.material = ColorMaterial.GetLineMaterial(this.ColorIndex);
|
||||||
|
|
||||||
|
let geo = lineObj.geometry as THREE.Geometry;
|
||||||
|
|
||||||
|
geo.vertices[0].copy(this.startPoint);
|
||||||
|
geo.vertices[1].copy(this.endPoint);
|
||||||
|
|
||||||
|
geo.computeBoundingSphere();
|
||||||
|
|
||||||
|
geo.verticesNeedUpdate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GetStretchPoints(): Array<THREE.Vector3>
|
||||||
|
{
|
||||||
|
return [this.StartPoint, this.EndPoint]
|
||||||
|
}
|
||||||
|
MoveStretchPoints(indexList: Array<number>, vec: Vector3)
|
||||||
|
{
|
||||||
|
for (let index of indexList)
|
||||||
|
{
|
||||||
|
if (index == 0)
|
||||||
|
this.StartPoint = this.StartPoint.add(vec);
|
||||||
|
else
|
||||||
|
this.EndPoint = this.EndPoint.add(vec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//#region -----------------------------File-----------------------------
|
||||||
|
//对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化
|
||||||
|
|
||||||
|
//对象从文件中读取数据,初始化自身
|
||||||
|
ReadFile(file: CADFile)
|
||||||
|
{
|
||||||
|
super.ReadFile(file);
|
||||||
|
let ver = file.Read();//1
|
||||||
|
this.startPoint.fromArray(file.Read());
|
||||||
|
this.endPoint.fromArray(file.Read());
|
||||||
|
}
|
||||||
|
//对象将自身数据写入到文件.
|
||||||
|
WriteFile(file: CADFile)
|
||||||
|
{
|
||||||
|
super.WriteFile(file);
|
||||||
|
file.Write(1);//ver
|
||||||
|
file.Write(this.startPoint.toArray());
|
||||||
|
file.Write(this.endPoint.toArray());
|
||||||
|
}
|
||||||
|
//#endregion-----------------------------File End-----------------------------
|
||||||
|
|
||||||
|
//#region 属性
|
||||||
|
set StartPoint(v: Vector3)
|
||||||
|
{
|
||||||
|
this.WriteAllObjectRecord();
|
||||||
|
this.startPoint.copy(v);
|
||||||
|
|
||||||
|
this.Update();
|
||||||
|
}
|
||||||
|
get StartPoint(): Vector3
|
||||||
|
{
|
||||||
|
return this.startPoint.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
get EndPoint(): Vector3
|
||||||
|
{
|
||||||
|
return this.endPoint.clone();
|
||||||
|
}
|
||||||
|
set EndPoint(v: Vector3)
|
||||||
|
{
|
||||||
|
this.WriteAllObjectRecord();
|
||||||
|
this.endPoint.copy(v);
|
||||||
|
this.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
import { observable } from 'mobx';
|
||||||
|
|
||||||
|
import { Factory } from './CADFactory';
|
||||||
|
import { Material } from './Material';
|
||||||
|
import { ObjectCollection } from './ObjectCollection';
|
||||||
|
|
||||||
|
@Factory
|
||||||
|
export class MaerialTableRecord extends ObjectCollection<Material>
|
||||||
|
{
|
||||||
|
|
||||||
|
@observable
|
||||||
|
objectCol: Material[] = [];
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
import { Factory } from './CADFactory';
|
||||||
|
import { CADObject } from './CADObject';
|
||||||
|
|
||||||
|
@Factory
|
||||||
|
export class Material extends CADObject
|
||||||
|
{
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
import { Factory } from './CADFactory';
|
||||||
|
import { CADFile } from './CADFile';
|
||||||
|
import { AllObjectData, CADObject } from './CADObject';
|
||||||
|
import { HistorycRecord } from './HistorycRecord';
|
||||||
|
import { ObjectId } from './ObjectId';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Factory
|
||||||
|
export class ObjectAllDataHistoryRecord extends HistorycRecord
|
||||||
|
{
|
||||||
|
objId: ObjectId;
|
||||||
|
constructor(id?: ObjectId)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
this.objId = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
//将数据写入 手动调用
|
||||||
|
WriteUndo()
|
||||||
|
{
|
||||||
|
this.undoData = new AllObjectData(this.objId.Object);
|
||||||
|
}
|
||||||
|
WriteRedo()
|
||||||
|
{
|
||||||
|
this.redoData = new AllObjectData(this.objId.Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
//#region -------------------------File-------------------------
|
||||||
|
//对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化
|
||||||
|
|
||||||
|
//类名,保证序列化时得到正确的new
|
||||||
|
get ClassName(): string
|
||||||
|
{
|
||||||
|
return "CADObject";
|
||||||
|
}
|
||||||
|
|
||||||
|
//对象从文件中读取数据,初始化自身
|
||||||
|
ReadFile(file: CADFile)
|
||||||
|
{
|
||||||
|
let ver = file.Read();
|
||||||
|
super.ReadFile(file);
|
||||||
|
this.objId = this.ReadObjectId(file);
|
||||||
|
}
|
||||||
|
//对象将自身数据写入到文件.
|
||||||
|
WriteFile(file: CADFile)
|
||||||
|
{
|
||||||
|
file.Write(1);
|
||||||
|
super.WriteFile(file);
|
||||||
|
this.WriteObjectId(file, this.objId);
|
||||||
|
}
|
||||||
|
//局部撤销
|
||||||
|
ApplyPartialUndo(undoData: CADObject)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
}
|
@ -0,0 +1,103 @@
|
|||||||
|
import { HistorycRecord } from './HistorycRecord';
|
||||||
|
import { ArrayRemove } from '../Common/Utils';
|
||||||
|
import { Factory } from './CADFactory';
|
||||||
|
import { CADFile } from './CADFile';
|
||||||
|
import { RemoveObjectData } from './RemoveObjectData';
|
||||||
|
import { CADObject } from './CADObject';
|
||||||
|
import { CreateObjectData } from './CreateObjectData';
|
||||||
|
|
||||||
|
|
||||||
|
//对象集合.
|
||||||
|
@Factory
|
||||||
|
export class ObjectCollection<T> extends CADObject
|
||||||
|
{
|
||||||
|
objectCol: CADObject[] = [];
|
||||||
|
|
||||||
|
//添加一个对象进入集合,这个集合存在db中,那么将自动分配id.
|
||||||
|
Append(obj: CADObject)
|
||||||
|
{
|
||||||
|
if (this._db && !obj.Id)
|
||||||
|
{
|
||||||
|
obj.InitObjectId(this._db);
|
||||||
|
}
|
||||||
|
this.objectCol.push(obj);
|
||||||
|
|
||||||
|
let undoRec = this.UndoRecord();
|
||||||
|
if (undoRec)
|
||||||
|
{
|
||||||
|
let hisRec = new HistorycRecord();
|
||||||
|
hisRec.redoData = new CreateObjectData(obj);
|
||||||
|
hisRec.undoData = new RemoveObjectData(this.objectCol.length - 1);
|
||||||
|
|
||||||
|
undoRec.WriteObjectHistoryPath(this, hisRec);
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj.Id;
|
||||||
|
}
|
||||||
|
Remove(obj: CADObject)
|
||||||
|
{
|
||||||
|
ArrayRemove(this.objectCol, obj);
|
||||||
|
obj.Erase();
|
||||||
|
obj.GoodBye();
|
||||||
|
let undoRec = this.UndoRecord();
|
||||||
|
if (undoRec)
|
||||||
|
{
|
||||||
|
let hisRec = new HistorycRecord();
|
||||||
|
hisRec.undoData = new CreateObjectData(obj);
|
||||||
|
hisRec.redoData = new RemoveObjectData(this.objectCol.length - 1);
|
||||||
|
|
||||||
|
undoRec.WriteObjectHistoryPath(this, hisRec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Destroy()
|
||||||
|
{
|
||||||
|
this.objectCol.length = 0;
|
||||||
|
}
|
||||||
|
Cout(): number
|
||||||
|
{
|
||||||
|
return this.objectCol.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
//#region -----------------------------File-----------------------------
|
||||||
|
//对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化
|
||||||
|
|
||||||
|
//对象从文件中读取数据,初始化自身
|
||||||
|
ReadFile(file: CADFile)
|
||||||
|
{
|
||||||
|
this.Destroy();
|
||||||
|
super.ReadFile(file);
|
||||||
|
let cout = file.Read();
|
||||||
|
this.objectCol = [];
|
||||||
|
for (let i = 0; i < cout; i++)
|
||||||
|
{
|
||||||
|
let obj = file.ReadObject(this._db);
|
||||||
|
this.objectCol.push(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//对象将自身数据写入到文件.
|
||||||
|
WriteFile(file: CADFile)
|
||||||
|
{
|
||||||
|
super.WriteFile(file);
|
||||||
|
file.Write(this.objectCol.length);
|
||||||
|
for (let obj of this.objectCol)
|
||||||
|
{
|
||||||
|
file.WriteObject(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//局部撤销
|
||||||
|
ApplyPartialUndo(undoData: CADObject)
|
||||||
|
{
|
||||||
|
if (undoData instanceof CreateObjectData)
|
||||||
|
{
|
||||||
|
let obj = undoData.getObject(this._db);
|
||||||
|
this.Append(obj);
|
||||||
|
}
|
||||||
|
else if (undoData instanceof RemoveObjectData)
|
||||||
|
{
|
||||||
|
this.Remove(this.objectCol[undoData.Index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endregion -----------------------------File End-----------------------------
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,59 @@
|
|||||||
|
import { Database } from './Database';
|
||||||
|
import { CADObject } from './CADObject';
|
||||||
|
|
||||||
|
/*
|
||||||
|
CADObject对象拥有Id属性,用来记录引用关系.
|
||||||
|
通过id可以得到对应的关联实体,或者记录实体的关联关系.
|
||||||
|
|
||||||
|
ObjectId必须使用 Database分配(db里面会存id的列表,以便同时更新id指向实体)
|
||||||
|
|
||||||
|
*/
|
||||||
|
export class ObjectId
|
||||||
|
{
|
||||||
|
private id: number;
|
||||||
|
private obj: CADObject;
|
||||||
|
|
||||||
|
//对外隐藏构造函数,如果需要构造一个id,请使用 Create 静态方法.
|
||||||
|
private constructor(index: number = -1, obj?: CADObject)
|
||||||
|
{
|
||||||
|
this.id = index;
|
||||||
|
this.obj = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
get IsErase(): boolean
|
||||||
|
{
|
||||||
|
return !this.obj || this.obj.IsErase;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
创建一个id, 如果db中已经存在id,那么自动获得该id,如果不存在,new一个新的id,并且加入到db中
|
||||||
|
该方法的使用场景:
|
||||||
|
1.对象加入到db中时
|
||||||
|
2.对象从数据从读取时.
|
||||||
|
3.对象redo创建时
|
||||||
|
4.引用读取时
|
||||||
|
*/
|
||||||
|
static Create(db: Database, index: number): ObjectId
|
||||||
|
{
|
||||||
|
let id = db.GetObjectId(index);
|
||||||
|
if (!id && index >= 0)
|
||||||
|
{
|
||||||
|
id = new ObjectId(index);
|
||||||
|
db.SetObjectId(index, id);
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
set Object(v: CADObject)
|
||||||
|
{
|
||||||
|
this.obj = v;
|
||||||
|
}
|
||||||
|
get Object(): CADObject
|
||||||
|
{
|
||||||
|
return this.obj;
|
||||||
|
}
|
||||||
|
get Index(): number
|
||||||
|
{
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,82 @@
|
|||||||
|
import * as THREE from 'three';
|
||||||
|
|
||||||
|
import { Factory } from './CADFactory';
|
||||||
|
import { Material } from './Material';
|
||||||
|
import { ObjectId } from './ObjectId';
|
||||||
|
import { DbTexture } from './Texture';
|
||||||
|
import { autorun, observable } from 'mobx';
|
||||||
|
import * as xaop from 'xaop';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 物理材质类,实现了序列化操作,可存入db.可得到three.material
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @class PhysicalMaterial
|
||||||
|
* @extends {Material}
|
||||||
|
*/
|
||||||
|
@Factory
|
||||||
|
|
||||||
|
export class DbPhysicalMaterial extends Material
|
||||||
|
{
|
||||||
|
@observable name: string = "测试";//名称
|
||||||
|
@observable color: string = "0";
|
||||||
|
@observable transparent: boolean = true; //透明度 0-1
|
||||||
|
@observable matalness: number = 0.8;//金属性 0-1
|
||||||
|
@observable opacity: number = 1;//不透明度.
|
||||||
|
@observable depthTest: boolean = true;//深度测试
|
||||||
|
@observable map: ObjectId;//纹理贴图
|
||||||
|
@observable bumpMap: ObjectId;//凹凸贴图
|
||||||
|
@observable bumpScale: number = 0.5;//凹凸比例
|
||||||
|
@observable roughnessMap: ObjectId;//粗糙贴图
|
||||||
|
@observable roughness: number = 0.8; //粗糙度
|
||||||
|
|
||||||
|
private material: THREE.MeshPhysicalMaterial;
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
autorun(() =>
|
||||||
|
{
|
||||||
|
this.name;
|
||||||
|
this.color;
|
||||||
|
this.transparent;
|
||||||
|
this.matalness;
|
||||||
|
this.opacity.toExponential;
|
||||||
|
this.depthTest;
|
||||||
|
this.map;
|
||||||
|
this.bumpMap;
|
||||||
|
this.bumpScale;
|
||||||
|
this.roughnessMap;
|
||||||
|
this.roughness;
|
||||||
|
this.Update();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
Update()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
get Material(): THREE.MeshPhysicalMaterial
|
||||||
|
{
|
||||||
|
if (!this.material)
|
||||||
|
{
|
||||||
|
this.material = new THREE.MeshPhysicalMaterial({});
|
||||||
|
xaop.end(this, this.Update, () =>
|
||||||
|
{
|
||||||
|
this.material.color = new THREE.Color(this.color);
|
||||||
|
|
||||||
|
this.material.transparent = this.transparent;
|
||||||
|
this.material.metalness = this.matalness;
|
||||||
|
this.material.opacity = this.opacity;
|
||||||
|
this.material.depthTest = this.depthTest;
|
||||||
|
this.material.bumpScale = this.bumpScale;
|
||||||
|
this.material.roughness = this.roughness;
|
||||||
|
|
||||||
|
this.material.map = this.map ? (this.map.Object as DbTexture).GetThreeTexture() : undefined;
|
||||||
|
this.material.bumpMap = this.bumpMap ? (this.bumpMap.Object as DbTexture).GetThreeTexture() : undefined;
|
||||||
|
this.material.roughnessMap = this.roughnessMap ? (this.roughnessMap.Object as DbTexture).GetThreeTexture() : undefined;
|
||||||
|
|
||||||
|
this.material.needsUpdate = true;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return this.material;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
import { Factory } from './CADFactory';
|
||||||
|
import { CADFile } from './CADFile';
|
||||||
|
import { CADObject } from './CADObject';
|
||||||
|
|
||||||
|
@Factory
|
||||||
|
export class RemoveObjectData extends CADObject
|
||||||
|
{
|
||||||
|
private index: number;
|
||||||
|
constructor(index?: number)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
get Index()
|
||||||
|
{
|
||||||
|
return this.index;
|
||||||
|
}
|
||||||
|
|
||||||
|
//#region -----------------------------File-----------------------------
|
||||||
|
//对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化
|
||||||
|
|
||||||
|
//对象从文件中读取数据,初始化自身
|
||||||
|
ReadFile(file: CADFile)
|
||||||
|
{
|
||||||
|
file.Read();//ver
|
||||||
|
this.index = file.Read();
|
||||||
|
}
|
||||||
|
//对象将自身数据写入到文件.
|
||||||
|
WriteFile(file: CADFile)
|
||||||
|
{
|
||||||
|
file.Write(1);
|
||||||
|
file.Write(this.index);
|
||||||
|
}
|
||||||
|
//局部撤销
|
||||||
|
ApplyPartialUndo(file: CADObject)
|
||||||
|
{ }
|
||||||
|
//#endregion -----------------------------File End-----------------------------
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,44 @@
|
|||||||
|
import * as THREE from 'three';
|
||||||
|
|
||||||
|
import { Factory } from './CADFactory';
|
||||||
|
import { CADObject } from './CADObject';
|
||||||
|
import { loaderImage, loaderImageFromMd5 } from '../Loader/ImageLoader';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据化的贴图类.实现了序列化.
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @class Texture
|
||||||
|
* @extends {CADObject}
|
||||||
|
*/
|
||||||
|
@Factory
|
||||||
|
export class DbTexture extends CADObject
|
||||||
|
{
|
||||||
|
name: string;
|
||||||
|
wrapS: THREE.Wrapping = THREE.RepeatWrapping;//横向(水平)平铺
|
||||||
|
wrapT: THREE.Wrapping = THREE.RepeatWrapping;//竖向(垂直)平铺
|
||||||
|
repeat: THREE.Vector2 = new THREE.Vector2(1, 1);//重复
|
||||||
|
rotate: number = 0;//旋转
|
||||||
|
imageMd5: string; //使用md5保存贴图
|
||||||
|
|
||||||
|
private texture: THREE.Texture = new THREE.Texture();
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
async Update()
|
||||||
|
{
|
||||||
|
if (this.imageMd5) this.texture.image = await (loaderImageFromMd5(this.imageMd5));
|
||||||
|
this.texture.wrapS = THREE.RepeatWrapping;
|
||||||
|
this.texture.wrapT = THREE.RepeatWrapping;
|
||||||
|
this.texture.anisotropy = 16;
|
||||||
|
this.texture.repeat.set(10, 24);
|
||||||
|
this.texture.format = THREE.RGBFormat;
|
||||||
|
this.texture.needsUpdate = true;
|
||||||
|
}
|
||||||
|
GetThreeTexture()
|
||||||
|
{
|
||||||
|
return this.texture;
|
||||||
|
}
|
||||||
|
}
|
@ -1,72 +0,0 @@
|
|||||||
import * as xaop from 'xaop';
|
|
||||||
|
|
||||||
import { app, ApplicationService } from '../ApplicationServices/Application';
|
|
||||||
import { commandMachine } from '../Editor/CommandMachine';
|
|
||||||
import { ISnapDatabaseData } from './EntityData';
|
|
||||||
|
|
||||||
export class UndoData
|
|
||||||
{
|
|
||||||
m_App: ApplicationService;
|
|
||||||
|
|
||||||
m_UndoDataList: Array<ISnapDatabaseData> = [];
|
|
||||||
|
|
||||||
m_UndoIndex = 0;//0表示当前状态
|
|
||||||
|
|
||||||
constructor(app: ApplicationService)
|
|
||||||
{
|
|
||||||
this.m_App = app;
|
|
||||||
|
|
||||||
let ed = app.m_Editor;
|
|
||||||
|
|
||||||
this.m_UndoDataList.push(app.m_Database.dataOut())//初始化空状态
|
|
||||||
|
|
||||||
|
|
||||||
xaop.end(commandMachine, commandMachine.CommandEnd, (name) =>
|
|
||||||
{
|
|
||||||
if (name == "u" || name == "redo")
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.createUndoData();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
xaop.end(app.m_Database, app.m_Database.CommitTransaction, () =>
|
|
||||||
{
|
|
||||||
this.createUndoData();
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
createUndoData()
|
|
||||||
{
|
|
||||||
let remove;
|
|
||||||
if (this.m_UndoIndex > 0)
|
|
||||||
{
|
|
||||||
this.m_UndoDataList = this.m_UndoDataList.splice(0, this.m_UndoDataList.length - this.m_UndoIndex);
|
|
||||||
}
|
|
||||||
this.m_UndoIndex = 0;
|
|
||||||
this.m_UndoDataList.push(app.m_Database.dataOut())
|
|
||||||
}
|
|
||||||
undo(cout: number)
|
|
||||||
{
|
|
||||||
let index = this.m_UndoIndex + 1;
|
|
||||||
if (index < this.m_UndoDataList.length)
|
|
||||||
{
|
|
||||||
this.m_UndoIndex = index;
|
|
||||||
app.m_Database.dataIn(this.m_UndoDataList[this.m_UndoDataList.length - index - 1]);
|
|
||||||
app.m_Editor.UpdateScreen();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
redo(cout: number)
|
|
||||||
{
|
|
||||||
let index = this.m_UndoIndex - 1;
|
|
||||||
if (index < this.m_UndoDataList.length - 1 && index >= 0)
|
|
||||||
{
|
|
||||||
this.m_UndoIndex = index;
|
|
||||||
app.m_Database.dataIn(this.m_UndoDataList[this.m_UndoDataList.length - index - 1]);
|
|
||||||
app.m_Editor.UpdateScreen();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,109 @@
|
|||||||
|
|
||||||
|
//参考 http://robnyman.github.io/html5demos/indexeddb/js/base.js
|
||||||
|
|
||||||
|
enum DbMode
|
||||||
|
{
|
||||||
|
ReadWrite = "readwrite",
|
||||||
|
ReadOnly = "readonly"
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum StoreName
|
||||||
|
{
|
||||||
|
Texture = "Texture",
|
||||||
|
Dwg = "Dwg",
|
||||||
|
}
|
||||||
|
|
||||||
|
export class IndexedDbStore
|
||||||
|
{
|
||||||
|
private dbRequest: IDBOpenDBRequest;
|
||||||
|
private isOK: boolean = true;;
|
||||||
|
private db: IDBDatabase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of IndexedDbStore.
|
||||||
|
* @param {string} dbName
|
||||||
|
* @memberof IndexedDbStore
|
||||||
|
*/
|
||||||
|
private constructor()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
private static cadStore: IndexedDbStore = new IndexedDbStore();
|
||||||
|
static async CADStore()
|
||||||
|
{
|
||||||
|
await this.cadStore.Open();
|
||||||
|
return this.cadStore;
|
||||||
|
}
|
||||||
|
Open(): Promise<boolean>
|
||||||
|
{
|
||||||
|
return new Promise<boolean>((res) =>
|
||||||
|
{
|
||||||
|
let funcs = this.InitStore();
|
||||||
|
this.dbRequest = indexedDB.open("webCAD", funcs.length);
|
||||||
|
|
||||||
|
//出错
|
||||||
|
this.dbRequest.onerror = () =>
|
||||||
|
{
|
||||||
|
console.log("打开数据库出错!");
|
||||||
|
res(false);
|
||||||
|
}
|
||||||
|
//连接成功
|
||||||
|
this.dbRequest.onsuccess = (event) =>
|
||||||
|
{
|
||||||
|
this.db = this.dbRequest.result;
|
||||||
|
this.db.onerror = () =>
|
||||||
|
{
|
||||||
|
res(false);
|
||||||
|
}
|
||||||
|
res(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
//需要升级版本号时触发该事件
|
||||||
|
this.dbRequest.onupgradeneeded = (event) =>
|
||||||
|
{
|
||||||
|
let db = event.target["result"] as IDBDatabase;
|
||||||
|
for (let i = event.oldVersion; i < funcs.length; i++)
|
||||||
|
{
|
||||||
|
funcs[i](db);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})
|
||||||
|
}
|
||||||
|
InitStore()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
//ver1.
|
||||||
|
(db: IDBDatabase) =>
|
||||||
|
{
|
||||||
|
db.createObjectStore(StoreName.Texture);
|
||||||
|
},
|
||||||
|
//ver2.
|
||||||
|
(db: IDBDatabase) =>
|
||||||
|
{
|
||||||
|
db.createObjectStore(StoreName.Dwg);
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
Put(storeName: StoreName, key: string, value: any)
|
||||||
|
{
|
||||||
|
let tr = this.db.transaction(storeName, DbMode.ReadWrite);
|
||||||
|
return tr.objectStore(storeName).put(value, key);
|
||||||
|
}
|
||||||
|
Get(storeName: StoreName, key: string)
|
||||||
|
{
|
||||||
|
return new Promise<any>((res) =>
|
||||||
|
{
|
||||||
|
let tr = this.db.transaction(storeName, DbMode.ReadOnly);
|
||||||
|
let request = tr.objectStore(storeName).get(key);
|
||||||
|
request.onsuccess = (e) =>
|
||||||
|
{
|
||||||
|
res(request.result);
|
||||||
|
}
|
||||||
|
request.onerror = (e) =>
|
||||||
|
{
|
||||||
|
res(request.result);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
import { blobMd5 } from "../Common/MD5";
|
||||||
|
import { IndexedDbStore, StoreName } from "../IndexedDb/IndexedDbStore";
|
||||||
|
|
||||||
|
//节点缓存.使用它来缓存已经加载的图片.
|
||||||
|
let imageCache = new Map<string, HTMLImageElement>();
|
||||||
|
|
||||||
|
//根据blob文件加载image
|
||||||
|
export function loaderImage(blob: File): Promise<HTMLImageElement>
|
||||||
|
{
|
||||||
|
return new Promise<HTMLImageElement>(async (res, rej) =>
|
||||||
|
{
|
||||||
|
let md5 = await blobMd5(blob);
|
||||||
|
if (imageCache.has(md5))
|
||||||
|
{
|
||||||
|
res(imageCache.get(md5));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
(await IndexedDbStore.CADStore()).Put(StoreName.Texture, md5, blob);
|
||||||
|
|
||||||
|
let url = URL.createObjectURL(blob);
|
||||||
|
let image = document.createElement('img');
|
||||||
|
image.onload = () =>
|
||||||
|
{
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
imageCache.set(md5, image);
|
||||||
|
res(image);
|
||||||
|
}
|
||||||
|
image.onerror = (err) =>
|
||||||
|
{
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
rej(err);
|
||||||
|
}
|
||||||
|
image.src = url;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//通过md5来加载图片.这个方法会尝试从缓存里面读取,也会尝试从indexedDb读取,未来也会支持从外部的网站读取.
|
||||||
|
export async function loaderImageFromMd5(md5: string): Promise<HTMLImageElement>
|
||||||
|
{
|
||||||
|
if (imageCache.has(md5))
|
||||||
|
return imageCache.get(md5);
|
||||||
|
let store = await IndexedDbStore.CADStore();
|
||||||
|
let file = await store.Get(StoreName.Texture, md5) as File;
|
||||||
|
if (file)
|
||||||
|
{
|
||||||
|
return await loaderImage(file);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue