From 980b5529fb203a2b51f9a4951a4998e28e4331cc Mon Sep 17 00:00:00 2001 From: cx Date: Sun, 17 Dec 2017 23:32:08 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=95=B0=E6=8D=AE=E6=8C=81?= =?UTF-8?q?=E4=B9=85=E5=8C=96=E8=AE=BE=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __test__/FileSystem/FileSystem.test.ts | 288 +++++++++++++++----- __test__/FileSystemImmutable.test.ts | 353 ------------------------- __test__/Geometry/Vector3Ext.test.ts | 15 -- 3 files changed, 223 insertions(+), 433 deletions(-) delete mode 100644 __test__/FileSystemImmutable.test.ts diff --git a/__test__/FileSystem/FileSystem.test.ts b/__test__/FileSystem/FileSystem.test.ts index 653ce9ac2..cb8a1d2f1 100644 --- a/__test__/FileSystem/FileSystem.test.ts +++ b/__test__/FileSystem/FileSystem.test.ts @@ -1,5 +1,6 @@ import { ArrayRemove } from '../../src/Common/Utils'; +import { Vector3 } from 'three'; /* 关于webCAD 文件系统的原型. 包括了对象的保存,撤销,还原. @@ -96,12 +97,13 @@ cmdName:"Ohther" //假设这个是一个复杂度很高的命令 id只有在一个情况下才会更新.跨文档复制时. 问题:对象的id如何分配. +在加入到图形记录时,分配id. - -*/ - +撤销创建对象,采用完全撤销模式,删除对象与集合的记录. +还原对象时,创建对象,并且加入集合. +*/ //CAD对象工厂,通过注册 和暴露的创建方法,动态创建对象 @@ -130,16 +132,16 @@ class CADObject { //#region -------------------------DB------------------------- - protected db: Database; + protected _db: Database; get Db(): Database { - return this.db; + return this._db; } SetDb(db: Database) { - if (!this.db) + if (!this._db) { - this.db = db; + this._db = db; this.objectId = db.AllocateId(this); } else @@ -150,14 +152,14 @@ class CADObject //#endregion //#region -------------------------isErase------------------------- - protected isErase: boolean = false; + protected _isErase: boolean = false; get IsErase(): boolean { - return this.isErase; + return this._isErase; } Erase(isErase: boolean = true) { - this.isErase = isErase; + this._isErase = isErase; } //#endregion @@ -182,49 +184,153 @@ class CADObject //对象从文件中读取数据,初始化自身 FileIn(file: CADFile) { + //write Id; + this.objectId = this.ReadObjectId(file); + if (this.objectId) + { + this.objectId.Object = this; + } } //对象将自身数据写入到文件. FileOut(file: CADFile) { + this.WriteObjectId(file) } //局部撤销 - ApplyPartialUndo(file: CADFile) + ApplyPartialUndo(file: CADObject) { } //#endregion + + + private WriteObjectId(file: CADFile) + { + if (this.objectId) + { + file.Write(this.objectId.Index); + } + else + file.Write(-1); + } + private ReadObjectId(file: CADFile): ObjectId + { + let index = file.Read(); + if (index >= 0 && this._db) + { + return this._db.GetObjectId(index); + } + } } +/* +CADObject对象拥有Id属性,用来记录引用关系. +通过id可以得到对应的关联实体,或者记录实体的关联关系. + +ObjectId必须使用 Database分配(db里面会存id的列表,以便同时更新id指向实体) + +*/ class ObjectId { private id: number; private obj: CADObject; - constructor(id: number, obj: CADObject) + private constructor() { - this.id = id; - this.obj = obj; + this.id = -1; + } + static Create(db: Database, index: number): ObjectId + { + let id = db.GetObjectId(index); + if (!id) + { + id = new ObjectId(); + id.id = index; + } + return id; } + set Object(v: CADObject) + { + this.obj = v; + } get Object(): CADObject { return this.obj; } + get Index(): number + { + return this.id; + } } //cad文件数据 class CADFile { + private readIndex: number = 0; + private dataList: any[] = []; + WriteString(str: string) + { + this.dataList.push(str); + } + ReadString(): string + { + let str = this.dataList[this.readIndex] as string; + this.readIndex++; + return str; + } + WriteObject(obj: CADObject) + { + this.WriteString(obj.ClassName); + obj.FileOut(this); + } + ReadObject(db: Database): CADObject + { + let className = this.ReadString(); + let obj = CADFactory.CreateObject(className); + obj.SetDb(db); + obj.FileIn(this); + return obj; + } + + Write(data: any) + { + this.dataList.push(data); + } + Read(): any + { + let data = this.dataList[this.readIndex]; + this.readIndex++; + return data; + } } class AppendData extends CADObject { - objData: CADFile; + private object: CADObject; + private cadFile: CADFile; + constructor(obj: CADObject) + { + super(); + this.cadFile = new CADFile(); + this.cadFile.WriteObject(obj); + } + + getObject(db: Database): CADObject + { + if (!this.object) + { + this.object = this.cadFile.ReadObject(db); + } + + return this.object; + } + //#region -----------------------------File----------------------------- //对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化 //类名,保证序列化时得到正确的new get ClassName(): string { - return "CADObject"; + return "AppendData"; } //对象从文件中读取数据,初始化自身 FileIn(file: CADFile) @@ -233,20 +339,29 @@ class AppendData extends CADObject FileOut(file: CADFile) { } //局部撤销 - ApplyPartialUndo(file: CADFile) + ApplyPartialUndo(file: CADObject) { } //#endregion -----------------------------File End----------------------------- } class RemoveData extends CADObject { - index: number; + private index: number; + constructor(index: number) + { + super(); + this.index = index; + } + get Index() + { + return this.index; + } //#region -----------------------------File----------------------------- //对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化 //类名,保证序列化时得到正确的new get ClassName(): string { - return "CADObject"; + return "RemoveData"; } //对象从文件中读取数据,初始化自身 FileIn(file: CADFile) @@ -255,7 +370,7 @@ class RemoveData extends CADObject FileOut(file: CADFile) { } //局部撤销 - ApplyPartialUndo(file: CADFile) + ApplyPartialUndo(file: CADObject) { } //#endregion -----------------------------File End----------------------------- } @@ -268,23 +383,31 @@ class ObjectCollection extends CADObject { this.objectCol.push(obj); - let hisRec = new HistoricRecord(); - let redo = new AppendData(); - redo.objData = new CADFile(); - obj.FileOut(redo.objData); - hisRec.redoData = redo; - let undo = new RemoveData(); - undo.index = this.objectCol.length - 1; - hisRec.undoData = undo; + if (this._db && this._db.hm.UndoData) + { + let hisRec = new HistoricRecord(); + hisRec.redoData = new AppendData(obj); + hisRec.undoData = new RemoveData(this.objectCol.length - 1); - this.db.hm.UndoData.WriteObjectHistoryPath(this, hisRec); + this._db.hm.UndoData.WriteObjectHistoryPath(this, hisRec); + } } Remove(obj: CADObject) { ArrayRemove(this.objectCol, obj); + if (this._db && this._db.hm.UndoData) + { + let hisRec = new HistoricRecord(); + hisRec.undoData = new AppendData(obj); + hisRec.redoData = new RemoveData(this.objectCol.length - 1); - this.db.hm.UndoData.WriteObjectHistoryPath(this, undefined); + this._db.hm.UndoData.WriteObjectHistoryPath(this, hisRec); + } + } + Cout(): number + { + return this.objectCol.length; } //#region -----------------------------File----------------------------- @@ -301,17 +424,15 @@ class ObjectCollection extends CADObject FileOut(file: CADFile) { } //局部撤销 - ApplyPartialUndo(file: CADObject) + ApplyPartialUndo(undoData: CADObject) { - if (file instanceof AppendData) + if (undoData instanceof AppendData) { - file.objData//cad file. - //create object - //append object + let obj = undoData.getObject(this._db); } - else if (file instanceof RemoveData) + else if (undoData instanceof RemoveData) { - //remove object + this.Remove(this.objectCol[undoData.Index]); } } //#endregion -----------------------------File End----------------------------- @@ -363,14 +484,19 @@ class HistoricManage extends CADObject { private curIndex: number = -1; //当前执行位置 private historyRecord: CommandHistoryRecord[] = []; //历史记录 + private doing: boolean = false; constructor(db: Database) { super(); - this.db = db; + this._db = db; } get UndoData(): CommandHistoryRecord { + if (this.doing) + { + return undefined; + } if (this.historyRecord.length === 0) { this.StartCmd(""); @@ -392,7 +518,7 @@ class HistoricManage extends CADObject { return false; } - + this.doing = true; for (let [id, recList] of historyRec.HistoryList) { let obj = id.Object; @@ -402,7 +528,7 @@ class HistoricManage extends CADObject } } this.curIndex--; - + this.doing = false; return true; } Redo() @@ -412,6 +538,7 @@ class HistoricManage extends CADObject { return false; } + this.doing = true; for (let [id, recList] of historyRec.HistoryList) { let obj = id.Object; @@ -421,7 +548,7 @@ class HistoricManage extends CADObject } } this.curIndex++; - + this.doing = false; return true; } } @@ -478,7 +605,7 @@ class Database if (obj.Db === this) { this.idCout++; - let id = new ObjectId(this.idCout, obj); + let id = ObjectId.Create(this, this.idCout); this.idMap.set(this.idCout, id); return id; } @@ -487,18 +614,15 @@ class Database console.warn("对象不属于该数据库!"); } } - //获得指定索引的id - GetId(index: number) + GetObjectId(index: number): ObjectId { return this.idMap.get(index); } } - -class BlockTableRecord extends CADObject +class BlockTableRecord extends ObjectCollection { - private objectCol: CADObject[] = []; constructor(db: Database) { super(); @@ -519,8 +643,10 @@ class BlockTableRecord extends CADObject FileOut(file: CADFile) { } //局部撤销 - ApplyPartialUndo(file: CADFile) - { } + ApplyPartialUndo(file: CADObject) + { + super.ApplyPartialUndo(file); + } //#endregion-----------------------------File End----------------------------- AppendEntity(ent: Entity): ObjectId { @@ -530,28 +656,19 @@ class BlockTableRecord extends CADObject return; } ent.SetDb(this.Db); - this.objectCol.push(ent); - - let historyData = new HistoricRecord(); - // historyData.undoData - this.db.hm.UndoData.WriteObjectHistoryPath(this, historyData); + this.Append(ent); return ent.Id; } -} -enum EntityUndoType -{ } - - //所有图元的基类 class Entity extends CADObject { } //直线撤销类型 -export enum LineUndoType +export enum LineUndoType { Full = 0, StartPoint = 1, @@ -561,9 +678,11 @@ export enum LineUndoType //直线对象 class Line extends Entity { + private startPoint: Vector3; constructor() { super(); + this.startPoint = new Vector3(0, 0, 0); } //-----------------------------File----------------------------- @@ -578,10 +697,14 @@ class Line extends Entity //对象从文件中读取数据,初始化自身 FileIn(file: CADFile) { + super.FileIn(file); + this.startPoint.fromArray(file.Read()); } //对象将自身数据写入到文件. FileOut(file: CADFile) { + super.FileOut(file); + file.Write(this.startPoint.toArray()); } ApplyPartialUndo(data) { @@ -596,19 +719,54 @@ class Line extends Entity } } //-----------------------------File End----------------------------- + + + set StartPoint(v: Vector3) + { + this.startPoint.copy(v); + } + get StartPoint(): Vector3 + { + return this.startPoint.clone(); + } } CADFactory.RegisterObject(Line); -let l = CADFactory.CreateObject("Line") as Entity; +let db = new Database(); + +let l = CADFactory.CreateObject("Line") as Line; console.log(l); -let db = new Database(); +l.StartPoint = new Vector3(0, 1, 0); let id = db.ModelSpace.AppendEntity(l); -db.GetId(0).Object.ClassName /*?*/ +db.GetObjectId(0).Object.ClassName /*?*/ console.log(id); -db.hm.Undo();/*?*/ -db.hm.Redo();/*?*/ +function createLine() +{ + for (let i = 0; i < 5000; i++) + { + let l = CADFactory.CreateObject("Line") as Line; + } +} + +test('create line', () => +{ +}); + +// createLine(); //?. + + +function undoRedo() +{ + for (let i = 0; i < 5000; i++) + { + db.hm.Undo(); + db.hm.Redo(); + } +} + +// undoRedo(); //?. diff --git a/__test__/FileSystemImmutable.test.ts b/__test__/FileSystemImmutable.test.ts deleted file mode 100644 index 1f2b8aebb..000000000 --- a/__test__/FileSystemImmutable.test.ts +++ /dev/null @@ -1,353 +0,0 @@ -/* -关于webCAD 文件系统的原型. -包括了对象的保存,撤销,还原. - -对象的绘制 更新. - -对象ID更新 引用 - -材质字典 - -关于对象的撤销和重做设计. - - -*/ - - -import { List } from "immutable" - - -class CADObject -{ - - ApplyUndoData(data: any) - { - - } -} - - -/** - * 表示了一个图纸该有的数据结构 - * - * @class Database - */ -class Database extends CADObject -{ - - private curUndoIndex = -1; - //命令撤销数据列表 - commandUndoData: { cmdName: string, undoData: Map }[] = []; - - - get UndoData(): Map - { - if (this.commandUndoData.length == 0) - { - this.startCmd(""); - } - return this.commandUndoData[this.commandUndoData.length - 1].undoData; - } - - startCmd(cmdName: string) - { - if (this.commandUndoData.length > 0 && this.curUndoIndex != this.commandUndoData.length - 1) - { - this.commandUndoData.splice(this.curUndoIndex, this.commandUndoData.length - this.curUndoIndex); - } - - this.commandUndoData.push({ cmdName: "", undoData: new Map() }); - this.curUndoIndex = this.commandUndoData.length - 1; - } - - Undo(cout: number) - { - if (this.curUndoIndex == -1) - { - return; - } - - for (let [obj, data] of this.commandUndoData[this.curUndoIndex].undoData) - { - for (let i = data.m_UndoDataList.length; i--;) - { - let d = data.m_UndoDataList[i]; - obj.ApplyUndoData(d); - } - } - this.curUndoIndex--; - } - Redo(cout: number) - { - let undoFile = this.commandUndoData[this.curUndoIndex + 1]; - if (undoFile) - { - for (let [obj, data] of undoFile.undoData) - { - for (let d of data.m_UndoDataList) - { - obj.ApplyUndoData(d); - } - } - this.curUndoIndex++; - } - } -} - -let arr = [0, 1, 2, 3, 4, 5, 6]; -arr.splice(3, arr.length - 3); - -arr - - -/** - * - * - * @class UndoFile - */ -class UndoFile -{ - m_UndoDataList = []; -} - - - - -enum EntityUndoType -{ - -} - -// -interface EntityData -{ - id: number; - isErase: boolean; -} - -/** - * - * 所有图元的基类 - * - * @class Entity - */ -class Entity extends CADObject -{ - protected m_Data: EntityData; - m_Db: Database; - constructor() - { - super(); - this.m_Data = { - id: -1, - isErase: false - } - } - - - get UndoFile(): UndoFile - { - if (this.m_Db) - { - let undoData = this.m_Db.UndoData; - if (!undoData.has(this)) - { - undoData.set(this, new UndoFile()); - } - return undoData.get(this); - } - } - - WriteUndoData(data: any) - { - let undoFile = this.UndoFile; - if (undoFile) - { - undoFile.m_UndoDataList.push(data); - } - } -} - - -/** - * 直线撤销类型 - * - * @enum {number} - */ -enum LineUndoType -{ - Full = 0, - StartPoint = 1, - EndPoint = 2, -} - -// -interface LineData extends EntityData -{ - startPoint: List, - endPoint: List -} - -/** - * 直线对象 - * - * @class Line - */ -class Line extends Entity -{ - protected m_Data: LineData; - constructor() - { - super(); - this.m_Data.startPoint = List([0, 0, 0]); - this.m_Data.endPoint = List([0, 0, 0]); - } - get StartPoint(): number[] - { - return this.m_Data.startPoint.toJS(); - } - set StartPoint(value: number[]) - { - let newP = List(value); - this.WriteUndoData({ type: LineUndoType.StartPoint, data: { startPoint: this.m_Data.startPoint } }); - this.m_Data.startPoint = newP; - } - - ApplyUndoData(data: any) - { - switch (data.type) - { - case LineUndoType.Full: - break; - case LineUndoType.StartPoint: - this.m_Data.startPoint = data.data.startPoint; - break; - default: - break; - } - } -} - -/** - * 图纸绘制适配器,使用适配器绘制对象图元. - * - * @class EentiyDrawAdapter - */ -class EentiyDrawAdapter -{ - Draw() - { - return undefined; - } -} - - -/** - * 直线的绘制适配 - * - * @class LineAdapter - * @extends {EentiyDrawAdapter} - */ -class LineAdapter extends EentiyDrawAdapter -{ - Draw() - { - return undefined; - } - - Update(type: number) - { - switch (type) - { - case LineUndoType.Full: - break; - case LineUndoType.StartPoint: - break; - case LineUndoType.EndPoint: - break; - default: - break; - } - } -} - - -let line = new Line(); - -console.log(line); - -line.StartPoint = [1, 2, 3]; - -console.log(line); - - -let db = new Database(); - -line.m_Db = db; - - -line.StartPoint = [3, 3, 3]; - -console.log(line); -line.StartPoint = [3, 3, 5]; - -line.StartPoint = [12, 3, 5]; -console.log(line); - -console.log(db.commandUndoData); - -db.Undo(1); - -console.log(line.StartPoint); - -db.Redo(1); - -db.startCmd(""); - -console.log(line.StartPoint); - - - - -function per() -{ - for (let i = 0; i < 5000; i++) - { - new Line(); - } -} - -function per2() -{ - for (let i = 0; i < 5000; i++) - { - - line.StartPoint = [3, 3, 3]; - - // console.log(line); - // line.StartPoint = [3, 3, 5]; - - line.StartPoint = [12, 3, 5]; - // console.log(line); - - // console.log(db.commandUndoData); - - db.Undo(1); - - // console.log(line); - - db.Redo(1); - - db.startCmd(""); - - // console.log(line.StartPoint); - } -} - -per();/*?.*/ -per2();/*?.*/ -per2();/*?.*/ -per2();/*?.*/ -per2();/*?.*/ - -console.log(3); diff --git a/__test__/Geometry/Vector3Ext.test.ts b/__test__/Geometry/Vector3Ext.test.ts index c407669a9..e69de29bb 100644 --- a/__test__/Geometry/Vector3Ext.test.ts +++ b/__test__/Geometry/Vector3Ext.test.ts @@ -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); -}) \ No newline at end of file