build-dxf 0.0.17 → 0.0.19

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 (41) hide show
  1. package/package.json +1 -1
  2. package/src/build.d.ts +10 -1
  3. package/src/build.js +556 -450
  4. package/src/components/Editor.vue.d.ts +26 -0
  5. package/src/index.js +3 -2
  6. package/src/index2.js +373 -3426
  7. package/src/index3.js +1937 -0
  8. package/src/pages/Editor.vue.d.ts +2 -0
  9. package/src/pages/Editor02.vue.d.ts +4 -0
  10. package/src/selectLocalFile.js +3745 -0
  11. package/src/utils/CommandManager/CommandFlow.d.ts +23 -0
  12. package/src/utils/CommandManager/CommandManager.d.ts +59 -0
  13. package/src/utils/CommandManager/index.d.ts +2 -0
  14. package/src/utils/ComponentManager/EventDispatcher.d.ts +11 -1
  15. package/src/utils/DxfSystem/components/Dxf.d.ts +15 -12
  16. package/src/utils/DxfSystem/components/LineAnalysis.d.ts +5 -21
  17. package/src/utils/DxfSystem/components/Variable.d.ts +8 -0
  18. package/src/utils/DxfSystem/plugin/Editor/components/CommandFlow/CommandFlowComponent.d.ts +36 -0
  19. package/src/utils/DxfSystem/plugin/Editor/components/CommandFlow/Default.d.ts +57 -0
  20. package/src/utils/DxfSystem/plugin/Editor/components/CommandFlow/DrawDoorLine.d.ts +19 -0
  21. package/src/utils/DxfSystem/plugin/Editor/components/CommandFlow/DrawLine.d.ts +20 -0
  22. package/src/utils/DxfSystem/plugin/Editor/components/CommandFlow/DrawWindow.d.ts +25 -0
  23. package/src/utils/DxfSystem/plugin/Editor/components/CommandFlow/PointDrag.d.ts +27 -0
  24. package/src/utils/DxfSystem/plugin/Editor/components/Editor.d.ts +22 -3
  25. package/src/utils/DxfSystem/plugin/Editor/components/RenderManager.d.ts +88 -0
  26. package/src/utils/DxfSystem/plugin/Editor/components/index.d.ts +6 -0
  27. package/src/utils/DxfSystem/plugin/Editor/pages/EditorTool.vue.d.ts +6 -0
  28. package/src/utils/DxfSystem/plugin/ModelDataPlugin/components/DxfLineModel.d.ts +7 -3
  29. package/src/utils/DxfSystem/plugin/ModelDataPlugin/index.d.ts +9 -1
  30. package/src/utils/DxfSystem/plugin/RenderPlugin/components/DomContainer.d.ts +1 -0
  31. package/src/utils/DxfSystem/plugin/RenderPlugin/components/DomEventRegister.d.ts +20 -1
  32. package/src/utils/DxfSystem/plugin/RenderPlugin/components/EventInput.d.ts +74 -0
  33. package/src/utils/DxfSystem/plugin/RenderPlugin/components/Renderer.d.ts +0 -11
  34. package/src/utils/DxfSystem/plugin/RenderPlugin/components/index.d.ts +1 -0
  35. package/src/utils/DxfSystem/plugin/RenderPlugin/index.d.ts +11 -1
  36. package/src/utils/PointVirtualGrid/index.d.ts +10 -4
  37. package/src/utils/Quadtree/Box2.d.ts +3 -2
  38. package/src/utils/Quadtree/LineSegment.d.ts +11 -9
  39. package/src/utils/Quadtree/Point.d.ts +11 -6
  40. package/src/utils/Quadtree/Quadtree.d.ts +5 -0
  41. 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,218 +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
