build-dxf 0.1.56 → 0.1.57

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.57",
4
4
  "description": "线段构建双线墙壁的dxf版本",
5
5
  "main": "./src/index.js",
6
6
  "types": "./src/index.d.ts",
package/src/build.js CHANGED
@@ -4883,19 +4883,35 @@ class Polygon extends Array {
4883
4883
  this.forEach((p2) => p2.multiplyScalar(scale2));
4884
4884
  return this;
4885
4885
  }
4886
+ round() {
4887
+ this.forEach((p2) => {
4888
+ p2.x = Math.round(p2.x);
4889
+ p2.y = Math.round(p2.y);
4890
+ });
4891
+ return this;
4892
+ }
4886
4893
  /**
4887
4894
  * @param polygon
4888
4895
  */
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]);
4896
+ union(polygons, scale2 = 1) {
4897
+ polygons = Polygon.booleanOp(this, polygons, {
4898
+ scale: scale2,
4899
+ type: "Union"
4900
+ });
4901
+ if (polygons.length !== 1) return false;
4902
+ this.set(polygons[0]);
4903
+ return true;
4904
+ }
4905
+ /** 差集
4906
+ * @param polygon
4907
+ */
4908
+ difference(polygons, scale2 = 1) {
4909
+ polygons = Polygon.booleanOp(this, polygons, {
4910
+ scale: scale2,
4911
+ type: "Difference"
4912
+ });
4913
+ if (polygons.length !== 1) return false;
4914
+ this.set(polygons[0]);
4899
4915
  return true;
4900
4916
  }
4901
4917
  /** 拆分为凸包
@@ -4936,6 +4952,10 @@ class Polygon extends Array {
4936
4952
  }
4937
4953
  return this;
4938
4954
  }
4955
+ clone() {
4956
+ const polygon2 = new Polygon([...this].map((p2) => p2.clone()));
4957
+ return polygon2;
4958
+ }
4939
4959
  /** 通过线段创建, 默认路径只有一条
4940
4960
  * @param lines
4941
4961
  * @returns
@@ -5023,6 +5043,53 @@ class Polygon extends Array {
5023
5043
  }
5024
5044
  return polygon2;
5025
5045
  }
5046
+ /**
5047
+ * @param poly
5048
+ */
5049
+ static ensureCCW(poly) {
5050
+ if (!ClipperLib.Clipper.Orientation(poly)) poly.reverse();
5051
+ }
5052
+ /** 布尔运算
5053
+ * @param subject
5054
+ * @param polygons
5055
+ * @param scale 数据缩放
5056
+ * @returns
5057
+ */
5058
+ static booleanOp(subject, clips, opt) {
5059
+ const { type = "Union", subjectFillType = "NonZero", clipFillType = "NonZero", scale: scale2 = 100 } = opt;
5060
+ if (subject instanceof Polygon) subject = [subject];
5061
+ if (clips instanceof Polygon) clips = [clips];
5062
+ subject = subject.map((subject2) => subject2.clone().scale(scale2).round());
5063
+ clips = clips.map((clips2) => clips2.clone().scale(scale2).round());
5064
+ const clipper = new ClipperLib.Clipper();
5065
+ clipper.StrictlySimple = true;
5066
+ clipper.PreserveCollinear = true;
5067
+ subject = subject.map((p2) => {
5068
+ p2 = ClipperLib.Clipper.CleanPolygon(p2, 0.5 * scale2 / 100);
5069
+ Polygon.ensureCCW(p2);
5070
+ return p2;
5071
+ });
5072
+ clips = clips.map((p2) => {
5073
+ p2 = ClipperLib.Clipper.CleanPolygon(p2, 0.5 * scale2 / 100);
5074
+ Polygon.ensureCCW(p2);
5075
+ return p2;
5076
+ });
5077
+ clipper.AddPaths(subject, ClipperLib.PolyType.ptSubject, true);
5078
+ clipper.AddPaths(clips, ClipperLib.PolyType.ptClip, true);
5079
+ let solutions = [];
5080
+ clipper.Execute(
5081
+ ClipperLib.ClipType["ct" + type],
5082
+ solutions,
5083
+ ClipperLib.PolyFillType["pft" + subjectFillType],
5084
+ ClipperLib.PolyFillType["pft" + clipFillType]
5085
+ );
5086
+ const inv = 1 / scale2;
5087
+ const results = solutions.map((solution) => {
5088
+ solution = solution.map((p2) => new Point(p2.X * inv, p2.Y * inv));
5089
+ return new Polygon(solution);
5090
+ }).filter((poly) => Math.abs(poly.area()) > 0.01);
5091
+ return results;
5092
+ }
5026
5093
  }
