build-dxf 0.0.6 → 0.0.7

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.0.6",
3
+ "version": "0.0.7",
4
4
  "description": "线段构建双线墙壁的dxf版本",
5
5
  "main": "./src/index.js",
6
6
  "types": "./src/index.d.ts",
package/src/index.d.ts CHANGED
@@ -10,6 +10,12 @@ declare class Box2 {
10
10
  get height(): number;
11
11
  get center(): Point;
12
12
  constructor(minX?: number, maxX?: number, minY?: number, maxY?: number);
13
+ /**
14
+ *
15
+ * @param z
16
+ * @returns
17
+ */
18
+ getPaths3D(z?: number): number[];
13
19
  /**
14
20
  * 判断线段是与包围盒相交
15
21
  * @description Liang-Barsky算法的变种
@@ -41,6 +47,10 @@ declare class Box2 {
41
47
  * @param box
42
48
  */
43
49
  containsBox(box: Box2): boolean;
50
+ /** 判断点是在包围盒内
51
+ * @param point
52
+ */
53
+ containsPoint(point: Point): boolean;
44
54
  /**
45
55
  *
46
56
  * @param minX
@@ -340,6 +350,7 @@ declare class Point {
340
350
  * @param y
341
351
  */
342
352
  constructor(x?: number, y?: number);
353
+ set(x: number, y: number): this;
343
354
  setX(x: number): this;
344
355
  setY(y: number): this;
345
356
  /**
@@ -362,6 +373,7 @@ declare class Point {
362
373
  * @param scalar
363
374
  */
364
375
  mutiplyScalar(scalar: number): this;
376
+ multiplyScalar(scalar: number): this;
365
377
  /**
366
378
  *
367
379
  * @param scalar
@@ -401,7 +413,7 @@ declare class Point {
401
413
  */
402
414
  normal(point: Point): Point;
403
415
  /**
404
- * 获取单位方向向量
416
+ * 获取由传入的点到该点的单位方向向量
405
417
  * @description 计算当前点到指定点的方向向量,并返回单位方向
406
418
  * @param point
407
419
  * @returns
@@ -460,6 +472,16 @@ declare class Rectangle {
460
472
  * @returns 是否完全在矩形内部
461
473
  */
462
474
  containsLineSegment(line: LineSegment): boolean;
475
+ /**
476
+ * 判断点是否完全位于矩形内部
477
+ * @param point
478
+ */
479
+ containsPoint(point: Point): boolean;
480
+ /**
481
+ *
482
+ * @returns
483
+ */
484
+ toBox(): Box2;
463
485
  /**
464
486
  *
465
487
  * @param line
package/src/index.js CHANGED
@@ -12545,6 +12545,11 @@ class Point {
12545
12545
  this.x = x;
12546
12546
  this.y = y;
12547
12547
  }
12548
+ set(x, y) {
12549
+ this.x = x;
12550
+ this.y = y;
12551
+ return this;
12552
+ }
12548
12553
  setX(x) {
12549
12554
  this.x = x;
12550
12555
  return this;
@@ -12585,6 +12590,11 @@ class Point {
12585
12590
  this.y *= scalar;
12586
12591
  return this;
12587
12592
  }
12593
+ multiplyScalar(scalar) {
12594
+ this.x *= scalar;
12595
+ this.y *= scalar;
12596
+ return this;
12597
+ }
12588
12598
  /**
12589
12599
  *
12590
12600
  * @param scalar
@@ -12653,7 +12663,7 @@ class Point {
12653
12663
  return new Point(nx, ny);
12654
12664
  }
12655
12665
  /**
12656
- * 获取单位方向向量
12666
+ * 获取由传入的点到该点的单位方向向量
12657
12667
  * @description 计算当前点到指定点的方向向量,并返回单位方向
12658
12668
  * @param point
12659
12669
  * @returns
@@ -12764,6 +12774,20 @@ class Box2 {
12764
12774
  this.minY = minY;
12765
12775
  this.maxY = maxY;
12766
12776
  }
12777
+ /**
12778
+ *
12779
+ * @param z
12780
+ * @returns
12781
+ */
12782
+ getPaths3D(z = 0) {
12783
+ const points = this.points, list = [];
12784
+ points.forEach((p, i) => {
12785
+ const nextP = points[(i + 1) % points.length];
12786
+ list.push(p.x, p.y, z);
12787
+ list.push(nextP.x, nextP.y, z);
12788
+ });
12789
+ return list;
12790
+ }
12767
12791
  /**
12768
12792
  * 判断线段是与包围盒相交
12769
12793
  * @description Liang-Barsky算法的变种
@@ -12891,6 +12915,12 @@ class Box2 {
12891
12915
  containsBox(box) {
12892
12916
  return this.minX <= box.minX && box.maxX <= this.maxX && this.minY <= box.minY && box.maxY <= this.maxY;
12893
12917
  }
12918
+ /** 判断点是在包围盒内
12919
+ * @param point
12920
+ */
12921
+ containsPoint(point) {
12922
+ return point.x >= this.minX && point.x <= this.maxX && point.y >= this.minY && point.y <= this.maxY;
12923
+ }
12894
12924
  /**
12895
12925
  *
12896
12926
  * @param minX
@@ -13519,6 +13549,37 @@ class Rectangle {
13519
13549
  };
13520
13550
  return isPointInRectangle(line.points[0]) && isPointInRectangle(line.points[1]);
13521
13551
  }
13552
+ /**
13553
+ * 判断点是否完全位于矩形内部
13554
+ * @param point
13555
+ */
13556
+ containsPoint(point) {
13557
+ let positiveCount = 0;
13558
+ let negativeCount = 0;
13559
+ for (let i = 0; i < 4; i++) {
13560
+ const p1 = this.points[i];
13561
+ const p2 = this.points[(i + 1) % 4];
13562
+ const cross = (p2.x - p1.x) * (point.y - p1.y) - (p2.y - p1.y) * (point.x - p1.x);
13563
+ if (cross > 0) positiveCount++;
13564
+ else if (cross < 0) negativeCount++;
13565
+ else return false;
13566
+ }
13567
+ return positiveCount === 4 || negativeCount === 4;
13568
+ }
13569
+ /**
13570
+ *
13571
+ * @returns
13572
+ */
13573
+ toBox() {
13574
+ let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
13575
+ this.points.forEach((p) => {
13576
+ maxX = Math.max(p.x, maxX);
13577
+ minX = Math.min(p.x, minX);
13578
+ maxY = Math.max(p.x, maxY);
13579
+ minY = Math.min(p.x, minY);
13580
+ });
13581
+ return new Box2(minX, maxX, minY, maxY);
13582
+ }
13522
13583
  /**
13523
13584
  *
13524
13585
  * @param line
@@ -13719,8 +13780,7 @@ class Quadtree {
13719
13780
  */
13720
13781
  queryRect(rectangle) {
13721
13782
  const result = [];
13722
- const rectBox = Box2.fromByPoints(...rectangle.points);
13723
- if (!this.bounds.intersectBox(rectBox)) {
13783
+ if (!this.bounds.intersectRectangle(rectangle)) {
13724
13784
  return result;
13725
13785
  }
13726
13786
  for (const node of this.nodes) {
@@ -13754,17 +13814,135 @@ class Quadtree {
13754
13814
  return array;
13755
13815
  }
13756
13816
  }
13817
+ class PointVirtualGrid {
13818
+ map = /* @__PURE__ */ new Map();
13819
+ gridSize;
13820
+ constructor(gridSize = 2) {
13821
+ this.gridSize = gridSize;
13822
+ }
13823
+ /**
13824
+ * 插入
13825
+ * @param point
13826
+ * @param userData
13827
+ */
13828
+ insert(point, userData) {
13829
+ if (!point || isNaN(point.x) || isNaN(point.y)) {
13830
+ throw new Error("无效的点坐标");
13831
+ }
13832
+ const id = this.getGridId(point);
13833
+ if (!this.map.has(id)) this.map.set(id, /* @__PURE__ */ new Set());
13834
+ const set = this.map.get(id);
13835
+ set?.add({ point, userData });
13836
+ }
13837
+ /**
13838
+ * 批量加入
13839
+ * @param points
13840
+ */
13841
+ insertBatch(points) {
13842
+ for (const { point, userData } of points) {
13843
+ this.insert(point, userData);
13844
+ }
13845
+ }
13846
+ /**
13847
+ * 获取通过坐标,获取唯一网格索引
13848
+ * @param point
13849
+ * @returns
13850
+ */
13851
+ getGridId(point) {
13852
+ const i = Math.ceil(point.x / this.gridSize), j = Math.ceil(point.y / this.gridSize);
13853
+ return `${i}.${j}`;
13854
+ }
13855
+ /**
13856
+ *
13857
+ * @param gridId
13858
+ * @returns
13859
+ */
13860
+ decodeGridId(gridId) {
13861
+ const [i, j] = gridId.split(".").map(Number);
13862
+ return new Point(i, j);
13863
+ }
13864
+ /**
13865
+ * 查询与矩形相交的点
13866
+ * @param rectangle 矩形
13867
+ * @returns 相交的节点数组
13868
+ */
13869
+ queryRect(rectangle) {
13870
+ const box2 = rectangle.toBox();
13871
+ const minI = Math.ceil(box2.minX / this.gridSize), maxI = Math.ceil(box2.maxX / this.gridSize), minJ = Math.ceil(box2.minY / this.gridSize), maxJ = Math.ceil(box2.maxY / this.gridSize);
13872
+ for (let i = minI; i <= maxI; i++) {
13873
+ for (let j = minJ; j <= maxJ; j++) {
13874
+ const id = `${i}.${j}`;
13875
+ if (!this.map.has(id)) continue;
13876
+ const set = this.map.get(id);
13877
+ set?.forEach((item) => {
13878
+ if (rectangle.containsPoint(item.point)) ;
13879
+ });
13880
+ }
13881
+ }
13882
+ }
13883
+ /**
13884
+ * 查询与圆形区域相交的点
13885
+ * @param pos 圆心
13886
+ * @param radius 半径
13887
+ * @returns 相交的节点数组
13888
+ */
13889
+ queryCircle(pos, radius) {
13890
+ const box2 = new Box2(pos.x - radius, pos.x + radius, pos.y - radius, pos.y + radius);
13891
+ const minI = Math.ceil(box2.minX / this.gridSize), maxI = Math.ceil(box2.maxX / this.gridSize), minJ = Math.ceil(box2.minY / this.gridSize), maxJ = Math.ceil(box2.maxY / this.gridSize), list = [];
13892
+ for (let i = minI; i <= maxI; i++) {
13893
+ for (let j = minJ; j <= maxJ; j++) {
13894
+ const id = `${i}.${j}`;
13895
+ if (!this.map.has(id)) continue;
13896
+ const set = this.map.get(id);
13897
+ set?.forEach((item) => {
13898
+ if (pos.distance(item.point) <= radius) list.push(item);
13899
+ });
13900
+ }
13901
+ }
13902
+ return list;
13903
+ }
13904
+ /**
13905
+ * 查询与包围盒相交的点
13906
+ * @param box2 包围盒
13907
+ * @returns 相交的节点数组
13908
+ */
13909
+ queryBox(box2) {
13910
+ const minI = Math.ceil(box2.minX / this.gridSize), maxI = Math.ceil(box2.maxX / this.gridSize), minJ = Math.ceil(box2.minY / this.gridSize), maxJ = Math.ceil(box2.maxY / this.gridSize), list = [];
13911
+ for (let i = minI; i <= maxI; i++) {
13912
+ for (let j = minJ; j <= maxJ; j++) {
13913
+ const id = `${i}.${j}`;
13914
+ if (!this.map.has(id)) continue;
13915
+ const set = this.map.get(id);
13916
+ set?.forEach((item) => {
13917
+ if (box2.containsPoint(item.point)) list.push(item);
13918
+ });
13919
+ }
13920
+ }
13921
+ return list;
13922
+ }
13923
+ /**
13924
+ * 查找相同点
13925
+ * @param point
13926
+ */
13927
+ queryPoint(point) {
13928
+ const id = this.getGridId(point), list = [];
13929
+ if (this.map.has(id)) {
13930
+ const set = this.map.get(id);
13931
+ set?.forEach((item) => {
13932
+ if (point.equal(item.point)) list.push(item);
13933
+ });
13934
+ }
13935
+ return list;
13936
+ }
13937
+ }
13757
13938
  class LineAnalysis extends Component {
13758
13939
  Dxf = null;
13759
13940
  Variable = null;
13760
13941
  lineSegmentList = [];
13761
13942
  container = new Group();
13762
- showQuadtreeGrid = false;
13763
- showLineInfo = false;
13764
- showProjectLineInfo = false;
13765
- showSearchRectangle = false;
13766
13943
  // 误差角度
13767
13944
  errorAngle = 4;
13945
+ width = 0.4;
13768
13946
  /**
13769
13947
  *
13770
13948
  * @param parent
@@ -13781,16 +13959,25 @@ class LineAnalysis extends Component {
13781
13959
  */
13782
13960
  duplicatePointFiltering() {
13783
13961
  const dxf = this.Dxf;
13784
- dxf.wallsGroup = dxf.wallsGroup.filter((i) => i.length >= 4);
13785
13962
  dxf.wallsGroup = dxf.wallsGroup.map((points) => {
13786
13963
  const filterPoints = [];
13787
13964
  points.forEach((point, index) => {
13788
13965
  if (index < 1 || points.length - 1 === index) return filterPoints.push(point);
13789
13966
  const preP = points[index - 1], nextP = points[index + 1], direct1 = point.direction(preP), direct2 = nextP.direction(point), angle = direct1.angleBetween(direct2) / (Math.PI / 180);
13790
- if (angle > 0.2 && angle < 180 - 0.2) filterPoints.push(point);
13967
+ if (angle > 0.02 && angle < 180 - 0.02) filterPoints.push(point);
13791
13968
  });
13792
- return filterPoints;
13969
+ points = [filterPoints[0]];
13970
+ for (let i = 1; i < filterPoints.length; i++) {
13971
+ const point = filterPoints[i];
13972
+ const nextP = filterPoints[i - 1];
13973
+ if (nextP.distance(point) < dxf.width * 0.5) {
13974
+ console.log(111);
13975
+ }
13976
+ points.push(point);
13977
+ }
13978
+ return points;
13793
13979
  });
13980
+ dxf.wallsGroup = dxf.wallsGroup.filter((i) => i.length >= 4);
13794
13981
  }
13795
13982
  /**
13796
13983
  *
@@ -13818,29 +14005,50 @@ class LineAnalysis extends Component {
13818
14005
  rectIndices: [0, 1, 3, 2, 0]
13819
14006
  };
13820
14007
  }
14008
+ appendLineSegmentList = [];
14009
+ /**
14010
+ * 追加数据
14011
+ * @param p1
14012
+ * @param p2
14013
+ */
14014
+ addData(p1, p2) {
14015
+ const dxf = this.Dxf;
14016
+ dxf.data.push([p1.clone(), p2.clone(), [], false, dxf.data.length]);
14017
+ this.appendLineSegmentList.push(new LineSegment(p1.clone(), p2.clone()));
14018
+ }
13821
14019
  /** 结果分析创建矩形
13822
14020
  * @param result
13823
14021
  */
13824
14022
  createRectangle(result) {
13825
14023
  const dxf = this.Dxf;
13826
- const pl0 = result.source.projectLineSegment(result.project);
13827
- dxf.data.push([pl0.points[0].clone(), result.project.points[0].clone(), [], false, dxf.data.length]);
13828
- dxf.data.push([pl0.points[1].clone(), result.project.points[1].clone(), [], false, dxf.data.length]);
13829
- const direct = pl0.points[0].direction(result.project.points[0]);
13830
- const distance = Math.min(
13831
- result.project.points[0].distance(pl0.points[0]),
13832
- result.project.points[1].distance(pl0.points[1])
13833
- );
13834
- const count = Math.ceil(distance / dxf.width);
13835
- const fragment = distance / count;
13836
- for (let i = 1; i <= count; i++) {
13837
- const incrementP = direct.clone().mutiplyScalar(fragment * i), p1 = result.project.points[0].clone().add(incrementP), p2 = result.project.points[1].clone().add(incrementP);
13838
- const temDirect = p2.direction(p1).mutiplyScalar(dxf.width);
13839
- p2.division(temDirect);
13840
- p1.division(temDirect.mutiplyScalar(-1));
13841
- dxf.data.push([p1, p2, [], false, dxf.data.length]);
14024
+ const project0 = result.project, project1 = result.project2;
14025
+ this.addData(project0.points[0], project1.points[0]);
14026
+ this.addData(project0.points[1], project1.points[1]);
14027
+ const leftHeight = project0.points[0].distance(project1.points[0]), rightHeight = project0.points[1].distance(project1.points[1]), count = Math.ceil(Math.max(leftHeight, rightHeight) / dxf.width), leftFragment = leftHeight / count, rightFragment = rightHeight / count, leftDirection = project1.points[0].direction(project0.points[0]), rightDirection = project1.points[1].direction(project0.points[1]), leftP = project0.points[0].clone(), rightP = project0.points[1].clone(), direction = rightP.direction(leftP);
14028
+ direction.multiplyScalar(dxf.width * 0.5);
14029
+ const _leftP = leftP.clone().add(direction), _rightP = rightP.clone().add(direction.multiplyScalar(-1)), d1 = leftP.direction(rightP), d2 = _leftP.direction(_rightP);
14030
+ if (d1.x > 0 && d2.x < 0 || d1.x < 0 && d2.x > 0 || d1.y > 0 && d2.y < 0 || d1.y < 0 && d2.y > 0) return;
14031
+ leftP.set(_leftP.x, _leftP.y);
14032
+ rightP.set(_rightP.x, _rightP.y);
14033
+ for (let i = 1; i < count; i++) {
14034
+ const left = leftDirection.clone().multiplyScalar(leftFragment * i), right = rightDirection.clone().multiplyScalar(rightFragment * i), p1 = leftP.clone().add(left), p2 = rightP.clone().add(right);
14035
+ this.addData(p1, p2);
13842
14036
  }
13843
14037
  }
14038
+ pointVirtualGrid = new PointVirtualGrid();
14039
+ /**
14040
+ * 构建点的虚拟网格索引
14041
+ */
14042
+ buildVirtualGrid() {
14043
+ const dxf = this.Dxf;
14044
+ const pointVirtualGrid = new PointVirtualGrid();
14045
+ dxf.originalData.forEach((d, index) => {
14046
+ const [p1, p2] = [Point.from(d.start), Point.from(d.end)];
14047
+ pointVirtualGrid.insert(p1, { index, type: "start" });
14048
+ pointVirtualGrid.insert(p2, { index, type: "end" });
14049
+ });
14050
+ this.pointVirtualGrid = pointVirtualGrid;
14051
+ }
13844
14052
  quadtree;
13845
14053
  /**
13846
14054
  * 构建线段四叉树,快速查找,
@@ -13848,7 +14056,7 @@ class LineAnalysis extends Component {
13848
14056
  buildQuadtree() {
13849
14057
  const dxf = this.Dxf;
13850
14058
  const lineSegmentList = [];
13851
- this.quadtree = new Quadtree(new Box2(-20, 20, -20, 20), 2);
14059
+ this.quadtree = new Quadtree(dxf.originalBox, 2);
13852
14060
  dxf.originalData.forEach((d) => {
13853
14061
  if (d.isDoor) return;
13854
14062
  const lineSegment = new LineSegment(Point.from(d.start), Point.from(d.end));
@@ -13867,11 +14075,12 @@ class LineAnalysis extends Component {
13867
14075
  */
13868
14076
  lineAnalysis() {
13869
14077
  this.buildQuadtree();
14078
+ this.buildVirtualGrid();
13870
14079
  const quadtree = this.quadtree;
13871
14080
  const lineSegmentList = this.lineSegmentList;
13872
14081
  const visited = /* @__PURE__ */ new Set(), resultList = [];
13873
14082
  lineSegmentList.forEach((_0, i) => {
13874
- const sourceLineSegment = lineSegmentList[i], rectangle = Rectangle.fromByLineSegment(sourceLineSegment, 0.4 * 2, true, -0.01), ids = quadtree.queryRect(rectangle).map((i2) => i2.userData).filter((index) => index !== i);
14083
+ const sourceLineSegment = lineSegmentList[i], rectangle = Rectangle.fromByLineSegment(sourceLineSegment, this.width * 2, false, -0.01), ids = quadtree.queryRect(rectangle).map((i2) => i2.userData).filter((index) => index !== i);
13875
14084
  ids.forEach((id) => {
13876
14085
  try {
13877
14086
  if (visited.has(`${i}-${id}`) || visited.has(`${id}-${i}`)) return;
@@ -13879,10 +14088,10 @@ class LineAnalysis extends Component {
13879
14088
  if (res) resultList.push(res);
13880
14089
  visited.add(`${i}-${id}`);
13881
14090
  } catch (error) {
13882
- console.log(error);
13883
14091
  }
13884
14092
  });
13885
14093
  });
14094
+ this.appendLineSegmentList.length = 0;
13886
14095
  resultList.forEach(this.createRectangle.bind(this));
13887
14096
  this.resultList = [];
13888
14097
  }
@@ -13896,13 +14105,18 @@ class LineAnalysis extends Component {
13896
14105
  const temLineSegment = lineSegmentList[index], direct = sourceLineSegment.direction(), temDirect = temLineSegment.direction(), angle = direct.angleBetween(temDirect) / (Math.PI / 180);
13897
14106
  if (angle < this.errorAngle || angle > 180 - this.errorAngle) {
13898
14107
  let data;
13899
- if (temLineSegment.getLength() > sourceLineSegment.getLength()) {
14108
+ const p1 = temLineSegment.projectLineSegment(sourceLineSegment), p2 = sourceLineSegment.projectLineSegment(temLineSegment), d1 = p1.direction(), d2 = p2.direction();
14109
+ if (d1.x > 0 && d2.x < 0 || d1.x < 0 && d2.x > 0 || d1.y > 0 && d2.y < 0 || d1.y < 0 && d2.y > 0) {
14110
+ p1.points = [p1.points[1], p1.points[0]];
14111
+ }
14112
+ if (p1.getLength() > p2.getLength()) {
13900
14113
  data = {
13901
14114
  target: temLineSegment,
13902
14115
  targetIndex: index,
13903
14116
  source: sourceLineSegment,
13904
14117
  sourceIndex,
13905
- project: temLineSegment.projectLineSegment(sourceLineSegment)
14118
+ project: p1,
14119
+ project2: p2
13906
14120
  };
13907
14121
  } else {
13908
14122
  data = {
@@ -13910,10 +14124,11 @@ class LineAnalysis extends Component {
13910
14124
  targetIndex: sourceIndex,
13911
14125
  source: temLineSegment,
13912
14126
  sourceIndex: index,
13913
- project: sourceLineSegment.projectLineSegment(temLineSegment)
14127
+ project: p2,
14128
+ project2: p1
13914
14129
  };
13915
14130
  }
13916
- if (!data || data.project.getLength() < 1e-3) return;
14131
+ if (!data || data.project.getLength() < 0.01) return;
13917
14132
  return data;
13918
14133
  }
13919
14134
  }