- const dxf = this.Dxf, doorPoints = [], pointVirtualGrid = this.pointVirtualGrid, quadtree = this.quadtree, doorSearchNearAngle = this.doorSearchNearAngle, doorSearchDistance = this.doorSearchDistance, doors = [];
2202
- const excludePoints = dxf.doors.flatMap((item) => {
2203
- const index2 = item[4];
2204
- 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]];
2205
2238
  if (doorData.drawDoorData) {
2206
2239
  const point = Point.from(doorData.drawDoorData.start);
2207
2240
  const direct = Point.from(doorData.drawDoorData.n);
2208
2241
  const resList = pointVirtualGrid.queryPoint(point).filter((res) => {
2209
- if (res.userData?.index === index2) return false;
2210
- const line = dxf.lineSegments[res.userData?.index];
2242
+ if (res.userData === doorLine) return false;
2243
+ const line = res.userData;
2211
2244
  const direct2 = line.direction();
2212
2245
  if (line.start.equal(point)) direct2.multiplyScalar(-1);
2213
2246
  const angle = direct.angleBetween(direct2, "angle");
2214
2247
  return angle > 80 || angle < 10;
2215
2248
  });
2216
2249
  if (resList.length) {
2217
- const index22 = resList[0].userData?.index;
2218
2250
  doorPoints.push({
2219
- line: dxf.lineSegments[index22],
2220
- point: Point.from(doorData.drawDoorData.start),
2221
- index: index22,
2222
- direct,
2223
- sure: true
2251
+ line: resList[0].userData,
2252
+ point,
2253
+ uuid: uuid()
2224
2254
  });
2225
- return [point];
2226
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属性`);
2227
2266
  }
2228
- return [];
2229
2267
  });
2268
+ console.log("门点位数量:", doorPoints.length);
2269
+ return doorPoints;
2270
+ }
2271
+ /**
2272
+ * 查找双线墙的点位
2273
+ * @returns
2274
+ */
2275
+ searchDoubleLinePoint() {
2230
2276
  const excludeIndexMap = /* @__PURE__ */ new Map();
2231
2277
  this.resultList.flatMap((p) => {
2232
- 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;
2233
2279
  if (excludeIndexMap.has(p.sourceIndex)) {
2234
2280
  if (excludeIndexMap.get(p.sourceIndex) != mode0) excludeIndexMap.set(p.sourceIndex, -1);
2235
2281
  } else excludeIndexMap.set(p.sourceIndex, mode0);
@@ -2237,54 +2283,42 @@ class LineAnalysis extends Component {
2237
2283
  if (excludeIndexMap.get(p.targetIndex) != mode1) excludeIndexMap.set(p.targetIndex, -1);
2238
2284
  } else excludeIndexMap.set(p.targetIndex, mode1);
2239
2285
  });
2240
- dxf.lineSegments.forEach((line, i) => {
2241
- if (line.userData?.isDoor) return;
2242
- const excludeMode = excludeIndexMap.get(i);
2243
- if (excludeMode === -1) return;
2244
- line.points.forEach((p, j) => {
2245
- if (excludeMode === j) return;
2246
- if (excludePoints.find((p1) => p1.equal(p))) return;
2247
- const res = this.pointVirtualGrid.queryPoint(p).filter((d) => d.userData?.index !== i);
2248
- if (res.length === 0) {
2249
- doorPoints.push({
2250
- line,
2251
- point: p,
2252
- index: i
2253
- });
2254
- }
2255
- });
2256
- });
2257
- 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) {
2258
2299
  const direct = line.direction();
2259
2300
  if (line.start === point) direct.multiplyScalar(-1);
2260
- const res = pointVirtualGrid.queryCircle(point, doorSearchDistance).filter(
2261
- (r) => (
2262
- // 不能是自己
2263
- r.userData?.index !== index2 && // 存在于可疑点位内,且不能是已知门的点位
2264
- !!doorPoints.find((p) => !p.sure && p.point === r.point)
2265
- )
2266
- ).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));
2267
2302
  const list = [];
2268
2303
  for (let i = 0; i < res.length; i++) {
2269
- const doorIndex2 = doorPoints.findIndex((p) => p.point === res[i].point);
2270
- if (record2.has(`${doorIndex}.${doorIndex2}`)) continue;
2271
- record2.add(`${doorIndex}.${doorIndex2}`);
2272
- 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}`);
2273
2309
  const targetPoint = res[i].point, line2 = new LineSegment(point.clone(), targetPoint.clone()), angle = line2.direction().angleBetween(direct, "angle");
2274
2310
  if (angle < doorSearchNearAngle) {
2275
2311
  const direct2 = doorPoints[doorIndex2].line.direction();
2276
- const line22 = dxf.lineSegments[res[i].userData?.index];
2312
+ const line22 = res[i].userData;
2277
2313
  if (line22.start.equal(res[i].point)) direct2.multiplyScalar(-1);
2278
2314
  const angle2 = line2.direction().multiplyScalar(-1).angleBetween(direct2, "angle");
2279
2315
  if (angle2 < doorSearchNearAngle) {
2280
2316
  if (!quadtree.queryLineSegment(line2).length) {
2281
2317
  list.push({
2282
2318
  findData: res[i],
2283
- findDoorIndex: doorIndex2,
2284
- findAngle: angle2,
2285
- doorAngle: angle,
2319
+ findUuid: id2,
2286
2320
  doorLine: line2,
2287
- doorIndex
2321
+ doorUuid: id1
2288
2322
  });
2289
2323
  }
2290
2324
  }
@@ -2292,65 +2326,15 @@ class LineAnalysis extends Component {
2292
2326
  }
2293
2327
  return list;
2294
2328
  }
2295
- function searchAlongDirection({ point, line }) {
2296
- const direct = line.direction();
2297
- if (line.start === point) direct.multiplyScalar(-1);
2298
- const endPoint = point.clone().add(direct.clone().multiplyScalar(doorSearchDistance)), rline = new LineSegment(point.clone(), endPoint), result = quadtree.queryLineSegment(rline).map((l) => {
2299
- const res = l.line.getIntersection(rline);
2300
- return {
2301
- point: res,
2302
- line: l.line
2303
- };
2304
- }).filter((i) => i.point).sort((a, b) => point.distance(a.point) - point.distance(b.point));
2305
- if (result.length) {
2306
- const item = result[0];
2307
- if (Math.abs(90 - item.line.direction().angleBetween(direct, "angle")) < 5) {
2308
- return item;
2309
- }
2310
- }
2311
- }
2312
- function searchAlongNormalDirection({ point, line, index: index2 }) {
2313
- const direct = line.direction();
2314
- if (line.start === point) direct.multiplyScalar(-1);
2315
- const normal = line.start.normal(line.end);
2316
- const prePoint = line.start.clone();
2317
- if (line.start === point) prePoint.copy(line.end);
2318
- const result = pointVirtualGrid.queryPoint(prePoint).filter((r) => r.userData?.index !== index2);
2319
- for (let i = 0; i < result.length; i++) {
2320
- const element = result[i];
2321
- const l = dxf.lineSegments[element.userData?.index ?? 0];
2322
- const d1 = l.direction();
2323
- if (l.start === element.point) direct.multiplyScalar(-1);
2324
- const angle = d1.angleBetween(normal) / (Math.PI / 180);
2325
- if (angle > 90) {
2326
- normal.multiplyScalar(-1);
2327
- break;
2328
- }
2329
- }
2330
- const rline3 = new LineSegment(point.clone(), point.clone().add(normal.multiplyScalar(doorSearchDistance)));
2331
- const r3 = quadtree.queryLineSegment(rline3).map((l) => {
2332
- const res = l.line.getIntersection(rline3);
2333
- return {
2334
- point: res,
2335
- line: l.line
2336
- };
2337
- }).filter((i) => i.point).sort((a, b) => point.distance(a.point) - point.distance(b.point));
2338
- if (r3.length) {
2339
- const item = r3[0];
2340
- if (Math.abs(90 - item.line.direction().angleBetween(normal, "angle")) < 5) {
2341
- return item;
2342
- }
2343
- }
2344
- }
2345
- function deepSearchNearHandle(index2, snFindRecord2, list, record2, other) {
2346
- record2.add(`${index2}`);
2329
+ function deepSearchNearHandle(uuid2, snFindRecord2, list, record2, other) {
2330
+ record2.add(uuid2);
2347
2331
  const newList = [];
2348
2332
  if (other) newList.push(other);
2349
2333
  for (let i = 0; i < list.length; i++) {
2350
2334
  const item = list[i];
2351
- if (snFindRecord2.has(item.findDoorIndex)) {
2352
- const list2 = snFindRecord2.get(item.findDoorIndex);
2353
- 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);
2354
2338
  } else newList.push(item);
2355
2339
  }
2356
2340
  newList.sort((a, b) => a.doorLine.length() - b.doorLine.length());
@@ -2364,22 +2348,21 @@ class LineAnalysis extends Component {
2364
2348
  const record = /* @__PURE__ */ new Set();
2365
2349
  const snFindRecord = /* @__PURE__ */ new Map();
2366
2350
  doorPoints.map((p, index2) => {
2367
- if (dxf.doors.length >= 2 && !p.sure) return;
2368
- const list = searchNearby(p, index2, record);
2369
- if (list.length) snFindRecord.set(index2, list);
2351
+ const list = find(p, index2, record);
2352
+ if (list.length) snFindRecord.set(p.uuid, list);
2370
2353
  });
2371
2354
  record.clear();
2372
2355
  const temMap = /* @__PURE__ */ new Map();
2373
2356
  snFindRecord.forEach((list, key) => {
2374
- if (!record.has(`${key}`) && list.length) {
2357
+ if (!record.has(key) && list.length) {
2375
2358
  deepSearchNearHandle(key, snFindRecord, list, record);
2376
2359
  }
2377
2360
  if (list.length) {
2378
2361
  const item = list[0];
2379
- if (!temMap.has(item.doorIndex)) temMap.set(item.doorIndex, []);
2380
- temMap.get(item.doorIndex)?.push(item);
2381
- if (!temMap.has(item.findDoorIndex)) temMap.set(item.findDoorIndex, []);
2382
- 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);
2383
2366
  }
2384
2367
  });
2385
2368
  const deleteSet = /* @__PURE__ */ new Set();
@@ -2389,38 +2372,24 @@ class LineAnalysis extends Component {
2389
2372
  for (let i = 1; i < list.length; i++) deleteSet.add(list[i]);
2390
2373
  }
2391
2374
  });
2392
- const searchNearRasult = [], removeDoorPointsIndex = [];
2375
+ const searchNearRasult = [], removeDoorPointsUuid = [];
2393
2376
  snFindRecord.forEach((list) => {
2394
2377
  if (list.length) {
2395
2378
  const item = list[0];
2396
2379
  if (!deleteSet.has(item)) {
2397
2380
  searchNearRasult.push(item);
2398
- removeDoorPointsIndex.push(item.doorIndex, item.findDoorIndex);
2381
+ removeDoorPointsUuid.push(item.doorUuid, item.findUuid);
2399
2382
  }
2400
2383
  }
2401
2384
  });
2402
- const doors_ = doorPoints.map((item, index2) => {
2403
- if (removeDoorPointsIndex.includes(index2)) return;
2404
- if (dxf.doors.length >= 2 && !item.sure) return;
2405
- const res2 = searchAlongDirection(item);
2406
- if (res2) return {
2407
- start: item.point,
2408
- end: res2.point,
2409
- index: item.index
2410
- };
2411
- const res3 = searchAlongNormalDirection(item);
2412
- if (res3) return {
2413
- start: item.point,
2414
- end: res3.point,
2415
- index: item.index
2416
- };
2417
- }).filter((i) => !!i && i.start.distance(i.end) < doorSearchDistance);
2418
- doors.push(...doors_);
2385
+ const doors = [];
2419
2386
  searchNearRasult.forEach((item) => {
2420
- const start = doorPoints[item.doorIndex].point.clone();
2421
- const end = doorPoints[item.findDoorIndex].point.clone();
2422
- const startLine = this.findLongLineSegment(doorPoints[item.doorIndex].line);
2423
- 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);
2424
2393
  const p = startLine.projectPoint(end);
2425
2394
  if (p) {
2426
2395
  start.copy(p);
@@ -2429,8 +2398,7 @@ class LineAnalysis extends Component {
2429
2398
  if (angle < 10 || angle > 170 || Math.abs(90 - angle) < 10) {
2430
2399
  doors.push({
2431
2400
  start,
2432
- end,
2433
- index: doorPoints[item.doorIndex].index
2401
+ end
2434
2402
  });
2435
2403
  }
2436
2404
  } else {
@@ -2441,30 +2409,82 @@ class LineAnalysis extends Component {
2441
2409
  if (angle < 10 || angle > 170 || Math.abs(90 - angle) < 10) {
2442
2410
  doors.push({
2443
2411
  start,
2444
- end,
2445
- index: doorPoints[item.doorIndex].index
2412
+ end
2446
2413
  });
2447
2414
  }
2448
2415
  }
2449
2416
  });
2450
- dxf.doorLineSegment.length = 0;
2451
- doors.forEach((p) => {
2452
- const line = new LineSegment(p?.start, p?.end);
2453
- const len = line.length();
2454
- if (len < 0.6) return;
2455
- const normal = line.normal(), direction = line.direction(), step = (len - dxf.width * 2) / 2;
2456
- for (let i = 0; i < 3; i++) {
2457
- const point = line.start.clone().add(direction.clone().multiplyScalar(dxf.width + step * i));
2458
- const rLine = new LineSegment(
2459
- point,
2460
- point.clone().add(normal.clone().multiplyScalar(1))
2461
- );
2462
- rLine.directionMove(normal, -0.5);
2463
- const res = this.quadtree?.queryLineSegment(rLine);
2464
- 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;
2465
2449
  }
2466
- dxf.doorLineSegment.push(line);
2467
- });
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
+ }
2468
2488
  }
