build-dxf 0.1.85 → 0.1.86

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "build-dxf",
3
- "version": "0.1.85",
3
+ "version": "0.1.86",
4
4
  "description": "线段构建双线墙壁的dxf版本",
5
5
  "main": "./src/index.js",
6
6
  "types": "./src/index.d.ts",
package/src/build.js CHANGED
@@ -1573,7 +1573,7 @@ class LineSegment {
1573
1573
  * @param errAngle
1574
1574
  * @returns
1575
1575
  */
1576
- isPerpendicularTo(line, eps = 0.1) {
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" });
@@ -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) => {
@@ -8308,530 +8309,178 @@ class DxfDataPlugin extends Pipeline {
8308
8309
  DxfDataPlugin.initData(cad, this.lines);
8309
8310
  }
8310
8311
  }
8311
- class LineQueryer {
8312
- pointVirtualGrid;
8313
- quadtree;
8314
- constructor(lines) {
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
- queryNearestPoint(point2, opt) {
8334
- if (!point2) throw new Error("请传入查询点");
8335
- const { resultIndex = 0, radius = 0.4, condition } = opt ?? {};
8336
- const results = this.pointVirtualGrid.queryCircle(point2, radius).filter((item) => item.point !== point2).filter((item) => condition ? condition(item) : true);
8337
- results.sort((a2, b4) => a2.point.distance(point2, true) - b4.point.distance(point2, true));
8338
- if (results.length > resultIndex) return {
8339
- point: results[resultIndex].point,
8340
- line: results[resultIndex].userData
8341
- };
8342
- return null;
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 point
8346
- * @param radius
8347
- * @param opt
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
- queryNearestLine(point2, opt) {
8351
- if (!point2) throw new Error("请传入查询点");
8352
- const { resultIndex = 0, radius = 0.4, condition } = opt ?? {};
8353
- const results = this.quadtree.queryCircle(point2, radius).map((item) => {
8354
- const projPoint = item.line.projectPoint(point2, false);
8355
- if (projPoint && (!condition || condition(item, projPoint))) {
8356
- if (projPoint) return {
8357
- ...item,
8358
- distance: projPoint.distance(point2) ?? Infinity,
8359
- projPoint
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
- function parallel(line, baseline) {
8373
- const currentAngle = Math.atan2(line.end.y - line.start.y, line.end.x - line.start.x);
8374
- const targetAngle = Math.atan2(baseline.end.y - baseline.start.y, baseline.end.x - baseline.start.x);
8375
- let diff = targetAngle - currentAngle;
8376
- while (diff > Math.PI) diff -= 2 * Math.PI;
8377
- while (diff < -Math.PI) diff += 2 * Math.PI;
8378
- const center = line.center;
8379
- line.start.rotate(center, diff);
8380
- line.end.rotate(center, diff);
8381
- if (Math.abs(diff) > Math.PI / 2) line.swapValue();
8382
- return line;
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
- function vertical(line, baseline) {
8385
- const currentAngle = Math.atan2(line.end.y - line.start.y, line.end.x - line.start.x);
8386
- const targetAngle = Math.atan2(baseline.end.y - baseline.start.y, baseline.end.x - baseline.start.x);
8387
- let diff1 = targetAngle + Math.PI / 2 - currentAngle;
8388
- let diff2 = targetAngle - Math.PI / 2 - currentAngle;
8389
- while (diff1 > Math.PI) diff1 -= 2 * Math.PI;
8390
- while (diff1 < -Math.PI) diff1 += 2 * Math.PI;
8391
- while (diff2 > Math.PI) diff2 -= 2 * Math.PI;
8392
- while (diff2 < -Math.PI) diff2 += 2 * Math.PI;
8393
- const diff = Math.abs(diff1) < Math.abs(diff2) ? diff1 : diff2;
8394
- const center = line.center;
8395
- line.start.rotate(center, diff);
8396
- line.end.rotate(center, diff);
8397
- if (Math.abs(diff) > Math.PI / 2) line.swapValue();
8398
- return line;
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
- class AxisAlignCorr {
8401
- static start(lines, targettLine) {
8402
- return new AxisAlignCorr(lines, targettLine).start();
8403
- }
8404
- lines;
8405
- baseline;
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 maxAngle 找到的门线与原来的之间最大夹角
19021
- * @returns
18926
+ * @param errAngle
19022
18927
  */
19023
- adsorpt(dock, line, maxAngle = 70) {
19024
- const length = line.length(), targetDirect = dock.dockLine.getAnotherPoint(dock.dockPoint).directionFrom(dock.dockPoint);
19025
- dock.point.copy(dock.dockPoint);
19026
- const list = this.grid.queryCircle(dock.point, length * 2, true).map((item) => {
19027
- return { ...item };
19028
- }).filter((item) => item.userData !== dock.dockLine).filter((item) => {
19029
- return this.grid.queryPoint(item.point, true).length === 0;
19030
- }).filter((item) => {
19031
- const d1 = item.point.directionFrom(dock.point);
19032
- return d1.angleBetween(targetDirect, "angle") > 70;
19033
- }).filter((item) => {
19034
- 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));
19035
- return d1.angleBetween(d2, "angle") < maxAngle && d3.angleBetween(d2, "angle") < maxAngle;
19036
- }).filter((item) => {
19037
- const queryLine = new LineSegment(item.point.clone(), dock.point.clone());
19038
- queryLine.startShrink(0.01).endShrink(1e-3);
19039
- return this.quadtree.queryLineSegment(queryLine).length === 0;
19040
- }).filter((item) => {
19041
- return item.point.distance(dock.point) / length > 0.5;
19042
- }).filter((item) => {
19043
- 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);
19044
- const normalLine = new LineSegment(
19045
- center,
19046
- center.clone().add(normal.clone().multiplyScalar(length2))
19047
- );
19048
- normalLine.translate(-length2 * 0.5, normal);
19049
- const results = this.quadtree.queryLineSegment(normalLine).filter((result) => result.line !== line && result.line !== dock.dockLine);
19050
- return results.length === 0;
19051
- }).sort((a2, b4) => {
19052
- return getWeight(b4, dock, length) - getWeight(a2, dock, length);
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 (list.length) {
19055
- const line2 = list[0].userData;
19056
- let point2 = list[0].point;
19057
- if (dock.dockLine.isPerpendicularTo(line2, 25)) {
19058
- const p2 = line2.projectPoint(dock.point, true);
19059
- if (p2) point2 = p2;
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
- extendLink(dock, line) {
19066
- const length = line.length();
19067
- const direct = dock.dockPoint.directionFrom(dock.dockLine.getAnotherPoint(dock.dockPoint)), queryLine = new LineSegment(
19068
- dock.dockPoint,
19069
- dock.dockPoint.clone().add(direct.multiplyScalar(length * 2))
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
- getLines() {
19095
- return this.lines.filter((line) => {
19096
- if (line.userData.isDoor && line.length() < 0.4) return false;
19097
- return true;
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
- function init(lines, option) {
19102
- buildDoubleWallGroup.setTrajectory(option.trajectory);
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 = axisAlignCorr$1(lines, verticalReferenceLine, option);
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,4 +1,3 @@
1
- export * from './lineHandle/AxisAlignCorr';
2
1
  export * from './lineHandle/BoundExt';
3
2
  export * from './lineHandle/lineSegmentClipping';
4
3
  export * from './lineHandle/DoubleWallHelper';
@@ -1,5 +1,15 @@
1
1
  import { LineSegment } from '../../../../algorithmsStructures/LineSegment';
2
- import { LineUserData, SetDataOption } from '../../../type';
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>[];