import { Intersection, Object3D, Raycaster, Vector3 } from "three"; import { begin, end } from "xaop"; import { app } from "../ApplicationServices/Application"; import { Sleep } from "../Common/Sleep"; import { FixedNotZero, GetEntity } from "../Common/Utils"; import { CommandHistoryRecord } from "../DatabaseServices/CommandHistoryRecord"; import { AlignedDimension } from "../DatabaseServices/Dimension/AlignedDimension"; import { Board } from "../DatabaseServices/Entity/Board"; import { equaln, rotatePoint } from "../Geometry/GeUtils"; import { RenderType } from "../GraphicsSystem/RenderType"; import { CommandState } from "./CommandState"; import { Raycast } from "./PointPick"; export class BoardMoveTool { _DrawDimPoints: [Vector3, Vector3][]; _DrawDims: AlignedDimension[] = []; _Board: Board; ForceUpdate = false; constructor() { let selectCtrl = app.Editor.SelectCtrl; end(selectCtrl, selectCtrl.UpdateSelectEvent, async () => { if (!CommandState.CommandIng) { let set = selectCtrl.SelectSet; if (set.SelectObjectCount > 200) return; for (let i = set._SelectSetList.length; i--;) { let s = set._SelectSetList[i]; let br: Board; for (let o of s._SelectList) { let e = GetEntity(o); if (e instanceof Board) br = e; } if (br) { this._Board = br; this.HitBoard(this._Board); return; } } } }); begin(app.Viewer.PreViewer, app.Viewer.PreViewer.UpdateScreen, () => { this.UpdateDimensionDraw(); }); end(selectCtrl, selectCtrl.CanenEvent, () => { this.Clear(); }); //监听模块树的变更,当变更时,刷新视图 end(app.Database.hm, app.Database.hm.RedoEvent, (cmdName: string, historyRec: CommandHistoryRecord) => { this._Board && this.HitBoard(this._Board); }); end(app.Database.hm, app.Database.hm.UndoEvent, (cmdName: string, historyRec: CommandHistoryRecord) => { this._Board && this.HitBoard(this._Board); }); app.CommandReactor.OnCommandEnd((cmdName, changeObjects, createObjects) => { this._Board && this.HitBoard(this._Board); }); end(app.Database, app.Database.FileRead, () => { this.Clear(); }); } Clear() { this._Board = undefined; this._DrawDimPoints = undefined; this.ForceUpdate = false; this.UpdateDimensionDraw(); app.Viewer.PreViewer.UpdateScreen(); } private async HitBoard(br: Board) { await Sleep(1); let brOCS = br.OCS; let brRot = brOCS.clone().setPosition(0, 0, 0); let brOCSInv = br.OCSInv; let brNormal = br.Normal; let brNormal2 = brNormal.clone().negate(); let brsObject: Object3D[] = []; let start = performance.now(); let i = 0; for (let obj of app.Viewer.Scene.children) { if (obj.visible) { i++; if (i > 30) { let now = performance.now(); let r = now - start; if (now - start > 15) { await Sleep(1); start = now; } else { i -= (16 - r) * 3; } } let ent = GetEntity(obj); if (ent instanceof Board && ent !== br) { brsObject.push(ent.GetDrawObjectFromRenderType(RenderType.Physical)); } } } let dimPoints: [Vector3, Vector3][] = []; //首先计算四周的板件 let sideBoards: Board[] = []; let pl = br.ContourCurve; let d = Math.sign(pl.Area2); for (let i = 0.5; i < pl.EndParam; i++) { let p = pl.GetPointAtParam(i); let derv = pl.GetFistDeriv(i).normalize(); rotatePoint(derv, Math.PI * -0.5 * d); derv.applyMatrix4(brRot); p.setZ(br.Thickness * 0.5); p.applyMatrix4(brOCS); await Sleep(1); let intersection = this.RayPoint(p, derv, brsObject); if (intersection) { sideBoards.push(GetEntity(intersection.object) as Board); if (intersection.distance > 0.1) dimPoints.push([p, intersection.point]); } } //计算最高和最低 let maxZ = -Infinity; let minZ = Infinity; for (let sbr of sideBoards) { let sbrOCS = sbr.OCS; let mtx = sbrOCS.multiplyMatrices(brOCSInv, sbrOCS); for (let p of [new Vector3(), new Vector3(sbr.Width), new Vector3(sbr.Width, sbr.Height), new Vector3(0, sbr.Height)]) { p.applyMatrix4(mtx); maxZ = Math.max(maxZ, p.z - br.Thickness); minZ = Math.min(minZ, p.z); } } //正面 { let dist: number; let centerP: Vector3; for (let y of [0.5, 0.71, 0.21]) { let p = new Vector3(br.Width * 0.5, br.Height * y, br.Thickness).applyMatrix4(brOCS); centerP = centerP ?? p; await Sleep(1); let intersection = this.RayPoint(p, brNormal, brsObject); if (intersection) { if (dist !== undefined && equaln(dist, intersection.distance, 0.1)) continue; dist = dist ?? intersection.distance; if (intersection.distance > 0.01) { dimPoints.push([p, intersection.point]); } } } if (dist === undefined && maxZ > 0) { let tp = centerP.clone().add(brNormal.clone().multiplyScalar(maxZ)); dimPoints.push([centerP, tp]); } } //反面 { let dist: number; let centerP: Vector3; for (let y of [0.5, 0.71, 0.21]) { let p = new Vector3(br.Width * 0.5, br.Height * y, 0).applyMatrix4(brOCS); centerP = centerP ?? p; await Sleep(1); let intersection = this.RayPoint(p, brNormal2, brsObject); if (intersection) { if (dist !== undefined && equaln(dist, intersection.distance, 0.1)) continue; dist = dist ?? intersection.distance; if (intersection.distance > 0.01) dimPoints.push([p, intersection.point]); } } if (dist === undefined && minZ < 0) { let tp = centerP.clone().sub(brNormal2.clone().multiplyScalar(minZ)); dimPoints.push([centerP, tp]); } } this._DrawDimPoints = dimPoints; this.UpdateDimensionDraw(); app.Viewer.PreViewer.UpdateScreen(); } private RayPoint(p: Vector3, n: Vector3, brs: Object3D[]): Intersection { let ray = new Raycaster(p, n); let intersection = Raycast(ray, brs); return intersection; } private UpdateDimensionDraw() { if ((!this._DrawDimPoints || CommandState.CommandIng) && !this.ForceUpdate) { for (let dim of this._DrawDims) dim.Visible = false; return; } for (let i = this._DrawDims.length; i < this._DrawDimPoints.length; i++) { let dim = new AlignedDimension(); dim.Text.Height = 20; dim.LeadOutVisible = false; this._DrawDims.push(dim); app.Viewer.PreViewer.Scene.add(dim.DrawObject); } for (let i = this._DrawDimPoints.length; i < this._DrawDims.length; i++) { let dim = this._DrawDims[i]; dim.Visible = false; } for (let i = 0; i < this._DrawDimPoints.length; i++) { let dim = this._DrawDims[i]; dim.Visible = true; let pts = this._DrawDimPoints[i]; let p1 = app.Viewer.PreViewer.WorldToViewPoint(pts[0].clone()).setZ(0); let p2 = app.Viewer.PreViewer.WorldToViewPoint(pts[1].clone()).setZ(0); dim.FootP1 = p1; dim.ArmP1 = p1; dim.FootP2 = p2; dim.ArmP2 = p2; dim.TextRotation = 0; dim.TextString = FixedNotZero(pts[0].distanceTo(pts[1]), 2); } } }