build-dxf 0.1.48 → 0.1.50

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "build-dxf",
3
- "version": "0.1.48",
3
+ "version": "0.1.50",
4
4
  "description": "线段构建双线墙壁的dxf版本",
5
5
  "main": "./src/index.js",
6
6
  "types": "./src/index.d.ts",
@@ -1230,12 +1230,12 @@ class DomEventRegister extends Component {
1230
1230
  const click = (e) => {
1231
1231
  if (lock) return;
1232
1232
  lock = true;
1233
+ setTimeout(() => lock = false, 200);
1233
1234
  let rect = domElement.getBoundingClientRect();
1234
1235
  const { offsetX, offsetY } = this.computedPosition(e, rect);
1235
1236
  if (!this.pointInDOMRect(offsetX, offsetY, rect)) return;
1236
1237
  this.pointer.set(offsetX, offsetY);
1237
1238
  this.dispatchEvent({ type: "click", x: offsetX, y: offsetY });
1238
- setTimeout(() => lock = false, 100);
1239
1239
  };
1240
1240
  document.addEventListener("click", click);
1241
1241
  this.addEventRecord("destory", () => {
package/src/build.js CHANGED
@@ -946,6 +946,13 @@ class MapEnhance extends Map {
946
946
  }
947
947
  return result;
948
948
  }
949
+ filterKey(callbackfn) {
950
+ const result = [];
951
+ for (const [k, v2] of this) {
952
+ callbackfn(v2, k) && result.push(k);
953
+ }
954
+ return result;
955
+ }
949
956
  reduce(callbackfn, result) {
950
957
  for (const [k, v2] of this) {
951
958
  result = callbackfn(result, v2, k);
@@ -1023,7 +1030,7 @@ class ArrayMap extends MapEnhance {
1023
1030
  const list = this.get(k);
1024
1031
  list.push(v2);
1025
1032
  if (list.length > this.maxLength) {
1026
- list.splice(0, this.maxLength - list.length);
1033
+ list.splice(0, list.length - this.maxLength);
1027
1034
  }
1028
1035
  });
1029
1036
  return this;
@@ -1060,12 +1067,20 @@ class SetMap extends MapEnhance {
1060
1067
  return this.get(key)?.has(value) ?? false;
1061
1068
  }
1062
1069
  }
1063
- class CountMap extends MapEnhance {
1064
- set(key) {
1065
- let count = super.get(key) ?? 0;
1066
- super.set(key, ++count);
1070
+ class CounterMap extends MapEnhance {
1071
+ set(key, step = 1) {
1072
+ console.warn("Use increment() instead of set() in CounterMap");
1073
+ this.increment(key, step);
1074
+ return this;
1075
+ }
1076
+ increment(key, step = 1) {
1077
+ const count = super.get(key) ?? 0;
1078
+ super.set(key, count + step);
1067
1079
  return this;
1068
1080
  }
1081
+ getByCount(count) {
1082
+ return this.filterKey((v2) => v2 === count);
1083
+ }
1069
1084
  }
1070
1085
  class UnionFindSet {
1071
1086
  parent;
@@ -1148,7 +1163,11 @@ function addLengthAsyncClear(line) {
1148
1163
  });
1149
1164
  set$1.add(line);
1150
1165
  }
1166
+ const LINE_SYMBOL = Symbol("LINE_SYMBOL");
1151
1167
  class LineSegment {
1168
+ static get LINE_SYMBOL() {
1169
+ return LINE_SYMBOL;
1170
+ }
1152
1171
  points = [new Point(), new Point()];
1153
1172
  userData = {};
1154
1173
  currentData = {};
@@ -1166,8 +1185,10 @@ class LineSegment {
1166
1185
  get end() {
1167
1186
  return this.points[1];
1168
1187
  }
1169
- constructor(p1 = new Point(), p2 = new Point()) {
1170
- this.points = [p1, p2];
1188
+ constructor(p1, p2) {
1189
+ this.set(p1 ?? this.start, p2 ?? this.end);
1190
+ this.start.currentData[LineSegment.LINE_SYMBOL] = this;
1191
+ this.end.currentData[LineSegment.LINE_SYMBOL] = this;
1171
1192
  }
1172
1193
  set(p1, p2) {
1173
1194
  this.start.copy(p1);
@@ -1731,6 +1752,13 @@ class LineSegment {
1731
1752
  this.start.copy(line.start);
1732
1753
  this.end.copy(line.end);
1733
1754
  }
1755
+ /** 获取点属于的线段
1756
+ * @param point
1757
+ * @returns
1758
+ */
1759
+ static getPointBelongLine(point2) {
1760
+ return point2.currentData[LINE_SYMBOL] ?? null;
1761
+ }
1734
1762
  /**
1735
1763
  * 获取最长线段
1736
1764
  * @param lines
@@ -2135,8 +2163,8 @@ class LineSegment {
2135
2163
  for (const line of lines) {
2136
2164
  const p1 = line.start;
2137
2165
  const p2 = line.end;
2138
- const key1 = `${p1.x.toFixed(6)}_${p1.y.toFixed(6)}`;
2139
- const key2 = `${p2.x.toFixed(6)}_${p2.y.toFixed(6)}`;
2166
+ const key1 = `${p1.x.toFixed(2)}_${p1.y.toFixed(2)}`;
2167
+ const key2 = `${p2.x.toFixed(2)}_${p2.y.toFixed(2)}`;
2140
2168
  const key = key1 < key2 ? `${key1}_${key2}` : `${key2}_${key1}`;
2141
2169
  if (!seen.has(key)) {
2142
2170
  seen.add(key);
@@ -2203,7 +2231,7 @@ class LineSegment {
2203
2231
  const arrayMap = modifyMap.get(line);
2204
2232
  arrayMap.append(point2, value);
2205
2233
  }
2206
- function modify2() {
2234
+ function modify() {
2207
2235
  modifyMap.forEach((arrayMap, line) => {
2208
2236
  arrayMap.forEach((list, point2) => {
2209
2237
  const otherPoint = line.getAnotherPoint(point2);
@@ -2220,7 +2248,10 @@ class LineSegment {
2220
2248
  return setPoint;
2221
2249
  },
2222
2250
  get modify() {
2223
- return modify2;
2251
+ return modify;
2252
+ },
2253
+ clear() {
2254
+ modifyMap.clear();
2224
2255
  }
2225
2256
  };
2226
2257
  }
@@ -2400,12 +2431,12 @@ class Point {
2400
2431
  * @param point
2401
2432
  * @returns
2402
2433
  */
2403
- direction(point2) {
2434
+ direction(point2, out = new Point()) {
2404
2435
  const dx = this.x - point2.x;
2405
2436
  const dy = this.y - point2.y;
2406
2437
  const length = Math.sqrt(dx * dx + dy * dy);
2407
- if (length === 0) return new Point(0, 0);
2408
- return new Point(dx / length, dy / length);
2438
+ if (length !== 0) out.set(dx / length, dy / length);
2439
+ return out;
2409
2440
  }
2410
2441
  /** 展开为线
2411
2442
  * @param direction
@@ -2484,7 +2515,7 @@ class Point {
2484
2515
  * @param point
2485
2516
  */
2486
2517
  _distanceMap = /* @__PURE__ */ new Map();
2487
- distance(point2, cached = true) {
2518
+ distance(point2, cached = false) {
2488
2519
  if (cached && this._distanceMap.has(point2)) return this._distanceMap.get(point2);
2489
2520
  const num = Math.sqrt(
2490
2521
  (this.x - point2.x) * (this.x - point2.x) + (this.y - point2.y) * (this.y - point2.y)
@@ -2531,7 +2562,12 @@ class Point {
2531
2562
  toVector3(z = 0) {
2532
2563
  return new Vector3(this.x, this.y, z);
2533
2564
  }
2534
- static adsorb(points, tolerance = 15e-5) {
2565
+ /** 点吸附
2566
+ * @param points
2567
+ * @param tolerance
2568
+ * @returns
2569
+ */
2570
+ static adsorb(points, tolerance = 15e-5, mode = "average") {
2535
2571
  const grid = new PointVirtualGrid();
2536
2572
  points.forEach((p2) => grid.insert(p2));
2537
2573
  const visited = /* @__PURE__ */ new Set();
@@ -2539,21 +2575,30 @@ class Point {
2539
2575
  const point2 = points[i];
2540
2576
  if (visited.has(point2)) continue;
2541
2577
  const results = grid.queryCircle(point2, tolerance).map((item) => item.point);
2542
- let countX = 0, countY = 0;
2543
- results.forEach((point22) => {
2544
- countX += point22.x;
2545
- countY += point22.y;
2546
- });
2547
- const x = countX / results.length, y = countY / results.length;
2548
- results.forEach((point22) => {
2549
- point22.set(x, y);
2550
- visited.add(point22);
2551
- grid.remove(point22);
2578
+ let x = 0, y = 0;
2579
+ if (mode === "average") {
2580
+ let countX = 0, countY = 0;
2581
+ results.forEach((point22) => (countX += point22.x, countY += point22.y));
2582
+ x = countX / results.length;
2583
+ y = countY / results.length;
2584
+ } else {
2585
+ x = point2.x;
2586
+ y = point2.y;
2587
+ }
2588
+ results.forEach((p2) => {
2589
+ p2.set(x, y);
2590
+ visited.add(p2);
2591
+ grid.update(p2);
2592
+ grid.remove(p2);
2552
2593
  });
2553
2594
  }
2554
2595
  visited.clear();
2555
2596
  return points;
2556
2597
  }
2598
+ /** 创建
2599
+ * @param arr
2600
+ * @returns
2601
+ */
2557
2602
  static from(arr) {
2558
2603
  if (Array.isArray(arr)) {
2559
2604
  return new Point(arr[0], arr[1]);
@@ -5075,12 +5120,12 @@ class LineGroupType {
5075
5120
  * @returns
5076
5121
  */
5077
5122
  static getIntersectionTypes(lines) {
5078
- const countMap = new CountMap();
5123
+ const countMap = new CounterMap();
5079
5124
  lines.forEach((line) => {
5080
5125
  if (line.userData.groups) {
5081
5126
  line.userData.groups.forEach((group2) => countMap.set(group2.type));
5082
5127
  }
5083
- if (line.userData.groupType) countMap.set(line.userData.groupType);
5128
+ if (line.userData.groupType) countMap.increment(line.userData.groupType);
5084
5129
  });
5085
5130
  const types = [];
5086
5131
  countMap.forEach((v2, k) => {
@@ -5185,6 +5230,7 @@ class LineGroupType {
5185
5230
  }
5186
5231
  function mergeLineUserData(line1, line2) {
5187
5232
  if (Array.isArray(line2)) {
5233
+ line2 = [...line2].sort((a2, b4) => a2.length(true) - b4.length(true));
5188
5234
  return line2.forEach((l) => mergeLineUserData(line1, l));
5189
5235
  }
5190
5236
  const { drawWindow, ...opt } = line2.userData;
@@ -6376,6 +6422,12 @@ class LineSegmentUndirectedGraph extends UndirectedGraph {
6376
6422
  const key = a2 < b4 ? `${a2}-${b4}` : `${b4}-${a2}`;
6377
6423
  return this.lineMap.get(key);
6378
6424
  }
6425
+ /** 获取所有线段
6426
+ * @returns
6427
+ */
6428
+ getLineAll() {
6429
+ return Array.from(this.lineMap.values());
6430
+ }
6379
6431
  /**
6380
6432
  * 获取或创建点的索引
6381
6433
  */
@@ -6421,6 +6473,20 @@ class LineSegmentUndirectedGraph extends UndirectedGraph {
6421
6473
  this.buildFromLines(lines);
6422
6474
  return this;
6423
6475
  }
6476
+ /** 批量移除线段边
6477
+ * @param lines
6478
+ */
6479
+ removeLines(lines) {
6480
+ for (const line of lines) {
6481
+ const i1 = this.getIndex(line.start);
6482
+ const i2 = this.getIndex(line.end);
6483
+ if (i1 !== void 0 && i2 !== void 0) {
6484
+ super.removeEdge(i1, i2);
6485
+ const key = i1 < i2 ? `${i1}-${i2}` : `${i2}-${i1}`;
6486
+ this.lineMap.delete(key);
6487
+ }
6488
+ }
6489
+ }
6424
6490
  /** 路径转线段组
6425
6491
  * @param path
6426
6492
  */
@@ -6442,6 +6508,47 @@ class LineSegmentUndirectedGraph extends UndirectedGraph {
6442
6508
  this.indexToPoint.clear();
6443
6509
  this.nextIndex = 0;
6444
6510
  }
6511
+ /** 断点合并
6512
+ * @description 合并断开的直线,断点
6513
+ * @param lines
6514
+ * @param callBack
6515
+ * @returns
6516
+ */
6517
+ breakpointMerging(callBack, removeLines = /* @__PURE__ */ new Set(), newLines = []) {
6518
+ const unionFindSet = new UnionFindSet(this.lineMap.size);
6519
+ const lineIndexGenerator = new LineIndexGenerator();
6520
+ this.adjacencyList.forEach((set2, k) => {
6521
+ if (set2.size !== 2) return;
6522
+ const values = set2.values(), v12 = values.next().value, v2 = values.next().value, line1 = this.getLine(k, v12), line2 = this.getLine(k, v2);
6523
+ if (!line1.parallel(line2)) return;
6524
+ unionFindSet.union(
6525
+ lineIndexGenerator.getIndex(line1),
6526
+ lineIndexGenerator.getIndex(line2)
6527
+ );
6528
+ });
6529
+ unionFindSet.getAllSets().forEach((list) => {
6530
+ if (list.length <= 1) return;
6531
+ const lines = list.map((i) => lineIndexGenerator.getLine(i)), newLine = LineSegment.mergeLines(...lines);
6532
+ callBack && callBack(newLine, lines);
6533
+ lines.forEach((line) => removeLines.add(line));
6534
+ newLines.push(newLine);
6535
+ this.removeLines(lines);
6536
+ this.addLines([newLine]);
6537
+ });
6538
+ }
6539
+ /** 断点合并
6540
+ * @param lines
6541
+ * @param callBack
6542
+ * @param removeLines
6543
+ * @param newLines
6544
+ * @returns
6545
+ */
6546
+ static breakpointMerging(lines, callBack, removeLines = /* @__PURE__ */ new Set(), newLines = []) {
6547
+ const lud = new LineSegmentUndirectedGraph(lines);
6548
+ lud.breakpointMerging(callBack, removeLines, newLines);
6549
+ lines = lud.getLineAll();
6550
+ return lines;
6551
+ }
6445
6552
  /** 线段图旋转
6446
6553
  * @param lines
6447
6554
  * @param angle 弧度
@@ -6609,13 +6716,13 @@ class MaxiCircles extends MiniCircles {
6609
6716
  else visited.set(line, index2);
6610
6717
  }
6611
6718
  });
6612
- const countMap = new CountMap();
6719
+ const countMap = new CounterMap();
6613
6720
  const groups = unionFindSet.getAllSets().valueArray.map((list) => {
6614
6721
  let group2 = list.map((i) => circles[i]);
6615
6722
  if (group2.length === 1) return group2[0];
6616
6723
  countMap.clear();
6617
6724
  group2 = this.deduplicate(group2);
6618
- group2.forEach((lines) => lines.forEach((line) => countMap.set(line)));
6725
+ group2.forEach((lines) => lines.forEach((line) => countMap.increment(line)));
6619
6726
  if (test) {
6620
6727
  countMap.forEach((count, line) => drawText(count, line.center));
6621
6728
  drawLines(circles.flat(), { color: randomColor() });
@@ -6833,8 +6940,14 @@ class DoubleWallHelper {
6833
6940
  return data;
6834
6941
  }
6835
6942
  }
6943
+ /** 查找
6944
+ * @param lines
6945
+ * @param wallWidth
6946
+ * @returns
6947
+ */
6836
6948
  static findDoubleLine(lines, wallWidth = 0.4) {
6837
- const walls = lines.filter((line) => !line.userData.isDoor && !LineGroupType.hasType(line, "doubleWall")), visited = /* @__PURE__ */ new Set(), resultList = [];
6949
+ let walls = lines.filter((line) => !line.userData.isDoor && !LineGroupType.hasType(line, "doubleWall")), visited = /* @__PURE__ */ new Set(), resultList = [];
6950
+ walls = walls.filter((line) => !line.userData.isWindowWall);
6838
6951
  let quadtree = new Quadtree(Box2.fromByLineSegment(...walls));
6839
6952
  walls.forEach((line, index2) => quadtree.insert({ line, userData: index2 }));
6840
6953
  walls.forEach((sourceLineSegment, i) => {
@@ -6856,10 +6969,7 @@ class DoubleWallHelper {
6856
6969
  quadtree
6857
6970
  };
6858
6971
  }
6859
- // static findDoubleLine2( lines: LineSegment<LineUserData>[], wallWidth = 0.4 ) {
6860
- // // LineSegment.groupByAxis()
6861
- // }
6862
- /**
6972
+ /** 补双线墙壁
6863
6973
  * @param lines
6864
6974
  * @param wallWidth
6865
6975
  * @returns
@@ -6940,6 +7050,67 @@ class DoubleWallHelper {
6940
7050
  return [...lineSegments, ...doors];
6941
7051
  }
6942
7052
  }
7053
+ class LineQueryer {
7054
+ pointVirtualGrid;
7055
+ quadtree;
7056
+ constructor(lines) {
7057
+ this.pointVirtualGrid = createPointVirtualGrid(lines);
7058
+ this.quadtree = createQuadtree(lines);
7059
+ }
7060
+ update(lines) {
7061
+ this.clear();
7062
+ this.pointVirtualGrid = createPointVirtualGrid(lines);
7063
+ this.quadtree = createQuadtree(lines);
7064
+ }
7065
+ clear() {
7066
+ this.pointVirtualGrid.clear();
7067
+ this.quadtree.clear();
7068
+ }
7069
+ /**
7070
+ * @param point
7071
+ * @param radius
7072
+ * @param opt
7073
+ * @returns
7074
+ */
7075
+ queryNearestPoint(point2, opt) {
7076
+ if (!point2) throw new Error("请传入查询点");
7077
+ const { resultIndex = 0, radius = 0.4, condition } = opt ?? {};
7078
+ const results = this.pointVirtualGrid.queryCircle(point2, radius).filter((item) => item.point !== point2).filter((item) => condition ? condition(item) : true);
7079
+ results.sort((a2, b4) => a2.point.distance(point2, true) - b4.point.distance(point2, true));
7080
+ if (results.length > resultIndex) return {
7081
+ point: results[resultIndex].point,
7082
+ line: results[resultIndex].userData
7083
+ };
7084
+ return null;
7085
+ }
7086
+ /**
7087
+ * @param point
7088
+ * @param radius
7089
+ * @param opt
7090
+ * @returns
7091
+ */
7092
+ queryNearestLine(point2, opt) {
7093
+ if (!point2) throw new Error("请传入查询点");
7094
+ const { resultIndex = 0, radius = 0.4, condition } = opt ?? {};
7095
+ const results = this.quadtree.queryCircle(point2, radius).map((item) => {
7096
+ const projPoint = item.line.projectPoint(point2, false);
7097
+ if (projPoint && (!condition || condition(item, projPoint))) {
7098
+ if (projPoint) return {
7099
+ ...item,
7100
+ distance: projPoint.distance(point2) ?? Infinity,
7101
+ projPoint
7102
+ };
7103
+ }
7104
+ return null;
7105
+ }).filter((i) => !!i);
7106
+ results.sort((a2, b4) => a2.distance - b4.distance);
7107
+ if (results.length > resultIndex) return {
7108
+ point: results[resultIndex].projPoint,
7109
+ line: results[resultIndex].line
7110
+ };
7111
+ return null;
7112
+ }
7113
+ }
6943
7114
  function shortDistanceLink(lines, radius = 0.1) {
6944
7115
  const dpLines = [...findDiscretePointLine2(lines.filter((line) => !line.userData.isDoor), void 0, false)], pointVirtualGrid = createPointVirtualGrid(dpLines), appendLines = [], visited = /* @__PURE__ */ new Set();
6945
7116
  const getWeight2 = (target, point2, line) => {
@@ -7014,7 +7185,7 @@ function calculateIntersectionPoint(lines) {
7014
7185
  quadtree.clear();
7015
7186
  return map;
7016
7187
  }
7017
- function correction$1(targettLine, lines, intersectMap, errAngle = 15) {
7188
+ function correction(targettLine, lines, intersectMap, errAngle = 15) {
7018
7189
  const parallelLines = [targettLine], verticalLines = [], doorLines = [], windowLines = [];
7019
7190
  function parallel(line) {
7020
7191
  if (line.userData.isDoor) return doorLines.push(line);
@@ -7120,7 +7291,7 @@ function removeGroupLinkLine(groups, intersectmap) {
7120
7291
  });
7121
7292
  return groups.map((group2) => group2.filter((line) => !removeSet.has(line)));
7122
7293
  }
7123
- function lineSegmentFitting2(groups, minWallWidth = 0.1, option) {
7294
+ function lineSegmentFitting(groups, minWallWidth = 0.1, option) {
7124
7295
  const { fittingMethod = "average" } = option ?? {};
7125
7296
  return groups.flatMap((group2) => {
7126
7297
  if (group2.length <= 1) return group2;
@@ -7145,89 +7316,101 @@ function lineSegmentFitting2(groups, minWallWidth = 0.1, option) {
7145
7316
  line.userData.wallWidth = line.userData.wallWidth ?? wallWidth;
7146
7317
  });
7147
7318
  Point.adsorb(group2.flatMap((line) => line.points), 5e-3);
7319
+ group2 = group2.filter((line) => line.length() > 1e-9);
7320
+ const points = group2.flatMap((line) => line.points);
7321
+ points.forEach((point2) => point2.currentData.sortValue = fittedLine.projectValue(point2));
7322
+ points.sort((a2, b4) => a2.currentData.sortValue - b4.currentData.sortValue);
7323
+ const visited = /* @__PURE__ */ new Set(), counter = new CounterMap(), arrayMap = new ArrayMap();
7324
+ for (let i = 0; i < points.length - 1; i++) {
7325
+ const point2 = points[i], line = LineSegment.getPointBelongLine(point2);
7326
+ if (visited.has(line)) continue;
7327
+ counter.clear();
7328
+ arrayMap.clear();
7329
+ for (let j = i + 1; j < points.length; j++) {
7330
+ const point22 = points[j], line2 = LineSegment.getPointBelongLine(point22);
7331
+ if (line === line2) {
7332
+ const countLines = counter.getByCount(2);
7333
+ if (countLines.length) {
7334
+ countLines.flatMap((line3) => arrayMap.get(line3)).sort((a2, b4) => b4 - a2).forEach((index2) => {
7335
+ points[index2].set(0, 0);
7336
+ points.splice(index2, 1);
7337
+ j--;
7338
+ });
7339
+ }
7340
+ if (j - i > 1) {
7341
+ point22.copy(points[i + 1]);
7342
+ points.splice(j, 1);
7343
+ }
7344
+ break;
7345
+ }
7346
+ counter.increment(line2);
7347
+ arrayMap.append(line2, j);
7348
+ }
7349
+ visited.add(line);
7350
+ }
7351
+ group2 = group2.filter((line) => line.length() > 1e-9);
7148
7352
  return group2;
7149
7353
  });
7150
7354
  }
7151
- function adsorption(lines, intersectionMap, option) {
7152
- const { snapThreshold: threshold = 0.2 } = option ?? {};
7153
- const pointVirtualGrid = new PointVirtualGrid(), quadtree = new Quadtree(Box2.fromByLineSegment(...lines)), queryLine = new LineSegment(), map = /* @__PURE__ */ new Map();
7154
- lines.forEach((line) => {
7155
- if (line.userData.isDoor) return;
7156
- quadtree.insert(line);
7157
- line.points.forEach((point2) => pointVirtualGrid.insert(point2, line));
7158
- });
7159
- function setPoint(line, line1) {
7160
- if (!map.has(line)) map.set(line, []);
7161
- map.get(line)?.push(line1);
7162
- }
7163
- function getAdsorptionPointByLine(point2, line) {
7164
- if (quadtree.queryPoint(point2).length > 1) return;
7165
- const direction = line.direction().multiplyScalar(threshold);
7166
- queryLine.set(point2, point2);
7167
- queryLine.start.add(direction);
7168
- queryLine.end.add(direction.multiplyScalar(-1));
7169
- const map2 = /* @__PURE__ */ new Map();
7170
- const list = quadtree.queryLineSegment(queryLine).filter((res) => res.line !== line).map((res) => {
7171
- const point22 = res.line.getIntersection(queryLine);
7172
- map2.set(res.line, point22);
7173
- return res.line;
7174
- }).sort((line1, line2) => {
7175
- const point1 = map2.get(line1);
7176
- const point22 = map2.get(line2);
7177
- if (point1 && point22) return point1.distance(point2) - point22.distance(point2);
7178
- return 0;
7355
+ function adsorption(lines, option) {
7356
+ const { snapThreshold: threshold = 0.2 } = option ?? {}, lineQueryer = new LineQueryer(lines), modifyManager = LineSegment.createModifyManager();
7357
+ function adsorptLine(point2, line) {
7358
+ const otherPoint = line.getAnotherPoint(point2);
7359
+ const direct = otherPoint.direction(point2);
7360
+ const len = line.length();
7361
+ const result = lineQueryer.queryNearestLine(point2, {
7362
+ radius: threshold,
7363
+ condition: (node, projPoint) => {
7364
+ if (line !== node.line && node.line.vertical(line, 35)) {
7365
+ if (projPoint.distance(point2) < len) return true;
7366
+ const direct2 = projPoint.direction(point2);
7367
+ return direct2.angleBetween(direct) > Math.PI * 0.5;
7368
+ }
7369
+ return false;
7370
+ }
7179
7371
  });
7180
- if (list.length) return map2.get(list[0]);
7181
- }
7182
- function getObtainNearestAbsorbableLine(point2, line) {
7183
- let newPoint = getAdsorptionPointByLine(point2, line);
7184
- if (newPoint) {
7185
- return setPoint(line, new LineSegment(point2.clone(), newPoint.clone()));
7186
- }
7187
- if (pointVirtualGrid.queryPoint(point2).filter((item) => item.userData !== line).length !== 0) return;
7188
- const list0 = quadtree.queryCircle(point2, 1e-3).filter((item) => item.line !== line);
7189
- if (list0.length > 0) return;
7190
- const list = pointVirtualGrid.queryCircle(point2, threshold).filter((item) => item.userData !== line && item.userData?.vertical(line)).sort((item02, item1) => item02.point.distance(point2) - item1.point.distance(point2));
7191
- if (!list.length) return;
7192
- const item0 = list[0];
7193
- const pPoint = item0.userData?.projectPoint(point2, false);
7194
- if (pPoint) {
7195
- const line0 = item0.userData;
7196
- setPoint(line, new LineSegment(point2.clone(), pPoint.clone()));
7197
- setPoint(line0, new LineSegment(item0.point.clone(), pPoint.clone()));
7198
- }
7199
- }
7200
- function handle(line, point2, intersectList) {
7201
- return null;
7372
+ if (result) return modifyManager.setPoint(line, point2, result.point.clone());
7373
+ }
7374
+ function adsorptPoint(point2, line) {
7375
+ const otherPoint = line.getAnotherPoint(point2);
7376
+ otherPoint.direction(point2);
7377
+ line.length();
7378
+ const result = lineQueryer.queryNearestPoint(point2, {
7379
+ radius: threshold,
7380
+ condition(node) {
7381
+ const line2 = node.userData;
7382
+ return line2.vertical(line, 15);
7383
+ }
7384
+ });
7385
+ if (result) {
7386
+ const propPoint = result.line.projectPoint(point2, false);
7387
+ if (propPoint) {
7388
+ modifyManager.setPoint(line, point2, propPoint);
7389
+ modifyManager.setPoint(result.line, result.point, propPoint);
7390
+ }
7391
+ }
7202
7392
  }
7203
7393
  for (let i = 0; i < lines.length; i++) {
7204
7394
  const line = lines[i];
7205
- const intersections = intersectionMap.get(line) ?? [];
7206
- const groups = intersections.reduce((groups2, item) => {
7207
- if (item.sourcePoint === line.start) groups2[0].push(item);
7208
- else groups2[1].push(item);
7209
- return groups2;
7210
- }, [[], []]);
7211
- const [isStart, isEnd] = line.points.map((point2, j) => {
7212
- if (!pointVirtualGrid.queryPoint(point2, true).length) {
7213
- const newPoint = handle(line, point2, groups[j]);
7214
- if (newPoint) {
7215
- point2.copy(newPoint);
7216
- pointVirtualGrid.update(point2);
7217
- quadtree.update(line);
7218
- } else return false;
7219
- }
7220
- return true;
7395
+ line.points.map((point2) => {
7396
+ let results = lineQueryer.pointVirtualGrid.queryPoint(point2, true);
7397
+ if (results.length === 0 && lineQueryer.quadtree.queryCircle(point2, 1e-3).length < 2) adsorptLine(point2, line);
7221
7398
  });
7222
- if (!isStart) getObtainNearestAbsorbableLine(line.start, line);
7223
- if (!isEnd) getObtainNearestAbsorbableLine(line.end, line);
7224
7399
  }
7225
- map.forEach((lines2, line) => {
7226
- const newLine = LineSegment.mergeLines(line, ...lines2);
7227
- line.set(newLine.start, newLine.end);
7228
- });
7229
- pointVirtualGrid.clear();
7230
- quadtree.clear();
7400
+ modifyManager.modify();
7401
+ lines = lines.filter((line) => line.length() > 1e-9);
7402
+ const dpls = [...findDiscretePointLine2(lines)];
7403
+ lineQueryer.update(lines);
7404
+ for (let i = 0; i < dpls.length; i++) {
7405
+ const line = dpls[i];
7406
+ line.points.map((point2) => {
7407
+ let results = lineQueryer.pointVirtualGrid.queryPoint(point2, true);
7408
+ if (results.length === 0 && lineQueryer.quadtree.queryCircle(point2, 1e-3).length < 2) adsorptPoint(point2, line);
7409
+ });
7410
+ }
7411
+ modifyManager.modify();
7412
+ lineQueryer.clear();
7413
+ Point.adsorb(lines.flatMap((line) => line.points), 1e-4, "first");
7231
7414
  return lines;
7232
7415
  }
7233
7416
  function removeShortLine(lines, doorLines, len = 0.01) {
@@ -7336,7 +7519,7 @@ class AxisAlignCorr {
7336
7519
  targettLine = targetLineIndex > -1 ? lines[targetLineIndex] : targettLine;
7337
7520
  lines = preprocessing(lines);
7338
7521
  const intersectionMap = calculateIntersectionPoint(lines);
7339
- const { parallelLines, verticalLines, doorLines } = correction$1(targettLine, lines, intersectionMap, 25);
7522
+ const { parallelLines, verticalLines, doorLines } = correction(targettLine, lines, intersectionMap, 25);
7340
7523
  const normal = targettLine.normal(), center = targettLine.center, direction = targettLine.direction(), xAxisLine = new LineSegment(
7341
7524
  center.clone().add(normal.clone().multiplyScalar(-1e3)),
7342
7525
  center.clone().add(normal.clone().multiplyScalar(1e3))
@@ -7346,13 +7529,14 @@ class AxisAlignCorr {
7346
7529
  );
7347
7530
  let groups = group(parallelLines, verticalLines, xAxisLine, yAxisLine2, option);
7348
7531
  groups = removeGroupLinkLine(groups, intersectionMap);
7349
- let newLines = lineSegmentFitting2(groups, 0.1, option);
7350
- newLines = adsorption(newLines, intersectionMap, option);
7351
- newLines = LineSegment.brokenLineMerging(newLines, mergeLineUserData);
7532
+ let newLines = lineSegmentFitting(groups, 0.1, option);
7533
+ newLines = adsorption(newLines, option);
7352
7534
  newLines = lineSegmentClipping(newLines, 1e-9);
7535
+ newLines = LineSegmentUndirectedGraph.breakpointMerging(newLines, mergeLineUserData);
7353
7536
  doorRecover(doorLines);
7354
7537
  newLines = removeShortLine(newLines, doorLines, 0.15);
7355
7538
  newLines = buildBayWindowGroup(newLines);
7539
+ doorAdsorption(newLines, doorLines);
7356
7540
  const { wallGroup = true } = option ?? {};
7357
7541
  if (wallGroup) {
7358
7542
  newLines = buildDoubleWallGroup(newLines);
@@ -7360,7 +7544,6 @@ class AxisAlignCorr {
7360
7544
  newLines = buildDoubleWallGroup(newLines, doorLines, true, true);
7361
7545
  newLines = buildBayWindowGroup(newLines, false);
7362
7546
  }
7363
- doorAdsorption(newLines, doorLines);
7364
7547
  recomputedWindow(...newLines);
7365
7548
  mergeWindow(...newLines);
7366
7549
  newLines.push(...doorLines);
@@ -7369,7 +7552,7 @@ class AxisAlignCorr {
7369
7552
  return newLines;
7370
7553
  }
7371
7554
  }
7372
- let BoundExt$1 = class BoundExt {
7555
+ class BoundExt {
7373
7556
  /** 通过轨迹点查找外墙
7374
7557
  * @param lines
7375
7558
  * @param trajectoryPoints
@@ -7470,7 +7653,9 @@ let BoundExt$1 = class BoundExt {
7470
7653
  appendLines = LineSegment.autoMergeLines(appendLines).lines;
7471
7654
  lines.push(...appendLines.filter((line) => line.length() > 1e-9));
7472
7655
  lines = lineSegmentClipping(lines, 1e-9);
7473
- lines = LineSegment.brokenLineMerging(lines, mergeLineUserData);
7656
+ const doors = lines.filter((line) => line.userData.isDoor);
7657
+ const walls = lines.filter((line) => !line.userData.isDoor);
7658
+ lines = [...LineSegment.brokenLineMerging(walls, mergeLineUserData), ...doors];
7474
7659
  recomputedWindow(...lines);
7475
7660
  lines = lines.filter((line) => line.length() > 0.01);
7476
7661
  findCallBack && findCallBack([...exteriorLines, ...appendLines], trajectoryPoints);
@@ -7481,7 +7666,7 @@ let BoundExt$1 = class BoundExt {
7481
7666
  }
7482
7667
  };
7483
7668
  }
7484
- };
7669
+ }
7485
7670
  function getGroups(lines, updateGroup = true) {
7486
7671
  if (updateGroup) lines = DoubleWallHelper.buildGroup(lines);
7487
7672
  const map = lines.reduce((map2, line) => {
@@ -16417,7 +16602,6 @@ class DoorFind {
16417
16602
  const openDoors = doors.filter((line) => !line.userData.doorDirectConnection), closeDoors = doors.filter((line) => line.userData.doorDirectConnection);
16418
16603
  this.grid = createPointVirtualGrid(noDoorLines);
16419
16604
  this.quadtree = createQuadtree([...noDoorLines, ...closeDoors]);
16420
- openDoors.forEach((l) => l.userData.doorDirectConnection = true);
16421
16605
  closeDoors.forEach((line) => this.findCloseDoors(line));
16422
16606
  openDoors.forEach((line) => this.findOpenDoors(line));
16423
16607
  }
@@ -16625,160 +16809,6 @@ class DoorFind {
16625
16809
  return this.lines;
16626
16810
  }
16627
16811
  }
16628
- function getIntersection(line, mode, cell) {
16629
- return cell.reduce((list, item, i) => {
16630
- const currentLine = item.userData;
16631
- if (currentLine.parallel(line)) list[0] = i;
16632
- else {
16633
- const center = currentLine.center, position = line.pointPosition(center);
16634
- if (mode !== position) list[1] = i;
16635
- else list[2] = i;
16636
- }
16637
- return list;
16638
- }, [-1, -1, -1]);
16639
- }
16640
- function createNewLine(cell, reference, opt, appendLines, grid) {
16641
- const { point: point2 } = cell[opt[0]];
16642
- const newLine = new LineSegment(point2.clone(), reference.clone());
16643
- newLine.points.forEach((p2) => grid.insert(p2, newLine));
16644
- appendLines.push(newLine);
16645
- return newLine;
16646
- }
16647
- function setSameDirection(cell, reference, opt, grid) {
16648
- const { point: point2 } = cell[opt[1]];
16649
- point2.copy(reference);
16650
- grid.update(point2);
16651
- }
16652
- function setDifferentDirection(cell, reference, opt, grid) {
16653
- const { point: point2 } = cell[opt[2]];
16654
- point2.copy(reference);
16655
- grid.update(point2);
16656
- }
16657
- function modify(reference, cell, opt, appendLines, grid) {
16658
- const hasParallel = opt[0] > -1, hasSameDirection = opt[1] > -1, hasDifferentDirection = opt[2] > -1;
16659
- if (hasSameDirection) setSameDirection(cell, reference, opt, grid);
16660
- if (hasParallel) {
16661
- const newLine = createNewLine(cell, reference, opt, appendLines, grid);
16662
- if (hasSameDirection) newLine.userData = cloneUserData(cell[opt[1]].userData?.userData ?? {});
16663
- newLine.userData.rooftopPz = cell[opt[1]]?.userData?.userData.rooftopPz ?? newLine.userData.rooftopPz;
16664
- return;
16665
- }
16666
- if (hasDifferentDirection) {
16667
- if (hasSameDirection) {
16668
- const line = cell[opt[1]].userData;
16669
- reference = line.start.distance(cell[opt[2]].point) < line.end.distance(cell[opt[2]].point) ? line.start : line.end;
16670
- }
16671
- setDifferentDirection(cell, reference, opt, grid);
16672
- }
16673
- }
16674
- function correction(line, wallWidth = 0.12, appendLines, grid, quadtree) {
16675
- const startCell = grid.queryPoint(line.start, true), endCell = grid.queryPoint(line.end, true), mode = line.userData.expandDirect, startIntersection = getIntersection(line, mode, startCell), endIntersection = getIntersection(line, mode, endCell), direction = mode === "left" ? line.getRightDirection() : line.getLeftDirection(), doorIntersection = line.userData.isDoor ? [] : quadtree.queryLineSegment(line, false);
16676
- line.directionMove(direction, wallWidth * 0.5);
16677
- line.points.forEach((p2) => grid.update(p2));
16678
- modify(line.start, startCell, startIntersection, appendLines, grid);
16679
- modify(line.end, endCell, endIntersection, appendLines, grid);
16680
- if (line.userData.isDoor) return quadtree.update(line);
16681
- if (!doorIntersection.length) return;
16682
- doorIntersection.forEach(({ line: doorLine }) => {
16683
- if (line.parallel(doorLine, 25)) return;
16684
- const interPoint = line.getIntersection(doorLine);
16685
- if (!interPoint) return;
16686
- if (doorLine.start.distance(interPoint) < doorLine.end.distance(interPoint)) {
16687
- doorLine.start.copy(interPoint);
16688
- grid.update(doorLine.start);
16689
- } else {
16690
- doorLine.end.copy(interPoint);
16691
- grid.update(doorLine.end);
16692
- }
16693
- quadtree.update(doorLine);
16694
- });
16695
- }
16696
- class BoundExt2 {
16697
- /** 通过轨迹点查找外墙
16698
- * @param lines
16699
- * @param trajectoryPoints
16700
- * @returns
16701
- */
16702
- static findExtWallByTraj(lines, trajectoryPoints, minWidth = 0.4) {
16703
- lines = lines.filter((line) => !line.userData.isBayWindow);
16704
- const quadtree = new Quadtree(Box2.fromByLineSegment(...lines));
16705
- lines.forEach((line) => quadtree.insert({ line, userData: void 0 }));
16706
- const vrLine = findVerticalReference(lines);
16707
- lines = lines.filter((line) => {
16708
- if (LineGroupType.hasType(line, "doubleWall")) return;
16709
- if (line.userData.isDoor) {
16710
- if (!(vrLine.vertical(line, 0.1) || vrLine.parallel(line, 0.1))) return;
16711
- }
16712
- const center = line.center;
16713
- const set2 = /* @__PURE__ */ new Set();
16714
- for (const point2 of trajectoryPoints) {
16715
- if (set2.size === 2) break;
16716
- const lineA = new LineSegment(center, point2);
16717
- const list = quadtree.queryLineSegment(lineA).filter((target) => {
16718
- if (target.line === line) return false;
16719
- if (LineGroupType.hasGroup(line)) return true;
16720
- if (target.line.parallel(line)) {
16721
- if (line.getMinLength(target.line) < minWidth) {
16722
- const projectLine = target.line.projectLineSegment(line);
16723
- if (projectLine.length() / line.length() > 0.6) return false;
16724
- }
16725
- }
16726
- return true;
16727
- });
16728
- if (!list.length) {
16729
- const position = line.pointPosition(point2);
16730
- position !== "on" && set2.add(position);
16731
- }
16732
- }
16733
- line.userData.expandDirect = [...set2][0];
16734
- if (set2.size < 2) return true;
16735
- });
16736
- return lines;
16737
- }
16738
- /** 通过轨迹点外扩边线
16739
- * @param lines
16740
- * @param trajectoryPoints
16741
- */
16742
- static boundExtbyTrajAndOriginalData(opt) {
16743
- const zList = [];
16744
- let lines = opt.data.map(({ start, end, ...opt2 }) => {
16745
- const line = new LineSegment(Point.from(start), Point.from(end));
16746
- line.userData = opt2;
16747
- zList.push(start.z ?? 0, end.z ?? 0);
16748
- return line;
16749
- });
16750
- const originalZAverage = zList.reduce((count, num) => count + num, 0) / zList.length;
16751
- return this.boundExtbyTraj({ ...opt, lines }).toOriginalData(originalZAverage);
16752
- }
16753
- /** 通过轨迹点外扩边线
16754
- * @param lines
16755
- * @param trajectory
16756
- * @param wallWidth
16757
- * @param findCallBack
16758
- * @returns
16759
- */
16760
- static boundExtbyTraj(opt) {
16761
- let { lines, trajectory, wallWidth = 0.12, updateDoubleWallGroup = true, findCallBack } = opt;
16762
- if (updateDoubleWallGroup) lines = DoubleWallHelper.buildGroup(lines);
16763
- const trajectoryPoints = Object.keys(trajectory).map((key) => Point.from(trajectory[key]));
16764
- const findLines = BoundExt2.findExtWallByTraj(lines, trajectoryPoints);
16765
- let exteriorLines = findLines.filter((line) => line.userData.expandDirect);
16766
- lines = lines.filter((line) => !exteriorLines.includes(line));
16767
- lines.push(...exteriorLines);
16768
- const grid = createPointVirtualGrid(lines), quadtree = createQuadtree(lines.filter((line) => line.userData.isDoor)), appendLines = [];
16769
- exteriorLines.forEach((line) => correction(line, wallWidth, appendLines, grid, quadtree));
16770
- lines.push(...appendLines.filter((line) => line.length() > 1e-9));
16771
- recomputedWindow(...lines);
16772
- lines = lines.filter((line) => line.length() > 0.01);
16773
- findCallBack && findCallBack(exteriorLines, trajectoryPoints);
16774
- return {
16775
- lines,
16776
- toOriginalData(originalZAverage) {
16777
- return lineDataToOriginalData(lines, originalZAverage);
16778
- }
16779
- };
16780
- }
16781
- }
16782
16812
  const PRE_PROCESSOR = {
16783
16813
  /** 根据交点,对线段进行裁剪
16784
16814
  * @param lines
@@ -16796,7 +16826,7 @@ const PRE_PROCESSOR = {
16796
16826
  polygons.forEach((polygon2) => {
16797
16827
  polygon2.pop();
16798
16828
  polygon2.splitConvexHull()?.forEach((poly) => {
16799
- drawLines(poly, { color: randomColor() });
16829
+ drawLines(poly, { color: randomColor() }, 5e-3);
16800
16830
  drawLines(poly.getMinimumBoundingRectangle());
16801
16831
  });
16802
16832
  });
@@ -16847,7 +16877,7 @@ const PRE_PROCESSOR = {
16847
16877
  return lines;
16848
16878
  }
16849
16879
  let t2 = performance.now();
16850
- lines = BoundExt2.boundExtbyTraj({ lines, trajectory, wallWidth: DEFAULT_WALL_WIDTH, findCallBack: onBoundExt }).lines;
16880
+ lines = BoundExt.boundExtbyTraj({ lines, trajectory, wallWidth: DEFAULT_WALL_WIDTH, findCallBack: onBoundExt }).lines;
16851
16881
  console.log(`外墙外扩总消耗时间: ${(performance.now() - t2).toFixed(2)} ms 处理线段数量:`, lines.length);
16852
16882
  return lines;
16853
16883
  },
@@ -19498,13 +19528,13 @@ const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert
19498
19528
  __proto__: null,
19499
19529
  ArrayMap,
19500
19530
  AxisAlignCorr,
19501
- BoundExt: BoundExt$1,
19531
+ BoundExt,
19502
19532
  Box2,
19503
19533
  CommandFlow,
19504
19534
  CommandManager,
19505
19535
  Component,
19506
19536
  ComponentManager,
19507
- CountMap,
19537
+ CounterMap,
19508
19538
  DoubleWallHelper,
19509
19539
  DxfSystem,
19510
19540
  EventDispatcher,
@@ -19621,7 +19651,7 @@ async function getModels(originData, trajectory, itemList) {
19621
19651
  itemList = [];
19622
19652
  }
19623
19653
  const { lineSegments, originalZAverage } = originalDataToLineData(originData);
19624
- const lines = BoundExt$1.boundExtbyTraj({
19654
+ const lines = BoundExt.boundExtbyTraj({
19625
19655
  lines: lineSegments,
19626
19656
  trajectory,
19627
19657
  updateDoubleWallGroup: true,
package/src/index3.js CHANGED
@@ -11335,7 +11335,9 @@ class Default extends CommandFlowComponent {
11335
11335
  const direction = line2.direction();
11336
11336
  currentSelectWinIndex = line2.userData.drawWindow?.findIndex((d) => {
11337
11337
  Point.from(d.p).expandAsLine(direction, d.width, {}, wiLine).directionMove(direction, -d.width * 0.5);
11338
- return wiLine.isPointOnSegment(Point.from(point));
11338
+ const p = Point.from(point);
11339
+ const p2 = wiLine.projectPoint(p, true);
11340
+ return (p2?.distance(p) ?? Infinity) < 0.08;
11339
11341
  });
11340
11342
  }
11341
11343
  dom.style.cursor = "pointer";
@@ -21,10 +21,13 @@ export type WallLineGlobalOption = {
21
21
  isWindow?: boolean;
22
22
  /** 是不是飘窗虚线 */
23
23
  isBayWindow?: boolean;
24
+ /** 是不是飘窗墙壁 */
25
+ isWindowWall?: boolean;
24
26
  /** 是不是门线 */
25
27
  isDoor?: boolean;
26
28
  doorAutomaticFind?: boolean;
27
29
  doorDirectConnection?: boolean;
30
+ topClearance?: number;
28
31
  isVerticalReferenceLine?: boolean;
29
32
  insetionArr?: {
30
33
  index: number;
@@ -0,0 +1,14 @@
1
+ import { LineSegment } from '../../LineSegment';
2
+ import { SetDataOption, LineUserData } from '../type';
3
+ /**
4
+ * 轴对齐垂直纠正类
5
+ */
6
+ export declare class AxisAlignCorr {
7
+ /**
8
+ * 轴对齐垂直修正
9
+ * @param lines 待调整线段组
10
+ * @param targettLine 轴线段
11
+ * @returns
12
+ */
13
+ static correction(lines: LineSegment<LineUserData>[], targettLine: LineSegment<LineUserData>, option?: SetDataOption): LineSegment<any>[];
14
+ }
@@ -0,0 +1,23 @@
1
+ import { LineSegment } from '../../LineSegment';
2
+ import { LineUserData } from '../type';
3
+ import { Point } from '../../Point';
4
+ interface IDrawBayWindowData {
5
+ height1: number;
6
+ height2: number;
7
+ height3: number;
8
+ depth: number;
9
+ windowWidth: number;
10
+ windowHeight: number;
11
+ bayWindowLine: LineSegment;
12
+ windowLine: LineSegment;
13
+ deptLine: LineSegment;
14
+ direction: Point;
15
+ }
16
+ export declare class BayWindowHelper {
17
+ static getDrawData(lines: LineSegment<LineUserData>[]): IDrawBayWindowData | null;
18
+ static getDrawDataAll(lineSegments: LineSegment[]): {
19
+ group: LineSegment<Record<string, any>>[];
20
+ drawData: IDrawBayWindowData;
21
+ }[];
22
+ }
23
+ export {};
@@ -18,12 +18,17 @@ export declare class DoubleWallHelper {
18
18
  * @returns
19
19
  */
20
20
  private static projectionAnalysis;
21
+ /** 查找
22
+ * @param lines
23
+ * @param wallWidth
24
+ * @returns
25
+ */
21
26
  static findDoubleLine(lines: LineSegment<LineUserData>[], wallWidth?: number): {
22
27
  resultList: ProjectionAnalysisResult[];
23
28
  walls: LineSegment<LineUserData>[];
24
29
  quadtree: Quadtree<number>;
25
30
  };
26
- /**
31
+ /** 补双线墙壁
27
32
  * @param lines
28
33
  * @param wallWidth
29
34
  * @returns
@@ -0,0 +1,42 @@
1
+ import { LineSegment } from './LineSegment';
2
+ import { Point } from './Point';
3
+ import { PointVirtualGrid } from './PointVirtualGrid';
4
+ import { Quadtree, QuadtreeNode } from './Quadtree';
5
+ export declare class LineQueryer {
6
+ pointVirtualGrid: PointVirtualGrid<LineSegment>;
7
+ quadtree: Quadtree<any>;
8
+ constructor(lines: LineSegment[]);
9
+ update(lines: LineSegment[]): void;
10
+ clear(): void;
11
+ /**
12
+ * @param point
13
+ * @param radius
14
+ * @param opt
15
+ * @returns
16
+ */
17
+ queryNearestPoint(point: Point, opt?: {
18
+ resultIndex?: number;
19
+ radius?: number;
20
+ condition?: (node: {
21
+ point: Point<Record<string, any>>;
22
+ userData?: LineSegment<Record<string, any>> | undefined;
23
+ }) => boolean;
24
+ }): {
25
+ point: Point<Record<string, any>>;
26
+ line: LineSegment;
27
+ } | null;
28
+ /**
29
+ * @param point
30
+ * @param radius
31
+ * @param opt
32
+ * @returns
33
+ */
34
+ queryNearestLine(point: Point, opt?: {
35
+ resultIndex?: number;
36
+ radius?: number;
37
+ condition?: (node: QuadtreeNode<any>, point: Point) => boolean;
38
+ }): {
39
+ point: Point<Record<string, any>>;
40
+ line: LineSegment<Record<string, any>>;
41
+ } | null;
42
+ }
@@ -4,6 +4,7 @@ import { Rectangle } from './Rectangle';
4
4
  * 非轴对称线段
5
5
  */
6
6
  export declare class LineSegment<T = Record<string, any>> {
7
+ static get LINE_SYMBOL(): symbol;
7
8
  points: Point[];
8
9
  userData: T;
9
10
  currentData: Record<string | number | symbol, any>;
@@ -222,6 +223,11 @@ export declare class LineSegment<T = Record<string, any>> {
222
223
  * @param line
223
224
  */
224
225
  copy(line: LineSegment): void;
226
+ /** 获取点属于的线段
227
+ * @param point
228
+ * @returns
229
+ */
230
+ static getPointBelongLine(point: Point): LineSegment | null;
225
231
  /**
226
232
  * 获取最长线段
227
233
  * @param lines
@@ -315,5 +321,6 @@ export declare class LineSegment<T = Record<string, any>> {
315
321
  static createModifyManager(): {
316
322
  readonly setPoint: (line: LineSegment, point: Point, value: Point) => void;
317
323
  readonly modify: () => void;
324
+ clear(): void;
318
325
  };
319
326
  }
@@ -2,6 +2,7 @@ export declare class MapEnhance<K, V> extends Map<K, V> {
2
2
  get valueArray(): V[];
3
3
  map<T = any>(callbackfn: (v: V, k: K) => T): T[];
4
4
  filter(callbackfn: (v: V, k: K) => boolean): V[];
5
+ filterKey(callbackfn: (v: V, k: K) => boolean): K[];
5
6
  reduce<T>(callbackfn: (pre: T, v: V, k: K) => T, result: T): T;
6
7
  some(callbackfn: (v: V, k: K) => boolean): boolean;
7
8
  every(callbackfn: (v: V, k: K) => boolean): boolean;
@@ -28,6 +29,8 @@ export declare class SetMap<K, V> extends MapEnhance<K, Set<V>> {
28
29
  append(k: K, ...arr: V[]): this;
29
30
  hasValue(key: K, value: V): boolean;
30
31
  }
31
- export declare class CountMap<K> extends MapEnhance<K, number> {
32
- set(key: K): this;
32
+ export declare class CounterMap<K> extends MapEnhance<K, number> {
33
+ set(key: K, step?: number): this;
34
+ increment(key: K, step?: number): this;
35
+ getByCount(count: number): K[];
33
36
  }
@@ -92,7 +92,7 @@ export declare class Point<T = Record<string, any>> {
92
92
  * @param point
93
93
  * @returns
94
94
  */
95
- direction(point: Point): Point<Record<string, any>>;
95
+ direction(point: Point, out?: Point<Record<string, any>>): Point<Record<string, any>>;
96
96
  /** 展开为线
97
97
  * @param direction
98
98
  * @param length
@@ -161,7 +161,16 @@ export declare class Point<T = Record<string, any>> {
161
161
  z: number;
162
162
  };
163
163
  toVector3(z?: number): Vector3;
164
- static adsorb(points: Point[], tolerance?: number): Point<Record<string, any>>[];
164
+ /** 点吸附
165
+ * @param points
166
+ * @param tolerance
167
+ * @returns
168
+ */
169
+ static adsorb(points: Point[], tolerance?: number, mode?: "average" | "first"): Point<Record<string, any>>[];
170
+ /** 创建
171
+ * @param arr
172
+ * @returns
173
+ */
165
174
  static from(arr: any): Point<Record<string, any>>;
166
175
  static fromByList(arr: any[]): Point<Record<string, any>>[];
167
176
  static zero(): Point<Record<string, any>>;
@@ -19,6 +19,9 @@ export declare class UndirectedGraph {
19
19
  */
20
20
  forEach(callbackFun: (node: number, neighbors: Set<number>) => void): void;
21
21
  }
22
+ /**
23
+ * 线段无向图
24
+ */
22
25
  export declare class LineSegmentUndirectedGraph extends UndirectedGraph {
23
26
  private readonly lineMap;
24
27
  private readonly pointToIndex;
@@ -30,6 +33,10 @@ export declare class LineSegmentUndirectedGraph extends UndirectedGraph {
30
33
  * 获取两点之间的线段(无向)
31
34
  */
32
35
  getLine(a: number, b: number): LineSegment | undefined;
36
+ /** 获取所有线段
37
+ * @returns
38
+ */
39
+ getLineAll(): LineSegment<Record<string, any>>[];
33
40
  /**
34
41
  * 获取或创建点的索引
35
42
  */
@@ -55,6 +62,10 @@ export declare class LineSegmentUndirectedGraph extends UndirectedGraph {
55
62
  * 批量添加线段(比逐条 addLine 更快)
56
63
  */
57
64
  addLines(lines: readonly LineSegment[]): this;
65
+ /** 批量移除线段边
66
+ * @param lines
67
+ */
68
+ removeLines(lines: readonly LineSegment[]): void;
58
69
  /** 路径转线段组
59
70
  * @param path
60
71
  */
@@ -63,6 +74,21 @@ export declare class LineSegmentUndirectedGraph extends UndirectedGraph {
63
74
  * 清空图
64
75
  */
65
76
  clear(): void;
77
+ /** 断点合并
78
+ * @description 合并断开的直线,断点
79
+ * @param lines
80
+ * @param callBack
81
+ * @returns
82
+ */
83
+ breakpointMerging(callBack?: (newLine: LineSegment, group: LineSegment[]) => void, removeLines?: Set<LineSegment<Record<string, any>>>, newLines?: LineSegment[]): void;
84
+ /** 断点合并
85
+ * @param lines
86
+ * @param callBack
87
+ * @param removeLines
88
+ * @param newLines
89
+ * @returns
90
+ */
91
+ static breakpointMerging(lines: LineSegment[], callBack?: (newLine: LineSegment, group: LineSegment[]) => void, removeLines?: Set<LineSegment<Record<string, any>>>, newLines?: LineSegment[]): LineSegment<Record<string, any>>[];
66
92
  /** 线段图旋转
67
93
  * @param lines
68
94
  * @param angle 弧度