build-dxf 0.0.18 → 0.0.19-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +30 -0
  2. package/package.json +1 -3
  3. package/src/build.d.ts +10 -1
  4. package/src/build.js +555 -471
  5. package/src/components/Editor.vue.d.ts +26 -0
  6. package/src/index.js +3 -2
  7. package/src/index2.js +373 -3426
  8. package/src/index3.js +1937 -0
  9. package/src/pages/Editor.vue.d.ts +2 -0
  10. package/src/pages/Editor02.vue.d.ts +4 -0
  11. package/src/selectLocalFile.js +3745 -0
  12. package/src/utils/CommandManager/CommandFlow.d.ts +23 -0
  13. package/src/utils/CommandManager/CommandManager.d.ts +59 -0
  14. package/src/utils/CommandManager/index.d.ts +2 -0
  15. package/src/utils/ComponentManager/EventDispatcher.d.ts +11 -1
  16. package/src/utils/DxfSystem/components/Dxf.d.ts +15 -12
  17. package/src/utils/DxfSystem/components/LineAnalysis.d.ts +1 -20
  18. package/src/utils/DxfSystem/components/Variable.d.ts +8 -0
  19. package/src/utils/DxfSystem/plugin/Editor/components/CommandFlow/CommandFlowComponent.d.ts +36 -0
  20. package/src/utils/DxfSystem/plugin/Editor/components/CommandFlow/Default.d.ts +57 -0
  21. package/src/utils/DxfSystem/plugin/Editor/components/CommandFlow/DrawDoorLine.d.ts +19 -0
  22. package/src/utils/DxfSystem/plugin/Editor/components/CommandFlow/DrawLine.d.ts +20 -0
  23. package/src/utils/DxfSystem/plugin/Editor/components/CommandFlow/DrawWindow.d.ts +25 -0
  24. package/src/utils/DxfSystem/plugin/Editor/components/CommandFlow/PointDrag.d.ts +27 -0
  25. package/src/utils/DxfSystem/plugin/Editor/components/Editor.d.ts +22 -3
  26. package/src/utils/DxfSystem/plugin/Editor/components/RenderManager.d.ts +88 -0
  27. package/src/utils/DxfSystem/plugin/Editor/components/index.d.ts +6 -0
  28. package/src/utils/DxfSystem/plugin/Editor/pages/EditorTool.vue.d.ts +6 -0
  29. package/src/utils/DxfSystem/plugin/ModelDataPlugin/components/DxfLineModel.d.ts +7 -3
  30. package/src/utils/DxfSystem/plugin/ModelDataPlugin/index.d.ts +9 -1
  31. package/src/utils/DxfSystem/plugin/RenderPlugin/components/DomContainer.d.ts +1 -0
  32. package/src/utils/DxfSystem/plugin/RenderPlugin/components/DomEventRegister.d.ts +20 -1
  33. package/src/utils/DxfSystem/plugin/RenderPlugin/components/EventInput.d.ts +74 -0
  34. package/src/utils/DxfSystem/plugin/RenderPlugin/components/Renderer.d.ts +0 -11
  35. package/src/utils/DxfSystem/plugin/RenderPlugin/components/index.d.ts +1 -0
  36. package/src/utils/DxfSystem/plugin/RenderPlugin/index.d.ts +11 -1
  37. package/src/utils/PointVirtualGrid/index.d.ts +10 -4
  38. package/src/utils/Quadtree/Box2.d.ts +3 -2
  39. package/src/utils/Quadtree/LineSegment.d.ts +11 -9
  40. package/src/utils/Quadtree/Point.d.ts +11 -6
  41. package/src/utils/Quadtree/Quadtree.d.ts +5 -0
  42. package/src/utils/Quadtree/Rectangle.d.ts +5 -4
package/src/build.js CHANGED
@@ -12,6 +12,35 @@ function uuid() {
12
12
  }
13
13
  class EventDispatcher extends EventDispatcher$1 {
14
14
  uuid = uuid();
15
+ addEventListener(type, listener, option) {
16
+ const { once = false } = option ?? {};
17
+ const callBack = (event) => {
18
+ listener(event);
19
+ once && canceCallBack();
20
+ };
21
+ const canceCallBack = () => this.removeEventListener(type, callBack);
22
+ super.addEventListener(type, callBack);
23
+ return canceCallBack;
24
+ }
25
+ eventRecordStack = /* @__PURE__ */ new Map();
26
+ addEventRecord(name, ...cancels) {
27
+ if (!this.eventRecordStack.has(name)) this.eventRecordStack.set(name, []);
28
+ cancels.forEach((cancel) => {
29
+ this.eventRecordStack.get(name)?.push(cancel);
30
+ });
31
+ const add = (cancel) => {
32
+ this.addEventRecord(name, cancel);
33
+ return { add };
34
+ };
35
+ return { add };
36
+ }
37
+ canceEventRecord(name) {
38
+ const list = this.eventRecordStack.get(name);
39
+ if (list) {
40
+ list.forEach((cancel) => cancel());
41
+ this.eventRecordStack.delete(name);
42
+ }
43
+ }
15
44
  }
