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 { app } from '../ApplicationServices/Application';
|
||||
import { CreateBoardUtil } from '../ApplicationServices/mesh/createBoard';
|
||||
import { MaterialNeedUpdateKey } from '../DatabaseServices/MaterialDictionary';
|
||||
import { Command } from '../Editor/CommandMachine';
|
||||
import { Move } from '../Geometry/GeUtils';
|
||||
|
||||
export class Command_DrawBoard implements Command
|
||||
{
|
||||
async exec()
|
||||
{
|
||||
|
||||
let boardMaterial = new THREE.MeshStandardMaterial({
|
||||
roughness: 0.3,
|
||||
color: 0xffffff,
|
||||
metalness: 0.2,
|
||||
bumpScale: 0.0005
|
||||
})
|
||||
|
||||
boardMaterial.name = "板"
|
||||
|
||||
|
||||
let textureLoader = new THREE.TextureLoader();
|
||||
textureLoader.load("textures/019.jpg", function (map)
|
||||
{
|
||||
map.wrapS = THREE.MirroredRepeatWrapping;
|
||||
map.wrapT = THREE.MirroredRepeatWrapping;
|
||||
map.anisotropy = 16;
|
||||
map.repeat.set(1, 1);
|
||||
boardMaterial.map = map;
|
||||
boardMaterial.needsUpdate = true;
|
||||
boardMaterial[MaterialNeedUpdateKey] = true;
|
||||
});
|
||||
|
||||
// let scale = new THREE.Matrix4();
|
||||
// scale.scale(new THREE.Vector3(0.001, 0.001, 0.001));
|
||||
|
||||
let move = Move(new THREE.Vector3(-1, 2.5, 0));
|
||||
|
||||
// let mat = move.multiply(scale);
|
||||
|
||||
app.m_Database.m_MaterialDictionary.addMaterial(boardMaterial);
|
||||
|
||||
for (let i = 0; i < 50; i++)
|
||||
{
|
||||
let boardList = CreateBoardUtil.createTemplateBoard();
|
||||
for (let board of boardList)
|
||||
{
|
||||
let br = board as THREE.Mesh;
|
||||
br.applyMatrix(move);
|
||||
br.material = boardMaterial;
|
||||
br.castShadow = true;
|
||||
br.receiveShadow = true;
|
||||
app.m_Viewer.m_Scene.add(board);
|
||||
|
||||
let move2 = Move(new THREE.Vector3(i * 1, 0, 0));
|
||||
br.applyMatrix(move2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// //绘制板件
|
||||
// import * as THREE from 'three';
|
||||
|
||||
// import { app } from '../ApplicationServices/Application';
|
||||
// import { CreateBoardUtil } from '../ApplicationServices/mesh/createBoard';
|
||||
// import { MaterialNeedUpdateKey } from '../DatabaseServices/MaterialDictionary';
|
||||
// import { Command } from '../Editor/CommandMachine';
|
||||
// import { Move } from '../Geometry/GeUtils';
|
||||
|
||||
// export class Command_DrawBoard implements Command
|
||||
// {
|
||||
// async exec()
|
||||
// {
|
||||
|
||||
// let boardMaterial = new THREE.MeshStandardMaterial({
|
||||
// roughness: 0.3,
|
||||
// color: 0xffffff,
|
||||
// metalness: 0.2,
|
||||
// bumpScale: 0.0005
|
||||
// })
|
||||
|
||||
// boardMaterial.name = "板"
|
||||
|
||||
|
||||
// let textureLoader = new THREE.TextureLoader();
|
||||
// textureLoader.load("textures/019.jpg", function (map)
|
||||
// {
|
||||
// map.wrapS = THREE.MirroredRepeatWrapping;
|
||||
// map.wrapT = THREE.MirroredRepeatWrapping;
|
||||
// map.anisotropy = 16;
|
||||
// map.repeat.set(1, 1);
|
||||
// boardMaterial.map = map;
|
||||
// boardMaterial.needsUpdate = true;
|
||||
// boardMaterial[MaterialNeedUpdateKey] = true;
|
||||
// });
|
||||
|
||||
// // let scale = new THREE.Matrix4();
|
||||
// // scale.scale(new THREE.Vector3(0.001, 0.001, 0.001));
|
||||
|
||||
// let move = Move(new THREE.Vector3(-1, 2.5, 0));
|
||||
|
||||
// // let mat = move.multiply(scale);
|
||||
|
||||
// app.m_Database.m_MaterialDictionary.addMaterial(boardMaterial);
|
||||
|
||||
// for (let i = 0; i < 50; i++)
|
||||
// {
|
||||
// let boardList = CreateBoardUtil.createTemplateBoard();
|
||||
// for (let board of boardList)
|
||||
// {
|
||||
// let br = board as THREE.Mesh;
|
||||
// br.applyMatrix(move);
|
||||
// br.material = boardMaterial;
|
||||
// br.castShadow = true;
|
||||
// br.receiveShadow = true;
|
||||
// app.m_Viewer.m_Scene.add(board);
|
||||
|
||||
// let move2 = Move(new THREE.Vector3(i * 1, 0, 0));
|
||||
// br.applyMatrix(move2);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
@ -1,401 +1,401 @@
|
||||
import * as path from 'path';
|
||||
import * as THREE from 'three';
|
||||
|
||||
import { app } from '../ApplicationServices/Application';
|
||||
import { Solid3d } from '../DatabaseServices/Entity';
|
||||
import { Command } from '../Editor/CommandMachine';
|
||||
import { Move } from '../Geometry/GeUtils';
|
||||
import { RenderType } from '../GraphicsSystem/Enum';
|
||||
|
||||
export class DrawFloor implements Command
|
||||
{
|
||||
textureLoader: THREE.TextureLoader;
|
||||
|
||||
get scene()
|
||||
{
|
||||
return app.m_Viewer.m_Scene;
|
||||
}
|
||||
constructor()
|
||||
{
|
||||
this.textureLoader = new THREE.TextureLoader();
|
||||
}
|
||||
async exec()
|
||||
{
|
||||
app.m_Viewer.m_Camera.Camera.position.set(0, 0, 2);
|
||||
this.drawFloor();
|
||||
|
||||
this.drawLight();
|
||||
this.drawHemiLight();
|
||||
|
||||
// this.drawWall();
|
||||
|
||||
// this.drawBox();
|
||||
// //绘制一个盒子 带反射
|
||||
// this.drawBox2();
|
||||
|
||||
|
||||
this.loadMaterial();
|
||||
|
||||
app.m_Viewer.m_Render.toneMappingExposure = Math.pow(0.68, 5.0); // to allow for very bright scenes.
|
||||
}
|
||||
|
||||
async loadFbx()
|
||||
{
|
||||
// let obj = await loadFBX("123456.FBX");
|
||||
|
||||
// this.scene.add(obj.object);
|
||||
}
|
||||
|
||||
private drawFloor()
|
||||
{
|
||||
let floorMat = new THREE.MeshStandardMaterial({
|
||||
roughness: 0.8,
|
||||
color: 0xffffff,
|
||||
metalness: 0.2,
|
||||
bumpScale: 0.0005,
|
||||
transparent: true,
|
||||
opacity: 0.9
|
||||
});
|
||||
this.materialList.push(floorMat);
|
||||
|
||||
var floorGeometry = new THREE.PlaneBufferGeometry(20, 20);
|
||||
var floorMesh = new THREE.Mesh(floorGeometry, floorMat);
|
||||
floorMesh.receiveShadow = true;
|
||||
this.scene.add(floorMesh);
|
||||
|
||||
//使用镜子
|
||||
let useRef = false;
|
||||
if (useRef)
|
||||
{
|
||||
floorMat.transparent = true;
|
||||
floorMat.opacity = 0.9
|
||||
|
||||
// let ref = new THREE.Reflector(20, 20, {
|
||||
// clipBias: 0.003,
|
||||
// textureWidth: app.m_Viewer.Width * window.devicePixelRatio,
|
||||
// textureHeight: app.m_Viewer.Height * window.devicePixelRatio,
|
||||
// color: 0x777777
|
||||
// import * as path from 'path';
|
||||
// import * as THREE from 'three';
|
||||
|
||||
// import { app } from '../ApplicationServices/Application';
|
||||
// import { Solid3d } from '../DatabaseServices/Entity';
|
||||
// import { Command } from '../Editor/CommandMachine';
|
||||
// import { Move } from '../Geometry/GeUtils';
|
||||
// import { RenderType } from '../GraphicsSystem/Enum';
|
||||
|
||||
// export class DrawFloor implements Command
|
||||
// {
|
||||
// textureLoader: THREE.TextureLoader;
|
||||
|
||||
// get scene()
|
||||
// {
|
||||
// return app.m_Viewer.m_Scene;
|
||||
// }
|
||||
// constructor()
|
||||
// {
|
||||
// this.textureLoader = new THREE.TextureLoader();
|
||||
// }
|
||||
// async exec()
|
||||
// {
|
||||
// app.m_Viewer.m_Camera.Camera.position.set(0, 0, 2);
|
||||
// this.drawFloor();
|
||||
|
||||
// this.drawLight();
|
||||
// this.drawHemiLight();
|
||||
|
||||
// // this.drawWall();
|
||||
|
||||
// // this.drawBox();
|
||||
// // //绘制一个盒子 带反射
|
||||
// // this.drawBox2();
|
||||
|
||||
|
||||
// this.loadMaterial();
|
||||
|
||||
// app.m_Viewer.m_Render.toneMappingExposure = Math.pow(0.68, 5.0); // to allow for very bright scenes.
|
||||
// }
|
||||
|
||||
// async loadFbx()
|
||||
// {
|
||||
// // let obj = await loadFBX("123456.FBX");
|
||||
|
||||
// // this.scene.add(obj.object);
|
||||
// }
|
||||
|
||||
// private drawFloor()
|
||||
// {
|
||||
// let floorMat = new THREE.MeshStandardMaterial({
|
||||
// roughness: 0.8,
|
||||
// color: 0xffffff,
|
||||
// metalness: 0.2,
|
||||
// bumpScale: 0.0005,
|
||||
// transparent: true,
|
||||
// opacity: 0.9
|
||||
// });
|
||||
// this.materialList.push(floorMat);
|
||||
|
||||
// ref.position.z = -0.1;
|
||||
// this.scene.add(ref);
|
||||
}
|
||||
}
|
||||
materialList = [];
|
||||
loadMaterial()
|
||||
{
|
||||
let self = this;
|
||||
|
||||
this.textureLoader.load("textures/hardwood2_diffuse.jpg", function (map)
|
||||
{
|
||||
map.wrapS = THREE.RepeatWrapping;
|
||||
map.wrapT = THREE.RepeatWrapping;
|
||||
map.anisotropy = 16;
|
||||
map.repeat.set(10, 24);
|
||||
|
||||
self.materialList.forEach(m =>
|
||||
{
|
||||
m.map = map;
|
||||
m.needsUpdate = true;
|
||||
})
|
||||
});
|
||||
this.textureLoader.load("textures/hardwood2_bump.jpg", function (map)
|
||||
{
|
||||
map.wrapS = THREE.RepeatWrapping;
|
||||
map.wrapT = THREE.RepeatWrapping;
|
||||
map.anisotropy = 16;
|
||||
map.repeat.set(10, 24);
|
||||
|
||||
self.materialList.forEach(m =>
|
||||
{
|
||||
(<THREE.MeshStandardMaterial>m).bumpMap = map;
|
||||
m.needsUpdate = true;
|
||||
})
|
||||
});
|
||||
this.textureLoader.load("textures/hardwood2_roughness.jpg", function (map)
|
||||
{
|
||||
map.wrapS = THREE.RepeatWrapping;
|
||||
map.wrapT = THREE.RepeatWrapping;
|
||||
map.anisotropy = 16;
|
||||
map.repeat.set(10, 24);
|
||||
|
||||
self.materialList.forEach(m =>
|
||||
{
|
||||
(<THREE.MeshStandardMaterial>m).roughnessMap = map;
|
||||
m.needsUpdate = true;
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
drawLight()
|
||||
{
|
||||
var bulbGeometry = new THREE.SphereGeometry(0.02, 16, 8);
|
||||
let bulbLight = new THREE.PointLight(0x999999, 1, 100, 2);
|
||||
|
||||
let bulbMat = new THREE.MeshStandardMaterial({
|
||||
emissive: 0xffffee,
|
||||
emissiveIntensity: 1,
|
||||
color: 0x000000
|
||||
});
|
||||
|
||||
|
||||
bulbLight.add(new THREE.Mesh(bulbGeometry, bulbMat));
|
||||
bulbLight.position.set(0, 2, 2);
|
||||
bulbLight.castShadow = true;
|
||||
|
||||
bulbLight.power = 400;
|
||||
bulbMat.emissiveIntensity = bulbLight.intensity / Math.pow(0.02, 2.0); // convert from intensity to irradiance at bulb surface
|
||||
this.scene.add(bulbLight);
|
||||
|
||||
let light2 = bulbLight.clone();
|
||||
|
||||
light2.position.set(-3, -1, 2);
|
||||
this.scene.add(light2);
|
||||
// var floorGeometry = new THREE.PlaneBufferGeometry(20, 20);
|
||||
// var floorMesh = new THREE.Mesh(floorGeometry, floorMat);
|
||||
// floorMesh.receiveShadow = true;
|
||||
// this.scene.add(floorMesh);
|
||||
|
||||
// //使用镜子
|
||||
// let useRef = false;
|
||||
// if (useRef)
|
||||
// {
|
||||
// floorMat.transparent = true;
|
||||
// floorMat.opacity = 0.9
|
||||
|
||||
// // let ref = new THREE.Reflector(20, 20, {
|
||||
// // clipBias: 0.003,
|
||||
// // textureWidth: app.m_Viewer.Width * window.devicePixelRatio,
|
||||
// // textureHeight: app.m_Viewer.Height * window.devicePixelRatio,
|
||||
// // color: 0x777777
|
||||
// // });
|
||||
|
||||
// // ref.position.z = -0.1;
|
||||
// // this.scene.add(ref);
|
||||
// }
|
||||
// }
|
||||
// materialList = [];
|
||||
// loadMaterial()
|
||||
// {
|
||||
// let self = this;
|
||||
|
||||
// var clock = new THREE.Clock();
|
||||
// xaop.begin(app.m_Viewer, app.m_Viewer.StartRender, () =>
|
||||
// this.textureLoader.load("textures/hardwood2_diffuse.jpg", function (map)
|
||||
// {
|
||||
// map.wrapS = THREE.RepeatWrapping;
|
||||
// map.wrapT = THREE.RepeatWrapping;
|
||||
// map.anisotropy = 16;
|
||||
// map.repeat.set(10, 24);
|
||||
|
||||
// self.materialList.forEach(m =>
|
||||
// {
|
||||
// var time = Date.now() * 0.0005;
|
||||
// var delta = clock.getDelta();
|
||||
// bulbLight.position.z = Math.cos(time) * 0.75 + 1.25;
|
||||
// app.m_Viewer.m_bNeedUpdate = true;
|
||||
// m.map = map;
|
||||
// m.needsUpdate = true;
|
||||
// })
|
||||
}
|
||||
private drawHemiLight()
|
||||
{
|
||||
//0xddeeff 0x0f0e0d
|
||||
var hemiLight = new THREE.HemisphereLight(0xffffff, 0xffffff, 0.02);
|
||||
hemiLight.intensity = 3;
|
||||
this.scene.add(hemiLight);
|
||||
}
|
||||
// });
|
||||
// this.textureLoader.load("textures/hardwood2_bump.jpg", function (map)
|
||||
// {
|
||||
// map.wrapS = THREE.RepeatWrapping;
|
||||
// map.wrapT = THREE.RepeatWrapping;
|
||||
// map.anisotropy = 16;
|
||||
// map.repeat.set(10, 24);
|
||||
|
||||
// self.materialList.forEach(m =>
|
||||
// {
|
||||
// (<THREE.MeshStandardMaterial>m).bumpMap = map;
|
||||
// m.needsUpdate = true;
|
||||
// })
|
||||
// });
|
||||
// this.textureLoader.load("textures/hardwood2_roughness.jpg", function (map)
|
||||
// {
|
||||
// map.wrapS = THREE.RepeatWrapping;
|
||||
// map.wrapT = THREE.RepeatWrapping;
|
||||
// map.anisotropy = 16;
|
||||
// map.repeat.set(10, 24);
|
||||
|
||||
drawWall()
|
||||
{
|
||||
let floorMat = new THREE.MeshStandardMaterial({
|
||||
roughness: 0.8,
|
||||
color: 0xffffff,
|
||||
metalness: 0.2,
|
||||
bumpScale: 0.0005
|
||||
});
|
||||
|
||||
this.textureLoader.load("textures/wallmap.png", function (map)
|
||||
{
|
||||
map.wrapS = THREE.RepeatWrapping;
|
||||
map.wrapT = THREE.RepeatWrapping;
|
||||
map.anisotropy = 4;
|
||||
map.repeat.set(10, 24);
|
||||
floorMat.map = map;
|
||||
floorMat.needsUpdate = true;
|
||||
});
|
||||
|
||||
|
||||
let wallFont = new Solid3d(4, 0.12, 2.8);
|
||||
let obj = wallFont.Draw(RenderType.Wireframe) as THREE.Mesh;
|
||||
obj.material = floorMat;
|
||||
|
||||
obj.castShadow = true;
|
||||
obj.receiveShadow = true;
|
||||
|
||||
let objLeft = obj.clone();
|
||||
let objRight = obj.clone();
|
||||
|
||||
|
||||
obj.applyMatrix(Move(new THREE.Vector3(-2.1, 4, 0)));
|
||||
|
||||
let roMatLeft = new THREE.Matrix4();
|
||||
roMatLeft.makeRotationZ(Math.PI / 2);
|
||||
objLeft.applyMatrix(roMatLeft);
|
||||
// self.materialList.forEach(m =>
|
||||
// {
|
||||
// (<THREE.MeshStandardMaterial>m).roughnessMap = map;
|
||||
// m.needsUpdate = true;
|
||||
// })
|
||||
// });
|
||||
// }
|
||||
|
||||
let roMatRight = new THREE.Matrix4();
|
||||
roMatRight.makeRotationZ(Math.PI / 2);
|
||||
objRight.applyMatrix(roMatRight);
|
||||
// drawLight()
|
||||
// {
|
||||
// var bulbGeometry = new THREE.SphereGeometry(0.02, 16, 8);
|
||||
// let bulbLight = new THREE.PointLight(0x999999, 1, 100, 2);
|
||||
|
||||
objLeft.applyMatrix(Move(new THREE.Vector3(-2, 0, 0)))
|
||||
objRight.applyMatrix(Move(new THREE.Vector3(2, 0, 0)))
|
||||
// let bulbMat = new THREE.MeshStandardMaterial({
|
||||
// emissive: 0xffffee,
|
||||
// emissiveIntensity: 1,
|
||||
// color: 0x000000
|
||||
// });
|
||||
|
||||
|
||||
this.scene.add(obj);
|
||||
this.scene.add(objLeft);
|
||||
this.scene.add(objRight);
|
||||
// bulbLight.add(new THREE.Mesh(bulbGeometry, bulbMat));
|
||||
// bulbLight.position.set(0, 2, 2);
|
||||
// bulbLight.castShadow = true;
|
||||
|
||||
// bulbLight.power = 400;
|
||||
// bulbMat.emissiveIntensity = bulbLight.intensity / Math.pow(0.02, 2.0); // convert from intensity to irradiance at bulb surface
|
||||
// this.scene.add(bulbLight);
|
||||
|
||||
let skyMaterail = new THREE.MeshStandardMaterial({
|
||||
roughness: 0.8,
|
||||
color: 0xffffff,
|
||||
metalness: 0.2,
|
||||
bumpScale: 0.0005
|
||||
})
|
||||
//天花板.
|
||||
let skyWall = new Solid3d(4.12, 4, 0.12);
|
||||
let skyObj = skyWall.Draw(RenderType.Wireframe) as THREE.Mesh;
|
||||
skyObj.material = skyMaterail;
|
||||
// let light2 = bulbLight.clone();
|
||||
|
||||
// light2.position.set(-3, -1, 2);
|
||||
// this.scene.add(light2);
|
||||
|
||||
|
||||
// var clock = new THREE.Clock();
|
||||
// // xaop.begin(app.m_Viewer, app.m_Viewer.StartRender, () =>
|
||||
// // {
|
||||
// // var time = Date.now() * 0.0005;
|
||||
// // var delta = clock.getDelta();
|
||||
// // bulbLight.position.z = Math.cos(time) * 0.75 + 1.25;
|
||||
// // app.m_Viewer.m_bNeedUpdate = true;
|
||||
// // })
|
||||
// }
|
||||
// private drawHemiLight()
|
||||
// {
|
||||
// //0xddeeff 0x0f0e0d
|
||||
// var hemiLight = new THREE.HemisphereLight(0xffffff, 0xffffff, 0.02);
|
||||
// hemiLight.intensity = 3;
|
||||
// this.scene.add(hemiLight);
|
||||
// }
|
||||
|
||||
skyObj.applyMatrix(Move(new THREE.Vector3(-2.12, 0, 2.8)));
|
||||
|
||||
this.scene.add(skyObj);
|
||||
}
|
||||
// drawWall()
|
||||
// {
|
||||
// let floorMat = new THREE.MeshStandardMaterial({
|
||||
// roughness: 0.8,
|
||||
// color: 0xffffff,
|
||||
// metalness: 0.2,
|
||||
// bumpScale: 0.0005
|
||||
// });
|
||||
|
||||
drawBox()
|
||||
{
|
||||
let solid = new Solid3d(1.2, 0.05, 2.4);
|
||||
// this.textureLoader.load("textures/wallmap.png", function (map)
|
||||
// {
|
||||
// map.wrapS = THREE.RepeatWrapping;
|
||||
// map.wrapT = THREE.RepeatWrapping;
|
||||
// map.anisotropy = 4;
|
||||
// map.repeat.set(10, 24);
|
||||
// floorMat.map = map;
|
||||
// floorMat.needsUpdate = true;
|
||||
// });
|
||||
|
||||
let obj = solid.Draw(RenderType.Wireframe);
|
||||
|
||||
obj.castShadow = true;
|
||||
// let wallFont = new Solid3d(4, 0.12, 2.8);
|
||||
// let obj = wallFont.Draw(RenderType.Wireframe) as THREE.Mesh;
|
||||
// obj.material = floorMat;
|
||||
|
||||
let mat = new THREE.MeshStandardMaterial({
|
||||
roughness: 0.8,
|
||||
color: 0xffffff,
|
||||
metalness: 0.2,
|
||||
bumpScale: 0.0005
|
||||
});
|
||||
// obj.castShadow = true;
|
||||
// obj.receiveShadow = true;
|
||||
|
||||
this.textureLoader.load("textures/door.png", function (map)
|
||||
{
|
||||
map.wrapS = THREE.RepeatWrapping;
|
||||
map.wrapT = THREE.RepeatWrapping;
|
||||
map.anisotropy = 16;
|
||||
map.repeat.set(1, 1);
|
||||
mat.map = map;
|
||||
mat.needsUpdate = true;
|
||||
});
|
||||
(<THREE.Mesh>obj).material = mat;
|
||||
// let objLeft = obj.clone();
|
||||
// let objRight = obj.clone();
|
||||
|
||||
|
||||
this.scene.add(obj);
|
||||
}
|
||||
// obj.applyMatrix(Move(new THREE.Vector3(-2.1, 4, 0)));
|
||||
|
||||
// let roMatLeft = new THREE.Matrix4();
|
||||
// roMatLeft.makeRotationZ(Math.PI / 2);
|
||||
// objLeft.applyMatrix(roMatLeft);
|
||||
|
||||
cubemap()
|
||||
{
|
||||
var path = "textures/cube/Park2/";
|
||||
var format = '.jpg';
|
||||
var urls = [
|
||||
path + 'posx' + format, path + 'negx' + format,
|
||||
path + 'posy' + format, path + 'negy' + format,
|
||||
path + 'posz' + format, path + 'negz' + format
|
||||
];
|
||||
var textureCube = new THREE.CubeTextureLoader().load(urls);
|
||||
textureCube.format = THREE.RGBFormat;
|
||||
return textureCube;
|
||||
};
|
||||
// let roMatRight = new THREE.Matrix4();
|
||||
// roMatRight.makeRotationZ(Math.PI / 2);
|
||||
// objRight.applyMatrix(roMatRight);
|
||||
|
||||
drawBox2()
|
||||
{
|
||||
let solid = new Solid3d(1, 1, 1);
|
||||
// objLeft.applyMatrix(Move(new THREE.Vector3(-2, 0, 0)))
|
||||
// objRight.applyMatrix(Move(new THREE.Vector3(2, 0, 0)))
|
||||
|
||||
let obj = solid.Draw(RenderType.Wireframe);
|
||||
|
||||
// obj = new THREE.Mesh(new THREE.SphereGeometry(1, 32, 32));
|
||||
obj.position.set(0, 0, 1);
|
||||
// this.scene.add(obj);
|
||||
// this.scene.add(objLeft);
|
||||
// this.scene.add(objRight);
|
||||
|
||||
obj.castShadow = true;
|
||||
|
||||
let cubeCamera1 = new THREE.CubeCamera(0.1, 15, 1024);
|
||||
let cubeCamera2 = new THREE.CubeCamera(0.1, 15, 1024);
|
||||
cubeCamera1.position.set(0, 0, 1);
|
||||
cubeCamera2.position.set(0, 0, 1);
|
||||
cubeCamera1.renderTarget.texture.minFilter = THREE.LinearMipMapLinearFilter;
|
||||
cubeCamera2.renderTarget.texture.minFilter = THREE.LinearMipMapLinearFilter;
|
||||
cubeCamera1.renderTarget.texture.anisotropy = 16;
|
||||
cubeCamera2.renderTarget.texture.anisotropy = 16;
|
||||
// let skyMaterail = new THREE.MeshStandardMaterial({
|
||||
// roughness: 0.8,
|
||||
// color: 0xffffff,
|
||||
// metalness: 0.2,
|
||||
// bumpScale: 0.0005
|
||||
// })
|
||||
// //天花板.
|
||||
// let skyWall = new Solid3d(4.12, 4, 0.12);
|
||||
// let skyObj = skyWall.Draw(RenderType.Wireframe) as THREE.Mesh;
|
||||
// skyObj.material = skyMaterail;
|
||||
|
||||
// skyObj.applyMatrix(Move(new THREE.Vector3(-2.12, 0, 2.8)));
|
||||
|
||||
this.scene.add(cubeCamera1);
|
||||
this.scene.add(cubeCamera2);
|
||||
// this.scene.add(skyObj);
|
||||
// }
|
||||
|
||||
// drawBox()
|
||||
// {
|
||||
// let solid = new Solid3d(1.2, 0.05, 2.4);
|
||||
|
||||
// let obj = solid.Draw(RenderType.Wireframe);
|
||||
|
||||
// obj.castShadow = true;
|
||||
|
||||
let mat = new THREE.MeshStandardMaterial({
|
||||
roughness: 0.8,
|
||||
metalness: 0.8,
|
||||
// let mat = new THREE.MeshStandardMaterial({
|
||||
// roughness: 0.8,
|
||||
// color: 0xffffff,
|
||||
// emissive: 0x000000,
|
||||
emissiveIntensity: 0,
|
||||
envMap: cubeCamera1.renderTarget.texture,
|
||||
envMapIntensity: 1
|
||||
});
|
||||
|
||||
this.textureLoader.load("textures/Metal/130616_header2.jpg", function (map)
|
||||
{
|
||||
map.wrapS = THREE.RepeatWrapping;
|
||||
map.wrapT = THREE.RepeatWrapping;
|
||||
map.anisotropy = 16;
|
||||
map.repeat.set(1, 1);
|
||||
mat.map = map;
|
||||
mat.needsUpdate = true;
|
||||
});
|
||||
|
||||
this.textureLoader.load("textures/Metal/Titanium-Scuffed_basecolor.png", function (map)
|
||||
{
|
||||
map.wrapS = THREE.RepeatWrapping;
|
||||
map.wrapT = THREE.RepeatWrapping;
|
||||
map.anisotropy = 16;
|
||||
map.repeat.set(1, 1);
|
||||
mat.map = map;
|
||||
mat.needsUpdate = true;
|
||||
});
|
||||
this.textureLoader.load("textures/Metal/Titanium-Scuffed_roughness.png", function (map)
|
||||
{
|
||||
map.wrapS = THREE.RepeatWrapping;
|
||||
map.wrapT = THREE.RepeatWrapping;
|
||||
map.anisotropy = 16;
|
||||
map.repeat.set(1, 1);
|
||||
mat.roughnessMap = map;
|
||||
mat.needsUpdate = true;
|
||||
});
|
||||
this.textureLoader.load("textures/Metal/Titanium-Scuffed_normal.png", function (map)
|
||||
{
|
||||
map.wrapS = THREE.RepeatWrapping;
|
||||
map.wrapT = THREE.RepeatWrapping;
|
||||
map.anisotropy = 16;
|
||||
map.repeat.set(1, 1);
|
||||
mat.normalMap = map;
|
||||
mat.needsUpdate = true;
|
||||
});
|
||||
this.textureLoader.load("textures/Metal/Titanium-Scuffed_metallic.png", function (map)
|
||||
{
|
||||
map.wrapS = THREE.RepeatWrapping;
|
||||
map.wrapT = THREE.RepeatWrapping;
|
||||
map.anisotropy = 16;
|
||||
map.repeat.set(1, 1);
|
||||
mat.metalnessMap = map;
|
||||
mat.needsUpdate = true;
|
||||
});
|
||||
|
||||
let isOne = false;
|
||||
// begin(app.m_Viewer, app.m_Viewer.StartRender, () =>
|
||||
// {
|
||||
// obj.visible = false;
|
||||
// let render = app.m_Viewer.m_Render;
|
||||
// let scene = app.m_Viewer.m_Scene;
|
||||
// metalness: 0.2,
|
||||
// bumpScale: 0.0005
|
||||
// });
|
||||
|
||||
// render.autoClear = true;
|
||||
// // render.clear();
|
||||
// if (isOne)
|
||||
// this.textureLoader.load("textures/door.png", function (map)
|
||||
// {
|
||||
// mat.envMap = cubeCamera2.renderTarget.texture;
|
||||
// cubeCamera2.position.copy(obj.position);
|
||||
// cubeCamera2.update(render, scene);
|
||||
// map.wrapS = THREE.RepeatWrapping;
|
||||
// map.wrapT = THREE.RepeatWrapping;
|
||||
// map.anisotropy = 16;
|
||||
// map.repeat.set(1, 1);
|
||||
// mat.map = map;
|
||||
// mat.needsUpdate = true;
|
||||
// });
|
||||
// (<THREE.Mesh>obj).material = mat;
|
||||
|
||||
|
||||
// this.scene.add(obj);
|
||||
// }
|
||||
// else
|
||||
|
||||
|
||||
// cubemap()
|
||||
// {
|
||||
// mat.envMap = cubeCamera1.renderTarget.texture;
|
||||
// cubeCamera1.position.copy(obj.position);
|
||||
// cubeCamera1.update(render, scene);
|
||||
// }
|
||||
// obj.visible = true;
|
||||
// isOne = !isOne;
|
||||
// var path = "textures/cube/Park2/";
|
||||
// var format = '.jpg';
|
||||
// var urls = [
|
||||
// path + 'posx' + format, path + 'negx' + format,
|
||||
// path + 'posy' + format, path + 'negy' + format,
|
||||
// path + 'posz' + format, path + 'negz' + format
|
||||
// ];
|
||||
// var textureCube = new THREE.CubeTextureLoader().load(urls);
|
||||
// textureCube.format = THREE.RGBFormat;
|
||||
// return textureCube;
|
||||
// };
|
||||
|
||||
// drawBox2()
|
||||
// {
|
||||
// let solid = new Solid3d(1, 1, 1);
|
||||
|
||||
// let obj = solid.Draw(RenderType.Wireframe);
|
||||
|
||||
// // obj = new THREE.Mesh(new THREE.SphereGeometry(1, 32, 32));
|
||||
// obj.position.set(0, 0, 1);
|
||||
|
||||
// obj.castShadow = true;
|
||||
|
||||
// let cubeCamera1 = new THREE.CubeCamera(0.1, 15, 1024);
|
||||
// let cubeCamera2 = new THREE.CubeCamera(0.1, 15, 1024);
|
||||
// cubeCamera1.position.set(0, 0, 1);
|
||||
// cubeCamera2.position.set(0, 0, 1);
|
||||
// cubeCamera1.renderTarget.texture.minFilter = THREE.LinearMipMapLinearFilter;
|
||||
// cubeCamera2.renderTarget.texture.minFilter = THREE.LinearMipMapLinearFilter;
|
||||
// cubeCamera1.renderTarget.texture.anisotropy = 16;
|
||||
// cubeCamera2.renderTarget.texture.anisotropy = 16;
|
||||
|
||||
|
||||
// this.scene.add(cubeCamera1);
|
||||
// this.scene.add(cubeCamera2);
|
||||
|
||||
|
||||
|
||||
|
||||
// let mat = new THREE.MeshStandardMaterial({
|
||||
// roughness: 0.8,
|
||||
// metalness: 0.8,
|
||||
// // color: 0xffffff,
|
||||
// // emissive: 0x000000,
|
||||
// emissiveIntensity: 0,
|
||||
// envMap: cubeCamera1.renderTarget.texture,
|
||||
// envMapIntensity: 1
|
||||
// });
|
||||
(<THREE.Mesh>obj).material = mat;
|
||||
this.scene.add(obj);
|
||||
}
|
||||
|
||||
// this.textureLoader.load("textures/Metal/130616_header2.jpg", function (map)
|
||||
// {
|
||||
// map.wrapS = THREE.RepeatWrapping;
|
||||
// map.wrapT = THREE.RepeatWrapping;
|
||||
// map.anisotropy = 16;
|
||||
// map.repeat.set(1, 1);
|
||||
// mat.map = map;
|
||||
// mat.needsUpdate = true;
|
||||
// });
|
||||
|
||||
loadMaterialNode()
|
||||
{
|
||||
}
|
||||
}
|
||||
// this.textureLoader.load("textures/Metal/Titanium-Scuffed_basecolor.png", function (map)
|
||||
// {
|
||||
// map.wrapS = THREE.RepeatWrapping;
|
||||
// map.wrapT = THREE.RepeatWrapping;
|
||||
// map.anisotropy = 16;
|
||||
// map.repeat.set(1, 1);
|
||||
// mat.map = map;
|
||||
// mat.needsUpdate = true;
|
||||
// });
|
||||
// this.textureLoader.load("textures/Metal/Titanium-Scuffed_roughness.png", function (map)
|
||||
// {
|
||||
// map.wrapS = THREE.RepeatWrapping;
|
||||
// map.wrapT = THREE.RepeatWrapping;
|
||||
// map.anisotropy = 16;
|
||||
// map.repeat.set(1, 1);
|
||||
// mat.roughnessMap = map;
|
||||
// mat.needsUpdate = true;
|
||||
// });
|
||||
// this.textureLoader.load("textures/Metal/Titanium-Scuffed_normal.png", function (map)
|
||||
// {
|
||||
// map.wrapS = THREE.RepeatWrapping;
|
||||
// map.wrapT = THREE.RepeatWrapping;
|
||||
// map.anisotropy = 16;
|
||||
// map.repeat.set(1, 1);
|
||||
// mat.normalMap = map;
|
||||
// mat.needsUpdate = true;
|
||||
// });
|
||||
// this.textureLoader.load("textures/Metal/Titanium-Scuffed_metallic.png", function (map)
|
||||
// {
|
||||
// map.wrapS = THREE.RepeatWrapping;
|
||||
// map.wrapT = THREE.RepeatWrapping;
|
||||
// map.anisotropy = 16;
|
||||
// map.repeat.set(1, 1);
|
||||
// mat.metalnessMap = map;
|
||||
// mat.needsUpdate = true;
|
||||
// });
|
||||
|
||||
// let isOne = false;
|
||||
// // begin(app.m_Viewer, app.m_Viewer.StartRender, () =>
|
||||
// // {
|
||||
// // obj.visible = false;
|
||||
// // let render = app.m_Viewer.m_Render;
|
||||
// // let scene = app.m_Viewer.m_Scene;
|
||||
|
||||
// // render.autoClear = true;
|
||||
// // // render.clear();
|
||||
// // if (isOne)
|
||||
// // {
|
||||
// // mat.envMap = cubeCamera2.renderTarget.texture;
|
||||
// // cubeCamera2.position.copy(obj.position);
|
||||
// // cubeCamera2.update(render, scene);
|
||||
// // }
|
||||
// // else
|
||||
// // {
|
||||
// // mat.envMap = cubeCamera1.renderTarget.texture;
|
||||
// // cubeCamera1.position.copy(obj.position);
|
||||
// // cubeCamera1.update(render, scene);
|
||||
// // }
|
||||
// // obj.visible = true;
|
||||
// // isOne = !isOne;
|
||||
// // });
|
||||
// (<THREE.Mesh>obj).material = mat;
|
||||
// this.scene.add(obj);
|
||||
// }
|
||||
|
||||
|
||||
// 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 { IJsonPatch } from 'mobx-state-tree';
|
||||
import { BlockTableRecord } from './BlockTableRecord';
|
||||
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';
|
||||
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
|
||||
*/
|
||||
@Factory
|
||||
export class Database
|
||||
{
|
||||
m_Data: IDataBaseData
|
||||
//场景
|
||||
m_EntityCollection: Map<number, Entity> = new Map<number, Entity>();//图形集合
|
||||
id: ObjectId;
|
||||
hm: HistoricManage;
|
||||
//块表记录
|
||||
blockTableCol: BlockTableRecord[];
|
||||
//模型空间
|
||||
ModelSpace: BlockTableRecord;
|
||||
//材质字典...
|
||||
MaterialDict: MaerialTableRecord;
|
||||
|
||||
m_MaterialDictionary: MaterialDictionary;
|
||||
constructor()
|
||||
{
|
||||
this.initData();
|
||||
}
|
||||
initData()
|
||||
{
|
||||
this.m_MaterialDictionary = new MaterialDictionary();
|
||||
private idCout = -1;
|
||||
private idMap = new Map<number, ObjectId>();
|
||||
|
||||
this.m_Data = DataBaseData.create();
|
||||
mst.onPatch(this.m_Data, (patch: IJsonPatch, reversePatch: IJsonPatch) =>
|
||||
{
|
||||
if (patch.op == "add")
|
||||
{
|
||||
this.addEntityId(patch.value);
|
||||
}
|
||||
else if (patch.op == "remove")
|
||||
constructor()
|
||||
{
|
||||
this.removeEntityId(reversePatch.value);
|
||||
}
|
||||
})
|
||||
}
|
||||
this.id = ObjectId.Create(this, -100);
|
||||
|
||||
dataIn(data: ISnapDatabaseData)
|
||||
{
|
||||
mst.applySnapshot(this.m_Data, data);
|
||||
}
|
||||
dataOut(): ISnapDatabaseData
|
||||
{
|
||||
return mst.getSnapshot(this.m_Data);
|
||||
}
|
||||
this.ModelSpace = new BlockTableRecord();
|
||||
this.ModelSpace.InitObjectId(this);
|
||||
this.MaterialDict = new MaerialTableRecord();
|
||||
this.MaterialDict.InitObjectId(this);
|
||||
|
||||
//添加图元到数据对象
|
||||
appendEntity(ent: Entity)
|
||||
{
|
||||
if (ent.objectId != 0)
|
||||
{
|
||||
console.warn("已经分配ID的图形不允许再次加入数据库!");
|
||||
return;
|
||||
this.hm = new HistoricManage();
|
||||
this.hm.SetDefaultDb(this);
|
||||
}
|
||||
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++)
|
||||
Destroy()
|
||||
{
|
||||
this.disposeEntity(id);
|
||||
}
|
||||
}
|
||||
this.m_EntityCollection.set(ent.objectId, ent);
|
||||
this.m_Data.addEntity(ent.objectId);
|
||||
ed.UpdateScreen();
|
||||
}
|
||||
getEntity(id: number): Entity
|
||||
{
|
||||
if (this.m_EntityCollection.has(id))
|
||||
{
|
||||
return this.m_EntityCollection.get(id);
|
||||
}
|
||||
return null;
|
||||
this.idMap.clear();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
//删除
|
||||
removeEntityId(ent: number)
|
||||
FileRead(file: CADFile)
|
||||
{
|
||||
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 (ent)
|
||||
if (obj.Db.id === this.id)
|
||||
// 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列表
|
||||
*
|
||||
* @returns {Array<number>}
|
||||
* @memberof Database
|
||||
获得指定索引的id, 注意该id可能为空, 如果需要创建, 请使用 ObjectId.Create,如果需要自动分配,请使用,AllocateId
|
||||
*/
|
||||
getObjectIdCollection(): Array<number>
|
||||
GetObjectId(index: number): ObjectId
|
||||
{
|
||||
return this.m_Data.idColl;
|
||||
}
|
||||
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
|
||||
// })
|
||||
return this.idMap.get(index);
|
||||
}
|
||||
|
||||
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 { Vector3 } from 'three';
|
||||
|
||||
import { Move } from '../Geometry/GeUtils';
|
||||
import { OBB } from '../Geometry/OBB/obb';
|
||||
import { RenderType } from '../GraphicsSystem/Enum';
|
||||
import { Database } from './Database';
|
||||
import { EntityData, IEntityData, ILineData, iSnapshotEntityData, LineData } from './EntityData';
|
||||
import { Factory } from './CADFactory';
|
||||
import { CADFile } from './CADFile';
|
||||
import { CADObject } from './CADObject';
|
||||
import { ObjectId } from './ObjectId';
|
||||
|
||||
export class Entity
|
||||
@Factory
|
||||
export class Entity extends CADObject
|
||||
{
|
||||
/**
|
||||
* 图形所属Db
|
||||
*
|
||||
* @type {Database}
|
||||
* @memberof Entity
|
||||
*/
|
||||
m_Db: Database;
|
||||
protected m_DrawEntity = new Map<RenderType, THREE.Object3D>();
|
||||
//材质id
|
||||
protected m_MaterialId: ObjectId;
|
||||
protected m_Color: number = 7;
|
||||
|
||||
|
||||
/**
|
||||
* 图形数据
|
||||
*
|
||||
* @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()
|
||||
set ColorIndex(v: number)
|
||||
{
|
||||
this.initData();
|
||||
this.m_Color = v;
|
||||
this.Update();
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param data 快照数据 用于还原
|
||||
*/
|
||||
dataIn(data: iSnapshotEntityData)
|
||||
get ColorIndex(): number
|
||||
{
|
||||
mst.applySnapshot(this.m_Data, data);
|
||||
}
|
||||
dataOut(): iSnapshotEntityData
|
||||
{
|
||||
return mst.getSnapshot(this.m_Data);
|
||||
return this.m_Color;
|
||||
}
|
||||
|
||||
Draw(renderType: RenderType): THREE.Object3D
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
get objectId(): number
|
||||
{
|
||||
return this.m_Data.objectId;
|
||||
}
|
||||
set objectId(id: number)
|
||||
{
|
||||
this.m_Data.setObjectId(id);
|
||||
}
|
||||
|
||||
get Size()
|
||||
{
|
||||
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)
|
||||
//绘制一个threeJs对象.
|
||||
Draw(renderType: RenderType = RenderType.Wireframe): THREE.Object3D
|
||||
{
|
||||
this.m_Data.setErase(isErase);
|
||||
}
|
||||
|
||||
getBox(): THREE.Box3
|
||||
if (this.m_DrawEntity && this.m_DrawEntity.has(renderType))
|
||||
{
|
||||
let box = new THREE.Box3();
|
||||
// box.setFromObject(this.m_ThreeObj);
|
||||
return box;
|
||||
return this.m_DrawEntity.get(renderType);
|
||||
}
|
||||
|
||||
getStretchPoints(): Array<THREE.Vector3>
|
||||
{
|
||||
return []
|
||||
}
|
||||
|
||||
getOBB(): OBB
|
||||
{
|
||||
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)
|
||||
{
|
||||
this.m_DrawEntity.forEach(e =>
|
||||
{
|
||||
e.applyMatrix(mat);
|
||||
})
|
||||
}
|
||||
setIsSelct(bool: boolean)
|
||||
//你必须重载该方法来更新绘制,在撤销重做时会自动调用该方法.
|
||||
Update()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export class Curve extends Entity
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
export class Line extends Curve
|
||||
GoodBye()
|
||||
{
|
||||
|
||||
constructor(startPt?: THREE.Vector3, endPt?: THREE.Vector3)
|
||||
for (let [, obj] of this.m_DrawEntity)
|
||||
{
|
||||
super();
|
||||
let data = <ILineData>this.m_Data;
|
||||
|
||||
if (startPt)
|
||||
let geo = obj['Geometry']
|
||||
if (geo && geo instanceof THREE.Geometry)
|
||||
{
|
||||
data.setStartPoint(startPt);
|
||||
if (endPt)
|
||||
data.setEndPoint(endPt);
|
||||
geo.dispose();
|
||||
}
|
||||
obj.parent.remove(obj);
|
||||
}
|
||||
initData()
|
||||
{
|
||||
this.m_Data = LineData.create();
|
||||
}
|
||||
private getData(): ILineData
|
||||
Erase(isErase: boolean = true)
|
||||
{
|
||||
return <ILineData>this.m_Data;
|
||||
}
|
||||
Draw(renderType: RenderType): THREE.Object3D
|
||||
super.Erase(isErase);
|
||||
if (isErase)
|
||||
{
|
||||
if (this.m_DrawEntity.has(renderType))
|
||||
for (let [, en] of this.m_DrawEntity)
|
||||
{
|
||||
return this.m_DrawEntity.get(renderType);
|
||||
}
|
||||
//创建几何体
|
||||
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];
|
||||
en.visible = !isErase;
|
||||
}
|
||||
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();
|
||||
this.m_Center = center;
|
||||
this.m_Radius = radius;
|
||||
return []
|
||||
}
|
||||
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
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
//#region -------------------------File-------------------------
|
||||
|
||||
export class Solid3d extends Entity
|
||||
{
|
||||
constructor(len: number, wid: number, hei: number)
|
||||
//对象从文件中读取数据,初始化自身
|
||||
ReadFile(file: CADFile)
|
||||
{
|
||||
super();
|
||||
this.Size = new THREE.Vector3(len, wid, hei);
|
||||
let ver = file.Read();
|
||||
super.ReadFile(file);
|
||||
this.m_Color = file.Read();
|
||||
}
|
||||
applyMatrix4(mat: THREE.Matrix4)
|
||||
//对象将自身数据写入到文件.
|
||||
WriteFile(file: CADFile)
|
||||
{
|
||||
super.applyMatrix4(mat);
|
||||
// Entity.prototype.applyMatrix4.call(this,mat)
|
||||
file.Write(1);
|
||||
super.WriteFile(file);
|
||||
file.Write(this.m_Color);
|
||||
}
|
||||
Draw(renderType: RenderType): THREE.Object3D
|
||||
{
|
||||
if (this.m_DrawEntity.has(renderType))
|
||||
//局部撤销
|
||||
ApplyPartialUndo(undoData: CADObject)
|
||||
{
|
||||
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;
|
||||
super.ApplyPartialUndo(undoData);
|
||||
this.Update();
|
||||
}
|
||||
//#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