2469
2489
  /**
2470
2490
  *
@@ -2476,8 +2496,7 @@ class LineAnalysis extends Component {
2476
2496
  const res1 = this.pointVirtualGrid.queryPoint(line.start);
2477
2497
  const res2 = this.pointVirtualGrid.queryPoint(line.end);
2478
2498
  for (let i = 0; i < res1.length; i++) {
2479
- const { userData } = res1[i];
2480
- const line2 = this.lineSegmentList[userData?.index];
2499
+ const { userData: line2 } = res1[i];
2481
2500
  if (line2 === line) continue;
2482
2501
  if (line2 && line2.directionEqual(line)) {
2483
2502
  if (line2.start.equal(line.start)) resLine.start.copy(line2.end);
@@ -2486,8 +2505,7 @@ class LineAnalysis extends Component {
2486
2505
  }
2487
2506
  }
2488
2507
  for (let i = 0; i < res2.length; i++) {
2489
- const { userData } = res2[i];
2490
- const line2 = this.lineSegmentList[userData?.index];
2508
+ const { userData: line2 } = res2[i];
2491
2509
  if (line2 === line) continue;
2492
2510
  if (line2 && line2.directionEqual(line)) {
2493
2511
  if (line2.end.equal(line.end)) resLine.end.copy(line2.start);
@@ -2497,127 +2515,169 @@ class LineAnalysis extends Component {
2497
2515
  }
2498
2516
  return resLine;
2499
2517
  }
2500
- doorsAnalysis2() {
2501
- const renderer = this.parent?.findComponentByName("Renderer");
2502
- const dxf = this.Dxf, pointVirtualGrid = this.pointVirtualGrid, quadtree = this.quadtree;
2503
- this.doorSearchNearAngle;
2504
- this.doorSearchDistance;
2505
- const doorsAnalysis = new DoorsAnalysis(dxf, pointVirtualGrid, quadtree, this.resultList, this.lineSegmentList);
2506
- const possiblePoints = doorsAnalysis.searchPossiblePoints();
2507
- possiblePoints.forEach((l) => {
2508
- renderer.createPointMesh(l.point).position.z = dxf.originalZAverage;
2509
- });
2510
- }
2511
2518
  }
2512
- class DoorsAnalysis {
2513
- // 所有可查找的点位
2514
- possibleDoorPoints = [];
2515
- doorPoint = [];
2516
- dxf;
2517
- pointVirtualGrid;
2518
- quadtree;
2519
- resultList;
2520
- // 已过滤门的线段
2521
- lineSegments;
2522
- constructor(dxf, pointVirtualGrid, quadtree, resultList = [], lineSegments = []) {
2523
- this.dxf = dxf;
2524
- this.pointVirtualGrid = pointVirtualGrid;
2525
- this.quadtree = quadtree;
2526
- this.resultList = resultList;
2527
- this.lineSegments = lineSegments;
2528
- this.addPointsExcludeRule((line) => line.userData.isDoor);
2529
- const excludeIndexMap = this.searchDoubleLinePoint();
2530
- this.addPointsExcludeRule((_1, _2, index2, pointIndex) => {
2531
- const excludeMode = excludeIndexMap.get(index2);
2532
- if (typeof excludeMode === "number") {
2533
- return excludeMode === -1 || excludeMode === pointIndex;
2534
- }
2535
- return false;
2536
- });
2537
- this.doorPoint = this.searchDoorPoint();
2538
- this.addPointsExcludeRule((_1, point) => {
2539
- return !!this.doorPoint.find((p1) => p1.point.equal(point));
2540
- });
2541
- this.possibleDoorPoints = this.searchPossiblePoints();
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));
2542
2537
  }
2543
2538
  /**
2544
2539
  *
2545
- * @param rule
2540
+ * @param p1
2541
+ * @param p2
2542
+ * @param width
2543
+ * @returns
2546
2544
  */
