From cf7dfe3980212c1646cb082ec155408f0f5ddbb9 Mon Sep 17 00:00:00 2001 From: zc <14204416+zhangconging@user.noreply.gitee.com> Date: Fri, 28 Jun 2024 03:17:22 +0000 Subject: [PATCH] =?UTF-8?q?!2757=20feat:=20=E5=9C=86=E5=BC=A7=E6=9D=BF?= =?UTF-8?q?=E5=A4=B9=E7=82=B9=E5=92=8C=E5=BB=B6=E4=BC=B8=E7=82=B9=E6=8B=96?= =?UTF-8?q?=E6=8B=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __test__/ArcBoard/ArcBoardBuild.test.ts | 10 + __test__/Polyline/polyline_ext.test.ts | 13 + src/Add-on/ArcBoard/ArcBoardBuild.ts | 6 +- src/DatabaseServices/Entity/Board.ts | 610 ++++++++++-------- .../Entity/CompositeEntity.ts | 1 + src/DatabaseServices/Entity/Entity.ts | 3 +- src/DatabaseServices/Entity/Extrude.ts | 2 +- src/DatabaseServices/Entity/Polyline.ts | 25 +- 8 files changed, 395 insertions(+), 275 deletions(-) create mode 100644 __test__/Polyline/polyline_ext.test.ts diff --git a/__test__/ArcBoard/ArcBoardBuild.test.ts b/__test__/ArcBoard/ArcBoardBuild.test.ts index 57d7565cf..2cd3bac9f 100644 --- a/__test__/ArcBoard/ArcBoardBuild.test.ts +++ b/__test__/ArcBoard/ArcBoardBuild.test.ts @@ -1,3 +1,4 @@ +import { Vector3 } from "three"; import { LoadBoardsFromFileData } from "../Utils/LoadEntity.util"; // 测试命令(用于复制):npm run test -- ArcBoardBuild.test.ts @@ -30,3 +31,12 @@ test('创建圆弧板4', () => let br = LoadBoardsFromFileData(data)[0]; expect(!br.GetSweepPath()).toBe(false); }); + +test('创建圆弧板MeshGeometry', () => +{ + const data = { "file": [1, "Board", 10, 2, 112, 0, 1, 2, 71, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 19904.78327896535, 4187.958560325209, -11618.264484039242, 1], 0, 0, 1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 16198.407124815723, 17111.522686662538, -11618.264484039242, 1], 0, 0, 1, 3, 28334.00417465891, 29190.267294923055, 18, false, "Polyline", 10, 2, 0, 0, 0, 7, 71, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 12923.564126337336, 3706.376154149625, 0, 1], 0, 0, 1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 12923.564126337336, 3706.376154149625, 0, 1], 0, 0, 1, 2, 4, [-12923.564126337336, -3706.376154149625], 0, [6386.434340466485, 993.3625201318764], 0, [16266.703168585718, 12209.356716972983], 0, [5532.995149899774, 24627.628020509284], 0, true, 0, 3, 0, 0, 0, 0, 0, 20, 0, "层板", "", "", "", "", "", 0, 0, "三合一", 2, 0, "1", "1", "1", "1", "", "", "", 4, "三合一", "三合一", "三合一", "三合一", true, true, 0, 0, 0, 0, 0, 0, 0, 0, true, 0, 0, null, 0, 0, "", "", "", "", 0, false, 0, "Polyline", 10, 2, 0, 0, 0, 7, 71, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, 1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, 1, 2, 4, [2.4868995751603507e-14, -1.0658141036401503e-14], 0, [5602.807360060827, 16026.299899791413], 0, [9473.648588094784, 17992.44147593565], 0, [19929.97581119567, 12595.62742530294], 0, false, 0.7853981633974483, 1, true, 1, -1, 0, 6, 6, 2, 0, 0, 0, 3, 0, 0], "basePt": { "x": 867.6016383403512, "y": 4175.9435246959365, "z": -11618.264484039242 }, "ucs": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] }; + + const br = LoadBoardsFromFileData(data)[0]; + br.MoveGripPoints([2], new Vector3(7509.205851318104, -4891.551400246293, 0)); + br.MeshGeometry; +}); diff --git a/__test__/Polyline/polyline_ext.test.ts b/__test__/Polyline/polyline_ext.test.ts new file mode 100644 index 000000000..edaadb030 --- /dev/null +++ b/__test__/Polyline/polyline_ext.test.ts @@ -0,0 +1,13 @@ +import { Polyline } from "../../src/DatabaseServices/Entity/Polyline"; +import { LoadCurvesFromFileData } from "../Utils/LoadEntity.util"; +import "../Utils/jest.util"; +test('多段线圆弧前向延伸错误', () => +{ + let d = + { "file": [1, "Polyline", 10, 2, 103, 0, 1, 7, 71, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 379.4117647058823, 179.41176470588238, 0, 1], 0, 0, 1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, 1, 2, 4, [0, 0], -0.592698851053085, [511.76470588235316, -30.882352941176464], 0, [1054.4117647058824, -45.58823529411765], -0.8681818857079551, [1107.3529411764707, -508.8235294117648], 0, false], "basePt": { "x": 379.4117647058823, "y": -329.41176470588243, "z": 0 }, "ucs": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] }; + let pl = LoadCurvesFromFileData(d)[0] as Polyline; + + pl.Extend(-0.2); + + expect(pl.Length).toMatchNumberSnapshot(); +}); diff --git a/src/Add-on/ArcBoard/ArcBoardBuild.ts b/src/Add-on/ArcBoard/ArcBoardBuild.ts index aae23628f..216875700 100644 --- a/src/Add-on/ArcBoard/ArcBoardBuild.ts +++ b/src/Add-on/ArcBoard/ArcBoardBuild.ts @@ -413,8 +413,10 @@ export class ArcBoardBuild leftPolys.push(poly); else if (res.type === 4) { - leftPolys.push(res.back); - rightPolys.push(res.front); + if (res.back) + leftPolys.push(res.back); + if (res.front) + rightPolys.push(res.front); } } diff --git a/src/DatabaseServices/Entity/Board.ts b/src/DatabaseServices/Entity/Board.ts index e244c66f4..6ad270a54 100644 --- a/src/DatabaseServices/Entity/Board.ts +++ b/src/DatabaseServices/Entity/Board.ts @@ -1,5 +1,5 @@ import Geom3 from '@jscad/modeling/src/geometries/geom3/type'; -import { BufferAttribute, BufferGeometry, Euler, FrontSide, Frustum, Geometry, LineSegments, Matrix3, Matrix4, Mesh, Object3D, ShapeGeometry, Line as TLine, UVGenerator, Vector2, Vector3 } from 'three'; +import { BufferAttribute, BufferGeometry, Euler, FrontSide, Frustum, Geometry, LineSegments, Matrix3, Matrix4, Mesh, Object3D, ShapeGeometry, Line as TLine, UVGenerator, Vector3 } from 'three'; import { ArcBoardBuild } from '../../Add-on/ArcBoard/ArcBoardBuild'; import { ArcBoardOptions, ParseBoardArcFeed, defultArcBoardOption } from '../../Add-on/ArcBoard/ArcBoardFeeding'; import { SplitBoardSideModelUtil } from '../../Add-on/BoardCutting/SplitBoardSideModel'; @@ -9,7 +9,7 @@ import { DrillType, FaceDirection } from "../../Add-on/DrawDrilling/DrillType"; import { CyHoleInBoard, IBoardRectHoleType, ParseBoardRectHoleType, SetBrHighHoleTypeFromRectHoleType } from '../../Add-on/DrawDrilling/HoleUtils'; import { HostApplicationServices } from '../../ApplicationServices/HostApplicationServices'; import { AddEntityDrawObject } from '../../Common/AddEntityDrawObject'; -import { arrayClone, arrayPushArray, arrayRemoveDuplicateBySort, arrayRemoveIf, arraySortByNumber, arraySum } from '../../Common/ArrayExt'; +import { arrayLast, arrayPushArray, arrayRemoveDuplicateBySort, arrayRemoveIf, arraySortByNumber, arraySum } from '../../Common/ArrayExt'; import { EBoardKeyList } from '../../Common/BoardKeyList'; import { Geom3Res } from '../../Common/CSGIntersect'; import { ColorMaterial } from '../../Common/ColorPalette'; @@ -28,7 +28,7 @@ import { Box3Ext } from '../../Geometry/Box'; import { BufferGeometryUtils } from '../../Geometry/BufferGeometryUtils'; import { AddCSGSubtractTask, CSGTask, TerminateCSGTask } from '../../Geometry/CSGSubtract/CSGSubtractTaskManager'; import { EdgesGeometry } from '../../Geometry/EdgeGeometry'; -import { AsVector2, AsVector3, IdentityMtx4, XAxis, XAxisN, YAxis, YAxisN, ZAxis, ZeroVec, equaln, equalv3 } from '../../Geometry/GeUtils'; +import { AsVector2, AsVector3, IdentityMtx4, XAxis, XAxisN, YAxis, YAxisN, ZAxis, ZeroVec, equaln, equalv2, equalv3 } from '../../Geometry/GeUtils'; import { PointShapeUtils } from '../../Geometry/PointShapeUtils'; import { GetBoardContour, GetBoardHighSeal, GetBoardSealingCurves, GetHighBoardEdgeRemark, SetBoardEdgeRemarkData, SetBoardTopDownLeftRightSealData } from '../../GraphicsSystem/CalcEdgeSealing'; import { RenderType } from '../../GraphicsSystem/RenderType'; @@ -161,19 +161,15 @@ export class Board extends ExtrudeSolid //二维刀路 id -> polyline private _KnifePolylineMap: Map = new Map(); + private _jigSweepPath: Polyline; // 拖拽时见光面的SweepPath + private _jigPath2WCSMtx: Matrix4; // 拖拽时路径转世界坐标系矩阵 + constructor() { super(); this.InitBoardData(); } - override CheckContourCurve() - { - super.CheckContourCurve(); - if (this._SweepPath && !this._FixContourByArcSweepPath_Ing) - this.FixArcSweepPathLength(); - } - get BoundingBoxInOCS() { if (this._SweepPath) @@ -192,6 +188,56 @@ export class Board extends ExtrudeSolid this._isDrawArcGroove = v; } + /** + * path 发生改变,更新圆弧配置 + * @param {{ key: number, arc: Arc; }[]} oldArcs 旧圆弧和对应的board options key + * @param {Polyline} nPath 新路径(未进行起点偏移) + * @return {*} {void} + */ + private UpdateArcBoardOptionsByPath(oldArcs: { key: number, arc: Arc; }[], nPath: Polyline): void + { + if (oldArcs.length === 0) return; + + const nCurves = nPath.Explode(); + const newArcs: { key: number, arc: Arc; }[] = []; + for (let i = 0; i < nCurves.length; i++) + if (nCurves[i] instanceof Arc) + newArcs.push({ key: i, arc: nCurves[i] as Arc }); + + const newOpts = new Map(); + const oldOpts = this._ArcBoardOptions; + newOpts.set(-1, oldOpts.get(-1)); + + // 设置新圆弧对应的原始配置 + for (let i = 0; i < newArcs.length; i++) + for (const item of oldArcs) + { + const oldArc = item.arc; + const oldKey = item.key; + const newArc = newArcs[i].arc; + const newKey = newArcs[i].key; + if (equalv3(newArc.StartPoint, oldArc.StartPoint, 1e-5) || equalv3(newArc.EndPoint, oldArc.EndPoint, 1e-5)) // 若圆弧的头或尾部位置相同,说明是同一段圆弧 + { + newOpts.set(newKey, { ...oldOpts.get(oldKey), arcLength: parseFloat(FixedNotZero(newArc.Length, 5)) }); + break; + } + } + + // 曲线从头拉到尾部后面,或者从尾拉到头部前面 + if (newArcs.length === 1 && newOpts.size === 1) + { + let oldArcIndex = 0;// 第一个圆弧 + if (equalv3(newArcs[0].arc.StartPoint, arrayLast(oldArcs).arc.EndPoint, 1e-3)) // 从头拉伸到尾部后面,则新圆弧的起点和旧圆弧的尾点相等。 + oldArcIndex = oldArcs.length - 1; // 最后一个圆弧 + const oldKey = oldArcs[oldArcIndex].key; + const newKey = newArcs[0].key; + newOpts.set(newKey, { ...oldOpts.get(oldKey), arcLength: parseFloat(FixedNotZero(newArcs[0].arc.Length, 5)) }); + } + + this._ArcBoardOptions.clear(); + this._ArcBoardOptions = newOpts; + } + get ArcBoardOptions() { if (this._ArcBoardOptions.size > 0) @@ -2191,6 +2237,7 @@ export class Board extends ExtrudeSolid || renderType === RenderType.CustomNumber //自定义编号 || renderType === RenderType.CustomNumberPrint//自定义编号打印 || renderType === RenderType.ModelGroove //造型槽 + || this.IsEmbedEntity && !this.ParentEntity.objectId // 复合实体 ) { obj = new Object3D(); @@ -2207,22 +2254,25 @@ export class Board extends ExtrudeSolid UpdateDrawObject(renderType: RenderType, obj: Object3D) { - if (this._SweepPath && renderType === RenderType.Jig) - // if (this._SweepPath) + // 圆弧板和复合实体内的圆弧板,Jig时,实时显示见光面路径 + if (this._SweepPath && (renderType === RenderType.Jig || this.IsEmbedEntity && !this.ParentEntity.objectId)) { DisposeThreeObj(obj); Object3DRemoveAll(obj); - let pts = this._SweepPath.Shape.getPoints().map(AsVector3); - for (let p of pts) - { - p.z = p.y; - p.y = 0; - if (this._SweepAngle !== 0) - p.applyMatrix4(this.ArcBuild.Rotate2OCSMtx); - } - let geo = new BufferGeometry().setFromPoints(pts); - obj.add(new TLine(geo, ColorMaterial.GetLineMaterial(this.DrawColorIndex))); + if (!this._jigSweepPath) + return; + + const path2BoardMtx = new Matrix4(); + const invMtx = new Matrix4().getInverse(this._Matrix); + path2BoardMtx.multiplyMatrices(invMtx, this._jigPath2WCSMtx); + const pts = this._jigSweepPath.Shape.getPoints().map(AsVector3); + const geo = new BufferGeometry().setFromPoints(pts); + const line = new TLine(geo, ColorMaterial.GetLineMaterial(this.ColorIndex)); + line.matrix = path2BoardMtx; + obj.add(line); + this._jigSweepPath = undefined; + this._jigPath2WCSMtx = undefined; return; } @@ -2522,30 +2572,17 @@ export class Board extends ExtrudeSolid override GetGripPoints(): Vector3[] { let pts = super.GetGripPoints(); + pts = this.MapToArcPoints(pts, DragPointType.Grip); + return pts; + } + + private MapToArcPoints(pts: Vector3[], dragPointType: DragPointType): Vector3[] + { if (this._SweepPath) { if (!this._SweepArcBoardBuild) this._SweepArcBoardBuild = new ArcBoardBuild(this); - if (false)//暂时放弃这个直接拉伸路径的功能 - { - // if (!this._SweepArcBoardBuild) - // { - // this._SweepArcBoardBuild = new ArcBoardBuild(this); - // this._SweepArcBoardBuild.ParseSweepCurves(); - // } - - let pts = this._SweepPath.GetGripPoints(); - for (let p of pts) - { - [p.y, p.z] = [p.z, p.y];//映射点 - if (this._SweepAngle !== 0) - p.applyMatrix4(this._SweepArcBoardBuild.Rotate2OCSMtx); - p.applyMatrix4(this.OCSNoClone); - } - return pts; - } - let inv = this.OCSInv; let mtx = this.OCSNoClone; if (this._SweepArcBoardBuild._OCS2RotateMtx) @@ -2567,10 +2604,8 @@ export class Board extends ExtrudeSolid this._SweepArcBoardBuild.PosMap2ArcPos(p); p.applyMatrix4(mtx); } - } - - if (this.HasSideModel) - this.AddSideModelGripPoints(pts, DragPointType.Grip); + } else if (this.HasSideModel) + this.AddSideModelGripPoints(pts, dragPointType); return pts; } @@ -2578,101 +2613,25 @@ export class Board extends ExtrudeSolid override MoveGripPoints(indexList: number[], vec: Vector3): void { if (indexList.length === 0) return; + this.ClearSideModelingCache(); if (this._SweepPath) { - this.WriteAllObjectRecord(); - if (false)//暂时放弃这个直接拉伸路径的功能 - { - vec = TransformVector(vec.clone(), this.OCSInv); - - if (this._SweepAngle !== 0) - TransformVector(vec, this.ArcBuild.OCS2RotateMtx); - - [vec.y, vec.z] = [vec.z, -vec.y]; - - this._SweepPath.MoveGripPoints(indexList, vec); - let sp = this._SweepPath.StartPoint; - if (!equalv3(sp, ZeroVec)) - { - for (let i = 0; i < this._SweepPath.LineData.length; i++) - this._SweepPath.LineData[i].pt.sub(sp as unknown as Vector2); - this._SweepPath.OCSNoClone.identity(); - - let [y, z] = [sp.y, sp.z]; - sp.z = y; - sp.y = -z; - - if (this._SweepAngle !== 0) - TransformVector(sp, this.ArcBuild.Rotate2OCSMtx); - - TransformVector(sp, this.OCSNoClone); - this.Move(sp); - } - if (this.objectId) - this.FixContourByArcSweepPath(); - this.Update(); - return; - } + this.MoveArcBoardPoints(indexList, vec, DragPointType.Grip); + this.Update(); } - - this.ClearSideModelingCache(); - super.MoveGripPoints(indexList, vec); + else + super.MoveGripPoints(indexList, vec); } GetStretchPoints() { - if (this._SweepPath) - { - let spts = this._SweepPath.GetStretchPoints(); - let pts: Vector3[] = []; - - if (!this._SweepArcBoardBuild) - this._SweepArcBoardBuild = new ArcBoardBuild(this); - - for (let p of spts) - { - [p.y, p.z] = [p.z, p.y];//映射点 - if (this._SweepAngle !== 0) - p.applyMatrix4(this._SweepArcBoardBuild.Rotate2OCSMtx); - pts.push(p); - } - - let brWidth: number; - if (this._SweepAngle === 0) - brWidth = this.height; - else if (equaln(Math.abs(this._SweepAngle), Math.PI / 2)) - brWidth = this.width; - - else - { - let con = this.ContourCurve.Clone(); - let ro = new Matrix4().makeRotationZ(-this._SweepAngle); - con.ApplyMatrix(ro); - let box = con.BoundingBox; - brWidth = box.max.y - box.min.y; - } - - let v = new Vector3(0, brWidth, 0); - if (this._SweepAngle !== 0) - TransformVector(v, this._SweepArcBoardBuild.Rotate2OCSMtx); - - for (let p of spts) - pts.push(p.clone().add(v)); - - for (let p of pts) - p.applyMatrix4(this.OCSNoClone); - return pts; - } - let pts = this.GetGripOrStretchPoints(DragPointType.Stretch); + pts = this.MapToArcPoints(pts, DragPointType.Stretch); for (let m of this._2DModelingList) { pts.push(...m.path.GetStretchPoints().map(p => p.add(new Vector3(0, 0, m.dir === FaceDirection.Front ? this.thickness : 0)).applyMatrix4(this.OCSNoClone))); } - if (this.HasSideModel) - this.AddSideModelGripPoints(pts, DragPointType.Stretch); - return pts; } @@ -2685,147 +2644,6 @@ export class Board extends ExtrudeSolid undoData.WriteObjectHistoryPath(this, new HistorycRecord); return; } - - if (this._SweepPath) - { - if (false) - { - this.WriteAllObjectRecord(); - let stretchCount = this._SweepPath.GetDragPointCount(DragPointType.Stretch); - //Move - if (indexList.length === stretchCount * 2) - { - this.Position = this.Position.add(vec); - return; - } - - vec = vec.clone(); - let inv = this.OCSInv.setPosition(0, 0, 0); - vec.applyMatrix4(inv); - - if (this._SweepAngle !== 0) - TransformVector(vec, this.ArcBuild.OCS2RotateMtx); - - const IsStretchThickness = (indexs: number[]) => - { - if (indexs.length === stretchCount) - { - let isF = indexs[0] < stretchCount; - return indexs.every(i => isF === (i < stretchCount)); - } - return false; - }; - if (IsStretchThickness(indexList)) - { - let isFront = indexList[0] < stretchCount; - - if (indexList.every(v => v < stretchCount === isFront)) - { - - function UnEqualProportionScale(cu: Curve, ref: number, dist: number, isFront: boolean) - { - if (cu instanceof Polyline) - { - let lineData = cu.LineData; - let length = lineData.length; - let p = cu.Position.y; - - let moveIndexs: number[] = []; - for (let i = 0; i < length; i++) - { - if (isFront ? (lineData[i].pt.y + p < ref) : (lineData[i].pt.y + p > ref)) - moveIndexs.push(i); - } - let moveVec = new Vector3(); - moveVec.y = dist; - cu.MoveStretchPoints(moveIndexs, moveVec); - return true; - } - return false; - } - - //Change thickness - let con = this.ContourCurve.Clone(); - if (this._SweepAngle !== 0) - con.ApplyMatrix(this.ArcBuild.OCS2RotateMtx); - (con as Polyline).UpdateOCSTo(new Matrix4); - - let box = con.BoundingBox; - let size = box.max.y - box.min.y; - { - // if (this.objectId) - // TestDraw(con.Clone(), 4); - let isSuccess = UnEqualProportionScale(con, size / 2, vec.y, isFront); - - // if (this.objectId) - // TestDraw(con.Clone(), 3); - - if (this._SweepAngle !== 0) - con.ApplyMatrix(this.ArcBuild.Rotate2OCSMtx); - - let box = con.BoundingBox; - // if (this.objectId) - // TestDraw(con.Clone(), 2); - con.Move(box.min.clone().negate()); - - // if (this.objectId) - // TestDraw(con.Clone(), 1); - this.SetContourCurve(con); - - // //移动位置而不改变内部拉槽 - let v = box.min; - TransformVector(v, this.OCSNoClone); - - this._Matrix.elements[12] += v.x; - this._Matrix.elements[13] += v.y; - this._Matrix.elements[14] += v.z; - } - return; - } - } - indexList = arrayClone(indexList); - //修正点的索引 - for (let i = 0; i < indexList.length; i++) - { - let index = indexList[i]; - if (index >= stretchCount) - { - index -= stretchCount; - indexList[i] = index; - } - } - indexList = [...new Set(indexList)]; - - - - [vec.y, vec.z] = [vec.z, -vec.y]; - - this._SweepPath.MoveStretchPoints(indexList, vec); - let sp = this._SweepPath.StartPoint; - if (!equalv3(sp, ZeroVec)) - { - for (let i = 0; i < this._SweepPath.LineData.length; i++) - this._SweepPath.LineData[i].pt.sub(sp as unknown as Vector2); - this._SweepPath.OCSNoClone.identity(); - - let [y, z] = [sp.y, sp.z]; - sp.z = y; - sp.y = -z; - - if (this._SweepAngle !== 0) - TransformVector(sp, this.ArcBuild.Rotate2OCSMtx); - - TransformVector(sp, this.OCSNoClone); - this.Move(sp); - } - this.FixContourByArcSweepPath(); - this.Update(); - } - - return;//暂时屏蔽圆弧板的拉伸 - - } - let exCount = arraySum(this.GetStrectchPointCountList(DragPointType.Stretch)); let originIndexList: number[] = []; let mIndexList: number[] = []; @@ -2839,7 +2657,10 @@ export class Board extends ExtrudeSolid let oldOcs = this.OCS; - super.MoveStretchPoints(originIndexList, vec); + if (this._SweepPath) + this.MoveArcBoardPoints(originIndexList, vec, DragPointType.Stretch); + else + super.MoveStretchPoints(originIndexList, vec); if (!this.Id) return; @@ -2991,6 +2812,257 @@ export class Board extends ExtrudeSolid return pts; } + + private MoveArcBoardPoints(indexList: Array, vec: Vector3, dragType: DragPointType) + { + this.WriteAllObjectRecord(); + const isGrip = dragType === DragPointType.Grip; + const oldPts = isGrip ? this.GetGripPoints() : this.GetStretchPoints(); + const MoveBack = () => isGrip ? super.MoveGripPoints(indexList, offsetVec.clone().negate()) : super.MoveStretchPoints(indexList, offsetVec.clone().negate()); + + let path = this.ArcBuild.SweepPath1.Clone(); + + // 1、计算沿着SweepPath偏移的向量 + const offsetVec = this.GetOffsetVecAlongPath(oldPts[indexList[0]].clone(), vec, path); + + const oldPos = this.Position; + const oldCon = this.ContourCurve.Clone(); + const ocs2rot = this.ArcBuild.OCS2RotateMtx; + oldCon.ApplyMatrix(ocs2rot); + const oldBox = oldCon.BoundingBox; + + // 2、移动平板上的点 + isGrip ? super.MoveGripPoints(indexList, offsetVec) : super.MoveStretchPoints(indexList, offsetVec); + + const newPos = this.Position; + const conMoveVec = TransformVector(newPos.clone().sub(oldPos), this.OCSInv);//轮廓在OCS中移动的向量 + const newCon = this.ContourCurve.Clone(); + newCon.Move(conMoveVec); + newCon.ApplyMatrix(ocs2rot); + const newBox = newCon.BoundingBox; + + this._jigSweepPath = path.Clone(); + + // 特殊场景:闭合SweepPath,其对应的首尾不能发生变化,否者会发生path和Contour映射错误。 + if (path.CloseMark && !(equaln(newBox.min.x, oldBox.min.x) && equaln(newBox.max.x, oldBox.max.x))) + { + MoveBack();// 若头尾被拖拽过,需要恢复回去 + return; + } + + // 特殊场景:某些操作,对弧形板进行移动(如当拖拽中间点),未发生路径改变,则重新移动回去 + const newSize = newBox.getSize(new Vector3); + const oldSize = oldBox.getSize(new Vector3); + if (equaln(newSize.x, oldSize.x, 1e-3)) + { + const newPts = isGrip ? this.GetGripPoints() : this.GetStretchPoints(); + if (oldPts.length === newPts.length) + { + const vec = oldPts[0].clone().sub(newPts[0]); + const isMoveArcBoard = oldPts.every((pt, i) => equalv3(pt.clone().sub(newPts[i]), vec)); + if (isMoveArcBoard) + { + MoveBack(); + return; + } + } + } + + // 3、修正SweepPath + path = this.FixSweepPathByContourBondingbox(newBox, oldBox, path); + // 特殊场景:path 计算发生错误,需要恢复板的状态 + if (!path) + { + MoveBack(); + return; + } + + // 4、计算弧形板偏移矩阵 + if (this.objectId || (this.IsEmbedEntity && this.ParentEntity.objectId)) + { + const pts1 = isGrip ? newCon.GetGripPoints() : newCon.GetStretchPoints(); + const pts2 = isGrip ? oldCon.GetGripPoints() : oldCon.GetStretchPoints(); + const count = Math.min(pts1.length, pts2.length); + this._SweepArcBoardBuild = undefined; + for (let i = 0; i < count; i++) + { + if (equalv2(pts1[i], pts2[i], 1e-3)) // 找到新板和旧板上不变的点,计算出偏移矩阵 + { + const pts = isGrip ? this.GetGripPoints() : this.GetStretchPoints(); + this.Move(oldPts[i].sub(pts[i])); + break; + } + } + this._SweepArcBoardBuild = undefined; + } + } + + private GetOffsetVecAlongPath(oldP: Vector3, vec: Vector3, path: Polyline): Vector3 + { + const p = oldP.clone().add(vec);//拉伸后的点 在世界坐标系中 + + const path2WCSMtx = new Matrix4().makeBasis(XAxis, ZAxis, YAxisN); + if (this._SweepAngle !== 0) + path2WCSMtx.premultiply(this.ArcBuild.Rotate2OCSMtx); + path2WCSMtx.premultiply(this.OCSNoClone); + const wcs2PathMtx = new Matrix4().getInverse(path2WCSMtx); + this._jigPath2WCSMtx = path2WCSMtx.clone(); + + //变换到路径坐标系 + p.applyMatrix4(wcs2PathMtx); + oldP.applyMatrix4(wcs2PathMtx); + + // 限制p, 在见光面的曲面中,计算偏移向量 + const cp = path.GetClosestPointTo(p, true); + + const oldZ = oldP.z; + const newZ = p.z; + + const oldPCp = path.GetClosestPointTo(oldP.setZ(0), false);//旧的最近点 + const oldDist = path.GetDistAtPoint2(oldPCp);// 移动前的Dist + const movedDist = path.GetDistAtPoint2(cp);// 移动后的Dist + + const moveVec = new Vector3(movedDist - oldDist, - newZ + oldZ, 0); + + //将moveVec转换到世界坐标系 + if (this._SweepAngle !== 0) + TransformVector(moveVec, this.ArcBuild.Rotate2OCSMtx); + TransformVector(moveVec, this.OCSNoClone); + + return moveVec; + } + + /** + * @private 通过新旧轮廓的Bondingbox修正路径 + * @param {Box3Ext} newBox 路径坐标系下,新轮廓的Bondingbox + * @param {Box3Ext} oldBox 路径坐标系下,旧轮廓的Bondingbox + * @param {Polyline} path 见光面路径 + * @return {*} {Polyline} 修正好的路径 + */ + private FixSweepPathByContourBondingbox(newBox: Box3Ext, oldBox: Box3Ext, path: Polyline): Polyline + { + // 若头部和尾部重合,则直接不处理 + if (equaln(newBox.min.x, newBox.max.x, 0.1)) + return; + + const GetArcAndKeys = (): { key: number, arc: Arc; }[] => + { + const curves = path.Explode(); + const arcs: { key: number, arc: Arc; }[] = []; + for (let i = 0; i < curves.length; i++) + if (curves[i] instanceof Arc) + arcs.push({ key: i, arc: curves[i].Clone() as Arc }); + return arcs; + }; + const arcKeys = GetArcAndKeys(); + + const MovePath = (pathToMove: Polyline, mVec: Vector3) => + { + // 修正SWeepPath + pathToMove.Move(mVec); + const { pts: pathPts, buls } = pathToMove.MatrixAlignTo2(new Matrix4); + pathToMove.OCSNoClone.identity(); + for (let i = 0; i < pathToMove.LineData.length; i++) + { + pathToMove.LineData[i].pt.copy(pathPts[i]); + pathToMove.LineData[i].bul = buls[i]; + } + }; + + let jigSpt: Vector3 = undefined; + const FixHead = () => + { + if (!equaln(newBox.min.x, 0, 1e-3)) // 头部 + { + const c1 = path.GetCurveAtIndex(0); + if (newBox.min.x < 0) + path.Extend(newBox.min.x / c1.Length); // 延伸 + else + path = path.GetSplitCurves(path.GetParamAtDist(newBox.min.x))[1]; // 裁剪 + + jigSpt = path.StartPoint.clone(); + MovePath(path, path.StartPoint.clone().negate());// 修正Path + } + }; + + const FixTail = () => + { + if (!equaln(newBox.max.x, oldBox.max.x, 1e-3)) // 尾部 + { + const dist = newBox.max.x - oldBox.max.x; + const ce = path.GetCurveAtIndex(path.EndParam - 1); + if (dist > 0) + path.Extend(path.EndParam + ((dist) / ce.Length)); // 延伸 + else + path = path.GetSplitCurves(path.GetParamAtDist(newBox.max.x - newBox.min.x))[0]; // 裁剪, PS: 从尾部点拉伸到头部点之前,newBox.min.x不为零 + } + }; + + /** + * 某些异形板左侧头部拉伸到尾部后面示意图: + * ___________ + * A | | + * |_______ | + * | | + * old B |___| + * _____ + * | | A + * ___|_____| + * | | + * new B |___| + */ + const outofTail = newBox.min.x >= oldBox.max.x + || equaln(newBox.min.x, oldBox.max.x, 1e-3) // 矩形板:拉伸后,新板头和旧板尾部相同 + || newBox.min.x > oldBox.min.x && newBox.max.x > oldBox.max.x; // 某些异形板:新板头会在旧板中间某处,新板尾超过旧版尾 + if (outofTail) + { + // 头部拉伸在超过尾部,即新头部大于等于原尾部。则先对尾部延伸,再裁剪头部(若先裁剪头部,则path可能会为空) + FixTail(); + FixHead(); + } else + { + FixHead(); + FixTail(); + } + + // 计算 this._SweepPath + let sweepPath = undefined; + if (this._SweepVisibleFace === FaceDirection.Back) + { + sweepPath = path; + // 做offset偏移,查看path是否会被裁剪。若被裁剪,会破坏板和路径的映射关系,则不能继续其他操作 + if (this.objectId || (this.IsEmbedEntity && this.ParentEntity.objectId)) + { + const frontPath = ArcBoardBuild.OffsetPolyline(sweepPath, -this.thickness); // 正面path + const backPath = ArcBoardBuild.OffsetPolyline(frontPath, this.thickness); // 背面path + if (!equaln(backPath.Length, sweepPath.Length, 1e-3)) + return; + } + } + else + { + sweepPath = ArcBoardBuild.OffsetPolyline(path, this.thickness); + // 做offset偏移,查看path是否会被裁剪。若被裁剪,会破坏板和路径的映射关系,则不能继续其他操作 + if (this.objectId || (this.IsEmbedEntity && this.ParentEntity.objectId)) + { + const frontPath = ArcBoardBuild.OffsetPolyline(sweepPath, -this.thickness);// 正面path + if (!equaln(frontPath.Length, path.Length, 1e-3)) + return; + } + } + this._SweepPath = sweepPath; + + this._jigSweepPath = path.Clone(); + if (jigSpt) + MovePath(this._jigSweepPath, jigSpt);// 新路径,但是未进行起始点偏移。方便拖拽时,实时显示当前路径 + + // 更新圆弧配置 + if (this.objectId || (this.IsEmbedEntity && this.ParentEntity.objectId)) + this.UpdateArcBoardOptionsByPath(arcKeys, this._jigSweepPath); + + return path; + } + DeferUpdate() { if (this.NeedUpdateFlag & UpdateDraw.Matrix) diff --git a/src/DatabaseServices/Entity/CompositeEntity.ts b/src/DatabaseServices/Entity/CompositeEntity.ts index bb5c0b3ef..b7fa6537c 100644 --- a/src/DatabaseServices/Entity/CompositeEntity.ts +++ b/src/DatabaseServices/Entity/CompositeEntity.ts @@ -114,6 +114,7 @@ export abstract class CompositeEntity extends Entity for (let e of this.Entitys) { e.IsEmbedEntity = true; + e.ParentEntity = this.ParentEntity || this; // //内嵌实体在某些时候可能被清理,修复它 // if (e.DrawObject.children.length === 0) diff --git a/src/DatabaseServices/Entity/Entity.ts b/src/DatabaseServices/Entity/Entity.ts index 3c7626a22..9a841770a 100644 --- a/src/DatabaseServices/Entity/Entity.ts +++ b/src/DatabaseServices/Entity/Entity.ts @@ -27,7 +27,8 @@ import { PhysicalMaterialRecord } from '../PhysicalMaterialRecord'; export class Entity extends CADObject { - IsEmbedEntity = false; + ParentEntity: Entity; //当这个实体是内嵌实体时,提供了一个访问它父亲的链接 + IsEmbedEntity = false;//当这个值为true时,这个实体是复合实体的内嵌实体 /** * 该实体的只有一个渲染类型,任何渲染类型都一个样 diff --git a/src/DatabaseServices/Entity/Extrude.ts b/src/DatabaseServices/Entity/Extrude.ts index c479b9fe0..aee7156e5 100644 --- a/src/DatabaseServices/Entity/Extrude.ts +++ b/src/DatabaseServices/Entity/Extrude.ts @@ -1104,7 +1104,7 @@ export class ExtrudeSolid extends Entity } } - if (this.objectId) + if (this.objectId || (this.IsEmbedEntity && this.ParentEntity.objectId)) { this.CheckContourCurve(); let splitEntitys: this[] = []; diff --git a/src/DatabaseServices/Entity/Polyline.ts b/src/DatabaseServices/Entity/Polyline.ts index 4f274810f..504aa338d 100644 --- a/src/DatabaseServices/Entity/Polyline.ts +++ b/src/DatabaseServices/Entity/Polyline.ts @@ -629,6 +629,27 @@ export class Polyline extends Curve return this.GetDistAtParam(param); } + /** + * 这个方法允许点在曲线的延伸线上 + * @param pt 需要保证传入的点路径上 + * @returns + */ + GetDistAtPoint2(pt: Vector3): number + { + let param = this.GetParamAtPoint(pt); + if (param < 0) + { + let c1 = this.GetCurveAtIndex(0); + return c1.Length * param; + } + else if (param > this.EndParam) + { + let ce = this.GetCurveAtIndex(this.EndParam - 1); + return this.Length + ce.Length * (param - this.EndParam); + } + return this.GetDistAtParam(param); + } + /** * 返回曲线的一阶导数. * 当曲线闭合(标志)且点不在曲线上. @@ -850,8 +871,8 @@ export class Polyline extends Curve //修改凸度 let oldBul = this._LineData[bulIndex].bul; - if (oldBul != 0) - this._LineData[bulIndex].bul = Math.tan(Math.atan(oldBul) * (1 + newParam - ptIndex)); + if (oldBul !== 0) + this._LineData[bulIndex].bul = Math.tan(Math.atan(oldBul) * (1 + Math.abs(newParam - ptIndex))); this.Update(); }