build-dxf 0.1.84 → 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.84",
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
@@ -1562,19 +1562,21 @@ class LineSegment {
1562
1562
  * 两条线段或角度是否平行,忽略方向
1563
1563
  * @param line
1564
1564
  */
1565
- isParallelTo(angle, eps = 1) {
1566
- if (angle instanceof LineSegment) return this.isParallelTo(this.includedAngle(angle), eps);
1567
- if (typeof angle !== "number") angle = Number(angle);
1568
- return angle < eps || angle > 180 - eps;
1565
+ isParallelTo(line, eps = 1) {
1566
+ const d1 = this.direction();
1567
+ const d2 = line.direction();
1568
+ const angle = d1.angle(d2, { unit: "degree", range: "180" });
1569
+ return Math.min(angle, 180 - angle) < eps;
1569
1570
  }
1570
1571
  /** 两条线段或角度是否 垂直, 忽略方向
1571
1572
  * @param line
1572
1573
  * @param errAngle
1573
1574
  * @returns
1574
1575
  */
1575
- isPerpendicularTo(angle, eps = 0.1) {
1576
- if (angle instanceof LineSegment) return this.isPerpendicularTo(this.includedAngle(angle), eps);
1577
- if (typeof angle !== "number") angle = Number(angle);
1576
+ isPerpendicularTo(line, eps = 1) {
1577
+ const d1 = this.direction();
1578
+ const d2 = line.direction();
1579
+ const angle = d1.angle(d2, { unit: "degree", range: "180" });
1578
1580
  return Math.abs(angle - 90) < eps;
1579
1581
  }
1580
1582
  /**
@@ -2286,6 +2288,7 @@ class LineSegment {
2286
2288
  };
2287
2289
  }
2288
2290
  }
2291
+ const PRECISION = 1e-6;
2289
2292
  class Point {
2290
2293
  x;
2291
2294
  y;
@@ -2428,6 +2431,14 @@ class Point {
2428
2431
  this.y = Number(this.y.toFixed(count));
2429
2432
  return this;
2430
2433
  }
2434
+ /** 精度处理
2435
+ * @returns
2436
+ */
2437
+ precision() {
2438
+ this.x = Math.round(this.x / PRECISION) * PRECISION;
2439
+ this.y = Math.round(this.y / PRECISION) * PRECISION;
2440
+ return this;
2441
+ }
2431
2442
  /**
2432
2443
  * 归一化
2433
2444
  * @description 将当前点的坐标归一化为单位向量
@@ -3310,7 +3321,7 @@ function findDiscretePointLine2(lines, lineSet, deep = false) {
3310
3321
  lines.forEach((line) => {
3311
3322
  if (lineSet.size && lineSet.has(line)) return;
3312
3323
  line.points.forEach((p2) => {
3313
- const id = p2.hashCode();
3324
+ const id = p2.hashCode(4);
3314
3325
  if (!map.has(id)) map.set(id, /* @__PURE__ */ new Set());
3315
3326
  map.get(id)?.add(line);
3316
3327
  });
@@ -6655,8 +6666,7 @@ function buildDoubleWallGroup_(lines_, clearInternalLine = false) {
6655
6666
  // peDoors,
6656
6667
  peDoubleDoors
6657
6668
  } = initData(lines_);
6658
- const { notFoundLines, circlesList } = getPeDoubleDoorCircles(otherLines, peDoubleDoors);
6659
- otherLines.push(...notFoundLines);
6669
+ const { circlesList } = getPeDoubleDoorCircles(otherLines, peDoubleDoors);
6660
6670
  let { internalEdges, circles } = maxiCircles.maxiCircles(otherLines, (circles2) => circles2.filter(isPolyHasTrajectoryPoint));
6661
6671
  const { circles: finalCircles } = maxiCircles.mergeCircles([...circlesList, ...circles], internalEdges);
6662
6672
  lines_.forEach((line) => LineGroupType.removeByTypes(line, ["doubleWall", "wall"]));