2547
- addPointsExcludeRule(rule) {
2548
- 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
+ };
2549
2563
  }
2550
- _pointsExcludeRule = [];
2564
+ appendLineSegmentList = [];
2551
2565
  /**
2552
- * 查找所有可能为门的点位
2566
+ * 追加数据
2567
+ * @param p1
2568
+ * @param p2
2553
2569
  */
2554
- searchPossiblePoints() {
2555
- const dxf = this.dxf, doorPoints = [];
2556
- dxf.lineSegments.forEach((line, i) => {
2557
- line.points.forEach((p, j) => {
2558
- for (let i2 = 0; i2 < this._pointsExcludeRule.length; i2++)
2559
- if (this._pointsExcludeRule[i2](line, p, i2, j)) return;
2560
- const res = this.pointVirtualGrid.queryPoint(p).filter((d) => d.userData?.index !== i);
2561
- if (res.length === 0) {
2562
- doorPoints.push({
2563
- line,
2564
- point: p,
2565
- index: i
2566
- });
2567
- }
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()));
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;
2598
+ /**
2599
+ * 构建线段四叉树,快速查找,
2600
+ */
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
2568
2610
  });
2611
+ lineSegmentList.push(lineSegment);
2569
2612
  });
2570
- return doorPoints;
2613
+ this.lineSegmentList = lineSegmentList;
2571
2614
  }
