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 +1 -1
- package/src/DomEventRegister.js +1 -1
- package/src/build.js +309 -279
- package/src/index3.js +3 -1
- package/src/utils/DxfSystem/type.d.ts +3 -0
- package/src/utils/DxfSystem/utils/AxisAlignCorr copy.d.ts +14 -0
- package/src/utils/DxfSystem/utils/BayWindowHelper.d.ts +23 -0
- package/src/utils/DxfSystem/utils/DoubleWallHelper.d.ts +6 -1
- package/src/utils/LineQueryer.d.ts +42 -0
- package/src/utils/LineSegment.d.ts +7 -0
- package/src/utils/Map.d.ts +5 -2
- package/src/utils/Point.d.ts +11 -2
- package/src/utils/UndirectedGraph.d.ts +26 -0
package/package.json
CHANGED
package/src/DomEventRegister.js
CHANGED
|
@@ -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,
|
|
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
|
|
1064
|
-
set(key) {
|
|
1065
|
-
|
|
1066
|
-
|
|
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
|
|
1170
|
-
this.
|
|
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(
|
|
2139
|
-
const key2 = `${p2.x.toFixed(
|
|
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
|
|
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
|
|
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
|
|
2408
|
-
return
|
|
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 =
|
|
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
|
-
|
|
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
|
|
2543
|
-
|
|
2544
|
-
countX
|
|
2545
|
-
countY += point22.y;
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
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
|
|
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.
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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,
|
|
7152
|
-
const { snapThreshold: threshold = 0.2 } = option ?? {};
|
|
7153
|
-
|
|
7154
|
-
|
|
7155
|
-
|
|
7156
|
-
|
|
7157
|
-
|
|
7158
|
-
|
|
7159
|
-
|
|
7160
|
-
|
|
7161
|
-
|
|
7162
|
-
|
|
7163
|
-
|
|
7164
|
-
|
|
7165
|
-
|
|
7166
|
-
|
|
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 (
|
|
7181
|
-
}
|
|
7182
|
-
function
|
|
7183
|
-
|
|
7184
|
-
|
|
7185
|
-
|
|
7186
|
-
|
|
7187
|
-
|
|
7188
|
-
|
|
7189
|
-
|
|
7190
|
-
|
|
7191
|
-
|
|
7192
|
-
|
|
7193
|
-
|
|
7194
|
-
|
|
7195
|
-
|
|
7196
|
-
|
|
7197
|
-
|
|
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
|
-
|
|
7206
|
-
|
|
7207
|
-
if (
|
|
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
|
-
|
|
7226
|
-
|
|
7227
|
-
|
|
7228
|
-
|
|
7229
|
-
|
|
7230
|
-
|
|
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
|
|
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 =
|
|
7350
|
-
newLines = adsorption(newLines,
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
|
19531
|
+
BoundExt,
|
|
19502
19532
|
Box2,
|
|
19503
19533
|
CommandFlow,
|
|
19504
19534
|
CommandManager,
|
|
19505
19535
|
Component,
|
|
19506
19536
|
ComponentManager,
|
|
19507
|
-
|
|
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
|
|
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
|
-
|
|
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
|
}
|
package/src/utils/Map.d.ts
CHANGED
|
@@ -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
|
|
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
|
}
|
package/src/utils/Point.d.ts
CHANGED
|
@@ -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
|
-
|
|
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 弧度
|