From 6052844c2c541239560f10f00ec116b30e288f95 Mon Sep 17 00:00:00 2001 From: ChenX Date: Wed, 10 Oct 2018 14:04:48 +0800 Subject: [PATCH] =?UTF-8?q?!166=20=E5=8F=8C=E5=87=BB=E5=A4=9A=E6=AE=B5?= =?UTF-8?q?=E7=BA=BF=20Merge=20pull=20request=20!166=20from=20ZoeLeeFZ/dbc?= =?UTF-8?q?lickPl?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/DatabaseServices/Entity.ts | 7 + src/DatabaseServices/Point.ts | 47 +-- src/DatabaseServices/Polyline.ts | 11 + src/DatabaseServices/Spline.ts | 27 +- src/Editor/DbClick.ts | 44 -- src/Editor/DbClick/DBClickPolyline.ts | 386 ++++++++++++++++++ src/Editor/DbClick/DbClick.ts | 59 +++ src/Editor/GetKeyWordService.tsx | 2 +- src/Editor/MouseControls.ts | 2 +- src/UI/Components/ContextMenu/ContextMenu.tsx | 5 +- 10 files changed, 496 insertions(+), 94 deletions(-) delete mode 100644 src/Editor/DbClick.ts create mode 100644 src/Editor/DbClick/DBClickPolyline.ts create mode 100644 src/Editor/DbClick/DbClick.ts diff --git a/src/DatabaseServices/Entity.ts b/src/DatabaseServices/Entity.ts index c50579455..cbcab53ed 100644 --- a/src/DatabaseServices/Entity.ts +++ b/src/DatabaseServices/Entity.ts @@ -83,6 +83,13 @@ export class Entity extends CADObject return new Vector3().setFromMatrixPosition(this.m_Matrix); } + set Position(v: Vector3) + { + this.WriteAllObjectRecord(); + this.m_Matrix.setPosition(v); + this.Update(); + } + get OCSInv(): Matrix4 { return new Matrix4().getInverse(this.m_Matrix); diff --git a/src/DatabaseServices/Point.ts b/src/DatabaseServices/Point.ts index c4cfca7bf..e18e5bdbf 100644 --- a/src/DatabaseServices/Point.ts +++ b/src/DatabaseServices/Point.ts @@ -1,8 +1,7 @@ -import { AdditiveBlending, BufferGeometry, Float32BufferAttribute, Geometry, Object3D, Points, PointsMaterial, TextureLoader, Vector3 } from "three"; +import { AdditiveBlending, BufferGeometry, Float32BufferAttribute, Object3D, Points, PointsMaterial, TextureLoader, Vector3 } from "three"; import { MoveMatrix } from "../Geometry/GeUtils"; import { RenderType } from "../GraphicsSystem/Enum"; import { Factory } from "./CADFactory"; -import { CADFile } from "./CADFile"; import { Entity } from "./Entity"; let pointMaterial: PointsMaterial; @@ -28,11 +27,10 @@ LoadPointMaterial(); @Factory export class Point extends Entity { - private m_Position: Vector3; constructor(position: Vector3 = new Vector3()) { super(); - this.m_Position = position; + this.m_Matrix.setPosition(position); } /** @@ -46,33 +44,13 @@ export class Point extends Entity protected InitDrawObject(renderType: RenderType = RenderType.Wireframe): Object3D { let geometry = new BufferGeometry(); - geometry.addAttribute("position", new Float32BufferAttribute(this.m_Position.toArray(), 3)); + geometry.addAttribute("position", new Float32BufferAttribute([0, 0, 0], 3)); return new Points(geometry, LoadPointMaterial()); } - - private UpdateGeometry(geometry: Geometry) - { - } - - - /** - * 当实体需要更新时,需要重载该方法,实现实体更新 - * - * @param {RenderType} type - * @param {Object3D} en - * @memberof Entity - */ - UpdateDrawObject(type: RenderType, en: Object3D) - { - - } - - GetSnapPoints(): Array { - return [this.m_Position.clone().applyMatrix4(this.OCS)]; + return [this.Position]; } - MoveSnapPoints(indexList: number[], vec: Vector3) { if (indexList.length === 1) @@ -98,21 +76,4 @@ export class Point extends Entity { this.MoveSnapPoints(indexList, vec); } - - //#region -------------------------File------------------------- - - //对象从文件中读取数据,初始化自身 - ReadFile(file: CADFile) - { - let ver = file.Read(); - super.ReadFile(file); - this.m_Position.fromArray(file.Read()); - } - //对象将自身数据写入到文件. - WriteFile(file: CADFile) - { - file.Write(1); - super.WriteFile(file); - file.Write(this.m_Position.toArray()); - } } diff --git a/src/DatabaseServices/Polyline.ts b/src/DatabaseServices/Polyline.ts index 10a31e050..67202cfff 100644 --- a/src/DatabaseServices/Polyline.ts +++ b/src/DatabaseServices/Polyline.ts @@ -102,11 +102,22 @@ export class Polyline extends Curve { if (index < this.m_LineData.length) { + this.WriteAllObjectRecord(); this.m_LineData.splice(index, 1); this.Update(); } return this; } + RemoveVertexIn(from: number, to: number): this + { + if (from + 1 < this.m_LineData.length && to > from) + { + this.WriteAllObjectRecord(); + this.m_LineData.splice(from + 1, to - from - 1); + this.Update(); + } + return this; + } GetPoint2dAt(index: number): Vector2 | undefined { if (index >= 0 && this.m_LineData.length > index) diff --git a/src/DatabaseServices/Spline.ts b/src/DatabaseServices/Spline.ts index 35944401a..28aa32a7e 100644 --- a/src/DatabaseServices/Spline.ts +++ b/src/DatabaseServices/Spline.ts @@ -6,12 +6,14 @@ import { RenderType } from '../GraphicsSystem/Enum'; import { Factory } from './CADFactory'; import { CADFile } from './CADFile'; import { Curve } from './Curve'; +import { equalv3 } from '../Geometry/GeUtils'; @Factory export class Spline extends Curve { private m_PointList: Vector3[]; + private m_ClosedMark: boolean = false; constructor(points?: Vector3[]) { super(); @@ -28,6 +30,22 @@ export class Spline extends Curve this.m_PointList = v; this.Update(); } + //闭合标志 + get CloseMark(): boolean + { + return this.m_ClosedMark; + } + //曲线是否闭合 + get IsClose(): boolean + { + return this.CloseMark || (equalv3(this.StartPoint, this.EndPoint, 1e-4)) && this.EndParam > 1; + } + set CloseMark(v: boolean) + { + this.WriteAllObjectRecord(); + this.m_ClosedMark = v; + this.Update() + } get StartPoint() { return this.m_PointList[0]; @@ -46,11 +64,11 @@ export class Spline extends Curve } GetSnapPoints() { - return this.m_PointList + return this.m_PointList.map(p => p.clone().applyMatrix4(this.OCS)); } GetStretchPoints() { - return this.m_PointList; + return this.GetSnapPoints(); } MoveSnapPoints(indexList: Array, vec: Vector3) { @@ -83,7 +101,10 @@ export class Spline extends Curve let spl = en as THREE.Line; let geo = spl.geometry as Geometry; geo.dispose(); - + if (this.CloseMark && !equalv3(this.m_PointList[0], arrayLast(this.m_PointList))) + { + this.m_PointList.push(this.m_PointList[0].clone()); + } let curve = new THREE.CatmullRomCurve3(this.Points); spl.geometry = new Geometry().setFromPoints(curve.getPoints(this.Points.length * 10)); geo.verticesNeedUpdate = true; diff --git a/src/Editor/DbClick.ts b/src/Editor/DbClick.ts deleted file mode 100644 index af22306ec..000000000 --- a/src/Editor/DbClick.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { PointPick } from "./PointPick"; -import { PointLight } from "../DatabaseServices/PointLight"; -import { app } from "../ApplicationServices/Application"; -import { LightModal } from "../UI/Components/Modal/LightModal"; -import { ModalPosition } from "../UI/Components/Modal/ModalsManage"; -import { Text } from "../DatabaseServices/Text/Text"; -import { Board } from "../DatabaseServices/Board"; -import { BoardOptionModal } from "../UI/Components/Board/BoardOptionModal"; -import { Singleton } from "../Common/Singleton"; -import { TextArea } from "../DatabaseServices/Text/TextArea"; -import { Entity } from "../DatabaseServices/Entity"; - -export class DbClickManager -{ - OnDbClick() - { - let en = PointPick(app.m_Editor.m_MouseCtrl.m_CurMousePointVCS, app.m_Viewer)[0]; - //防止双击到Jig对象 - if (!en || !en.userData - || !(en.userData instanceof Entity) - || !en.userData.Id) - return; - //双击实体取消选中状态 - app.m_Editor.m_SelectCtrl.Cancel(); - - if (en.userData instanceof PointLight) - { - app.m_Editor.m_ModalManage.RenderModeless(LightModal, ModalPosition.Right, { selectedObj: en.userData }); - } - else if (en.userData instanceof Text) - { - let textarea = Singleton.GetInstance(TextArea); - textarea.StartEditorText(en); - } - else if (en.userData instanceof Board) - { - app.m_Editor.m_ModalManage.RenderModeless( - BoardOptionModal, - ModalPosition.Right, - { board: en.userData } - ); - } - } -} diff --git a/src/Editor/DbClick/DBClickPolyline.ts b/src/Editor/DbClick/DBClickPolyline.ts new file mode 100644 index 000000000..f8b4d3299 --- /dev/null +++ b/src/Editor/DbClick/DBClickPolyline.ts @@ -0,0 +1,386 @@ +import { app } from "../../ApplicationServices/Application"; +import { arraySortByNumber } from "../../Common/ArrayExt"; +import { curveLinkGroup, Vec3DTo2D } from "../../Common/CurveUtils"; +import { KeyWord } from "../../Common/InputState"; +import { Curve } from "../../DatabaseServices/Curve"; +import { Point } from "../../DatabaseServices/Point"; +import { Polyline, PolylineProps } from "../../DatabaseServices/Polyline"; +import { Spline } from "../../DatabaseServices/Spline"; +import { equaln, equalv3 } from "../../Geometry/GeUtils"; +import { Jig } from "../Jig"; +import { PromptStatus } from "../PromptResult"; +import { log } from "../../Common/Utils"; + +interface IVertex +{ + index: number; + point: Point; +} +export class DBClickPolyline +{ + private entity: Curve; + HandlePolyline = async (pl: Polyline) => + { + this.entity = pl; + + //默认关键字列表 + const defaultKW: KeyWord[] = [ + { key: "C", msg: "闭合" }, + { key: "J", msg: "合并" }, + { key: "E", msg: "编辑顶点" }, + // { key: "F", msg: "拟合" }, + // { key: "S", msg: "样条曲线" }, + { key: "D", msg: "非曲线化" }, + { key: "R", msg: "反转" }, + { key: "U", msg: "放弃" } + ]; + + //操作记录数,用于撤销双击后的操作 + let totalRecCount = 0; + while (true) + { + let pl = this.entity as Polyline; + + defaultKW[0].key = pl.CloseMark ? "O" : "C"; + defaultKW[0].msg = pl.CloseMark ? "打开" : "闭合"; + + let res = await app.m_Editor.GetKeyWords({ + Msg: "请输入选项", + KeyWordList: defaultKW + }) + + if (res.Status !== PromptStatus.Keyword) + return; + + let execStatus = PromptStatus.OK; + + switch (res.StringResult) + { + case "C": //闭合 + app.m_Database.hm.StartCmd(""); + totalRecCount++; + pl.CloseMark = true; + app.m_Database.hm.EndCmd(); + break; + case "O": //打开 + app.m_Database.hm.StartCmd(""); + totalRecCount++; + pl.CloseMark = false; + app.m_Database.hm.EndCmd(); + break; + case "J": //合并 + if (!pl.CloseMark) + { + app.m_Database.hm.StartCmd(""); + totalRecCount++; + execStatus = await this.Join(); + app.m_Database.hm.EndCmd(); + } + else + log("无法合并闭合多段线") + + break; + case "E": //编辑顶点 + execStatus = await this.EditorVertex(); + Jig.Destroy(); + break; + case "D": //非曲线化 + totalRecCount++; + this.TransfromNonCurve(); + break; + case "R": //反转 + totalRecCount++; + app.m_Database.hm.StartCmd(""); + pl.Reverse(); + app.m_Database.hm.EndCmd(); + break; + case "U": //放弃 + if (totalRecCount > 0) + { + totalRecCount--; + app.m_Database.hm.Undo(); + } + + break; + } + app.m_Editor.UpdateScreen(); + if (execStatus === PromptStatus.Cancel) + return; + } + } + private EditorVertex = async () => + { + //编辑顶点关键字列表 + const editeVertexKW: KeyWord[] = [ + { key: "N", msg: "下一个" }, + { key: "P", msg: "上一个" }, + { key: "B", msg: "打断" }, + { key: "I", msg: "插入" }, + { key: "M", msg: "移动" }, + { key: "S", msg: "拉直" }, + // { key: "T", msg: "切向" }, + { key: "X", msg: "退出" }, + ]; + + //顶点位置 + let vertex: IVertex = { + index: 0, + point: Jig.Draw(new Point(this.entity.StartPoint)) + }; + + //存储前后顶点索引 + let indexList: number[] = []; + + while (true) + { + app.m_Editor.UpdateScreen(); + + let res = await app.m_Editor.GetKeyWords({ + Msg: "输入顶点编辑选项", + KeyWordList: editeVertexKW + }) + + if (res.Status !== PromptStatus.Keyword) + { + return PromptStatus.Cancel; + } + + let execStatus = PromptStatus.OK; + + switch (res.StringResult) + { + case "N": //下一个顶点 + this.ToggleVertex(vertex, true); + break; + case "P": //上一个 + this.ToggleVertex(vertex, false); + break; + case "B": //打断 + //存入第一个索引 + indexList.push(vertex.index); + execStatus = await this.ExecEditor(vertex, indexList, "B"); + break; + case "I": //插入 + app.m_Database.hm.StartCmd(""); + execStatus = await this.ChangeVertex(vertex, false); + app.m_Database.hm.EndCmd(); + break; + case "M": //移动 + app.m_Database.hm.StartCmd(""); + execStatus = await this.ChangeVertex(vertex, true); + app.m_Database.hm.EndCmd(); + break; + case "S": //拉直 + indexList.push(vertex.index); + execStatus = await this.ExecEditor(vertex, indexList, "S"); + break + case "X": //退出 + return PromptStatus.None; + } + if (execStatus === PromptStatus.Cancel) + { + return PromptStatus.Cancel; + } + } + } + private ExecEditor = async (vertex: IVertex, indexList: number[], editorCommand: string) => + { + //打断/拉直关键字列表 + const execKW: KeyWord[] = [ + { key: "N", msg: "下一个" }, + { key: "P", msg: "上一个" }, + { key: "G", msg: "执行" }, + { key: "X", msg: "退出" } + ]; + + while (true) + { + let res = await app.m_Editor.GetKeyWords({ + Msg: "请输入选项", + KeyWordList: execKW + }) + + if (res.Status !== PromptStatus.Keyword) + { + return PromptStatus.Cancel; + } + + switch (res.StringResult) + { + case "N": //下一个顶点 + this.ToggleVertex(vertex, true); + break; + case "P": //上一个 + this.ToggleVertex(vertex, false); + break; + case "G": //执行 + this.ExecSAndBCommand(indexList, vertex, editorCommand); + case "X": //退出 + return PromptStatus.None; + } + app.m_Editor.UpdateScreen(); + } + } + private Join = async () => + { + let pl = this.entity as Polyline; + let exSsRes = await app.m_Editor.GetSelection({ + Msg: "请选择对象<全部选择>:", + Filter: { filterTypes: [Curve] } + }); + if (exSsRes.Status === PromptStatus.Cancel) + return PromptStatus.Cancel; + + let cus = exSsRes.SelectSet.SelectEntityList as Curve[]; + if (!cus.includes(pl)) + cus.push(pl); + + let groups = curveLinkGroup(cus); + for (let g of groups) + { + if (!g.includes(pl)) + continue; + + for (let cu of g) + { + if (cu !== pl) + { + pl.Join(cu); + cu.Erase(); + } + } + } + return PromptStatus.OK; + } + private ToggleVertex(vertex: IVertex, isNext: boolean) + { + let pl = this.entity as Polyline; + isNext ? vertex.index++ : vertex.index--; + if (vertex.index < 0) + vertex.index = 0; + else if (vertex.index > pl.EndParam) + vertex.index = pl.EndParam; + + vertex.point.Position = pl.GetPointAtParam(vertex.index); + } + private Break(indexList: number[]) + { + let pl = this.entity as Polyline; + let cus = pl.GetSplitCurves(indexList); + pl.Erase(); + this.entity = null; + + for (let cu of cus) + { + if (indexList.length === 2) + { + if (equalv3(cu.StartPoint, pl.GetPointAtParam(Math.min(...indexList)))) + continue; + } + if (!this.entity) this.entity = cu; + app.m_Database.ModelSpace.Append(cu) + } + } + //改变顶点,移动或者插入 + private ChangeVertex = async (vertex: IVertex, isMove: boolean) => + { + let pl = this.entity as Polyline; + let ptRes = await app.m_Editor.GetPoint({ + Msg: "为新顶点指定位置", + BasePoint: vertex.point.Position, + AllowDrawRubberBand: true + }) + if (ptRes.Status === PromptStatus.Cancel) + return PromptStatus.Cancel; + + let newPt = ptRes.Value.clone().applyMatrix4(pl.OCSInv); + if (isMove) + { + pl.SetPointAt(vertex.index, Vec3DTo2D(newPt)); + } + else + { + vertex.index++ + pl.AddVertexAt(vertex.index, Vec3DTo2D(newPt)); + } + vertex.point.Position = ptRes.Value; + + return PromptStatus.OK; + } + //拉直曲线 + private StretchStraight(indexList: number[]) + { + let pl = this.entity as Polyline; + + arraySortByNumber(indexList); + + pl.SetBulgeAt(indexList[0], 0); + if (indexList.length === 2) + pl.RemoveVertexIn(indexList[0], indexList[1]); + } + private ExecSAndBCommand(indexList: number[], vertex: IVertex, editorCommand: string) + { + app.m_Database.hm.StartCmd(""); + if (!equaln(indexList[0], vertex.index)) + indexList.push(vertex.index); + //执行并更新顶点信息 + if (editorCommand === "B") + { + //执行打断操作 + this.Break(indexList); + } + else + { + //执行拉直操作 + this.StretchStraight(indexList); + } + vertex.index = indexList[0]; + vertex.point.Position = this.entity.GetPointAtParam(indexList[0]); + app.m_Database.hm.EndCmd(); + } + private TransfromNonCurve() + { + app.m_Database.hm.StartCmd("d"); + let pl = this.entity; + if (pl instanceof Polyline) + { + for (let i = 0; i < pl.EndParam; i++) + { + let bul = pl.GetBuilgeAt(i); + if (bul !== 0) + pl.SetBulgeAt(i, 0); + } + } + else if (pl instanceof Spline) + { + let pts = pl.Points; + let data: PolylineProps[] = []; + for (let p of pts) + { + data.push({ + pt: Vec3DTo2D(p), + bul: 0 + }) + } + pl.Erase(); + this.entity = new Polyline(data); + app.m_Database.ModelSpace.Append(this.entity); + } + app.m_Database.hm.EndCmd(); + } + private TransfromSpline() + { + app.m_Database.hm.StartCmd("s"); + let pl = this.entity; + if (pl instanceof Polyline) + { + pl.Erase(); + let pts = pl.GetStretchPoints(); + let spl = new Spline(pts); + app.m_Database.ModelSpace.Append(spl); + spl.CloseMark = pl.CloseMark; + this.entity = spl; + } + app.m_Database.hm.EndCmd(); + } +} diff --git a/src/Editor/DbClick/DbClick.ts b/src/Editor/DbClick/DbClick.ts new file mode 100644 index 000000000..d9fa26b6c --- /dev/null +++ b/src/Editor/DbClick/DbClick.ts @@ -0,0 +1,59 @@ +import { app } from "../../ApplicationServices/Application"; +import { Singleton } from "../../Common/Singleton"; +import { Board } from "../../DatabaseServices/Board"; +import { Entity } from "../../DatabaseServices/Entity"; +import { PointLight } from "../../DatabaseServices/PointLight"; +import { Polyline } from "../../DatabaseServices/Polyline"; +import { Text } from "../../DatabaseServices/Text/Text"; +import { TextArea } from "../../DatabaseServices/Text/TextArea"; +import { BoardOptionModal } from "../../UI/Components/Board/BoardOptionModal"; +import { LightModal } from "../../UI/Components/Modal/LightModal"; +import { ModalPosition } from "../../UI/Components/Modal/ModalsManage"; +import { PointPick } from "../PointPick"; +import { DBClickPolyline } from "./DBClickPolyline"; +import { commandMachine } from "../CommandMachine"; + +export class DbClickManager +{ + OnDbClick = async () => + { + let obj3d = PointPick(app.m_Editor.m_MouseCtrl.m_CurMousePointVCS, app.m_Viewer)[0]; + //防止双击到Jig对象 + if (!obj3d || !obj3d.userData + || !(obj3d.userData instanceof Entity) + || !obj3d.userData.Id) + return; + //双击实体取消选中状态 + app.m_Editor.m_SelectCtrl.Cancel(); + + if (obj3d.userData instanceof PointLight) + { + app.m_Editor.m_ModalManage.RenderModeless(LightModal, ModalPosition.Right, { selectedObj: obj3d.userData }); + } + else if (obj3d.userData instanceof Text) + { + let textarea = Singleton.GetInstance(TextArea); + textarea.StartEditorText(obj3d); + } + else if (obj3d.userData instanceof Board) + { + app.m_Editor.m_ModalManage.RenderModeless( + BoardOptionModal, + ModalPosition.Right, + { board: obj3d.userData } + ); + } + else if (obj3d.userData instanceof Polyline) + { + commandMachine.CommandStart("_pedit"); + await Singleton.GetInstance(DBClickPolyline).HandlePolyline(obj3d.userData); + commandMachine.CommandEnd("_pedit"); + } + else + { + //TODO: + } + } +} + + diff --git a/src/Editor/GetKeyWordService.tsx b/src/Editor/GetKeyWordService.tsx index 615a6673a..d8f274edc 100644 --- a/src/Editor/GetKeyWordService.tsx +++ b/src/Editor/GetKeyWordService.tsx @@ -49,7 +49,7 @@ export class GetKeyWordsServices implements EditorService this.m_Editor = ed; let container = document.createElement("div"); - document.body.appendChild(container); + document.getElementById("Webgl").appendChild(container); ReactDOM.render( diff --git a/src/Editor/MouseControls.ts b/src/Editor/MouseControls.ts index 256f357eb..f70cc4ce0 100644 --- a/src/Editor/MouseControls.ts +++ b/src/Editor/MouseControls.ts @@ -4,7 +4,7 @@ import { app } from '../ApplicationServices/Application'; import { InputState } from '../Common/InputState'; import { Singleton } from '../Common/Singleton'; import { Viewer } from '../GraphicsSystem/Viewer'; -import { DbClickManager } from './DbClick'; +import { DbClickManager } from './DbClick/DbClick'; import { Editor } from './Editor'; diff --git a/src/UI/Components/ContextMenu/ContextMenu.tsx b/src/UI/Components/ContextMenu/ContextMenu.tsx index fbc6ac6b1..c012d1fcd 100644 --- a/src/UI/Components/ContextMenu/ContextMenu.tsx +++ b/src/UI/Components/ContextMenu/ContextMenu.tsx @@ -45,10 +45,10 @@ export class KeyWordContextMenu extends React.Component<{ keywordStore?: GetKeyW } }) } - public render() { let store = this.props.keywordStore; + return (