From 89dc6da05e8bfd5d73b151446322ba4bc2a3f3cd Mon Sep 17 00:00:00 2001 From: ChenX Date: Mon, 2 Mar 2020 21:02:49 +0800 Subject: [PATCH] =?UTF-8?q?!745=20=E6=AD=A3=E7=A1=AE=E7=9A=84=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E6=9D=BF=E4=BB=B6=E9=80=A0=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __test__/Geometry/EdgeGeometry.test.ts | 15 + .../__snapshots__/EdgeGeometry.test.ts.snap | 44 +- __test__/Geometry/edgebuilderData.json | 1 + config/webpack.dev.ts | 2 +- src/Add-on/test/TestTape.ts | 122 ++ src/Add-on/testEntity/test.ts | 176 +-- src/DatabaseServices/Entity/Curve.ts | 4 +- src/DatabaseServices/Entity/Extrude.ts | 95 +- src/DatabaseServices/Entity/Polyline.ts | 66 +- src/DatabaseServices/Entity/Region.ts | 6 +- src/DatabaseServices/ShapeManager.ts | 14 + src/Editor/CommandRegister.ts | 4 + src/Geometry/ExtrudeEdgeGeometry2.ts | 1268 +++++++++++++++++ src/Geometry/GenerateExtrudeGeometry.ts | 200 +++ src/GraphicsSystem/OffsetPolyline.ts | 1 + 15 files changed, 1786 insertions(+), 232 deletions(-) create mode 100644 __test__/Geometry/edgebuilderData.json create mode 100644 src/Add-on/test/TestTape.ts create mode 100644 src/Geometry/ExtrudeEdgeGeometry2.ts create mode 100644 src/Geometry/GenerateExtrudeGeometry.ts diff --git a/__test__/Geometry/EdgeGeometry.test.ts b/__test__/Geometry/EdgeGeometry.test.ts index a3d5b10a0..36a87f2a9 100644 --- a/__test__/Geometry/EdgeGeometry.test.ts +++ b/__test__/Geometry/EdgeGeometry.test.ts @@ -1,6 +1,7 @@ import { Line } from "three"; import { RenderType } from "../../src/GraphicsSystem/RenderType"; import { LoadBoardsFromFileData } from "../Utils/LoadEntity.util"; +import { ExtrudeGeometryBuilder } from "../../src/Geometry/ExtrudeEdgeGeometry2"; test('EdgeGeometry生成', () => { @@ -27,3 +28,17 @@ test('EdgeGeometry生成2', () => expect(line.geometry.attributes.position.count).toMatchSnapshot(); } }); + +test('Geometry构建测试', () => +{ + let d = require("./edgebuilderData.json"); + + let brs = LoadBoardsFromFileData(d); + + for (let br of brs) + { + let builder = new ExtrudeGeometryBuilder(br); + expect(builder.verticesArray.length).toMatchSnapshot(); + expect(builder.edgeAndLidBuilder.verticesArray.length).toMatchSnapshot(); + } +}); diff --git a/__test__/Geometry/__snapshots__/EdgeGeometry.test.ts.snap b/__test__/Geometry/__snapshots__/EdgeGeometry.test.ts.snap index abdd62a41..0e397d362 100644 --- a/__test__/Geometry/__snapshots__/EdgeGeometry.test.ts.snap +++ b/__test__/Geometry/__snapshots__/EdgeGeometry.test.ts.snap @@ -2,8 +2,48 @@ exports[`EdgeGeometry生成 1`] = `114`; -exports[`EdgeGeometry生成 2`] = `858`; +exports[`EdgeGeometry生成 2`] = `360`; exports[`EdgeGeometry生成 3`] = `60`; -exports[`EdgeGeometry生成2 1`] = `110`; +exports[`EdgeGeometry生成2 1`] = `80`; + +exports[`Geometry构建测试 1`] = `540`; + +exports[`Geometry构建测试 2`] = `408`; + +exports[`Geometry构建测试 3`] = `378`; + +exports[`Geometry构建测试 4`] = `288`; + +exports[`Geometry构建测试 5`] = `1188`; + +exports[`Geometry构建测试 6`] = `888`; + +exports[`Geometry构建测试 7`] = `774`; + +exports[`Geometry构建测试 8`] = `552`; + +exports[`Geometry构建测试 9`] = `630`; + +exports[`Geometry构建测试 10`] = `456`; + +exports[`Geometry构建测试 11`] = `1548`; + +exports[`Geometry构建测试 12`] = `1056`; + +exports[`Geometry构建测试 13`] = `639`; + +exports[`Geometry构建测试 14`] = `480`; + +exports[`Geometry构建测试 15`] = `1998`; + +exports[`Geometry构建测试 16`] = `1368`; + +exports[`Geometry构建测试 17`] = `1908`; + +exports[`Geometry构建测试 18`] = `1344`; + +exports[`Geometry构建测试 19`] = `2232`; + +exports[`Geometry构建测试 20`] = `1584`; diff --git a/__test__/Geometry/edgebuilderData.json b/__test__/Geometry/edgebuilderData.json new file mode 100644 index 000000000..32ed26f62 --- /dev/null +++ b/__test__/Geometry/edgebuilderData.json @@ -0,0 +1 @@ +{"file":[10,"Board",8,2,100,false,1,2,0,[0,1,0,0,-1,0,0,0,0,0,1,0,1220.6832547056076,-614.1937811916556,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,1220.6832547056076,-614.1937811916556,0,1],0,2,1200,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,1200],0,[0,1200],0,true,3,2,427.9177033492818,285.2784688995216,1,true,"Polyline",8,2,0,false,0,1,0,[1,0,0,0,0,1,0,0,0,0,1,0,-1196.7846889952152,620.5550239234445,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,-1196.7846889952152,620.5550239234445,0,1],0,2,4,[1196.7846889952152,-620.5550239234445],0,[1482.0631578947368,-620.5550239234445],0,[1482.0631578947368,-192.63732057416274],0,[1196.7846889952152,-192.63732057416274],0,true,0,3,0,0,0,[0,1,0,0,-1,0,0,0,0,0,1,0,745.219139873071,-480.0885180337606,17,1],2,213.30051674641152,142.2003444976076,2,true,"Polyline",8,2,0,false,0,2,0,[1,0,0,0,0,1,0,0,0,0,1,0,-1417.6048535885168,773.7568765550237,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,-1417.6048535885168,773.7568765550237,0,1],0,2,4,[1417.6048535885168,-773.7568765550237],0,[1559.8051980861244,-773.7568765550237],0,[1559.8051980861244,-560.4563598086122],0,[1417.6048535885168,-560.4563598086122],0,true,0,3,0,0,0,[0,1,0,0,-1,0,0,0,0,0,1,0,958.5196566194826,-395.3827572682102,16,1],2,91.89818181818191,95.500861244019,3,true,"Polyline",8,2,0,false,0,3,0,[1,0,0,0,0,1,0,0,0,0,1,0,-525.0804394258374,1518.945332057416,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,-525.0804394258374,1518.945332057416,0,1],0,2,4,[525.0804394258374,-1518.945332057416],0,[620.5813006698564,-1518.945332057416],0,[620.5813006698564,-1427.047150239234],0,[525.0804394258374,-1427.047150239234],0,true,0,3,0,0,0,[0,1,0,0,-1,0,0,0,0,0,1,0,600.1466039879047,-290.3109103782584,15,1],3,0,0,0,9,0,"层板","","","","","",0,0,"三合一",2,0,"1","1","1","1","","","",4,"三合一","三合一","三合一","三合一",true,true,0,0,0,0,0,0,0,0,true,"Board",8,2,161,false,1,2,0,[0,1,0,0,-1,0,0,0,0,0,1,0,1232.1409653875162,268.66932986374013,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,1232.1409653875162,268.66932986374013,0,1],0,2,1200,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,1200],0,[0,1200],0,true,2,2,91.89818181818191,95.500861244019,4,true,"Polyline",8,2,0,false,0,2,0,[1,0,0,0,0,1,0,0,0,0,1,0,-525.0804394258374,1518.945332057416,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,-525.0804394258374,1518.945332057416,0,1],0,2,4,[525.0804394258374,-1518.945332057416],0,[620.5813006698564,-1518.945332057416],0,[620.5813006698564,-1427.047150239234],0,[525.0804394258374,-1427.047150239234],0,true,0,3,0,0,0,[0,1,0,0,-1,0,0,0,0,0,1,0,611.6043146698132,592.5522006771374,14,1],2,427.9177033492818,285.2784688995216,2,true,"Polyline",8,2,0,false,0,1,0,[1,0,0,0,0,1,0,0,0,0,1,0,-1196.7846889952152,620.5550239234445,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,-1196.7846889952152,620.5550239234445,0,1],0,2,4,[1196.7846889952152,-620.5550239234445],0,[1482.0631578947368,-620.5550239234445],0,[1482.0631578947368,-192.63732057416274],0,[1196.7846889952152,-192.63732057416274],0,true,0,3,0,0,0,[0,1,0,0,-1,0,0,0,0,0,1,0,756.6768505549795,402.7745930216349,16,1],3,0,0,0,9,0,"层板","","","","","",0,0,"三合一",2,0,"1","1","1","1","","","",4,"三合一","三合一","三合一","三合一",true,true,0,0,0,0,0,0,0,0,true,"Board",8,2,182,false,1,2,0,[0,1,0,0,-1,0,0,0,0,0,1,0,1220.6832547056076,-1913.544673994938,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,1220.6832547056076,-1913.544673994938,0,1],0,2,1200,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,1200],0,[0,1200],0,true,3,2,55.488229665071685,291.60405741626744,3,true,"Polyline",8,2,0,false,0,3,0,[1,0,0,0,0,1,0,0,0,0,1,0,1300.9485400236458,1746.5554078156551,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,1300.9485400236458,1746.5554078156551,0,1],0,2,4,[-1300.9485400236458,-1746.5554078156551],0,[-1009.3444826073784,-1746.5554078156551],0,[-1009.3444826073784,-1691.0671781505835],0,[-1300.9485400236458,-1691.0671781505835],0,true,1,2,23.361485167464252,59.62633492822988,3,true,"Polyline",8,2,0,false,1,3,0,[1,0,0,0,0,1,0,0,0,0,1,0,1166.0839275834542,1728.4229829352726,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,1166.0839275834542,1728.4229829352726,0,1],0,2,4,[-1166.0839275834542,-1728.4229829352726],0,[-1106.4575926552243,-1728.4229829352726],0,[-1106.4575926552243,-1705.0614977678083],0,[-1166.0839275834542,-1705.0614977678083],0,true,0,3,0,0,0,[0,1,0,0,-1,0,0,0,0,0,1,0,501.5808776721158,-1553.7872768657508,15,1],3,0,0,0,[0,1,0,0,-1,0,0,0,0,0,1,0,519.7133025524984,-1688.6518893059424,15,1],2,213.30051674641152,194.11475598086145,1,true,"Polyline",8,2,0,false,0,2,0,[1,0,0,0,0,1,0,0,0,0,1,0,-1365.690442105263,773.7568765550237,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,-1365.690442105263,773.7568765550237,0,1],0,2,4,[1365.690442105263,-773.7568765550237],0,[1559.8051980861244,-773.7568765550237],0,[1559.8051980861244,-560.4563598086122],0,[1365.690442105263,-560.4563598086122],0,true,1,2,117.37171291866025,107.77883253588561,1,true,"Polyline",8,2,0,false,1,2,0,[1,0,0,0,0,1,0,0,0,0,1,0,2825.0451524638374,1503.9637140357506,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,2825.0451524638374,1503.9637140357506,0,1],0,2,4,[-2825.0451524638374,-1503.9637140357506],0,[-2717.266319927952,-1503.9637140357506],0,[-2717.266319927952,-1386.5920011170904],0,[-2825.0451524638374,-1386.5920011170904],0,true,0,3,0,0,0,[0,1,0,0,-1,0,0,0,0,0,1,0,914.0594078156555,-1686.9590280619236,17,1],3,0,0,0,[0,1,0,0,-1,0,0,0,0,0,1,0,958.5196566194826,-1746.6480615547473,17,1],2,479.38625837320643,285.2784688995216,2,true,"Polyline",8,2,0,false,0,1,0,[1,0,0,0,0,1,0,0,0,0,1,0,-1196.7846889952152,672.0235789473692,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,-1196.7846889952152,672.0235789473692,0,1],0,2,4,[1196.7846889952152,-672.0235789473692],0,[1482.0631578947368,-672.0235789473692],0,[1482.0631578947368,-192.63732057416274],0,[1196.7846889952152,-192.63732057416274],0,true,1,2,172.10755980861222,134.86461244019165,2,true,"Polyline",8,2,0,false,1,1,0,[1,0,0,0,0,1,0,0,0,0,1,0,2826.738013707856,1209.4058575764207,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,2826.738013707856,1209.4058575764207,0,1],0,2,4,[-2826.738013707856,-1209.4058575764207],0,[-2691.8734012676646,-1209.4058575764207],0,[-2691.8734012676646,-1037.2982977678084],0,[-2826.738013707856,-1037.2982977678084],0,true,0,3,0,0,0,[0,1,0,0,-1,0,0,0,0,0,1,0,619.5015513563255,-1688.6518893059424,16,1],3,0,0,0,[0,1,0,0,-1,0,0,0,0,0,1,0,796.6876948969956,-1779.4394108370425,16,1],3,0,0,0,9,0,"层板","","","","","",0,0,"三合一",2,0,"1","1","1","1","","","",4,"三合一","三合一","三合一","三合一",true,true,0,0,0,0,0,0,0,0,true,"Board",8,2,194,false,1,2,0,[0,1,0,0,-1,0,0,0,0,0,1,0,1220.6832547056076,-2829.3590022698745,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,1220.6832547056076,-2829.3590022698745,0,1],0,2,1200,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,1200],0,[0,1200],0,true,2,2,596.7579712918666,285.2784688995216,5,true,"Polyline",8,2,0,false,0,2,0,[1,0,0,0,0,1,0,0,0,0,1,0,-1196.7846889952152,789.3952918660294,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,-1196.7846889952152,789.3952918660294,0,1],0,2,4,[1196.7846889952152,-789.3952918660294],0,[1482.0631578947368,-789.3952918660294],0,[1482.0631578947368,-192.63732057416274],0,[1196.7846889952152,-192.63732057416274],0,true,1,2,172.10755980861222,134.86461244019165,5,true,"Polyline",8,2,0,false,1,2,0,[1,0,0,0,0,1,0,0,0,0,1,0,2826.738013707856,1209.4058575764207,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,2826.738013707856,1209.4058575764207,0,1],0,2,4,[-2826.738013707856,-1209.4058575764207],0,[-2691.8734012676646,-1209.4058575764207],0,[-2691.8734012676646,-1037.2982977678084],0,[-2826.738013707856,-1037.2982977678084],0,true,0,3,0,0,0,[0,1,0,0,-1,0,0,0,0,0,1,0,619.5015513563255,-2604.466217580879,13,1],3,0,0,0,[0,1,0,0,-1,0,0,0,0,0,1,0,914.0594078156558,-2695.2537391119795,13,1],2,213.30051674641152,194.11475598086145,10,true,"Polyline",8,2,0,false,0,1,0,[1,0,0,0,0,1,0,0,0,0,1,0,-1365.690442105263,773.7568765550237,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,-1365.690442105263,773.7568765550237,0,1],0,2,4,[1365.690442105263,-773.7568765550237],0,[1559.8051980861244,-773.7568765550237],0,[1559.8051980861244,-560.4563598086122],0,[1365.690442105263,-560.4563598086122],0,true,1,2,117.37171291866025,107.77883253588561,10,true,"Polyline",8,2,0,false,1,1,0,[1,0,0,0,0,1,0,0,0,0,1,0,2825.0451524638374,1503.9637140357506,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,2825.0451524638374,1503.9637140357506,0,1],0,2,4,[-2825.0451524638374,-1503.9637140357506],0,[-2717.266319927952,-1503.9637140357506],0,[-2717.266319927952,-1386.5920011170904],0,[-2825.0451524638374,-1386.5920011170904],0,true,0,3,0,0,0,[0,1,0,0,-1,0,0,0,0,0,1,0,914.0594078156555,-2602.77335633686,8,1],3,0,0,0,[0,1,0,0,-1,0,0,0,0,0,1,0,958.5196566194826,-2662.462389829684,8,1],3,0,0,0,9,0,"层板","","","","","",0,0,"三合一",2,0,"1","1","1","1","","","",4,"三合一","三合一","三合一","三合一",true,true,0,0,0,0,0,0,0,0,true,"Board",8,2,319,false,1,2,0,[0,1,0,0,-1,0,0,0,0,0,1,0,3366.98687361705,-1104.0111748335803,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,3366.98687361705,-1104.0111748335785,0,1],0,2,1504.290464961884,1207.3269751150392,18,false,"Polyline",8,2,0,false,0,1,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,true,[0,-1,0,0,1,0,0,0,0,0,1,0,-176.14448023328896,6084.154346660455,0,1],0,2,5,[0,1504.290464961884],0,[0,0],0,[635.2041889874231,0],0.41421356237309503,[1207.3269751150392,572.1227861276166],0,[1207.3269751150392,1504.290464961884],0,true,1,2,353.17496519675166,156.621909607771,5,false,"Polyline",8,2,0,false,0,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,-996.3522883039657,-128.39253837964628,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,-996.3522883039657,-128.39253837964628,0,1],0,2,4,[996.3522883039659,128.3925383796465],0.11252667928830218,[1152.9741979117366,328.73276935424474],0,[1152.9741979117366,481.56750357639794],0,[996.3522883039659,481.56750357639794],0,true,0,3,0,0,0,[0,1,0,0,-1,0,0,0,0,0,1,0,3238.594335237405,-107.65888652961257,13,1],3,0,0,0,9,0,"层板","","","","","",0,0,"三合一",2,0,"1","1","1","1","","","",5,"三合一","三合一","三合一","三合一","三合一",true,true,0,0,0,0,0,0,0,0,true,"Board",8,2,320,false,1,2,0,[0,1,0,0,-1,0,0,0,0,0,1,0,3136.208185162639,-2616.253434415853,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,3136.208185162639,-2616.253434415853,0,1],0,2,1200,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,1200],0,[0,1200],0,true,1,2,261.54004645088276,261.54004645088276,5,false,"Circle",8,2,0,false,0,1,0,[1,0,0,0,0,1,0,0,0,0,1,0,130.77002322544138,130.77002322544138,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,-967.3161011764724,632.9231332732883,0,1],0,1,130.77002322544138,0,3,0,0,0,[0,1,0,0,-1,0,0,0,0,0,1,0,2707.1695959478893,-2420.4684337178496,13,1],3,0,0,0,9,0,"层板","","","","","",0,0,"三合一",2,0,"1","1","1","1","","","",4,"三合一","三合一","三合一","三合一",true,true,0,0,0,0,0,0,0,0,true,"Board",8,2,321,false,1,2,0,[0,1,0,0,-1,0,0,0,0,0,1,0,4974.002597849426,-1611.7130364802154,18,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,4974.002597849426,-1611.7130364802154,18,1],0,2,1200,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,1200],0,[0,1200],0,true,3,2,504.5666104553118,180.4654300168635,1,true,"Polyline",8,2,0,false,0,3,0,[1,0,0,0,0,1,0,0,0,0,1,0,-192.18887015177063,2042.7723440134907,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,-192.18887015177063,2042.7723440134907,0,1],0,2,4,[192.1888701517706,-2042.7723440134907],0,[372.6543001686341,-2042.7723440134907],0,[372.6543001686341,-1538.205733558179],0,[192.1888701517706,-1538.205733558179],0,true,0,3,0,0,0,[0,1,0,0,-1,0,0,0,0,0,1,0,4419.715919940489,-1301.1160718933688,35,1],2,294.6374367622252,366.4059877764512,3,false,"Polyline",8,2,0,false,0,2,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,-104.96458684654363,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,0,-104.96458684654363,0,1],0,2,4,[0,399.60202360876883],0,[0,104.96458684654363],0,[312.43844856661036,104.96458684654363],0,[366.4059877764512,399.60202360876883],0,true,0,3,0,0,0,[0,1,0,0,-1,0,0,0,0,0,1,0,4623.506813701027,-1526.2155659911766,33,1],2,355.8893169877406,166.08168126094597,2,true,"Polyline",8,2,0,false,0,1,0,[1,0,0,0,0,1,0,0,0,0,1,0,-1550.934999630836,-989.7071461268802,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,-1550.934999630836,-989.7071461268802,0,1],0,2,4,[1550.934999630836,989.7071461268802],0,[1717.016680891782,989.7071461268802],0,[1717.016680891782,1345.5964631146207],0,[1550.934999630836,1345.5964631146207],0,true,0,3,0,0,0,[0,1,0,0,-1,0,0,0,0,0,1,0,4374.263193296011,-1402.1337720318782,34,1],3,0,0,0,9,0,"层板","","","","","",0,0,"三合一",2,0,"1","1","1","1","","","",4,"三合一","三合一","三合一","三合一",true,true,0,0,0,0,0,0,0,0,true,"Board",8,2,322,false,1,2,0,[0,1,0,0,-1,0,0,0,0,0,1,0,5075.449989621094,-2406.2197872516485,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,5075.449989621094,-2406.2197872516485,0,1],0,2,1200,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,1200],0,[0,1200],0,true,2,2,296.25071770334944,167.71866028708132,3,false,"Polyline",8,2,0,false,0,2,0,[1,0,0,0,0,1,0,0,0,0,1,0,1643.9637349663465,3181.1583717776566,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,1643.9637349663465,3181.1583717776566,0,1],0,2,5,[-1643.9637349663465,-3181.1583717776566],0,[-1476.2450746792651,-3181.1583717776566],0,[-1476.2450746792651,-2963.5887820114735],0.41421356237309503,[-1554.9262026164317,-2884.907654074307],0,[-1643.9637349663465,-2884.907654074307],0,true,0,3,0,0,0,[0,1,0,0,-1,0,0,0,0,0,1,0,4697.69810445363,-2223.871461892797,15,1],2,259.36676716622435,259.36676716622435,1,false,"Circle",8,2,0,false,0,1,0,[1,0,0,0,0,1,0,0,0,0,1,0,129.68338358311217,129.68338358311212,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,1618.4681711810376,2929.9479754564627,0,1],0,1,129.68338358311217,0,3,0,0,0,[0,1,0,0,-1,0,0,0,0,0,1,0,4434.6376794243015,-2198.375898107488,17,1],3,0,0,0,9,0,"层板","","","","","",0,0,"三合一",2,0,"1","1","1","1","","","",4,"三合一","三合一","三合一","三合一",true,true,0,0,0,0,0,0,0,0,true,"Board",8,2,323,false,1,2,0,[0,1,0,0,-1,0,0,0,0,0,1,0,3031.191361580537,292.71257880837857,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,3031.191361580537,292.71257880837857,0,1],0,2,1200,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,1200],0,[0,1200],0,true,2,2,261.54004645088276,261.54004645088276,9,false,"Circle",8,2,0,false,0,2,0,[1,0,0,0,0,1,0,0,0,0,1,0,130.77002322544138,130.77002322544138,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,-967.316101176474,632.9231332732892,0,1],0,1,130.77002322544138,0,3,0,0,0,[0,1,0,0,-1,0,0,0,0,0,1,0,2602.1527723657873,488.49757950638195,9,1],2,522.8612440191387,104.12440191387532,9,true,"Polyline",8,2,0,false,0,1,0,[1,0,0,0,0,1,0,0,0,0,1,0,3238.071616234034,3266.8206253540266,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,3238.071616234034,3266.8206253540266,0,1],0,2,4,[-3238.071616234034,-3266.8206253540266],0,[-3133.9472143201588,-3266.8206253540266],0,[-3133.9472143201588,-2743.959381334888],0,[-3238.071616234034,-2743.959381334888],0,true,0,3,0,0,0,[0,1,0,0,-1,0,0,0,0,0,1,0,2738.59806014513,565.1527701959385,0,1],3,0,0,0,9,0,"层板","","","","","",0,0,"三合一",2,0,"1","1","1","1","","","",4,"三合一","三合一","三合一","三合一",true,true,0,0,0,0,0,0,0,0,true,"Board",8,2,324,false,1,2,0,[0,1,0,0,-1,0,0,0,0,0,1,0,4998.286032361368,293.35775691911863,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,4998.286032361368,293.35775691911863,0,1],0,2,1200,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,1200],0,[0,1200],0,true,4,2,40.30622009569379,104.12440191387532,9,true,"Polyline",8,2,0,false,0,2,0,[1,0,0,0,0,1,0,0,0,0,1,0,-1624.6496229478253,4405.824788342229,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,-1624.6496229478253,4405.824788342229,0,1],0,2,4,[1624.6496229478253,-4405.824788342229],0,[1728.7740248617006,-4405.824788342229],0,[1728.7740248617006,-4365.518568246535],0,[1624.6496229478253,-4365.518568246535],0,true,0,3,0,0,0,[0,1,0,0,-1,0,0,0,0,0,1,0,4663.719525184334,565.797948306677,9,1],2,50.03345454545433,136.79035406698677,9,true,"Polyline",8,2,0,false,0,2,0,[1,0,0,0,0,1,0,0,0,0,1,0,-1907.9127808425624,4646.9694390599325,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,-1907.9127808425624,4646.9694390599325,0,1],0,2,4,[1907.9127808425624,-4646.9694390599325],0,[2044.7031349095491,-4646.9694390599325],0,[2044.7031349095491,-4596.935984514478],0,[1907.9127808425624,-4596.935984514478],0,true,0,3,0,0,0,[0,1,0,0,-1,0,0,0,0,0,1,0,4275.141687863759,669.9223502205527,9,1],2,261.54004645088276,261.54004645088276,9,false,"Circle",8,2,0,false,0,2,0,[1,0,0,0,0,1,0,0,0,0,1,0,130.77002322544138,130.77002322544138,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,-967.3161011764741,632.9231332732892,0,1],0,1,130.77002322544138,0,3,0,0,0,[0,1,0,0,-1,0,0,0,0,0,1,0,4569.247443146618,489.14275761712213,9,1],2,522.8612440191387,104.12440191387532,9,true,"Polyline",8,2,0,false,0,1,0,[1,0,0,0,0,1,0,0,0,0,1,0,3238.071616234034,3266.8206253540266,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,3238.071616234034,3266.8206253540266,0,1],0,2,4,[-3238.071616234034,-3266.8206253540266],0,[-3133.9472143201588,-3266.8206253540266],0,[-3133.9472143201588,-2743.959381334888],0,[-3238.071616234034,-2743.959381334888],0,true,0,3,0,0,0,[0,1,0,0,-1,0,0,0,0,0,1,0,4705.692730925961,565.7979483066777,0,1],3,0,0,0,9,0,"层板","","","","","",0,0,"三合一",2,0,"1","1","1","1","","","",4,"三合一","三合一","三合一","三合一",true,true,0,0,0,0,0,0,0,0,true],"basePt":{"x":20.683254705607624,"y":-2829.3590022698745,"z":0}} \ No newline at end of file diff --git a/config/webpack.dev.ts b/config/webpack.dev.ts index 98c720e56..d6cd0250f 100644 --- a/config/webpack.dev.ts +++ b/config/webpack.dev.ts @@ -8,7 +8,7 @@ const config: webpack.Configuration = merge( { mode: "development", output: { pathinfo: false }, - devtool: "cheap-module-eval-source-map", + devtool: "eval-source-map", //https://www.webpackjs.com/configuration/stats/ stats: { assets: false, diff --git a/src/Add-on/test/TestTape.ts b/src/Add-on/test/TestTape.ts new file mode 100644 index 000000000..5eb13ff39 --- /dev/null +++ b/src/Add-on/test/TestTape.ts @@ -0,0 +1,122 @@ +import { Vector3 } from "three"; +import { TestDraw } from "./TestUtil"; +import { app } from "../../ApplicationServices/Application"; +import { Board } from "../../DatabaseServices/Entity/Board"; +import { PromptStatus } from "../../Editor/PromptResult"; +import { HotCMD } from "../../Hot/HotCommand"; +import { MoveMatrix } from "../../Geometry/GeUtils"; +import { ExtrudeGeometryBuilder } from "../../Geometry/ExtrudeEdgeGeometry2"; +@HotCMD +export class Command_TestTape +{ + async exec() + { + let enRes = await app.Editor.GetEntity({ Filter: { filterTypes: [Board] } }); + if (enRes.Status !== PromptStatus.OK) + return; + let br = enRes.Entity as Board; + let geo = new ExtrudeGeometryBuilder(br); + return; + let k = 0; + let i = 1; + let testOut = true; + for (let s of geo.shapes) + { + if (testOut) + { + let m = MoveMatrix(new Vector3(0, k * 20)); + for (let t of s.contour.Tape) + { + t.Curve.ApplyMatrix(m); + TestDraw(t.Curve, s.depth); + } + k++; + } + else + { + for (let w of s.holes) + { + let m = MoveMatrix(new Vector3(0, k * 20)); + for (let t of w.Tape) + { + t.Curve.ApplyMatrix(m); + TestDraw(t.Curve, w.depth); + } + k++; + } + } + } + // let gs = br.Grooves; + // let brOcsInv = br.OCSInv; + // let alm = new Matrix4; + // let ws = gs.map(g => + // { + // alm.multiplyMatrices(brOcsInv, g.OCSNoClone); + // let type: DepthType; + // if (equaln(g.Thickness, br.Thickness)) + // type = DepthType.All; + // else if (equaln(g.Position.applyMatrix4(brOcsInv).z, 0)) + // type = DepthType.Back; + // else + // type = DepthType.Front; + // //槽轮廓 + // let gContour = g.ContourCurve.Clone(); + // gContour.ApplyMatrix(alm); + // gContour.Z0(); + // let holes: ExtureContourCurve[] = []; + // //孤岛 + // for (let gg of g.Grooves) + // { + // let c = gg.ContourCurve.Clone(); + // alm.multiplyMatrices(brOcsInv, gg.OCSNoClone); + // c.ApplyMatrix(alm).Z0(); + // holes.push(c); + // } + // let s = new ExtrudeWallShape(gContour, holes, type, g.Thickness, br.Thickness); + // return s; + // }); + // let brS = new ExtrudeWallShape(br.ContourCurve.Clone(), [], DepthType.All, br.Thickness, br.Thickness); + // brS.contour.wallType = WallType.Outer; + // let k = 0; + // for (let i = 0; i < ws.length; i++) + // { + // let w1 = ws[i]; + // brS.Clip(w1, false); + // for (let j = i + 1; j < ws.length; j++) + // { + // let w2 = ws[j]; + // w1.Clip(w2); + // } + // for (let c of [w1.contour, ...w1.holes]) + // { + // let m = MoveMatrix(new Vector3(0, k * 20)); + // k++; + // for (let tape of c.Tape) + // { + // let en = tape.Curve.Clone(); + // en.ApplyMatrix(m); + // TestDraw(en, w1.depth); + // } + // let mesh = c.ToMesh(); + // mesh.applyMatrix4(br.OCS); + // mesh.updateMatrixWorld(true); + // TestDraw(mesh, w1.depth); + // } + // } + // for (let c of [brS.contour]) + // { + // let m = MoveMatrix(new Vector3(0, k * 20)); + // k++; + // for (let tape of c.Tape) + // { + // let en = tape.Curve.Clone(); + // en.ApplyMatrix(m); + // TestDraw(en, br.Thickness); + // } + // let mesh = c.ToMesh(); + // mesh.applyMatrix4(br.OCS); + // mesh.updateMatrixWorld(true); + // TestDraw(mesh, br.Thickness); + // } + } +} diff --git a/src/Add-on/testEntity/test.ts b/src/Add-on/testEntity/test.ts index 7d66a77fe..068a4568d 100644 --- a/src/Add-on/testEntity/test.ts +++ b/src/Add-on/testEntity/test.ts @@ -1,15 +1,8 @@ -import { BufferGeometry, Float32BufferAttribute, Matrix4, Mesh, Shape, ShapeUtils, Vector2 } from "three"; +import { Command } from "../../Editor/CommandMachine"; +import { HotCMD } from "../../Hot/HotCommand"; import { app } from "../../ApplicationServices/Application"; -import { Contour } from "../../DatabaseServices/Contour"; import { Board } from "../../DatabaseServices/Entity/Board"; -import { Circle } from "../../DatabaseServices/Entity/Circle"; -import { Curve } from "../../DatabaseServices/Entity/Curve"; -import { Polyline } from "../../DatabaseServices/Entity/Polyline"; -import { Command } from "../../Editor/CommandMachine"; import { PromptStatus } from "../../Editor/PromptResult"; -import { equaln } from "../../Geometry/GeUtils"; -import { HotCMD } from "../../Hot/HotCommand"; -import { TestDraw } from "../test/TestUtil"; @HotCMD export class Test implements Command @@ -20,169 +13,6 @@ export class Test implements Command if (enRes.Status !== PromptStatus.OK) return; let br = enRes.Entity as Board; - let ocsInv = br.OCSInv; - let alMatrix4 = new Matrix4(); - - let frontHoles: Shape[] = []; - let backHoles: Shape[] = []; - - let frontCurves: Curve[] = []; - let backCurves: Curve[] = []; - - let frontHoleCurves: Curve[] = []; - let backHoleCurves: Curve[] = []; - - for (let g of br.Grooves) - { - let back = false; - let front = false; - if (equaln(g.Thickness, br.Thickness)) - { - back = true; - front = true; - } - else - { - if (equaln(g.Position.applyMatrix4(ocsInv).z, 0)) - back = true; - else - front = true; - } - - alMatrix4.multiplyMatrices(ocsInv, g.OCSNoClone); - let gContour = g.ContourCurve.Clone(); - gContour.ApplyMatrix(alMatrix4); - - if (gContour instanceof Polyline) - gContour.UpdateMatrixTo(br.ContourCurve.OCS); - - let sp: Shape; - if (gContour instanceof Circle) - { - sp = new Shape(); - let cen = gContour.Center.applyMatrix4(ocsInv); - sp.ellipse(cen.x, cen.y, gContour.Radius, gContour.Radius, 0, 2 * Math.PI, false, 0); - } - else - sp = gContour.Shape; - - gContour.Z0(); - gContour.TempData = g.Thickness; - let holeCurves: Curve[] = []; - for (let gg of g.Grooves) - { - let c = gg.ContourCurve; - c.ApplyMatrix(alMatrix4).Z0(); - c.TempData = g.Thickness; - holeCurves.push(c); - } - if (back) - { - backHoles.push(sp); - backCurves.push(gContour); - backHoleCurves.push(...holeCurves); - } - if (front) - { - frontHoles.push(sp); - frontCurves.push(gContour); - frontHoleCurves.push(...holeCurves); - } - } - - let contourShape = br.ContourCurve.Shape; - let verticesArray: number[] = []; - - //draw front - contourShape.holes = frontHoles; - DrawShapeFaces(contourShape, verticesArray, br); - - //front 孤岛 - let frontCurveContours = frontCurves.map(c => Contour.CreateContour([c])); - DrawIslandFaces(frontHoleCurves, frontCurveContours, verticesArray, br); - - //draw back - contourShape.holes = backHoles; - DrawShapeFaces(contourShape, verticesArray, br, false); - - let backCurveContours = backCurves.map(c => Contour.CreateContour([c])); - DrawIslandFaces(backHoleCurves, backCurveContours, verticesArray, br, false); - - //绘制内部造型 - //绘制边缘 - - - //geo - let geo = new BufferGeometry(); - geo.setAttribute('position', new Float32BufferAttribute(verticesArray, 3)); - - TestDraw(new Mesh(geo)); - } -} -function DrawIslandFaces(HoleCurves: Curve[], CurveContours: Contour[], verticesArray: number[], br: Board, front = true) -{ - for (let c of HoleCurves) - { - let contours = [Contour.CreateContour([c])]; - for (let hole of CurveContours) - { - if (!equaln(c.TempData as number, hole.Curve.TempData as number)) - { - let newcs: Contour[] = []; - for (let con of contours) - newcs.push(...con.SubstactBoolOperation(hole)); - contours = newcs; - } - } - for (let con of contours) - { - DrawShapeFaces(con.Curve.Shape, verticesArray, br); - } - } -} - -function DrawShapeFaces(contourShape: Shape, verticesArray: number[], br: Board, front = true) -{ - let shapePoints = contourShape.extractPoints(6); - let vertices = shapePoints.shape; - let holes = shapePoints.holes; - let reverse = !ShapeUtils.isClockWise(vertices); - if (reverse) - { - vertices = vertices.reverse(); - for (let h = 0, hl = holes.length; h < hl; h++) - { - let ahole = holes[h]; - if (ShapeUtils.isClockWise(ahole)) - holes[h] = ahole.reverse(); - } - } - let faces = ShapeUtils.triangulateShape(vertices, holes); - for (let h of holes) - vertices.push(...h); - for (let f of faces) - { - if (front) - { - newFunction_1(vertices[f[0]]); - newFunction_1(vertices[f[1]]); - newFunction_1(vertices[f[2]]); - } - else - { - newFunction_1(vertices[f[0]]); - newFunction_1(vertices[f[2]]); - newFunction_1(vertices[f[1]]); - } - } - - function newFunction_1(v: Vector2) - { - verticesArray.push(v.x); - verticesArray.push(v.y); - if (front) - verticesArray.push(br.Thickness); - else - verticesArray.push(0); + br.ApplyMatrix(br.OCSInv); } } diff --git a/src/DatabaseServices/Entity/Curve.ts b/src/DatabaseServices/Entity/Curve.ts index 18de8cac9..ed670b020 100644 --- a/src/DatabaseServices/Entity/Curve.ts +++ b/src/DatabaseServices/Entity/Curve.ts @@ -88,12 +88,12 @@ export abstract class Curve extends Entity /** * 返回切割曲线后的结果.总是从起点开始切割,并且按顺序返回曲线. - * * @param {(number[] | number)} param * @returns {Array} - * @memberof Curve */ GetSplitCurves(param: number[] | number): Array { return; } + //未完善 + GetCurveAtParamRange(startParam: number, EndParam: number): Array { return; } GetSplitCurvesByPts(pt: Vector3[] | Vector3): Array { let pts = Array.isArray(pt) ? pt : [pt]; diff --git a/src/DatabaseServices/Entity/Extrude.ts b/src/DatabaseServices/Entity/Extrude.ts index 3d429a327..dce007090 100644 --- a/src/DatabaseServices/Entity/Extrude.ts +++ b/src/DatabaseServices/Entity/Extrude.ts @@ -1,4 +1,4 @@ -import { BoxGeometry, BufferGeometry, ExtrudeGeometry, ExtrudeGeometryOptions, Geometry, Line, LineSegments, Matrix3, Matrix4, Mesh, Object3D, Vector3, Path } from "three"; +import { BoxGeometry, BufferGeometry, ExtrudeGeometry, ExtrudeGeometryOptions, Geometry, Line, LineSegments, Matrix3, Matrix4, Mesh, Object3D, Path, Vector3 } from "three"; import { arrayClone, arrayLast, arrayRemoveIf, arraySortByNumber, arraySum } from "../../Common/ArrayExt"; import { ColorMaterial } from "../../Common/ColorPalette"; import { equalCurve } from "../../Common/CurveUtils"; @@ -6,7 +6,7 @@ import { DisposeThreeObj } from "../../Common/Dispose"; import { matrixSetVector, Vector2ApplyMatrix4 } from "../../Common/Matrix4Utils"; import { Status, UpdateDraw } from "../../Common/Status"; import { CSG } from "../../csg/core/CSG"; -import { CSG2Geometry, Geometry2CSG } from "../../csg/core/Geometry2CSG"; +import { Geometry2CSG } from "../../csg/core/Geometry2CSG"; import { ObjectSnapMode } from "../../Editor/ObjectSnapMode"; import { boardUVGenerator } from "../../Geometry/BoardUVGenerator"; import { Box3Ext } from "../../Geometry/Box"; @@ -14,6 +14,7 @@ import { BSPGroupParse } from "../../Geometry/BSPGroupParse"; import { FastWireframe } from "../../Geometry/CreateWireframe"; import { EdgesGeometry } from "../../Geometry/EdgeGeometry"; import { GenerateExtrudeEdgeGeometry } from "../../Geometry/ExtrudeEdgeGeometry"; +import { ExtrudeGeometryBuilder } from "../../Geometry/ExtrudeEdgeGeometry2"; import { AsVector2, AsVector3, equaln, equalv2, equalv3, IdentityMtx4, isIntersect, isParallelTo, isPerpendicularityTo, MoveMatrix, XAxis, YAxis, ZAxis, ZeroVec } from "../../Geometry/GeUtils"; import { OBB } from "../../Geometry/OBB/obb"; import { ScaleUV } from "../../Geometry/UVUtils"; @@ -1219,11 +1220,47 @@ export class ExtrudeSolid extends Entity if (this._MeshGeometry) return this._MeshGeometry; - this._MeshGeometry = this.GeneralMeshGeometry(); + this.csg = undefined; + let grooves = this.Grooves; + if (grooves.every(g => equaln(g.thickness, this.thickness))) + { + let contour = this.ContourCurve; + let holes: Contour[] = []; + + let ocsInv = this.OCSInv; + let alMatrix4 = new Matrix4(); + for (let g of grooves) + { + alMatrix4.multiplyMatrices(ocsInv, g.OCSNoClone); + let gContour = g.ContourCurve.Clone(); + gContour.ApplyMatrix(alMatrix4); + holes.push(Contour.CreateContour(gContour)); + + } + + let shape = new Shape(Contour.CreateContour(contour), holes); + + let extrudeSettings: ExtrudeGeometryOptions = { + steps: 1, + bevelEnabled: false, + depth: this.Thickness, + UVGenerator: this.UCGenerator, + }; + let geo = new ExtrudeGeometry(shape.Shape, extrudeSettings); + geo.applyMatrix4(contour.OCSNoClone); + ScaleUV(geo); + return geo; + } + + let builder = new ExtrudeGeometryBuilder(this); + + this._MeshGeometry = builder.MeshGeometry; + this._EdgeGeometry = builder.EdgeGeometry; + return this._MeshGeometry; } - private _EdgeGeometry: EdgesGeometry; + private _EdgeGeometry: EdgesGeometry | BufferGeometry; private get EdgeGeometry() { if (this._EdgeGeometry) @@ -1256,55 +1293,9 @@ export class ExtrudeSolid extends Entity } return GenerateExtrudeEdgeGeometry(pts, this.thickness).applyMatrix4(this.contourCurve.OCSNoClone); } - this._EdgeGeometry = new EdgesGeometry().FromCSG(this.CSG); - return this._EdgeGeometry; - } - - private GeneralMeshGeometry() - { - this.csg = undefined; - let grooves = this.Grooves; - let gs: ExtrudeSolid[] = [];//不是全深槽 - - let contour = this.ContourCurve; - let holes: Contour[] = []; - - let ocsInv = this.OCSInv; - let alMatrix4 = new Matrix4(); - for (let g of grooves) - { - if (equaln(g.Thickness, this.Thickness)) - { - alMatrix4.multiplyMatrices(ocsInv, g.OCSNoClone); - let gContour = g.ContourCurve.Clone(); - gContour.ApplyMatrix(alMatrix4); - holes.push(Contour.CreateContour(gContour)); - } - else if (g.Thickness > 0) - gs.push(g); - } - - let shape = new Shape(Contour.CreateContour(contour), holes); - let extrudeSettings: ExtrudeGeometryOptions = { - steps: 1, - bevelEnabled: false, - depth: this.Thickness, - UVGenerator: this.UCGenerator, - }; - let geo = new ExtrudeGeometry(shape.Shape, extrudeSettings); - geo.applyMatrix4(contour.OCSNoClone); - ScaleUV(geo); - - if (gs.length === 0 || gs.length > MaxGrooveCount) - return geo; - - this.csg = Geometry2CSG(geo); - for (let g of gs) - this.csg = this.csg.subtract(g.CSG.transform1(this.OCSInv.multiply(g.OCSNoClone))); - - let bgeo = CSG2Geometry(this.csg); - return bgeo; + this.MeshGeometry; + return this._EdgeGeometry; } DeferUpdate() diff --git a/src/DatabaseServices/Entity/Polyline.ts b/src/DatabaseServices/Entity/Polyline.ts index 023f1d8cd..571e78e61 100644 --- a/src/DatabaseServices/Entity/Polyline.ts +++ b/src/DatabaseServices/Entity/Polyline.ts @@ -647,7 +647,7 @@ export class Polyline extends Curve //添加点 for (let i = 0; i < pafloor; i++) { - if (i == 0 && !equaln(buls[0], 0, 1e-8)) + if (i === 0 && !equaln(buls[0], 0, 1e-8)) { buls[0] = Math.tan((1 - prePa) * Math.atan(buls[0])); } @@ -694,6 +694,70 @@ export class Polyline extends Curve return pls; } + //未完善 + GetCurveAtParamRange(startParam: number, endParam: number): Array + { + let sfloor = Math.floor(startParam + 0.5); + if (equaln(sfloor, startParam, 1e-8)) startParam = sfloor; + else sfloor = Math.floor(startParam); + let efloor = Math.floor(endParam + 0.5); + if (equaln(efloor, endParam, 1e-8)) endParam = efloor; + else efloor = Math.floor(efloor); + + const GetCurve = (index: number) => + { + let d = this._LineData[index]; + let next = this._LineData[index + 1]; + if (!equaln(d.bul, 0, 1e-8)) + return new Arc().ParseFromBul(d.pt, next.pt, d.bul); + else + return new Line(AsVector3(d.pt), AsVector3(next.pt)); + }; + + let lined: PolylineProps[] = []; + if (startParam === sfloor) + { + let d = this._LineData[sfloor]; + lined.push({ pt: d.pt.clone(), bul: d.bul }); + } + else + { + let d = this._LineData[sfloor]; + let cu = GetCurve(sfloor); + let remParam = startParam - sfloor; + let p = cu.GetPointAtParam(remParam); + let bul = d.bul; + if (!equaln(bul, 0)) + bul = Math.tan(Math.atan(bul) * (1 - remParam)); + lined.push({ pt: AsVector2(p), bul: bul }); + } + + for (let i = sfloor + 1; i < efloor; i++) + { + let d = this._LineData[i]; + lined.push({ pt: d.pt.clone(), bul: d.bul }); + } + + if (efloor !== endParam) + { + let d = this.LineData[efloor]; + let remParam = endParam - efloor; + let cu = GetCurve(efloor); + let p = cu.GetPointAtParam(remParam); + let bul = d.bul; + if (!equaln(bul, 0)) + { + arrayLast(lined).bul = Math.tan(Math.atan(bul) * remParam); + bul = Math.tan(Math.atan(bul) * (1 - remParam)); + } + lined.push({ pt: AsVector2(p), bul }); + } + + let pl = new Polyline(lined); + pl.OCS = this.OCSNoClone; + return; + } + Extend(newParam: number) { if (this.CloseMark || this.ParamOnCurve(newParam)) return; diff --git a/src/DatabaseServices/Entity/Region.ts b/src/DatabaseServices/Entity/Region.ts index 501728e0e..e52178e61 100644 --- a/src/DatabaseServices/Entity/Region.ts +++ b/src/DatabaseServices/Entity/Region.ts @@ -18,7 +18,6 @@ import { ShapeManager } from '../ShapeManager'; @Factory export class Region extends Entity { - private _ShapeManager: ShapeManager = new ShapeManager(); static CreateFromCurves(cus: Curve[]): Region | undefined { let shapes = Contour.GetAllContour(cus).map(out => new Shape(out)); @@ -32,6 +31,11 @@ export class Region extends Entity } } + constructor(private _ShapeManager: ShapeManager = new ShapeManager()) + { + super(); + } + //如果需要修改获取到的属性,需要Clone后进行操作,否则会对原实体进行破坏 get ShapeManager() { diff --git a/src/DatabaseServices/ShapeManager.ts b/src/DatabaseServices/ShapeManager.ts index 964ab8780..b954c2f8d 100644 --- a/src/DatabaseServices/ShapeManager.ts +++ b/src/DatabaseServices/ShapeManager.ts @@ -109,6 +109,20 @@ export class ShapeManager } return true; } + SubstactShape(target: Shape) + { + //减数形状 + let tmpShapes: Shape[] = []; + //被减形状 + for (let minuendShape of this._ShapeList) + { + let operatedShapes = minuendShape.SubstactBoolOperation(target); + tmpShapes.push(...operatedShapes); + } + //迭代this形状列表,每次赋予新的结果 + this._ShapeList = tmpShapes; + return true; + } /** * 与region.ApplyMatrix不同的是,这个是直接操作内部对象. diff --git a/src/Editor/CommandRegister.ts b/src/Editor/CommandRegister.ts index cdf8b65eb..c395be73f 100644 --- a/src/Editor/CommandRegister.ts +++ b/src/Editor/CommandRegister.ts @@ -159,6 +159,7 @@ import { Align } from './../Add-on/Align'; import { BuyMaterial } from './../Add-on/BuyMaterial'; import { Interfere } from './../Add-on/interfere'; import { Command_ShowProcessingGroupModal2 } from "../Add-on/ShowProcessingGroupModal"; +import { Command_TestTape } from "../Add-on/test/TestTape"; export function registerCommand() { @@ -438,6 +439,9 @@ export function registerCommand() commandMachine.RegisterCommand("buymaterial", new BuyMaterial()); commandMachine.RegisterCommand("interfere", new Interfere()); + + commandMachine.RegisterCommand("testw", new Command_TestTape()); + RegistCustomCommand(); } diff --git a/src/Geometry/ExtrudeEdgeGeometry2.ts b/src/Geometry/ExtrudeEdgeGeometry2.ts new file mode 100644 index 000000000..9c104e2ad --- /dev/null +++ b/src/Geometry/ExtrudeEdgeGeometry2.ts @@ -0,0 +1,1268 @@ +import { Box3, BufferGeometry, Float32BufferAttribute, Matrix4, Shape as TShape, ShapeUtils, Vector2, Vector3 } from "three"; +import { arrayRemoveDuplicateBySort, arraySortByNumber } from "../Common/ArrayExt"; +import { curveLinkGroup } from "../Common/CurveUtils"; +import { clamp, FixIndex } from "../Common/Utils"; +import { Contour } from "../DatabaseServices/Contour"; +import { Arc } from "../DatabaseServices/Entity/Arc"; +import { Circle } from "../DatabaseServices/Entity/Circle"; +import { Curve } from "../DatabaseServices/Entity/Curve"; +import { ExtrudeSolid, ExtureContourCurve } from "../DatabaseServices/Entity/Extrude"; +import { Line } from "../DatabaseServices/Entity/Line"; +import { Polyline } from "../DatabaseServices/Entity/Polyline"; +import { IntersectOption } from "../GraphicsSystem/IntersectWith"; +import { AsVector2, equaln, equalv3, IdentityMtx4 } from "./GeUtils"; +import { RegionParse } from "./RegionParse"; + +export enum DepthType +{ + Front = 1, + Back = 2, + All = 3, +} + +class Shape2 +{ + constructor(public contour: Contour, public holes: Contour[]) + { + + } + + Parse(contour: Contour, s: this, isOut: boolean) + { + let [res1,] = Parse(this.contour.Curve, s.contour.Curve); + if (!isOut) + [res1.reverse, res1.syntropy] = [res1.syntropy, res1.reverse]; + if (res1.container.length > 0) + { + for (let h of s.holes) + { + let [res2,] = Parse(this.contour.Curve, h.Curve); + if (isOut) + [res2.reverse, res2.syntropy] = [res2.syntropy, res2.reverse]; + + res1.container = SubtractRanges(res1.container, res2.container, contour.Curve.EndParam); + res1.container = SubtractRanges(res1.container, res2.syntropy, contour.Curve.EndParam); + res1.container = SubtractRanges(res1.container, res2.reverse, contour.Curve.EndParam); + + //被网洞包含等于在形状外部 + res1.outer.push(...res2.container); + + res1.syntropy.push(...res2.syntropy); + res1.reverse.push(...res2.reverse); + } + } + return res1; + } + + Sub(s: Shape2) + { + + } +} + + +/** + * 由ExtudeWall围成的形状,包含外轮廓和网洞 + */ +export class ExtudeWallShape +{ + contour: ExtudeWall; + holes: ExtudeWall[] = []; + + box: Box3; + shape: CurveTapeShape; + constructor(contour: Contour, + holes: Contour[], + public depthType: DepthType, + public depth: number, + public allDepth: number) + { + this.contour = new ExtudeWall(contour.Curve, depthType, depth, allDepth, DirectionType.Inner); + this.box = contour.BoundingBox; + + for (let h of holes) + this.holes.push(new ExtudeWall(h.Curve, depthType, depth, allDepth, DirectionType.Outer)); + + this.shape = new CurveTapeShape(contour, holes); + } + + /** + * + * @param shape + * @param [eachOther=true] 相互裁剪 + */ + ClipWall(shape: ExtudeWallShape, eachOther = true) + { + //相同深度和面不用操作 + if (shape.depthType === this.depthType && shape.depth === this.depth) return; + + if (!this.box.intersectsBox(shape.box)) return; + + this.ClipShape(shape); + shape.ClipShape(this); + + //一正一反,不交集 + if (this.depthType + shape.depthType === 3 && this.depth + shape.depth < this.allDepth) + return; + + this.contour.Clip(shape, true); + for (let c of this.holes) + c.Clip(shape, true); + + if (eachOther) + { + shape.contour.Clip(this, false); + for (let c of shape.holes) + c.Clip(this, false); + } + } + + ClipShape(shape: ExtudeWallShape) + { + if (this.depthType === DepthType.All) return; + if (shape.depthType === DepthType.All) return; + + if (this.depthType === shape.depthType) + { + if (shape.depth > this.depth) + this.shape.ClipTo(shape.shape, true); + else + { + this.shape.SplitTo(shape.shape); + } + } + else + { + if (this.depth + shape.depth >= this.allDepth) + this.shape.ClipTo(shape.shape, true); + else + { + this.shape.SplitTo(shape.shape); + } + } + } + + Draw(verticesArray: number[], uvArray: number[], edgeBuild: EdgeGeometryBuild) + { + this.contour.Draw(verticesArray, uvArray, edgeBuild); + for (let wall of this.holes) + wall.Draw(verticesArray, uvArray, edgeBuild); + + if (this.depthType === DepthType.All) return; + + let isFront = this.depthType === DepthType.Front; + this.shape.Draw(verticesArray, uvArray, isFront, isFront ? this.allDepth - this.depth : this.depth); + } +} + +function GetShape(cu: ExtureContourCurve): TShape +{ + if (cu instanceof Circle) + { + let sp = new TShape(); + let cen = cu.Center; + sp.ellipse(cen.x, cen.y, cu.Radius, cu.Radius, 0, 2 * Math.PI, false, 0); + return sp; + } + else + { + if (cu.OCSNoClone !== IdentityMtx4) + cu.UpdateMatrixTo(IdentityMtx4); + return cu.Shape; + } +} + +function CreateTape(faceType: DepthType, startParam: number, endParam: number, depth: number, allDepth: number): Tape +{ + if (faceType === DepthType.Front) + return new Tape(startParam, endParam, allDepth - depth, allDepth); + else + return new Tape(startParam, endParam, 0, depth); +} + +//朝向类型 +enum DirectionType +{ + Outer = 0,//外墙 + Inner = 1 //内墙 +} + +//轮廓树,用于重新确认外墙和网洞的关系 +class ContourTree +{ + parent: ContourTree; + constructor(public contour: Contour, public children: ContourTree[] = []) + { + } + + SetParent(s: ContourTree) + { + this.parent = s; + s.children.push(this); + } + + Draw(verticesArray: number[], uvArray: number[], front: boolean, z: number)//, depth = 1 + { + // TestDraw(this.contour.Curve, depth); + let pts = this.contour.Curve.GetStretchPoints(); + + let vertices = [...pts]; + let holes = this.children.map(h => + { + // TestDraw(h.contour.Curve, depth + 1); + let pts = h.contour.Curve.GetStretchPoints(); + vertices.push(...pts); + return pts; + }); + + let faces = ShapeUtils.triangulateShape(pts, holes); + + for (let f of faces) + { + if (front) + { + AddVertice(vertices[f[0]]); + AddVertice(vertices[f[1]]); + AddVertice(vertices[f[2]]); + } + else + { + AddVertice(vertices[f[0]]); + AddVertice(vertices[f[2]]); + AddVertice(vertices[f[1]]); + } + } + + function AddVertice(v: Vector3) + { + verticesArray.push(v.x, v.y, z); + uvArray.push(v.x * 1e-3, v.y * 1e-3); + } + + for (let hole of this.children) + { + for (let h of hole.children) + { + h.Draw(verticesArray, uvArray, front, z);//, depth + 2 + } + } + } +} + +class EdgeGeometryBuild +{ + verticesArray: number[] = []; + + frontLines: Line[] = []; + backLines: Line[] = []; + constructor(public allDepth: number) { } + AddLidLine(p1: Vector3, p2: Vector3, depth: number) + { + if (depth === 0) + { + p1 = p1.clone().setZ(0); + p2 = p2.clone().setZ(0); + let line = new Line(p1, p2); + this.backLines.push(line); + } + else if (depth === this.allDepth) + { + p1 = p1.clone().setZ(0); + p2 = p2.clone().setZ(0); + let line = new Line(p1, p2); + this.frontLines.push(line); + } + } + + /** + * @param pts3d 给了首尾相等的点表 + */ + AddEdgePolygon(pts3d: Vector3[]) + { + for (let i = 0; i < pts3d.length - 1; i++) + { + let p = pts3d[i]; + let np = pts3d[i + 1]; + this.verticesArray.push(p.x, p.y, p.z, np.x, np.y, np.z); + } + } + + BuildLid(verticesArray: number[], uvArray: number[]) + { + let arr = [this.backLines, this.frontLines]; + + for (let index = 0; index < 2; index++) + { + let lines = arr[index]; + let parse = new RegionParse(lines); + let contours: ContourTree[] = []; + for (let routes of parse.RegionsOutline) + { + let cs: Curve[] = []; + for (let r of routes) + cs.push(r.curve); + let c = Contour.CreateContour(cs, false); + if (!c) + { + Contour.CreateContour(cs, false); + return; + } + contours.push(new ContourTree(c)); + } + + contours.sort((c1, c2) => c1.contour.Curve.Area - c2.contour.Curve.Area); + + for (let i = 0; i < contours.length; i++) + { + const s = contours[i]; + let p = s.contour.Curve.StartPoint; + for (let j = i + 1; j < contours.length; j++) + { + const s2 = contours[j]; + if (s2.contour.BoundingBox.intersectsBox(s.contour.BoundingBox) + && s2.contour.Curve.PtInCurve(p)) + { + s.SetParent(s2); + break; + } + } + } + + for (let j = contours.length; j--;) + { + let s = contours[j]; + if (s.parent) continue; + + s.Draw(verticesArray, uvArray, index === 1, this.allDepth * index); + } + } + } +} + +class Tape +{ + constructor( + public start: number, + public end: number, + + public bottom: number, + public top: number + ) + { + + } + + //用于测试 + get Curve() + { + return new Polyline().RectangleFrom2Pt(new Vector3(this.start, this.bottom), new Vector3(this.end, this.top)); + } + + Clip(t: this): Tape[] + { + let yr = IntersectRange(this.bottom, this.top, t.bottom, t.top, 1e5); + if (yr === undefined) return [this]; + + let xr = IntersectRange(this.start, this.end, t.start, t.end, 1e5); + if (xr === undefined) return [this]; + + let rem = SubtractRange(this.start, this.end, t.start, t.end, 1e5).map(r => + { + return new Tape(r[0], r[1], this.bottom, this.top); + }); + + let remR = SubtractRange(this.bottom, this.top, t.bottom, t.top, 1e5); + for (let hr of remR) + { + rem.push(new Tape(xr[0], xr[1], hr[0], hr[1])); + } + return rem; + } + + Split(xlst: number[]): Tape[] + { + let ret: Tape[] = []; + let pre = this.start; + for (let x of xlst) + { + if (x > pre) + { + if (x >= this.end) x = this.end; + if (equaln(pre, x)) continue; + ret.push(new Tape(pre, x, this.bottom, this.top)); + pre = x; + if (x === this.end) break; + } + } + return ret; + } + + ToPoints(): Vector2[] + { + return [ + new Vector2(this.start, this.bottom), + new Vector2(this.end, this.bottom), + new Vector2(this.end, this.top), + new Vector2(this.start, this.top), + ]; + } +} + +class CurveTapeShape +{ + children: CurveTapeShape[] = []; + contour: CurveTape; + holes: CurveTape[]; + constructor(contour: Contour, holes: Contour[]) + { + this.contour = new CurveTape(contour, DirectionType.Outer); + this.holes = holes.map(h => new CurveTape(h, DirectionType.Inner)); + } + + CloneNew() + { + let s = new CurveTapeShape(this.contour.contour, this.holes.map(h => h.contour)); + return s; + } + + /** + * 删除包含,同向 + */ + ClipTo(s: CurveTapeShape, append: boolean = false) + { + for (let c of [this.contour, ... this.holes]) + if (c.tapes.length > 0) + c.ClipTo(s); + + if (append) + { + let sn = s.CloneNew(); + sn.ReverseClipTo(this); + this.children.push(sn); + } + } + + //合理打断 + SplitTo(s: CurveTapeShape) + { + for (let c of [this.contour, ...this.holes]) + { + for (let c2 of [s.contour, ...s.holes]) + { + let int = c.contour.Curve.IntersectWith2(c2.contour.Curve, IntersectOption.OnBothOperands); + c.splitParams.push(...int.map(i => i.thisParam)); + } + } + } + + ReverseClipTo(s: CurveTapeShape): this + { + for (let c of [this.contour, ... this.holes]) + if (c.tapes.length > 0) + c.ReverseClipTo(s); + + return this; + } + + ChildrenClip() + { + for (let i = 0; i < this.children.length; i++) + { + let s1 = this.children[i]; + for (let j = i + 1; j < this.children.length; j++) + { + let s2 = this.children[j]; + + s1.ClipTo(s2, false); + s2.ClipTo(s1, false); + } + } + } + + Draw(verticesArray: number[], uvArray: number[], front: boolean, z: number) + { + this.ChildrenClip(); + + let polylines: Polyline[] = this.contour.Curves; + + for (let h of this.holes) + polylines.push(...h.Curves); + + for (let s of this.children) + { + polylines.push(...s.contour.Curves); + for (let h of s.holes) + polylines.push(...h.Curves); + } + + // TestDraw(polylines, z); + let groups = curveLinkGroup(polylines); + let contourTrees: ContourTree[] = []; + for (let cus of groups) + { + let c = Contour.CreateContour(cus, false); + if (c) + contourTrees.push(new ContourTree(c)); + else + console.error("出错"); + } + + contourTrees.sort((c1, c2) => c1.contour.Curve.Area - c2.contour.Curve.Area); + + for (let i = 0; i < contourTrees.length; i++) + { + const s = contourTrees[i]; + let p = s.contour.Curve.StartPoint; + for (let j = i + 1; j < contourTrees.length; j++) + { + const s2 = contourTrees[j]; + if (s2.contour.BoundingBox.intersectsBox(s.contour.BoundingBox) + && s2.contour.Curve.PtInCurve(p)) + { + s.SetParent(s2); + break; + } + } + } + + for (let j = contourTrees.length; j--;) + { + let s = contourTrees[j]; + // TestDraw(s.contour.Curve.Clone(), z); + if (s.parent) continue; + + s.Draw(verticesArray, uvArray, front, z); + } + } +} + +const SplitLength = 2; +function SplitCurveParams(cu: ExtureContourCurve): number[] +{ + let xparams: number[] = []; + if (cu instanceof Circle) + { + let splitCount = cu.Radius / SplitLength; + splitCount = clamp(Math.floor(splitCount), 8, 40); + for (let i = 0; i < splitCount; i++) + xparams.push(i / splitCount); + } + else + //分段1 + for (let i = 0; i < cu.EndParam; i++) + { + xparams.push(i); + if (cu.GetBuilgeAt(i) !== 0) + { + let arc = cu.GetCurveAtIndex(i) as Arc; + let splitCount = arc.Radius / SplitLength; + splitCount = clamp(Math.floor(splitCount), 8, 40); + if (splitCount === 0) continue; + + let a = Math.PI * 2 / splitCount; + let params: number[] = []; + for (let j = 0; j < splitCount; j++) + { + let param = arc.GetParamAtAngle(a * j); + if (arc.ParamOnCurve(param)) + params.push(param); + } + arraySortByNumber(params); + if (params.length === 0) continue; + + for (let p of params) + { + if (p > 1e-5 && p < 9.99999) + xparams.push(p + i); + } + } + } + xparams.push(cu.EndParam); + return xparams; +} + +class CurveTape +{ + type: DirectionType; + tapes: Range[]; + + splitParams: number[] = []; + constructor(public contour: Contour, public wallType: DirectionType) + { + this.tapes = [[0, this.contour.Curve.EndParam]]; + } + + get Curves(): Polyline[] + { + let xparams: number[] = SplitCurveParams(this.contour.Curve); + if (this.splitParams.length > 0) + { + xparams.push(...this.splitParams); + arraySortByNumber(xparams); + arrayRemoveDuplicateBySort(xparams, (p1, p2) => equaln(p1, p2)); + } + + let polylines: Polyline[] = []; + + function TD(p: Vector3) + { + return { + pt: AsVector2(p), bul: 0 + }; + } + + const addPolyline = (t: Range) => + { + let pts = [TD(this.contour.Curve.GetPointAtParam(t[0]))]; + for (let x of xparams) + { + if (x <= t[0]) continue; + if (x >= t[1]) break; + + pts.push(TD(this.contour.Curve.GetPointAtParam(x))); + } + pts.push(TD(this.contour.Curve.GetPointAtParam(t[1]))); + + let pl = new Polyline(pts); + polylines.push(pl); + }; + + for (let t of this.tapes) + { + if (t[0] > t[1]) + { + addPolyline([0, t[1]]); + addPolyline([t[0], this.contour.Curve.EndParam]); + } + else + addPolyline(t); + } + return polylines; + } + + Parse(s: CurveTapeShape): CurveRange + { + let [res1] = Parse(this.contour.Curve, s.contour.contour.Curve); + if (this.wallType === DirectionType.Inner) + [res1.syntropy, res1.reverse] = [res1.reverse, res1.syntropy]; + if (res1.container.length > 0) + { + for (let h of s.holes) + { + let [res2] = Parse(this.contour.Curve, h.contour.Curve); + if (this.wallType === DirectionType.Outer) + [res2.syntropy, res2.reverse] = [res2.reverse, res2.syntropy]; + + res1.syntropy.push(...res2.syntropy); + res1.reverse.push(...res2.reverse); + + res1.container = SubtractRanges(res1.container, res2.container, this.contour.Curve.EndParam); + res1.container = SubtractRanges(res1.container, res2.syntropy, this.contour.Curve.EndParam); + res1.container = SubtractRanges(res1.container, res2.reverse, this.contour.Curve.EndParam); + } + } + return res1; + } + + /** + * 删除包含,同向面 + */ + ClipTo(s: CurveTapeShape): this + { + let d = this.Parse(s); + + this.tapes = SubtractRanges(this.tapes, d.container, this.contour.Curve.EndParam); + this.tapes = SubtractRanges(this.tapes, d.syntropy, this.contour.Curve.EndParam); + + return this; + } + + /** + * 保留被包含的部分 + */ + ReverseClipTo(s: CurveTapeShape): this + { + let d = this.Parse(s); + this.tapes = d.container; + return this; + } +} + +export class ExtudeWall +{ + //胶带(立面) + Tape: Tape[]; + constructor(public curve: ExtureContourCurve, + public depthType: DepthType, + public depth: number, + public allDepth: number, + public wallType: DirectionType + ) + { + //一整段 + this.Tape = [CreateTape(depthType, 0, this.curve.EndParam, depth, allDepth)]; + } + + /** + * 裁剪 + * @param shape + * @param [clipSyntropy=false] 删除同向的面 + */ + Clip(shape: ExtudeWallShape, clipSyntropy = false) + { + let [res1, res2] = Parse(this.curve, shape.contour.curve); + if (this.wallType !== shape.contour.wallType) + [res1.syntropy, res1.reverse] = [res1.reverse, res1.syntropy]; + if (res1.container.length > 0) + { + for (let h of shape.holes) + { + let [resh1, resh2] = Parse(this.curve, h.curve); + + //翻转 + if (this.wallType !== h.wallType) + [resh1.syntropy, resh1.reverse] = [resh1.reverse, resh1.syntropy]; + + //删除在网洞内的 + let subParams: [number, number][]; + if (clipSyntropy) + subParams = resh1.container;//删除共面, + else + subParams = [...resh1.container, ...resh1.syntropy];//保留共面部分 + + for (let i of subParams) + { + let rems: [number, number][] = []; + for (let r of res1.container) + rems.push(...SubtractRange(r[0], r[1], i[0], i[1], this.curve.EndParam)); + res1.container = rems; + } + } + } + + let params = [...res1.container, ...res1.reverse]; + if (clipSyntropy) + params.push(...res1.syntropy); + + for (let c of params) + { + this.ClipFromParam(c[0], c[1], shape.depthType, shape.depth); + } + } + + ClipReverse(wall: this) + { + let [res1, res2] = Parse(this.curve, wall.curve); + for (let c of res1.syntropy) + this.ClipFromParam(c[0], c[1], wall.depthType, wall.depth); + } + + /** + * 当起始参数大于终止参数时,裁剪的区域经过终点 + * + * @param startParam 起始参数 + * @param endParam 终止参数 + * @param faceType 裁剪面朝向 + * @param depth 裁剪面的深度 + */ + ClipFromParam(startParam: number, endParam: number, faceType: DepthType, depth: number) + { + if (equaln(startParam, endParam)) return; + if (startParam > endParam) + { + this.ClipFromParam(startParam, this.curve.EndParam, faceType, depth); + this.ClipFromParam(0, endParam, faceType, depth); + return this; + } + + let subTape = CreateTape(faceType, startParam, endParam, depth, this.allDepth); + let taps: Tape[] = []; + for (let t of this.Tape) + taps.push(...t.Clip(subTape)); + + this.Tape = taps; + return this; + } + + Draw(verticesArray: number[], uvArray: number[], edgeBuild: EdgeGeometryBuild) + { + let xparams = SplitCurveParams(this.curve); + + function AddVertice(v: Vector3) + { + verticesArray.push(v.x); + verticesArray.push(v.y); + verticesArray.push(v.z); + } + for (let tape of this.Tape) + { + let tapes = tape.Split(xparams); + for (let t of tapes) + { + let p1 = this.curve.GetPointAtParam(t.start).setZ(t.bottom); + let p2 = this.curve.GetPointAtParam(t.end).setZ(t.bottom); + let vs = [p1, p2, p2.clone().setZ(t.top), p1.clone().setZ(t.top), p1]; + edgeBuild.AddLidLine(p1, p2, t.bottom); + edgeBuild.AddLidLine(p1, p2, t.top); + edgeBuild.AddEdgePolygon(vs); + + //和X平行平行 + let isXPar = (vs[0].y + vs[1].y + vs[2].y) < 0.01; + + function AddUv(p: Vector3) + { + if (isXPar) + uvArray.push((p.z - 1) * 1e-3, p.y * 1e-3); + else + uvArray.push((p.z - 1) * 1e-3, p.x * 1e-3); + } + if (this.wallType === DirectionType.Outer) + { + AddVertice(vs[0]); + AddUv(vs[0]); + AddVertice(vs[1]); + AddUv(vs[1]); + AddVertice(vs[2]); + AddUv(vs[2]); + + AddVertice(vs[0]); + AddUv(vs[0]); + AddVertice(vs[2]); + AddUv(vs[2]); + AddVertice(vs[3]); + AddUv(vs[3]); + } + else + { + AddVertice(vs[0]); + AddUv(vs[0]); + AddVertice(vs[2]); + AddUv(vs[2]); + AddVertice(vs[1]); + AddUv(vs[1]); + + AddVertice(vs[0]); + AddUv(vs[0]); + AddVertice(vs[3]); + AddUv(vs[3]); + AddVertice(vs[2]); + AddUv(vs[2]); + } + } + } + } +} + +interface CurveRange +{ + outer: Range[];//外部 + container: Range[];//被包含 + syntropy: Range[];//同向 + reverse: Range[];//反向 +} + +function CloneCurveRange(r: CurveRange): CurveRange +{ + return { + outer: r.outer.slice(), + container: r.container.slice(), + syntropy: r.syntropy.slice(), + reverse: r.reverse.slice(), + }; +} + +interface CurveSegs +{ + outer: Curve[];//外部 + container: Curve[];//被包含 + syntropy: Curve[];//同向 + reverse: Curve[];//反向 +} + +function binarySearch(ar: number[], el: number): number +{ + let m = 0; + let n = ar.length - 1; + while (m <= n) + { + let k = (n + m) >> 1; + let cmp = (el - ar[k]); + if (cmp > 1e8) + m = k + 1; + else if (cmp < -1e8) + n = k - 1; + else + return k; + } + return -m - 1; +} + +function CurveSplit(cu: Curve, range: CurveRange): CurveSegs +{ + let segs = { outer: [], container: [], syntropy: [], reverse: [] }; + + let ranges: Range[] = [...range.outer, ...range.container, ...range.syntropy, ...range.reverse]; + + ranges.sort((r1, r2) => r1[0] - r2[0]); + + let params: number[] = ranges.flat(); + arrayRemoveDuplicateBySort(params, (p1, p2) => equaln(p1, p2)); + let cus = cu.GetSplitCurves(params); + + for (let key in range) + { + for (let r of range[key]) + { + let i = binarySearch(params, r[0]); + segs[key].push(cus[i]); + } + } + + return segs; +} + +/** + * 分析两个曲线的状态 + * @param cu1 + * @param cu2 + * @param ins + * @returns + */ +function Parse(cu1: ExtureContourCurve, cu2: ExtureContourCurve, reverseParse = false): [CurveRange, CurveRange] +{ + let ins = cu1.IntersectWith2(cu2, IntersectOption.OnBothOperands); + + let c1Res: CurveRange = { container: [], syntropy: [], reverse: [], outer: [] }; + let c2Res: CurveRange = { container: [], syntropy: [], reverse: [], outer: [] }; + if (ins.length === 0) + { + if (cu2.PtInCurve(cu1.StartPoint)) + c1Res.container.push([0, cu1.EndParam]); + else + c1Res.outer.push([0, cu1.EndParam]); + + if (cu1.PtInCurve(cu2.StartPoint)) + c2Res.container.push([0, cu2.EndParam]); + else + c2Res.outer.push([0, cu2.EndParam]); + + return [c1Res, c2Res]; + } + + type CurveSeg = { + startParam: number; + endParam: number; + startPoint: Vector3; + endPoint: Vector3; + used?: boolean; + }; + + //解析出线段列表 + let c1Curves: CurveSeg[] = []; + let c2Curves: CurveSeg[] = []; + + ins.sort((a1, a2) => a1.thisParam - a2.thisParam); + for (let i = 0; i < ins.length; i++) + { + let n1 = ins[i]; + let n2 = ins[FixIndex(i + 1, ins)]; + c1Curves.push({ startParam: n1.thisParam, endParam: n2.thisParam, startPoint: n1.pt, endPoint: n2.pt }); + } + ins.sort((a1, a2) => a1.argParam - a2.argParam); + for (let i = 0; i < ins.length; i++) + { + let n1 = ins[i]; + let n2 = ins[FixIndex(i + 1, ins)]; + c2Curves.push({ startParam: n1.argParam, endParam: n2.argParam, startPoint: n1.pt, endPoint: n2.pt }); + } + + function IsNeighbor(c: CurveSeg, endParam: number): boolean + { + let a = c.startParam; + let b = c.endParam; + if (a > b) + b += endParam; + return b - a < 1.0001; + } + + //分析共边关系和包含关系 + for (let c of c1Curves) + { + if (IsNeighbor(c, cu1.EndParam)) + { + let c1CenParam = CenterParam(c.startParam, c.endParam, cu1.EndParam); + for (let c2 of c2Curves) + { + if (c2.used || !IsNeighbor(c2, cu2.EndParam)) + continue; + + let c2CenParam = CenterParam(c2.startParam, c2.endParam, cu2.EndParam); + + c.used = true; + if (c.startPoint === c2.startPoint + && c.endPoint === c2.endPoint + && equalv3(cu1.GetPointAtParam(c1CenParam), cu2.GetPointAtParam(c2CenParam)) + ) + { + c1Res.syntropy.push([c.startParam, c.endParam]); + c2Res.syntropy.push([c2.startParam, c2.endParam]); + c2.used = true; + break; + } + else if (c.startPoint === c2.endPoint + && c.endPoint === c2.startPoint + && equalv3(cu1.GetPointAtParam(c1CenParam), cu2.GetPointAtParam(c2CenParam)) + ) + { + c1Res.reverse.push([c.startParam, c.endParam]); + c2Res.reverse.push([c2.startParam, c2.endParam]); + c2.used = true; + break; + } + else + c.used = false; + } + } + + if (!c.used) + { + let p = cu1.GetPointAtParam(CenterParam(c.startParam, c.endParam, cu1.EndParam)); + if (cu2.PtInCurve(p)) + c1Res.container.push([c.startParam, c.endParam]); + else + c1Res.outer.push([c.startParam, c.endParam]); + } + } + + //只分析包含关系 + if (reverseParse) + for (let c of c2Curves) + { + if (c.used) continue; + let p = cu2.GetPointAtParam(CenterParam(c.startParam, c.endParam, cu2.EndParam)); + if (cu1.PtInCurve(p)) + c2Res.container.push([c.startParam, c.endParam]); + else + c2Res.outer.push([c.startParam, c.endParam]); + } + + return [c1Res, c2Res]; +} + +function CenterParam(start: number, end: number, all: number) +{ + if (end > start) + return (end + start) * 0.5; + + let sum = (all - start + end) * 0.5 + start; + if (sum > all) return sum - all; + return sum; +} + + +//求参数并集部分,交集部分,差集部分 + +//求 ab 和 cd 的并集部分 +function UnionRange(a: number, b: number, c: number, d: number, end: number): [number, number][] +{ + let b1 = b < a ? b + end : b; + let d1 = d < c ? d + end : d; + let a1 = a; + let c1 = c; + + if (c < a) + [a1, b1, c1, d1] = [c1, d1, a1, b1]; + + if (c1 > b1) + return [[a, b], [c, d]]; + + let e = Math.max(b1, d1); + if (e >= end) + { + e -= end; + if (e > a1) + return [[0, end]]; + } + + return [[a1, e]]; +} + +// //0-1 +// UnionRange(0.5, 0.3, 0.3, 0.5, 1);//? + +// //0-1 +// UnionRange(0.4, 0.3, 0.3, 0.5, 1);//? + +// //[ [ 0.8, 0.1 ], [ 0.3, 0.5 ] ] +// UnionRange(0.8, 0.1, 0.3, 0.5, 1);//? + +// //[ 0.3, 0.10000000000000009 ] ]  +// UnionRange(0.8, 0.1, 0.3, 0.9, 1);//? + +function SubtractRange(a: number, b: number, c: number, d: number, end: number): Range[] +{ + if (a > b) + return [...SubtractRange(a, end, c, d, end), ...SubtractRange(0, b, c, d, end)]; + if (c > d) + { + let arr = SubtractRange(a, b, c, end, end); + let rem: [number, number][] = []; + for (let s of arr) + rem.push(...SubtractRange(s[0], s[1], 0, d, end)); + return rem; + } + + if (c >= b || d <= a) + return [[a, b]]; + + if (c <= a)// c1 a1 b1 + { + if (d >= b) return []; + return [[d, b]]; + } + + if (d < b) + return [[a, c], [d, b]]; + return [[a, c]]; +} + +function SubtractRange2(r: Range, sr: Range, end: number): Range[] +{ + return SubtractRange(r[0], r[1], sr[0], sr[1], end); +} + +type Range = [number, number]; +function SubtractRanges(ranges: Range[], subRanges: Range[], end: number): Range[] +{ + let rets: Range[] = ranges; + for (let sr of subRanges) + { + let temps: Range[] = []; + for (let r of rets) + temps.push(...SubtractRange2(r, sr, end)); + + rets = temps; + } + return rets; +} + +function IntersectRange(a: number, b: number, c: number, d: number, end: number): Range +{ + let b1 = b < a ? b + end : b; + let d1 = d < c ? d + end : d; + let a1 = a; + let c1 = c; + + if (c < a) + [a1, b1, c1, d1] = [c1, d1, a1, b1]; + + if (c1 > b1) + return; + + return [c1, Math.min(b1, d1)]; +} + +export class ExtrudeGeometryBuilder +{ + brOcsInv: Matrix4; + alMatrix4: Matrix4 = new Matrix4; + + contour: Contour; + + shape: TShape; + + shapes: ExtudeWallShape[] = []; + + verticesArray: number[] = []; + uvArray: number[] = []; + + edgeAndLidBuilder: EdgeGeometryBuild; + + constructor(private br: ExtrudeSolid) + { + this.edgeAndLidBuilder = new EdgeGeometryBuild(this.br.Thickness); + this.brOcsInv = br.OCSInv; + this.contour = Contour.CreateContour(br.ContourCurve.Clone()); + + this.shape = GetShape(this.contour.Curve); + + this.ParseGrooves(); + + //计算墙 + let outerWall = new ExtudeWall(this.contour.Curve, DepthType.All, br.Thickness, br.Thickness, DirectionType.Outer); + for (let i = 0; i < this.shapes.length; i++) + { + let s1 = this.shapes[i]; + outerWall.Clip(s1, false); + s1.contour.ClipReverse(outerWall); + for (let j = i + 1; j < this.shapes.length; j++) + { + let s2 = this.shapes[j]; + s1.ClipWall(s2, true); + } + + s1.Draw(this.verticesArray, this.uvArray, this.edgeAndLidBuilder); + } + outerWall.Draw(this.verticesArray, this.uvArray, this.edgeAndLidBuilder); + + this.edgeAndLidBuilder.BuildLid(this.verticesArray, this.uvArray); + } + + get MeshGeometry() + { + let geo = new BufferGeometry(); + geo.setAttribute('position', new Float32BufferAttribute(this.verticesArray, 3)); + geo.setAttribute('uv', new Float32BufferAttribute(this.uvArray, 2)); + geo.computeVertexNormals(); + return geo; + } + + get EdgeGeometry() + { + let geo = new BufferGeometry(); + geo.setAttribute('position', new Float32BufferAttribute(this.edgeAndLidBuilder.verticesArray, 3)); + return geo; + } + + private ParseGrooves() + { + let br = this.br; + for (let g of br.Grooves) + { + //判断槽正反面 + let type: DepthType; + if (equaln(g.Thickness, br.Thickness)) + type = DepthType.All; + else + { + if (equaln(g.Position.applyMatrix4(this.brOcsInv).z, 0)) + type = DepthType.Back; + else + type = DepthType.Front; + } + this.alMatrix4.multiplyMatrices(this.brOcsInv, g.OCSNoClone); + //槽轮廓 + let gContour = g.ContourCurve.Clone(); + gContour.ApplyMatrix(this.alMatrix4); + gContour.Z0(); + gContour.TempData = g.Thickness; + if (gContour instanceof Polyline) gContour.UpdateMatrixTo(IdentityMtx4);//不可能改变这个 + let contour = Contour.CreateContour(gContour); + + let holes: Contour[] = []; + //孤岛 + for (let gg of g.Grooves) + { + let c = gg.ContourCurve.Clone(); + this.alMatrix4.multiplyMatrices(this.brOcsInv, gg.OCSNoClone); + c.ApplyMatrix(this.alMatrix4).Z0(); + c.TempData = g.Thickness; + if (c instanceof Polyline) c.UpdateMatrixTo(IdentityMtx4); + let contour = Contour.CreateContour(c); + holes.push(contour); + } + + this.shapes.push(new ExtudeWallShape(contour, holes, type, g.Thickness, br.Thickness)); + } + } +} diff --git a/src/Geometry/GenerateExtrudeGeometry.ts b/src/Geometry/GenerateExtrudeGeometry.ts new file mode 100644 index 000000000..4910988b1 --- /dev/null +++ b/src/Geometry/GenerateExtrudeGeometry.ts @@ -0,0 +1,200 @@ +import { Matrix4, Shape as TShape } from "three"; +import { Contour } from "../DatabaseServices/Contour"; +import { Circle } from "../DatabaseServices/Entity/Circle"; +import { Curve } from "../DatabaseServices/Entity/Curve"; +import { ExtrudeSolid, ExtureContourCurve } from "../DatabaseServices/Entity/Extrude"; +import { Polyline } from "../DatabaseServices/Entity/Polyline"; +import { equaln } from "./GeUtils"; + +/* +1.绘制正反面 + +2.绘制槽的面 + +3.绘制侧面 + +*/ + + +export class GenMeshGeom +{ + brOcsInv: Matrix4; + alMatrix4: Matrix4 = new Matrix4; + + //网洞 + frontHoleCurves: ExtureContourCurve[] = []; + backHoleCurves: ExtureContourCurve[] = []; + + //孤岛 + frontIslandCurves: ExtureContourCurve[] = []; + backIslandCurves: ExtureContourCurve[] = []; + + constructor(private br: ExtrudeSolid) + { + this.brOcsInv = br.OCSInv; + + this.InitHoles(br); + + //合并网洞 + let frontCurveContours = this.frontHoleCurves.map(c => Contour.CreateContour(c as Polyline)); + let backCurveContours = this.backHoleCurves.map(c => Contour.CreateContour(c as Polyline)); + let frontHoleContours: Contour[] = []; + for (let i = 0; i < frontCurveContours.length; i++) + { + let c1 = frontCurveContours[i]; + if (isNaN(c1.Curve.TempData)) continue;//已使用 + for (let j = i + 1; j < frontCurveContours.length; j++) + { + let c2 = frontCurveContours[j]; + if (isNaN(c2.Curve.TempData)) continue; + if (!c1.BoundingBox.intersectsBox(c2.BoundingBox)) continue; + if (equaln(c1.Curve.TempData, c2.Curve.TempData)) continue;//同深度的网洞不需要求交 + + let cs = c1.UnionBoolOperation(c2); + if (cs.length === 1) + { + c1 = cs[0]; + c2.Curve.TempData = NaN;//已使用 + c1.Curve.TempData = NaN;//和同类相残 + j = i;//从下一个开始 + } + } + frontHoleContours.push(c1); + } + + let contourShape = br.ContourCurve.Shape; + let verticesArray: number[] = []; + + //draw front + contourShape.holes = frontHoleContours.map(c => + { + let gContour = c.Curve; + if (gContour instanceof Polyline) + gContour.UpdateMatrixTo(br.ContourCurve.OCS); + + let sp: TShape; + if (gContour instanceof Circle) + { + sp = new TShape(); + let cen = gContour.Center.applyMatrix4(this.brOcsInv); + sp.ellipse(cen.x, cen.y, gContour.Radius, gContour.Radius, 0, 2 * Math.PI, false, 0); + } + else + sp = gContour.Shape; + + return sp; + }); + } + + private InitHoles(br: ExtrudeSolid) + { + for (let g of br.Grooves) + { + //判断槽正反面 + let back = false; + let front = false; + if (equaln(g.Thickness, br.Thickness)) + { + back = true; + front = true; + } + else + { + if (equaln(g.Position.applyMatrix4(this.brOcsInv).z, 0)) + back = true; + else + front = true; + } + this.alMatrix4.multiplyMatrices(this.brOcsInv, g.OCSNoClone); + //槽轮廓 + let gContour = g.ContourCurve.Clone(); + gContour.ApplyMatrix(this.alMatrix4); + gContour.Z0(); + gContour.TempData = g.Thickness; + if (back) + this.backHoleCurves.push(gContour); + if (front) + this.frontHoleCurves.push(gContour); + //孤岛 + for (let gg of g.Grooves) + { + let c = gg.ContourCurve.Clone(); + this.alMatrix4.multiplyMatrices(this.brOcsInv, gg.OCSNoClone); + c.ApplyMatrix(this.alMatrix4).Z0(); + c.TempData = g.Thickness; + if (back) + this.backIslandCurves.push(c); + if (front) + this.frontIslandCurves.push(c); + } + } + } +} + +enum ContourFace +{ + Front = 1, + Back = 2, + All = 3, +} + +interface OperatorData +{ + //外部 + outer: Curve[]; + //被包含 + beContainer: Curve[]; + //共线 + collineation: Curve[]; +} + + +/** + * 轮廓曲线 + * + * 板件轮廓与所有非全深槽的外轮廓进行计算 + */ +class ContourCurveWrap +{ + static Thickness: number = 1; + + /** + * @param curve + * @param face 正面,反面,全深 + * @param depth + * @param [isOuter=false] 外面(孤岛和板件轮廓) + */ + constructor( + public curve: ExtureContourCurve, + public face: ContourFace, + public depth: number, + public isOuter = false, + // public isBrContour = false, + public contour = Contour.CreateContour(curve) + ) + { + } + + /** + * 和轮廓进行求交,记录轮廓的关系 + * + * 轮廓间关系:分离,包含,共线 + * + * 分离:分离部分都需要绘制面 + * 包含:共同方向的部分不绘制 + * 共线:共同方向的包含只绘制一次,相反方向的面则取消绘制 + */ + Operator(c: ContourCurveWrap) + { + if (c.face === this.face //面相同 + && equaln(this.depth, c.depth) && this.isOuter === c.isOuter)//深度相同 + return; + + if ((c.face & this.face) === 0 //没有全深槽 + && c.face !== this.face //面相反 + && this.depth + c.depth < ContourCurveWrap.Thickness)//不可能相交 + return; + + + } +} diff --git a/src/GraphicsSystem/OffsetPolyline.ts b/src/GraphicsSystem/OffsetPolyline.ts index e9304bd4d..225bfbcbc 100644 --- a/src/GraphicsSystem/OffsetPolyline.ts +++ b/src/GraphicsSystem/OffsetPolyline.ts @@ -172,6 +172,7 @@ export class OffsetPolyline this._Polyline.OCS = IdentityMtx4; this._SubCurves = this._Polyline.Explode().filter(c => c.Length > 1e-4); this._Polyline.OCS = this._CacheOCS; + return this; } protected GeneralCirclesAndVertexs()