@@ -6817,7 +6827,8 @@ class DoubleWallHelper {
6817
6827
  lines = lineSegmentClipping(lines, 1e-9);
6818
6828
  quadtree.clear();
6819
6829
  lines.push(...otherLines);
6820
- return lines.filter((line) => line.length() > 1e-9);
6830
+ Point.adsorb(lines.flatMap((line) => line.points), 1e-4);
6831
+ return lines.filter((line) => line.length() > 1e-5);
6821
6832
  }
6822
6833
  /**
6823
6834
  * 创建分组
@@ -7398,6 +7409,7 @@ class ThreeVJiaJson extends Pipeline {
7398
7409
  */
7399
7410
  wallHoleHandle({ data: { lines, json } }) {
7400
7411
  lines.forEach((line) => {
7412
+ if (line.length() < 1e-4) return;
7401
7413
  let type = holeTypeMap[line.userData.type] ?? "WALL_HOLE";
7402
7414
  const hole = {
7403
7415
  id: this.index++,
@@ -7418,8 +7430,8 @@ class ThreeVJiaJson extends Pipeline {
7418
7430
  * @param param0
7419
7431
  * @returns
7420
7432
  */
7421
- balconyRailing({ data }) {
7422
- return data;
7433
+ balconyRailing({ data: { lines }, cache }) {
7434
+ cache.wallLines.push(...lines);
7423
7435
  }
7424
7436
  /** 转换
7425
7437
  * @returns
@@ -7447,7 +7459,7 @@ class ThreeVJiaJson extends Pipeline {
7447
7459
  ID: this.index++,
7448
7460
  start: line.start.toJson2D(),
7449
7461
  end: line.end.toJson2D(),
7450
- thickness: line.userData.wallWidth ? line.userData.wallWidth : 0.12,
7462
+ thickness: Math.max(line.userData.wallWidth ? line.userData.wallWidth : 0.12, 0.12),
7451
7463
  type: "LINE",
7452
7464
  isDoor: false,
7453
7465
  loadBearingWall: false,
@@ -8297,236 +8309,6 @@ class DxfDataPlugin extends Pipeline {
8297
8309
  DxfDataPlugin.initData(cad, this.lines);
8298
8310
  }
8299
8311
  }
8300
- function parallel(line, baseline) {
8301
- const currentAngle = Math.atan2(line.end.y - line.start.y, line.end.x - line.start.x);
8302
- const targetAngle = Math.atan2(baseline.end.y - baseline.start.y, baseline.end.x - baseline.start.x);
8303
- let diff = targetAngle - currentAngle;
8304
- while (diff > Math.PI) diff -= 2 * Math.PI;
8305
- while (diff < -Math.PI) diff += 2 * Math.PI;
8306
- const center = line.center;
8307
- line.start.rotate(center, diff);
8308
- line.end.rotate(center, diff);
8309
- if (Math.abs(diff) > Math.PI / 2) line.swapValue();
8310
- return line;
8311
- }
8312
- function vertical(line, baseline) {
8313
- const currentAngle = Math.atan2(line.end.y - line.start.y, line.end.x - line.start.x);
8314
- const targetAngle = Math.atan2(baseline.end.y - baseline.start.y, baseline.end.x - baseline.start.x);
8315
- let diff1 = targetAngle + Math.PI / 2 - currentAngle;
8316
- let diff2 = targetAngle - Math.PI / 2 - currentAngle;
8317
- while (diff1 > Math.PI) diff1 -= 2 * Math.PI;
8318
- while (diff1 < -Math.PI) diff1 += 2 * Math.PI;
8319
- while (diff2 > Math.PI) diff2 -= 2 * Math.PI;
8320
- while (diff2 < -Math.PI) diff2 += 2 * Math.PI;
8321
- const diff = Math.abs(diff1) < Math.abs(diff2) ? diff1 : diff2;
8322
- const center = line.center;
8323
- line.start.rotate(center, diff);
8324
- line.end.rotate(center, diff);
8325
- if (Math.abs(diff) > Math.PI / 2) line.swapValue();
8326
- return line;
8327
- }
8328
- class AxisAlignCorr {
8329
- static start(lines, targettLine) {
8330
- return new AxisAlignCorr(lines, targettLine).start();
8331
- }
8332
- lines;
8333
- baseline;
8334
- grid;
8335
- constructor(lines, baseline) {
8336
- this.lines = lines;
8337
- this.baseline = baseline;
8338
- this.grid = createPointVirtualGrid(lines);
8339
- }
8340
- visited = /* @__PURE__ */ new Set();
8341
- newLines = [];
8342
- start() {
8343
- for (let i = 0; i < this.lines.length; i++) {
8344
- const line = this.lines[i];
8345
- if (this.visited.has(line)) continue;
8346
- this.correction(line);
8347
- }
8348
- return [
8349
- ...this.lines,
8350
- ...this.newLines
8351
- ];
8352
- }
8353
- /** 添加
8354
- * @param lines
8355
- * @returns
8356
- */
8357
- addVisited(lines) {
8358
- if (lines instanceof LineSegment) lines = [lines];
8359
- lines.forEach((line) => this.visited.add(line));
8360
- return this;
8361
- }
8362
- queryPoint(point2) {
8363
- return this.grid.queryPoint(point2, true).filter((item) => !this.visited.has(item.userData));
8364
- }
8365
- /** 纠正
8366
- * @param line
8367
- * @param targettLine
8368
- */
8369
- correction(line) {
8370
- const startConnectList = this.queryPoint(line.start);
8371
- const endConnectLines = this.queryPoint(line.end);
8372
- this.rotate(line);
8373
- startConnectList.forEach(({ userData: queryLine, point: point2 }) => {
8374
- this.recursion(queryLine, point2, line, line.start);
8375
- });
8376
- endConnectLines.forEach(({ userData: queryLine, point: point2 }) => {
8377
- this.recursion(queryLine, point2, line, line.end);
8378
- });
8379
- }
8380
- /** 递归执行
8381
- * @param line
8382
- * @param enterPoint
8383
- */
8384
- recursion(line, enterPoint, nextLine, nextPoint) {
8385
- const otherPoint = line.getAnotherPoint(enterPoint);
8386
- const connectList = this.queryPoint(otherPoint);
8387
- this.rotate(line);
8388
- this.establishConnection(enterPoint, line, nextLine, nextPoint);
8389
- connectList.forEach(({ userData: queryLine, point: point2 }) => {
8390
- this.recursion(queryLine, point2, line, otherPoint);
8391
- });
8392
- }
8393
- /** 构建连接
8394
- */
8395
- establishConnection(point2, line, nextLine, nextPoint) {
8396
- if (line.isParallelTo(nextLine)) {
8397
- const interPoint2 = nextLine.projectPoint(point2, false);
8398
- const newLine = new LineSegment(point2.clone(), interPoint2?.clone() ?? nextPoint.clone());
8399
- newLine.length() > 1e-9 && this.newLines.push(newLine);
8400
- return;
8401
- }
8402
- const interPoint = nextLine.projectPoint(point2, false);
8403
- if (!interPoint) return;
8404
- point2.copy(interPoint);
8405
- if (nextLine.isPointOnSegment(interPoint)) return;
8406
- nextPoint.copy(interPoint);
8407
- }
8408
- point = new Point();
8409
- /** 旋转
8410
- * @param line
8411
- * @param errAngle
8412
- */
8413
- rotate(line, errAngle = 45) {
8414
- const baseline = this.baseline;
8415
- this.point.copy(line.start);
8416
- if (line.isParallelTo(baseline, errAngle)) parallel(line, baseline);
8417
- else vertical(line, baseline);
8418
- this.addVisited(line);
8419
- }
8420
- }
8421
- function shortDistanceLink(lines, radius = 0.1) {
8422
- const dpSet = findDiscretePoint(lines.filter((line) => !line.userData.isDoor)), pointVirtualGrid = createPointVirtualGrid(dpSet.map((v2) => v2)), appendLines = [], visited = /* @__PURE__ */ new Set();
8423
- const getWeight2 = (target, point2, line) => {
8424
- if (target.weight) return target.weight;
8425
- const targetLine = target.userData, targetPoint = target.point;
8426
- 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;
8427
- target.weight = weight;
8428
- return weight;
8429
- };
8430
- for (const [point2, line] of dpSet) {
8431
- if (line.userData.isDoor) continue;
8432
- if (visited.has(point2)) continue;
8433
- const list = pointVirtualGrid.queryCircle(point2, radius, true).map((item) => Object.assign({}, item)).filter((item) => {
8434
- const targetLine2 = item.userData, targetPoint2 = item.point, direct1 = line.getAnotherPoint(point2).directionFrom(point2), direct2 = targetLine2.getAnotherPoint(targetPoint2).directionFrom(targetPoint2), angle = direct1.angleBetween(direct2, "angle");
8435
- return angle > 90;
8436
- }).sort((a2, b4) => getWeight2(b4, point2, line) - getWeight2(a2, point2, line));
8437
- if (list.length === 0) continue;
8438
- const { point: targetPoint } = list[0];
8439
- const targetLine = list[0].userData;
8440
- visited.add(point2);
8441
- visited.add(targetPoint);
8442
- const projectLine1 = line.projectLineSegment(targetLine), projectLine2 = targetLine.projectLineSegment(line), len1 = projectLine1.length(), len2 = projectLine2.length();
8443
- if (len1 === 0 && len2 === 0) appendLines.push(new LineSegment(point2.clone(), list[0].point.clone()));
8444
- else appendLines.push(new LineSegment(projectLine1.center, projectLine2.center));
8445
- }
8446
- return [...lines, ...appendLines];
8447
- }
8448
- function preprocessing(lines) {
8449
- const pointVirtualGrid = new PointVirtualGrid(), quadtree = new Quadtree(Box2.fromByLineSegment(...lines)), doors = [];
8450
- lines.forEach((line) => {
8451
- if (line.userData.isDoor) doors.push(line);
8452
- else {
8453
- line.points.forEach((p2) => pointVirtualGrid.insert(p2, line));
8454
- quadtree.insert(line);
8455
- }
8456
- });
8457
- doors.forEach((door) => {
8458
- const startIntersection = pointVirtualGrid.queryPoint(door.start);
8459
- const endIntersection = pointVirtualGrid.queryPoint(door.end);
8460
- if (startIntersection.length) door.userData.startIntersection = startIntersection[0].userData;
8461
- else door.userData.startIntersection = quadtree.queryPoint(door.start)[0]?.line;
8462
- if (endIntersection.length) door.userData.endIntersection = endIntersection[0].userData;
8463
- else door.userData.endIntersection = quadtree.queryPoint(door.end)[0]?.line;
8464
- });
8465
- lines = shortDistanceLink(lines, 0.4);
8466
- pointVirtualGrid.clear();
8467
- quadtree.clear();
8468
- return lines;
8469
- }
8470
- function removeShortLine(lines, len = 0.01) {
8471
- let defaultLines = [], doorLines = [];
8472
- for (let i = 0; i < lines.length; i++) {
8473
- const line = lines[i];
8474
- if (line.userData.isDoor) doorLines.push(line);
8475
- else defaultLines.push(line);
8476
- }
8477
- const lineSet = findDiscretePointLine2(lines);
8478
- const grid = createPointVirtualGrid([...lineSet]);
8479
- for (let i = 0; i < doorLines.length; i++) {
8480
- const doorLine = doorLines[i];
8481
- doorLine.points.forEach((p2) => {
8482
- grid.queryPoint(p2, true).forEach((item) => lineSet.delete(item.userData));
8483
- });
8484
- }
8485
- defaultLines = defaultLines.filter((line) => !lineSet.has(line) || line.length() > len);
8486
- defaultLines = LineSegmentUndirectedGraph.breakpointMerging(defaultLines, (newLine, lines2) => {
8487
- lines2 = lines2.filter((line) => line.length() > 0);
8488
- mergeLineUserData(newLine, lines2);
8489
- newLine.userData.isBayWindow = lines2.some((line) => line.userData.isBayWindow);
8490
- });
8491
- WallInsertObject.recomputed(defaultLines);
8492
- return [...defaultLines, ...doorLines];
8493
- }
8494
- function breakpointMerging(lines) {
8495
- let defaultLines = [], doorLines = [];
8496
- for (let i = 0; i < lines.length; i++) {
8497
- const line = lines[i];
8498
- if (line.userData.isDoor) doorLines.push(line);
8499
- else defaultLines.push(line);
8500
- }
8501
- defaultLines = LineSegmentUndirectedGraph.breakpointMerging(defaultLines, mergeLineUserData);
8502
- doorLines = LineSegmentUndirectedGraph.breakpointMerging(doorLines, mergeLineUserData);
8503
- return [...defaultLines, ...doorLines];
8504
- }
8505
- function axisAlignCorr$1(lines, targettLine, option) {
8506
- lines = lines.map((line) => line.clone());
8507
- lines = breakpointMerging(lines);
8508
- lines = lineSegmentClipping(lines, 1e-9);
8509
- lines = preprocessing(lines);
8510
- lines = AxisAlignCorr.start(lines, targettLine);
8511
- lines = lineSegmentClipping(lines, 1e-9);
8512
- lines = removeShortLine(lines, 0.15);
8513
- let newLines = lines.filter((line) => !line.userData.isDoor);
8514
- let doorLines = lines.filter((line) => line.userData.isDoor);
8515
- newLines = buildBayWindowGroup(newLines, false);
8516
- const { wallGroup = true } = option ?? {};
8517
- if (wallGroup) {
8518
- newLines = DoubleWallHelper.complementSide(newLines);
8519
- WallInsertObject.recomputed(newLines);
8520
- newLines = buildDoubleWallGroup(newLines, true);
8521
- newLines = buildBayWindowGroup(newLines, false);
8522
- }
8523
- new WallInsertObject(lines).recomputed().merge();
8524
- newLines.push(...doorLines);
8525
- Point.adsorb(newLines.flatMap((line) => line.points), 1e-4);
8526
- lines = removeShortLine(lines, 0.05);
8527
- lines = breakpointMerging(lines);
8528
- return newLines;
8529
- }
8530
8312
  class BoundExt {
8531
8313
  /** 通过轨迹点查找外墙
8532
8314
  * @param lines
@@ -10231,8 +10013,8 @@ class Scenario {
10231
10013
  }
10232
10014
  windowTreatment1(dblWin, mesh, wallHeight) {
10233
10015
  const doorList = dblWin;
10234
- const MobileX = this.angleToXAxisDegrees(doorList.start.x, doorList.start.y, doorList.end.x, doorList.end.y, doorList.userData.wallWidth ? doorList.userData.wallWidth + 1e-4 : 0.5, true);
10235
- const MobileY = this.angleToXAxisDegrees(doorList.start.x, doorList.start.y, doorList.end.x, doorList.end.y, doorList.userData.wallWidth ? doorList.userData.wallWidth + 1e-4 : 0.5, false);
10016
+ const MobileX = this.angleToXAxisDegrees(doorList.start.x, doorList.start.y, doorList.end.x, doorList.end.y, doorList.userData.wallWidth ? doorList.userData.wallWidth + 1e-3 : 0.5, true);
10017
+ const MobileY = this.angleToXAxisDegrees(doorList.start.x, doorList.start.y, doorList.end.x, doorList.end.y, doorList.userData.wallWidth ? doorList.userData.wallWidth + 1e-3 : 0.5, false);
10236
10018
  let startingPoint = BayWindow.Instance.xinLine(MobileX, MobileY, doorList.start, wallHeight);
10237
10019
  let finishLine = BayWindow.Instance.xinLine(MobileX, MobileY, doorList.end, wallHeight);
10238
10020
  startingPoint.push(finishLine[1]);
@@ -10651,14 +10433,12 @@ class Scenario {
10651
10433
  xinLine1(x, y, pointa, pointb, num, wallHeight) {
10652
10434
  let point1;
10653
10435
  let point2;
10654
- let xx = x > 0 ? x + -1e-3 : 1e-3;
10655
- let yy = y > 0 ? y + -1e-3 : 1e-3;
10656
10436
  if (num === 0) {
10657
- point1 = new THREE.Vector3(pointa.x - xx, pointa.y - yy, wallHeight);
10658
- point2 = new THREE.Vector3(pointb.x - xx, pointb.y - yy, wallHeight);
10437
+ point1 = new THREE.Vector3(pointa.x - x, pointa.y - y, wallHeight);
10438
+ point2 = new THREE.Vector3(pointb.x - x, pointb.y - y, wallHeight);
10659
10439
  } else {
10660
- point1 = new THREE.Vector3(pointa.x + xx, pointa.y + yy, wallHeight);
10661
- point2 = new THREE.Vector3(pointb.x + xx, pointb.y + yy, wallHeight);
10440
+ point1 = new THREE.Vector3(pointa.x + x, pointa.y + y, wallHeight);
10441
+ point2 = new THREE.Vector3(pointb.x + x, pointb.y + y, wallHeight);
10662
10442
  }
10663
10443
  return [point1, point2];
10664
10444
  }
@@ -10888,7 +10668,6 @@ class Scenario {
10888
10668
  //
10889
10669
  createAPlane(lines, menList) {
10890
10670
  const lineList = lines;
10891
- console.log("初始数据", lines);
10892
10671
  let precision = lineList.map((pos) => {
10893
10672
  pos.start.x = parseFloat(pos.start.x.toFixed(3));
10894
10673
  pos.start.y = parseFloat(pos.start.y.toFixed(3));
@@ -18972,11 +18751,363 @@ function init(lines, option) {
18972
18751
  buildDoubleWallGroup.setTrajectory(option.trajectory);
18973
18752
  return lines;
18974
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
+ /** 旋转
18925
+ * @param line
18926
+ * @param errAngle
18927
+ */
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
+ }
19001
+ });
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);
19017
+ }
19018
+ }
19019
+ }
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
+ });
19026
+ }
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
+ }
19038
+ });
19039
+ }
19040
+ modifyManager.modify();
19041
+ lineQueryer.clear();
19042
+ Point.adsorb(lines.flatMap((line) => line.points), 1e-4, "first");
19043
+ return lines;
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
+ }
18975
19106
  function axisAlignCorr(lines, option, verticalReferenceLine) {
18976
19107
  verticalReferenceLine = verticalReferenceLine ?? findVerticalReference(lines.filter((line) => !line.userData.isDoor));
18977
19108
  if (verticalReferenceLine) {
18978
19109
  const t2 = performance.now();
18979
- const lineSegments = axisAlignCorr$1(lines, verticalReferenceLine, option);
19110
+ const lineSegments = correction(lines, verticalReferenceLine, option);
18980
19111
  console.log("垂直纠正总消耗时间:", (performance.now() - t2).toFixed(2), "ms", "处理线段数量:", lines.length);
18981
19112
  return lineSegments;
18982
19113
  } else {
@@ -19164,7 +19295,7 @@ function stepElimination(lineSegments, findMinWidth = 0.1, onMerge) {
19164
19295
  let parallel2 = new PvgList();
19165
19296
  for (let i = 0; i < intersList.length; i++) {
19166
19297
  const res = intersList[i];
19167
- if (line.isPerpendicularTo(res.userData)) {
19298
+ if (line.isPerpendicularTo(res.userData, 5)) {
19168
19299
  count++;
19169
19300
  firstLine = res.userData;
19170
19301
  firstPoint = res.point;
@@ -21817,7 +21948,6 @@ const index$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePrope
21817
21948
  Side,
21818
21949
  UndirectedGraph,
21819
21950
  UnionFindSet,
21820
- axisAlignCorr: axisAlignCorr$1,
21821
21951
  buildBayWindowGroup,
21822
21952
  buildDoubleWallGroup,
21823
21953
  buildDoubleWallGroup_,
@@ -22031,7 +22161,6 @@ async function buildJson(opt) {
22031
22161
  if (opt.axisAlignCorr !== false) {
22032
22162
  dxfSystem.Dxf.addPreProcessor(PRE_PROCESSOR.AxisAlignCorr);
22033
22163
  dxfSystem.Dxf.addPreProcessor(PRE_PROCESSOR.LinesSmoothing);
22034
- dxfSystem.Dxf.addPreProcessor(PRE_PROCESSOR.RemoveShortDoubleWall);
22035
22164
  }
22036
22165
  if (trajectory2) {
22037
22166
  if (typeof trajectory2 === "string") {
@@ -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
@@ -99,7 +99,7 @@ export declare class ThreeVJiaJson extends Pipeline<DataOption, ICache> {
99
99
  * @param param0
100
100
  * @returns
101
101
  */
102
- balconyRailing({ data }: HandlerContext<DataOption>): DataOption;
102
+ balconyRailing({ data: { lines }, cache }: HandlerContext<DataOption, ICache>): void;
103
103
  /** 转换
104
104
  * @returns
105
105
  */
@@ -139,13 +139,13 @@ export declare class LineSegment<T = Record<string, any>> {
139
139
  * 两条线段或角度是否平行,忽略方向
140
140
  * @param line
141
141
  */
142
- isParallelTo(angle: LineSegment | number, eps?: number): boolean;
142
+ isParallelTo(line: LineSegment, eps?: number): boolean;
143
143
  /** 两条线段或角度是否 垂直, 忽略方向
144
144
  * @param line
145
145
  * @param errAngle
146
146
  * @returns
147
147
  */
148
- isPerpendicularTo(angle: LineSegment | number, eps?: number): boolean;
148
+ isPerpendicularTo(line: LineSegment, eps?: number): boolean;
149
149
  /**
150
150
  * @param line
151
151
  * @param eps
@@ -73,6 +73,10 @@ export declare class Point<T = Record<string, any>> {
73
73
  * @param count
74
74
  */
75
75
  fixed(count: number): this;
76
+ /** 精度处理
77
+ * @returns
78
+ */
79
+ precision(): this;
76
80
  /**
77
81
  * 归一化
78
82
  * @description 将当前点的坐标归一化为单位向量
@@ -47,7 +47,7 @@ export default class Scenario {
47
47
  executionOffset(data: any, index: number, wallHeight: number): THREE.Mesh<THREE.ExtrudeGeometry, THREE.MeshStandardMaterial, THREE.Object3DEventMap> | null | undefined;
48
48
  windowTreatment(dblWin: any, mesh: any, wallHeight: number): Brush;
49
49
  windowTreatment1(dblWin: any, mesh: any, wallHeight: number): Brush;
50
- TheHandlingOfTheDoor1(data: LineSegment<LineUserData>): THREE.Vector3[];
50
+ TheHandlingOfTheDoor1(data: LineSegment<LineUserData>): any[];
51
51
  TheHandlingOfTheDoor(data: LineSegment<LineUserData>[]): void;
52
52
  doorCenterOffset(distanceFromB: number, point: any, pointc: THREE.Vector3): THREE.Vector3;
53
53
  installWindows(data: any, index: string): void;
@@ -60,7 +60,7 @@ export default class Scenario {
60
60
  doorHoleOpening(wallHeight: number, data: any, data1: any, groundHeight?: number, Height?: number, distance?: number, center?: THREE.Vector3, angleRad?: any, index?: string, doorList?: LineSegment): void;
61
61
  angleToXAxisDegrees(x1: number, y1: number, x2: number, y2: number, wide: number, cd: boolean): number;
62
62
  xinLine(x: number, y: number, point: THREE.Vector3 | Point, wallHeight: number): THREE.Vector3[];
63
- xinLine1(x: number, y: number, pointa: THREE.Vector3, pointb: THREE.Vector3, num: number, wallHeight: number): THREE.Vector3[];
63
+ xinLine1(x: number, y: number, pointa: THREE.Vector3, pointb: THREE.Vector3, num: number, wallHeight: number): any[];
64
64
  createParallelepipedFromBase(points: any, height: number): THREE.ExtrudeGeometry;
65
65
  correctionSorting(bitem: any): {
66
66
  dian: THREE.Vector3;
@@ -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>[];