2572
- /**
2573
- * 查找已知为门的点位
2615
+ resultList = [];
2616
+ mergeWallLines = [];
2617
+ /** 线段分析
2618
+ * @description 判断两条线段距离是否较短且趋近平行,然后查找两条线段的重合部分的投影线,以此判断两根线是否需要合并
2619
+ * @param data
2574
2620
  */
2575
- searchDoorPoint() {
2576
- const doorPoints = [], dxf = this.dxf, pointVirtualGrid = this.pointVirtualGrid;
2577
- dxf.doors.forEach((item) => {
2578
- const index2 = item[4];
2579
- const doorData = dxf.originalData[index2];
2580
- if (doorData.drawDoorData) {
2581
- const point = Point.from(doorData.drawDoorData.start);
2582
- const direct = Point.from(doorData.drawDoorData.n);
2583
- const resList = pointVirtualGrid.queryPoint(point).filter((res) => {
2584
- if (res.userData?.index === index2) return false;
2585
- const line = dxf.lineSegments[res.userData?.index];
2586
- const direct2 = line.direction();
2587
- if (line.start.equal(point)) direct2.multiplyScalar(-1);
2588
- const angle = direct.angleBetween(direct2, "angle");
2589
- return angle > 80 || angle < 10;
2590
- });
2591
- if (resList.length) {
2592
- const index22 = resList[0].userData?.index;
2593
- doorPoints.push({
2594
- line: dxf.lineSegments[index22],
2595
- point: Point.from(doorData.drawDoorData.start),
2596
- index: index22,
2597
- direct,
2598
- sure: true
2599
- });
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) {
2600
2635
  }
2601
- }
2636
+ });
2602
2637
  });