5027
5094
  async function include(path, exportDefault = true) {
5028
5095
  if (typeof global !== "undefined" && typeof require !== "undefined") {
@@ -5464,11 +5531,41 @@ function getLineIndexByCenter(targetLines, lines) {
5464
5531
  });
5465
5532
  return indices;
5466
5533
  }
5534
+ function lazy(fn2) {
5535
+ let cached = false;
5536
+ let value;
5537
+ let type;
5538
+ return Object.freeze({
5539
+ get isValueCreated() {
5540
+ return cached;
5541
+ },
5542
+ get value() {
5543
+ if (!cached) {
5544
+ value = fn2();
5545
+ cached = true;
5546
+ }
5547
+ return value;
5548
+ },
5549
+ get cachedValue() {
5550
+ return cached ? value : void 0;
5551
+ },
5552
+ get valueType() {
5553
+ if (type === void 0) type = typeof this.value;
5554
+ return type;
5555
+ },
5556
+ reset() {
5557
+ cached = false;
5558
+ type = void 0;
5559
+ value = void 0;
5560
+ }
5561
+ });
5562
+ }
5467
5563
  const tools = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
5468
5564
  __proto__: null,
5469
5565
  createPointVirtualGrid,
5470
5566
  createQuadtree,
5471
5567
  getLineIndexByCenter,
5568
+ lazy,
5472
5569
  mToMm,
5473
5570
  mmTom
5474
5571
  }, Symbol.toStringTag, { value: "Module" }));
@@ -16537,23 +16634,41 @@ class SceneAutoGenerat {
16537
16634
  child.updateWorldMatrix(false, false);
16538
16635
  });
16539
16636
  }
16637
+ createGeometryByLines(lines) {
16638
+ const shape = new THREE.Shape();
16639
+ Polygon.fromByLinePath(lines, polygon);
16640
+ polygon.forEach((p2, i) => i === 0 ? shape.moveTo(p2.x, p2.y) : shape.lineTo(p2.x, p2.y));
16641
+ shape.closePath();
16642
+ const geometry = new THREE.ShapeGeometry(shape);
16643
+ return geometry;
16644
+ }
16540
16645
  buildPlane(lines) {
16541
16646
  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);
16647
+ LineSegment.groupByPath(lines).forEach((lines2, i) => {
16648
+ const removeSet = findDiscretePointLine2(lines2, null, true);
16649
+ lines2 = lines2.filter((line) => !removeSet.has(line) && !line.userData.isBayWindow);
16650
+ 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)));
16651
+ outCircles.forEach((circle) => {
16652
+ const polygon2 = Polygon.fromByLinePath(circle);
16653
+ const newPolys = Polygon.booleanOp(polygon2, ploys, { scale: 100, type: "Difference" });
16654
+ newPolys.forEach((poly, j) => {
16655
+ const geometry = this.createGeometryByLines(poly.toLines());
16656
+ const mesh = new THREE.Mesh(geometry, new THREE.MeshStandardMaterial({ color: 11184810, side: THREE.DoubleSide }));
16657
+ mesh.position.z = this.z;
16658
+ mesh.name = `平面_out_${i}_${j}`;
16659
+ mesh.userData.category = "plane";
16660
+ this.scene.add(mesh);
16661
+ });
16662
+ });
16663
+ circles.forEach((circle, j) => {
16664
+ const geometry = this.createGeometryByLines(circle);
16665
+ const mesh = new THREE.Mesh(geometry, new THREE.MeshStandardMaterial({ color: 11184810, side: THREE.DoubleSide }));
16666
+ mesh.position.z = this.z;
16667
+ mesh.name = `平面_${i}_${j}`;
16668
+ mesh.userData.category = "plane";
16669
+ mesh.userData.room = true;
16670
+ this.scene.add(mesh);
16671
+ });
16557
16672
  });
16558
16673
  }
16559
16674
  wallGroup = null;
@@ -19896,16 +20011,14 @@ function hasCircle(lineData, startIndex, direction) {
19896
20011
  path
19897
20012
  });
19898
20013
  if (result) {
19899
- let indices = null;
19900
- let originalDataIndices = null;
20014
+ let indices = lazy(() => getLineIndexByCenter(result, findlines).filter((i) => i > -1));
20015
+ let originalDataIndices = lazy(() => getLineIndexByCenter(result, lines).filter((i) => i > -1));
19901
20016
  return {
19902
20017
  get originalIndices() {
19903
- if (!originalDataIndices) originalDataIndices = getLineIndexByCenter(result, lines).filter((i) => i > -1);
19904
- return originalDataIndices;
20018
+ return originalDataIndices.value;
19905
20019
  },
19906
20020
  get indices() {
19907
- if (!indices) indices = getLineIndexByCenter(result, findlines).filter((i) => i > -1);
19908
- return indices;
20021
+ return indices.value;
19909
20022
  },
19910
20023
  circle: result,
19911
20024
  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
  /** 构建墙壁
@@ -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 {};