build-dxf 0.1.55 → 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.55",
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.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { DxfSystem } from './utils/DxfSystem';
2
- import { OriginalDataItem, SetDataOption } from './utils/DxfSystem/type';
2
+ import { LineUserData, OriginalDataItem, SetDataOption } from './utils/DxfSystem/type';
3
3
  import { WhiteModel } from './utils/DxfSystem/plugin/ModelDataPlugin/components/WhiteModel';
4
+ import { LineSegment } from './utils';
4
5
  import * as THREE from "three";
5
6
  export { Dxf } from './utils/DxfSystem/components/Dxf';
6
7
  export * from './utils/DxfSystem/DxfSystem';
@@ -83,4 +84,10 @@ export declare function getGlobalDxfSystem(): DxfSystem | null;
83
84
  * @param direction
84
85
  * @returns
85
86
  */
86
- export declare function hasCircle(lineData: OriginalDataItem[], startIndex: number, direction: any): boolean;
87
+ export declare function hasCircle(lineData: OriginalDataItem[], startIndex: number, direction: any): {
88
+ readonly originalIndices: number[];
89
+ readonly indices: number[];
90
+ circle: LineSegment<Record<string, any>>[];
91
+ originalLines: LineSegment<LineUserData>[];
92
+ lines: LineSegment<Record<string, any>>[];
93
+ } | null;
package/src/build.js CHANGED
@@ -711,9 +711,9 @@ class Quadtree {
711
711
  * 插入线段节点
712
712
  * @param node 线段节点
713
713
  */
714
- insert(node) {
714
+ insert(node, userData) {
715
715
  if (node instanceof LineSegment) {
716
- this.insert({ line: node, userData: {} });
716
+ this.insert({ line: node, userData: userData ?? {} });
717
717
  return;
718
718
  }
719
719
  if (!this.isLeaf) {
@@ -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") {
@@ -5443,8 +5510,9 @@ function createPointVirtualGrid(lines) {
5443
5510
  }
5444
5511
  function createQuadtree(lines) {
5445
5512
  const quadtree = new Quadtree(Box2.fromByLineSegment(...lines));
5446
- for (const seg of lines) {
5447
- quadtree.insert(seg);
5513
+ for (let i = 0; i < lines.length; i++) {
5514
+ const seg = lines[i];
5515
+ quadtree.insert(seg, { index: i });
5448
5516
  }
5449
5517
  return quadtree;
5450
5518
  }
@@ -5454,10 +5522,50 @@ function mToMm(value) {
5454
5522
  function mmTom(value) {
5455
5523
  return Number((value / 1e3).toFixed(4));
5456
5524
  }
5525
+ function getLineIndexByCenter(targetLines, lines) {
5526
+ const grid = createQuadtree(lines);
5527
+ const indices = targetLines.map((line) => {
5528
+ const res = grid.queryPoint(line.center);
5529
+ if (res.length) return res[0].userData.index;
5530
+ return -1;
5531
+ });
5532
+ return indices;
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
+ }
5457
5563
  const tools = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
5458
5564
  __proto__: null,
5459
5565
  createPointVirtualGrid,
5460
5566
  createQuadtree,
5567
+ getLineIndexByCenter,
5568
+ lazy,
5461
5569
  mToMm,
5462
5570
  mmTom
5463
5571
  }, Symbol.toStringTag, { value: "Module" }));
@@ -16526,23 +16634,41 @@ class SceneAutoGenerat {
16526
16634
  child.updateWorldMatrix(false, false);
16527
16635
  });
16528
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
+ }
16529
16645
  buildPlane(lines) {
16530
16646
  lines = lineSegmentClipping(lines, 0);
16531
- const removeSet = findDiscretePointLine2(lines, null, true);
16532
- lines = lines.filter((line) => !removeSet.has(line) && !line.userData.isBayWindow);
16533
- const doors = lines.filter((line) => line.userData.isDoor);
16534
- const maxiCircles2 = new MaxiCircles(), { circles } = maxiCircles2.miniCircle(lines, { circleEdges: doors, side: Side.IN });
16535
- circles.forEach((circle, i) => {
16536
- const shape = new THREE.Shape();
16537
- Polygon.fromByLinePath(circle, polygon);
16538
- polygon.forEach((p2, i2) => i2 === 0 ? shape.moveTo(p2.x, p2.y) : shape.lineTo(p2.x, p2.y));
16539
- shape.closePath();
16540
- const geometry = new THREE.ShapeGeometry(shape);
16541
- const mesh = new THREE.Mesh(geometry, new THREE.MeshStandardMaterial({ color: 11184810, side: THREE.DoubleSide }));
16542
- mesh.position.z = this.z;
16543
- mesh.name = `平面_${i}`;
16544
- mesh.userData.category = "plane";
16545
- 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
+ });
16546
16672
  });
