build-dxf 0.1.85 → 0.1.87
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
package/src/build.js
CHANGED
|
@@ -1573,7 +1573,7 @@ class LineSegment {
|
|
|
1573
1573
|
* @param errAngle
|
|
1574
1574
|
* @returns
|
|
1575
1575
|
*/
|
|
1576
|
-
isPerpendicularTo(line, eps =
|
|
1576
|
+
isPerpendicularTo(line, eps = 1) {
|
|
1577
1577
|
const d1 = this.direction();
|
|
1578
1578
|
const d2 = line.direction();
|
|
1579
1579
|
const angle = d1.angle(d2, { unit: "degree", range: "180" });
|
|
@@ -2594,7 +2594,7 @@ class Point {
|
|
|
2594
2594
|
}
|
|
2595
2595
|
return num;
|
|
2596
2596
|
}
|
|
2597
|
-
hashCode(fixed =
|
|
2597
|
+
hashCode(fixed = 4) {
|
|
2598
2598
|
return `${this.x.toFixed(fixed)},${this.y.toFixed(6)}`;
|
|
2599
2599
|
}
|
|
2600
2600
|
/**
|
|
@@ -3321,7 +3321,7 @@ function findDiscretePointLine2(lines, lineSet, deep = false) {
|
|
|
3321
3321
|
lines.forEach((line) => {
|
|
3322
3322
|
if (lineSet.size && lineSet.has(line)) return;
|
|
3323
3323
|
line.points.forEach((p2) => {
|
|
3324
|
-
const id = p2.hashCode();
|
|
3324
|
+
const id = p2.hashCode(4);
|
|
3325
3325
|
if (!map.has(id)) map.set(id, /* @__PURE__ */ new Set());
|
|
3326
3326
|
map.get(id)?.add(line);
|
|
3327
3327
|
});
|
|
@@ -7477,6 +7477,7 @@ class ThreeVJiaJson extends Pipeline {
|
|
|
7477
7477
|
}
|
|
7478
7478
|
}
|
|
7479
7479
|
function lineDataToThreeVJiaJson(lineSegments, angle = 0, updateGroup = true) {
|
|
7480
|
+
angle = 0;
|
|
7480
7481
|
lineSegments = LineSegmentUndirectedGraph.rotate(lineSegments.map((line) => line.clone()), angle, (line, center, angle2) => {
|
|
7481
7482
|
WallInsertObject.forEachInsertObjectData(line, (data) => {
|
|
7482
7483
|
data.forEach((item) => {
|
|
@@ -7910,11 +7911,11 @@ class CAD {
|
|
|
7910
7911
|
function drawRulerLine(p1, p2) {
|
|
7911
7912
|
line.set(p1, p2);
|
|
7912
7913
|
const length = line.length();
|
|
7913
|
-
const angle = line.direction().
|
|
7914
|
+
const angle = line.direction().angle(new Point(0, 1), { unit: "degree", range: "180" });
|
|
7914
7915
|
const p1C = p1.clone();
|
|
7915
7916
|
const p2C = p2.clone();
|
|
7916
7917
|
const offset = expansionWidth * 0.4;
|
|
7917
|
-
if (
|
|
7918
|
+
if (Math.min(angle, 180 - angle) < 1) {
|
|
7918
7919
|
if (p1.x < center.x) {
|
|
7919
7920
|
p1C.x = box.minX + offset;
|
|
7920
7921
|
p2C.x = box.minX + offset;
|
|
@@ -8308,530 +8309,178 @@ class DxfDataPlugin extends Pipeline {
|
|
|
8308
8309
|
DxfDataPlugin.initData(cad, this.lines);
|
|
8309
8310
|
}
|
|
8310
8311
|
}
|
|
8311
|
-
class
|
|
8312
|
-
|
|
8313
|
-
|
|
8314
|
-
|
|
8315
|
-
this.pointVirtualGrid = createPointVirtualGrid(lines);
|
|
8316
|
-
this.quadtree = createQuadtree(lines);
|
|
8317
|
-
}
|
|
8318
|
-
update(lines) {
|
|
8319
|
-
this.clear();
|
|
8320
|
-
this.pointVirtualGrid = createPointVirtualGrid(lines);
|
|
8321
|
-
this.quadtree = createQuadtree(lines);
|
|
8322
|
-
}
|
|
8323
|
-
clear() {
|
|
8324
|
-
this.pointVirtualGrid.clear();
|
|
8325
|
-
this.quadtree.clear();
|
|
8326
|
-
}
|
|
8327
|
-
/**
|
|
8328
|
-
* @param point
|
|
8329
|
-
* @param radius
|
|
8330
|
-
* @param opt
|
|
8312
|
+
class BoundExt {
|
|
8313
|
+
/** 通过轨迹点查找外墙
|
|
8314
|
+
* @param lines
|
|
8315
|
+
* @param trajectoryPoints
|
|
8331
8316
|
* @returns
|
|
8332
8317
|
*/
|
|
8333
|
-
|
|
8334
|
-
|
|
8335
|
-
const
|
|
8336
|
-
|
|
8337
|
-
|
|
8338
|
-
|
|
8339
|
-
|
|
8340
|
-
|
|
8341
|
-
|
|
8342
|
-
|
|
8318
|
+
static findExtWallByTraj(lines, trajectoryPoints, minWidth = 0.4) {
|
|
8319
|
+
lines = lines.filter((line) => !line.userData.isBayWindow);
|
|
8320
|
+
const quadtree = new Quadtree(Box2.fromByLineSegment(...lines));
|
|
8321
|
+
lines.forEach((line) => quadtree.insert({ line, userData: void 0 }));
|
|
8322
|
+
lines = lines.filter((line) => {
|
|
8323
|
+
if (LineGroupType.hasType(line, "doubleWall")) return;
|
|
8324
|
+
const center = line.center;
|
|
8325
|
+
const set2 = /* @__PURE__ */ new Set();
|
|
8326
|
+
for (const point2 of trajectoryPoints) {
|
|
8327
|
+
if (set2.size === 2) break;
|
|
8328
|
+
const lineA = new LineSegment(center, point2);
|
|
8329
|
+
const list = quadtree.queryLineSegment(lineA).filter((target) => {
|
|
8330
|
+
if (target.line === line) return false;
|
|
8331
|
+
if (LineGroupType.hasGroup(line)) return true;
|
|
8332
|
+
if (target.line.isParallelTo(line)) {
|
|
8333
|
+
if (line.distanceToSegment(target.line) < minWidth) {
|
|
8334
|
+
const projectLine = target.line.projectLineSegment(line);
|
|
8335
|
+
if (projectLine.length() / line.length() > 0.6) return false;
|
|
8336
|
+
}
|
|
8337
|
+
}
|
|
8338
|
+
return true;
|
|
8339
|
+
});
|
|
8340
|
+
if (!list.length) {
|
|
8341
|
+
const position = line.getPointSideOfLine(point2);
|
|
8342
|
+
position !== "on" && set2.add(position);
|
|
8343
|
+
}
|
|
8344
|
+
}
|
|
8345
|
+
line.userData.expandDirect = [...set2][0];
|
|
8346
|
+
if (set2.size < 2) return true;
|
|
8347
|
+
});
|
|
8348
|
+
return lines;
|
|
8343
8349
|
}
|
|
8344
|
-
/**
|
|
8345
|
-
* @param
|
|
8346
|
-
* @param
|
|
8347
|
-
|
|
8350
|
+
/** 通过轨迹点外扩边线
|
|
8351
|
+
* @param lines
|
|
8352
|
+
* @param trajectoryPoints
|
|
8353
|
+
*/
|
|
8354
|
+
static boundExtbyTrajAndOriginalData(opt) {
|
|
8355
|
+
const zList = [];
|
|
8356
|
+
let lines = opt.data.map(({ start, end, ...opt2 }) => {
|
|
8357
|
+
const line = new LineSegment(Point.from(start), Point.from(end));
|
|
8358
|
+
line.userData = opt2;
|
|
8359
|
+
zList.push(start.z ?? 0, end.z ?? 0);
|
|
8360
|
+
return line;
|
|
8361
|
+
});
|
|
8362
|
+
const originalZAverage = zList.reduce((count, num) => count + num, 0) / zList.length;
|
|
8363
|
+
return this.boundExtbyTraj({ ...opt, lines }).toOriginalData(originalZAverage);
|
|
8364
|
+
}
|
|
8365
|
+
/** 通过轨迹点外扩边线
|
|
8366
|
+
* @param lines
|
|
8367
|
+
* @param trajectory
|
|
8368
|
+
* @param wallWidth
|
|
8369
|
+
* @param findCallBack
|
|
8348
8370
|
* @returns
|
|
8349
8371
|
*/
|
|
8350
|
-
|
|
8351
|
-
|
|
8352
|
-
|
|
8353
|
-
const
|
|
8354
|
-
|
|
8355
|
-
|
|
8356
|
-
|
|
8357
|
-
|
|
8358
|
-
|
|
8359
|
-
|
|
8360
|
-
|
|
8372
|
+
static boundExtbyTraj(opt) {
|
|
8373
|
+
let { lines, trajectory: trajectory2, wallWidth = 0.12, updateDoubleWallGroup = false, findCallBack } = opt;
|
|
8374
|
+
if (updateDoubleWallGroup) lines = DoubleWallHelper.buildGroup(lines);
|
|
8375
|
+
const trajectoryPoints = Object.keys(trajectory2).map((key) => Point.from(trajectory2[key]));
|
|
8376
|
+
const findLines = BoundExt.findExtWallByTraj(lines, trajectoryPoints);
|
|
8377
|
+
let exteriorLines = findLines.filter((line) => line.userData.expandDirect).filter((line) => !line.userData.isBalconyRailing).filter((line) => !LineGroupType.hasType(line, "bayWindow"));
|
|
8378
|
+
lines = lines.filter((line) => !exteriorLines.includes(line));
|
|
8379
|
+
lines.push(...exteriorLines);
|
|
8380
|
+
const grid = createPointVirtualGrid(lines), quadtree = createQuadtree(lines), arrayMap = new ArrayMap(), pointMap = /* @__PURE__ */ new Map();
|
|
8381
|
+
let appendLines = [];
|
|
8382
|
+
exteriorLines.forEach((line) => {
|
|
8383
|
+
const mode = line.userData.expandDirect, direction = mode === "left" ? line.getRightDirection() : line.getLeftDirection();
|
|
8384
|
+
line.points.forEach((point2) => {
|
|
8385
|
+
const id = point2.hashCode();
|
|
8386
|
+
arrayMap.append(id, { point: point2, line });
|
|
8387
|
+
if (!pointMap.has(id)) pointMap.set(id, point2.clone());
|
|
8388
|
+
grid.update(point2);
|
|
8389
|
+
});
|
|
8390
|
+
line.translate(wallWidth * 0.5, direction);
|
|
8391
|
+
});
|
|
8392
|
+
arrayMap.forEach((list, id) => {
|
|
8393
|
+
if (list.length >= 2) {
|
|
8394
|
+
const p1 = list[0].line.getIntersection(list[1].line);
|
|
8395
|
+
if (p1) {
|
|
8396
|
+
list[0].point.copy(p1);
|
|
8397
|
+
list[1].point.copy(p1);
|
|
8398
|
+
}
|
|
8399
|
+
} else {
|
|
8400
|
+
const queryList = grid.queryCircle(pointMap.get(id), 1e-4);
|
|
8401
|
+
if (queryList.length) {
|
|
8402
|
+
const newLine = new LineSegment(pointMap.get(id), list[0].point.clone());
|
|
8403
|
+
const list_ = list.filter((i) => !i.line.userData.isDoor && !i.line.userData.isWindow);
|
|
8404
|
+
if (list_.length) newLine.userData = cloneUserData(list_[0].line.userData);
|
|
8405
|
+
if (quadtree.queryCircle(newLine.center, 1e-4).length) return;
|
|
8406
|
+
appendLines.push(newLine);
|
|
8407
|
+
}
|
|
8408
|
+
}
|
|
8409
|
+
});
|
|
8410
|
+
appendLines = LineSegment.mergeParallelSegments(appendLines).lines;
|
|
8411
|
+
lines.push(...appendLines.filter((line) => line.length() > 1e-9));
|
|
8412
|
+
lines = lineSegmentClipping(lines, 1e-9);
|
|
8413
|
+
const doors = lines.filter((line) => line.userData.isDoor);
|
|
8414
|
+
const walls = lines.filter((line) => !line.userData.isDoor);
|
|
8415
|
+
lines = [...LineSegment.mergeCollinearSegments(walls, mergeLineUserData), ...doors];
|
|
8416
|
+
WallInsertObject.recomputed(lines);
|
|
8417
|
+
lines = lines.filter((line) => line.length() > 1e-4).filter((line) => line.userData.isDoor ? line.length() > 0.25 : true);
|
|
8418
|
+
findCallBack && findCallBack([...exteriorLines, ...appendLines], trajectoryPoints);
|
|
8419
|
+
return {
|
|
8420
|
+
lines,
|
|
8421
|
+
toOriginalData(originalZAverage) {
|
|
8422
|
+
return lineDataToOriginalData(lines, originalZAverage);
|
|
8361
8423
|
}
|
|
8362
|
-
return null;
|
|
8363
|
-
}).filter((i) => !!i);
|
|
8364
|
-
results.sort((a2, b4) => a2.distance - b4.distance);
|
|
8365
|
-
if (results.length > resultIndex) return {
|
|
8366
|
-
point: results[resultIndex].projPoint,
|
|
8367
|
-
line: results[resultIndex].line
|
|
8368
8424
|
};
|
|
8369
|
-
return null;
|
|
8370
8425
|
}
|
|
8371
8426
|
}
|
|
8372
|
-
|
|
8373
|
-
|
|
8374
|
-
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
|
|
8378
|
-
|
|
8379
|
-
|
|
8380
|
-
|
|
8381
|
-
|
|
8382
|
-
|
|
8427
|
+
if (typeof globalThis !== "undefined" && typeof ProgressEvent === "undefined") {
|
|
8428
|
+
globalThis.ProgressEvent = class ProgressEvent extends EventTarget {
|
|
8429
|
+
type;
|
|
8430
|
+
lengthComputable;
|
|
8431
|
+
loaded;
|
|
8432
|
+
total;
|
|
8433
|
+
bubbles;
|
|
8434
|
+
cancelable;
|
|
8435
|
+
defaultPrevented;
|
|
8436
|
+
eventPhase;
|
|
8437
|
+
timeStamp;
|
|
8438
|
+
isTrusted;
|
|
8439
|
+
constructor(type, options = {}) {
|
|
8440
|
+
super();
|
|
8441
|
+
this.type = type;
|
|
8442
|
+
this.lengthComputable = options.lengthComputable || false;
|
|
8443
|
+
this.loaded = options.loaded || 0;
|
|
8444
|
+
this.total = options.total || 0;
|
|
8445
|
+
this.bubbles = false;
|
|
8446
|
+
this.cancelable = false;
|
|
8447
|
+
this.defaultPrevented = false;
|
|
8448
|
+
this.eventPhase = 0;
|
|
8449
|
+
this.timeStamp = Date.now();
|
|
8450
|
+
this.isTrusted = true;
|
|
8451
|
+
}
|
|
8452
|
+
preventDefault() {
|
|
8453
|
+
}
|
|
8454
|
+
stopPropagation() {
|
|
8455
|
+
}
|
|
8456
|
+
stopImmediatePropagation() {
|
|
8457
|
+
}
|
|
8458
|
+
};
|
|
8383
8459
|
}
|
|
8384
|
-
|
|
8385
|
-
|
|
8386
|
-
|
|
8387
|
-
|
|
8388
|
-
|
|
8389
|
-
|
|
8390
|
-
|
|
8391
|
-
|
|
8392
|
-
|
|
8393
|
-
|
|
8394
|
-
|
|
8395
|
-
|
|
8396
|
-
|
|
8397
|
-
|
|
8398
|
-
|
|
8460
|
+
let gltfLoader = GLTFExporter;
|
|
8461
|
+
let gltfExporter = GLTFLoader;
|
|
8462
|
+
let promise;
|
|
8463
|
+
function GltfInit() {
|
|
8464
|
+
if (promise) return promise;
|
|
8465
|
+
promise = new Promise(async (resolve) => {
|
|
8466
|
+
try {
|
|
8467
|
+
const { GLTFLoader: GLTFLoader2 } = await (typeof window !== "undefined" ? import("three/addons/loaders/GLTFLoader.js") : include("node-three-gltf", false));
|
|
8468
|
+
gltfLoader = GLTFLoader2;
|
|
8469
|
+
const { GLTFExporter: GLTFExporter2 } = await (typeof window !== "undefined" ? import("three/addons/exporters/GLTFExporter.js") : include("node-three-gltf", false));
|
|
8470
|
+
gltfExporter = GLTFExporter2;
|
|
8471
|
+
} catch (error) {
|
|
8472
|
+
console.error(error);
|
|
8473
|
+
}
|
|
8474
|
+
resolve(true);
|
|
8475
|
+
});
|
|
8476
|
+
return promise;
|
|
8399
8477
|
}
|
|
8400
|
-
|
|
8401
|
-
|
|
8402
|
-
return
|
|
8403
|
-
}
|
|
8404
|
-
|
|
8405
|
-
|
|
8406
|
-
grid;
|
|
8407
|
-
constructor(lines, baseline) {
|
|
8408
|
-
this.lines = lines;
|
|
8409
|
-
this.baseline = baseline;
|
|
8410
|
-
this.grid = createPointVirtualGrid(lines);
|
|
8411
|
-
}
|
|
8412
|
-
visited = /* @__PURE__ */ new Set();
|
|
8413
|
-
newLines = [];
|
|
8414
|
-
start() {
|
|
8415
|
-
for (let i = 0; i < this.lines.length; i++) {
|
|
8416
|
-
const line = this.lines[i];
|
|
8417
|
-
if (this.visited.has(line)) continue;
|
|
8418
|
-
this.correction(line);
|
|
8419
|
-
}
|
|
8420
|
-
return [
|
|
8421
|
-
...this.lines,
|
|
8422
|
-
...this.newLines
|
|
8423
|
-
];
|
|
8424
|
-
}
|
|
8425
|
-
/** 添加
|
|
8426
|
-
* @param lines
|
|
8427
|
-
* @returns
|
|
8428
|
-
*/
|
|
8429
|
-
addVisited(lines) {
|
|
8430
|
-
if (lines instanceof LineSegment) lines = [lines];
|
|
8431
|
-
lines.forEach((line) => this.visited.add(line));
|
|
8432
|
-
return this;
|
|
8433
|
-
}
|
|
8434
|
-
queryPoint(point2) {
|
|
8435
|
-
return this.grid.queryPoint(point2, true).filter((item) => !this.visited.has(item.userData));
|
|
8436
|
-
}
|
|
8437
|
-
/** 纠正
|
|
8438
|
-
* @param line
|
|
8439
|
-
* @param targettLine
|
|
8440
|
-
*/
|
|
8441
|
-
correction(line) {
|
|
8442
|
-
const startConnectList = this.queryPoint(line.start);
|
|
8443
|
-
const endConnectLines = this.queryPoint(line.end);
|
|
8444
|
-
this.rotate(line);
|
|
8445
|
-
startConnectList.forEach(({ userData: queryLine, point: point2 }) => {
|
|
8446
|
-
this.recursion(queryLine, point2, line, line.start);
|
|
8447
|
-
});
|
|
8448
|
-
endConnectLines.forEach(({ userData: queryLine, point: point2 }) => {
|
|
8449
|
-
this.recursion(queryLine, point2, line, line.end);
|
|
8450
|
-
});
|
|
8451
|
-
}
|
|
8452
|
-
/** 递归执行
|
|
8453
|
-
* @param line
|
|
8454
|
-
* @param enterPoint
|
|
8455
|
-
*/
|
|
8456
|
-
recursion(line, enterPoint, nextLine, nextPoint) {
|
|
8457
|
-
const otherPoint = line.getAnotherPoint(enterPoint);
|
|
8458
|
-
const connectList = this.queryPoint(otherPoint);
|
|
8459
|
-
this.rotate(line);
|
|
8460
|
-
this.establishConnection(enterPoint, line, nextLine, nextPoint);
|
|
8461
|
-
connectList.forEach(({ userData: queryLine, point: point2 }) => {
|
|
8462
|
-
this.recursion(queryLine, point2, line, otherPoint);
|
|
8463
|
-
});
|
|
8464
|
-
}
|
|
8465
|
-
/** 构建连接
|
|
8466
|
-
*/
|
|
8467
|
-
establishConnection(point2, line, nextLine, nextPoint) {
|
|
8468
|
-
if (line.isParallelTo(nextLine)) {
|
|
8469
|
-
const interPoint2 = nextLine.projectPoint(point2, false);
|
|
8470
|
-
const newLine = new LineSegment(point2.clone(), interPoint2?.clone() ?? nextPoint.clone());
|
|
8471
|
-
newLine.length() > 1e-9 && this.newLines.push(newLine);
|
|
8472
|
-
return;
|
|
8473
|
-
}
|
|
8474
|
-
const interPoint = nextLine.projectPoint(point2, false);
|
|
8475
|
-
if (!interPoint) return;
|
|
8476
|
-
point2.copy(interPoint);
|
|
8477
|
-
if (nextLine.isPointOnSegment(interPoint)) return;
|
|
8478
|
-
nextPoint.copy(interPoint);
|
|
8479
|
-
}
|
|
8480
|
-
point = new Point();
|
|
8481
|
-
/** 旋转
|
|
8482
|
-
* @param line
|
|
8483
|
-
* @param errAngle
|
|
8484
|
-
*/
|
|
8485
|
-
rotate(line, errAngle = 45) {
|
|
8486
|
-
const baseline = this.baseline;
|
|
8487
|
-
this.point.copy(line.start);
|
|
8488
|
-
if (line.isParallelTo(baseline, errAngle)) parallel(line, baseline);
|
|
8489
|
-
else vertical(line, baseline);
|
|
8490
|
-
this.addVisited(line);
|
|
8491
|
-
}
|
|
8492
|
-
}
|
|
8493
|
-
function shortDistanceLink(lines, radius = 0.1) {
|
|
8494
|
-
const dpSet = findDiscretePoint(lines.filter((line) => !line.userData.isDoor)), pointVirtualGrid = createPointVirtualGrid(dpSet.map((v2) => v2)), appendLines = [], visited = /* @__PURE__ */ new Set();
|
|
8495
|
-
const getWeight2 = (target, point2, line) => {
|
|
8496
|
-
if (target.weight) return target.weight;
|
|
8497
|
-
const targetLine = target.userData, targetPoint = target.point;
|
|
8498
|
-
const direct1 = line.getAnotherPoint(point2).directionFrom(point2), direct2 = targetLine.getAnotherPoint(targetPoint).directionFrom(targetPoint), direct3 = targetPoint.directionFrom(point2), angle = direct1.angleBetween(direct2), angle2 = direct1.angleBetween(direct3), length = point2.distance(target.point), weight = 1 - length / radius + angle / Math.PI * 1.2 + (1 - angle2 / Math.PI) * 1.2;
|
|
8499
|
-
target.weight = weight;
|
|
8500
|
-
return weight;
|
|
8501
|
-
};
|
|
8502
|
-
for (const [point2, line] of dpSet) {
|
|
8503
|
-
if (line.userData.isDoor) continue;
|
|
8504
|
-
if (visited.has(point2)) continue;
|
|
8505
|
-
const list = pointVirtualGrid.queryCircle(point2, radius, true).map((item) => Object.assign({}, item)).filter((item) => {
|
|
8506
|
-
const targetLine2 = item.userData, targetPoint2 = item.point, direct1 = line.getAnotherPoint(point2).directionFrom(point2), direct2 = targetLine2.getAnotherPoint(targetPoint2).directionFrom(targetPoint2), angle = direct1.angleBetween(direct2, "angle");
|
|
8507
|
-
return angle > 90;
|
|
8508
|
-
}).sort((a2, b4) => getWeight2(b4, point2, line) - getWeight2(a2, point2, line));
|
|
8509
|
-
if (list.length === 0) continue;
|
|
8510
|
-
const { point: targetPoint } = list[0];
|
|
8511
|
-
const targetLine = list[0].userData;
|
|
8512
|
-
visited.add(point2);
|
|
8513
|
-
visited.add(targetPoint);
|
|
8514
|
-
const projectLine1 = line.projectLineSegment(targetLine), projectLine2 = targetLine.projectLineSegment(line), len1 = projectLine1.length(), len2 = projectLine2.length();
|
|
8515
|
-
if (len1 === 0 && len2 === 0) appendLines.push(new LineSegment(point2.clone(), list[0].point.clone()));
|
|
8516
|
-
else appendLines.push(new LineSegment(projectLine1.center, projectLine2.center));
|
|
8517
|
-
}
|
|
8518
|
-
return [...lines, ...appendLines];
|
|
8519
|
-
}
|
|
8520
|
-
function preprocessing(lines) {
|
|
8521
|
-
const pointVirtualGrid = new PointVirtualGrid(), quadtree = new Quadtree(Box2.fromByLineSegment(...lines)), doors = [];
|
|
8522
|
-
lines.forEach((line) => {
|
|
8523
|
-
if (line.userData.isDoor) doors.push(line);
|
|
8524
|
-
else {
|
|
8525
|
-
line.points.forEach((p2) => pointVirtualGrid.insert(p2, line));
|
|
8526
|
-
quadtree.insert(line);
|
|
8527
|
-
}
|
|
8528
|
-
});
|
|
8529
|
-
doors.forEach((door) => {
|
|
8530
|
-
const startIntersection = pointVirtualGrid.queryPoint(door.start);
|
|
8531
|
-
const endIntersection = pointVirtualGrid.queryPoint(door.end);
|
|
8532
|
-
if (startIntersection.length) door.userData.startIntersection = startIntersection[0].userData;
|
|
8533
|
-
else door.userData.startIntersection = quadtree.queryPoint(door.start)[0]?.line;
|
|
8534
|
-
if (endIntersection.length) door.userData.endIntersection = endIntersection[0].userData;
|
|
8535
|
-
else door.userData.endIntersection = quadtree.queryPoint(door.end)[0]?.line;
|
|
8536
|
-
});
|
|
8537
|
-
lines = shortDistanceLink(lines, 0.4);
|
|
8538
|
-
pointVirtualGrid.clear();
|
|
8539
|
-
quadtree.clear();
|
|
8540
|
-
return lines;
|
|
8541
|
-
}
|
|
8542
|
-
function adsorption(lines, option) {
|
|
8543
|
-
const { snapThreshold: threshold = 0.2 } = option ?? {}, lineQueryer = new LineQueryer(lines), modifyManager = LineSegment.createModifyManager();
|
|
8544
|
-
function adsorptLine(point2, line) {
|
|
8545
|
-
const otherPoint = line.getAnotherPoint(point2);
|
|
8546
|
-
const direct = otherPoint.directionFrom(point2);
|
|
8547
|
-
const len = line.length();
|
|
8548
|
-
const result = lineQueryer.queryNearestLine(point2, {
|
|
8549
|
-
radius: threshold,
|
|
8550
|
-
condition: (node, projPoint) => {
|
|
8551
|
-
if (line !== node.line && node.line.isPerpendicularTo(line, 35)) {
|
|
8552
|
-
if (projPoint.distance(point2) < len) return true;
|
|
8553
|
-
const direct2 = projPoint.directionFrom(point2);
|
|
8554
|
-
return direct2.angleBetween(direct) > Math.PI * 0.5;
|
|
8555
|
-
}
|
|
8556
|
-
return false;
|
|
8557
|
-
}
|
|
8558
|
-
});
|
|
8559
|
-
if (result) return modifyManager.setPoint(line, point2, result.point.clone());
|
|
8560
|
-
}
|
|
8561
|
-
function adsorptPoint(point2, line) {
|
|
8562
|
-
const result = lineQueryer.queryNearestPoint(point2, {
|
|
8563
|
-
radius: threshold,
|
|
8564
|
-
condition(node) {
|
|
8565
|
-
const line2 = node.userData;
|
|
8566
|
-
return line2.isPerpendicularTo(line, 15);
|
|
8567
|
-
}
|
|
8568
|
-
});
|
|
8569
|
-
if (result) {
|
|
8570
|
-
const propPoint = result.line.projectPoint(point2, false);
|
|
8571
|
-
if (propPoint) {
|
|
8572
|
-
modifyManager.setPoint(line, point2, propPoint);
|
|
8573
|
-
modifyManager.setPoint(result.line, result.point, propPoint);
|
|
8574
|
-
}
|
|
8575
|
-
}
|
|
8576
|
-
}
|
|
8577
|
-
for (let i = 0; i < lines.length; i++) {
|
|
8578
|
-
const line = lines[i];
|
|
8579
|
-
line.points.map((point2) => {
|
|
8580
|
-
let results = lineQueryer.pointVirtualGrid.queryPoint(point2, true);
|
|
8581
|
-
if (results.length === 0 && lineQueryer.quadtree.queryCircle(point2, 1e-4).length < 2) adsorptLine(point2, line);
|
|
8582
|
-
});
|
|
8583
|
-
}
|
|
8584
|
-
modifyManager.modify();
|
|
8585
|
-
lines = lines.filter((line) => line.length() > 1e-9);
|
|
8586
|
-
const dpls = [...findDiscretePointLine2(lines)];
|
|
8587
|
-
lineQueryer.update(lines);
|
|
8588
|
-
for (let i = 0; i < dpls.length; i++) {
|
|
8589
|
-
const line = dpls[i];
|
|
8590
|
-
line.points.map((point2) => {
|
|
8591
|
-
let results = lineQueryer.pointVirtualGrid.queryPoint(point2, true);
|
|
8592
|
-
if (results.length === 0 && lineQueryer.quadtree.queryCircle(point2, 1e-4).length < 2) {
|
|
8593
|
-
adsorptPoint(point2, line);
|
|
8594
|
-
}
|
|
8595
|
-
});
|
|
8596
|
-
}
|
|
8597
|
-
modifyManager.modify();
|
|
8598
|
-
lineQueryer.clear();
|
|
8599
|
-
Point.adsorb(lines.flatMap((line) => line.points), 1e-4, "first");
|
|
8600
|
-
return lines;
|
|
8601
|
-
}
|
|
8602
|
-
function removeShortLine(lines, len = 0.01) {
|
|
8603
|
-
let defaultLines = [], doorLines = [];
|
|
8604
|
-
for (let i = 0; i < lines.length; i++) {
|
|
8605
|
-
const line = lines[i];
|
|
8606
|
-
if (line.userData.isDoor) doorLines.push(line);
|
|
8607
|
-
else defaultLines.push(line);
|
|
8608
|
-
}
|
|
8609
|
-
const lineSet = findDiscretePointLine2(lines);
|
|
8610
|
-
const grid = createPointVirtualGrid([...lineSet]);
|
|
8611
|
-
for (let i = 0; i < doorLines.length; i++) {
|
|
8612
|
-
const doorLine = doorLines[i];
|
|
8613
|
-
doorLine.points.forEach((p2) => {
|
|
8614
|
-
grid.queryPoint(p2, true).forEach((item) => lineSet.delete(item.userData));
|
|
8615
|
-
});
|
|
8616
|
-
}
|
|
8617
|
-
defaultLines = defaultLines.filter((line) => !lineSet.has(line) || line.length() > len);
|
|
8618
|
-
defaultLines = LineSegmentUndirectedGraph.breakpointMerging(defaultLines, (newLine, lines2) => {
|
|
8619
|
-
lines2 = lines2.filter((line) => line.length() > 0);
|
|
8620
|
-
mergeLineUserData(newLine, lines2);
|
|
8621
|
-
newLine.userData.isBayWindow = lines2.some((line) => line.userData.isBayWindow);
|
|
8622
|
-
});
|
|
8623
|
-
WallInsertObject.recomputed(defaultLines);
|
|
8624
|
-
return [...defaultLines, ...doorLines];
|
|
8625
|
-
}
|
|
8626
|
-
function breakpointMerging(lines) {
|
|
8627
|
-
let defaultLines = [], doorLines = [];
|
|
8628
|
-
for (let i = 0; i < lines.length; i++) {
|
|
8629
|
-
const line = lines[i];
|
|
8630
|
-
if (line.userData.isDoor) doorLines.push(line);
|
|
8631
|
-
else defaultLines.push(line);
|
|
8632
|
-
}
|
|
8633
|
-
defaultLines = LineSegmentUndirectedGraph.breakpointMerging(defaultLines, mergeLineUserData);
|
|
8634
|
-
doorLines = LineSegmentUndirectedGraph.breakpointMerging(doorLines, mergeLineUserData);
|
|
8635
|
-
return [...defaultLines, ...doorLines];
|
|
8636
|
-
}
|
|
8637
|
-
function axisAlignCorr$1(lines, targettLine, option) {
|
|
8638
|
-
lines = lines.map((line) => line.clone());
|
|
8639
|
-
lines = breakpointMerging(lines);
|
|
8640
|
-
lines = lineSegmentClipping(lines, 1e-9);
|
|
8641
|
-
lines = preprocessing(lines);
|
|
8642
|
-
lines = AxisAlignCorr.start(lines, targettLine);
|
|
8643
|
-
lines = adsorption(lines, option);
|
|
8644
|
-
lines = lineSegmentClipping(lines, 1e-9);
|
|
8645
|
-
lines = removeShortLine(lines, 0.15);
|
|
8646
|
-
let newLines = lines.filter((line) => !line.userData.isDoor);
|
|
8647
|
-
let doorLines = lines.filter((line) => line.userData.isDoor);
|
|
8648
|
-
newLines = buildBayWindowGroup(newLines, false);
|
|
8649
|
-
const { wallGroup = true } = option ?? {};
|
|
8650
|
-
if (wallGroup) {
|
|
8651
|
-
newLines = DoubleWallHelper.complementSide(newLines);
|
|
8652
|
-
WallInsertObject.recomputed(newLines);
|
|
8653
|
-
newLines = buildDoubleWallGroup(newLines, true);
|
|
8654
|
-
newLines = buildBayWindowGroup(newLines, false);
|
|
8655
|
-
}
|
|
8656
|
-
new WallInsertObject(lines).recomputed().merge();
|
|
8657
|
-
newLines.push(...doorLines);
|
|
8658
|
-
Point.adsorb(newLines.flatMap((line) => line.points), 1e-4);
|
|
8659
|
-
lines = removeShortLine(lines, 0.05);
|
|
8660
|
-
lines = breakpointMerging(lines);
|
|
8661
|
-
return newLines;
|
|
8662
|
-
}
|
|
8663
|
-
class BoundExt {
|
|
8664
|
-
/** 通过轨迹点查找外墙
|
|
8665
|
-
* @param lines
|
|
8666
|
-
* @param trajectoryPoints
|
|
8667
|
-
* @returns
|
|
8668
|
-
*/
|
|
8669
|
-
static findExtWallByTraj(lines, trajectoryPoints, minWidth = 0.4) {
|
|
8670
|
-
lines = lines.filter((line) => !line.userData.isBayWindow);
|
|
8671
|
-
const quadtree = new Quadtree(Box2.fromByLineSegment(...lines));
|
|
8672
|
-
lines.forEach((line) => quadtree.insert({ line, userData: void 0 }));
|
|
8673
|
-
lines = lines.filter((line) => {
|
|
8674
|
-
if (LineGroupType.hasType(line, "doubleWall")) return;
|
|
8675
|
-
const center = line.center;
|
|
8676
|
-
const set2 = /* @__PURE__ */ new Set();
|
|
8677
|
-
for (const point2 of trajectoryPoints) {
|
|
8678
|
-
if (set2.size === 2) break;
|
|
8679
|
-
const lineA = new LineSegment(center, point2);
|
|
8680
|
-
const list = quadtree.queryLineSegment(lineA).filter((target) => {
|
|
8681
|
-
if (target.line === line) return false;
|
|
8682
|
-
if (LineGroupType.hasGroup(line)) return true;
|
|
8683
|
-
if (target.line.isParallelTo(line)) {
|
|
8684
|
-
if (line.distanceToSegment(target.line) < minWidth) {
|
|
8685
|
-
const projectLine = target.line.projectLineSegment(line);
|
|
8686
|
-
if (projectLine.length() / line.length() > 0.6) return false;
|
|
8687
|
-
}
|
|
8688
|
-
}
|
|
8689
|
-
return true;
|
|
8690
|
-
});
|
|
8691
|
-
if (!list.length) {
|
|
8692
|
-
const position = line.getPointSideOfLine(point2);
|
|
8693
|
-
position !== "on" && set2.add(position);
|
|
8694
|
-
}
|
|
8695
|
-
}
|
|
8696
|
-
line.userData.expandDirect = [...set2][0];
|
|
8697
|
-
if (set2.size < 2) return true;
|
|
8698
|
-
});
|
|
8699
|
-
return lines;
|
|
8700
|
-
}
|
|
8701
|
-
/** 通过轨迹点外扩边线
|
|
8702
|
-
* @param lines
|
|
8703
|
-
* @param trajectoryPoints
|
|
8704
|
-
*/
|
|
8705
|
-
static boundExtbyTrajAndOriginalData(opt) {
|
|
8706
|
-
const zList = [];
|
|
8707
|
-
let lines = opt.data.map(({ start, end, ...opt2 }) => {
|
|
8708
|
-
const line = new LineSegment(Point.from(start), Point.from(end));
|
|
8709
|
-
line.userData = opt2;
|
|
8710
|
-
zList.push(start.z ?? 0, end.z ?? 0);
|
|
8711
|
-
return line;
|
|
8712
|
-
});
|
|
8713
|
-
const originalZAverage = zList.reduce((count, num) => count + num, 0) / zList.length;
|
|
8714
|
-
return this.boundExtbyTraj({ ...opt, lines }).toOriginalData(originalZAverage);
|
|
8715
|
-
}
|
|
8716
|
-
/** 通过轨迹点外扩边线
|
|
8717
|
-
* @param lines
|
|
8718
|
-
* @param trajectory
|
|
8719
|
-
* @param wallWidth
|
|
8720
|
-
* @param findCallBack
|
|
8721
|
-
* @returns
|
|
8722
|
-
*/
|
|
8723
|
-
static boundExtbyTraj(opt) {
|
|
8724
|
-
let { lines, trajectory: trajectory2, wallWidth = 0.12, updateDoubleWallGroup = false, findCallBack } = opt;
|
|
8725
|
-
if (updateDoubleWallGroup) lines = DoubleWallHelper.buildGroup(lines);
|
|
8726
|
-
const trajectoryPoints = Object.keys(trajectory2).map((key) => Point.from(trajectory2[key]));
|
|
8727
|
-
const findLines = BoundExt.findExtWallByTraj(lines, trajectoryPoints);
|
|
8728
|
-
let exteriorLines = findLines.filter((line) => line.userData.expandDirect).filter((line) => !line.userData.isBalconyRailing).filter((line) => !LineGroupType.hasType(line, "bayWindow"));
|
|
8729
|
-
lines = lines.filter((line) => !exteriorLines.includes(line));
|
|
8730
|
-
lines.push(...exteriorLines);
|
|
8731
|
-
const grid = createPointVirtualGrid(lines), quadtree = createQuadtree(lines), arrayMap = new ArrayMap(), pointMap = /* @__PURE__ */ new Map();
|
|
8732
|
-
let appendLines = [];
|
|
8733
|
-
exteriorLines.forEach((line) => {
|
|
8734
|
-
const mode = line.userData.expandDirect, direction = mode === "left" ? line.getRightDirection() : line.getLeftDirection();
|
|
8735
|
-
line.points.forEach((point2) => {
|
|
8736
|
-
const id = point2.hashCode();
|
|
8737
|
-
arrayMap.append(id, { point: point2, line });
|
|
8738
|
-
if (!pointMap.has(id)) pointMap.set(id, point2.clone());
|
|
8739
|
-
grid.update(point2);
|
|
8740
|
-
});
|
|
8741
|
-
line.translate(wallWidth * 0.5, direction);
|
|
8742
|
-
});
|
|
8743
|
-
arrayMap.forEach((list, id) => {
|
|
8744
|
-
if (list.length >= 2) {
|
|
8745
|
-
const p1 = list[0].line.getIntersection(list[1].line);
|
|
8746
|
-
if (p1) {
|
|
8747
|
-
list[0].point.copy(p1);
|
|
8748
|
-
list[1].point.copy(p1);
|
|
8749
|
-
}
|
|
8750
|
-
} else {
|
|
8751
|
-
const queryList = grid.queryCircle(pointMap.get(id), 1e-4);
|
|
8752
|
-
if (queryList.length) {
|
|
8753
|
-
const newLine = new LineSegment(pointMap.get(id), list[0].point.clone());
|
|
8754
|
-
const list_ = list.filter((i) => !i.line.userData.isDoor && !i.line.userData.isWindow);
|
|
8755
|
-
if (list_.length) newLine.userData = cloneUserData(list_[0].line.userData);
|
|
8756
|
-
if (quadtree.queryCircle(newLine.center, 1e-4).length) return;
|
|
8757
|
-
appendLines.push(newLine);
|
|
8758
|
-
}
|
|
8759
|
-
}
|
|
8760
|
-
});
|
|
8761
|
-
appendLines = LineSegment.mergeParallelSegments(appendLines).lines;
|
|
8762
|
-
lines.push(...appendLines.filter((line) => line.length() > 1e-9));
|
|
8763
|
-
lines = lineSegmentClipping(lines, 1e-9);
|
|
8764
|
-
const doors = lines.filter((line) => line.userData.isDoor);
|
|
8765
|
-
const walls = lines.filter((line) => !line.userData.isDoor);
|
|
8766
|
-
lines = [...LineSegment.mergeCollinearSegments(walls, mergeLineUserData), ...doors];
|
|
8767
|
-
WallInsertObject.recomputed(lines);
|
|
8768
|
-
lines = lines.filter((line) => line.length() > 1e-4).filter((line) => line.userData.isDoor ? line.length() > 0.25 : true);
|
|
8769
|
-
findCallBack && findCallBack([...exteriorLines, ...appendLines], trajectoryPoints);
|
|
8770
|
-
return {
|
|
8771
|
-
lines,
|
|
8772
|
-
toOriginalData(originalZAverage) {
|
|
8773
|
-
return lineDataToOriginalData(lines, originalZAverage);
|
|
8774
|
-
}
|
|
8775
|
-
};
|
|
8776
|
-
}
|
|
8777
|
-
}
|
|
8778
|
-
if (typeof globalThis !== "undefined" && typeof ProgressEvent === "undefined") {
|
|
8779
|
-
globalThis.ProgressEvent = class ProgressEvent extends EventTarget {
|
|
8780
|
-
type;
|
|
8781
|
-
lengthComputable;
|
|
8782
|
-
loaded;
|
|
8783
|
-
total;
|
|
8784
|
-
bubbles;
|
|
8785
|
-
cancelable;
|
|
8786
|
-
defaultPrevented;
|
|
8787
|
-
eventPhase;
|
|
8788
|
-
timeStamp;
|
|
8789
|
-
isTrusted;
|
|
8790
|
-
constructor(type, options = {}) {
|
|
8791
|
-
super();
|
|
8792
|
-
this.type = type;
|
|
8793
|
-
this.lengthComputable = options.lengthComputable || false;
|
|
8794
|
-
this.loaded = options.loaded || 0;
|
|
8795
|
-
this.total = options.total || 0;
|
|
8796
|
-
this.bubbles = false;
|
|
8797
|
-
this.cancelable = false;
|
|
8798
|
-
this.defaultPrevented = false;
|
|
8799
|
-
this.eventPhase = 0;
|
|
8800
|
-
this.timeStamp = Date.now();
|
|
8801
|
-
this.isTrusted = true;
|
|
8802
|
-
}
|
|
8803
|
-
preventDefault() {
|
|
8804
|
-
}
|
|
8805
|
-
stopPropagation() {
|
|
8806
|
-
}
|
|
8807
|
-
stopImmediatePropagation() {
|
|
8808
|
-
}
|
|
8809
|
-
};
|
|
8810
|
-
}
|
|
8811
|
-
let gltfLoader = GLTFExporter;
|
|
8812
|
-
let gltfExporter = GLTFLoader;
|
|
8813
|
-
let promise;
|
|
8814
|
-
function GltfInit() {
|
|
8815
|
-
if (promise) return promise;
|
|
8816
|
-
promise = new Promise(async (resolve) => {
|
|
8817
|
-
try {
|
|
8818
|
-
const { GLTFLoader: GLTFLoader2 } = await (typeof window !== "undefined" ? import("three/addons/loaders/GLTFLoader.js") : include("node-three-gltf", false));
|
|
8819
|
-
gltfLoader = GLTFLoader2;
|
|
8820
|
-
const { GLTFExporter: GLTFExporter2 } = await (typeof window !== "undefined" ? import("three/addons/exporters/GLTFExporter.js") : include("node-three-gltf", false));
|
|
8821
|
-
gltfExporter = GLTFExporter2;
|
|
8822
|
-
} catch (error) {
|
|
8823
|
-
console.error(error);
|
|
8824
|
-
}
|
|
8825
|
-
resolve(true);
|
|
8826
|
-
});
|
|
8827
|
-
return promise;
|
|
8828
|
-
}
|
|
8829
|
-
const gltf = {
|
|
8830
|
-
get GLTFLoader() {
|
|
8831
|
-
return gltfLoader;
|
|
8832
|
-
},
|
|
8833
|
-
get GLTFExporter() {
|
|
8834
|
-
return gltfExporter;
|
|
8478
|
+
const gltf = {
|
|
8479
|
+
get GLTFLoader() {
|
|
8480
|
+
return gltfLoader;
|
|
8481
|
+
},
|
|
8482
|
+
get GLTFExporter() {
|
|
8483
|
+
return gltfExporter;
|
|
8835
8484
|
}
|
|
8836
8485
|
};
|
|
8837
8486
|
let loader;
|
|
@@ -19013,100 +18662,452 @@ class DoorFind {
|
|
|
19013
18662
|
line.getAnotherPoint(dock.point).copy(point2);
|
|
19014
18663
|
}
|
|
19015
18664
|
}
|
|
19016
|
-
/**
|
|
19017
|
-
* 对门的两侧进行吸附
|
|
19018
|
-
* @param dock
|
|
18665
|
+
/**
|
|
18666
|
+
* 对门的两侧进行吸附
|
|
18667
|
+
* @param dock
|
|
18668
|
+
* @param line
|
|
18669
|
+
* @param maxAngle 找到的门线与原来的之间最大夹角
|
|
18670
|
+
* @returns
|
|
18671
|
+
*/
|
|
18672
|
+
adsorpt(dock, line, maxAngle = 70) {
|
|
18673
|
+
const length = line.length(), targetDirect = dock.dockLine.getAnotherPoint(dock.dockPoint).directionFrom(dock.dockPoint);
|
|
18674
|
+
dock.point.copy(dock.dockPoint);
|
|
18675
|
+
const list = this.grid.queryCircle(dock.point, length * 2, true).map((item) => {
|
|
18676
|
+
return { ...item };
|
|
18677
|
+
}).filter((item) => item.userData !== dock.dockLine).filter((item) => {
|
|
18678
|
+
return this.grid.queryPoint(item.point, true).length === 0;
|
|
18679
|
+
}).filter((item) => {
|
|
18680
|
+
const d1 = item.point.directionFrom(dock.point);
|
|
18681
|
+
return d1.angleBetween(targetDirect, "angle") > 70;
|
|
18682
|
+
}).filter((item) => {
|
|
18683
|
+
const line2 = item.userData, d1 = item.point.directionFrom(dock.point), d2 = line2.getAnotherPoint(item.point).directionFrom(item.point), d3 = dock.dockPoint.directionFrom(dock.dockLine.getAnotherPoint(dock.dockPoint));
|
|
18684
|
+
return d1.angleBetween(d2, "angle") < maxAngle && d3.angleBetween(d2, "angle") < maxAngle;
|
|
18685
|
+
}).filter((item) => {
|
|
18686
|
+
const queryLine = new LineSegment(item.point.clone(), dock.point.clone());
|
|
18687
|
+
queryLine.startShrink(0.01).endShrink(1e-3);
|
|
18688
|
+
return this.quadtree.queryLineSegment(queryLine).length === 0;
|
|
18689
|
+
}).filter((item) => {
|
|
18690
|
+
return item.point.distance(dock.point) / length > 0.5;
|
|
18691
|
+
}).filter((item) => {
|
|
18692
|
+
const normal = item.point.normal(dock.point), center = new Point((item.point.x + dock.point.x) / 2, (item.point.y + dock.point.y) / 2), length2 = item.point.distance(dock.point);
|
|
18693
|
+
const normalLine = new LineSegment(
|
|
18694
|
+
center,
|
|
18695
|
+
center.clone().add(normal.clone().multiplyScalar(length2))
|
|
18696
|
+
);
|
|
18697
|
+
normalLine.translate(-length2 * 0.5, normal);
|
|
18698
|
+
const results = this.quadtree.queryLineSegment(normalLine).filter((result) => result.line !== line && result.line !== dock.dockLine);
|
|
18699
|
+
return results.length === 0;
|
|
18700
|
+
}).sort((a2, b4) => {
|
|
18701
|
+
return getWeight(b4, dock, length) - getWeight(a2, dock, length);
|
|
18702
|
+
});
|
|
18703
|
+
if (list.length) {
|
|
18704
|
+
const line2 = list[0].userData;
|
|
18705
|
+
let point2 = list[0].point;
|
|
18706
|
+
if (dock.dockLine.isPerpendicularTo(line2, 25)) {
|
|
18707
|
+
const p2 = line2.projectPoint(dock.point, true);
|
|
18708
|
+
if (p2) point2 = p2;
|
|
18709
|
+
}
|
|
18710
|
+
return point2;
|
|
18711
|
+
}
|
|
18712
|
+
return this.extendLink(dock, line);
|
|
18713
|
+
}
|
|
18714
|
+
extendLink(dock, line) {
|
|
18715
|
+
const length = line.length();
|
|
18716
|
+
const direct = dock.dockPoint.directionFrom(dock.dockLine.getAnotherPoint(dock.dockPoint)), queryLine = new LineSegment(
|
|
18717
|
+
dock.dockPoint,
|
|
18718
|
+
dock.dockPoint.clone().add(direct.multiplyScalar(length * 2))
|
|
18719
|
+
);
|
|
18720
|
+
let result = this.quadtree.queryLineSegment(queryLine, false).filter((item) => item.line !== dock.dockLine && item.line !== line).map((item) => item.line.getIntersection(queryLine)).filter((p2) => !!p2).filter((p2) => p2.distance(dock.dockPoint, true) > 0.2).sort((a2, b4) => a2.distance(dock.dockPoint, true) - b4.distance(dock.dockPoint, true));
|
|
18721
|
+
if (result.length) return result[0];
|
|
18722
|
+
const normal = dock.dockLine.normal(), nNormal = normal.multiplyScalar(-1), direct2 = line.getAnotherPoint(dock.point).directionFrom(dock.point);
|
|
18723
|
+
if (direct2.angleBetween(normal) < direct2.angleBetween(nNormal)) {
|
|
18724
|
+
queryLine.set(
|
|
18725
|
+
dock.dockPoint,
|
|
18726
|
+
dock.dockPoint.clone().add(normal.multiplyScalar(length * 2))
|
|
18727
|
+
);
|
|
18728
|
+
} else {
|
|
18729
|
+
queryLine.set(
|
|
18730
|
+
dock.dockPoint,
|
|
18731
|
+
dock.dockPoint.clone().add(nNormal.multiplyScalar(length * 2))
|
|
18732
|
+
);
|
|
18733
|
+
}
|
|
18734
|
+
result = this.quadtree.queryLineSegment(queryLine, false).filter((item) => {
|
|
18735
|
+
item.line !== dock.dockLine && item.line !== line;
|
|
18736
|
+
}).map((item) => {
|
|
18737
|
+
const point2 = item.line.getIntersection(queryLine);
|
|
18738
|
+
if (point2) return point2;
|
|
18739
|
+
}).filter((p2) => !!p2).filter((p2) => p2.distance(dock.dockPoint, true) > 0.2).sort((a2, b4) => a2.distance(dock.dockPoint, true) - b4.distance(dock.dockPoint, true));
|
|
18740
|
+
if (result.length) return result[0];
|
|
18741
|
+
return null;
|
|
18742
|
+
}
|
|
18743
|
+
getLines() {
|
|
18744
|
+
return this.lines.filter((line) => {
|
|
18745
|
+
if (line.userData.isDoor && line.length() < 0.4) return false;
|
|
18746
|
+
return true;
|
|
18747
|
+
});
|
|
18748
|
+
}
|
|
18749
|
+
}
|
|
18750
|
+
function init(lines, option) {
|
|
18751
|
+
buildDoubleWallGroup.setTrajectory(option.trajectory);
|
|
18752
|
+
return lines;
|
|
18753
|
+
}
|
|
18754
|
+
class LineQueryer {
|
|
18755
|
+
pointVirtualGrid;
|
|
18756
|
+
quadtree;
|
|
18757
|
+
constructor(lines) {
|
|
18758
|
+
this.pointVirtualGrid = createPointVirtualGrid(lines);
|
|
18759
|
+
this.quadtree = createQuadtree(lines);
|
|
18760
|
+
}
|
|
18761
|
+
update(lines) {
|
|
18762
|
+
this.clear();
|
|
18763
|
+
this.pointVirtualGrid = createPointVirtualGrid(lines);
|
|
18764
|
+
this.quadtree = createQuadtree(lines);
|
|
18765
|
+
}
|
|
18766
|
+
clear() {
|
|
18767
|
+
this.pointVirtualGrid.clear();
|
|
18768
|
+
this.quadtree.clear();
|
|
18769
|
+
}
|
|
18770
|
+
/**
|
|
18771
|
+
* @param point
|
|
18772
|
+
* @param radius
|
|
18773
|
+
* @param opt
|
|
18774
|
+
* @returns
|
|
18775
|
+
*/
|
|
18776
|
+
queryNearestPoint(point2, opt) {
|
|
18777
|
+
if (!point2) throw new Error("请传入查询点");
|
|
18778
|
+
const { resultIndex = 0, radius = 0.4, condition } = opt ?? {};
|
|
18779
|
+
const results = this.pointVirtualGrid.queryCircle(point2, radius).filter((item) => item.point !== point2).filter((item) => condition ? condition(item) : true);
|
|
18780
|
+
results.sort((a2, b4) => a2.point.distance(point2, true) - b4.point.distance(point2, true));
|
|
18781
|
+
if (results.length > resultIndex) return {
|
|
18782
|
+
point: results[resultIndex].point,
|
|
18783
|
+
line: results[resultIndex].userData
|
|
18784
|
+
};
|
|
18785
|
+
return null;
|
|
18786
|
+
}
|
|
18787
|
+
/**
|
|
18788
|
+
* @param point
|
|
18789
|
+
* @param radius
|
|
18790
|
+
* @param opt
|
|
18791
|
+
* @returns
|
|
18792
|
+
*/
|
|
18793
|
+
queryNearestLine(point2, opt) {
|
|
18794
|
+
if (!point2) throw new Error("请传入查询点");
|
|
18795
|
+
const { resultIndex = 0, radius = 0.4, condition } = opt ?? {};
|
|
18796
|
+
const results = this.quadtree.queryCircle(point2, radius).map((item) => {
|
|
18797
|
+
const projPoint = item.line.projectPoint(point2, false);
|
|
18798
|
+
if (projPoint && (!condition || condition(item, projPoint))) {
|
|
18799
|
+
if (projPoint) return {
|
|
18800
|
+
...item,
|
|
18801
|
+
distance: projPoint.distance(point2) ?? Infinity,
|
|
18802
|
+
projPoint
|
|
18803
|
+
};
|
|
18804
|
+
}
|
|
18805
|
+
return null;
|
|
18806
|
+
}).filter((i) => !!i);
|
|
18807
|
+
results.sort((a2, b4) => a2.distance - b4.distance);
|
|
18808
|
+
if (results.length > resultIndex) return {
|
|
18809
|
+
point: results[resultIndex].projPoint,
|
|
18810
|
+
line: results[resultIndex].line
|
|
18811
|
+
};
|
|
18812
|
+
return null;
|
|
18813
|
+
}
|
|
18814
|
+
}
|
|
18815
|
+
function parallel(line, baseline) {
|
|
18816
|
+
const currentAngle = Math.atan2(line.end.y - line.start.y, line.end.x - line.start.x);
|
|
18817
|
+
const targetAngle = Math.atan2(baseline.end.y - baseline.start.y, baseline.end.x - baseline.start.x);
|
|
18818
|
+
let diff = targetAngle - currentAngle;
|
|
18819
|
+
while (diff > Math.PI) diff -= 2 * Math.PI;
|
|
18820
|
+
while (diff < -Math.PI) diff += 2 * Math.PI;
|
|
18821
|
+
const center = line.center;
|
|
18822
|
+
line.start.rotate(center, diff);
|
|
18823
|
+
line.end.rotate(center, diff);
|
|
18824
|
+
if (Math.abs(diff) > Math.PI / 2) line.swapValue();
|
|
18825
|
+
return line;
|
|
18826
|
+
}
|
|
18827
|
+
function vertical(line, baseline) {
|
|
18828
|
+
const currentAngle = Math.atan2(line.end.y - line.start.y, line.end.x - line.start.x);
|
|
18829
|
+
const targetAngle = Math.atan2(baseline.end.y - baseline.start.y, baseline.end.x - baseline.start.x);
|
|
18830
|
+
let diff1 = targetAngle + Math.PI / 2 - currentAngle;
|
|
18831
|
+
let diff2 = targetAngle - Math.PI / 2 - currentAngle;
|
|
18832
|
+
while (diff1 > Math.PI) diff1 -= 2 * Math.PI;
|
|
18833
|
+
while (diff1 < -Math.PI) diff1 += 2 * Math.PI;
|
|
18834
|
+
while (diff2 > Math.PI) diff2 -= 2 * Math.PI;
|
|
18835
|
+
while (diff2 < -Math.PI) diff2 += 2 * Math.PI;
|
|
18836
|
+
const diff = Math.abs(diff1) < Math.abs(diff2) ? diff1 : diff2;
|
|
18837
|
+
const center = line.center;
|
|
18838
|
+
line.start.rotate(center, diff);
|
|
18839
|
+
line.end.rotate(center, diff);
|
|
18840
|
+
if (Math.abs(diff) > Math.PI / 2) line.swapValue();
|
|
18841
|
+
return line;
|
|
18842
|
+
}
|
|
18843
|
+
class AxisAlignCorr {
|
|
18844
|
+
static start(lines, targettLine) {
|
|
18845
|
+
return new AxisAlignCorr(lines, targettLine).start();
|
|
18846
|
+
}
|
|
18847
|
+
lines;
|
|
18848
|
+
baseline;
|
|
18849
|
+
grid;
|
|
18850
|
+
constructor(lines, baseline) {
|
|
18851
|
+
this.lines = lines;
|
|
18852
|
+
this.baseline = baseline;
|
|
18853
|
+
this.grid = createPointVirtualGrid(lines);
|
|
18854
|
+
}
|
|
18855
|
+
visited = /* @__PURE__ */ new Set();
|
|
18856
|
+
newLines = [];
|
|
18857
|
+
start() {
|
|
18858
|
+
for (let i = 0; i < this.lines.length; i++) {
|
|
18859
|
+
const line = this.lines[i];
|
|
18860
|
+
if (this.visited.has(line)) continue;
|
|
18861
|
+
this.correction(line);
|
|
18862
|
+
}
|
|
18863
|
+
return [
|
|
18864
|
+
...this.lines,
|
|
18865
|
+
...this.newLines
|
|
18866
|
+
];
|
|
18867
|
+
}
|
|
18868
|
+
/** 添加
|
|
18869
|
+
* @param lines
|
|
18870
|
+
* @returns
|
|
18871
|
+
*/
|
|
18872
|
+
addVisited(lines) {
|
|
18873
|
+
if (lines instanceof LineSegment) lines = [lines];
|
|
18874
|
+
lines.forEach((line) => this.visited.add(line));
|
|
18875
|
+
return this;
|
|
18876
|
+
}
|
|
18877
|
+
queryPoint(point2) {
|
|
18878
|
+
return this.grid.queryPoint(point2, true).filter((item) => !this.visited.has(item.userData));
|
|
18879
|
+
}
|
|
18880
|
+
/** 纠正
|
|
18881
|
+
* @param line
|
|
18882
|
+
* @param targettLine
|
|
18883
|
+
*/
|
|
18884
|
+
correction(line) {
|
|
18885
|
+
const startConnectList = this.queryPoint(line.start);
|
|
18886
|
+
const endConnectLines = this.queryPoint(line.end);
|
|
18887
|
+
this.rotate(line);
|
|
18888
|
+
startConnectList.forEach(({ userData: queryLine, point: point2 }) => {
|
|
18889
|
+
this.recursion(queryLine, point2, line, line.start);
|
|
18890
|
+
});
|
|
18891
|
+
endConnectLines.forEach(({ userData: queryLine, point: point2 }) => {
|
|
18892
|
+
this.recursion(queryLine, point2, line, line.end);
|
|
18893
|
+
});
|
|
18894
|
+
}
|
|
18895
|
+
/** 递归执行
|
|
18896
|
+
* @param line
|
|
18897
|
+
* @param enterPoint
|
|
18898
|
+
*/
|
|
18899
|
+
recursion(line, enterPoint, nextLine, nextPoint) {
|
|
18900
|
+
const otherPoint = line.getAnotherPoint(enterPoint);
|
|
18901
|
+
const connectList = this.queryPoint(otherPoint);
|
|
18902
|
+
this.rotate(line);
|
|
18903
|
+
this.establishConnection(enterPoint, line, nextLine, nextPoint);
|
|
18904
|
+
connectList.forEach(({ userData: queryLine, point: point2 }) => {
|
|
18905
|
+
this.recursion(queryLine, point2, line, otherPoint);
|
|
18906
|
+
});
|
|
18907
|
+
}
|
|
18908
|
+
/** 构建连接
|
|
18909
|
+
*/
|
|
18910
|
+
establishConnection(point2, line, nextLine, nextPoint) {
|
|
18911
|
+
if (line.isParallelTo(nextLine)) {
|
|
18912
|
+
const interPoint2 = nextLine.projectPoint(point2, false);
|
|
18913
|
+
const newLine = new LineSegment(point2.clone(), interPoint2?.clone() ?? nextPoint.clone());
|
|
18914
|
+
newLine.length() > 1e-9 && this.newLines.push(newLine);
|
|
18915
|
+
return;
|
|
18916
|
+
}
|
|
18917
|
+
const interPoint = nextLine.projectPoint(point2, false);
|
|
18918
|
+
if (!interPoint) return;
|
|
18919
|
+
point2.copy(interPoint);
|
|
18920
|
+
if (nextLine.isPointOnSegment(interPoint)) return;
|
|
18921
|
+
nextPoint.copy(interPoint);
|
|
18922
|
+
}
|
|
18923
|
+
point = new Point();
|
|
18924
|
+
/** 旋转
|
|
19019
18925
|
* @param line
|
|
19020
|
-
* @param
|
|
19021
|
-
* @returns
|
|
18926
|
+
* @param errAngle
|
|
19022
18927
|
*/
|
|
19023
|
-
|
|
19024
|
-
const
|
|
19025
|
-
|
|
19026
|
-
|
|
19027
|
-
|
|
19028
|
-
|
|
19029
|
-
|
|
19030
|
-
|
|
19031
|
-
|
|
19032
|
-
|
|
19033
|
-
|
|
19034
|
-
|
|
19035
|
-
|
|
19036
|
-
|
|
19037
|
-
|
|
19038
|
-
|
|
19039
|
-
|
|
19040
|
-
|
|
19041
|
-
|
|
19042
|
-
|
|
19043
|
-
|
|
19044
|
-
const
|
|
19045
|
-
|
|
19046
|
-
|
|
19047
|
-
|
|
19048
|
-
|
|
19049
|
-
|
|
19050
|
-
|
|
19051
|
-
|
|
19052
|
-
|
|
18928
|
+
rotate(line, errAngle = 45) {
|
|
18929
|
+
const baseline = this.baseline;
|
|
18930
|
+
this.point.copy(line.start);
|
|
18931
|
+
if (line.isParallelTo(baseline, errAngle)) parallel(line, baseline);
|
|
18932
|
+
else vertical(line, baseline);
|
|
18933
|
+
this.addVisited(line);
|
|
18934
|
+
}
|
|
18935
|
+
}
|
|
18936
|
+
function shortDistanceLink(lines, radius = 0.1) {
|
|
18937
|
+
const dpSet = findDiscretePoint(lines.filter((line) => !line.userData.isDoor)), pointVirtualGrid = createPointVirtualGrid(dpSet.map((v2) => v2)), appendLines = [], visited = /* @__PURE__ */ new Set();
|
|
18938
|
+
const getWeight2 = (target, point2, line) => {
|
|
18939
|
+
if (target.weight) return target.weight;
|
|
18940
|
+
const targetLine = target.userData, targetPoint = target.point;
|
|
18941
|
+
const direct1 = line.getAnotherPoint(point2).directionFrom(point2), direct2 = targetLine.getAnotherPoint(targetPoint).directionFrom(targetPoint), direct3 = targetPoint.directionFrom(point2), angle = direct1.angleBetween(direct2), angle2 = direct1.angleBetween(direct3), length = point2.distance(target.point), weight = 1 - length / radius + angle / Math.PI * 1.2 + (1 - angle2 / Math.PI) * 1.2;
|
|
18942
|
+
target.weight = weight;
|
|
18943
|
+
return weight;
|
|
18944
|
+
};
|
|
18945
|
+
for (const [point2, line] of dpSet) {
|
|
18946
|
+
if (line.userData.isDoor) continue;
|
|
18947
|
+
if (visited.has(point2)) continue;
|
|
18948
|
+
const list = pointVirtualGrid.queryCircle(point2, radius, true).map((item) => Object.assign({}, item)).filter((item) => {
|
|
18949
|
+
const targetLine2 = item.userData, targetPoint2 = item.point, direct1 = line.getAnotherPoint(point2).directionFrom(point2), direct2 = targetLine2.getAnotherPoint(targetPoint2).directionFrom(targetPoint2), angle = direct1.angleBetween(direct2, "angle");
|
|
18950
|
+
return angle > 90;
|
|
18951
|
+
}).sort((a2, b4) => getWeight2(b4, point2, line) - getWeight2(a2, point2, line));
|
|
18952
|
+
if (list.length === 0) continue;
|
|
18953
|
+
const { point: targetPoint } = list[0];
|
|
18954
|
+
const targetLine = list[0].userData;
|
|
18955
|
+
visited.add(point2);
|
|
18956
|
+
visited.add(targetPoint);
|
|
18957
|
+
const projectLine1 = line.projectLineSegment(targetLine), projectLine2 = targetLine.projectLineSegment(line), len1 = projectLine1.length(), len2 = projectLine2.length();
|
|
18958
|
+
if (len1 === 0 && len2 === 0) appendLines.push(new LineSegment(point2.clone(), list[0].point.clone()));
|
|
18959
|
+
else appendLines.push(new LineSegment(projectLine1.center, projectLine2.center));
|
|
18960
|
+
}
|
|
18961
|
+
return [...lines, ...appendLines];
|
|
18962
|
+
}
|
|
18963
|
+
function preprocessing(lines) {
|
|
18964
|
+
const pointVirtualGrid = new PointVirtualGrid(), quadtree = new Quadtree(Box2.fromByLineSegment(...lines)), doors = [];
|
|
18965
|
+
lines.forEach((line) => {
|
|
18966
|
+
if (line.userData.isDoor) doors.push(line);
|
|
18967
|
+
else {
|
|
18968
|
+
line.points.forEach((p2) => pointVirtualGrid.insert(p2, line));
|
|
18969
|
+
quadtree.insert(line);
|
|
18970
|
+
}
|
|
18971
|
+
});
|
|
18972
|
+
doors.forEach((door) => {
|
|
18973
|
+
const startIntersection = pointVirtualGrid.queryPoint(door.start);
|
|
18974
|
+
const endIntersection = pointVirtualGrid.queryPoint(door.end);
|
|
18975
|
+
if (startIntersection.length) door.userData.startIntersection = startIntersection[0].userData;
|
|
18976
|
+
else door.userData.startIntersection = quadtree.queryPoint(door.start)[0]?.line;
|
|
18977
|
+
if (endIntersection.length) door.userData.endIntersection = endIntersection[0].userData;
|
|
18978
|
+
else door.userData.endIntersection = quadtree.queryPoint(door.end)[0]?.line;
|
|
18979
|
+
});
|
|
18980
|
+
lines = shortDistanceLink(lines, 0.4);
|
|
18981
|
+
pointVirtualGrid.clear();
|
|
18982
|
+
quadtree.clear();
|
|
18983
|
+
return lines;
|
|
18984
|
+
}
|
|
18985
|
+
function adsorption(lines, option) {
|
|
18986
|
+
const { snapThreshold: threshold = 0.2 } = option ?? {}, lineQueryer = new LineQueryer(lines), modifyManager = LineSegment.createModifyManager();
|
|
18987
|
+
function adsorptLine(point2, line) {
|
|
18988
|
+
const otherPoint = line.getAnotherPoint(point2);
|
|
18989
|
+
const direct = otherPoint.directionFrom(point2);
|
|
18990
|
+
const len = line.length();
|
|
18991
|
+
const result = lineQueryer.queryNearestLine(point2, {
|
|
18992
|
+
radius: threshold,
|
|
18993
|
+
condition: (node, projPoint) => {
|
|
18994
|
+
if (line !== node.line && node.line.isPerpendicularTo(line, 35)) {
|
|
18995
|
+
if (projPoint.distance(point2) < len) return true;
|
|
18996
|
+
const direct2 = projPoint.directionFrom(point2);
|
|
18997
|
+
return direct2.angleBetween(direct) > Math.PI * 0.5;
|
|
18998
|
+
}
|
|
18999
|
+
return false;
|
|
19000
|
+
}
|
|
19053
19001
|
});
|
|
19054
|
-
if (
|
|
19055
|
-
|
|
19056
|
-
|
|
19057
|
-
|
|
19058
|
-
|
|
19059
|
-
|
|
19002
|
+
if (result) return modifyManager.setPoint(line, point2, result.point.clone());
|
|
19003
|
+
}
|
|
19004
|
+
function adsorptPoint(point2, line) {
|
|
19005
|
+
const result = lineQueryer.queryNearestPoint(point2, {
|
|
19006
|
+
radius: threshold,
|
|
19007
|
+
condition(node) {
|
|
19008
|
+
const line2 = node.userData;
|
|
19009
|
+
return line2.isPerpendicularTo(line, 15);
|
|
19010
|
+
}
|
|
19011
|
+
});
|
|
19012
|
+
if (result) {
|
|
19013
|
+
const propPoint = result.line.projectPoint(point2, false);
|
|
19014
|
+
if (propPoint) {
|
|
19015
|
+
modifyManager.setPoint(line, point2, propPoint);
|
|
19016
|
+
modifyManager.setPoint(result.line, result.point, propPoint);
|
|
19060
19017
|
}
|
|
19061
|
-
return point2;
|
|
19062
19018
|
}
|
|
19063
|
-
return this.extendLink(dock, line);
|
|
19064
19019
|
}
|
|
19065
|
-
|
|
19066
|
-
const
|
|
19067
|
-
|
|
19068
|
-
|
|
19069
|
-
|
|
19070
|
-
);
|
|
19071
|
-
let result = this.quadtree.queryLineSegment(queryLine, false).filter((item) => item.line !== dock.dockLine && item.line !== line).map((item) => item.line.getIntersection(queryLine)).filter((p2) => !!p2).filter((p2) => p2.distance(dock.dockPoint, true) > 0.2).sort((a2, b4) => a2.distance(dock.dockPoint, true) - b4.distance(dock.dockPoint, true));
|
|
19072
|
-
if (result.length) return result[0];
|
|
19073
|
-
const normal = dock.dockLine.normal(), nNormal = normal.multiplyScalar(-1), direct2 = line.getAnotherPoint(dock.point).directionFrom(dock.point);
|
|
19074
|
-
if (direct2.angleBetween(normal) < direct2.angleBetween(nNormal)) {
|
|
19075
|
-
queryLine.set(
|
|
19076
|
-
dock.dockPoint,
|
|
19077
|
-
dock.dockPoint.clone().add(normal.multiplyScalar(length * 2))
|
|
19078
|
-
);
|
|
19079
|
-
} else {
|
|
19080
|
-
queryLine.set(
|
|
19081
|
-
dock.dockPoint,
|
|
19082
|
-
dock.dockPoint.clone().add(nNormal.multiplyScalar(length * 2))
|
|
19083
|
-
);
|
|
19084
|
-
}
|
|
19085
|
-
result = this.quadtree.queryLineSegment(queryLine, false).filter((item) => {
|
|
19086
|
-
item.line !== dock.dockLine && item.line !== line;
|
|
19087
|
-
}).map((item) => {
|
|
19088
|
-
const point2 = item.line.getIntersection(queryLine);
|
|
19089
|
-
if (point2) return point2;
|
|
19090
|
-
}).filter((p2) => !!p2).filter((p2) => p2.distance(dock.dockPoint, true) > 0.2).sort((a2, b4) => a2.distance(dock.dockPoint, true) - b4.distance(dock.dockPoint, true));
|
|
19091
|
-
if (result.length) return result[0];
|
|
19092
|
-
return null;
|
|
19020
|
+
for (let i = 0; i < lines.length; i++) {
|
|
19021
|
+
const line = lines[i];
|
|
19022
|
+
line.points.map((point2) => {
|
|
19023
|
+
let results = lineQueryer.pointVirtualGrid.queryPoint(point2, true);
|
|
19024
|
+
if (results.length === 0 && lineQueryer.quadtree.queryCircle(point2, 1e-4).length < 2) adsorptLine(point2, line);
|
|
19025
|
+
});
|
|
19093
19026
|
}
|
|
19094
|
-
|
|
19095
|
-
|
|
19096
|
-
|
|
19097
|
-
|
|
19027
|
+
modifyManager.modify();
|
|
19028
|
+
lines = lines.filter((line) => line.length() > 1e-9);
|
|
19029
|
+
const dpls = [...findDiscretePointLine2(lines)];
|
|
19030
|
+
lineQueryer.update(lines);
|
|
19031
|
+
for (let i = 0; i < dpls.length; i++) {
|
|
19032
|
+
const line = dpls[i];
|
|
19033
|
+
line.points.map((point2) => {
|
|
19034
|
+
let results = lineQueryer.pointVirtualGrid.queryPoint(point2, true);
|
|
19035
|
+
if (results.length === 0 && lineQueryer.quadtree.queryCircle(point2, 1e-4).length < 2) {
|
|
19036
|
+
adsorptPoint(point2, line);
|
|
19037
|
+
}
|
|
19098
19038
|
});
|
|
19099
19039
|
}
|
|
19100
|
-
|
|
19101
|
-
|
|
19102
|
-
|
|
19040
|
+
modifyManager.modify();
|
|
19041
|
+
lineQueryer.clear();
|
|
19042
|
+
Point.adsorb(lines.flatMap((line) => line.points), 1e-4, "first");
|
|
19103
19043
|
return lines;
|
|
19104
19044
|
}
|
|
19045
|
+
function removeShortLine(lines, len = 0.01) {
|
|
19046
|
+
let defaultLines = [], doorLines = [];
|
|
19047
|
+
for (let i = 0; i < lines.length; i++) {
|
|
19048
|
+
const line = lines[i];
|
|
19049
|
+
if (line.userData.isDoor) doorLines.push(line);
|
|
19050
|
+
else defaultLines.push(line);
|
|
19051
|
+
}
|
|
19052
|
+
const lineSet = findDiscretePointLine2(lines);
|
|
19053
|
+
const grid = createPointVirtualGrid([...lineSet]);
|
|
19054
|
+
for (let i = 0; i < doorLines.length; i++) {
|
|
19055
|
+
const doorLine = doorLines[i];
|
|
19056
|
+
doorLine.points.forEach((p2) => {
|
|
19057
|
+
grid.queryPoint(p2, true).forEach((item) => lineSet.delete(item.userData));
|
|
19058
|
+
});
|
|
19059
|
+
}
|
|
19060
|
+
defaultLines = defaultLines.filter((line) => !lineSet.has(line) || line.length() > len);
|
|
19061
|
+
defaultLines = LineSegmentUndirectedGraph.breakpointMerging(defaultLines, (newLine, lines2) => {
|
|
19062
|
+
lines2 = lines2.filter((line) => line.length() > 0);
|
|
19063
|
+
mergeLineUserData(newLine, lines2);
|
|
19064
|
+
newLine.userData.isBayWindow = lines2.some((line) => line.userData.isBayWindow);
|
|
19065
|
+
});
|
|
19066
|
+
WallInsertObject.recomputed(defaultLines);
|
|
19067
|
+
return [...defaultLines, ...doorLines];
|
|
19068
|
+
}
|
|
19069
|
+
function breakpointMerging(lines) {
|
|
19070
|
+
let defaultLines = [], doorLines = [];
|
|
19071
|
+
for (let i = 0; i < lines.length; i++) {
|
|
19072
|
+
const line = lines[i];
|
|
19073
|
+
if (line.userData.isDoor) doorLines.push(line);
|
|
19074
|
+
else defaultLines.push(line);
|
|
19075
|
+
}
|
|
19076
|
+
defaultLines = LineSegmentUndirectedGraph.breakpointMerging(defaultLines, mergeLineUserData);
|
|
19077
|
+
doorLines = LineSegmentUndirectedGraph.breakpointMerging(doorLines, mergeLineUserData);
|
|
19078
|
+
return [...defaultLines, ...doorLines];
|
|
19079
|
+
}
|
|
19080
|
+
function correction(lines, targettLine, option) {
|
|
19081
|
+
lines = lines.map((line) => line.clone());
|
|
19082
|
+
lines = breakpointMerging(lines);
|
|
19083
|
+
lines = lineSegmentClipping(lines, 1e-9);
|
|
19084
|
+
lines = preprocessing(lines);
|
|
19085
|
+
lines = AxisAlignCorr.start(lines, targettLine);
|
|
19086
|
+
lines = adsorption(lines, option);
|
|
19087
|
+
lines = lineSegmentClipping(lines, 1e-9);
|
|
19088
|
+
lines = removeShortLine(lines, 0.15);
|
|
19089
|
+
let newLines = lines.filter((line) => !line.userData.isDoor);
|
|
19090
|
+
let doorLines = lines.filter((line) => line.userData.isDoor);
|
|
19091
|
+
newLines = buildBayWindowGroup(newLines, false);
|
|
19092
|
+
const { wallGroup = true } = option ?? {};
|
|
19093
|
+
if (wallGroup) {
|
|
19094
|
+
newLines = DoubleWallHelper.complementSide(newLines);
|
|
19095
|
+
WallInsertObject.recomputed(newLines);
|
|
19096
|
+
newLines = buildDoubleWallGroup(newLines, true);
|
|
19097
|
+
newLines = buildBayWindowGroup(newLines, false);
|
|
19098
|
+
}
|
|
19099
|
+
new WallInsertObject(lines).recomputed().merge();
|
|
19100
|
+
newLines.push(...doorLines);
|
|
19101
|
+
Point.adsorb(newLines.flatMap((line) => line.points), 1e-4);
|
|
19102
|
+
lines = removeShortLine(lines, 0.05);
|
|
19103
|
+
lines = breakpointMerging(lines);
|
|
19104
|
+
return newLines;
|
|
19105
|
+
}
|
|
19105
19106
|
function axisAlignCorr(lines, option, verticalReferenceLine) {
|
|
19106
19107
|
verticalReferenceLine = verticalReferenceLine ?? findVerticalReference(lines.filter((line) => !line.userData.isDoor));
|
|
19107
19108
|
if (verticalReferenceLine) {
|
|
19108
19109
|
const t2 = performance.now();
|
|
19109
|
-
const lineSegments =
|
|
19110
|
+
const lineSegments = correction(lines, verticalReferenceLine, option);
|
|
19110
19111
|
console.log("垂直纠正总消耗时间:", (performance.now() - t2).toFixed(2), "ms", "处理线段数量:", lines.length);
|
|
19111
19112
|
return lineSegments;
|
|
19112
19113
|
} else {
|
|
@@ -19294,7 +19295,7 @@ function stepElimination(lineSegments, findMinWidth = 0.1, onMerge) {
|
|
|
19294
19295
|
let parallel2 = new PvgList();
|
|
19295
19296
|
for (let i = 0; i < intersList.length; i++) {
|
|
19296
19297
|
const res = intersList[i];
|
|
19297
|
-
if (line.isPerpendicularTo(res.userData)) {
|
|
19298
|
+
if (line.isPerpendicularTo(res.userData, 5)) {
|
|
19298
19299
|
count++;
|
|
19299
19300
|
firstLine = res.userData;
|
|
19300
19301
|
firstPoint = res.point;
|
|
@@ -19397,9 +19398,6 @@ function stepEliminationMerge(target, _, source, oldLine) {
|
|
|
19397
19398
|
function linesSmoothing(lines, _) {
|
|
19398
19399
|
repetitiveTask(2, () => lines = stepElimination(lines, 0.1, stepEliminationMerge));
|
|
19399
19400
|
WallInsertObject.recomputed(lines);
|
|
19400
|
-
TEST = true;
|
|
19401
|
-
lines = stepElimination(lines, 0.1, stepEliminationMerge);
|
|
19402
|
-
TEST = false;
|
|
19403
19401
|
return lines;
|
|
19404
19402
|
}
|
|
19405
19403
|
const PRE_PROCESSOR = {
|
|
@@ -21950,7 +21948,6 @@ const index$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePrope
|
|
|
21950
21948
|
Side,
|
|
21951
21949
|
UndirectedGraph,
|
|
21952
21950
|
UnionFindSet,
|
|
21953
|
-
axisAlignCorr: axisAlignCorr$1,
|
|
21954
21951
|
buildBayWindowGroup,
|
|
21955
21952
|
buildDoubleWallGroup,
|
|
21956
21953
|
buildDoubleWallGroup_,
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import { LineSegment } from '../../../../algorithmsStructures/LineSegment';
|
|
2
|
-
import {
|
|
2
|
+
import { SetDataOption, LineUserData } from '../../../type';
|
|
3
|
+
/**
|
|
4
|
+
* 门的障碍物清理
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* 轴对齐垂直修正
|
|
8
|
+
* @param lines 待调整线段组
|
|
9
|
+
* @param targettLine 轴线段
|
|
10
|
+
* @returns
|
|
11
|
+
*/
|
|
12
|
+
export declare function correction(lines: LineSegment<LineUserData>[], targettLine: LineSegment<LineUserData>, option?: SetDataOption): LineSegment<any>[];
|
|
3
13
|
/** 轴对齐垂直纠正
|
|
4
14
|
* @param lines
|
|
5
15
|
* @param option
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { LineSegment } from '../../../algorithmsStructures/LineSegment';
|
|
2
|
-
import { SetDataOption, LineUserData } from '../../type';
|
|
3
|
-
/**
|
|
4
|
-
* 门的障碍物清理
|
|
5
|
-
*/
|
|
6
|
-
/**
|
|
7
|
-
* 轴对齐垂直修正
|
|
8
|
-
* @param lines 待调整线段组
|
|
9
|
-
* @param targettLine 轴线段
|
|
10
|
-
* @returns
|
|
11
|
-
*/
|
|
12
|
-
export declare function axisAlignCorr(lines: LineSegment<LineUserData>[], targettLine: LineSegment<LineUserData>, option?: SetDataOption): LineSegment<any>[];
|