build-dxf 0.1.56 → 0.1.58

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.56",
3
+ "version": "0.1.58",
4
4
  "description": "线段构建双线墙壁的dxf版本",
5
5
  "main": "./src/index.js",
6
6
  "types": "./src/index.d.ts",
package/src/build.js CHANGED
@@ -2223,8 +2223,8 @@ class LineSegment {
2223
2223
  for (const line of lines) {
2224
2224
  const p1 = line.start;
2225
2225
  const p2 = line.end;
2226
- const key1 = `${p1.x.toFixed(2)}_${p1.y.toFixed(2)}`;
2227
- const key2 = `${p2.x.toFixed(2)}_${p2.y.toFixed(2)}`;
2226
+ const key1 = `${p1.x.toFixed(4)}_${p1.y.toFixed(4)}`;
2227
+ const key2 = `${p2.x.toFixed(4)}_${p2.y.toFixed(4)}`;
2228
2228
  const key = key1 < key2 ? `${key1}_${key2}` : `${key2}_${key1}`;
2229
2229
  if (!seen.has(key)) {
2230
2230
  seen.add(key);
@@ -2660,6 +2660,7 @@ class Point {
2660
2660
  * @returns
2661
2661
  */
2662
2662
  static from(arr) {
2663
+ if (!arr) return new Point();
2663
2664
  if (Array.isArray(arr)) {
2664
2665
  return new Point(arr[0], arr[1]);
2665
2666
  } else if ("x" in arr && "y" in arr) {
@@ -2667,7 +2668,7 @@ class Point {
2667
2668
  } else if ("X" in arr && "Y" in arr) {
2668
2669
  return new Point(arr.X, arr.Y);
2669
2670
  }
2670
- return this.zero();
2671
+ return new Point();
2671
2672
  }
2672
2673
  static fromByList(arr) {
2673
2674
  return arr.map((item) => Point.from(item));
@@ -4883,19 +4884,35 @@ class Polygon extends Array {
4883
4884
  this.forEach((p2) => p2.multiplyScalar(scale2));
4884
4885
  return this;
4885
4886
  }
4887
+ round() {
4888
+ this.forEach((p2) => {
4889
+ p2.x = Math.round(p2.x);
4890
+ p2.y = Math.round(p2.y);
4891
+ });
4892
+ return this;
4893
+ }
4886
4894
  /**
4887
4895
  * @param polygon
4888
4896
  */
4889
- union(polygon2) {
4890
- const clipper = new ClipperLib.Clipper();
4891
- clipper.StrictlySimple = true;
4892
- clipper.AddPath(this, ClipperLib.PolyType.ptSubject, true);
4893
- clipper.AddPath(polygon2, ClipperLib.PolyType.ptClip, true);
4894
- let solutions = [];
4895
- clipper.Execute(ClipperLib.ClipType.ctUnion, solutions, ClipperLib.PolyFillType.pftEvenOdd, ClipperLib.PolyFillType.pftEvenOdd);
4896
- if (solutions.length > 1) return false;
4897
- const points = solutions.map((path) => path.map((p2) => Point.from(p2)));
4898
- this.set(points[0]);
4897
+ union(polygons, scale2 = 1) {
4898
+ polygons = Polygon.booleanOp(this, polygons, {
4899
+ scale: scale2,
4900
+ type: "Union"
4901
+ });
4902
+ if (polygons.length !== 1) return false;
4903
+ this.set(polygons[0]);
4904
+ return true;
4905
+ }
4906
+ /** 差集
4907
+ * @param polygon
4908
+ */
4909
+ difference(polygons, scale2 = 1) {
4910
+ polygons = Polygon.booleanOp(this, polygons, {
4911
+ scale: scale2,
4912
+ type: "Difference"
4913
+ });
4914
+ if (polygons.length !== 1) return false;
4915
+ this.set(polygons[0]);
4899
4916
  return true;
4900
4917
  }
4901
4918
  /** 拆分为凸包
@@ -4936,6 +4953,10 @@ class Polygon extends Array {
4936
4953
  }
4937
4954
  return this;
4938
4955
  }
4956
+ clone() {
4957
+ const polygon2 = new Polygon([...this].map((p2) => p2.clone()));
4958
+ return polygon2;
4959
+ }
4939
4960
  /** 通过线段创建, 默认路径只有一条
4940
4961
  * @param lines
4941
4962
  * @returns
@@ -5023,6 +5044,53 @@ class Polygon extends Array {
5023
5044
  }
5024
5045
  return polygon2;
5025
5046
  }
5047
+ /**
5048
+ * @param poly
5049
+ */
5050
+ static ensureCCW(poly) {
5051
+ if (!ClipperLib.Clipper.Orientation(poly)) poly.reverse();
5052
+ }
5053
+ /** 布尔运算
5054
+ * @param subject
5055
+ * @param polygons
5056
+ * @param scale 数据缩放
5057
+ * @returns
5058
+ */
5059
+ static booleanOp(subject, clips, opt) {
5060
+ const { type = "Union", subjectFillType = "NonZero", clipFillType = "NonZero", scale: scale2 = 100 } = opt;
5061
+ if (subject instanceof Polygon) subject = [subject];
5062
+ if (clips instanceof Polygon) clips = [clips];
5063
+ subject = subject.map((subject2) => subject2.clone().scale(scale2).round());
5064
+ clips = clips.map((clips2) => clips2.clone().scale(scale2).round());
5065
+ const clipper = new ClipperLib.Clipper();
5066
+ clipper.StrictlySimple = true;
5067
+ clipper.PreserveCollinear = true;
5068
+ subject = subject.map((p2) => {
5069
+ p2 = ClipperLib.Clipper.CleanPolygon(p2, 0.5 * scale2 / 100);
5070
+ Polygon.ensureCCW(p2);
5071
+ return p2;
5072
+ });
5073
+ clips = clips.map((p2) => {
5074
+ p2 = ClipperLib.Clipper.CleanPolygon(p2, 0.5 * scale2 / 100);
5075
+ Polygon.ensureCCW(p2);
5076
+ return p2;
5077
+ });
5078
+ clipper.AddPaths(subject, ClipperLib.PolyType.ptSubject, true);
5079
+ clipper.AddPaths(clips, ClipperLib.PolyType.ptClip, true);
5080
+ let solutions = [];
5081
+ clipper.Execute(
5082
+ ClipperLib.ClipType["ct" + type],
5083
+ solutions,
5084
+ ClipperLib.PolyFillType["pft" + subjectFillType],
5085
+ ClipperLib.PolyFillType["pft" + clipFillType]
5086
+ );
5087
+ const inv = 1 / scale2;
5088
+ const results = solutions.map((solution) => {
5089
+ solution = solution.map((p2) => new Point(p2.X * inv, p2.Y * inv));
5090
+ return new Polygon(solution);
5091
+ }).filter((poly) => Math.abs(poly.area()) > 0.01);
5092
+ return results;
5093
+ }
5026
5094
  }
5027
5095
  async function include(path, exportDefault = true) {
5028
5096
  if (typeof global !== "undefined" && typeof require !== "undefined") {
@@ -5464,11 +5532,41 @@ function getLineIndexByCenter(targetLines, lines) {
5464
5532
  });
5465
5533
  return indices;
5466
5534
  }
5535
+ function lazy(fn2) {
5536
+ let cached = false;
5537
+ let value;
5538
+ let type;
5539
+ return Object.freeze({
5540
+ get isValueCreated() {
5541
+ return cached;
5542
+ },
5543
+ get value() {
5544
+ if (!cached) {
5545
+ value = fn2();
5546
+ cached = true;
5547
+ }
5548
+ return value;
5549
+ },
5550
+ get cachedValue() {
5551
+ return cached ? value : void 0;
5552
+ },
5553
+ get valueType() {
5554
+ if (type === void 0) type = typeof this.value;
5555
+ return type;
5556
+ },
5557
+ reset() {
5558
+ cached = false;
5559
+ type = void 0;
5560
+ value = void 0;
5561
+ }
5562
+ });
5563
+ }
5467
5564
  const tools = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
5468
5565
  __proto__: null,
5469
5566
  createPointVirtualGrid,
5470
5567
  createQuadtree,
5471
5568
  getLineIndexByCenter,
5569
+ lazy,
5472
5570
  mToMm,
5473
5571
  mmTom
5474
5572
  }, Symbol.toStringTag, { value: "Module" }));
@@ -6981,7 +7079,7 @@ function migration(newLine, oldLine) {
6981
7079
  });
6982
7080
  }
6983
7081
  }