16547
16673
  }
16548
16674
  wallGroup = null;
@@ -19869,22 +19995,37 @@ function getGlobalDxfSystem() {
19869
19995
  function hasCircle(lineData, startIndex, direction) {
19870
19996
  let lines = originalDataToLineData(lineData).lineSegments;
19871
19997
  const center = lines[startIndex].center;
19872
- lines = lineSegmentClipping(lines, 1e-9);
19873
- let removeSet = findDiscretePointLine2(lines, /* @__PURE__ */ new Set(), true);
19874
- lines = lines.filter((line2) => !removeSet.has(line2));
19875
- const list = lines.filter((line2) => line2.userData.isBayWindow && line2.isPointOnSegment(center));
19876
- if (list.length === 0) return false;
19998
+ let findlines = lineSegmentClipping(lines.map((line2) => line2.clone()), 1e-9);
19999
+ let removeSet = findDiscretePointLine2(findlines, /* @__PURE__ */ new Set(), true);
20000
+ findlines = findlines.filter((line2) => !removeSet.has(line2));
20001
+ const list = findlines.filter((line2) => line2.userData.isBayWindow && line2.isPointOnSegment(center));
20002
+ if (list.length === 0) return null;
19877
20003
  const miniCircles = new MiniCircles(), line = list[0], direct = Point.from(direction), entity = line.center.add(direct.multiplyScalar(1e-8)), path = /* @__PURE__ */ new Set([line]);
19878
20004
  const result = miniCircles.findSameSidePath({
19879
20005
  line,
19880
20006
  currentPoint: line.start,
19881
20007
  exitPoint: line.start,
19882
20008
  entity: entity.clone(),
19883
- grid: lines,
20009
+ grid: findlines,
19884
20010
  side: Side.IN,
19885
20011
  path
19886
20012
  });
19887
- return !!result;
20013
+ if (result) {
20014
+ let indices = lazy(() => getLineIndexByCenter(result, findlines).filter((i) => i > -1));
20015
+ let originalDataIndices = lazy(() => getLineIndexByCenter(result, lines).filter((i) => i > -1));
20016
+ return {
20017
+ get originalIndices() {
20018
+ return originalDataIndices.value;
20019
+ },
20020
+ get indices() {
20021
+ return indices.value;
20022
+ },
20023
+ circle: result,
20024
+ originalLines: lines,
20025
+ lines: findlines
20026
+ };
20027
+ }
20028
+ return null;
19888
20029
  }
19889
20030
  export {
19890
20031
  ArrayMap as A,
@@ -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
  /** 构建墙壁
@@ -2,6 +2,19 @@ import { PointVirtualGrid } from '../../PointVirtualGrid';
2
2
  import { LineSegment } from '../../LineSegment';
3
3
  import { Quadtree } from '../../Quadtree';
4
4
  export declare function createPointVirtualGrid<T = any>(lines: LineSegment<T>[]): PointVirtualGrid<LineSegment<T>>;
5
- export declare function createQuadtree<T = any>(lines: LineSegment<T>[]): Quadtree<LineSegment<T>>;
5
+ export declare function createQuadtree<T = any>(lines: LineSegment<T>[]): Quadtree<{
6
+ index: number;
7
+ }>;
6
8
  export declare function mToMm(value: number): number;
7
9
  export declare function mmTom(value: number): number;
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 {};
@@ -22,7 +22,7 @@ export declare class Quadtree<T = any> {
22
22
  * 插入线段节点
23
23
  * @param node 线段节点
24
24
  */
25
- insert(node: QuadtreeNode<T> | LineSegment): void;
25
+ insert(node: QuadtreeNode<T> | LineSegment, userData?: any): void;
26
26
  /** 移除
27
27
  * @param node
28
28
  */