From f04751a65820761784e4a47db22f062f01f38c7f Mon Sep 17 00:00:00 2001 From: ChenX Date: Fri, 8 Dec 2017 17:20:21 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E6=8D=95=E6=8D=89=E7=82=B9?= =?UTF-8?q?=E8=BE=85=E5=8A=A9=E4=BA=A4=E7=82=B9.=20=E4=BB=8D=E7=84=B6?= =?UTF-8?q?=E6=9C=89bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__snapshots__/intersect.test.ts.snap | 11 + __test__/Geometry/intersect.test.ts | 22 ++ __test__/quokka.test.ts | 9 + src/Add-on/DrawBoard.ts | 6 +- src/Add-on/DrawFloor.ts | 12 +- src/Add-on/DrawLine.ts | 23 +- src/Add-on/Move.ts | 7 +- src/Add-on/Stretch.ts | 8 +- src/DatabaseServices/Entity.ts | 8 +- src/Editor/Editor.ts | 322 +--------------- src/Editor/GetPointServices.ts | 350 ++++++++++++++++++ src/Editor/SelectControls.ts | 6 +- src/Editor/SelectSet.ts | 9 +- src/Geometry/GeUtils.ts | 249 +++++++------ src/GraphicsSystem/PreViewer.ts | 13 + src/GraphicsSystem/Viewer.ts | 9 +- src/webview.ts | 15 +- 17 files changed, 602 insertions(+), 477 deletions(-) create mode 100644 __test__/Geometry/__snapshots__/intersect.test.ts.snap create mode 100644 __test__/Geometry/intersect.test.ts create mode 100644 src/Editor/GetPointServices.ts diff --git a/__test__/Geometry/__snapshots__/intersect.test.ts.snap b/__test__/Geometry/__snapshots__/intersect.test.ts.snap new file mode 100644 index 000000000..d347a20ee --- /dev/null +++ b/__test__/Geometry/__snapshots__/intersect.test.ts.snap @@ -0,0 +1,11 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`相交测试 1`] = ` +Vector3 { + "x": 0.5, + "y": 0, + "z": 0, +} +`; + +exports[`相交测试 2`] = `undefined`; diff --git a/__test__/Geometry/intersect.test.ts b/__test__/Geometry/intersect.test.ts new file mode 100644 index 000000000..a8e984e2e --- /dev/null +++ b/__test__/Geometry/intersect.test.ts @@ -0,0 +1,22 @@ +import * as assert from 'assert'; +import { Intersect } from '../../src/Geometry/GeUtils'; +import * as THREE from 'three'; + +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(); +}); + diff --git a/__test__/quokka.test.ts b/__test__/quokka.test.ts index 59462ff30..f5726eff3 100644 --- a/__test__/quokka.test.ts +++ b/__test__/quokka.test.ts @@ -1,6 +1,15 @@ +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); + }); + + + diff --git a/src/Add-on/DrawBoard.ts b/src/Add-on/DrawBoard.ts index 736cd3599..df3e2ac6d 100644 --- a/src/Add-on/DrawBoard.ts +++ b/src/Add-on/DrawBoard.ts @@ -5,7 +5,7 @@ import { app } from '../ApplicationServices/Application'; import { CreateBoardUtil } from '../ApplicationServices/mesh/createBoard'; import { MaterialNeedUpdateKey } from '../DatabaseServices/MaterialDictionary'; import { Command } from '../Editor/CommandMachine'; -import { GeUtils } from '../Geometry/GeUtils'; +import { Move } from '../Geometry/GeUtils'; export class Command_DrawBoard implements Command { @@ -37,7 +37,7 @@ export class Command_DrawBoard implements Command // let scale = new THREE.Matrix4(); // scale.scale(new THREE.Vector3(0.001, 0.001, 0.001)); - let move = GeUtils.Move(new THREE.Vector3(-1, 2.5, 0)); + let move = Move(new THREE.Vector3(-1, 2.5, 0)); // let mat = move.multiply(scale); @@ -55,7 +55,7 @@ export class Command_DrawBoard implements Command br.receiveShadow = true; app.m_Viewer.m_Scene.add(board); - let move2 = GeUtils.Move(new THREE.Vector3(i * 1, 0, 0)); + let move2 = Move(new THREE.Vector3(i * 1, 0, 0)); br.applyMatrix(move2); } } diff --git a/src/Add-on/DrawFloor.ts b/src/Add-on/DrawFloor.ts index c14237956..1d7993816 100644 --- a/src/Add-on/DrawFloor.ts +++ b/src/Add-on/DrawFloor.ts @@ -1,10 +1,10 @@ +import * as path from 'path'; import * as THREE from 'three'; -import { Scene } from 'three'; import { app } from '../ApplicationServices/Application'; import { Solid3d } from '../DatabaseServices/Entity'; import { Command } from '../Editor/CommandMachine'; -import { GeUtils } from '../Geometry/GeUtils'; +import { Move } from '../Geometry/GeUtils'; import { RenderType } from '../GraphicsSystem/Enum'; export class DrawFloor implements Command @@ -202,7 +202,7 @@ export class DrawFloor implements Command let objRight = obj.clone(); - obj.applyMatrix(GeUtils.Move(new THREE.Vector3(-2.1, 4, 0))); + obj.applyMatrix(Move(new THREE.Vector3(-2.1, 4, 0))); let roMatLeft = new THREE.Matrix4(); roMatLeft.makeRotationZ(Math.PI / 2); @@ -212,8 +212,8 @@ export class DrawFloor implements Command roMatRight.makeRotationZ(Math.PI / 2); objRight.applyMatrix(roMatRight); - objLeft.applyMatrix(GeUtils.Move(new THREE.Vector3(-2, 0, 0))) - objRight.applyMatrix(GeUtils.Move(new THREE.Vector3(2, 0, 0))) + objLeft.applyMatrix(Move(new THREE.Vector3(-2, 0, 0))) + objRight.applyMatrix(Move(new THREE.Vector3(2, 0, 0))) this.scene.add(obj); @@ -232,7 +232,7 @@ export class DrawFloor implements Command let skyObj = skyWall.Draw(RenderType.Wireframe) as THREE.Mesh; skyObj.material = skyMaterail; - skyObj.applyMatrix(GeUtils.Move(new THREE.Vector3(-2.12, 0, 2.8))); + skyObj.applyMatrix(Move(new THREE.Vector3(-2.12, 0, 2.8))); this.scene.add(skyObj); } diff --git a/src/Add-on/DrawLine.ts b/src/Add-on/DrawLine.ts index 95fbfdb53..611215802 100644 --- a/src/Add-on/DrawLine.ts +++ b/src/Add-on/DrawLine.ts @@ -1,12 +1,9 @@ -import { Command } from '../Editor/CommandMachine'; -import { app } from '../ApplicationServices/Application'; import * as THREE from 'three'; + +import { app } from '../ApplicationServices/Application'; import { Circle, Line, Solid3d } from '../DatabaseServices/Entity'; -import * as _ from 'lodash'; -import { UndoData } from '../DatabaseServices/UndoData'; -import { PromptResult, PromptStatus } from '../Editor/PromptResult'; -import * as ReactDOM from 'react-dom'; -import { GeUtils } from "../Geometry/GeUtils"; +import { Command } from '../Editor/CommandMachine'; +import { PromptStatus } from '../Editor/PromptResult'; import { RenderType } from '../GraphicsSystem/Enum'; export class DrawLine implements Command @@ -127,10 +124,10 @@ export class DrawRect implements Command app.m_Database.appendEntity(l3); app.m_Database.appendEntity(l4); - app.m_Editor.noSnapList.add(l1.Draw(RenderType.Wireframe)); - app.m_Editor.noSnapList.add(l2.Draw(RenderType.Wireframe)); - app.m_Editor.noSnapList.add(l3.Draw(RenderType.Wireframe)); - app.m_Editor.noSnapList.add(l4.Draw(RenderType.Wireframe)); + app.m_Editor.AddNoSnapEntity(l1.Draw(RenderType.Wireframe)); + app.m_Editor.AddNoSnapEntity(l2.Draw(RenderType.Wireframe)); + app.m_Editor.AddNoSnapEntity(l3.Draw(RenderType.Wireframe)); + app.m_Editor.AddNoSnapEntity(l4.Draw(RenderType.Wireframe)); let updateRect = (p1, p2) => @@ -185,7 +182,7 @@ export class DrawCircle implements Command } app.m_Database.appendEntity(cir); - app.m_Editor.noSnapList.add(cir.Draw(RenderType.Wireframe)); + app.m_Editor.AddNoSnapEntity(cir.Draw(RenderType.Wireframe)); ptRes = await app.m_Editor.GetPoint( { @@ -213,6 +210,8 @@ export class DrawTest implements Command obj.position.set(Math.random() * 1000, Math.random() * 1000, Math.random() * 1000, ); app.m_Database.appendEntity(box); + + app.m_Viewer.m_Scene.add(obj); } } } diff --git a/src/Add-on/Move.ts b/src/Add-on/Move.ts index bfb8e44e1..81f68e8da 100644 --- a/src/Add-on/Move.ts +++ b/src/Add-on/Move.ts @@ -1,7 +1,8 @@ -import { Command } from '../Editor/CommandMachine'; +import * as THREE from 'three'; + import { app } from '../ApplicationServices/Application'; +import { Command } from '../Editor/CommandMachine'; import { PromptStatus } from '../Editor/PromptResult'; -import * as THREE from 'three'; export class Command_Move implements Command { @@ -21,7 +22,7 @@ export class Command_Move implements Command for (let obj of app.m_Viewer.m_OutlinePass.selectedObjects) { - app.m_Editor.noSnapList.add(obj); + app.m_Editor.AddNoSnapEntity(obj); } let pt1 = ptRes.Value; diff --git a/src/Add-on/Stretch.ts b/src/Add-on/Stretch.ts index 16c1a3223..d2e9da441 100644 --- a/src/Add-on/Stretch.ts +++ b/src/Add-on/Stretch.ts @@ -1,3 +1,4 @@ +import { Callback } from 'awesome-typescript-loader/dist/paths-plugin'; import * as THREE from 'three'; import { app } from '../ApplicationServices/Application'; @@ -6,8 +7,7 @@ import { PromptStatus } from '../Editor/PromptResult'; import { SelectBox } from '../Editor/SelectBox'; import { SelectPick } from '../Editor/SelectPick'; import { SelectSet, SelectType } from '../Editor/SelectSet'; -import { GeUtils } from '../Geometry/GeUtils'; - +import { Move } from '../Geometry/GeUtils'; export class Stretch implements Command { @@ -115,7 +115,7 @@ export class Stretch implements Command } s(d: { str: Map>, move: Array }, vec: THREE.Vector3) { - let moveMat = GeUtils.Move(vec); + let moveMat = Move(vec); for (let obj of d.move) { obj.applyMatrix(moveMat); @@ -152,7 +152,7 @@ export class Stretch implements Command } stretch(ss: SelectSet, vec: THREE.Vector3) { - let moveMat = GeUtils.Move(vec); + let moveMat = Move(vec); for (let set of ss.SelectSetList) { diff --git a/src/DatabaseServices/Entity.ts b/src/DatabaseServices/Entity.ts index 9433676f3..2d32e8515 100644 --- a/src/DatabaseServices/Entity.ts +++ b/src/DatabaseServices/Entity.ts @@ -3,16 +3,12 @@ import * as mst from 'mobx-state-tree'; import * as THREE from 'three'; import { Vector3 } from 'three'; -import { GeUtils } from '../Geometry/GeUtils'; +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'; -var baseColor = 0x333333; -var foundColor = 0x12C0E3; -var intersectColor = 0x00D66B; - export class Entity { /** @@ -302,7 +298,7 @@ export class Solid3d extends Entity 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(GeUtils.Move(this.Size.clone().multiplyScalar(0.5))); + mesh.applyMatrix(Move(this.Size.clone().multiplyScalar(0.5))); this.m_DrawEntity.set(renderType, mesh); return mesh; } diff --git a/src/Editor/Editor.ts b/src/Editor/Editor.ts index c4b30dc73..f3905431b 100644 --- a/src/Editor/Editor.ts +++ b/src/Editor/Editor.ts @@ -1,18 +1,16 @@ //用户交互编辑工具 -import * as THREE from 'three'; import { Vector3 } from 'three'; +import * as THREE from 'three'; import * as xaop from 'xaop'; import { app, ApplicationService } from '../ApplicationServices/Application'; import { GetPointPrompt, InputState } from '../Common/InputState'; -import { MouseKey } from '../Common/KeyEnum'; -import { Entity, Line } from '../DatabaseServices/Entity'; -import { GeUtils } from '../Geometry/GeUtils'; -import { RenderType } from '../GraphicsSystem/Enum'; +import { Entity } from '../DatabaseServices/Entity'; import { CommandStore } from '../UI/Store/CommandStore'; +import { GetPointServices } from './GetPointServices'; import { KeyBoardControls } from './KeyBoardControls'; import { MouseControls } from './MouseControls'; -import { PromptPointResult, PromptStatus } from './PromptResult'; +import { PromptPointResult } from './PromptResult'; import { SelectControls } from './SelectControls'; //TODO: 增加鼠标状态. 鼠标位置. @@ -24,7 +22,8 @@ export class Editor m_App: ApplicationService; m_InputState: InputState = InputState.None; m_CommandStore: CommandStore; - private m_SelectList: Array = []; + + private m_GetpointServices: GetPointServices; constructor(app: ApplicationService) { @@ -33,6 +32,7 @@ export class Editor this.m_KeyCtrl = new KeyBoardControls(); this.m_SelectCtrl = new SelectControls(app.m_Viewer, this) this.m_CommandStore = new CommandStore(this); + this.m_GetpointServices = new GetPointServices(); xaop.end(this.m_MouseCtrl, this.m_MouseCtrl.onMouseMove, () => { @@ -41,233 +41,15 @@ export class Editor } GetPoint(prompt?: GetPointPrompt): Promise { - prompt = prompt ? prompt : {}; - - this.m_App.m_Viewer.m_PreViewer.ToGetpoint(); - this.m_InputState = InputState.GetPoint; - - let retValue = new PromptPointResult(); - - let removeCalls = []; //删除回调列表 - - removeCalls.push(this.Snap()); - - return new Promise((resolve, reject) => - { - //如果有基点,那么绘制直线 - if (prompt.BasePoint && prompt.AllowDrawRubberBand) - { - let preView = this.m_App.m_Viewer.m_PreViewer; - - let startP = prompt.BasePoint.clone(); - this.m_App.m_Viewer.WorldToScreen(startP); - preView.ScreenPointToViewerPoint(startP); - - let line = preView.DrawLine(startP, startP, preView.m_DashMaterial); - let geo = line.geometry as THREE.Geometry; - geo.computeLineDistances(); - - preView.Scene.add(line); - removeCalls.push( - () => - { - preView.Scene.remove(line); - }, - xaop.end(this.m_MouseCtrl, this.m_MouseCtrl.onMouseMove, () => - { - let endP = this.GetNowPoint(prompt.BasePoint); - this.m_App.m_Viewer.WorldToScreen(endP); - preView.ScreenPointToViewerPoint(endP); - - geo.vertices[1] = endP; - geo.computeLineDistances(); - geo.lineDistancesNeedUpdate = true; - geo.verticesNeedUpdate = true; - - preView.render(); - this.UpdateScreen(); - }) - ); - } - //调用回调 - if (prompt.Callback) - { - removeCalls.push( - xaop.end(this.m_MouseCtrl, this.m_MouseCtrl.onMouseMove, () => - { - let p = this.GetNowPoint(prompt.BasePoint); - prompt.Callback(p); - this.UpdateScreen(); - }) - ); - } - //鼠标按下 - removeCalls.push( - xaop.end(this.m_MouseCtrl, this.m_MouseCtrl.onMouseDown, (e: MouseEvent) => - { - if (e.button == MouseKey.Left) - { - retValue.Status = PromptStatus.OK; - retValue.Value = this.GetNowPoint(prompt.BasePoint); - _return(); - } - }) - ); - //键盘按下 - removeCalls.push( - xaop.begin(this.m_KeyCtrl, this.m_KeyCtrl.OnKeyDown, (e: KeyboardEvent) => - { - if (e.keyCode == 27) - { - retValue.Status = PromptStatus.Cancel; - _return(); - } - else if (e.keyCode == 32) - { - retValue.Status = PromptStatus.None; - _return(); - } - }) - ); - - //返回 - let _return = () => - { - this.m_InputState = InputState.None; - this.noSnapList.clear(); - - //清理所有的注入函数. - for (let destroyFunc of removeCalls) - { - destroyFunc(); - } - this.m_App.m_Viewer.m_PreViewer.ToSelect(); - - resolve(retValue); - this.UpdateScreen(); - } - }); - } - - /** - * - * 获得当前光标所在的点, 先判断捕捉,在判断极轴捕捉 - * - * @private - * @param {THREE.Vector3} [basePoint] - * @returns {THREE.Vector3} - * @memberof Editor - */ - private GetNowPoint(basePoint?: THREE.Vector3): THREE.Vector3 - { - if (this.m_App.m_Viewer.m_PreViewer.m_LastSnapPoint) - { - let retP = app.m_Viewer.m_PreViewer.ptWcs; - app.m_Viewer.ScreenToWorld(retP); - return retP; - } - if (basePoint) - { - let newP = this.AxisSnap(basePoint); - if (newP) - { - return newP; - } - } - return this.m_MouseCtrl.m_CurMousePointWCS.clone(); + return this.m_GetpointServices.Doit(prompt); } - - noSnapList = new Set(); - - /** - * 点捕捉服务. 如果有捕捉 将设置光标的捕捉设置 - * - * @returns - * @memberof Editor - */ - Snap() + AddNoSnapEntity(e) { - let testSnap = () => - { - - for (let obj of app.m_Viewer.m_Scene.children) - { - if (this.noSnapList.has(obj)) - { - continue; - } - let geo = obj["geometry"]; - - let g: THREE.Geometry - if (geo instanceof THREE.Geometry) - { - g = geo; - } - else if (geo instanceof THREE.BufferGeometry) - { - g = new THREE.Geometry().fromBufferGeometry(geo); - } - - if (g) - { - for (let i = 0; i < g.vertices.length; i++) - { - let ptC = g.vertices[i].clone(); - ptC.applyMatrix4(obj.matrix); - app.m_Viewer.WorldToScreen(ptC); - - if (ptC.distanceToSquared(this.m_MouseCtrl.m_CurMousePointVCS) < 100) - { - app.m_Viewer.m_PreViewer.m_LastSnapPoint = ptC; - - app.m_Viewer.m_PreViewer.m_LastEntity = obj; - app.m_Viewer.m_PreViewer.m_LastIndex = i; - - app.m_Viewer.m_PreViewer.SerCursorPostion(ptC); - - app.m_Viewer.m_PreViewer.render(); - return; - } - } - } - } - } - testSnap(); - return xaop.end(this.m_MouseCtrl, this.m_MouseCtrl.onMouseMove, testSnap); + this.m_GetpointServices.noSnapList.add(e); } - - /** - * - * 轴捕捉 - * @param {any} basePoint - * @returns {THREE.Vector3} 返回捕捉的点 如果捕捉不到 那么返回空 - * @memberof Editor - */ - AxisSnap(basePoint): THREE.Vector3 + RemoveNoSnapEntity(e) { - let wcs = this.m_MouseCtrl.m_CurMousePointWCS.clone(); - - //相差向量 - let subVec = wcs.clone().sub(basePoint); - let an = Math.atan2(subVec.y, subVec.x); - - if (an < 0) an += Math.PI * 2; - let newan = GeUtils.fixAngle(an, Math.PI * 0.25); - - if (!GeUtils.equaln(newan, an, 0.001)) - { - //dis. - let v0 = new THREE.Vector3(0, 0, 0); - GeUtils.angle(v0, newan, 1); - - let dis = v0.dot(wcs.sub(basePoint)); - - let retP = basePoint.clone(); - GeUtils.angle(retP, newan, dis); - - return retP; - } - return undefined; + this.m_GetpointServices.noSnapList.delete(e); } PointToScreen(pt: THREE.Vector3): THREE.Vector2 @@ -285,66 +67,6 @@ export class Editor } SelectWindow(p1: THREE.Vector3, p2: THREE.Vector3): Array { - // let sel = new SelectBox(); - - // let camera = this.m_App.m_Viewer.m_Camera.m_CurCamera; - // camera.updateMatrixWorld(false); - - // sel.m_ViewNormal = this.m_App.m_Viewer.m_Direction;//理论上这个... - // sel.m_ViewMat = camera.matrix;//缓存视图矩阵 - - // p1.applyMatrix4(camera.matrixWorldInverse); - // p2.applyMatrix4(camera.matrixWorldInverse); - - // sel.setRectSelect(p1, p2); - - - - - //test . - // let p3 = new THREE.Vector3(p1.x, p2.y); - // let p4 = new THREE.Vector3(p2.x, p1.y); - - // p1.applyMatrix4(camera.matrix); - // p2.applyMatrix4(camera.matrix); - // p3.applyMatrix4(camera.matrix); - // p4.applyMatrix4(camera.matrix); - - // let l1 = new Line(p1, p3); - // let l2 = new Line(p3, p2); - // let l3 = new Line(p4, p2); - // let l4 = new Line(p4, p1); - - // this.m_App.m_Database.appendEntity(l1); - // this.m_App.m_Database.appendEntity(l2); - // this.m_App.m_Database.appendEntity(l3); - // this.m_App.m_Database.appendEntity(l4); - - - - - - - // this.RemoveAllSelect() - // let cs = new CoordinateSystem() - // cs.copyForm(app.m_Viewer.m_Camera.m_CurCamera.matrix) - // cs.m_Postion.copy(p1) - // cs.m_Postion.sub(app.m_Viewer.m_Direction.clone().multiplyScalar(1e8)); - - // let sc = app.m_Viewer.m_ViewHeight / app.m_Viewer.m_HtmlElement.scrollHeight; - // let obb = new OBB(cs, new THREE.Vector3(this.m_SelectCss.width * sc, this.m_SelectCss.height * sc, 1e10)) - // db.m_EntityCollection.forEach(o => - // { - // let obb2 = o.getOBB() - // var xx = obb.intersectsOBB(obb2) - // if (xx.intersects) - // { - // o.setIsSelct(true) - // this.m_SelectList.push(o) - // } - // }) - - // this.UpdateScreen() return []; } SelectAll(): Array @@ -354,26 +76,6 @@ export class Editor RemoveSelect(ent: Entity) { } - RemoveAllSelect() - { - this.m_SelectList.forEach(o => - { - o.setIsSelct(false) - }) - this.m_SelectList = [] - } - SetCurSelect(entArr: Array) - { - this.m_SelectList.forEach(o => - { - this.RemoveSelect(o) - }); - this.m_SelectList = [] - entArr.forEach(o => - { - this.m_SelectList.push(o); - }) - } UpdateScreen() { this.m_App.m_Viewer.m_bNeedUpdate = true; diff --git a/src/Editor/GetPointServices.ts b/src/Editor/GetPointServices.ts new file mode 100644 index 000000000..5031e13d5 --- /dev/null +++ b/src/Editor/GetPointServices.ts @@ -0,0 +1,350 @@ +import * as THREE from 'three'; +import * as xaop from 'xaop'; + +import { app } from '../ApplicationServices/Application'; +import { GetPointPrompt, InputState } from '../Common/InputState'; +import { MouseKey } from '../Common/KeyEnum'; +import { Line } from '../DatabaseServices/Entity'; +import { angle, equaln, fixAngle, Intersect } from '../Geometry/GeUtils'; +import { PromptPointResult, PromptStatus } from './PromptResult'; + + +/** + * 为拾取点提供服务,提供一个类以供Editor引用. + * + * @export + * @class GetPointServices + */ +export class GetPointServices +{ + Doit(prompt?: GetPointPrompt): Promise + { + app.m_Editor.m_InputState = InputState.GetPoint; + + prompt = prompt ? prompt : {}; + app.m_Viewer.m_PreViewer.ToGetpoint(); + let retValue = new PromptPointResult(); + + let removeCalls = []; //删除回调列表 + + removeCalls.push(this.Snap()); + removeCalls.push(() => { this.DestroySnapLine() }); + + return new Promise((resolve, reject) => + { + //如果有基点,那么绘制直线 + if (prompt.BasePoint && prompt.AllowDrawRubberBand) + { + this.m_SnapPtList = [prompt.BasePoint]; + if (prompt.AllowDrawRubberBand) + { + let preView = app.m_Viewer.m_PreViewer; + + let startP = prompt.BasePoint.clone(); + app.m_Viewer.WorldToScreen(startP); + preView.ScreenPointToViewerPoint(startP); + + let line = preView.DrawLine(startP, startP, preView.m_DashMaterial); + let geo = line.geometry as THREE.Geometry; + geo.computeLineDistances(); + + preView.Scene.add(line); + removeCalls.push( + () => + { + preView.Scene.remove(line); + }, + xaop.end(app.m_Editor.m_MouseCtrl, app.m_Editor.m_MouseCtrl.onMouseMove, () => + { + let endP = this.GetNowPoint(); + app.m_Viewer.WorldToScreen(endP); + preView.ScreenPointToViewerPoint(endP); + + geo.vertices[1] = endP; + geo.computeLineDistances(); + geo.lineDistancesNeedUpdate = true; + geo.verticesNeedUpdate = true; + + preView.render(); + app.m_Editor.UpdateScreen(); + }) + ); + } + } + //调用回调 + if (prompt.Callback) + { + removeCalls.push( + xaop.end(app.m_Editor.m_MouseCtrl, app.m_Editor.m_MouseCtrl.onMouseMove, () => + { + let p = this.GetNowPoint(); + prompt.Callback(p); + app.m_Editor.UpdateScreen(); + }) + ); + } + //鼠标按下 + removeCalls.push( + xaop.end(app.m_Editor.m_MouseCtrl, app.m_Editor.m_MouseCtrl.onMouseDown, (e: MouseEvent) => + { + if (e.button == MouseKey.Left) + { + retValue.Status = PromptStatus.OK; + retValue.Value = this.GetNowPoint(); + _return(); + } + }) + ); + //键盘按下 + removeCalls.push( + xaop.begin(app.m_Editor.m_KeyCtrl, app.m_Editor.m_KeyCtrl.OnKeyDown, (e: KeyboardEvent) => + { + if (e.keyCode == 27) + { + retValue.Status = PromptStatus.Cancel; + _return(); + } + else if (e.keyCode == 32) + { + retValue.Status = PromptStatus.None; + _return(); + } + }) + ); + + //返回 + let _return = () => + { + app.m_Editor.m_InputState = InputState.None; + this.noSnapList.clear(); + + //清理所有的注入函数. + for (let destroyFunc of removeCalls) + { + destroyFunc(); + } + app.m_Viewer.m_PreViewer.ToSelect(); + + resolve(retValue); + app.m_Editor.UpdateScreen(); + } + }); + } + + + //极轴捕捉的线列表 + m_SnapAxisBlueLine: THREE.Line[] = []; + + private DestroySnapLine() + { + for (let l of this.m_SnapAxisBlueLine) + { + app.m_Viewer.m_PreViewer.Scene.remove(l); + l.geometry.dispose(); + } + this.m_SnapAxisBlueLine = []; + } + /** + * + * 获得当前光标所在的点, 先判断捕捉,在判断极轴捕捉 + * + * @private + * @returns {THREE.Vector3} + * @memberof Editor + */ + private GetNowPoint(): THREE.Vector3 + { + this.DestroySnapLine(); + if (app.m_Viewer.m_PreViewer.m_LastSnapPoint) + { + let retP = app.m_Viewer.m_PreViewer.ptWcs; + app.m_Viewer.ScreenToWorld(retP); + return retP; + } + + let snapPts: { pbase: THREE.Vector3, pSnap: THREE.Vector3 }[] = []; + for (let baseP of this.m_SnapPtList) + { + let newP = this.AxisSnap(baseP); + if (newP) + { + snapPts.push({ pbase: baseP, pSnap: newP }); + } + } + + + + let wcs = app.m_Editor.m_MouseCtrl.m_CurMousePointWCS; + if (snapPts.length > 0) + { + + let insPList: { + ins: THREE.Vector3, + i1: { pbase: THREE.Vector3, pSnap: THREE.Vector3 }, + i2: { pbase: THREE.Vector3, pSnap: THREE.Vector3 } + }[] = []; + + + for (let i = 0; i < snapPts.length; i++) + { + let d1 = snapPts[i]; + for (let j = i + 1; j < snapPts.length; j++) + { + let d2 = snapPts[j]; + let insP = Intersect(d1.pbase, d1.pSnap, d2.pbase, d2.pSnap); + if (insP) + { + insPList.push({ ins: insP, i1: d1, i2: d2 }) + } + } + } + + if (insPList.length > 0) + { + insPList.sort((d1, d2) => + { + let dis1 = d1.ins.distanceTo(wcs); + let dis2 = d2.ins.distanceTo(wcs); + if (dis1 == dis2) + return 0; + else + return dis1 < dis2 ? -1 : 1 + }); + if (insPList[0].ins.distanceToSquared(wcs) < 100) + { + let insD = insPList[0]; + + let l1 = app.m_Viewer.m_PreViewer.DrawLineFromWcs(insD.i1.pbase.clone(), insD.ins.clone(), app.m_Viewer.m_PreViewer.m_BlueDashMaterial) + let l2 = app.m_Viewer.m_PreViewer.DrawLineFromWcs(insD.i2.pbase.clone(), insD.ins.clone(), app.m_Viewer.m_PreViewer.m_BlueDashMaterial) + + app.m_Viewer.m_PreViewer.Scene.add(l1) + app.m_Viewer.m_PreViewer.Scene.add(l2) + + + this.m_SnapAxisBlueLine.push(l1, l2) + + return insPList[0].ins; + } + } + else + { + snapPts.sort((d1, d2) => + { + return d1.pSnap.distanceTo(wcs) < d2.pSnap.distanceTo(wcs) ? -1 : 1 + }) + return snapPts[0].pSnap; + } + } + + return wcs.clone(); + } + + noSnapList = new Set(); + m_SnapPtList: THREE.Vector3[] = []; + + /** + * 点捕捉服务. 如果有捕捉 将设置光标的捕捉设置 + * + * @returns + * @memberof Editor + */ + Snap() + { + this.m_SnapPtList.length = 0; + let testSnap = () => + { + + for (let obj of app.m_Viewer.m_Scene.children) + { + if (this.noSnapList.has(obj)) + { + continue; + } + let geo = obj["geometry"]; + + let g: THREE.Geometry + if (geo instanceof THREE.Geometry) + { + g = geo; + } + else if (geo instanceof THREE.BufferGeometry) + { + g = new THREE.Geometry().fromBufferGeometry(geo); + } + + if (g) + { + for (let i = 0; i < g.vertices.length; i++) + { + let ptC = g.vertices[i].clone(); + ptC.applyMatrix4(obj.matrix); + let ptWcs = ptC.clone(); + app.m_Viewer.WorldToScreen(ptC); + + if (ptC.distanceToSquared(app.m_Editor.m_MouseCtrl.m_CurMousePointVCS) < 100) + { + app.m_Viewer.m_PreViewer.m_LastSnapPoint = ptC; + + app.m_Viewer.m_PreViewer.m_LastEntity = obj; + app.m_Viewer.m_PreViewer.m_LastIndex = i; + + app.m_Viewer.m_PreViewer.SerCursorPostion(ptC); + + app.m_Viewer.m_PreViewer.render(); + + for (let p of this.m_SnapPtList) + { + if (p.distanceToSquared(ptWcs) < 0.01) + { + return; + } + } + this.m_SnapPtList.push(ptWcs); + if (this.m_SnapPtList.length > 7) + { + this.m_SnapPtList.shift(); + } + return; + } + } + } + } + } + testSnap(); + return xaop.end(app.m_Editor.m_MouseCtrl, app.m_Editor.m_MouseCtrl.onMouseMove, testSnap); + } + + /** + * + * 轴捕捉 + * @param {any} basePoint + * @returns {THREE.Vector3} 返回捕捉的点 如果捕捉不到 那么返回空 + * @memberof Editor + */ + AxisSnap(basePoint): THREE.Vector3 + { + let wcs = app.m_Editor.m_MouseCtrl.m_CurMousePointWCS.clone(); + + //相差向量 + let subVec = wcs.clone().sub(basePoint); + let an = Math.atan2(subVec.y, subVec.x); + + if (an < 0) an += Math.PI * 2; + let newan = fixAngle(an, Math.PI * 0.25); + + if (!equaln(newan, an, 0.001)) + { + //dis. + let v0 = new THREE.Vector3(0, 0, 0); + angle(v0, newan, 1); + + let dis = v0.dot(wcs.sub(basePoint)); + + let retP = basePoint.clone(); + angle(retP, newan, dis); + + return retP; + } + return undefined; + } +} \ No newline at end of file diff --git a/src/Editor/SelectControls.ts b/src/Editor/SelectControls.ts index ebf73d6ba..4185a2175 100644 --- a/src/Editor/SelectControls.ts +++ b/src/Editor/SelectControls.ts @@ -6,11 +6,11 @@ import { KeyBoard, MouseKey } from '../Common/KeyEnum'; import { GripScene } from '../GraphicsSystem/GripScene'; import { Viewer } from '../GraphicsSystem/Viewer'; import { SelectMarquee } from '../UI/JsPlugin/SelectMarquee'; +import { commandMachine } from './CommandMachine'; import { Editor } from './Editor'; import { SelectBox } from './SelectBox'; import { SelectPick } from './SelectPick'; import { SelectSet, SelectType } from './SelectSet'; -import { commandMachine } from './CommandMachine'; export class SelectControls { @@ -135,7 +135,7 @@ export class SelectControls let en = app.m_Viewer.m_PreViewer.m_LastEntity as THREE.Mesh; - app.m_Editor.noSnapList.add(en); + app.m_Editor.AddNoSnapEntity(en); let geo = en.geometry as THREE.Geometry; let movePoint = geo.vertices[app.m_Viewer.m_PreViewer.m_LastIndex]; @@ -159,7 +159,7 @@ export class SelectControls } }) - app.m_Editor.noSnapList.delete(en); + app.m_Editor.RemoveNoSnapEntity(en); app.m_Viewer.m_GripScene.Update(en); diff --git a/src/Editor/SelectSet.ts b/src/Editor/SelectSet.ts index 8a5e240cc..7578088fb 100644 --- a/src/Editor/SelectSet.ts +++ b/src/Editor/SelectSet.ts @@ -1,13 +1,8 @@ -import { Vector3, Matrix4 } from 'three'; -import { Entity } from '../DatabaseServices/Entity'; +import { Matrix4, Vector3 } from 'three'; import * as THREE from 'three'; -import { PlaneExt } from '../Geometry/Plane'; -import { GeUtils } from '../Geometry/GeUtils'; -import { Box2, Frustum, Geometry, OrthographicCamera } from 'three'; -import * as verb from "verb-nurbs-web" -import { Viewer } from '../GraphicsSystem/Viewer'; import { ArrayRemove } from '../Common/Utils'; +import { Viewer } from '../GraphicsSystem/Viewer'; // diff --git a/src/Geometry/GeUtils.ts b/src/Geometry/GeUtils.ts index b0deabce3..ca303c095 100644 --- a/src/Geometry/GeUtils.ts +++ b/src/Geometry/GeUtils.ts @@ -1,149 +1,176 @@ import { Vector3, Matrix4 } from 'three'; import * as THREE from 'three'; -export namespace GeUtils -{ - export const cZeroVec = new THREE.Vector3(); - export const cXAxis = new THREE.Vector3(1, 0, 0); - export const cYAxis = new THREE.Vector3(0, 1, 0); - export const cZAxis = new THREE.Vector3(0, 0, 1); +export const cZeroVec = new THREE.Vector3(); +export const cXAxis = new THREE.Vector3(1, 0, 0); +export const cYAxis = new THREE.Vector3(0, 1, 0); +export const cZAxis = new THREE.Vector3(0, 0, 1); - export function equaln(v1: number, v2: number, fuzz = 1e-3) +export function equaln(v1: number, v2: number, fuzz = 1e-3) +{ + return Math.abs(v1 - v2) < fuzz; +} +export function equal(v1: THREE.Vector3, v2: THREE.Vector3) +{ + return v1.manhattanDistanceTo(v2) < 1e-8; +} + +export function fixAngle(an: number, fixAngle: number, fuzz: number = 0.1) +{ + if (an < 0) + an += Math.PI * 2; + an += fuzz; + let rem = an % fixAngle; + if (rem < fuzz * 2) { - return Math.abs(v1 - v2) < fuzz; + an -= rem; } - export function equal(v1: THREE.Vector3, v2: THREE.Vector3) + else { - return v1.manhattanDistanceTo(v2) < 1e-8; + an -= fuzz; } + return an; +} +export function angle(v: THREE.Vector3, an: number, dis: number) +{ + v.x += Math.cos(an) * dis; + v.y += Math.sin(an) * dis; +} - export function fixAngle(an: number, fixAngle: number, fuzz: number = 0.1) +export function getLoocAtUpVec(dir: THREE.Vector3): THREE.Vector3 +{ + if (dir.equals(cZeroVec)) { - if (an < 0) - an += Math.PI * 2; - an += fuzz; - let rem = an % fixAngle; - if (rem < fuzz * 2) - { - an -= rem; - } - else - { - an -= fuzz; - } - return an; + throw ("zero vector") } - export function angle(v: THREE.Vector3, an: number, dis: number) + let norm = dir.clone().normalize(); + if (norm.equals(cZAxis)) { - v.x += Math.cos(an) * dis; - v.y += Math.sin(an) * dis; + return new THREE.Vector3(0, 1, 0); } - - export function getLoocAtUpVec(dir: THREE.Vector3): THREE.Vector3 + else if (norm.equals(cZAxis.clone().multiplyScalar(-1))) { - if (dir.equals(cZeroVec)) - { - throw ("zero vector") - } - let norm = dir.clone().normalize(); - if (norm.equals(cZAxis)) - { - return new THREE.Vector3(0, 1, 0); - } - else if (norm.equals(cZAxis.clone().multiplyScalar(-1))) - { - return new THREE.Vector3(0, -1, 0); - } - else - { - let xv: THREE.Vector3 = new THREE.Vector3(); - xv.crossVectors(cZAxis, norm); + return new THREE.Vector3(0, -1, 0); + } + else + { + let xv: THREE.Vector3 = new THREE.Vector3(); + xv.crossVectors(cZAxis, norm); - let up = new THREE.Vector3(); - up.crossVectors(norm, xv); - return up; - } + let up = new THREE.Vector3(); + up.crossVectors(norm, xv); + return up; } +} + +export function createLookAtMat4(dir: THREE.Vector3): THREE.Matrix4 +{ + let up = getLoocAtUpVec(dir); + let mat = new THREE.Matrix4(); + mat.lookAt(cZeroVec, dir, up); + return mat; +} - export function createLookAtMat4(dir: THREE.Vector3): THREE.Matrix4 +export function isParallelTo(v1: THREE.Vector3, v2: THREE.Vector3) +{ + return v1.clone().cross(v2).lengthSq() < 1e-9; +} + +export function ptToString(v: THREE.Vector3, fractionDigits: number = 3): string +{ + return v.toArray().map(o => { - let up = getLoocAtUpVec(dir); - let mat = new THREE.Matrix4(); - mat.lookAt(cZeroVec, dir, up); - return mat; - } + return o.toFixed(fractionDigits) + }).join(",") +} + +export function midPoint(v1: THREE.Vector3, v2: THREE.Vector3): THREE.Vector3 +{ + return v1.clone().add(v2).multiplyScalar(0.5); +} - export function isParallelTo(v1: THREE.Vector3, v2: THREE.Vector3) + +export function GetBox(obj: THREE.Object3D, updateMatrix?: boolean): THREE.Box3 +{ + if (updateMatrix) obj.updateMatrixWorld(false); + if (obj.hasOwnProperty("geometry")) { - return v1.clone().cross(v2).lengthSq() < 1e-9; + let geo = obj["geometry"]; + if (geo instanceof THREE.Geometry || geo instanceof THREE.BufferGeometry) + { + if (!geo.boundingBox) + geo.computeBoundingBox(); + return geo.boundingBox.clone().applyMatrix4(obj.matrixWorld); + } } - - export function ptToString(v: THREE.Vector3, fractionDigits: number = 3): string + else if (obj.children.length > 0) { - return v.toArray().map(o => + let box = obj.children.reduce((sumBox, itemObj) => { - return o.toFixed(fractionDigits) - }).join(",") + let itemBox = GetBox(itemObj); + if (itemBox) + sumBox.union(itemBox); + return sumBox; + }, new THREE.Box3()) + if (box) box.applyMatrix4(obj.matrixWorld); + return box; } + else + return null; +} - export function midPoint(v1: THREE.Vector3, v2: THREE.Vector3): THREE.Vector3 +export function GetBoxArr(arr: Array): THREE.Box3 +{ + if (arr.length == 0) { - return v1.clone().add(v2).multiplyScalar(0.5); + return null; } + return arr.map(o => + { + return GetBox(o); + }).filter(o => + { + return o; + }).reduce((sumBox: THREE.Box3, objBox: THREE.Box3) => + { + return sumBox.union(objBox) + }, new THREE.Box3()); +} + +export function Move(v: THREE.Vector3): THREE.Matrix4 +{ + let mat = new THREE.Matrix4(); + mat.makeTranslation(v.x, v.y, v.z); + return mat; +} +export function Intersect(p1: THREE.Vector3, p2: THREE.Vector3, p3: THREE.Vector3, p4: THREE.Vector3): THREE.Vector3 +{ + let dx1 = p1.x - p2.x; + let dx2 = p3.x - p4.x; + let dx3 = p4.x - p2.x; + let dy1 = p1.x - p2.y; + let dy2 = p3.y - p4.y; + let dy3 = p4.y - p2.y; - export function GetBox(obj: THREE.Object3D, updateMatrix?: boolean): THREE.Box3 + let det = (dx2 * dy1) - (dy2 * dx1); + + let pt = new THREE.Vector3(0, 0, 0); + if (equaln(det, 0.0, 1e-5)) { - if (updateMatrix) obj.updateMatrixWorld(false); - if (obj.hasOwnProperty("geometry")) + if (equaln(dx2 * dy3, dy2 * dx3, 1e-5)) { - let geo = obj["geometry"]; - if (geo instanceof THREE.Geometry || geo instanceof THREE.BufferGeometry) + if (p3.distanceTo(p2) < 1e-3) { - if (!geo.boundingBox) - geo.computeBoundingBox(); - return geo.boundingBox.clone().applyMatrix4(obj.matrixWorld); + return p2; } } - else if (obj.children.length > 0) - { - let box = obj.children.reduce((sumBox, itemObj) => - { - let itemBox = GetBox(itemObj); - if (itemBox) - sumBox.union(itemBox); - return sumBox; - }, new THREE.Box3()) - if (box) box.applyMatrix4(obj.matrixWorld); - return box; - } - else - return null; + return; } - export function GetBoxArr(arr: Array): THREE.Box3 - { - if (arr.length == 0) - { - return null; - } - return arr.map(o => - { - return GetBox(o); - }).filter(o => - { - return o; - }).reduce((sumBox: THREE.Box3, objBox: THREE.Box3) => - { - return sumBox.union(objBox) - }, new THREE.Box3()); - } + let ratio = ((dx1 * dy3) - (dy1 * dx3)) / det; + pt.x = (ratio * dx2) + p4.x; + pt.y = (ratio * dy2) + p4.y; - export function Move(v: THREE.Vector3): THREE.Matrix4 - { - let mat = new THREE.Matrix4(); - mat.makeTranslation(v.x, v.y, v.z); - return mat; - } + return pt; } - diff --git a/src/GraphicsSystem/PreViewer.ts b/src/GraphicsSystem/PreViewer.ts index a0b97da72..5c974fda3 100644 --- a/src/GraphicsSystem/PreViewer.ts +++ b/src/GraphicsSystem/PreViewer.ts @@ -1,5 +1,6 @@ import * as THREE from 'three'; +import { app } from '../ApplicationServices/Application'; import { CameraControl } from './CameraControl'; export class PreViewer @@ -170,6 +171,18 @@ export class PreViewer geometry.vertices.push(p1, p2); return new THREE.Line(geometry, material); } + DrawLineFromWcs(p1: THREE.Vector3, p2: THREE.Vector3, material?: THREE.LineBasicMaterial | THREE.LineDashedMaterial): THREE.Line + { + material = material ? material : this.m_LineMaterial; + + app.m_Viewer.WorldToScreen(p1); + this.ScreenPointToViewerPoint(p1); + + app.m_Viewer.WorldToScreen(p2); + this.ScreenPointToViewerPoint(p2); + + return this.DrawLine(p1, p2, material); + } SerCursorPostion(pt: THREE.Vector3) { let p = this.m_CursorObject.position; diff --git a/src/GraphicsSystem/Viewer.ts b/src/GraphicsSystem/Viewer.ts index 06d060402..8cfa5ebb4 100644 --- a/src/GraphicsSystem/Viewer.ts +++ b/src/GraphicsSystem/Viewer.ts @@ -1,9 +1,10 @@ import * as THREE from 'three'; import * as xaop from 'xaop'; +import { db } from '../ApplicationServices/Application'; import { Database } from '../DatabaseServices/Database'; import { Entity } from '../DatabaseServices/Entity'; -import { GeUtils } from '../Geometry/GeUtils'; +import { cZeroVec, GetBox, GetBoxArr } from '../Geometry/GeUtils'; import { PlaneExt } from '../Geometry/Plane'; import { CameraControl } from './CameraControl'; import { RenderType } from './Enum'; @@ -193,11 +194,11 @@ export class Viewer UpdateLockTarget() { let renderList = this.m_Render.renderLists.get(this.m_Scene, this.m_Camera.Camera); - let box = GeUtils.GetBoxArr(renderList.opaque.map(o => o.object)); + let box = GetBoxArr(renderList.opaque.map(o => o.object)); if (box) this.m_LookTarget = box.getCenter(); else - this.m_LookTarget = GeUtils.cZeroVec; + this.m_LookTarget = cZeroVec; } Rotate(mouseMove: THREE.Vector3) { @@ -216,7 +217,7 @@ export class Viewer } ZoomAll() { - this.m_Camera.ZoomExtensBox3(GeUtils.GetBox(this.m_Scene, true)); + this.m_Camera.ZoomExtensBox3(GetBox(this.m_Scene, true)); this.m_bNeedUpdate = true; } diff --git a/src/webview.ts b/src/webview.ts index 4c4b49261..2adbb26e5 100644 --- a/src/webview.ts +++ b/src/webview.ts @@ -1,15 +1,14 @@ -import { Line, Solid3d } from './DatabaseServices/Entity'; -import { WebCADView } from './WebCADView/WebCADView'; import './UI/Css/style.less'; + import * as THREE from 'three'; -import { RenderType } from './GraphicsSystem/Enum'; -import { app } from './ApplicationServices/Application'; -import { GetColorIndex } from './Common/ColorPalette'; -import { Viewer } from './GraphicsSystem/Viewer'; -import { GeUtils } from './Geometry/GeUtils'; + +import { guiMaterial, guiMeshBasicMaterial, guiScene } from './Common/Material'; +import { Solid3d } from './DatabaseServices/Entity'; import { CameraControlState } from './Editor/CameraControls'; import { DatGUI } from './Editor/DebugDatUi'; -import { guiMeshBasicMaterial, guiScene, guiMaterial } from './Common/Material'; +import { RenderType } from './GraphicsSystem/Enum'; +import { WebCADView } from './WebCADView/WebCADView'; + function createRootElement() { let root = document.createElement('div');