16
45
  class Component extends EventDispatcher {
17
46
  parent;
@@ -119,6 +148,7 @@ class Point {
119
148
  get Y() {
120
149
  return this.y;
121
150
  }
151
+ userData = {};
122
152
  /**
123
153
  *
124
154
  * @param x
@@ -333,6 +363,12 @@ class Point {
333
363
  this.x = p.x ?? 0;
334
364
  this.y = p.y ?? 0;
335
365
  }
366
+ toJson() {
367
+ return {
368
+ x: this.x,
369
+ y: this.y
370
+ };
371
+ }
336
372
  static from(arr) {
337
373
  if (Array.isArray(arr)) {
338
374
  return new Point(arr[0], arr[1]);
@@ -564,12 +600,19 @@ class Box2 {
564
600
  this.maxY *= scalar;
565
601
  return this;
566
602
  }
603
+ expansion(w) {
604
+ this.minX -= w;
605
+ this.minY -= w;
606
+ this.maxX += w;
607
+ this.maxY += w;
608
+ return this;
609
+ }
567
610
  /**
568
611
  *
569
612
  * @returns
570
613
  */
571
614
  clone() {
572
- return new Box2(this.minX, this.minY, this.maxX, this.maxY);
615
+ return new Box2(this.minX, this.maxX, this.minY, this.maxY);
573
616
  }
574
617
  /**
575
618
  *
@@ -617,6 +660,16 @@ class Rectangle {
617
660
  return [p.x, p.y, np.x, np.y];
618
661
  });
619
662
  }
663
+ createGeometry() {
664
+ return [
665
+ this.p0,
666
+ this.p2,
667
+ this.p1,
668
+ this.p2,
669
+ this.p0,
670
+ this.p3
671
+ ].flatMap((p) => [p.x, p.y, 0]);
672
+ }
620
673
  constructor(points) {
621
674
  if (points.length !== 4) {
622
675
  throw new Error("Rectangle must be defined by exactly 4 points");
@@ -781,6 +834,7 @@ class Rectangle {
781
834
  class LineSegment {
782
835
  points = [new Point(), new Point()];
783
836
  userData = {};
837
+ line;
784
838
  get center() {
785
839
  return new Point(
786
840
  this.points[0].x + (this.points[1].x - this.points[0].x) * 0.5,
@@ -937,11 +991,12 @@ class LineSegment {
937
991
  return new LineSegment(projP1, projP2);
938
992
  }
939
993
  /**
940
- * 计算一条线段在另一条直线上的投影,并裁剪超出目标线段的部分
941
- * @param line 要投影的线段
994
+ * 计算一条线段在另一条直线上的投影
995
+ * @param p1 要投影的点
996
+ * @param clip 是否裁剪超出目标线段的部分,默认裁剪
942
997
  * @returns 投影并裁剪后的线段
943
998
  */
944
- projectPoint(p1) {
999
+ projectPoint(p1, clip = true) {
945
1000
  const [q1, q2] = this.points;
946
1001
  const dir = new Point(q2.x - q1.x, q2.y - q1.y);
947
1002
  if (dir.x === 0 && dir.y === 0) {
@@ -957,6 +1012,7 @@ class LineSegment {
957
1012
  return new Point(projX, projY);
958
1013
  };
959
1014
  let projP1 = projectPoint(p1);
1015
+ if (!clip) return projP1;
960
1016
  const getT = (point) => {
961
1017
  const pq = new Point(point.x - q1.x, point.y - q1.y);
962
1018
  const dirLengthSquared = dir.x * dir.x + dir.y * dir.y;
@@ -1199,13 +1255,13 @@ class Dxf extends Component {
1199
1255
  this.originalData = data;
1200
1256
  this.lineSegments.length = 0;
1201
1257
  const zList = [];
1202
- this.data = data.map(({ start, end, insetionArr, isDoor = false, isWindow }, index2) => {
1258
+ this.data = data.map(({ start, end, insetionArr, isDoor = false, isWindow, drawDoorData }, index2) => {
1203
1259
  zList.push(start.z ?? 0, end.z ?? 0);
1204
1260
  const lineSegment = new LineSegment(
1205
1261
  Point.from(start).mutiplyScalar(scale),
1206
1262
  Point.from(end).mutiplyScalar(scale)
1207
1263
  );
1208
- lineSegment.userData = { isDoor, isWindow };
1264
+ lineSegment.userData = { isDoor, isWindow, drawDoorData };
1209
1265
  this.lineSegments.push(lineSegment);
1210
1266
  return [
1211
1267
  lineSegment.points[0],
@@ -1470,14 +1526,14 @@ class Dxf extends Component {
1470
1526
  /**
1471
1527
  * 将点云结构转换为Float32Array
1472
1528
  */
1473
- to3DArray(scale) {
1529
+ to3DArray(scale, z = this.originalZAverage) {
1474
1530
  const array = [];
1475
1531
  this.wallsGroup.forEach((points) => {
1476
1532
  for (let i = 0; i < points.length; i++) {
1477
1533
  const point1 = points[i];
1478
1534
  const nextIndex = i === points.length - 1 ? 0 : i + 1;
1479
1535
  const point2 = points[nextIndex];
1480
- array.push(point1.X * scale, point1.Y * scale, this.originalZAverage, point2.X * scale, point2.Y * scale, this.originalZAverage);
1536
+ array.push(point1.X * scale, point1.Y * scale, z, point2.X * scale, point2.Y * scale, z);
1481
1537
  }
1482
1538
  });
1483
1539
  return new Float32Array(array);
@@ -1562,6 +1618,20 @@ class Dxf extends Component {
1562
1618
  });
1563
1619
  d.addLayer("l_yellow", Drawing.ACI.YELLOW, "DOTTED");
1564
1620
  d.setActiveLayer("l_yellow");
1621
+ this.lineSegments.forEach((line) => {
1622
+ if (!line.userData.isWindow) return false;
1623
+ if (Array.isArray(line.userData.drawDoorData)) {
1624
+ line.userData.drawDoorData.forEach((w) => {
1625
+ const { p, width } = w;
1626
+ const center = Point.from(p);
1627
+ const start = center.clone().add(line.direction().multiplyScalar(width * 0.5));
1628
+ const end = center.clone().add(line.direction().multiplyScalar(-width * 0.5));
1629
+ const blinds = new LineSegment(start, end);
1630
+ drawLine(blinds.start, blinds.end);
1631
+ blinds.expandToRectangle(this.width, "bothSides").path2D((p1, p2) => drawLine(p1, p2));
1632
+ });
1633
+ }
1634
+ });
1565
1635
  return d.toDxfString();
1566
1636
  }
1567
1637
  /**
@@ -1644,6 +1714,10 @@ class Variable extends Component {
1644
1714
  currentWheel = 0;
1645
1715
  pointerMove = { x: 0, y: 0 };
1646
1716
  currentKeyUp = "";
1717
+ currentKeyDown = "";
1718
+ currentMouseUp = "";
1719
+ currentMouseDown = "";
1720
+ focus = false;
1647
1721
  set(key, value) {
1648
1722
  if (key in this) {
1649
1723
  const oldValue = this[key];
@@ -1695,6 +1769,7 @@ class Quadtree {
1695
1769
  }
1696
1770
  }
1697
1771
  this.nodes.push(node);
1772
+ node.parent = this;
1698
1773
  if (this.isLeaf && this.nodes.length > this.capacity && this.depth < this.maxDepth) {
1699
1774
  this.subdivide();
1700
1775
  const nodes = this.nodes;
@@ -1704,11 +1779,21 @@ class Quadtree {
1704
1779
  if (quadrant !== -1) {
1705
1780
  this.children[quadrant].insert(n);
1706
1781
  } else {
1782
+ n.parent = this;
1707
1783
  this.nodes.push(n);
1708
1784
  }
1709
1785
  }
1710
1786
  }
1711
1787
  }
1788
+ /** 移除
1789
+ * @param node
1790
+ */
1791
+ remove(node) {
1792
+ const index2 = node.parent?.nodes.indexOf(node);
1793
+ if (index2 > -1) {
1794
+ node.parent?.nodes.splice(index2, 1);
1795
+ }
1796
+ }
1712
1797
  /**
1713
1798
  * 获取线段所属的象限
1714
1799
  * @param line 线段
@@ -1915,7 +2000,9 @@ class PointVirtualGrid {
1915
2000
  const id = this.getGridId(point);
1916
2001
  if (!this.map.has(id)) this.map.set(id, /* @__PURE__ */ new Set());
1917
2002
  const set = this.map.get(id);
1918
- set?.add({ point, userData });
2003
+ const target = { point, userData };
2004
+ set.add(target);
2005
+ point.userData.pointVirtualGrid = { set, target };
1919
2006
  }
1920
2007
  /**
1921
2008
  * 批量加入
@@ -1926,6 +2013,16 @@ class PointVirtualGrid {
1926
2013
  this.insert(point, userData);
1927
2014
  }
1928
2015
  }
2016
+ /** 移除点
2017
+ * @param point
2018
+ */
2019
+ remove(point) {
2020
+ const { set, target } = point?.userData?.pointVirtualGrid;
2021
+ if (set) {
2022
+ set.delete(target);
2023
+ delete point?.userData?.pointVirtualGridMap;
2024
+ }
2025
+ }
1929
2026
  /**
1930
2027
  * 获取通过坐标,获取唯一网格索引
1931
2028
  * @param point
@@ -2018,219 +2115,167 @@ class PointVirtualGrid {
2018
2115
  return list;
2019
2116
  }
2020
2117
  }
2021
- class LineAnalysis extends Component {
2022
- static name = "LineAnalysis";
2023
- Dxf = null;
2024
- Variable = null;
2025
- lineSegmentList = [];
2026
- container = new THREE.Group();
2027
- // 误差角度
2028
- errorAngle = 4;
2029
- width = 0.4;
2030
- /**
2031
- *
2032
- * @param parent
2033
- */
2034
- onAddFromParent(parent) {
2035
- this.Dxf = parent.findComponentByType(Dxf);
2036
- this.Variable = this.parent?.findComponentByType(Variable);
2037
- this.Dxf.addEventListener("setDta", this.lineAnalysis.bind(this));
2038
- this.Dxf.addEventListener("createGroup", this.doorsAnalysis.bind(this));
2039
- }
2040
- /**
2041
- *
2042
- * @param p1
2043
- * @param p2
2044
- * @param width
2045
- * @returns
2046
- */
2047
- expandLineSegment(p1, p2, width = 0.1) {
2048
- const normal = p2.normal(p1);
2049
- const pDirect = p2.direction(p1).mutiplyScalar(width * 0.5);
2050
- const nDirect = p1.direction(p2).mutiplyScalar(width * 0.5);
2051
- const offsetX = normal.x * width * 0.5;
2052
- const offsetY = normal.y * width * 0.5;
2053
- return {
2054
- points: [
2055
- // 第一条线
2056
- new Point(p1.x + offsetX, p1.y + offsetY).add(nDirect),
2057
- new Point(p2.x + offsetX, p2.y + offsetY).add(pDirect),
2058
- // 第二条线
2059
- new Point(p1.x - offsetX, p1.y - offsetY).add(nDirect),
2060
- new Point(p2.x - offsetX, p2.y - offsetY).add(pDirect)
2061
- ],
2062
- indices: [0, 1, 1, 3, 3, 2, 2, 0],
2063
- rectIndices: [0, 1, 3, 2, 0]
2064
- };
2065
- }
2066
- appendLineSegmentList = [];
2067
- /**
2068
- * 追加数据
2069
- * @param p1
2070
- * @param p2
2071
- */
2072
- addData(p1, p2) {
2073
- const dxf = this.Dxf;
2074
- dxf.data.push([p1.clone(), p2.clone(), [], false, dxf.data.length]);
2075
- this.appendLineSegmentList.push(new LineSegment(p1.clone(), p2.clone()));
2076
- }
2077
- /** 结果分析创建矩形
2078
- * @param result
2079
- */
2080
- createRectangle(result) {
2081
- const dxf = this.Dxf;
2082
- const project0 = result.project, project1 = result.project2;
2083
- if (project0.includedAngle(project1) > 135) {
2084
- project1.points = [project1.points[1], project1.points[0]];
2085
- }
2086
- this.addData(project0.points[0], project1.points[0]);
2087
- this.addData(project0.points[1], project1.points[1]);
2088
- const leftHeight = project0.points[0].distance(project1.points[0]), rightHeight = project0.points[1].distance(project1.points[1]), count = Math.ceil(Math.max(leftHeight, rightHeight) / dxf.width), leftFragment = leftHeight / count, rightFragment = rightHeight / count, leftDirection = project1.points[0].direction(project0.points[0]), rightDirection = project1.points[1].direction(project0.points[1]), leftP = project0.points[0].clone(), rightP = project0.points[1].clone(), direction = rightP.direction(leftP);
2089
- direction.multiplyScalar(dxf.width * 0.5);
2090
- const _leftP = leftP.clone().add(direction), _rightP = rightP.clone().add(direction.multiplyScalar(-1)), d1 = leftP.direction(rightP), d2 = _leftP.direction(_rightP);
2091
- if (d1.x > 0 && d2.x < 0 || d1.x < 0 && d2.x > 0 || d1.y > 0 && d2.y < 0 || d1.y < 0 && d2.y > 0) return;
2092
- leftP.set(_leftP.x, _leftP.y);
2093
- rightP.set(_rightP.x, _rightP.y);
2094
- for (let i = 1; i < count; i++) {
2095
- const left = leftDirection.clone().multiplyScalar(leftFragment * i), right = rightDirection.clone().multiplyScalar(rightFragment * i), p1 = leftP.clone().add(left), p2 = rightP.clone().add(right);
2096
- this.addData(p1, p2);
2097
- }
2098
- }
2118
+ class DoorsAnalysis {
2119
+ // 所有可查找的点位
2120
+ possibleDoorPoints = [];
2121
+ doorPoint = [];
2122
+ dxf;
2123
+ // 包含所有点的虚拟网格
2099
2124
  pointVirtualGrid = new PointVirtualGrid();
2100
- /**
2101
- * 构建点的虚拟网格索引
2102
- */
2103
- buildVirtualGrid() {
2104
- const dxf = this.Dxf;
2105
- const pointVirtualGrid = new PointVirtualGrid();
2106
- dxf.lineSegments.forEach((d, index2) => {
2107
- if (d.userData?.isDoor) return;
2108
- const [p1, p2] = [d.start, d.end];
2109
- pointVirtualGrid.insert(p1, { index: index2, type: "start" });
2110
- pointVirtualGrid.insert(p2, { index: index2, type: "end" });
2125
+ // 只包含可查找点的虚拟网格
2126
+ findPointVirtualGrid;
2127
+ quadtree;
2128
+ resultList;
2129
+ // 已过滤门的线段
2130
+ lineSegments;
2131
+ doorSearchNearAngle = 110;
2132
+ doorSearchDistance = 2;
2133
+ doors = [];
2134
+ lineAnalysis;
2135
+ continueFind = true;
2136
+ constructor(lineAnalysis) {
2137
+ this.lineAnalysis = lineAnalysis;
2138
+ this.dxf = lineAnalysis.Dxf;
2139
+ this.findPointVirtualGrid = new PointVirtualGrid();
2140
+ this.quadtree = lineAnalysis.quadtree;
2141
+ this.resultList = lineAnalysis.resultList;
2142
+ this.lineSegments = lineAnalysis.lineSegmentList;
2143
+ this.dxf.doorLineSegment.length = 0;
2144
+ this.lineSegments.forEach((line) => {
2145
+ this.pointVirtualGrid.insert(line.start, line);
2146
+ this.pointVirtualGrid.insert(line.end, line);
2147
+ });
2148
+ this.doorPoint = this.getDoorPoint();
2149
+ if (!this.continueFind) return;
2150
+ const excludeIndexMap = this.searchDoubleLinePoint();
2151
+ this.addPointsExcludeRule((line, _2, pointIndex) => {
2152
+ const index2 = this.lineSegments.indexOf(line);
2153
+ const excludeMode = excludeIndexMap.get(index2);
2154
+ if (typeof excludeMode === "number") {
2155
+ return excludeMode === -1 || excludeMode === pointIndex;
2156
+ }
2157
+ return false;
2158
+ });
2159
+ this.addPointsExcludeRule((_1, point) => {
2160
+ return !!this.doorPoint.find((p1) => p1.point.equal(point));
2161
+ });
2162
+ this.possibleDoorPoints = this.getPossiblePoints();
2163
+ this.possibleDoorPoints.forEach((p) => this.findPointVirtualGrid.insert(p.point, p.line));
2164
+ this.handle();
2165
+ }
2166
+ handle() {
2167
+ this.dxf.doorLineSegment.push(...this.search(this.doorPoint, this.possibleDoorPoints, 0.5));
2168
+ if (this.doorPoint.length < 2) this.dxf.doorLineSegment.push(...this.search(this.possibleDoorPoints, this.possibleDoorPoints, 0.6));
2169
+ }
2170
+ search(doorPoints, possibleDoorPoints = [], minDoorWidth = 0.6, doorSearchDistance = this.doorSearchDistance, doorSearchNearAngle = this.doorSearchNearAngle) {
2171
+ const dxf = this.dxf;
2172
+ const doors = this.searchNearby(doorPoints, possibleDoorPoints, doorSearchDistance, doorSearchNearAngle);
2173
+ doors.push(
2174
+ ...doorPoints.map((item) => {
2175
+ const res2 = this.searchAlongDirection(item, doorSearchDistance);
2176
+ if (res2) return {
2177
+ start: item.point,
2178
+ end: res2.point
2179
+ };
2180
+ const res3 = this.searchAlongNormalDirection(item, doorSearchDistance);
2181
+ if (res3) return {
2182
+ start: item.point,
2183
+ end: res3.point
2184
+ };
2185
+ }).filter((i) => !!i && i.start.distance(i.end) < doorSearchDistance)
2186
+ );
2187
+ const doorLineSegment = [];
2188
+ doors.forEach((p) => {
2189
+ const line = new LineSegment(p?.start, p?.end);
2190
+ const len = line.length();
2191
+ if (len < minDoorWidth) return;
2192
+ const normal = line.normal(), direction = line.direction(), step = (len - dxf.width * 2) / 2;
2193
+ for (let i = 0; i < 3; i++) {
2194
+ const point = line.start.clone().add(direction.clone().multiplyScalar(dxf.width + step * i));
2195
+ const rLine = new LineSegment(
2196
+ point,
2197
+ point.clone().add(normal.clone().multiplyScalar(1))
2198
+ );
2199
+ rLine.directionMove(normal, -0.5);
2200
+ const res = this.quadtree.queryLineSegment(rLine);
2201
+ if (res.length) return;
2202
+ }
2203
+ doorLineSegment.push(line);
2111
2204
  });
2112
- this.pointVirtualGrid = pointVirtualGrid;
2205
+ return doorLineSegment;
2113
2206
  }
2114
- quadtree;
2115
- /**
2116
- * 构建线段四叉树,快速查找,
2207
+ /** 添加可查找点的过滤规则
2208
+ * @param rule
2117
2209
  */
2118
- buildQuadtree() {
2119
- const dxf = this.Dxf;
2120
- const lineSegmentList = [];
2121
- this.quadtree = new Quadtree(dxf.originalBox, 2);
2122
- dxf.lineSegments.forEach((lineSegment) => {
2123
- if (lineSegment.userData?.isDoor) return;
2124
- this.quadtree?.insert({
2125
- line: lineSegment,
2126
- userData: lineSegmentList.length
2127
- });
2128
- lineSegmentList.push(lineSegment);
2129
- });
2130
- this.lineSegmentList = lineSegmentList;
2210
+ addPointsExcludeRule(rule) {
2211
+ this._pointsExcludeRule.push(rule);
2131
2212
  }
2132
- resultList = [];
2133
- mergeWallLines = [];
2134
- /** 线段分析
2135
- * @description 判断两条线段距离是否较短且趋近平行,然后查找两条线段的重合部分的投影线,以此判断两根线是否需要合并
2136
- * @param data
2213
+ _pointsExcludeRule = [];
2214
+ /**
2215
+ * 查找所有可能为门的点位
2137
2216
  */
2138
- lineAnalysis() {
2139
- this.buildQuadtree();
2140
- this.buildVirtualGrid();
2141
- const quadtree = this.quadtree;
2142
- const lineSegmentList = this.lineSegmentList;
2143
- const visited = /* @__PURE__ */ new Set(), resultList = [];
2144
- lineSegmentList.forEach((_0, i) => {
2145
- const sourceLineSegment = lineSegmentList[i], rectangle = Rectangle.fromByLineSegment(sourceLineSegment, this.width * 2, false, -0.01), ids = quadtree.queryRect(rectangle).map((i2) => i2.userData).filter((index2) => index2 !== i);
2146
- ids.forEach((id) => {
2147
- try {
2148
- if (visited.has(`${i}-${id}`) || visited.has(`${id}-${i}`)) return;
2149
- const res = this.projectionAnalysis(id, i, sourceLineSegment, lineSegmentList);
2150
- if (res) resultList.push(res);
2151
- visited.add(`${i}-${id}`);
2152
- } catch (error) {
2217
+ getPossiblePoints() {
2218
+ const doorPoints = [];
2219
+ this.lineSegments.forEach((line) => {
2220
+ line.points.forEach((p, j) => {
2221
+ for (let i = 0; i < this._pointsExcludeRule.length; i++) if (this._pointsExcludeRule[i](line, p, j)) return;
2222
+ const res = this.pointVirtualGrid.queryPoint(p).filter((d) => d.userData !== line);
2223
+ if (res.length === 0) {
2224
+ doorPoints.push({ line, point: p, uuid: uuid() });
2153
2225
  }
2154
2226
  });
2155
2227
  });
2156
- this.appendLineSegmentList.length = 0;
2157
- resultList.forEach(this.createRectangle.bind(this));
2158
- this.resultList = resultList;
2159
- }
2160
- /** 线段投影分析
2161
- * @param index
2162
- * @param sourceLineSegment
2163
- * @param lineSegmentList
2164
- * @returns
2165
- */
2166
- projectionAnalysis(index2, sourceIndex, sourceLineSegment, lineSegmentList) {
2167
- const temLineSegment = lineSegmentList[index2], direct = sourceLineSegment.direction(), temDirect = temLineSegment.direction(), angle = direct.angleBetween(temDirect) / (Math.PI / 180);
2168
- if (angle < this.errorAngle || angle > 180 - this.errorAngle) {
2169
- let data;
2170
- const p1 = temLineSegment.projectLineSegment(sourceLineSegment), p2 = sourceLineSegment.projectLineSegment(temLineSegment);
2171
- if (p1.getLength() > p2.getLength()) {
2172
- data = {
2173
- target: temLineSegment,
2174
- targetIndex: index2,
2175
- source: sourceLineSegment,
2176
- sourceIndex,
2177
- project: p1,
2178
- project2: p2
2179
- };
2180
- } else {
2181
- data = {
2182
- target: sourceLineSegment,
2183
- targetIndex: sourceIndex,
2184
- source: temLineSegment,
2185
- sourceIndex: index2,
2186
- project: p2,
2187
- project2: p1
2188
- };
2189
- }
2190
- if (!data || data.project.getLength() < 0.2 || data.project2.getLength() < 0.2) return;
2191
- return data;
2192
- }
2228
+ return doorPoints;
2193
2229
  }
2194
- doorSearchNearAngle = 110;
2195
- doorSearchDistance = 2;
2196
- doors = [];
2197
2230
  /**
2198
- * 门的位置判断
2231
+ * 查找已知为门的点位
2199
2232
  */
2200
- doorsAnalysis() {
2201
- this.parent?.findComponentByName("Renderer");
2202
- const dxf = this.Dxf, doorPoints = [], pointVirtualGrid = this.pointVirtualGrid, quadtree = this.quadtree, doorSearchNearAngle = this.doorSearchNearAngle, doorSearchDistance = this.doorSearchDistance, doors = [];
2203
- const excludePoints = dxf.doors.flatMap((item) => {
2204
- const index2 = item[4];
2205
- const doorData = dxf.originalData[index2];
2233
+ getDoorPoint() {
2234
+ const doorPoints = [], dxf = this.dxf, pointVirtualGrid = this.pointVirtualGrid;
2235
+ dxf.doors.forEach((item) => {
2236
+ const doorLine = dxf.lineSegments[item[4]];
2237
+ const doorData = dxf.originalData[item[4]];
2206
2238
  if (doorData.drawDoorData) {
2207
2239
  const point = Point.from(doorData.drawDoorData.start);
2208
2240
  const direct = Point.from(doorData.drawDoorData.n);
2209
2241
  const resList = pointVirtualGrid.queryPoint(point).filter((res) => {
2210
- if (res.userData?.index === index2) return false;
2211
- const line = dxf.lineSegments[res.userData?.index];
2242
+ if (res.userData === doorLine) return false;
2243
+ const line = res.userData;
2212
2244
  const direct2 = line.direction();
2213
2245
  if (line.start.equal(point)) direct2.multiplyScalar(-1);
2214
2246
  const angle = direct.angleBetween(direct2, "angle");
2215
2247
  return angle > 80 || angle < 10;
2216
2248
  });
2217
2249
  if (resList.length) {
2218
- const index22 = resList[0].userData?.index;
2219
2250
  doorPoints.push({
2220
- line: dxf.lineSegments[index22],
2221
- point: Point.from(doorData.drawDoorData.start),
2222
- index: index22,
2223
- direct,
2224
- sure: true
2251
+ line: resList[0].userData,
2252
+ point,
2253
+ uuid: uuid()
2225
2254
  });
2226
- return [point];
2227
2255
  }
2256
+ } else if (doorData.doorDirectConnection) {
2257
+ this.continueFind = false;
2258
+ const line = new LineSegment(Point.from(doorData.start), Point.from(doorData.end));
2259
+ line.userData = {
2260
+ doorDirectConnection: true,
2261
+ isDoor: true
2262
+ };
2263
+ this.dxf.doorLineSegment.push(line);
2264
+ } else {
2265
+ console.warn(`门的线段顺序${item[4]} 没有drawDoorData属性`);
2228
2266
  }
2229
- return [];
2230
2267
  });
2268
+ console.log("门点位数量:", doorPoints.length);
2269
+ return doorPoints;
2270
+ }
2271
+ /**
2272
+ * 查找双线墙的点位
2273
+ * @returns
2274
+ */
2275
+ searchDoubleLinePoint() {
2231
2276
  const excludeIndexMap = /* @__PURE__ */ new Map();
2232
2277
  this.resultList.flatMap((p) => {
2233
- const line0 = this.lineSegmentList[p.sourceIndex], line1 = this.lineSegmentList[p.targetIndex], start0 = line1.projectPoint(line0.start), end0 = line1.projectPoint(line0.end), start1 = line0.projectPoint(line1.start), end1 = line0.projectPoint(line1.end), mode0 = start0 && end0 ? -1 : start0 ? 0 : end0 ? 1 : -1, mode1 = start1 && end1 ? -1 : start1 ? 0 : end1 ? 1 : -1;
2278
+ const line0 = this.lineSegments[p.sourceIndex], line1 = this.lineSegments[p.targetIndex], start0 = line1.projectPoint(line0.start), end0 = line1.projectPoint(line0.end), start1 = line0.projectPoint(line1.start), end1 = line0.projectPoint(line1.end), mode0 = start0 && end0 ? -1 : start0 ? 0 : end0 ? 1 : -1, mode1 = start1 && end1 ? -1 : start1 ? 0 : end1 ? 1 : -1;
2234
2279
  if (excludeIndexMap.has(p.sourceIndex)) {
2235
2280
  if (excludeIndexMap.get(p.sourceIndex) != mode0) excludeIndexMap.set(p.sourceIndex, -1);
2236
2281
  } else excludeIndexMap.set(p.sourceIndex, mode0);
@@ -2238,57 +2283,42 @@ class LineAnalysis extends Component {
2238
2283
  if (excludeIndexMap.get(p.targetIndex) != mode1) excludeIndexMap.set(p.targetIndex, -1);
2239
2284
  } else excludeIndexMap.set(p.targetIndex, mode1);
2240
2285
  });
2241
- dxf.lineSegments.forEach((line, i) => {
2242
- if (line.userData?.isDoor) return;
2243
- const index2 = this.lineSegmentList.indexOf(line);
2244
- const excludeMode = excludeIndexMap.get(index2);
2245
- if (excludeMode === -1) return;
2246
- line.points.forEach((p, j) => {
2247
- if (excludeMode === j) return;
2248
- if (excludePoints.find((p1) => p1.equal(p))) return;
2249
- const res = this.pointVirtualGrid.queryPoint(p).filter(
2250
- (d) => d.userData?.index !== i
2251
- );
2252
- if (res.length === 0) {
2253
- doorPoints.push({
2254
- line,
2255
- point: p,
2256
- index: i
2257
- });
2258
- }
2259
- });
2260
- });
2261
- function searchNearby({ point, line, index: index2 }, doorIndex, record2) {
2286
+ return excludeIndexMap;
2287
+ }
2288
+ /** 查找方案一:最近点查找
2289
+ * @description 以点为圆心,查找半径内符合角度的点
2290
+ * @param doorPoints
2291
+ * @param possibleDoorPoints
2292
+ * @param doorSearchDistance 查找的距离(半径)
2293
+ * @param doorSearchNearAngle 查找的角度
2294
+ * @returns
2295
+ */
2296
+ searchNearby(doorPoints, possibleDoorPoints = [], doorSearchDistance = this.doorSearchDistance, doorSearchNearAngle = this.doorSearchNearAngle) {
2297
+ const findPointVirtualGrid = this.findPointVirtualGrid, quadtree = this.quadtree;
2298
+ function find({ point, line }, doorIndex, record2) {
2262
2299
  const direct = line.direction();
2263
2300
  if (line.start === point) direct.multiplyScalar(-1);
2264
- const res = pointVirtualGrid.queryCircle(point, doorSearchDistance).filter(
2265
- (r) => (
2266
- // 不能是自己
2267
- r.userData?.index !== index2 && // 存在于可疑点位内,且不能是已知门的点位
2268
- !!doorPoints.find((p) => !p.sure && p.point === r.point)
2269
- )
2270
- ).sort((a, b) => a.point.distance(point) - b.point.distance(point));
2301
+ const res = findPointVirtualGrid.queryCircle(point, doorSearchDistance).filter((r) => r.userData !== line).sort((a, b) => a.point.distance(point) - b.point.distance(point));
2271
2302
  const list = [];
2272
2303
  for (let i = 0; i < res.length; i++) {
2273
- const doorIndex2 = doorPoints.findIndex((p) => p.point === res[i].point);
2274
- if (record2.has(`${doorIndex}.${doorIndex2}`)) continue;
2275
- record2.add(`${doorIndex}.${doorIndex2}`);
2276
- record2.add(`${doorIndex2}.${doorIndex}`);
2304
+ const doorIndex2 = possibleDoorPoints.findIndex((p) => p.point === res[i].point);
2305
+ const id1 = doorPoints[doorIndex].uuid, id2 = possibleDoorPoints[doorIndex2].uuid;
2306
+ if (record2.has(`${id1}.${id2}`)) continue;
2307
+ record2.add(`${id1}.${id2}`);
2308
+ record2.add(`${id2}.${id1}`);
2277
2309
  const targetPoint = res[i].point, line2 = new LineSegment(point.clone(), targetPoint.clone()), angle = line2.direction().angleBetween(direct, "angle");
2278
2310
  if (angle < doorSearchNearAngle) {
2279
2311
  const direct2 = doorPoints[doorIndex2].line.direction();
2280
- const line22 = dxf.lineSegments[res[i].userData?.index];
2312
+ const line22 = res[i].userData;
2281
2313
  if (line22.start.equal(res[i].point)) direct2.multiplyScalar(-1);
2282
2314
  const angle2 = line2.direction().multiplyScalar(-1).angleBetween(direct2, "angle");
2283
2315
  if (angle2 < doorSearchNearAngle) {
2284
2316
  if (!quadtree.queryLineSegment(line2).length) {
2285
2317
  list.push({
2286
2318
  findData: res[i],
2287
- findDoorIndex: doorIndex2,
2288
- findAngle: angle2,
2289
- doorAngle: angle,
2319
+ findUuid: id2,
2290
2320
  doorLine: line2,
2291
- doorIndex
2321
+ doorUuid: id1
2292
2322
  });
2293
2323
  }
2294
2324
  }
@@ -2296,65 +2326,15 @@ class LineAnalysis extends Component {
2296
2326
  }
2297
2327
  return list;
2298
2328
  }
2299
- function searchAlongDirection({ point, line }) {
2300
- const direct = line.direction();
2301
- if (line.start === point) direct.multiplyScalar(-1);
2302
- const endPoint = point.clone().add(direct.clone().multiplyScalar(doorSearchDistance)), rline = new LineSegment(point.clone(), endPoint), result = quadtree.queryLineSegment(rline).map((l) => {
2303
- const res = l.line.getIntersection(rline);
2304
- return {
2305
- point: res,
2306
- line: l.line
2307
- };
2308
- }).filter((i) => i.point).sort((a, b) => point.distance(a.point) - point.distance(b.point));
2309
- if (result.length) {
2310
- const item = result[0];
2311
- if (Math.abs(90 - item.line.direction().angleBetween(direct, "angle")) < 5) {
2312
- return item;
2313
- }
2314
- }
2315
- }
2316
- function searchAlongNormalDirection({ point, line, index: index2 }) {
2317
- const direct = line.direction();
2318
- if (line.start === point) direct.multiplyScalar(-1);
2319
- const normal = line.start.normal(line.end);
2320
- const prePoint = line.start.clone();
2321
- if (line.start === point) prePoint.copy(line.end);
2322
- const result = pointVirtualGrid.queryPoint(prePoint).filter((r) => r.userData?.index !== index2);
2323
- for (let i = 0; i < result.length; i++) {
2324
- const element = result[i];
2325
- const l = dxf.lineSegments[element.userData?.index ?? 0];
2326
- const d1 = l.direction();
2327
- if (l.start === element.point) direct.multiplyScalar(-1);
2328
- const angle = d1.angleBetween(normal) / (Math.PI / 180);
2329
- if (angle > 90) {
2330
- normal.multiplyScalar(-1);
2331
- break;
2332
- }
2333
- }
2334
- const rline3 = new LineSegment(point.clone(), point.clone().add(normal.multiplyScalar(doorSearchDistance)));
2335
- const r3 = quadtree.queryLineSegment(rline3).map((l) => {
2336
- const res = l.line.getIntersection(rline3);
2337
- return {
2338
- point: res,
2339
- line: l.line
2340
- };
2341
- }).filter((i) => i.point).sort((a, b) => point.distance(a.point) - point.distance(b.point));
2342
- if (r3.length) {
2343
- const item = r3[0];
2344
- if (Math.abs(90 - item.line.direction().angleBetween(normal, "angle")) < 5) {
2345
- return item;
2346
- }
2347
- }
2348
- }
2349
- function deepSearchNearHandle(index2, snFindRecord2, list, record2, other) {
2350
- record2.add(`${index2}`);
2329
+ function deepSearchNearHandle(uuid2, snFindRecord2, list, record2, other) {
2330
+ record2.add(uuid2);
2351
2331
  const newList = [];
2352
2332
  if (other) newList.push(other);
2353
2333
  for (let i = 0; i < list.length; i++) {
2354
2334
  const item = list[i];
2355
- if (snFindRecord2.has(item.findDoorIndex)) {
2356
- const list2 = snFindRecord2.get(item.findDoorIndex);
2357
- if (deepSearchNearHandle(item.findDoorIndex, snFindRecord2, list2, record2, item)) newList.push(item);
2335
+ if (snFindRecord2.has(item.findUuid)) {
2336
+ const list2 = snFindRecord2.get(item.findUuid);
2337
+ if (deepSearchNearHandle(item.findUuid, snFindRecord2, list2, record2, item)) newList.push(item);
2358
2338
  } else newList.push(item);
2359
2339
  }
2360
2340
  newList.sort((a, b) => a.doorLine.length() - b.doorLine.length());
@@ -2368,22 +2348,21 @@ class LineAnalysis extends Component {
2368
2348
  const record = /* @__PURE__ */ new Set();
2369
2349
  const snFindRecord = /* @__PURE__ */ new Map();
2370
2350
  doorPoints.map((p, index2) => {
2371
- if (dxf.doors.length >= 2 && !p.sure) return;
2372
- const list = searchNearby(p, index2, record);
2373
- if (list.length) snFindRecord.set(index2, list);
2351
+ const list = find(p, index2, record);
2352
+ if (list.length) snFindRecord.set(p.uuid, list);
2374
2353
  });
2375
2354
  record.clear();
2376
2355
  const temMap = /* @__PURE__ */ new Map();
2377
2356
  snFindRecord.forEach((list, key) => {
2378
- if (!record.has(`${key}`) && list.length) {
2357
+ if (!record.has(key) && list.length) {
2379
2358
  deepSearchNearHandle(key, snFindRecord, list, record);
2380
2359
  }
2381
2360
  if (list.length) {
2382
2361
  const item = list[0];
2383
- if (!temMap.has(item.doorIndex)) temMap.set(item.doorIndex, []);
2384
- temMap.get(item.doorIndex)?.push(item);
2385
- if (!temMap.has(item.findDoorIndex)) temMap.set(item.findDoorIndex, []);
2386
- temMap.get(item.findDoorIndex)?.push(item);
2362
+ if (!temMap.has(item.doorUuid)) temMap.set(item.doorUuid, []);
2363
+ temMap.get(item.doorUuid)?.push(item);
2364
+ if (!temMap.has(item.findUuid)) temMap.set(item.findUuid, []);
2365
+ temMap.get(item.findUuid)?.push(item);
2387
2366
  }
2388
2367
  });
2389
2368
  const deleteSet = /* @__PURE__ */ new Set();
@@ -2393,38 +2372,24 @@ class LineAnalysis extends Component {
2393
2372
  for (let i = 1; i < list.length; i++) deleteSet.add(list[i]);
2394
2373
  }
2395
2374
  });
2396
- const searchNearRasult = [], removeDoorPointsIndex = [];
2375
+ const searchNearRasult = [], removeDoorPointsUuid = [];
2397
2376
  snFindRecord.forEach((list) => {
2398
2377
  if (list.length) {
2399
2378
  const item = list[0];
2400
2379
  if (!deleteSet.has(item)) {
2401
2380
  searchNearRasult.push(item);
2402
- removeDoorPointsIndex.push(item.doorIndex, item.findDoorIndex);
2381
+ removeDoorPointsUuid.push(item.doorUuid, item.findUuid);
2403
2382
  }
2404
2383
  }
2405
2384
  });
2406
- const doors_ = doorPoints.map((item, index2) => {
2407
- if (removeDoorPointsIndex.includes(index2)) return;
2408
- if (dxf.doors.length >= 2 && !item.sure) return;
2409
- const res2 = searchAlongDirection(item);
2410
- if (res2) return {
2411
- start: item.point,
2412
- end: res2.point,
2413
- index: item.index
2414
- };
2415
- const res3 = searchAlongNormalDirection(item);
2416
- if (res3) return {
2417
- start: item.point,
2418
- end: res3.point,
2419
- index: item.index
2420
- };
2421
- }).filter((i) => !!i && i.start.distance(i.end) < doorSearchDistance);
2422
- doors.push(...doors_);
2385
+ const doors = [];
2423
2386
  searchNearRasult.forEach((item) => {
2424
- const start = doorPoints[item.doorIndex].point.clone();
2425
- const end = doorPoints[item.findDoorIndex].point.clone();
2426
- const startLine = this.findLongLineSegment(doorPoints[item.doorIndex].line);
2427
- const endLine = this.findLongLineSegment(doorPoints[item.findDoorIndex].line);
2387
+ const doorIndex = doorPoints.findIndex((p2) => p2.uuid === item.doorUuid);
2388
+ const findDoorIndex = possibleDoorPoints.findIndex((p2) => p2.uuid === item.findUuid);
2389
+ const start = doorPoints[doorIndex].point.clone();
2390
+ const end = possibleDoorPoints[findDoorIndex].point.clone();
2391
+ const startLine = this.findLongLineSegment(doorPoints[doorIndex].line);
2392
+ const endLine = this.findLongLineSegment(possibleDoorPoints[findDoorIndex].line);
2428
2393
  const p = startLine.projectPoint(end);
2429
2394
  if (p) {
2430
2395
  start.copy(p);
@@ -2433,8 +2398,7 @@ class LineAnalysis extends Component {
2433
2398
  if (angle < 10 || angle > 170 || Math.abs(90 - angle) < 10) {
2434
2399
  doors.push({
2435
2400
  start,
2436
- end,
2437
- index: doorPoints[item.doorIndex].index
2401
+ end
2438
2402
  });
2439
2403
  }
2440
2404
  } else {
@@ -2445,30 +2409,82 @@ class LineAnalysis extends Component {
2445
2409
  if (angle < 10 || angle > 170 || Math.abs(90 - angle) < 10) {
2446
2410
  doors.push({
2447
2411
  start,
2448
- end,
2449
- index: doorPoints[item.doorIndex].index
2412
+ end
2450
2413
  });
2451
2414
  }
2452
2415
  }
2453
2416
  });
2454
- dxf.doorLineSegment.length = 0;
2455
- doors.forEach((p) => {
2456
- const line = new LineSegment(p?.start, p?.end);
2457
- const len = line.length();
2458
- if (len < 0.6) return;
2459
- const normal = line.normal(), direction = line.direction(), step = (len - dxf.width * 2) / 2;
2460
- for (let i = 0; i < 3; i++) {
2461
- const point = line.start.clone().add(direction.clone().multiplyScalar(dxf.width + step * i));
2462
- const rLine = new LineSegment(
2463
- point,
2464
- point.clone().add(normal.clone().multiplyScalar(1))
2465
- );
2466
- rLine.directionMove(normal, -0.5);
2467
- const res = this.quadtree?.queryLineSegment(rLine);
2468
- if (res?.length) return;
2417
+ possibleDoorPoints.splice(
2418
+ 0,
2419
+ possibleDoorPoints.length,
2420
+ ...possibleDoorPoints.filter((p) => removeDoorPointsUuid.indexOf(p.uuid) === -1)
2421
+ );
2422
+ doorPoints.splice(
2423
+ 0,
2424
+ doorPoints.length,
2425
+ ...doorPoints.filter((p) => removeDoorPointsUuid.indexOf(p.uuid) === -1)
2426
+ );
2427
+ return doors;
2428
+ }
2429
+ /** 方案二: 沿方向查找
2430
+ * @description
2431
+ * @param param0
2432
+ * @returns
2433
+ */
2434
+ searchAlongDirection({ point, line }, doorSearchDistance = this.doorSearchDistance) {
2435
+ const quadtree = this.quadtree;
2436
+ const direct = line.direction();
2437
+ if (line.start === point) direct.multiplyScalar(-1);
2438
+ const endPoint = point.clone().add(direct.clone().multiplyScalar(doorSearchDistance)), rline = new LineSegment(point.clone(), endPoint), result = quadtree.queryLineSegment(rline).map((l) => {
2439
+ const res = l.line.getIntersection(rline);
2440
+ return {
2441
+ point: res,
2442
+ line: l.line
2443
+ };
2444
+ }).filter((i) => i.point).sort((a, b) => point.distance(a.point) - point.distance(b.point));
2445
+ if (result.length) {
2446
+ const item = result[0];
2447
+ if (Math.abs(90 - item.line.direction().angleBetween(direct, "angle")) < 5) {
2448
+ return item;
2469
2449
  }
2470
- dxf.doorLineSegment.push(line);
2471
- });
2450
+ }
2451
+ }
2452
+ /** 方案三: 沿法线方向查找
2453
+ * @description
2454
+ * @param param0
2455
+ * @param doorSearchDistance
2456
+ * @returns
2457
+ */
2458
+ searchAlongNormalDirection({ point, line }, doorSearchDistance = this.doorSearchDistance) {
2459
+ const pointVirtualGrid = this.pointVirtualGrid, quadtree = this.quadtree, direct = line.direction(), normal = line.start.normal(line.end), prePoint = line.start.clone();
2460
+ if (line.start === point) direct.multiplyScalar(-1);
2461
+ if (line.start === point) prePoint.copy(line.end);
2462
+ const result = pointVirtualGrid.queryPoint(prePoint).filter((r) => r.userData !== line);
2463
+ for (let i = 0; i < result.length; i++) {
2464
+ const element = result[i];
2465
+ const l = element.userData;
2466
+ const d1 = l.direction();
2467
+ if (l.start === element.point) direct.multiplyScalar(-1);
2468
+ const angle = d1.angleBetween(normal) / (Math.PI / 180);
2469
+ if (angle > 90) {
2470
+ normal.multiplyScalar(-1);
2471
+ break;
2472
+ }
2473
+ }
2474
+ const rline3 = new LineSegment(point.clone(), point.clone().add(normal.multiplyScalar(doorSearchDistance)));
2475
+ const r3 = quadtree.queryLineSegment(rline3).map((l) => {
2476
+ const res = l.line.getIntersection(rline3);
2477
+ return {
2478
+ point: res,
2479
+ line: l.line
2480
+ };
2481
+ }).filter((i) => i.point).sort((a, b) => point.distance(a.point) - point.distance(b.point));
2482
+ if (r3.length) {
2483
+ const item = r3[0];
2484
+ if (Math.abs(90 - item.line.direction().angleBetween(normal, "angle")) < 5) {
2485
+ return item;
2486
+ }
2487
+ }
2472
2488
  }
2473
2489
  /**
2474
2490
  *
@@ -2476,13 +2492,11 @@ class LineAnalysis extends Component {
2476
2492
  * @returns
2477
2493
  */
2478
2494
  findLongLineSegment(line) {
2479
- const dxf = this.Dxf;
2480
2495
  const resLine = line.clone();
2481
2496
  const res1 = this.pointVirtualGrid.queryPoint(line.start);
2482
2497
  const res2 = this.pointVirtualGrid.queryPoint(line.end);
2483
2498
  for (let i = 0; i < res1.length; i++) {
2484
- const { userData } = res1[i];
2485
- const line2 = dxf.lineSegments[userData?.index];
2499
+ const { userData: line2 } = res1[i];
2486
2500
  if (line2 === line) continue;
2487
2501
  if (line2 && line2.directionEqual(line)) {
2488
2502
  if (line2.start.equal(line.start)) resLine.start.copy(line2.end);
@@ -2491,8 +2505,7 @@ class LineAnalysis extends Component {
2491
2505
  }
2492
2506
  }
2493
2507
  for (let i = 0; i < res2.length; i++) {
2494
- const { userData } = res2[i];
2495
- const line2 = dxf.lineSegments[userData?.index];
2508
+ const { userData: line2 } = res2[i];
2496
2509
  if (line2 === line) continue;
2497
2510
  if (line2 && line2.directionEqual(line)) {
2498
2511
  if (line2.end.equal(line.end)) resLine.end.copy(line2.start);
@@ -2502,144 +2515,169 @@ class LineAnalysis extends Component {
2502
2515
  }
2503
2516
  return resLine;
2504
2517
  }
2505
- doorsAnalysis2() {
2506
- const renderer = this.parent?.findComponentByName("Renderer");
2507
- const dxf = this.Dxf, pointVirtualGrid = this.pointVirtualGrid, quadtree = this.quadtree;
2508
- this.doorSearchNearAngle;
2509
- this.doorSearchDistance;
2510
- const doorsAnalysis = new DoorsAnalysis(dxf, pointVirtualGrid, quadtree, this.resultList, this.lineSegmentList);
2511
- const possiblePoints = doorsAnalysis.searchPossiblePoints();
2512
- possiblePoints.forEach((l) => {
2513
- renderer.createPointMesh(l.point).position.z = dxf.originalZAverage;
2514
- });
2515
- }
2516
2518
  }
2517
- class DoorsAnalysis {
2518
- // 所有可查找的点位
2519
- possibleDoorPoints = [];
2520
- doorPoint = [];
2521
- dxf;
2522
- pointVirtualGrid;
2523
- quadtree;
2524
- resultList;
2525
- // 已过滤门的线段
2526
- lineSegments;
2527
- doorSearchNearAngle = 110;
2528
- doorSearchDistance = 2;
2529
- doors = [];
2530
- constructor(dxf, pointVirtualGrid, quadtree, resultList = [], lineSegments = []) {
2531
- this.dxf = dxf;
2532
- this.pointVirtualGrid = pointVirtualGrid;
2533
- this.quadtree = quadtree;
2534
- this.resultList = resultList;
2535
- this.lineSegments = lineSegments;
2536
- this.addPointsExcludeRule((line) => line.userData.isDoor);
2537
- const excludeIndexMap = this.searchDoubleLinePoint();
2538
- this.addPointsExcludeRule((_1, _2, index2, pointIndex) => {
2539
- const excludeMode = excludeIndexMap.get(index2);
2540
- if (typeof excludeMode === "number") {
2541
- return excludeMode === -1 || excludeMode === pointIndex;
2542
- }
2543
- return false;
2544
- });
2545
- this.doorPoint = this.searchDoorPoint();
2546
- this.addPointsExcludeRule((_1, point) => {
2547
- return !!this.doorPoint.find((p1) => p1.point.equal(point));
2548
- });
2549
- this.possibleDoorPoints = this.searchPossiblePoints();
2550
- if (dxf.doors.length < 2) ;
2519
+ class LineAnalysis extends Component {
2520
+ static name = "LineAnalysis";
2521
+ Dxf = null;
2522
+ Variable = null;
2523
+ lineSegmentList = [];
2524
+ container = new THREE.Group();
2525
+ // 误差角度
2526
+ errorAngle = 4;
2527
+ width = 0.4;
2528
+ /**
2529
+ *
2530
+ * @param parent
2531
+ */
2532
+ onAddFromParent(parent) {
2533
+ this.Dxf = parent.findComponentByType(Dxf);
2534
+ this.Variable = this.parent?.findComponentByType(Variable);
2535
+ this.Dxf.addEventListener("setDta", this.lineAnalysis.bind(this));
2536
+ this.Dxf.addEventListener("createGroup", this.doorsAnalysis.bind(this));
2551
2537
  }
2552
2538
  /**
2553
2539
  *
2554
- * @param rule
2540
+ * @param p1
2541
+ * @param p2
2542
+ * @param width
2543
+ * @returns
2555
2544
  */
2556
- addPointsExcludeRule(rule) {
2557
- this._pointsExcludeRule.push(rule);
2545
+ expandLineSegment(p1, p2, width = 0.1) {
2546
+ const normal = p2.normal(p1);
2547
+ const pDirect = p2.direction(p1).mutiplyScalar(width * 0.5);
2548
+ const nDirect = p1.direction(p2).mutiplyScalar(width * 0.5);
2549
+ const offsetX = normal.x * width * 0.5;
2550
+ const offsetY = normal.y * width * 0.5;
2551
+ return {
2552
+ points: [
2553
+ // 第一条线
2554
+ new Point(p1.x + offsetX, p1.y + offsetY).add(nDirect),
2555
+ new Point(p2.x + offsetX, p2.y + offsetY).add(pDirect),
2556
+ // 第二条线
2557
+ new Point(p1.x - offsetX, p1.y - offsetY).add(nDirect),
2558
+ new Point(p2.x - offsetX, p2.y - offsetY).add(pDirect)
2559
+ ],
2560
+ indices: [0, 1, 1, 3, 3, 2, 2, 0],
2561
+ rectIndices: [0, 1, 3, 2, 0]
2562
+ };
2558
2563
  }
2559
- _pointsExcludeRule = [];
2564
+ appendLineSegmentList = [];
2560
2565
  /**
2561
- * 查找所有可能为门的点位
2566
+ * 追加数据
2567
+ * @param p1
2568
+ * @param p2
2562
2569
  */
2563
- searchPossiblePoints() {
2564
- const dxf = this.dxf, doorPoints = [];
2565
- dxf.lineSegments.forEach((line, i) => {
2566
- line.points.forEach((p, j) => {
2567
- for (let i2 = 0; i2 < this._pointsExcludeRule.length; i2++)
2568
- if (this._pointsExcludeRule[i2](line, p, i2, j)) return;
2569
- const res = this.pointVirtualGrid.queryPoint(p).filter((d) => d.userData?.index !== i);
2570
- if (res.length === 0) {
2571
- doorPoints.push({
2572
- line,
2573
- point: p,
2574
- index: i
2575
- });
2576
- }
2577
- });
2578
- });
2579
- return doorPoints;
2570
+ addData(p1, p2) {
2571
+ const dxf = this.Dxf;
2572
+ dxf.data.push([p1.clone(), p2.clone(), [], false, dxf.data.length]);
2573
+ this.appendLineSegmentList.push(new LineSegment(p1.clone(), p2.clone()));
2580
2574
  }
2575
+ /** 结果分析创建矩形
2576
+ * @param result
2577
+ */
2578
+ createRectangle(result) {
2579
+ const dxf = this.Dxf;
2580
+ const project0 = result.project, project1 = result.project2;
2581
+ if (project0.includedAngle(project1) > 135) {
2582
+ project1.points = [project1.points[1], project1.points[0]];
2583
+ }
2584
+ this.addData(project0.points[0], project1.points[0]);
2585
+ this.addData(project0.points[1], project1.points[1]);
2586
+ const leftHeight = project0.points[0].distance(project1.points[0]), rightHeight = project0.points[1].distance(project1.points[1]), count = Math.ceil(Math.max(leftHeight, rightHeight) / dxf.width), leftFragment = leftHeight / count, rightFragment = rightHeight / count, leftDirection = project1.points[0].direction(project0.points[0]), rightDirection = project1.points[1].direction(project0.points[1]), leftP = project0.points[0].clone(), rightP = project0.points[1].clone(), direction = rightP.direction(leftP);
2587
+ direction.multiplyScalar(dxf.width * 0.5);
2588
+ const _leftP = leftP.clone().add(direction), _rightP = rightP.clone().add(direction.multiplyScalar(-1)), d1 = leftP.direction(rightP), d2 = _leftP.direction(_rightP);
2589
+ if (d1.x > 0 && d2.x < 0 || d1.x < 0 && d2.x > 0 || d1.y > 0 && d2.y < 0 || d1.y < 0 && d2.y > 0) return;
2590
+ leftP.set(_leftP.x, _leftP.y);
2591
+ rightP.set(_rightP.x, _rightP.y);
2592
+ for (let i = 1; i < count; i++) {
2593
+ const left = leftDirection.clone().multiplyScalar(leftFragment * i), right = rightDirection.clone().multiplyScalar(rightFragment * i), p1 = leftP.clone().add(left), p2 = rightP.clone().add(right);
2594
+ this.addData(p1, p2);
2595
+ }
2596
+ }
2597
+ quadtree;
2581
2598
  /**
2582
- * 查找已知为门的点位
2599
+ * 构建线段四叉树,快速查找,
2583
2600
  */
2584
- searchDoorPoint() {
2585
- const doorPoints = [], dxf = this.dxf, pointVirtualGrid = this.pointVirtualGrid;
2586
- dxf.doors.forEach((item) => {
2587
- const index2 = item[4];
2588
- const doorData = dxf.originalData[index2];
2589
- if (doorData.drawDoorData) {
2590
- const point = Point.from(doorData.drawDoorData.start);
2591
- const direct = Point.from(doorData.drawDoorData.n);
2592
- const resList = pointVirtualGrid.queryPoint(point).filter((res) => {
2593
- if (res.userData?.index === index2) return false;
2594
- const line = dxf.lineSegments[res.userData?.index];
2595
- const direct2 = line.direction();
2596
- if (line.start.equal(point)) direct2.multiplyScalar(-1);
2597
- const angle = direct.angleBetween(direct2, "angle");
2598
- return angle > 80 || angle < 10;
2599
- });
2600
- if (resList.length) {
2601
- const index22 = resList[0].userData?.index;
2602
- doorPoints.push({
2603
- line: dxf.lineSegments[index22],
2604
- point: Point.from(doorData.drawDoorData.start),
2605
- index: index22,
2606
- direct,
2607
- sure: true
2608
- });
2609
- }
2610
- }
2601
+ buildQuadtree() {
2602
+ const dxf = this.Dxf;
2603
+ const lineSegmentList = [];
2604
+ this.quadtree = new Quadtree(dxf.originalBox, 2);
2605
+ dxf.lineSegments.forEach((lineSegment) => {
2606
+ if (lineSegment.userData?.isDoor) return;
2607
+ this.quadtree?.insert({
2608
+ line: lineSegment,
2609
+ userData: lineSegmentList.length
2610
+ });
2611
+ lineSegmentList.push(lineSegment);
2611
2612
  });
2612
- return doorPoints;
2613
+ this.lineSegmentList = lineSegmentList;
2613
2614
  }
2614
- /**
2615
- * 查找双线墙的点位
2616
- * @returns
2615
+ resultList = [];
2616
+ mergeWallLines = [];
2617
+ /** 线段分析
2618
+ * @description 判断两条线段距离是否较短且趋近平行,然后查找两条线段的重合部分的投影线,以此判断两根线是否需要合并
2619
+ * @param data
2617
2620
  */
2618
- searchDoubleLinePoint() {
2619
- const excludeIndexMap = /* @__PURE__ */ new Map();
2620
- this.resultList.flatMap((p) => {
2621
- const line0 = this.lineSegments[p.sourceIndex], line1 = this.lineSegments[p.targetIndex], start0 = line1.projectPoint(line0.start), end0 = line1.projectPoint(line0.end), start1 = line0.projectPoint(line1.start), end1 = line0.projectPoint(line1.end), mode0 = start0 && end0 ? -1 : start0 ? 0 : end0 ? 1 : -1, mode1 = start1 && end1 ? -1 : start1 ? 0 : end1 ? 1 : -1;
2622
- if (excludeIndexMap.has(p.sourceIndex)) {
2623
- if (excludeIndexMap.get(p.sourceIndex) != mode0) excludeIndexMap.set(p.sourceIndex, -1);
2624
- } else excludeIndexMap.set(p.sourceIndex, mode0);
2625
- if (excludeIndexMap.has(p.targetIndex)) {
2626
- if (excludeIndexMap.get(p.targetIndex) != mode1) excludeIndexMap.set(p.targetIndex, -1);
2627
- } else excludeIndexMap.set(p.targetIndex, mode1);
2621
+ lineAnalysis() {
2622
+ this.buildQuadtree();
2623
+ const quadtree = this.quadtree;
2624
+ const lineSegmentList = this.lineSegmentList;
2625
+ const visited = /* @__PURE__ */ new Set(), resultList = [];
2626
+ lineSegmentList.forEach((_0, i) => {
2627
+ const sourceLineSegment = lineSegmentList[i], rectangle = Rectangle.fromByLineSegment(sourceLineSegment, this.width * 2, false, -0.01), ids = quadtree.queryRect(rectangle).map((i2) => i2.userData).filter((index2) => index2 !== i);
2628
+ ids.forEach((id) => {
2629
+ try {
2630
+ if (visited.has(`${i}-${id}`) || visited.has(`${id}-${i}`)) return;
2631
+ const res = this.projectionAnalysis(id, i, sourceLineSegment, lineSegmentList);
2632
+ if (res) resultList.push(res);
2633
+ visited.add(`${i}-${id}`);
2634
+ } catch (error) {
2635
+ }
2636
+ });
2628
2637
  });
2629
- return excludeIndexMap;
2638
+ this.appendLineSegmentList.length = 0;
2639
+ resultList.forEach(this.createRectangle.bind(this));
2640
+ this.resultList = resultList;
2630
2641
  }
2631
- /** 最近点查找
2632
- * @description 以点为圆心,查找半径内符合角度的点,
2633
- * @param param0
2634
- * @param doorIndex
2635
- * @param record
2642
+ /** 线段投影分析
2643
+ * @param index
2644
+ * @param sourceLineSegment
2645
+ * @param lineSegmentList
2636
2646
  * @returns
2637
2647
  */
2638
- searchNearby({ point, line, index: index2 }, doorIndex, record) {
2639
- const pointVirtualGrid = this.pointVirtualGrid, doorSearchDistance = this.doorSearchDistance;
2640
- const direct = line.direction();
2641
- if (line.start === point) direct.multiplyScalar(-1);
2642
- pointVirtualGrid.queryCircle(point, doorSearchDistance).filter((r) => r.userData?.index !== index2).sort((a, b) => a.point.distance(point) - b.point.distance(point));
2648
+ projectionAnalysis(index2, sourceIndex, sourceLineSegment, lineSegmentList) {
2649
+ const temLineSegment = lineSegmentList[index2], direct = sourceLineSegment.direction(), temDirect = temLineSegment.direction(), angle = direct.angleBetween(temDirect) / (Math.PI / 180);
2650
+ if (angle < this.errorAngle || angle > 180 - this.errorAngle) {
2651
+ let data;
2652
+ const p1 = temLineSegment.projectLineSegment(sourceLineSegment), p2 = sourceLineSegment.projectLineSegment(temLineSegment);
2653
+ if (p1.getLength() > p2.getLength()) {
2654
+ data = {
2655
+ target: temLineSegment,
2656
+ targetIndex: index2,
2657
+ source: sourceLineSegment,
2658
+ sourceIndex,
2659
+ project: p1,
2660
+ project2: p2
2661
+ };
2662
+ } else {
2663
+ data = {
2664
+ target: sourceLineSegment,
2665
+ targetIndex: sourceIndex,
2666
+ source: temLineSegment,
2667
+ sourceIndex: index2,
2668
+ project: p2,
2669
+ project2: p1
2670
+ };
2671
+ }
2672
+ if (!data || data.project.getLength() < 0.2 || data.project2.getLength() < 0.2) return;
2673
+ return data;
2674
+ }
2675
+ }
2676
+ doorSearchNearAngle = 110;
2677
+ doorSearchDistance = 2;
2678
+ doors = [];
2679
+ doorsAnalysis() {
2680
+ new DoorsAnalysis(this);
2643
2681
  }
2644
2682
  }
2645
2683
  class DxfSystem extends ComponentManager {
@@ -2992,38 +3030,84 @@ class DxfLineModel extends Component {
2992
3030
  updateMode() {
2993
3031
  const dxf = this.parent?.findComponentByName("Dxf");
2994
3032
  this.dxfLineModel.clear();
2995
- const dxfArray = dxf.to3DArray(1 / dxf.scale);
3033
+ const dxfArray = dxf.to3DArray(1 / dxf.scale, 0);
2996
3034
  this.dxfLineModel.geometry = new THREE.BufferGeometry().setAttribute("position", new THREE.BufferAttribute(dxfArray, 3, true));
2997
3035
  const doorsArray = new Float32Array(
2998
- dxf.doorLineSegment.flatMap(({ start, end }) => [start.x, start.y, dxf.originalZAverage * 0.99, end.x, end.y, dxf.originalZAverage * 0.99])
3036
+ dxf.doorLineSegment.flatMap(({ start, end }) => [start.x, start.y, 0, end.x, end.y, 0])
2999
3037
  ).map((n) => n / dxf.scale);
3000
3038
  const doorsColorArray = new Float32Array(dxf.doorLineSegment.flatMap(() => [1, 0, 0, 0, 1, 0]));
3001
3039
  this.dxfDoorsLineModel.geometry = new THREE.BufferGeometry().setAttribute("position", new THREE.BufferAttribute(doorsArray, 3, true)).setAttribute("color", new THREE.BufferAttribute(doorsColorArray, 3));
3040
+ this.dxfModelGroup.position.z = dxf.originalZAverage;
3041
+ this.dispatchEvent({
3042
+ type: "modelUpdate",
3043
+ model: this.dxfModelGroup
3044
+ });
3002
3045
  }
3003
3046
  }
3004
- const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
3047
+ const index$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
3005
3048
  __proto__: null,
3006
3049
  DetailsPoint,
3007
3050
  DxfLineModel,
3008
3051
  WhiteModel
3009
3052
  }, Symbol.toStringTag, { value: "Module" }));
3010
- function ModelDataPlugin(dxfSystem) {
3011
- dxfSystem.addComponent(new DxfLineModel());
3012
- dxfSystem.addComponent(new WhiteModel());
3013
- dxfSystem.addComponent(new DetailsPoint());
3053
+ function ModelDataPlugin_(dxfSystem, option = {}) {
3054
+ const {
3055
+ detailsPoint = true,
3056
+ whiteModel = true,
3057
+ dxfLineModel = true
3058
+ } = option;
3059
+ dxfLineModel && dxfSystem.addComponent(new DxfLineModel());
3060
+ whiteModel && dxfSystem.addComponent(new WhiteModel());
3061
+ detailsPoint && dxfSystem.addComponent(new DetailsPoint());
3014
3062
  }
3063
+ const ModelDataPlugin = Object.assign(ModelDataPlugin_, {
3064
+ create(option = {}) {
3065
+ return (dxfSystem) => ModelDataPlugin_(dxfSystem, option);
3066
+ }
3067
+ });
3068
+ const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
3069
+ __proto__: null,
3070
+ ModelDataPlugin,
3071
+ components: index$1
3072
+ }, Symbol.toStringTag, { value: "Module" }));
3015
3073
  function loadRenderPlugin() {
3016
3074
  return import("./index2.js");
3017
3075
  }
3076
+ function loadEditorPlugin() {
3077
+ return import("./index3.js");
3078
+ }
3079
+ async function createEditor(dom, camera) {
3080
+ const mp = await Promise.resolve().then(() => index);
3081
+ const rp = await loadRenderPlugin();
3082
+ const editor = await loadEditorPlugin();
3083
+ const dxfSystem = new DxfSystem().usePlugin(mp.ModelDataPlugin.create({
3084
+ detailsPoint: false,
3085
+ whiteModel: false
3086
+ })).usePlugin(rp.RenderPlugin.create({
3087
+ originalLine: false,
3088
+ modelData: false,
3089
+ detailsPoint: false,
3090
+ camera
3091
+ })).usePlugin(editor.Editor);
3092
+ const domContainer = dxfSystem.findComponentByType(rp.components.DomContainer);
3093
+ domContainer && dom.appendChild(domContainer.domElement);
3094
+ return {
3095
+ dxfSystem
3096
+ };
3097
+ }
3018
3098
  export {
3019
3099
  Box2 as B,
3020
3100
  Component as C,
3021
3101
  DxfSystem as D,
3102
+ EventDispatcher as E,
3103
+ LineSegment as L,
3022
3104
  ModelDataPlugin as M,
3023
3105
  Point as P,
3106
+ Quadtree as Q,
3024
3107
  Variable as V,
3025
3108
  WhiteModel as W,
3026
3109
  DetailsPoint as a,
3027
- index as i,
3028
- loadRenderPlugin as l
3110
+ PointVirtualGrid as b,
3111
+ createEditor as c,
3112
+ index$1 as i
3029
3113
  };