diff --git a/src/Add-on/DrawDim/AutoDimBrs.ts b/src/Add-on/DrawDim/AutoDimBrs.ts index bd37eab98..9705645af 100644 --- a/src/Add-on/DrawDim/AutoDimBrs.ts +++ b/src/Add-on/DrawDim/AutoDimBrs.ts @@ -6,9 +6,33 @@ import { Board } from "../../DatabaseServices/Entity/Board"; import { Command } from "../../Editor/CommandMachine"; import { PromptStatus } from "../../Editor/PromptResult"; import { CoordinateSystem } from "../../Geometry/CoordinateSystem"; -import { equalnn, equaln } from "../../Geometry/GeUtils"; +import { equalnn, equaln, isParallelTo } from "../../Geometry/GeUtils"; import { JigUtils } from "../../Editor/JigUtils"; +import { SurroundOutlineParse } from "../../Geometry/SpaceParse/SurroundOutlineParse"; +import { ViewChange } from "../ViewChange"; +import { Polyline } from "../../DatabaseServices/Entity/Polyline"; +import { Curve } from "../../DatabaseServices/Entity/Curve"; +import { BoardType } from "../Erp/Models/CadBlock"; +import { Entity } from "../../DatabaseServices/Entity/Entity"; +import { OBB } from "../../Geometry/OBB/obb"; +import { Math as TMath } from "three"; +interface DirPls +{ + left: Curve[]; + right: Curve[]; + top: Curve[]; + bottom: Curve[]; +} +interface DirBrs +{ + left: Board[]; + right: Board[]; + top: Board[]; + bottom: Board[]; +} + +const DEG90 = TMath.radToDeg(Math.PI / 2);//90° export class Command_AutoDimBrs implements Command { async exec() @@ -16,30 +40,35 @@ export class Command_AutoDimBrs implements Command //选择板件 let enRes = await app.Editor.GetSelection({ Msg: "选择需要标注的柜体", - Filter: { filterTypes: [Board] } + Filter: { + filterFunction: (_object, board: Entity) => + { + return (board instanceof Board && (board.BoardType !== BoardType.Behind)); + } + }, }); - if (enRes.Status === PromptStatus.Cancel) + if (enRes.Status !== PromptStatus.OK) return; let brs = enRes.SelectSet.SelectEntityList as Board[]; //原数据转二维数组[[br0],[br1],[br2],[br3],[br4]...],并记录每组的Box let brBoxs: Box3[] = []; - let brRes: Board[][] = brs.map(item => + let brGroups: Board[][] = brs.map(item => { brBoxs.push(item.BoundingBox); return [item]; }); - for (let i = 0; i < brRes.length; i++) + for (let i = 0; i < brGroups.length; i++) { - for (let j = i + 1; j < brRes.length; j++) + for (let j = i + 1; j < brGroups.length; j++) { //如有合并则重新开始 if (brBoxs[i].intersectsBox(brBoxs[j])) { - brRes[i] = [...brRes[i], ...brRes[j]]; + brGroups[i] = [...brGroups[i], ...brGroups[j]]; brBoxs[i].union(brBoxs[j]); - brRes.splice(j, 1); + brGroups.splice(j, 1); brBoxs.splice(j, 1); i = -1; break; @@ -47,26 +76,104 @@ export class Command_AutoDimBrs implements Command } } - for (let brs of brRes) + for (let brs of brGroups) { let spaceOcs = brs[0].SpaceOCS; let cs = new CoordinateSystem().CopyForm(spaceOcs); + //排除旋转角度非90度倍数的板件 + brs = brs.filter(b => ( + equaln((TMath.radToDeg(b.Rotation.x) + 90) % (DEG90), 0) + && equaln((TMath.radToDeg(b.Rotation.y) + 90) % (DEG90), 0) + && equaln((TMath.radToDeg(b.Rotation.z) + 90) % (DEG90), 0) + )); + + if (brs.length === 0) + { + app.Editor.Prompt(`可标注板件数: 0, 已退出`); + return; + } + let right = new Matrix4() .makeBasis(cs.YAxis, cs.XAxis.clone().negate(), cs.ZAxis) .copyPosition(spaceOcs); - let front = new Matrix4() - .makeBasis(cs.ZAxis, cs.XAxis.clone().negate(), cs.YAxis.clone().negate()) - .copyPosition(spaceOcs); - this.DrawDim(brs, spaceOcs); + //绘制右侧标注(俯视图) this.DrawDim(brs, right, -Math.PI); - this.DrawDim(brs, front, -Math.PI); + //绘制前视图的标注 + await this.DrawFrontDim(brs, -Math.PI); } } /** - * + * 绘制前视图的标注 + * @param brs 需要绘制前视图标注的板件 + * @param textRo 字体旋转角度(弧度形式) + */ + async DrawFrontDim(brs: Board[], textRo: number) + { + //构造绘制坐标 + let spaceOcs = brs[0].SpaceOCS; + let cs = new CoordinateSystem().CopyForm(spaceOcs); + + let drawCS_right = new Matrix4() + .makeBasis(cs.ZAxis, cs.XAxis.clone().negate(), cs.YAxis) + .copyPosition(spaceOcs); + let drawCS_left = new Matrix4() + .makeBasis(cs.ZAxis.clone().negate(), cs.XAxis, cs.YAxis) + .copyPosition(spaceOcs); + let drawCS_top = new Matrix4() + .makeBasis(cs.XAxis.clone().negate(), cs.ZAxis.clone().negate(), cs.YAxis) + .copyPosition(spaceOcs); + let drawCS_bottom = new Matrix4() + .makeBasis(cs.XAxis, cs.ZAxis, cs.YAxis) + .copyPosition(spaceOcs); + + //获得外轮廓 + let viewDir = cs.YAxis; + let oldUCS = app.Editor.UCSMatrix; + let viewChange = new ViewChange(viewDir); + viewChange.UcsLookAt(viewDir); + let spaceParse = new SurroundOutlineParse(brs); + await spaceParse.Parse(); + app.Editor.UCSMatrix = oldUCS; + + let pl = new Polyline(); + for (let cu of spaceParse.m_Outlines) + { + pl.Join(cu); + cu.Erase(); + } + pl.CloseMark = true; + + //分析外轮廓上下左右并得到上下左右的板件 + let dirPls = this.JudgeOutlineDirection(pl, cs); + let dirBrs: DirBrs = { right: [], left: [], top: [], bottom: [] }; + + for (let key in dirPls) + { + for (let i = 0; i < dirPls[key].length; i++) + { + let l = dirPls[key][i] as Curve; + let xv = l.EndPoint.sub(l.StartPoint); + let zv = viewDir; + let yv = zv.clone().cross(xv); + let ocs = new Matrix4().makeBasis(xv.normalize(), yv.negate().normalize(), zv.normalize()); + ocs.setPosition(l.StartPoint); + + let cuObb = new OBB(ocs, new Vector3(l.Length, 20, 20).multiplyScalar(0.5)); + dirBrs[key].push(...brs.filter(b => cuObb.intersectsOBB(b.OBB))); + } + } + //绘制标注 + if (dirBrs.top.length > 0) this.DrawDim(dirBrs.top, drawCS_top, textRo); + if (dirBrs.right.length > 0) this.DrawDim(dirBrs.right, drawCS_right, textRo); + if (dirBrs.left.length > 0) this.DrawDim(dirBrs.left, drawCS_left, textRo); + if (dirBrs.bottom.length > 0) this.DrawDim(dirBrs.bottom, drawCS_bottom); + } + + /** + * 绘制标注 * @param brs * @param drawCS 绘制标注的坐标系 */ @@ -80,9 +187,6 @@ export class Command_AutoDimBrs implements Command let drawCSInv = new Matrix4().getInverse(drawCS); for (let br of brs) { - //排除酒格 - if (!(equaln(br.Rotation.x, 0) && equaln(br.Rotation.y, 0) && equaln(br.Rotation.z, 0))) - continue; let mtx = new Matrix4().multiplyMatrices(drawCSInv, br.OCS); let box = br.BoundingBoxInOCS.applyMatrix4(mtx); foots.push(box.min.x, box.max.x); @@ -91,15 +195,30 @@ export class Command_AutoDimBrs implements Command maxZ = Math.max(maxZ, box.max.z); } - if (!needJig) - minZ = 0; - arraySortByNumber(foots); arrayRemoveDuplicateBySort(foots, equalnn(1)); let drawY = minY - 20; let armY = drawY - 100; let z = useMaxZ ? maxZ : minZ; + let drawYTotal = minY - 120; + let armYTotal = drawYTotal - 100; + + if (!needJig) + { + //draw总长 + let alDimTotal = new AlignedDimension( + new Vector3(foots[0], drawYTotal, z), + new Vector3(foots[foots.length - 1], drawYTotal, z), + new Vector3(foots[0], armYTotal, z), + new Vector3(foots[foots.length - 1], armYTotal, z) + ); + if (textRotation) + alDimTotal.TextRotation = textRotation; + + alDimTotal.ApplyMatrix(drawCS); + app.Database.ModelSpace.Append(alDimTotal); + } //draw for (let i = 0; i < foots.length - 1; i++) @@ -128,4 +247,36 @@ export class Command_AutoDimBrs implements Command } return als; } + + /** + * 判断轮廓的上下左右 + * @param pl 轮廓(多段线) + * @param cs 参照坐标系 + * @memberof Command_AutoDimBrs + */ + JudgeOutlineDirection(pl: Polyline, cs: CoordinateSystem): DirPls + { + let clockWise = pl.Area2 < 0;//true为顺时针 false为逆时针 + let res: DirPls = { right: [], left: [], top: [], bottom: [] }; + for (let i = 0; i < pl.EndParam; i++) + { + let cu = pl.GetCurveAtParam(i); + let derv = cu.GetFistDeriv(0).normalize(); + if (isParallelTo(derv, cs.XAxis)) + { + if (derv.dot(cs.XAxis) > 0) + clockWise ? res.top.push(cu) : res.bottom.push(cu); + else + clockWise ? res.bottom.push(cu) : res.top.push(cu); + } + else + { + if (derv.dot(cs.ZAxis) < 0) + clockWise ? res.right.push(cu) : res.left.push(cu); + else + clockWise ? res.left.push(cu) : res.right.push(cu); + } + } + return res; + } } diff --git a/src/Add-on/DrawDim/FastDim.ts b/src/Add-on/DrawDim/FastDim.ts index fdc4a15f9..01b686650 100644 --- a/src/Add-on/DrawDim/FastDim.ts +++ b/src/Add-on/DrawDim/FastDim.ts @@ -7,6 +7,8 @@ import { JigUtils } from "../../Editor/JigUtils"; import { AlignedDimension } from "../../DatabaseServices/Dimension/AlignedDimension"; import { CoordinateSystem } from "../../Geometry/CoordinateSystem"; import { Command_AutoDimBrs } from "./AutoDimBrs"; +import { Math as TMath } from "three"; +import { equaln } from "../../Geometry/GeUtils"; enum Direction { @@ -16,6 +18,7 @@ enum Direction top = 8 } +const DEG90 = TMath.radToDeg(Math.PI / 2);//90° export class Command_FastDimBrs implements Command { async exec() @@ -30,6 +33,21 @@ export class Command_FastDimBrs implements Command let brs = enRes.SelectSet.SelectEntityList as Board[]; + //排除旋转角度非90度倍数的板件 + brs = brs.filter(b => ( + equaln((TMath.radToDeg(b.Rotation.x) + 90) % (DEG90), 0) + && equaln((TMath.radToDeg(b.Rotation.y) + 90) % (DEG90), 0) + && equaln((TMath.radToDeg(b.Rotation.z) + 90) % (DEG90), 0) + )) + + if (brs.length === 0) + { + app.Editor.Prompt(`可标注板件数: 0, 已退出`); + return; + } + + app.Editor.Prompt(`可标注板件数: ${brs.length}`); + let autoDim = new Command_AutoDimBrs(); let ucs = app.Editor.UCSMatrix; diff --git a/src/Geometry/OBB/obb.ts b/src/Geometry/OBB/obb.ts index 9f3a6a722..7034222a9 100644 --- a/src/Geometry/OBB/obb.ts +++ b/src/Geometry/OBB/obb.ts @@ -220,13 +220,13 @@ export class OBB // intersectsAABB(box: THREE.Box3): boolean // intersectsSphere(sphere: THREE.Sphere): boolean // intersectsOBB(box: OBB): boolean; - // intersectsPlane(plane: THREE.Plane): boolean - // intersectsRay(ray: THREE.Ray): boolean - // intersectRay(ray: THREE.Ray): THREE.Vector3 - // intersectSphere(sphere: THREE.Sphere): THREE.Vector3 - // size(optionalTarget: THREE.Vector3): THREE.Vector3 + // intersectsPlane(plane: Plane): boolean + // intersectsRay(ray: Ray): boolean + // intersectRay(ray: Ray): Vector3 + // intersectSphere(sphere: Sphere): Vector3 + // size(optionalTarget: Vector3): Vector3 - // translate(offset: THREE.Vector3): OBB + // translate(offset: Vector3): OBB // copy(obb: OBB): OBB // clone(obb: OBB): OBB diff --git a/src/UI/Components/TopToolBar/TopToolBar.tsx b/src/UI/Components/TopToolBar/TopToolBar.tsx index d225504e3..c53823a2d 100644 --- a/src/UI/Components/TopToolBar/TopToolBar.tsx +++ b/src/UI/Components/TopToolBar/TopToolBar.tsx @@ -82,8 +82,8 @@ export class TopToolBar extends React.Component<{}, {}> { svg: IconEnum.Circle, title: "半径标注", command: "DIMRAD" }, { svg: IconEnum.Diameter, title: "直径标注", command: "DIMDIA" }, { svg: IconEnum.AutoDim, title: "柜体标注", command: "AUTODIMBRS" }, - { svg: IconEnum.FastDim, title: "自由标注", command: "AUTODIMBRS" }, - { svg: IconEnum.DelDim, title: "快速删除", command: "AUTODIMBRS" }, + { svg: IconEnum.FastDim, title: "自由标注", command: "FASTDIMBRS" }, + { svg: IconEnum.DelDim, title: "快速删除", command: "DELETEDIM" }, ] store.iconList.light = [ { svg: IconEnum.SpotLamp, title: "射灯", command: "SL" },