build-dxf 0.1.106 → 0.1.108
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
package/src/build.js
CHANGED
|
@@ -5487,13 +5487,49 @@ class Polygon extends Array {
|
|
|
5487
5487
|
this.length = 0;
|
|
5488
5488
|
this.push(...points);
|
|
5489
5489
|
}
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5490
|
+
/**
|
|
5491
|
+
* 获取多边形几何中心(面积质心)
|
|
5492
|
+
* @description 使用多边形面积质心公式计算
|
|
5493
|
+
* @description 适用于闭合简单多边形(顺时针或逆时针均可)
|
|
5494
|
+
* @description 如果面积为 0,则退化为顶点平均中心
|
|
5495
|
+
* @param out 输出对象,用于减少 GC
|
|
5496
|
+
* @returns
|
|
5497
|
+
*/
|
|
5498
|
+
getCenter(out = new Point()) {
|
|
5499
|
+
const len = this.length;
|
|
5500
|
+
if (len === 0) {
|
|
5501
|
+
return out.set(0, 0);
|
|
5502
|
+
}
|
|
5503
|
+
let area2 = 0;
|
|
5504
|
+
let centerX = 0;
|
|
5505
|
+
let centerY = 0;
|
|
5506
|
+
for (let i = 0; i < len; i++) {
|
|
5507
|
+
const p1 = this[i];
|
|
5508
|
+
const p2 = this[(i + 1) % len];
|
|
5509
|
+
const cross = p1.x * p2.y - p2.x * p1.y;
|
|
5510
|
+
area2 += cross;
|
|
5511
|
+
centerX += (p1.x + p2.x) * cross;
|
|
5512
|
+
centerY += (p1.y + p2.y) * cross;
|
|
5513
|
+
}
|
|
5514
|
+
area2 *= 0.5;
|
|
5515
|
+
if (Math.abs(area2) < 1e-9) {
|
|
5516
|
+
let sumX = 0;
|
|
5517
|
+
let sumY = 0;
|
|
5518
|
+
for (let i = 0; i < len; i++) {
|
|
5519
|
+
sumX += this[i].x;
|
|
5520
|
+
sumY += this[i].y;
|
|
5521
|
+
}
|
|
5522
|
+
const inv = 1 / len;
|
|
5523
|
+
return out.set(
|
|
5524
|
+
sumX * inv,
|
|
5525
|
+
sumY * inv
|
|
5526
|
+
);
|
|
5527
|
+
}
|
|
5528
|
+
const factor = 1 / (6 * area2);
|
|
5529
|
+
return out.set(
|
|
5530
|
+
centerX * factor,
|
|
5531
|
+
centerY * factor
|
|
5532
|
+
);
|
|
5497
5533
|
}
|
|
5498
5534
|
/** 计算二维包围盒
|
|
5499
5535
|
* @returns
|
|
@@ -9536,6 +9572,10 @@ const holeTypeMap = {
|
|
|
9536
9572
|
passageEntrance: "WALL_HOLE",
|
|
9537
9573
|
bay_window: "BAY_WINDOW"
|
|
9538
9574
|
};
|
|
9575
|
+
const placeHoldersMap = {
|
|
9576
|
+
switch: "开关",
|
|
9577
|
+
socket: "插座"
|
|
9578
|
+
};
|
|
9539
9579
|
const WALL_HEIGHT_KEY = /* @__PURE__ */ Symbol("height");
|
|
9540
9580
|
class ThreeVJiaPipeline extends Pipeline {
|
|
9541
9581
|
manager;
|
|
@@ -9568,17 +9608,10 @@ class ThreeVJiaPipeline extends Pipeline {
|
|
|
9568
9608
|
if (lines2.length < 4) return lines2;
|
|
9569
9609
|
let newLine = null;
|
|
9570
9610
|
let wallWidth = 0;
|
|
9571
|
-
|
|
9572
|
-
|
|
9573
|
-
|
|
9574
|
-
|
|
9575
|
-
wallWidth = Math.min(len1, len2);
|
|
9576
|
-
} else {
|
|
9577
|
-
lines2 = [...lines2].sort((a2, b4) => a2.length() - b4.length());
|
|
9578
|
-
const line1 = lines2[0], line2 = lines2[1];
|
|
9579
|
-
newLine = new LineSegment(line1.center.clone(), line2.center.clone());
|
|
9580
|
-
wallWidth = line1.length();
|
|
9581
|
-
}
|
|
9611
|
+
lines2 = [...lines2].sort((a2, b4) => a2.length() - b4.length());
|
|
9612
|
+
const line1 = lines2[0], line2 = lines2[1];
|
|
9613
|
+
newLine = new LineSegment(line1.center.clone(), line2.center.clone());
|
|
9614
|
+
wallWidth = line1.length();
|
|
9582
9615
|
mergeLineUserData(newLine, lines2);
|
|
9583
9616
|
newLine.userData.wallWidth = wallWidth;
|
|
9584
9617
|
return [newLine];
|
|
@@ -9727,7 +9760,6 @@ class ThreeVJiaPipeline extends Pipeline {
|
|
|
9727
9760
|
type: "LINE",
|
|
9728
9761
|
isDoor: false,
|
|
9729
9762
|
loadBearingWall: false,
|
|
9730
|
-
// height: line.userData.height ?? DEFAULT_WALL_HEIGHT
|
|
9731
9763
|
height: precision4(line.currentData[WALL_HEIGHT_KEY] ?? this.maxHeight)
|
|
9732
9764
|
});
|
|
9733
9765
|
});
|
|
@@ -9760,12 +9792,13 @@ class ThreeVJiaPipeline extends Pipeline {
|
|
|
9760
9792
|
const rooms = json.rooms, roomPloys = rooms.map((room) => new Polygon(room.polygon.map((p2) => Point.from(p2))));
|
|
9761
9793
|
if (roomPloys.length === 0) return json;
|
|
9762
9794
|
publicInfo.itemInfo.forEach((item, i) => {
|
|
9795
|
+
if (!placeHoldersMap[item.category]) return;
|
|
9763
9796
|
const itemPoly = new Polygon(item.contour.map((p2) => Point.from(p2).rotate(json.center, json.angle))), center = itemPoly.getCenter(), index2 = roomPloys.findIndex((poly) => poly.pointWithin(center));
|
|
9764
9797
|
if (index2 < 0) return;
|
|
9765
9798
|
json.placeHolders.push({
|
|
9766
|
-
name: item.category,
|
|
9767
|
-
polygon:
|
|
9768
|
-
direction: item.direction,
|
|
9799
|
+
name: placeHoldersMap[item.category],
|
|
9800
|
+
polygon: itemPoly.getMinimumBoundingRectangle().map((p2) => p2.toJson2D()),
|
|
9801
|
+
direction: Point.from(item.direction).rotate(Point.zero(), json.angle),
|
|
9769
9802
|
height: item.box.max.z - item.box.min.z,
|
|
9770
9803
|
sillHeight: item.box.min.z - z,
|
|
9771
9804
|
roomId: rooms[index2].roomTypeId,
|
|
@@ -9782,7 +9815,6 @@ class ThreeVJiaPipeline extends Pipeline {
|
|
|
9782
9815
|
* @returns
|
|
9783
9816
|
*/
|
|
9784
9817
|
static toThreeVJiaJson(lineSegments, angle = 0, updateGroup = true) {
|
|
9785
|
-
angle = precision4(angle);
|
|
9786
9818
|
let centerVec2 = null;
|
|
9787
9819
|
lineSegments = LineSegmentUndirectedGraph.rotate(lineSegments.map((line) => line.clone()), angle, (line, center, angle2) => {
|
|
9788
9820
|
if (!centerVec2) centerVec2 = { x: center.x, y: center.y };
|
|
@@ -10679,13 +10711,19 @@ class DoubleWallHelper {
|
|
|
10679
10711
|
const newLine1 = new LineSegment(project0.start.clone(), project1.start.clone());
|
|
10680
10712
|
const newLine2 = new LineSegment(project0.end.clone(), project1.end.clone());
|
|
10681
10713
|
newLine1.userData.height = line0.userData.height;
|
|
10714
|
+
newLine1.userData.rooftopPz = line0.userData.rooftopPz;
|
|
10682
10715
|
newLine2.userData.height = line1.userData.height;
|
|
10716
|
+
newLine2.userData.rooftopPz = line1.userData.rooftopPz;
|
|
10683
10717
|
appendLines.push(newLine1, newLine2);
|
|
10684
10718
|
addClipingMap(line0, project0);
|
|
10685
10719
|
addClipingMap(line1, project1);
|
|
10686
10720
|
});
|
|
10687
10721
|
clipingMap.forEach((list, line) => {
|
|
10688
10722
|
const newLines = LineSegmentUtils.clippingByPoints(line, list);
|
|
10723
|
+
newLines.forEach((newLine) => {
|
|
10724
|
+
newLine.userData.height = line.userData.height;
|
|
10725
|
+
newLine.userData.rooftopPz = line.userData.rooftopPz;
|
|
10726
|
+
});
|
|
10689
10727
|
lines.push(...newLines);
|
|
10690
10728
|
});
|
|
10691
10729
|
lines = lines.filter((line) => !removeLines.has(line));
|
|
@@ -10696,9 +10734,11 @@ class DoubleWallHelper {
|
|
|
10696
10734
|
const queryLines = quadtree.queryRect(line.toRectangle(1e-3, "butt")).filter((item) => item.line.isParallelTo(line)).map((item) => item.line);
|
|
10697
10735
|
if (queryLines.length) {
|
|
10698
10736
|
const newLines = LineSegmentUtils.clippingByLines(line, queryLines);
|
|
10699
|
-
if (newLines) return newLines.forEach((
|
|
10700
|
-
|
|
10701
|
-
|
|
10737
|
+
if (newLines) return newLines.forEach((newLine) => {
|
|
10738
|
+
newLine.userData.height = line.userData.height;
|
|
10739
|
+
newLine.userData.rooftopPz = line.userData.rooftopPz;
|
|
10740
|
+
quadtree.insert(newLine);
|
|
10741
|
+
lines.push(newLine);
|
|
10702
10742
|
});
|
|
10703
10743
|
}
|
|
10704
10744
|
quadtree.insert(line);
|
|
@@ -11031,7 +11071,7 @@ class AlignToParallelSegments {
|
|
|
11031
11071
|
* @param esp 垂直投影值分组距离
|
|
11032
11072
|
* @param gap 平行轴投影区间间隙
|
|
11033
11073
|
*/
|
|
11034
|
-
static group(lines, parallelAxis, verticalAxis, esp = 0.05, gap = 0.01) {
|
|
11074
|
+
static group(lines, parallelAxis, verticalAxis, esp = 0.05, gap = 0.01, onGroup) {
|
|
11035
11075
|
esp = esp / verticalAxis.len;
|
|
11036
11076
|
gap = gap / parallelAxis.len;
|
|
11037
11077
|
const vls = lines.map((line) => [
|
|
@@ -11039,16 +11079,29 @@ class AlignToParallelSegments {
|
|
|
11039
11079
|
line,
|
|
11040
11080
|
[parallelAxis.projectPointValue(line.start), parallelAxis.projectPointValue(line.end)].sort((a2, b4) => a2 - b4)
|
|
11041
11081
|
]).sort((a2, b4) => a2[0] - b4[0]), unionFindSet = new UnionFindSet(vls.length);
|
|
11042
|
-
for (let
|
|
11043
|
-
const [ipv, _iline, [istart, iend]] = vls[
|
|
11044
|
-
for (let j =
|
|
11082
|
+
for (let i2 = 0; i2 < vls.length; i2++) {
|
|
11083
|
+
const [ipv, _iline, [istart, iend]] = vls[i2];
|
|
11084
|
+
for (let j = i2 + 1; j < vls.length; j++) {
|
|
11045
11085
|
const [jpv, _jline, [jstart, jend]] = vls[j];
|
|
11046
11086
|
if (jpv - ipv > esp) break;
|
|
11047
11087
|
const overlap = Math.min(iend, jend) - Math.max(istart, jstart);
|
|
11048
|
-
if (overlap > -gap) unionFindSet.union(
|
|
11049
|
-
}
|
|
11050
|
-
}
|
|
11051
|
-
const
|
|
11088
|
+
if (overlap > -gap) unionFindSet.union(i2, j);
|
|
11089
|
+
}
|
|
11090
|
+
}
|
|
11091
|
+
const map = unionFindSet.getAllSets();
|
|
11092
|
+
const groups = new Array(map.size);
|
|
11093
|
+
let i = 0;
|
|
11094
|
+
map.forEach((list) => {
|
|
11095
|
+
const group = new Array(list.length);
|
|
11096
|
+
const pvList = new Array(list.length);
|
|
11097
|
+
groups[i++] = group;
|
|
11098
|
+
for (let i2 = 0; i2 < list.length; i2++) {
|
|
11099
|
+
const [pv, line] = vls[list[i2]];
|
|
11100
|
+
group[i2] = line;
|
|
11101
|
+
pvList[i2] = pv;
|
|
11102
|
+
}
|
|
11103
|
+
onGroup?.(group, pvList, verticalAxis);
|
|
11104
|
+
});
|
|
11052
11105
|
return groups;
|
|
11053
11106
|
}
|
|
11054
11107
|
/** 拟合并对齐线段
|
|
@@ -11088,13 +11141,13 @@ class AlignToParallelSegments {
|
|
|
11088
11141
|
* @returns
|
|
11089
11142
|
*/
|
|
11090
11143
|
static align(lines, opt = {}) {
|
|
11091
|
-
const { esp = 0.
|
|
11144
|
+
const { esp = 0.08, gap = 0.05 } = opt;
|
|
11092
11145
|
const axisLine = lines[LineSegmentUtils.maxLengthLineIndex(lines)].clone().setLength(100), axisLineV = axisLine.clone().rotate(Math.PI * 0.5, axisLine.center);
|
|
11093
11146
|
let [pllLines, verticalLines] = LineSegmentUtils.groupByParallelToAxis(lines, axisLine);
|
|
11094
|
-
const groups = this.group(pllLines, axisLine, axisLineV, esp, gap);
|
|
11147
|
+
const groups = this.group(pllLines, axisLine, axisLineV, esp, gap, opt.onGroup);
|
|
11095
11148
|
pllLines = this.fittingAlignment(groups, verticalLines, opt);
|
|
11096
11149
|
verticalLines = verticalLines.filter((line) => line.length() > 1e-6);
|
|
11097
|
-
const groups2 = this.group(verticalLines, axisLineV, axisLine, esp, gap);
|
|
11150
|
+
const groups2 = this.group(verticalLines, axisLineV, axisLine, esp, gap, opt.onGroup);
|
|
11098
11151
|
verticalLines = this.fittingAlignment(groups2, pllLines, opt);
|
|
11099
11152
|
pllLines = pllLines.filter((line) => line.length() > 1e-6);
|
|
11100
11153
|
return [
|
|
@@ -11230,7 +11283,17 @@ function correction(lines, targettLine, option) {
|
|
|
11230
11283
|
lines = AxisAlignCorr.start(lines, targettLine);
|
|
11231
11284
|
lines = lineSegmentClipping(lines, 1e-9);
|
|
11232
11285
|
lines = AlignToParallelSegments.align(lines, {
|
|
11233
|
-
onMergeLine: mergeLineUserData
|
|
11286
|
+
onMergeLine: mergeLineUserData,
|
|
11287
|
+
onGroup(group, projValues, axis) {
|
|
11288
|
+
if (group.length <= 1) return;
|
|
11289
|
+
const max = Math.max(...projValues);
|
|
11290
|
+
const min = Math.min(...projValues);
|
|
11291
|
+
const dist = precision4((max - min) * axis.len);
|
|
11292
|
+
if (dist < DEFAULT_WALL_WIDTH) return;
|
|
11293
|
+
group.forEach((line) => {
|
|
11294
|
+
line.userData.wallWidth = dist;
|
|
11295
|
+
});
|
|
11296
|
+
}
|
|
11234
11297
|
// esp: 0.4
|
|
11235
11298
|
});
|
|
11236
11299
|
lines = adsorption(lines, option);
|
|
@@ -11269,7 +11332,22 @@ function axisAlignCorr(lines, option, verticalReferenceLine) {
|
|
|
11269
11332
|
}
|
|
11270
11333
|
return lines;
|
|
11271
11334
|
}
|
|
11335
|
+
function sparse(trajectory2, size2 = 0.4) {
|
|
11336
|
+
const idSet = /* @__PURE__ */ new Set();
|
|
11337
|
+
Object.keys(trajectory2 ?? {}).forEach((key) => {
|
|
11338
|
+
const p2 = trajectory2[key], i = Math.round(p2.x / size2), j = Math.round(p2.y / size2), id = BigInt(i) << 32n | BigInt(j) & 0xffffffffn;
|
|
11339
|
+
if (idSet.has(id)) {
|
|
11340
|
+
delete trajectory2[key];
|
|
11341
|
+
return;
|
|
11342
|
+
}
|
|
11343
|
+
idSet.add(id);
|
|
11344
|
+
});
|
|
11345
|
+
}
|
|
11272
11346
|
function init(lines, option) {
|
|
11347
|
+
if (option.trajectory) {
|
|
11348
|
+
sparse(option.trajectory, 0.2);
|
|
11349
|
+
sparse(option.trajectory, 0.5);
|
|
11350
|
+
}
|
|
11273
11351
|
BuildGroup.doubleWall.setTrajectory(option.trajectory);
|
|
11274
11352
|
lines = lines.map((line) => line.clone());
|
|
11275
11353
|
return lines;
|
|
@@ -11767,9 +11845,17 @@ function wallHeightHandle(lineSegments, option) {
|
|
|
11767
11845
|
Object.defineProperty(option.publicInfo.rootTopContourInfo, "quadtree", { value: quadtree });
|
|
11768
11846
|
}
|
|
11769
11847
|
}
|
|
11848
|
+
const psh = PointSpatialHash.fromByLines(lineSegments);
|
|
11770
11849
|
lineSegments.forEach((line) => {
|
|
11771
11850
|
if (!("height" in line.userData)) {
|
|
11772
|
-
if (!line.userData.rooftopPz && option?.publicInfo?.rootTopContourInfo)
|
|
11851
|
+
if (!line.userData.rooftopPz && option?.publicInfo?.rootTopContourInfo) {
|
|
11852
|
+
const list = psh.queryPoints(line.points, true).map((item) => item.userData?.userData.rooftopPz ?? 0);
|
|
11853
|
+
if (list.length) {
|
|
11854
|
+
line.userData.rooftopPz = Math.max(...list);
|
|
11855
|
+
} else {
|
|
11856
|
+
line.userData.rooftopPz = HeightQuery.query(line, option.publicInfo.rootTopContourInfo);
|
|
11857
|
+
}
|
|
11858
|
+
}
|
|
11773
11859
|
if ("rooftopPz" in line.userData) line.userData.height = Math.abs(line.userData.rooftopPz - (option.originalZ ?? 0));
|
|
11774
11860
|
}
|
|
11775
11861
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { LineSegment } from './LineSegment';
|
|
2
|
+
type OnGroupFun = (group: LineSegment[], projValues: number[], axis: LineSegment) => void;
|
|
2
3
|
export interface AlignDescriptor {
|
|
3
4
|
esp?: number;
|
|
4
5
|
gap?: number;
|
|
5
6
|
onMergeLine?: (target: LineSegment, source: LineSegment) => void;
|
|
7
|
+
onGroup?: OnGroupFun;
|
|
6
8
|
}
|
|
7
9
|
/** 通过平行轴和垂直轴分组对齐线段,搭配垂直纠正使用
|
|
8
10
|
*/
|
|
@@ -14,7 +16,7 @@ export declare class AlignToParallelSegments {
|
|
|
14
16
|
* @param esp 垂直投影值分组距离
|
|
15
17
|
* @param gap 平行轴投影区间间隙
|
|
16
18
|
*/
|
|
17
|
-
static group(lines: LineSegment[], parallelAxis: LineSegment, verticalAxis: LineSegment, esp?: number, gap?: number): LineSegment<Record<string, any>>[][];
|
|
19
|
+
static group(lines: LineSegment[], parallelAxis: LineSegment, verticalAxis: LineSegment, esp?: number, gap?: number, onGroup?: OnGroupFun): LineSegment<Record<string, any>>[][];
|
|
18
20
|
/** 拟合并对齐线段
|
|
19
21
|
* @param groups
|
|
20
22
|
* @param verticalLines
|
|
@@ -26,3 +28,4 @@ export declare class AlignToParallelSegments {
|
|
|
26
28
|
*/
|
|
27
29
|
static align(lines: LineSegment[], opt?: AlignDescriptor): LineSegment<Record<string, any>>[];
|
|
28
30
|
}
|
|
31
|
+
export {};
|
|
@@ -13,7 +13,15 @@ export declare class Polygon<T = any> extends Array<Point<T>> {
|
|
|
13
13
|
[Symbol.iterator](): ArrayIterator<Point<T>>;
|
|
14
14
|
constructor(points?: Point<T>[]);
|
|
15
15
|
set(points?: Point<T>[]): void;
|
|
16
|
-
|
|
16
|
+
/**
|
|
17
|
+
* 获取多边形几何中心(面积质心)
|
|
18
|
+
* @description 使用多边形面积质心公式计算
|
|
19
|
+
* @description 适用于闭合简单多边形(顺时针或逆时针均可)
|
|
20
|
+
* @description 如果面积为 0,则退化为顶点平均中心
|
|
21
|
+
* @param out 输出对象,用于减少 GC
|
|
22
|
+
* @returns
|
|
23
|
+
*/
|
|
24
|
+
getCenter(out?: Point<Record<string, any>>): Point<Record<string, any>>;
|
|
17
25
|
/** 计算二维包围盒
|
|
18
26
|
* @returns
|
|
19
27
|
*/
|