diff --git a/src/Add-on/DrawBoard/DrawBoardTool.ts b/src/Add-on/DrawBoard/DrawBoardTool.ts index bb74f2db7..80459e3e6 100644 --- a/src/Add-on/DrawBoard/DrawBoardTool.ts +++ b/src/Add-on/DrawBoard/DrawBoardTool.ts @@ -46,8 +46,8 @@ export abstract class DrawBoardTool implements Command private async SelectAndBuildBoard() { //原来禁用捕捉开启状态 - let oldSnapState = app.m_Editor.m_GetpointServices.snapServices.m_Disabled; - app.m_Editor.m_GetpointServices.snapServices.m_Disabled = true; + let oldSnapState = app.m_Editor.m_GetpointServices.snapServices.Disabled; + app.m_Editor.m_GetpointServices.snapServices.Disabled = true; while (true) { @@ -99,7 +99,7 @@ export abstract class DrawBoardTool implements Command app.m_Editor.UpdateScreen(); } //恢复原先状态 - app.m_Editor.m_GetpointServices.snapServices.m_Disabled = oldSnapState; + app.m_Editor.m_GetpointServices.snapServices.Disabled = oldSnapState; } //构建板件 diff --git a/src/Add-on/DrawDim/DrawAlignedDimension.ts b/src/Add-on/DrawDim/DrawAlignedDimension.ts index a71181ea2..5c3387021 100644 --- a/src/Add-on/DrawDim/DrawAlignedDimension.ts +++ b/src/Add-on/DrawDim/DrawAlignedDimension.ts @@ -3,6 +3,7 @@ import { AlignedDimension } from '../../DatabaseServices/Dimension/AlignedDimens import { LinearDimension } from '../../DatabaseServices/Dimension/LinearDimension'; import { Command } from '../../Editor/CommandMachine'; import { PromptStatus } from '../../Editor/PromptResult'; +import { Jig } from '../../Editor/Jig'; export enum DimensionType { @@ -46,8 +47,7 @@ export class DrawAlignedDimension implements Command alDim = new LinearDimension(startPt, endPt, linePt, startPt.distanceTo(endPt) + ''); } - app.m_Editor.AddNoSnapEntity(alDim); - app.m_Database.ModelSpace.Append(alDim); + Jig.Draw(alDim); app.m_Editor.Prompt("指定尺寸线位置:"); ptRes = await app.m_Editor.GetPoint({ @@ -62,6 +62,7 @@ export class DrawAlignedDimension implements Command if (ptRes.Status == PromptStatus.OK) { alDim.LinePoint = ptRes.Value; + app.m_Database.ModelSpace.Append(alDim); } else if (ptRes.Status == PromptStatus.Keyword) { diff --git a/src/Add-on/Entsel.ts b/src/Add-on/Entsel.ts index 51430cfcd..3135122e7 100644 --- a/src/Add-on/Entsel.ts +++ b/src/Add-on/Entsel.ts @@ -25,7 +25,7 @@ export class Entsel implements Command dyn.SetPostion(vcs); if (res.Entity instanceof Polyline) - dyn.updatePrompt(res.Entity.constructor.name + ",area:" + res.Entity.Area2); + dyn.UpdatePrompt(res.Entity.constructor.name + ",area:" + res.Entity.Area2); } else dyn.Visible = false; diff --git a/src/Add-on/Offset.ts b/src/Add-on/Offset.ts index d5de1c060..0e7ef7288 100644 --- a/src/Add-on/Offset.ts +++ b/src/Add-on/Offset.ts @@ -80,8 +80,8 @@ export class Command_Offset implements Command { let oldDir = 0; - let oldSnap = app.m_Editor.m_GetpointServices.snapServices.m_Disabled; - app.m_Editor.m_GetpointServices.snapServices.m_Disabled = true; + let oldSnap = app.m_Editor.m_GetpointServices.snapServices.Disabled; + app.m_Editor.m_GetpointServices.snapServices.Disabled = true; let ptRes = await app.m_Editor.GetPoint({ Msg: "指定要偏移的那一侧的点", Callback: (p: Vector3) => @@ -96,7 +96,7 @@ export class Command_Offset implements Command } } }); - app.m_Editor.m_GetpointServices.snapServices.m_Disabled = oldSnap; + app.m_Editor.m_GetpointServices.snapServices.Disabled = oldSnap; let status = { Status: ptRes.Status, offsetDist: 0 }; if (ptRes.Status === PromptStatus.OK) { diff --git a/src/Add-on/closetest.ts b/src/Add-on/closetest.ts index 7c36cae95..dfd18248a 100644 --- a/src/Add-on/closetest.ts +++ b/src/Add-on/closetest.ts @@ -11,6 +11,7 @@ import { Command } from '../Editor/CommandMachine'; import { PromptStatus } from '../Editor/PromptResult'; import { PromptBlock } from '../UI/DynamicPrompt/PromptBlock'; import { DynamicInputManage } from '../UI/DynamicPrompt/DynamicInputManage'; +import { Jig } from '../Editor/Jig'; export class Command_ClosePt implements Command @@ -26,20 +27,16 @@ export class Command_ClosePt implements Command { let cu = cuRes.Entity as Curve; let line = new Line(); - let closeCir = new Circle(new Vector3(), 0.5); + let closeCir = new Circle(new Vector3(), 5); let derLine = new Line(); - app.m_Database.ModelSpace.Append(closeCir); - app.m_Database.ModelSpace.Append(line); - app.m_Database.ModelSpace.Append(derLine); - app.m_Editor.AddNoSnapEntity(closeCir); - app.m_Editor.AddNoSnapEntity(line); - app.m_Editor.AddNoSnapEntity(derLine); + Jig.Draw(line); + Jig.Draw(closeCir); + Jig.Draw(derLine); let extend = false; while (true) { - app.m_Editor.AddNoSnapEntity(line); let p = await app.m_Editor.GetPoint({ KeyWordList: [{ key: "C", msg: (extend ? "不" : "") + "延伸" }], Callback: p => @@ -63,7 +60,7 @@ export class Command_ClosePt implements Command vcs.add(new Vector3(0, -20, 0)); dyn.SetPostion(vcs); - dyn.updatePrompt("点在线内外?:" + IsPointInPolyLine(cu, p)); + dyn.UpdatePrompt("点在线内外?:" + IsPointInPolyLine(cu, p)); closeCir.Center = p; closeCir.ColorIndex = GetPointAtCurveDir(cu, p) ? 1 : 2; } diff --git a/src/ApplicationServices/Application.ts b/src/ApplicationServices/Application.ts index a0290ed83..dc46563fb 100644 --- a/src/ApplicationServices/Application.ts +++ b/src/ApplicationServices/Application.ts @@ -3,17 +3,18 @@ import * as xaop from 'xaop'; import { KeyBoard } from '../Common/KeyEnum'; import { CADFile } from '../DatabaseServices/CADFile'; import { Database } from '../DatabaseServices/Database'; +import { FontLoader } from '../DatabaseServices/Text/FontLoader'; import { CameraControls } from '../Editor/CameraControls'; import { commandMachine } from '../Editor/CommandMachine'; import { DatGUI } from '../Editor/DebugDatUi'; import { Editor } from '../Editor/Editor'; +import { Gesture } from '../Editor/Gesture'; +import { RegisterGesture } from '../Editor/RegisterGesture'; import { SelectSetBase } from '../Editor/SelectBase'; import { Viewer } from '../GraphicsSystem/Viewer'; import { appUi } from '../UI/Layout/ApplicationLayout'; import { layoutOnsizeEvent } from '../UI/Layout/LayoutOnSizeEventManage'; -import { Gesture } from '../Editor/Gesture'; -import { RegisterGesture } from '../Editor/RegisterGesture'; -import { FontLoader } from '../DatabaseServices/Text/FontLoader'; +import { DownPanelStore } from '../UI/Store/DownPanelStore'; export var app: ApplicationService @@ -120,6 +121,11 @@ export class ApplicationService } app.m_Editor.UpdateScreen(); } + else if (e.keyCode === KeyBoard.F8) + { + let s = DownPanelStore.Store(); + s.useOrtho = !s.useOrtho; + } }); //加载字体. diff --git a/src/Editor/CommandMachine.ts b/src/Editor/CommandMachine.ts index 8e93744c4..2e7ce421a 100644 --- a/src/Editor/CommandMachine.ts +++ b/src/Editor/CommandMachine.ts @@ -75,7 +75,6 @@ export class CommandMachine app.m_Database.hm.Undo(); this.m_CommandIng = false; app.m_Viewer.m_GripScene.UpdateAll(); - app.m_Editor.ClearSnapEntity(); Jig.End(); app.m_Editor.UpdateScreen(); } diff --git a/src/Editor/Editor.ts b/src/Editor/Editor.ts index 1c9238625..278c0d8dc 100644 --- a/src/Editor/Editor.ts +++ b/src/Editor/Editor.ts @@ -131,20 +131,6 @@ export class Editor { return this.m_SsgetServices.Start(prompt); } - - AddNoSnapEntity(e: Entity) - { - this.m_GetpointServices.snapServices.notSnapEntity.add(e); - } - RemoveNoSnapEntity(e) - { - this.m_GetpointServices.snapServices.notSnapEntity.delete(e); - } - ClearSnapEntity() - { - this.m_GetpointServices.snapServices.notSnapEntity.clear(); - } - PointToScreen(pt: THREE.Vector3): THREE.Vector2 { return null; diff --git a/src/Editor/GetDistanceServices.ts b/src/Editor/GetDistanceServices.ts index 3b37e684d..13e119649 100644 --- a/src/Editor/GetDistanceServices.ts +++ b/src/Editor/GetDistanceServices.ts @@ -97,7 +97,7 @@ export class GetDistanceServices if (prompt.Default !== undefined) prompt.Msg += `<${prompt.Default}>`; - dynInput.updatePrompt(prompt.Msg); + dynInput.UpdatePrompt(prompt.Msg); this.removeCalls.push(() => { dynInput.Destroy(); diff --git a/src/Editor/GetEntityServices.ts b/src/Editor/GetEntityServices.ts index 4910d75ec..51cc4cd8e 100644 --- a/src/Editor/GetEntityServices.ts +++ b/src/Editor/GetEntityServices.ts @@ -144,7 +144,7 @@ export class GetEntityServices implements EditorService private InitDynPrompt(prompt: GetEntityPrompt, mouseCtrl: MouseControls) { let dyn = new PromptBlock(DynamicInputManage.GetManage()); - dyn.updatePrompt(prompt.Msg || "请选择对象:"); + dyn.UpdatePrompt(prompt.Msg || "请选择对象:"); this.removeCalls.push(() => { dyn.Destroy(); }); this.removeCalls.push(end(mouseCtrl, mouseCtrl.onMouseMove, () => { diff --git a/src/Editor/GetPointServices.ts b/src/Editor/GetPointServices.ts index 9018bed15..7f58fa504 100644 --- a/src/Editor/GetPointServices.ts +++ b/src/Editor/GetPointServices.ts @@ -266,13 +266,37 @@ export class GetPointServices implements EditorService } else dynPrompt = new GetPointPromptBlock(DynamicInputManage.GetManage()); - dynPrompt.updatePrompt(prompt.Msg); + dynPrompt.UpdatePrompt(prompt.Msg); this.removeCalls.push(() => { dynPrompt.Destroy(); }); this.removeCalls.push(xaop.end(this, this.UpdateCurPointEvent, () => { + //当存在轴线捕捉的时,并且不存在基点时,切换成轴线输入模式. + if (!prompt.BasePoint) + { + if (this.snapServices.m_AxisPts.length === 2) + { + if (dynPrompt instanceof GetPointPromptBlock) + { + dynPrompt.Destroy(); + dynPrompt = new GetPoint2PromptBlock(DynamicInputManage.GetManage()); + dynPrompt.BasePoint = this.snapServices.m_AxisPts[0]; + dynPrompt.UpdatePrompt("轴线:"); + } + } + else + { + if (dynPrompt instanceof GetPoint2PromptBlock) + { + dynPrompt.Destroy(); + dynPrompt = new GetPointPromptBlock(DynamicInputManage.GetManage()); + dynPrompt.UpdatePrompt(prompt.Msg); + } + } + } + dynPrompt.SetPostion(app.m_Editor.m_MouseCtrl.m_CurMousePointVCS); dynPrompt.Value = this.curPoint; })); diff --git a/src/Editor/SnapServices.ts b/src/Editor/SnapServices.ts index 81eddfaed..5acca9658 100644 --- a/src/Editor/SnapServices.ts +++ b/src/Editor/SnapServices.ts @@ -1,131 +1,255 @@ -import * as THREE from 'three'; -import { Matrix4, Vector3 } from 'three'; +import { BufferGeometry, Line, Matrix4, Object3D, Vector3, PerspectiveCamera } from 'three'; import { app } from '../ApplicationServices/Application'; import { ColorMaterial } from '../Common/ColorPalette'; -import { DisposeThreeObj } from '../Common/Dispose'; import { GetPointPrompt } from '../Common/InputState'; import { Entity } from '../DatabaseServices/Entity'; -import { equaln, fixAngle, polar, SnapPoint } from '../Geometry/GeUtils'; +import { Line as DbLine } from "../DatabaseServices/Line"; +import { BufferGeometryUtils } from '../Geometry/BufferGeometryUtils'; +import { cXAxis, cYAxis, cZAxis, isParallelTo, SnapPoint, midPoint } from '../Geometry/GeUtils'; import { IntersectLAndLFor3D } from '../GraphicsSystem/IntersectWith'; import { DrawMode } from '../GraphicsSystem/PreViewer'; +import { PromptBlock } from '../UI/DynamicPrompt/PromptBlock'; +import { DynamicInputManage } from '../UI/DynamicPrompt/DynamicInputManage'; - +/** + * 轴线捕捉模式 + */ +export enum AxisSnapMode +{ + Polar = 1,//极轴 + Ortho = 2,//正交 +} //捕捉轴 interface SnapAxis { - BasePoint: THREE.Vector3;//基点 - SnapPoint: THREE.Vector3;//捕捉到的点 + BasePoint: Vector3;//基点 + SnapPoint: Vector3;//捕捉到的点 } //轴线相交数据 interface SnapIntersect { - IntersectPoint: THREE.Vector3; + IntersectPoint: Vector3; Axis1: SnapAxis; Axis2: SnapAxis; } +//正交捕捉轴 +const OrthoAxis = [cXAxis, cYAxis, cZAxis]; +const PolarAxis = [cXAxis, new Vector3(1, 1).normalize(), cYAxis, new Vector3(-1, 1).normalize(), cZAxis]; //提供点捕捉的服务. export class SnapServices { - m_Disabled: boolean = false;//禁用捕捉 - private preLines: THREE.Line[] = []; //前视图绘制的线表 - notSnapEntity = new Set();//不参与捕捉的实体列表,这个属性由开发人员维护. + Disabled: boolean = false;//禁用捕捉 SnapSize = 15;//捕捉框大小 - private snapPoints: THREE.Vector3[] = [];//捕捉的点列表 + AxisSnapMode = AxisSnapMode.Polar;//极轴捕捉模式 + private m_SupportSnapPoints: Vector3[] = [];//辅助捕捉点WCS + private m_UCSInv: Matrix4; + private m_UCS: Matrix4; + m_AxisPts: Vector3[] = []; + SnapPoint: Vector3; + + private m_DynPrompt: PromptBlock; //开始捕捉 Start(prompt: GetPointPrompt) { - if (prompt.BasePoint) this.snapPoints.push(prompt.BasePoint); + this.m_UCSInv = app.m_Editor.UCSMatrixInv; + this.m_UCS = app.m_Editor.UCSMatrix; + + this.InitDynPrompt(); + this.InitCrossCursor(); + this.InitAxisCursor(); + this.InitSquareCursor(); + this.InitBiasCrossCursor(); + this.InitBiasOutline(); + + if (prompt.BasePoint) + { + this.m_SupportSnapPoints.push(prompt.BasePoint.clone()); + this.UpdateCrossCursor(); + } } + //结束捕捉服务 Stop() { - this.DestroySnapLine(); - this.snapPoints.length = 0; + this.m_SupportSnapPoints.length = 0; + this.m_AxisPts.length = 0; + this.SnapPoint = undefined; + + this.m_DynPrompt.Visible = false; + + this.UpdateCursort(); + } + + private UpdateCursort() + { + this.UpdateAxisCursor(); + this.UpdateSquareCursor(); + this.UpdateCrossCursor(); + this.UpdateBiasCrossCursor(); + this.UpdateBiasOutline(); + this.UpdateDynPrompt(); + + app.m_Viewer.m_PreViewer.UpdateScreen(); } - GetSnapPoint() + /** + * 返回合适的捕捉点,如果有的话. + * @returns 捕捉点或空 + */ + GetSnapPoint(): Vector3 | undefined { - this.DestroySnapLine(); - this.DrawSnapCross(); + this.m_AxisPts.length = 0; + this.SnapPoint = this.GetEntitySnapPoint() || this.GetAxisSnapPoint(); + + this.UpdateCursort(); - return this.GetEntitySnapPoint() || this.GetAxisSnapPoint(); + return this.SnapPoint; } - //-------------------计算函数//------------------- + //延迟添加辅助的捕捉点 + private m_DelaySupportSnapId; - //根据角度进行轴线捕捉,如果存在捕捉,那么返回捕捉点,(极轴捕捉,正交捕捉) - private AxisSnap(basePoint: THREE.Vector3, fixAn: number): THREE.Vector3 + /** + * 获得实体捕捉点,夹点,中点,垂点等 + * @returns + */ + private GetEntitySnapPoint() { - let ucsInv = app.m_Editor.UCSMatrixInv; + if (this.Disabled) return; + if (this.m_DelaySupportSnapId) + { + clearTimeout(this.m_DelaySupportSnapId); + this.m_DelaySupportSnapId = undefined; + } + + let vcsP = app.m_Editor.m_MouseCtrl.m_CurMousePointVCS; + for (let obj of app.m_Viewer.Scene.children) + { + if (obj.userData && obj.userData instanceof Entity) + { + let ent = obj.userData; + if (ent.IsErase || ent.Id === undefined) + continue; + for (let p of ent.GetSnapPoints()) + { + let pv = p.clone(); + app.m_Viewer.WorldToScreen(pv); + if (SnapPoint(vcsP, pv, this.SnapSize)) + { + if (!this.m_SupportSnapPoints.some(sp => sp.distanceToSquared(p) < 1e-5)) + { + this.m_DelaySupportSnapId = setTimeout(() => + { + this.m_SupportSnapPoints.push(p.clone()); + if (this.m_SupportSnapPoints.length > 7) + this.m_SupportSnapPoints.shift(); + + this.UpdateCrossCursor(); + }, 37); + } + return p.clone(); + } + } + } + } + } - let bpUCS = basePoint.clone().applyMatrix4(ucsInv); - let nowUCS = app.m_Editor.m_MouseCtrl.m_CurMousePointWCS.clone().applyMatrix4(ucsInv); + /** + * 根据角度进行轴线捕捉,如果存在捕捉,那么返回捕捉点,(极轴捕捉,正交捕捉) + * @param supportSnapPtUCS 辅助的捕捉点. + * @param nowPtUCS 需要捕捉点 + * @param snapAn + * @param [isFirst] + * @returns snapUCS + */ + private AxisSnap(supportSnapPtUCS: Vector3, nowPtUCS: Vector3, isFirst = false): Vector3 + { + let allowNegateSnap = true;//允许捕捉轴的反方向. + let allowMouseDistSq = 100;//允许鼠标距离Sq + let axisVecs = PolarAxis; + if (this.AxisSnapMode === AxisSnapMode.Ortho) + { + axisVecs = OrthoAxis; + if (isFirst) + allowMouseDistSq = Infinity; + } - //相差向量 - let subVec = nowUCS.sub(bpUCS); - let an = Math.atan2(subVec.y, subVec.x); - let newan = fixAngle(an, fixAn); + let nowVCS = app.m_Viewer.WorldToScreen(nowPtUCS.clone().applyMatrix4(this.m_UCS)); - if (!isNaN(newan)) + let pts: Vector3[] = [supportSnapPtUCS.clone()]; + pts.push(...axisVecs.map(v => supportSnapPtUCS.clone().add(v))); + for (let p of pts) { - //dis. - let v0 = new THREE.Vector3(0, 0, 0); - polar(v0, newan, 1); + p.applyMatrix4(this.m_UCS); + app.m_Viewer.WorldToScreen(p); + } - let dis = v0.clone().dot(subVec); + let minIndex = 0, minP: Vector3, minDist = Infinity; - let ucsRo = new Matrix4().extractRotation(app.m_Editor.UCSMatrix); - v0.multiplyScalar(dis); - v0.applyMatrix4(ucsRo); + let l = new DbLine(); + l.StartPoint = pts[0]; + for (let i = 1; i <= axisVecs.length; i++) + { + l.EndPoint = pts[i]; + let { closestPt, param } = l.GetClosestAtPoint(nowVCS, true); + let dist = closestPt.distanceToSquared(nowVCS); - return basePoint.clone().add(v0); + if (dist < minDist && (allowNegateSnap || param > 0)) + { + minIndex = i; + minDist = dist; + minP = closestPt; + } } - //#region Z轴捕捉 - let zv = new Vector3(0, 0, 1); - zv.applyMatrix4( - new Matrix4().getInverse( - new Matrix4().extractRotation(app.m_Viewer.Camera.matrix)) - ); - if (equaln(zv.x, 0, 1e-8) && !(equaln(zv.y, 0, 1e-8) || equaln(zv.y, 1, 1e-8))) + //超过最大间隙 + if (minDist > allowMouseDistSq) + return undefined; + + let snapAxis = axisVecs[minIndex - 1]; + //Z轴 + if (isParallelTo(snapAxis, cZAxis)) { - let bpVCS = app.m_Viewer.WorldToScreen(basePoint.clone()); - let nowVCS = app.m_Editor.m_MouseCtrl.m_CurMousePointVCS.clone(); + let dir = app.m_Viewer.m_CameraCtrl.Direction; + let supWcs = supportSnapPtUCS.clone().applyMatrix4(this.m_UCS); + if (app.m_Viewer.Camera instanceof PerspectiveCamera) + dir = app.m_Viewer.Camera.position.clone().sub(supWcs); - let v = nowVCS.clone().sub(bpVCS); - an = Math.atan2(v.y, v.x); - if (Math.abs(v.x) < 8) - { - let dir = app.m_Viewer.m_CameraCtrl.Direction; + let zVecWcs = snapAxis.clone().applyMatrix4(new Matrix4().extractRotation(this.m_UCS)); - let planVec: Vector3; - if (Math.abs(dir.x) > Math.abs(dir.y)) - planVec = new Vector3(0, 1, 0); - else - planVec = new Vector3(1, 0, 0); + dir.cross(zVecWcs).cross(zVecWcs); - let np = app.m_Viewer.ScreenToWorld(nowVCS, planVec, basePoint); - return basePoint.clone().setZ(np.z); - } + let zp = app.m_Viewer.ScreenToWorld(minP, dir, supWcs).applyMatrix4(this.m_UCSInv); + return supportSnapPtUCS.clone().setZ(zp.z); + } + else + { + //相差向量 + let subVec = nowPtUCS.clone().sub(supportSnapPtUCS); + let dis = snapAxis.dot(subVec); + return supportSnapPtUCS.clone().add(snapAxis.clone().multiplyScalar(dis)); } - //#endregion - - return undefined; } //返回合适的轴线交点,如果不存在交点,那么返回轴线上的点 private GetAxisSnapPoint() { //轴线列表 - let snapAxisList: SnapAxis[] = this.snapPoints.map((p) => + let snapAxisList: SnapAxis[] = []; + + let curPUCS = app.m_Editor.m_MouseCtrl.m_CurMousePointWCS.clone().applyMatrix4(this.m_UCSInv); + for (let i = 0, l = this.m_SupportSnapPoints.length; i < l; i++) { - let snapPoint = this.AxisSnap(p, Math.PI * 0.5); - return { BasePoint: p, SnapPoint: snapPoint }; - }).filter(a => a.SnapPoint); + let supWcs = this.m_SupportSnapPoints[i]; + let supUCS = supWcs.clone().applyMatrix4(this.m_UCSInv); + let snapUCS = this.AxisSnap(supUCS, curPUCS, i === 0); + if (snapUCS) + snapAxisList.push({ BasePoint: supWcs, SnapPoint: snapUCS.applyMatrix4(this.m_UCS) }); + } if (snapAxisList.length === 0) return; @@ -160,29 +284,30 @@ export class SnapServices }); let insData = axisIntersectList[0]; + if (this.AxisSnapMode === AxisSnapMode.Ortho) + { + let p = this.AxisSnap( + this.m_SupportSnapPoints[0].clone().applyMatrix4(this.m_UCSInv), + insData.IntersectPoint.clone().applyMatrix4(this.m_UCSInv), true) + .applyMatrix4(this.m_UCS); + this.m_AxisPts = [insData.Axis1.BasePoint, p, insData.Axis2.BasePoint]; + return p; + } + if (SnapPoint(app.m_Viewer.WorldToScreen(insData.IntersectPoint.clone()), mouseVcs, this.SnapSize)) { - this.preLines.push( - //交叉轴线 - app.m_Viewer.m_PreViewer.DrawLine( - [insData.Axis1.BasePoint, insData.IntersectPoint, insData.Axis2.BasePoint], - ColorMaterial.SnapAxisMaterial - ), - //X光标 - app.m_Viewer.m_PreViewer.Draw( - DrawMode.BaisCross, - this.SnapSize, - insData.IntersectPoint.clone(), - ColorMaterial.GetLineMaterial(3), - true - ) - ); - app.m_Viewer.m_PreViewer.UpdateScreen(); + this.m_AxisPts = [insData.Axis1.BasePoint, insData.IntersectPoint, insData.Axis2.BasePoint]; return insData.IntersectPoint.clone(); } } else//如果没有交叉点,那么使用轴线上的点 { + if (this.AxisSnapMode === AxisSnapMode.Ortho) + { + this.m_AxisPts = [snapAxisList[0].BasePoint, snapAxisList[0].SnapPoint]; + return snapAxisList[0].SnapPoint; + } + snapAxisList.sort((d1, d2) => { return app.m_Viewer.WorldToScreen(d1.SnapPoint.clone()).distanceToSquared(mouseVcs) @@ -190,81 +315,188 @@ export class SnapServices }); let snapAxis = snapAxisList[0]; + this.m_AxisPts = [snapAxis.BasePoint, snapAxis.SnapPoint]; + return snapAxis.SnapPoint; + } + } - this.preLines.push( - app.m_Viewer.m_PreViewer.DrawLine( - [snapAxis.BasePoint, snapAxis.SnapPoint], - ColorMaterial.SnapAxisMaterial + //#region 绘制 + + /** + * 十字光标组 + */ + private m_CrossCursor: Object3D[] = []; + /** + * 初始化捕捉光标(十字) + */ + private InitCrossCursor() + { + if (this.m_CrossCursor.length === 0) + { + let preView = app.m_Viewer.m_PreViewer; + for (let i = 0; i < 7; i++) + { + this.m_CrossCursor.push( + preView.Draw( + DrawMode.Cross, + this.SnapSize, + new Vector3(), + ColorMaterial.GetLineMaterial(3)) ) - ); - app.m_Viewer.m_PreViewer.UpdateScreen(); - return snapAxis.SnapPoint; + } } } - //计算图形的捕捉点 如果有 则返回. - private GetEntitySnapPoint() + /** + * 更新所有的十字光标 + */ + private UpdateCrossCursor() { - if (this.m_Disabled) return; - let vcsP = app.m_Editor.m_MouseCtrl.m_CurMousePointVCS; - for (let obj of app.m_Viewer.Scene.children) + let preView = app.m_Viewer.m_PreViewer; + for (let i = 0; i < 7; i++) { - if (obj.userData && obj.userData instanceof Entity) + let l = this.m_CrossCursor[i]; + if (this.m_SupportSnapPoints[i]) { - if (this.notSnapEntity.has(obj.userData)) continue; - if (obj.userData.IsErase) continue; - if (!obj.userData.Id) continue; - for (let p of obj.userData.GetSnapPoints()) - { - let pv = p.clone(); - app.m_Viewer.WorldToScreen(pv); - if (SnapPoint(vcsP, pv, this.SnapSize)) - { - if (!this.snapPoints.some(sp => { return sp.distanceToSquared(p) < 1e-5 })) - { - this.snapPoints.push(p); - if (this.snapPoints.length > 7) - this.snapPoints.shift(); - } - this.preLines.push( - app.m_Viewer.m_PreViewer.Draw( - DrawMode.Square, - this.SnapSize, - p.clone(), - ColorMaterial.GetLineMaterial(3) - ) - ); - return p.clone(); - } - } + l.position.copy(preView.WorldToViewPoint(this.m_SupportSnapPoints[i].clone())); + l.visible = true; } + else + l.visible = false; } + preView.UpdateScreen(); } - //-------------------绘制函数------------------- + private m_AxisCursor: Line; + /** + * 初始化轴线光标 + */ + private InitAxisCursor() + { + if (!this.m_AxisCursor) + this.m_AxisCursor = app.m_Viewer.m_PreViewer.DrawLine( + [new Vector3(), new Vector3(), new Vector3()], + ColorMaterial.SnapAxisMaterial, + ); + } + private UpdateAxisCursor() + { + if (this.m_AxisPts.length > 0) + { + this.m_AxisCursor.visible = true; + let geo = this.m_AxisCursor.geometry as BufferGeometry; + BufferGeometryUtils.UpdatePts(geo, this.m_AxisPts.map(p => + { + return app.m_Viewer.m_PreViewer.WorldToViewPoint(p.clone()); + })); + geo.drawRange.count = this.m_AxisPts.length; + this.m_AxisCursor.computeLineDistances(); + } + else + this.m_AxisCursor.visible = false; + } - //绘制所有的十字光标 - private DrawSnapCross() + //方向光标,用于捕捉实体夹点 + private m_SquareCursor: Line; + private InitSquareCursor() { - let preView = app.m_Viewer.m_PreViewer; - for (let snapP of this.snapPoints) - this.preLines.push( - preView.Draw( - DrawMode.Cross, - this.SnapSize, - snapP.clone(), - ColorMaterial.GetLineMaterial(3)) + if (!this.m_SquareCursor) + this.m_SquareCursor = app.m_Viewer.m_PreViewer.Draw( + DrawMode.Square, this.SnapSize, new Vector3(), + ColorMaterial.GetLineMaterial(3) ); } - //销毁绘制的函数 - private DestroySnapLine() + private UpdateSquareCursor() { - this.preLines.forEach(l => + this.UpdateObjectPosition( + this.m_SquareCursor, + this.SnapPoint && this.m_AxisPts.length === 0 + ); + } + + + private m_BiasCrossCursor: Line; + //×光标,用于捕捉轴线 + private InitBiasCrossCursor() + { + if (!this.m_BiasCrossCursor) { - l.parent.remove(l); - DisposeThreeObj(l); - }) - this.preLines.length = 0; + this.m_BiasCrossCursor = app.m_Viewer.m_PreViewer.Draw( + DrawMode.BaisCross, + 8, + new Vector3(), + ColorMaterial.GetLineMaterial(3) + ); + } + } + private UpdateBiasCrossCursor() + { + this.UpdateObjectPosition( + this.m_BiasCrossCursor, + this.m_AxisPts.length > 0 + ); } + + private m_BiasOutline: Line; + //初始化X光标外包围框(虚线),用户显示光标交叉 + private InitBiasOutline() + { + if (!this.m_BiasOutline) + this.m_BiasOutline = app.m_Viewer.m_PreViewer.Draw( + DrawMode.Square, + this.SnapSize, + new Vector3(), + ColorMaterial.SnapAxisMaterial, + ) + } + + private UpdateBiasOutline() + { + this.UpdateObjectPosition( + this.m_BiasOutline, + this.m_AxisPts.length > 2 + ); + } + + private UpdateObjectPosition(obj: Object3D, update: boolean) + { + if (update) + { + obj.visible = true; + obj.position.copy( + app.m_Viewer.m_PreViewer.WorldToViewPoint(this.SnapPoint.clone()) + ); + } + else + obj.visible = false; + } + + InitDynPrompt() + { + if (!this.m_DynPrompt) + { + this.m_DynPrompt = new PromptBlock(DynamicInputManage.GetManage()); + this.m_DynPrompt.Visible = false; + } + } + UpdateDynPrompt() + { + if (this.m_AxisPts.length === 2 + && isParallelTo(cZAxis, + this.m_AxisPts[1].clone().sub(this.m_AxisPts[0]) + .applyMatrix4(new Matrix4().extractRotation(this.m_UCSInv)) + ) + ) + { + this.m_DynPrompt.Visible = true; + this.m_DynPrompt.UpdatePrompt("Z轴"); + let vps = this.m_AxisPts.map(p => app.m_Viewer.WorldToScreen(p.clone())); + this.m_DynPrompt.SetPostion(midPoint(vps[0], vps[1])); + } + else + this.m_DynPrompt.Visible = false; + } + + //#endregion } diff --git a/src/Editor/TranstrolControl/TransformServices.ts b/src/Editor/TranstrolControl/TransformServices.ts index 6b2e4646a..555e90f31 100644 --- a/src/Editor/TranstrolControl/TransformServices.ts +++ b/src/Editor/TranstrolControl/TransformServices.ts @@ -3,13 +3,12 @@ import { end } from 'xaop'; import { app } from '../../ApplicationServices/Application'; import { InputState } from '../../Common/InputState'; import { MouseKey } from '../../Common/KeyEnum'; -import { CADFile } from '../../DatabaseServices/CADFile'; import { Entity } from '../../DatabaseServices/Entity'; import { MoveMatrix } from '../../Geometry/GeUtils'; -import { RenderType } from '../../GraphicsSystem/Enum'; import { PreViewer } from '../../GraphicsSystem/PreViewer'; import { commandMachine } from '../CommandMachine'; import { Editor, EditorService } from '../Editor'; +import { Jig } from '../Jig'; import { PointPick } from '../PointPick'; import { PromptStatus } from '../PromptResult'; import { MatrixToPreViewMat } from '../UCSServices'; @@ -87,13 +86,7 @@ export class TransformServicess implements EditorService app.m_Database.hm.StartCmd("_move"); app.m_Viewer.m_GripScene.visible = false; - let newEns: { old: Entity, new: Entity }[] = this.m_Ents.map(e => - { - let newE = e.Clone() as Entity; - app.m_Viewer.Scene.add(newE.Draw(RenderType.Wireframe)); - app.m_Editor.AddNoSnapEntity(newE); - return { old: e, new: newE }; - }); + let jigEns = this.m_Ents.map(e => Jig.Draw(e)); let base = new THREE.Vector3().setFromMatrixColumn(this.m_Matrix, 3); let ptRes = await this.m_Editor.GetPoint({ @@ -102,28 +95,18 @@ export class TransformServicess implements EditorService AllowDrawRubberBand: true, Callback: (newP) => { - for (let piar of newEns) - { - let f = new CADFile(); - piar.old.WriteFile(f); - piar.new.ReadFile(f); - piar.new.ApplyMatrix(MoveMatrix(newP.clone().sub(base))); - } + Jig.Restore(); + let m = MoveMatrix(newP.clone().sub(base)); + for (let e of jigEns) + e.ApplyMatrix(m); app.m_Editor.UpdateScreen(); } }); - newEns.forEach(p => - { - p.new.GoodBye(); - }); - if (ptRes.Status === PromptStatus.OK) { let m = MoveMatrix(ptRes.Value.sub(base)); - newEns.forEach(p => - { - p.old.ApplyMatrix(m); - }) + for (let e of this.m_Ents) + e.ApplyMatrix(m); } app.m_Viewer.m_GripScene.visible = true; diff --git a/src/Geometry/GeUtils.ts b/src/Geometry/GeUtils.ts index 8788cfa2f..83b54154b 100644 --- a/src/Geometry/GeUtils.ts +++ b/src/Geometry/GeUtils.ts @@ -2,10 +2,10 @@ import * as THREE from 'three'; import { Box3, BufferGeometry, Geometry, Matrix4, Vector, Vector2, Vector3, BufferAttribute } from 'three'; import { Matrix2 } from './Matrix2'; -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 Vector3(); +export const cXAxis = new Vector3(1, 0, 0); +export const cYAxis = new Vector3(0, 1, 0); +export const cZAxis = new Vector3(0, 0, 1); /** * 旋转一个点,旋转中心在原点 @@ -43,23 +43,6 @@ export function greater(v1, v2, fuzz = 0) return v1 - v2 > fuzz; } -/** - * 尝试对角度进行极轴测试 - * @param an 被测试的角度 - * @param fixAngle 测试角度等分位置 - * @param [fuzz] - * @returns - */ -export function fixAngle(an: number, fixAngle: number, fuzz: number = 0.05) -{ - let s = an / fixAngle; - let sf = Math.round(s); - - if (equaln(s, sf, fuzz)) - return sf * fixAngle; - else return NaN; -} - /** * 按照极坐标的方式移动一个点 * @@ -220,9 +203,9 @@ export function GetBoxArr(arr: Array): THREE.Box3 return box; } -export function MoveMatrix(v: THREE.Vector3): THREE.Matrix4 +export function MoveMatrix(v: Vector3): Matrix4 { - return new THREE.Matrix4().setPosition(v); + return new Matrix4().setPosition(v); } export function getProjectDist(v1: Vector3, v2: Vector3) @@ -247,24 +230,17 @@ export function getPtPostion(sp: Vector3, ep: Vector3, c: Vector3, inPt: Vector3 let ang3 = ang2 + Math.abs(ang1); let inputAng = angleTo(l1, inputLine); if (ang1 * inputAng < 0) - { inputAng = (Math.PI * 2 - Math.abs(inputAng)); - } ang1 = Math.abs(ang1); inputAng = Math.abs(inputAng); if (inputAng <= ang1) - { return { sp, ep }; - } else if (inputAng > ang1 && inputAng <= ang2) - { + else if (inputAng > ang1 && inputAng <= ang2) return { sp: c.clone().add(l3), ep } - } else if (inputAng > ang2 && inputAng <= ang3) - { + else if (inputAng > ang2 && inputAng <= ang3) return { sp: c.clone().add(l3), ep: c.clone().add(l4) } - } else - { + else return { sp, ep: c.clone().add(l4) }; - } } export function angleAndX(v: Vector3 | Vector2) { diff --git a/src/UI/Components/Panel.tsx b/src/UI/Components/Panel.tsx index 8ee77ae1a..daf6fdb54 100644 --- a/src/UI/Components/Panel.tsx +++ b/src/UI/Components/Panel.tsx @@ -186,6 +186,16 @@ export class DownPanel extends React.Component<{ store?: DownPanelStore }, {}> style={switchStyle} alignIndicator={Alignment.RIGHT} /> + + { + this.props.store.useOrtho = e.currentTarget.checked; + }} + style={switchStyle} + alignIndicator={Alignment.RIGHT} + />
{ - app.m_Editor.m_GetpointServices.snapServices.m_Disabled = !this.useDynSnap; + app.m_Editor.m_GetpointServices.snapServices.Disabled = !this.useDynSnap; + app.m_Editor.m_GetpointServices.snapServices.AxisSnapMode = this.useOrtho ? AxisSnapMode.Ortho : AxisSnapMode.Polar; app.m_Viewer.m_bUsePass = this.usePass; + }); }