6984
- function lineSegmentClipping(lines, minLen = 0.03) {
7082
+ function lineSegmentClipping(lines, minLen = 0.03, dedup = true) {
6985
7083
  const quadtree = new Quadtree(Box2.fromByLineSegment(...lines));
6986
7084
  lines.forEach((line) => quadtree.insert({ line, userData: void 0 }));
6987
7085
  const result = lines.flatMap((line) => {
@@ -7014,7 +7112,7 @@ function lineSegmentClipping(lines, minLen = 0.03) {
7014
7112
  return line;
7015
7113
  }).filter((line) => line.length() >= minLen);
7016
7114
  quadtree.clear();
7017
- return LineSegment.deduplication(result);
7115
+ return dedup ? LineSegment.deduplication(result) : result;
7018
7116
  }
7019
7117
  class DoubleWallHelper {
7020
7118
  static errorAngle = 4;
@@ -16537,23 +16635,41 @@ class SceneAutoGenerat {
16537
16635
  child.updateWorldMatrix(false, false);
16538
16636
  });
16539
16637
  }
16638
+ createGeometryByLines(lines) {
16639
+ const shape = new THREE.Shape();
16640
+ Polygon.fromByLinePath(lines, polygon);
16641
+ polygon.forEach((p2, i) => i === 0 ? shape.moveTo(p2.x, p2.y) : shape.lineTo(p2.x, p2.y));
16642
+ shape.closePath();
16643
+ const geometry = new THREE.ShapeGeometry(shape);
16644
+ return geometry;
16645
+ }
16540
16646
  buildPlane(lines) {
16541
16647
  lines = lineSegmentClipping(lines, 0);
16542
- const removeSet = findDiscretePointLine2(lines, null, true);
16543
- lines = lines.filter((line) => !removeSet.has(line) && !line.userData.isBayWindow);
16544
- const doors = lines.filter((line) => line.userData.isDoor);
16545
- const maxiCircles2 = new MaxiCircles(), { circles } = maxiCircles2.miniCircle(lines, { circleEdges: doors, side: Side.IN });
16546
- circles.forEach((circle, i) => {
16547
- const shape = new THREE.Shape();
16548
- Polygon.fromByLinePath(circle, polygon);
16549
- polygon.forEach((p2, i2) => i2 === 0 ? shape.moveTo(p2.x, p2.y) : shape.lineTo(p2.x, p2.y));
16550
- shape.closePath();
16551
- const geometry = new THREE.ShapeGeometry(shape);
16552
- const mesh = new THREE.Mesh(geometry, new THREE.MeshStandardMaterial({ color: 11184810, side: THREE.DoubleSide }));
16553
- mesh.position.z = this.z;
16554
- mesh.name = `平面_${i}`;
16555
- mesh.userData.category = "plane";
16556
- this.scene.add(mesh);
16648
+ LineSegment.groupByPath(lines).forEach((lines2, i) => {
16649
+ const removeSet = findDiscretePointLine2(lines2, null, true);
16650
+ lines2 = lines2.filter((line) => !removeSet.has(line) && !line.userData.isBayWindow);
16651
+ const doors = lines2.filter((line) => line.userData.isDoor), maxiCircles2 = new MaxiCircles(), { circles } = maxiCircles2.miniCircle(lines2, { circleEdges: doors, side: Side.IN }), { circles: outCircles } = maxiCircles2.miniCircle(lines2, { circleEdges: doors, side: Side.OUT }), ploys = circles.map(((p2) => Polygon.fromByLinePath(p2)));
16652
+ outCircles.forEach((circle) => {
16653
+ const polygon2 = Polygon.fromByLinePath(circle);
16654
+ const newPolys = Polygon.booleanOp(polygon2, ploys, { scale: 100, type: "Difference" });
16655
+ newPolys.forEach((poly, j) => {
16656
+ const geometry = this.createGeometryByLines(poly.toLines());
16657
+ const mesh = new THREE.Mesh(geometry, new THREE.MeshStandardMaterial({ color: 11184810, side: THREE.DoubleSide }));
16658
+ mesh.position.z = this.z;
16659
+ mesh.name = `平面_out_${i}_${j}`;
16660
+ mesh.userData.category = "plane";
16661
+ this.scene.add(mesh);
16662
+ });
16663
+ });
16664
+ circles.forEach((circle, j) => {
16665
+ const geometry = this.createGeometryByLines(circle);
16666
+ const mesh = new THREE.Mesh(geometry, new THREE.MeshStandardMaterial({ color: 11184810, side: THREE.DoubleSide }));
16667
+ mesh.position.z = this.z;
16668
+ mesh.name = `平面_${i}_${j}`;
16669
+ mesh.userData.category = "plane";
16670
+ mesh.userData.room = true;
16671
+ this.scene.add(mesh);
16672
+ });
16557
16673
  });
16558
16674
  }
16559
16675
  wallGroup = null;
@@ -19881,7 +19997,7 @@ function hasCircle(lineData, startIndex, direction) {
19881
19997
  let lines = originalDataToLineData(lineData).lineSegments;
19882
19998
  const center = lines[startIndex].center;
19883
19999
  let findlines = lineSegmentClipping(lines.map((line2) => line2.clone()), 1e-9);
19884
- let removeSet = findDiscretePointLine2(findlines, /* @__PURE__ */ new Set(), true);
20000
+ let removeSet = findDiscretePointLine2(findlines, /* @__PURE__ */ new Set(), false);
19885
20001
  findlines = findlines.filter((line2) => !removeSet.has(line2));
19886
20002
  const list = findlines.filter((line2) => line2.userData.isBayWindow && line2.isPointOnSegment(center));
19887
20003
  if (list.length === 0) return null;
@@ -19896,16 +20012,14 @@ function hasCircle(lineData, startIndex, direction) {
19896
20012
  path
19897
20013
  });
19898
20014
  if (result) {
19899
- let indices = null;
19900
- let originalDataIndices = null;
20015
+ let indices = lazy(() => getLineIndexByCenter(result, findlines).filter((i) => i > -1));
20016
+ let originalDataIndices = lazy(() => getLineIndexByCenter(result, lines).filter((i) => i > -1));
19901
20017
  return {
19902
20018
  get originalIndices() {
19903
- if (!originalDataIndices) originalDataIndices = getLineIndexByCenter(result, lines).filter((i) => i > -1);
19904
- return originalDataIndices;
20019
+ return originalDataIndices.value;
19905
20020
  },
19906
20021
  get indices() {
19907
- if (!indices) indices = getLineIndexByCenter(result, findlines).filter((i) => i > -1);
19908
- return indices;
20022
+ return indices.value;
19909
20023
  },
19910
20024
  circle: result,
19911
20025
  originalLines: lines,
@@ -11,6 +11,7 @@ export declare class SceneAutoGenerat {
11
11
  angle: number;
12
12
  constructor(lines: LineSegment[], itemList: any[], z: number, trajectory?: any);
13
13
  init(): Promise<void>;
14
+ private createGeometryByLines;
14
15
  buildPlane(lines: LineSegment<LineUserData>[]): void;
15
16
  wallGroup: Group | null;
16
17
  /** 构建墙壁
@@ -5,4 +5,4 @@ import { LineUserData } from '../type';
5
5
  * @param minLen
6
6
  * @returns
7
7
  */
8
- export declare function lineSegmentClipping(lines: LineSegment<LineUserData>[], minLen?: number): LineSegment<Record<string, any>>[];
8
+ export declare function lineSegmentClipping(lines: LineSegment<LineUserData>[], minLen?: number, dedup?: boolean): LineSegment<Record<string, any>>[] | LineSegment<LineUserData>[];
@@ -8,3 +8,13 @@ export declare function createQuadtree<T = any>(lines: LineSegment<T>[]): Quadtr
8
8
  export declare function mToMm(value: number): number;
9
9
  export declare function mmTom(value: number): number;
10
10
  export declare function getLineIndexByCenter(targetLines: LineSegment[], lines: LineSegment[]): number[];
11
+ type JSValueType = "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function";
12
+ export interface Lazy<T> {
13
+ readonly value: T;
14
+ readonly cachedValue: T | undefined;
15
+ readonly isValueCreated: boolean;
16
+ readonly valueType: JSValueType;
17
+ reset(): void;
18
+ }
19
+ export declare function lazy<T>(fn: () => T): Lazy<T>;
20
+ export {};
@@ -1,6 +1,14 @@
1
1
  import { Box2 } from './Box2';
2
2
  import { LineSegment } from './LineSegment';
3
3
  import { Point } from './Point';
4
+ type BooleanOpType = "Union" | "Intersection" | "Difference" | "Xor";
5
+ type FillType = "EvenOdd" | "NonZero" | "Positive" | "Negative";
6
+ type BooleanOpOption = {
7
+ type: BooleanOpType;
8
+ scale: number;
9
+ subjectFillType?: FillType;
10
+ clipFillType?: FillType;
11
+ };
4
12
  export declare class Polygon<T = any> extends Array<Point<T>> {
5
13
  [Symbol.iterator](): ArrayIterator<Point<T>>;
6
14
  constructor(points?: Point<T>[]);
@@ -55,10 +63,15 @@ export declare class Polygon<T = any> extends Array<Point<T>> {
55
63
  * @param scale
56
64
  */
57
65
  scale(scale?: number): this;
66
+ round(): this;
58
67
  /**
59
68
  * @param polygon
60
69
  */
61
- union(polygon: Polygon): boolean;
70
+ union(polygons: Polygon | Polygon[], scale?: number): boolean;
71
+ /** 差集
72
+ * @param polygon
73
+ */
74
+ difference(polygons: Polygon | Polygon[], scale?: number): boolean;
62
75
  /** 拆分为凸包
63
76
  * @returns
64
77
  */
@@ -70,6 +83,7 @@ export declare class Polygon<T = any> extends Array<Point<T>> {
70
83
  toLines(closed?: boolean): LineSegment<Record<string, any>>[];
71
84
  toArrays(): [number, number][];
72
85
  close(): this;
86
+ clone(): Polygon<Record<string, any>>;
73
87
  /** 通过线段创建, 默认路径只有一条
74
88
  * @param lines
75
89
  * @returns
@@ -92,4 +106,16 @@ export declare class Polygon<T = any> extends Array<Point<T>> {
92
106
  * @returns
93
107
  */
94
108
  static fromByLinePath(lines: LineSegment[], polygon?: Polygon<any>): Polygon<any>;
109
+ /**
110
+ * @param poly
111
+ */
112
+ static ensureCCW(poly: Polygon): void;
113
+ /** 布尔运算
114
+ * @param subject
115
+ * @param polygons
116
+ * @param scale 数据缩放
117
+ * @returns
118
+ */
119
+ static booleanOp(subject: Polygon | Polygon[], clips: Polygon | Polygon[], opt: BooleanOpOption): Polygon<Record<string, any>>[];
95
120
  }
121
+ export {};