2603
- return doorPoints;
2638
+ this.appendLineSegmentList.length = 0;
2639
+ resultList.forEach(this.createRectangle.bind(this));
2640
+ this.resultList = resultList;
2604
2641
  }
2605
- /**
2606
- * 查找双线墙的点位
2642
+ /** 线段投影分析
2643
+ * @param index
2644
+ * @param sourceLineSegment
2645
+ * @param lineSegmentList
2607
2646
  * @returns
2608
2647
  */
2609
- searchDoubleLinePoint() {
2610
- const excludeIndexMap = /* @__PURE__ */ new Map();
2611
- this.resultList.flatMap((p) => {
2612
- 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;
2613
- if (excludeIndexMap.has(p.sourceIndex)) {
2614
- if (excludeIndexMap.get(p.sourceIndex) != mode0) excludeIndexMap.set(p.sourceIndex, -1);
2615
- } else excludeIndexMap.set(p.sourceIndex, mode0);
2616
- if (excludeIndexMap.has(p.targetIndex)) {
2617
- if (excludeIndexMap.get(p.targetIndex) != mode1) excludeIndexMap.set(p.targetIndex, -1);
2618
- } else excludeIndexMap.set(p.targetIndex, mode1);
2619
- });
2620
- return excludeIndexMap;
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);
2621
2681
  }
