From 67ceed6e54095c396215d8f79921dc39fd259571 Mon Sep 17 00:00:00 2001 From: ChenX Date: Thu, 9 May 2019 01:11:45 +0800 Subject: [PATCH] =?UTF-8?q?fix=20#IWC0A=20=E6=96=B0=E5=A2=9E`FromCSG`?= =?UTF-8?q?=E8=A7=A3=E5=86=B3EdgeGeometry=E4=B8=A2=E7=BA=BF=E5=92=8C?= =?UTF-8?q?=E6=80=A7=E8=83=BD=E5=B7=AE=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __test__/Geometry/EdgeGeometry.test.ts | 25 ++-- .../__snapshots__/EdgeGeometry.test.ts.snap | 7 + src/DatabaseServices/3DSolid/GangDrill.ts | 2 +- src/DatabaseServices/3DSolid/SweepSolid.ts | 2 +- src/DatabaseServices/Extrude.ts | 2 +- src/Geometry/EdgeGeometry.ts | 141 +++++++++++++++++- src/csg/core/math/Vertex3.ts | 5 + 7 files changed, 163 insertions(+), 21 deletions(-) create mode 100644 __test__/Geometry/__snapshots__/EdgeGeometry.test.ts.snap diff --git a/__test__/Geometry/EdgeGeometry.test.ts b/__test__/Geometry/EdgeGeometry.test.ts index 005e303c6..c1f381878 100644 --- a/__test__/Geometry/EdgeGeometry.test.ts +++ b/__test__/Geometry/EdgeGeometry.test.ts @@ -1,21 +1,16 @@ -import { LoadEntityFromFileData } from "../Utils/LoadEntity.util"; -import { Board } from "../../src/DatabaseServices/Board"; -import { RenderType } from "../../src/GraphicsSystem/RenderType"; import { Line } from "three"; +import { RenderType } from "../../src/GraphicsSystem/RenderType"; +import { LoadBoardsFromFileData } from "../Utils/LoadEntity.util"; test('EdgeGeometry生成', () => { - let d = [1, "Board", 3, 2, 101, false, 1, 2, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, -646.2420911908739, 230.97217145381728, -423.9845986472139, 1], 2, 484.63826594239083, 642.7439363026181, 18, false, "Polyline", 3, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 54.03714224287984, -40.88462318428341, 0, 1], 2, 6, [226.89796571085776, 338.3121692475904], 0, [248.97426264670497, 525.5228891266743], 0, [-54.03714224287984, 287.9783168893773], 0, [141.82369879876416, 40.88462318428341], 0, [588.7067940597382, 306.7620304373949], 0, [320.72013691164284, 378.99785818408446], 0, true, 1, 2, 109.48289947281157, 198.20905225226585, 18, false, "Polyline", 3, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -208.29382686305865, -201.59010496470867, 0, 1], 2, 4, [298.05328308824403, 206.16728215262995], 0, [208.29382686305865, 201.59010496470867], 0, [267.90926007565713, 311.07300443752024], 0, [406.5028791153245, 272.1962944735834], 0, true, 0, 3, 0, 0, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, -646.2420911908739, 493.3031405597556, -263.2791168667886, 1], 3, 0, 0, 0, 2, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -314.3564875158372, 4019.556363898919, -46.81305616698228, 1], 1, "右侧板", "{\"roomName\":\"\",\"cabinetName\":\"\",\"boardName\":\"\",\"material\":\"\",\"color\":\"\",\"lines\":0,\"bigHoleDir\":0,\"drillType\":\"three\",\"composingFace\":2,\"highSealed\":[],\"sealedUp\":\"1\",\"sealedDown\":\"1\",\"sealedLeft\":\"1\",\"sealedRight\":\"1\",\"spliteHeight\":\"\",\"spliteWidth\":\"\",\"spliteThickness\":\"\"}", 0, 0]; - - let br: Board = LoadEntityFromFileData(d)[0] as Board; - - - let obj = br.GetDrawObjectFromRenderType(RenderType.Wireframe); - - let line = obj as Line; - - let geo = line.geometry; + let d = [3, "Board", 3, 2, 101, false, 1, 11, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 842.2974778978387, -349.77794462809106, 5.207248635008, 1], 2, 1200, 1287.9139521874604, 18, true, "Polyline", 3, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 4, [0, 0], 0, [1287.9139521874604, 0], 0, [1287.9139521874604, 1200], 0, [0, 1200], 0, true, 1, 2, 650.3947318524762, 368.7144637049523, 18, false, "Polyline", 3, 2, 0, false, 0, 1, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1827.9668979500452, -289.76232632197764, 0, 1], 2, 4, [1827.9668979500452, 755.7998263219777], 0, [1827.9668979500452, 289.76232632197764], 0, [2196.6813616549975, 289.76232632197764], 0, [2196.6813616549975, 755.7998263219777], 0.9999999999999999, true, 0, 3, 0, 0, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 842.2974778978387, -132.52737566129053, 492.2690189409713, 1], 3, 0, 0, 0, 2, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -331.4882673815591, 22.964750159997493, 5.207248635008, 1], 1, "左侧板", "{\"roomName\":\"\",\"cabinetName\":\"\",\"boardName\":\"\",\"material\":\"\",\"color\":\"\",\"lines\":0,\"bigHoleDir\":0,\"drillType\":\"three\",\"composingFace\":2,\"highSealed\":[],\"sealedUp\":\"1\",\"sealedDown\":\"1\",\"sealedLeft\":\"1\",\"sealedRight\":\"1\",\"spliteHeight\":\"\",\"spliteWidth\":\"\",\"spliteThickness\":\"\",\"highDrill\":[\"three\",\"three\",\"three\",\"three\",\"three\",\"three\"]}", 0, 0, "Board", 3, 2, 211, false, 1, 2, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1743.9852053204086, 1058.889397823259, -54.29958601640169, 1], 2, 1230.761278665225, 896.6684244728249, 18, false, "Polyline", 3, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.684341886080802e-14, 30.761278665225063, 0, 1], 2, 6, [0, 0], 0, [300, 0], 1.44245572325029, [315.9503077287227, 816.1221829065471], 0, [600, 1200], 0, [300, 1200], 0.41421356237309503, [0, 900], 0, true, 1, 2, 385.96920000000006, 177.84615384615404, 10, false, "Polyline", 3, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -422.15384615384596, -402.0513128205126, 0, 1], 2, 5, [597.7122651988514, 788.0205128205126], 0, [422.15384615384596, 788.0205128205126], 0, [422.15384615384596, 402.05131282051263], 0, [600, 402.0513128205126], 0, [599.9999999999998, 786.9320348416215], 0.0014989901540299988, true, 0, 3, 0, 0, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1751.9852053204086, 1481.043243977105, 378.51300546933595, 1], 3, 0, 0, 0, 2, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -17.633213176275603, 262.61914493865333, 0, 1], 1, "右侧板", "{\"roomName\":\"\",\"cabinetName\":\"\",\"boardName\":\"\",\"material\":\"\",\"color\":\"\",\"lines\":0,\"bigHoleDir\":0,\"drillType\":\"three\",\"composingFace\":2,\"highSealed\":[],\"sealedUp\":\"1\",\"sealedDown\":\"1\",\"sealedLeft\":\"1\",\"sealedRight\":\"1\",\"spliteHeight\":\"\",\"spliteWidth\":\"\",\"spliteThickness\":\"\",\"highDrill\":[]}", 0, 0, "Board", 3, 2, 212, false, 1, 2, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1111.9162051636208, 2117.9319139518834, -423.9845986472139, 1], 2, 484.63826594239083, 642.7439363026181, 18, false, "Polyline", 3, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 54.03714224287984, -40.88462318428341, 0, 1], 2, 6, [226.89796571085776, 338.3121692475904], 0, [248.97426264670497, 525.5228891266743], 0, [-54.03714224287984, 287.9783168893773], 0, [141.82369879876416, 40.88462318428341], 0, [588.7067940597382, 306.7620304373949], 0, [320.72013691164284, 378.99785818408446], 0, true, 1, 2, 63.40599363597872, 232.13273756151398, 18, false, "Polyline", 3, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -58.35238007400439, -234.55749771884788, 0, 1], 2, 4, [236.13305395456487, 234.55749771884788], 0, [83.25375055383591, 272.608758187791], 0, [58.35238007400439, 297.9634913548266], 0, [290.48511763551835, 268.97109344254164], 0, true, 0, 3, 0, 0, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1111.9162051636208, 2230.3214362687672, -230.31172411264944, 1], 3, 0, 0, 0, 2, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -776.2476068199197, 3557.665244594688, -46.81305616698228, 1], 1, "右侧板", "{\"roomName\":\"\",\"cabinetName\":\"\",\"boardName\":\"\",\"material\":\"\",\"color\":\"\",\"lines\":0,\"bigHoleDir\":0,\"drillType\":\"three\",\"composingFace\":2,\"highSealed\":[],\"sealedUp\":\"1\",\"sealedDown\":\"1\",\"sealedLeft\":\"1\",\"sealedRight\":\"1\",\"spliteHeight\":\"\",\"spliteWidth\":\"\",\"spliteThickness\":\"\",\"highDrill\":[]}", 0, 0] + let brs = LoadBoardsFromFileData(d); - //@ts-ignore - expect(geo.attributes.position.length).toBe(246); + for (let br of brs) + { + let line = br.GetDrawObjectFromRenderType(RenderType.Wireframe) as Line; + //@ts-ignore + expect(line.geometry.attributes.position.length).toMatchSnapshot(); + } }); diff --git a/__test__/Geometry/__snapshots__/EdgeGeometry.test.ts.snap b/__test__/Geometry/__snapshots__/EdgeGeometry.test.ts.snap new file mode 100644 index 000000000..e38535d1e --- /dev/null +++ b/__test__/Geometry/__snapshots__/EdgeGeometry.test.ts.snap @@ -0,0 +1,7 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`EdgeGeometry生成 1`] = `1296`; + +exports[`EdgeGeometry生成 2`] = `2592`; + +exports[`EdgeGeometry生成 3`] = `438`; diff --git a/src/DatabaseServices/3DSolid/GangDrill.ts b/src/DatabaseServices/3DSolid/GangDrill.ts index d69d010a4..a956d3095 100644 --- a/src/DatabaseServices/3DSolid/GangDrill.ts +++ b/src/DatabaseServices/3DSolid/GangDrill.ts @@ -87,7 +87,7 @@ export class GangDrill extends Solid3D { if (renderType === RenderType.Wireframe) { - return new LineSegments(new EdgesGeometry(this.CreateGeometry(), 2), ColorMaterial.GetLineMaterial(this.ColorIndex)); + return new LineSegments(new EdgesGeometry().FromGeometry(this.CreateGeometry(), 2), ColorMaterial.GetLineMaterial(this.ColorIndex)); } else return new THREE.Mesh(this.CreateGeometry(), new MeshNormalMaterial()); diff --git a/src/DatabaseServices/3DSolid/SweepSolid.ts b/src/DatabaseServices/3DSolid/SweepSolid.ts index 740e677c1..1e8c188a0 100644 --- a/src/DatabaseServices/3DSolid/SweepSolid.ts +++ b/src/DatabaseServices/3DSolid/SweepSolid.ts @@ -111,7 +111,7 @@ export class SweepSolid extends Solid3D { if (renderType === RenderType.Wireframe) { - let geo = new EdgesGeometry(this.CreateGeomtry()); + let geo = new EdgesGeometry().fromGeometry(this.CreateGeomtry()); return new LineSegments(geo, ColorMaterial.GetLineMaterial(this.ColorIndex)); } else diff --git a/src/DatabaseServices/Extrude.ts b/src/DatabaseServices/Extrude.ts index be816770f..3114d741b 100644 --- a/src/DatabaseServices/Extrude.ts +++ b/src/DatabaseServices/Extrude.ts @@ -1002,7 +1002,7 @@ export class ExtureSolid extends Entity if (this._EdgeGeometry) return this._EdgeGeometry; - this._EdgeGeometry = new EdgesGeometry(this.MeshGeometry); + this._EdgeGeometry = new EdgesGeometry().FromCSG(this.CSG); return this._EdgeGeometry; } diff --git a/src/Geometry/EdgeGeometry.ts b/src/Geometry/EdgeGeometry.ts index f29ebd6f4..736a5f13f 100644 --- a/src/Geometry/EdgeGeometry.ts +++ b/src/Geometry/EdgeGeometry.ts @@ -1,5 +1,10 @@ -import { BufferGeometry, Face3, Float32BufferAttribute, Geometry, Line3, Triangle, Vector3 } from "three"; +import { Box3, BufferGeometry, Face3, Float32BufferAttribute, Geometry, Line3, Triangle, Vector3 } from "three"; import { arraySortByNumber } from "../Common/ArrayExt"; +import { FixIndex } from "../Common/Utils"; +import { CSG } from "../csg/core/CSG"; +import { FuzzyCSGFactory } from "../csg/core/FuzzyFactory3d"; +import { Polygon } from "../csg/core/math/Polygon3"; +import { Vector3D } from "../csg/core/math/Vector3"; import { equalv3 } from "./GeUtils"; //ref: https://github.com/mrdoob/js/issues/10517 @@ -7,9 +12,11 @@ const keys = ['a', 'b', 'c']; export class EdgesGeometry extends BufferGeometry { - constructor(geometry, thresholdAngle: number = 1) + /** + * 在使用Extrude实体的时候,有可能导致面无限分裂,并且有可能造成丢线问题,使用FromCSG方法可解. + */ + FromGeometry(geometry, thresholdAngle: number = 1) { - super(); let geometry2: Geometry; if (geometry.isBufferGeometry) @@ -114,6 +121,134 @@ export class EdgesGeometry extends BufferGeometry } } this.addAttribute('position', new Float32BufferAttribute(coords, 3)); + + return this; + } + + /** + * 解决原来算法性能低下并且结果不理想的问题 + */ + FromCSG(csg: CSG) + { + let fuzzyfactory = new FuzzyCSGFactory(); + + let polygonsPerPlane: { [key: number]: Polygon[] } = {}; + + for (let polygon of csg.polygons) + { + let plane = polygon.plane; + plane = fuzzyfactory.getPlane(plane); + let tag = plane.getTag(); + if (!(tag in polygonsPerPlane)) polygonsPerPlane[tag] = [polygon]; + else polygonsPerPlane[tag].push(polygon); + } + + let coords: number[] = []; + + for (let key in polygonsPerPlane) + { + this.PolygonsOutline(polygonsPerPlane[key], coords); + } + this.addAttribute('position', new Float32BufferAttribute(coords, 3)); + return this; + } + + PolygonsOutline(polygons: Polygon[], coords: number[]) + { + let pts: Vector3[] = []; + let fp = new FuzzPoint(); + let record: { [key: string]: { p1: Vector3, p2: Vector3, count: number } } = {}; + + for (let polygon of polygons) + { + for (let i = 0, count = polygon.vertices.length; i < count; i++) + { + let p = polygon.vertices[i]; + let np = fp.GetVector(p.pos); + p.pos = np; + if (!("_added_" in np)) + { + np["_added_"] = pts.length; + pts.push(np); + } + } + } + + for (let polygon of polygons) + { + for (let i = 0, count = polygon.vertices.length; i < count; i++) + { + let p1 = polygon.vertices[i].pos as Vector3; + let p2 = polygon.vertices[FixIndex(i + 1, count)].pos; + + let delta = p2.clone().sub(p1); + let lengthSq = delta.dot(delta); + + let splitPts: { param: number, pt: Vector3 }[] = []; + + let box = new Box3().setFromPoints([p1, p2]).expandByVector(new Vector3(1, 1, 1)); + + for (let p of pts) + { + if (p === p1 || p === p2) continue; + + if (!box.containsPoint(p)) continue; + + let delta2 = p.clone().sub(p1); + let len2 = delta2.dot(delta); + + let t = len2 / lengthSq; + + if (t > 0 && t < 1) + { + let closestPoint = delta.clone().multiplyScalar(t).add(p1); + if (equalv3(closestPoint, p, 1e-3)) + splitPts.push({ param: t, pt: p }); + } + } + + splitPts.sort((p1, p2) => p1.param - p2.param); + splitPts.push({ param: 1, pt: p2 }); + + let lastP = p1; + + for (let p of splitPts) + { + let tag1 = lastP["_added_"] as number; + let tag2 = p.pt["_added_"] as number; + + let key: string; + if (tag1 < tag2) key = `${tag1},${tag2}`; + else key = `${tag2},${tag1}`; + + if (key in record) + record[key].count++; + else + record[key] = { p1: lastP, p2: p.pt, count: 1 }; + + lastP = p.pt; + } + } + } + + for (let key in record) + { + let d = record[key]; + if (d.count === 1) + coords.push(d.p1.x, d.p1.y, d.p1.z, d.p2.x, d.p2.y, d.p2.z); + } + } +} + +class FuzzPoint +{ + private map: { [key: string]: Vector3D } = {}; + GetVector(v: Vector3D) + { + let key = `${v.x.toFixed(3)},${v.y.toFixed(3)},${v.z.toFixed(3)}`; + if (key in this.map) return this.map[key]; + else this.map[key] = v; + return v; } } diff --git a/src/csg/core/math/Vertex3.ts b/src/csg/core/math/Vertex3.ts index 65f31f574..c8196800f 100644 --- a/src/csg/core/math/Vertex3.ts +++ b/src/csg/core/math/Vertex3.ts @@ -15,6 +15,11 @@ export class Vertex3D tag: number; constructor(public pos: Vector3D, public uv = new Vector2D()) { } + clone() + { + return new Vertex3D(this.pos.clone(), this.uv.clone()); + } + // Return a vertex with all orientation-specific data (e.g. vertex normal) flipped. Called when the // orientation of a polygon is flipped. flipped()