From c98bef1396ac027fb96b1aaacf428cf07912d315 Mon Sep 17 00:00:00 2001 From: ZoeLeeFZ Date: Thu, 4 Jun 2020 10:02:13 +0800 Subject: [PATCH] =?UTF-8?q?!1081=20=E4=BC=98=E5=8C=96:=E5=B9=B2=E6=B6=89?= =?UTF-8?q?=E6=A3=80=E6=9F=A5=E5=BF=BD=E7=95=A5=E6=A0=BC=E5=AD=90=E6=8A=BD?= =?UTF-8?q?=E5=92=8C=E9=85=92=E6=A0=BC,=E5=A2=9E=E5=8A=A0=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __test__/Interfere/interfere.test.ts | 27 +++++ src/Add-on/interfere.ts | 142 +----------------------- src/Common/InterfereUtil.ts | 160 +++++++++++++++++++++++++++ 3 files changed, 192 insertions(+), 137 deletions(-) create mode 100644 __test__/Interfere/interfere.test.ts create mode 100644 src/Common/InterfereUtil.ts diff --git a/__test__/Interfere/interfere.test.ts b/__test__/Interfere/interfere.test.ts new file mode 100644 index 000000000..abcd4956b --- /dev/null +++ b/__test__/Interfere/interfere.test.ts @@ -0,0 +1,27 @@ +import { LoadEntityFromFileData } from "../Utils/LoadEntity.util"; +import { Solid3D, checkInterfereTool } from "../../src/Common/InterfereUtil"; + +function Check(data: any[], count: number) +{ + let boards = LoadEntityFromFileData(data) as Solid3D[]; + checkInterfereTool.Check(boards); + expect(checkInterfereTool.objMap.size).toBe(count); +} + + +describe("干涉测试", () => +{ + test("切割板件", () => + { + let data = + [2, "Board", 8, 2, 100, false, 1, 11, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, -2231.9185171823483, -4422.281844206504, 0, 1], 0, 0, true, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -2231.9185171823483, -4422.281844206504, 0, 1], 0, 3, 2000, 600, 18, true, "Polyline", 8, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, true, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 2, 4, [0, 0], 0, [600, 0], 0, [600, 2000], 0, [0, 2000], 0, true, 4, 3, 18, 600, 9, true, "Polyline", 8, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, true, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 2, 4, [0, 0], 0, [600, 0], 0, [600, 18], 0, [0, 18], 0, true, 0, 3, 0, 0, 0, 0, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, -2222.9185171823483, -4422.281844206504, 486.5, 1], 3, 18, 600, 6, true, "Polyline", 8, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, true, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 2, 4, [0, 0], 0, [600, 0], 0, [600, 18], 0, [0, 18], 0, true, 0, 3, 0, 0, 0, 0, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, -2219.9185171823483, -4422.281844206504, 991, 1], 3, 1780.0698549677409, 18.000000000000455, 10, true, "Polyline", 8, 2, 0, false, 0, 1, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -500.6580645161275, -219.93014503225913, 0, 1], 0, 0, true, [-1.8369701987210297e-16, -1, 0, 0, 1, -1.8369701987210297e-16, 0, 0, 0, 0, 1, 0, 2789.204261929938, 4347.811790451612, 0, 1], 0, 2, 4, [500.658064516128, 2000], 0, [500.6580645161275, 219.93014503225913], 0, [518.6580645161275, 219.93014503225913], 0, [518.658064516128, 2000], 0, true, 0, 3, 0, 0, 0, 0, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, -2223.9185171823483, -3921.623779690376, 219.93014503225913, 1], 3, 18, 600, 9, true, "Polyline", 8, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, true, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 2, 4, [0, 0], 0, [600, 0], 0, [600, 18], 0, [0, 18], 0, true, 0, 3, 0, 0, 0, 0, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, -2222.9185171823483, -4422.281844206504, 50, 1], 3, 0, 0, 0, 0, 0, 9, 1, "左侧板", "主卧", "下柜", "", "", "", 0, 0, "三合一", 2, 0, "1", "1", "1", "1", "", "", "", 4, "三合一", "三合一", "三合一", "三合一", true, true, 0, 0, 0, 0, 0, 0, 0, 0, true, "Board", 8, 2, 103, false, 1, 2, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, -1049.9185171823483, -4422.281844206504, 486.5, 1], 0, 0, true, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1049.9185171823483, -4422.281844206504, 486.5, 1], 0, 3, 1173, 600, 18, true, "Polyline", 8, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, true, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 2, 4, [0, 0], 0, [600, 0], 0, [600, 1173], 0, [0, 1173], 0, true, 0, 3, 0, 0, 0, 0, 0, 9, 0, "层板", "主卧", "下柜", "", "", "", 0, 1, "三合一", 2, 0, "1", "1", "1", "1", "", "", "", 4, "三合一", "三合一", "三合一", "三合一", true, true, 0, 1, 101, 2, 3, 112, 113, 114, 3, 115, 116, 117, 0, 0, 0, 0, 0, 0, true]; + + Check(data, 0); + + data = [2, "Board", 8, 2, 101, false, 1, 11, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, -1049.9185171823483, -4422.281844206504, 0, 1], 0, 0, true, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1049.9185171823483, -4422.281844206504, 0, 1], 0, 3, 2000, 600, 18, true, "Polyline", 8, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, true, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 2, 4, [0, 0], 0, [600, 0], 0, [600, 2000], 0, [0, 2000], 0, true, 1, 3, 1780.0698549677409, 18.000000000000455, 10, true, "Polyline", 8, 2, 0, false, 0, 1, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -500.6580645161275, -219.93014503225913, 0, 1], 0, 0, true, [-1.8369701987210297e-16, -1, 0, 0, 1, -1.8369701987210297e-16, 0, 0, 0, 0, 1, 0, 2789.2042619299355, 4347.811790451612, 0, 1], 0, 2, 4, [500.658064516128, 2000], 0, [500.6580645161275, 219.93014503225913], 0, [518.6580645161275, 219.93014503225913], 0, [518.658064516128, 2000], 0, true, 0, 3, 0, 0, 0, 0, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, -1041.9185171823483, -3921.623779690376, 219.93014503225913, 1], 3, 0, 0, 0, 0, 0, 9, 1, "右侧板", "主卧", "下柜", "", "", "", 0, 0, "三合一", 2, 0, "1", "1", "1", "1", "", "", "", 4, "三合一", "三合一", "三合一", "三合一", true, true, 0, 2, 102, 2, 3, 104, 105, 106, 3, 107, 108, 109, 103, 2, 3, 112, 113, 114, 3, 115, 116, 117, 0, 0, 0, 0, 0, 0, true, "Board", 8, 2, 103, false, 1, 2, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, -606.3306739002, -4422.281844206504, 486.5, 1], 0, 0, true, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1049.9185171823483, -4422.281844206504, 486.5, 1], 0, 3, 1616.5878432821482, 600, 18, true, "Polyline", 8, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 443.58784328214824, 0, 1], 0, 0, true, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 443.58784328214824, 0, 1], 0, 2, 4, [0, -443.58784328214824], 0, [600, -443.58784328214824], 0, [600, 1173], 0, [0, 1173], 0, true, 0, 3, 0, 0, 0, 0, 0, 9, 0, "层板", "主卧", "下柜", "", "", "", 0, 1, "三合一", 2, 0, "1", "1", "1", "1", "", "", "", 4, "三合一", "三合一", "三合一", "三合一", true, true, 0, 1, 101, 2, 3, 112, 113, 114, 3, 115, 116, 117, 0, 0, 0, 0, 0, 0, true]; + Check(data, 1); + + data = [2, "Board", 8, 2, 15731, false, 1, 12, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, -17103.964135848066, 173.0236442641158, 3142.826736584199, 1], 0, 0, true, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -17103.964135848066, -20, 3142.826736584199, 1], 0, 3, 1182, 136.9763557358842, 18, true, "Polyline", 8, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -193.0236442641158, 0, 0, 1], 0, 0, true, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -193.0236442641158, 0, 0, 1], 0, 2, 4, [193.0236442641158, 0], 0, [330, 0], 0, [330, 1182], 0, [193.0236442641158, 1182], 0, true, 0, 3, 0, 0, 0, 0, 0, 9, 1, "右侧板", "鞋柜", "鞋柜左柜", "", "", "", 0, 1, "三合一", 2, 0, "1", "1", "1", "1", "", "", "", 4, "三合一", "三合一", "三合一", "三合一", true, true, 0, 0, 0, 0, 0, 0, 0, 0, true, "Board", 8, 2, 15732, false, 1, 5, 0, [1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, -17256.775064763995, 283, 3142.119629803012, 1], 0, 0, true, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -18267.25702906688, 274.6553453088989, 3142.119629803012, 1], 0, 3, 59.99999365700023, 153.5180356971141, 18, true, "Polyline", 8, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1010.4819643028859, 0, 0, 1], 0, 0, true, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1010.4819643028859, 0, 0, 1], 0, 2, 4, [1010.4819643028859, 0], 0, [1164, 0], 0, [1164, 59.99999365700023], 0, [1010.4819643028859, 59.99999365700023], 0, true, 0, 3, 0, 0, 0, 0, 0, 9, 2, "地脚线", "鞋柜", "鞋柜左柜", "", "", "", 1, 0, "地脚线三合一", 2, 0, "1", "1", "1", "1", "", "", "", 4, "地脚线三合一", "地脚线三合一", "地脚线三合一", "地脚线三合一", true, true, 0, 0, 0, 0, 0, 0, 0, 0, true]; + Check(data, 1); + }); +}); diff --git a/src/Add-on/interfere.ts b/src/Add-on/interfere.ts index ff0bdd4dd..724d9c916 100644 --- a/src/Add-on/interfere.ts +++ b/src/Add-on/interfere.ts @@ -1,27 +1,19 @@ import { Intent } from '@blueprintjs/core'; -import { Face3, Geometry, Mesh, Vector3 } from 'three'; import { app } from '../ApplicationServices/Application'; import { DisposeThreeObj } from '../Common/Dispose'; -import { FixedNotZero } from '../Common/Utils'; -import { Entity } from '../DatabaseServices/Entity/Entity'; import { ExtrudeSolid } from '../DatabaseServices/Entity/Extrude'; import { PromptStatus } from '../Editor/PromptResult'; import { userConfig } from '../Editor/UserConfig'; -import { Box3Ext } from '../Geometry/Box'; -import { equalv3 } from '../Geometry/GeUtils'; -import { RenderType } from '../GraphicsSystem/RenderType'; import { InterfereModal } from '../UI/Components/Modal/InterfereModal'; -import { ColorMaterial } from './../Common/ColorPalette'; -import { CSG } from './../csg/core/CSG'; -import { Geometry2CSG, Vector3DToVector3 } from './../csg/core/Geometry2CSG'; import { ExtrudeHole } from './../DatabaseServices/3DSolid/ExtrudeHole'; import { SweepSolid } from './../DatabaseServices/3DSolid/SweepSolid'; import { Command } from './../Editor/CommandMachine'; import { AppToaster } from './../UI/Components/Toaster'; +import { checkInterfereTool, Solid3D } from '../Common/InterfereUtil'; +import { RenderType } from '../GraphicsSystem/RenderType'; //| CylinderHole | ExtrudeHole -export type Solid3D = ExtrudeSolid | SweepSolid | ExtrudeHole; export class Interfere implements Command { @@ -39,122 +31,9 @@ export class Interfere implements Command if (enRes.Status === PromptStatus.Cancel) return; let ens = enRes.SelectSet.SelectEntityList as Solid3D[]; - let set1 = new Set(); - let objMap: Map = new Map(); - const csgCache: WeakMap = new WeakMap(); - - for (let i = 0; i < ens.length; i++) - { - let e1 = ens[i]; - - let c1: CSG; - if (csgCache.has(e1)) - c1 = csgCache.get(e1); - else - c1 = this.GetCSG(e1); - - let obb1 = e1.OBB; - - for (let j = i + 1; j < ens.length; j++) - { - let e2 = ens[j]; - if (!obb1.intersectsOBB(e2.OBB)) - continue; - - let c2: CSG; - if (csgCache.has(e2)) - c2 = csgCache.get(e2); - else - { - c2 = this.GetCSG(e2); - csgCache.set(e2, c2); - } - - if (!c2) - console.error("实体CSG出错"); - - let c = c1.intersect(c2.transform1(e1.OCSInv.multiply(e2.OCS))); - - if (c.polygons.length > 0) - { - set1.add(e1); - set1.add(e2); - - let ptsMap = new Map(); - let geo = new Geometry; - - for (let poly of c.polygons) - { - let normal = Vector3DToVector3(poly.plane.normal); - if (equalv3(normal, new Vector3())) continue; - let p0 = Vector3DToVector3(poly.vertices[0].pos); - if (poly.vertices.some((v, i) => - { - if (i === 0) - return false; - let p1 = Vector3DToVector3(v.pos); - return equalv3(p0, p1, 1e-2); - })) - continue; + checkInterfereTool.Check(ens); + let objMap = checkInterfereTool.objMap; - let k = `${FixedNotZero(normal.x, 2)},${FixedNotZero(normal.y, 2)},${FixedNotZero(normal.z, 2)}`; - let k2 = `${FixedNotZero(-normal.x, 2)},${FixedNotZero(-normal.y, 2)},${FixedNotZero(-normal.z, 2)}`; - let pts = ptsMap.get(k); - if (!pts) - pts = ptsMap.get(k2); - - if (!pts) - { - pts = []; - ptsMap.set(k, pts); - } - pts.push(...poly.vertices.map(v => Vector3DToVector3(v.pos))); - - for (let v of poly.vertices) - { - v.tag = geo.vertices.length; - geo.vertices.push(Vector3DToVector3(v.pos)); - } - - let firstVertex = poly.vertices[0]; - - for (let i = poly.vertices.length - 3; i >= 0; i--) - { - let [a, b, c] = [ - firstVertex.tag, - poly.vertices[i + 1].tag, - poly.vertices[i + 2].tag - ]; - let f = new Face3(a, b, c, normal); - - geo.faces.push(f); - } - } - let hasSolid = false; - let count = 0; - for (let [k, pts] of ptsMap) - { - let box = new Box3Ext().setFromPoints(pts); - if (box.isSolid(1e-3)) - { - count++; - hasSolid = true; - ptsMap.delete(k); - } - } - if (hasSolid) - { - //围不出一个实体的情况 - if (ptsMap.size === 1) continue; - if (ptsMap.size === 0 && count <= 2) continue; - - geo.applyMatrix4(e1.OCS); - let m = new Mesh(geo, ColorMaterial.GetBasicMaterial(1).clone()); - objMap.set(m, [e1, e2]); - } - } - } - } if (objMap.size === 0) { AppToaster.show({ @@ -172,7 +51,7 @@ export class Interfere implements Command let oldType = userConfig.RenderType; userConfig.RenderType = RenderType.Wireframe; - app.Editor.ModalManage.RenderModeless(InterfereModal, { count: set1.size, data: objMap }, { canMinimize: false }); + app.Editor.ModalManage.RenderModeless(InterfereModal, { count: checkInterfereTool.entitySet.size, data: objMap }, { canMinimize: false }); await app.Editor.ModalManage.Wait(); @@ -184,15 +63,4 @@ export class Interfere implements Command userConfig.RenderType = oldType; } - private GetCSG(en: Solid3D) - { - if (en instanceof ExtrudeSolid) - { - return en.CSG; - } - else - { - return Geometry2CSG(en.MeshGeometry); - } - } } diff --git a/src/Common/InterfereUtil.ts b/src/Common/InterfereUtil.ts new file mode 100644 index 000000000..e5043bd4d --- /dev/null +++ b/src/Common/InterfereUtil.ts @@ -0,0 +1,160 @@ +import { Mesh, Vector3, Geometry, Face3 } from "three"; +import { ExtrudeSolid } from "../DatabaseServices/Entity/Extrude"; +import { SweepSolid } from "../DatabaseServices/3DSolid/SweepSolid"; +import { ExtrudeHole } from "../DatabaseServices/3DSolid/ExtrudeHole"; +import { Entity } from "../DatabaseServices/Entity/Entity"; +import { CSG } from "../csg/core/CSG"; +import { Geometry2CSG, Vector3DToVector3 } from "../csg/core/Geometry2CSG"; +import { equalv3 } from "../Geometry/GeUtils"; +import { FixedNotZero } from "./Utils"; +import { Box3Ext } from "../Geometry/Box"; +import { ColorMaterial } from "./ColorPalette"; +import { TemplateWineRackRecord } from "../DatabaseServices/Template/ProgramTempate/TemplateWineRackRecord"; +import { TemplateLatticeRecord } from "../DatabaseServices/Template/ProgramTempate/TemplateLatticeRecord"; + +export type Solid3D = ExtrudeSolid | SweepSolid | ExtrudeHole; + +export class CheckInterfereTool +{ + entitySet: Set = new Set(); + objMap: Map = new Map(); + Check(ens: Solid3D[]) + { + let entitySet = this.entitySet; + let objMap = this.objMap; + entitySet.clear(); + objMap.clear(); + + const csgCache: WeakMap = new WeakMap(); + + for (let i = 0; i < ens.length; i++) + { + let e1 = ens[i]; + if (e1.Template && (e1.Template.Object instanceof TemplateWineRackRecord || e1.Template.Object instanceof TemplateLatticeRecord)) + continue; + let c1: CSG; + if (csgCache.has(e1)) + c1 = csgCache.get(e1); + else + c1 = this.GetCSG(e1); + + let obb1 = e1.OBB; + + for (let j = i + 1; j < ens.length; j++) + { + let e2 = ens[j]; + if (e2.Template && (e2.Template.Object instanceof TemplateWineRackRecord || e2.Template.Object instanceof TemplateLatticeRecord)) + continue; + if (!obb1.intersectsOBB(e2.OBB)) + continue; + + let c2: CSG; + if (csgCache.has(e2)) + c2 = csgCache.get(e2); + else + { + c2 = this.GetCSG(e2); + csgCache.set(e2, c2); + } + + if (!c2) + console.error("实体CSG出错"); + + let c = c1.intersect(c2.transform1(e1.OCSInv.multiply(e2.OCS))); + + if (c.polygons.length > 0) + { + entitySet.add(e1); + entitySet.add(e2); + + let ptsMap = new Map(); + let geo = new Geometry; + + for (let poly of c.polygons) + { + let normal = Vector3DToVector3(poly.plane.normal); + if (equalv3(normal, new Vector3())) continue; + let p0 = Vector3DToVector3(poly.vertices[0].pos); + if (poly.vertices.some((v, i) => + { + if (i === 0) + return false; + let p1 = Vector3DToVector3(v.pos); + return equalv3(p0, p1, 1e-2); + })) + continue; + + let k = `${FixedNotZero(normal.x, 2)},${FixedNotZero(normal.y, 2)},${FixedNotZero(normal.z, 2)}`; + let k2 = `${FixedNotZero(-normal.x, 2)},${FixedNotZero(-normal.y, 2)},${FixedNotZero(-normal.z, 2)}`; + let pts = ptsMap.get(k); + if (!pts) + pts = ptsMap.get(k2); + + if (!pts) + { + pts = []; + ptsMap.set(k, pts); + } + pts.push(...poly.vertices.map(v => Vector3DToVector3(v.pos))); + + for (let v of poly.vertices) + { + v.tag = geo.vertices.length; + geo.vertices.push(Vector3DToVector3(v.pos)); + } + + let firstVertex = poly.vertices[0]; + + for (let i = poly.vertices.length - 3; i >= 0; i--) + { + let [a, b, c] = [ + firstVertex.tag, + poly.vertices[i + 1].tag, + poly.vertices[i + 2].tag + ]; + let f = new Face3(a, b, c, normal); + + geo.faces.push(f); + } + } + let hasSolid = false; + let count = 0; + for (let [k, pts] of ptsMap) + { + let box = new Box3Ext().setFromPoints(pts); + if (box.isSolid(1e-3)) + { + count++; + hasSolid = true; + ptsMap.delete(k); + } + } + if (hasSolid) + { + //围不出一个实体的情况 + if (ptsMap.size === 1) continue; + if (ptsMap.size === 0 && count <= 2) continue; + + geo.applyMatrix4(e1.OCS); + let m = new Mesh(geo, ColorMaterial.GetBasicMaterial(1).clone()); + objMap.set(m, [e1, e2]); + } + } + } + } + return objMap; + } + private GetCSG(en: Solid3D) + { + if (en instanceof ExtrudeSolid) + { + return en.CSG; + } + else + { + return Geometry2CSG(en.MeshGeometry); + } + } +} + +export const checkInterfereTool = new CheckInterfereTool();