2622
2682
  }
2623
2683
  class DxfSystem extends ComponentManager {
@@ -2970,38 +3030,84 @@ class DxfLineModel extends Component {
2970
3030
  updateMode() {
2971
3031
  const dxf = this.parent?.findComponentByName("Dxf");
2972
3032
  this.dxfLineModel.clear();
2973
- const dxfArray = dxf.to3DArray(1 / dxf.scale);
3033
+ const dxfArray = dxf.to3DArray(1 / dxf.scale, 0);
2974
3034
  this.dxfLineModel.geometry = new THREE.BufferGeometry().setAttribute("position", new THREE.BufferAttribute(dxfArray, 3, true));
2975
3035
  const doorsArray = new Float32Array(
2976
- 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])
2977
3037
  ).map((n) => n / dxf.scale);
2978
3038
  const doorsColorArray = new Float32Array(dxf.doorLineSegment.flatMap(() => [1, 0, 0, 0, 1, 0]));
2979
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
+ });
2980
3045
  }
2981
3046
  }
2982
- const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
3047
+ const index$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2983
3048
  __proto__: null,
2984
3049
  DetailsPoint,
2985
3050
  DxfLineModel,
2986
3051
  WhiteModel
2987
3052
  }, Symbol.toStringTag, { value: "Module" }));
2988
- function ModelDataPlugin(dxfSystem) {
2989
- dxfSystem.addComponent(new DxfLineModel());
2990
- dxfSystem.addComponent(new WhiteModel());
2991
- 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());
2992
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" }));
2993
3073
  function loadRenderPlugin() {
2994
3074
  return import("./index2.js");
2995
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
+ }
2996
3098
  export {
2997
3099
  Box2 as B,
2998
3100
  Component as C,
2999
3101
  DxfSystem as D,
3102
+ EventDispatcher as E,
3103
+ LineSegment as L,
3000
3104
  ModelDataPlugin as M,
3001
3105
  Point as P,
3106
+ Quadtree as Q,
3002
3107
  Variable as V,
3003
3108
  WhiteModel as W,
3004
3109
  DetailsPoint as a,
3005
- index as i,
3006
- loadRenderPlugin as l
3110
+ PointVirtualGrid as b,
3111
+ createEditor as c,
3112
+ index$1 as i
3007
3113
  };