build-dxf 0.1.84 → 0.1.85

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.85",
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 = 0.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 将当前点的坐标归一化为单位向量
@@ -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,
@@ -7465,7 +7477,6 @@ class ThreeVJiaJson extends Pipeline {
7465
7477
  }
7466
7478
  }
7467
7479
  function lineDataToThreeVJiaJson(lineSegments, angle = 0, updateGroup = true) {
7468
- angle = 0;
7469
7480
  lineSegments = LineSegmentUndirectedGraph.rotate(lineSegments.map((line) => line.clone()), angle, (line, center, angle2) => {
7470
7481
  WallInsertObject.forEachInsertObjectData(line, (data) => {
7471
7482
  data.forEach((item) => {
@@ -8297,6 +8308,67 @@ class DxfDataPlugin extends Pipeline {
8297
8308
  DxfDataPlugin.initData(cad, this.lines);
8298
8309
  }
8299
8310
  }
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
8331
+ * @returns
8332
+ */
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;
8343
+ }
8344
+ /**
8345
+ * @param point
8346
+ * @param radius
8347
+ * @param opt
8348
+ * @returns
8349
+ */
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
+ };
8361
+ }
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
+ };
8369
+ return null;
8370
+ }
8371
+ }
8300
8372
  function parallel(line, baseline) {
8301
8373
  const currentAngle = Math.atan2(line.end.y - line.start.y, line.end.x - line.start.x);
8302
8374
  const targetAngle = Math.atan2(baseline.end.y - baseline.start.y, baseline.end.x - baseline.start.x);
@@ -8467,6 +8539,66 @@ function preprocessing(lines) {
8467
8539
  quadtree.clear();
8468
8540
  return lines;
8469
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
+ }
8470
8602
  function removeShortLine(lines, len = 0.01) {
8471
8603
  let defaultLines = [], doorLines = [];
8472
8604
  for (let i = 0; i < lines.length; i++) {
@@ -8508,6 +8640,7 @@ function axisAlignCorr$1(lines, targettLine, option) {
8508
8640
  lines = lineSegmentClipping(lines, 1e-9);
8509
8641
  lines = preprocessing(lines);
8510
8642
  lines = AxisAlignCorr.start(lines, targettLine);
8643
+ lines = adsorption(lines, option);
8511
8644
  lines = lineSegmentClipping(lines, 1e-9);
8512
8645
  lines = removeShortLine(lines, 0.15);
8513
8646
  let newLines = lines.filter((line) => !line.userData.isDoor);
@@ -10231,8 +10364,8 @@ class Scenario {
10231
10364
  }
10232
10365
  windowTreatment1(dblWin, mesh, wallHeight) {
10233
10366
  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);
10367
+ 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);
10368
+ 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
10369
  let startingPoint = BayWindow.Instance.xinLine(MobileX, MobileY, doorList.start, wallHeight);
10237
10370
  let finishLine = BayWindow.Instance.xinLine(MobileX, MobileY, doorList.end, wallHeight);
10238
10371
  startingPoint.push(finishLine[1]);
@@ -10651,14 +10784,12 @@ class Scenario {
10651
10784
  xinLine1(x, y, pointa, pointb, num, wallHeight) {
10652
10785
  let point1;
10653
10786
  let point2;
10654
- let xx = x > 0 ? x + -1e-3 : 1e-3;
10655
- let yy = y > 0 ? y + -1e-3 : 1e-3;
10656
10787
  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);
10788
+ point1 = new THREE.Vector3(pointa.x - x, pointa.y - y, wallHeight);
10789
+ point2 = new THREE.Vector3(pointb.x - x, pointb.y - y, wallHeight);
10659
10790
  } 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);
10791
+ point1 = new THREE.Vector3(pointa.x + x, pointa.y + y, wallHeight);
10792
+ point2 = new THREE.Vector3(pointb.x + x, pointb.y + y, wallHeight);
10662
10793
  }
10663
10794
  return [point1, point2];
10664
10795
  }
@@ -10888,7 +11019,6 @@ class Scenario {
10888
11019
  //
10889
11020
  createAPlane(lines, menList) {
10890
11021
  const lineList = lines;
10891
- console.log("初始数据", lines);
10892
11022
  let precision = lineList.map((pos) => {
10893
11023
  pos.start.x = parseFloat(pos.start.x.toFixed(3));
10894
11024
  pos.start.y = parseFloat(pos.start.y.toFixed(3));
@@ -19267,6 +19397,9 @@ function stepEliminationMerge(target, _, source, oldLine) {
19267
19397
  function linesSmoothing(lines, _) {
19268
19398
  repetitiveTask(2, () => lines = stepElimination(lines, 0.1, stepEliminationMerge));
19269
19399
  WallInsertObject.recomputed(lines);
19400
+ TEST = true;
19401
+ lines = stepElimination(lines, 0.1, stepEliminationMerge);
19402
+ TEST = false;
19270
19403
  return lines;
19271
19404
  }
19272
19405
  const PRE_PROCESSOR = {
@@ -22031,7 +22164,6 @@ async function buildJson(opt) {
22031
22164
  if (opt.axisAlignCorr !== false) {
22032
22165
  dxfSystem.Dxf.addPreProcessor(PRE_PROCESSOR.AxisAlignCorr);
22033
22166
  dxfSystem.Dxf.addPreProcessor(PRE_PROCESSOR.LinesSmoothing);
22034
- dxfSystem.Dxf.addPreProcessor(PRE_PROCESSOR.RemoveShortDoubleWall);
22035
22167
  }
22036
22168
  if (trajectory2) {
22037
22169
  if (typeof trajectory2 === "string") {
@@ -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;