brepjs-bim 0.2.0 → 0.3.1
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/README.md +8 -1
- package/dist/bcf/bcfXml.d.ts +9 -3
- package/dist/brepjs-bim.cjs +792 -309
- package/dist/brepjs-bim.js +793 -311
- package/dist/elementFns/placedGeometry.d.ts +18 -0
- package/dist/ifc-writer/geometryWriter.d.ts +4 -1
- package/dist/ifc-writer/railingWriter.d.ts +9 -3
- package/dist/import/placement.d.ts +18 -0
- package/dist/index.d.ts +1 -0
- package/dist/specs/railingSpec.d.ts +6 -0
- package/dist/specs/roofSpec.d.ts +7 -0
- package/package.json +6 -2
package/dist/brepjs-bim.cjs
CHANGED
|
@@ -265,7 +265,7 @@ function _usingCtx() {
|
|
|
265
265
|
//#region src/elementFns/wallFns.ts
|
|
266
266
|
function wallToSolid(spec) {
|
|
267
267
|
try {
|
|
268
|
-
var _usingCtx$
|
|
268
|
+
var _usingCtx$19 = _usingCtx();
|
|
269
269
|
if (spec.length <= 0) return (0, brepjs.err)(specError("WALL_ZERO_LENGTH", "Wall length must be positive"));
|
|
270
270
|
if (spec.height <= 0) return (0, brepjs.err)(specError("WALL_ZERO_HEIGHT", "Wall height must be positive"));
|
|
271
271
|
if (spec.thickness <= 0) return (0, brepjs.err)(specError("WALL_ZERO_THICKNESS", "Wall thickness must be positive"));
|
|
@@ -293,7 +293,7 @@ function wallToSolid(spec) {
|
|
|
293
293
|
]
|
|
294
294
|
]);
|
|
295
295
|
if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "WALL_PROFILE_FAILED", "Failed to create wall profile"));
|
|
296
|
-
const solidResult = (0, brepjs.extrude)(_usingCtx$
|
|
296
|
+
const solidResult = (0, brepjs.extrude)(_usingCtx$19.u(profileResult.value), [
|
|
297
297
|
length,
|
|
298
298
|
0,
|
|
299
299
|
0
|
|
@@ -306,16 +306,16 @@ function wallToSolid(spec) {
|
|
|
306
306
|
}
|
|
307
307
|
return (0, brepjs.ok)(solid);
|
|
308
308
|
} catch (_) {
|
|
309
|
-
_usingCtx$
|
|
309
|
+
_usingCtx$19.e = _;
|
|
310
310
|
} finally {
|
|
311
|
-
_usingCtx$
|
|
311
|
+
_usingCtx$19.d();
|
|
312
312
|
}
|
|
313
313
|
}
|
|
314
314
|
//#endregion
|
|
315
315
|
//#region src/elementFns/slabFns.ts
|
|
316
316
|
function slabToSolid(spec) {
|
|
317
317
|
try {
|
|
318
|
-
var _usingCtx$
|
|
318
|
+
var _usingCtx$18 = _usingCtx();
|
|
319
319
|
if (spec.length <= 0) return (0, brepjs.err)(specError("SLAB_ZERO_LENGTH", "Slab length must be positive"));
|
|
320
320
|
if (spec.width <= 0) return (0, brepjs.err)(specError("SLAB_ZERO_WIDTH", "Slab width must be positive"));
|
|
321
321
|
if (spec.thickness <= 0) return (0, brepjs.err)(specError("SLAB_ZERO_THICKNESS", "Slab thickness must be positive"));
|
|
@@ -343,7 +343,7 @@ function slabToSolid(spec) {
|
|
|
343
343
|
]
|
|
344
344
|
]);
|
|
345
345
|
if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "SLAB_PROFILE_FAILED", "Failed to create slab profile"));
|
|
346
|
-
const solidResult = (0, brepjs.extrude)(_usingCtx$
|
|
346
|
+
const solidResult = (0, brepjs.extrude)(_usingCtx$18.u(profileResult.value), [
|
|
347
347
|
0,
|
|
348
348
|
0,
|
|
349
349
|
thickness
|
|
@@ -356,9 +356,9 @@ function slabToSolid(spec) {
|
|
|
356
356
|
}
|
|
357
357
|
return (0, brepjs.ok)(solid);
|
|
358
358
|
} catch (_) {
|
|
359
|
-
_usingCtx$
|
|
359
|
+
_usingCtx$18.e = _;
|
|
360
360
|
} finally {
|
|
361
|
-
_usingCtx$
|
|
361
|
+
_usingCtx$18.d();
|
|
362
362
|
}
|
|
363
363
|
}
|
|
364
364
|
//#endregion
|
|
@@ -5035,14 +5035,14 @@ function to3D(points) {
|
|
|
5035
5035
|
}
|
|
5036
5036
|
function extendedProfileToFace(profile) {
|
|
5037
5037
|
try {
|
|
5038
|
-
var _usingCtx$
|
|
5038
|
+
var _usingCtx$17 = _usingCtx();
|
|
5039
5039
|
const invalid = validateProfile(profile);
|
|
5040
5040
|
if (invalid !== null) return (0, brepjs.err)(invalid);
|
|
5041
5041
|
const outerResult = (0, brepjs.polygon)(to3D(outerLoop(profile)));
|
|
5042
5042
|
if (!outerResult.ok) return (0, brepjs.err)(fromBrepError(outerResult.error, "PROFILE_FACE_FAILED", "Failed to build profile outer face"));
|
|
5043
5043
|
const holes = holeLoops(profile);
|
|
5044
5044
|
if (holes.length === 0) return (0, brepjs.ok)(outerResult.value);
|
|
5045
|
-
const outerFace = _usingCtx$
|
|
5045
|
+
const outerFace = _usingCtx$17.u(outerResult.value);
|
|
5046
5046
|
const holeFaces = [];
|
|
5047
5047
|
const holeWires = [];
|
|
5048
5048
|
const disposeHoleFaces = () => {
|
|
@@ -5067,9 +5067,9 @@ function extendedProfileToFace(profile) {
|
|
|
5067
5067
|
disposeHoleFaces();
|
|
5068
5068
|
return (0, brepjs.ok)(faceWithHoles);
|
|
5069
5069
|
} catch (_) {
|
|
5070
|
-
_usingCtx$
|
|
5070
|
+
_usingCtx$17.e = _;
|
|
5071
5071
|
} finally {
|
|
5072
|
-
_usingCtx$
|
|
5072
|
+
_usingCtx$17.d();
|
|
5073
5073
|
}
|
|
5074
5074
|
}
|
|
5075
5075
|
//#endregion
|
|
@@ -5390,7 +5390,7 @@ function profileToPolygon(profile, circleSegments = 32) {
|
|
|
5390
5390
|
//#region src/elementFns/beamFns.ts
|
|
5391
5391
|
function beamToSolid(spec) {
|
|
5392
5392
|
try {
|
|
5393
|
-
var _usingCtx$
|
|
5393
|
+
var _usingCtx$16 = _usingCtx();
|
|
5394
5394
|
if (spec.length <= 0) return (0, brepjs.err)(specError("BEAM_ZERO_LENGTH", "Beam length must be positive"));
|
|
5395
5395
|
if (isExtendedProfile(spec.profile)) try {
|
|
5396
5396
|
var _usingCtx3 = _usingCtx();
|
|
@@ -5425,7 +5425,7 @@ function beamToSolid(spec) {
|
|
|
5425
5425
|
py
|
|
5426
5426
|
]));
|
|
5427
5427
|
if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "BEAM_PROFILE_FAILED", "Failed to create beam profile"));
|
|
5428
|
-
const solidResult = (0, brepjs.extrude)(_usingCtx$
|
|
5428
|
+
const solidResult = (0, brepjs.extrude)(_usingCtx$16.u(profileResult.value), [
|
|
5429
5429
|
spec.length,
|
|
5430
5430
|
0,
|
|
5431
5431
|
0
|
|
@@ -5438,16 +5438,16 @@ function beamToSolid(spec) {
|
|
|
5438
5438
|
}
|
|
5439
5439
|
return (0, brepjs.ok)(solid);
|
|
5440
5440
|
} catch (_) {
|
|
5441
|
-
_usingCtx$
|
|
5441
|
+
_usingCtx$16.e = _;
|
|
5442
5442
|
} finally {
|
|
5443
|
-
_usingCtx$
|
|
5443
|
+
_usingCtx$16.d();
|
|
5444
5444
|
}
|
|
5445
5445
|
}
|
|
5446
5446
|
//#endregion
|
|
5447
5447
|
//#region src/elementFns/columnFns.ts
|
|
5448
5448
|
function columnToSolid(spec) {
|
|
5449
5449
|
try {
|
|
5450
|
-
var _usingCtx$
|
|
5450
|
+
var _usingCtx$15 = _usingCtx();
|
|
5451
5451
|
if (spec.height <= 0) return (0, brepjs.err)(specError("COLUMN_ZERO_HEIGHT", "Column height must be positive"));
|
|
5452
5452
|
if (isExtendedProfile(spec.profile)) try {
|
|
5453
5453
|
var _usingCtx3 = _usingCtx();
|
|
@@ -5475,7 +5475,7 @@ function columnToSolid(spec) {
|
|
|
5475
5475
|
const profilePts = profilePtsResult.value;
|
|
5476
5476
|
const profileResult = (0, brepjs.polygon)(profilePts);
|
|
5477
5477
|
if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "COLUMN_PROFILE_FAILED", "Failed to create column profile"));
|
|
5478
|
-
const solidResult = (0, brepjs.extrude)(_usingCtx$
|
|
5478
|
+
const solidResult = (0, brepjs.extrude)(_usingCtx$15.u(profileResult.value), [
|
|
5479
5479
|
0,
|
|
5480
5480
|
0,
|
|
5481
5481
|
spec.height
|
|
@@ -5488,9 +5488,9 @@ function columnToSolid(spec) {
|
|
|
5488
5488
|
}
|
|
5489
5489
|
return (0, brepjs.ok)(solid);
|
|
5490
5490
|
} catch (_) {
|
|
5491
|
-
_usingCtx$
|
|
5491
|
+
_usingCtx$15.e = _;
|
|
5492
5492
|
} finally {
|
|
5493
|
-
_usingCtx$
|
|
5493
|
+
_usingCtx$15.d();
|
|
5494
5494
|
}
|
|
5495
5495
|
}
|
|
5496
5496
|
//#endregion
|
|
@@ -5498,7 +5498,7 @@ function columnToSolid(spec) {
|
|
|
5498
5498
|
var EPSILON_MM$1 = 1;
|
|
5499
5499
|
function openingToSolid(spec, wallThickness) {
|
|
5500
5500
|
try {
|
|
5501
|
-
var _usingCtx$
|
|
5501
|
+
var _usingCtx$14 = _usingCtx();
|
|
5502
5502
|
if (spec.width <= 0) return (0, brepjs.err)(specError("OPENING_ZERO_WIDTH", "Opening width must be positive"));
|
|
5503
5503
|
if (spec.height <= 0) return (0, brepjs.err)(specError("OPENING_ZERO_HEIGHT", "Opening height must be positive"));
|
|
5504
5504
|
if (wallThickness <= 0) return (0, brepjs.err)(specError("OPENING_ZERO_WALL_THICKNESS", "Wall thickness must be positive"));
|
|
@@ -5530,7 +5530,7 @@ function openingToSolid(spec, wallThickness) {
|
|
|
5530
5530
|
]
|
|
5531
5531
|
]);
|
|
5532
5532
|
if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "OPENING_PROFILE_FAILED", "Failed to create opening profile"));
|
|
5533
|
-
const solidResult = (0, brepjs.extrude)(_usingCtx$
|
|
5533
|
+
const solidResult = (0, brepjs.extrude)(_usingCtx$14.u(profileResult.value), [
|
|
5534
5534
|
spec.width,
|
|
5535
5535
|
0,
|
|
5536
5536
|
0
|
|
@@ -5543,9 +5543,9 @@ function openingToSolid(spec, wallThickness) {
|
|
|
5543
5543
|
}
|
|
5544
5544
|
return (0, brepjs.ok)(solid);
|
|
5545
5545
|
} catch (_) {
|
|
5546
|
-
_usingCtx$
|
|
5546
|
+
_usingCtx$14.e = _;
|
|
5547
5547
|
} finally {
|
|
5548
|
-
_usingCtx$
|
|
5548
|
+
_usingCtx$14.d();
|
|
5549
5549
|
}
|
|
5550
5550
|
}
|
|
5551
5551
|
//#endregion
|
|
@@ -5553,7 +5553,7 @@ function openingToSolid(spec, wallThickness) {
|
|
|
5553
5553
|
var EPSILON_MM = 1;
|
|
5554
5554
|
function slabOpeningToSolid(spec, slabThickness) {
|
|
5555
5555
|
try {
|
|
5556
|
-
var _usingCtx$
|
|
5556
|
+
var _usingCtx$13 = _usingCtx();
|
|
5557
5557
|
if (spec.sizeX <= 0) return (0, brepjs.err)(specError("SLAB_OPENING_ZERO_SIZE_X", "Slab opening sizeX must be positive"));
|
|
5558
5558
|
if (spec.sizeY <= 0) return (0, brepjs.err)(specError("SLAB_OPENING_ZERO_SIZE_Y", "Slab opening sizeY must be positive"));
|
|
5559
5559
|
if (slabThickness <= 0) return (0, brepjs.err)(specError("SLAB_OPENING_ZERO_SLAB_THICKNESS", "Slab thickness must be positive"));
|
|
@@ -5585,7 +5585,7 @@ function slabOpeningToSolid(spec, slabThickness) {
|
|
|
5585
5585
|
]
|
|
5586
5586
|
]);
|
|
5587
5587
|
if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "SLAB_OPENING_PROFILE_FAILED", "Failed to create slab opening profile"));
|
|
5588
|
-
const solidResult = (0, brepjs.extrude)(_usingCtx$
|
|
5588
|
+
const solidResult = (0, brepjs.extrude)(_usingCtx$13.u(profileResult.value), [
|
|
5589
5589
|
0,
|
|
5590
5590
|
0,
|
|
5591
5591
|
slabThickness + 2 * EPSILON_MM
|
|
@@ -5598,16 +5598,16 @@ function slabOpeningToSolid(spec, slabThickness) {
|
|
|
5598
5598
|
}
|
|
5599
5599
|
return (0, brepjs.ok)(solid);
|
|
5600
5600
|
} catch (_) {
|
|
5601
|
-
_usingCtx$
|
|
5601
|
+
_usingCtx$13.e = _;
|
|
5602
5602
|
} finally {
|
|
5603
|
-
_usingCtx$
|
|
5603
|
+
_usingCtx$13.d();
|
|
5604
5604
|
}
|
|
5605
5605
|
}
|
|
5606
5606
|
//#endregion
|
|
5607
5607
|
//#region src/elementFns/spaceFns.ts
|
|
5608
5608
|
function spaceToSolid(spec) {
|
|
5609
5609
|
try {
|
|
5610
|
-
var _usingCtx$
|
|
5610
|
+
var _usingCtx$12 = _usingCtx();
|
|
5611
5611
|
if (spec.length <= 0) return (0, brepjs.err)(specError("SPACE_ZERO_LENGTH", "Space length must be positive"));
|
|
5612
5612
|
if (spec.width <= 0) return (0, brepjs.err)(specError("SPACE_ZERO_WIDTH", "Space width must be positive"));
|
|
5613
5613
|
if (spec.height <= 0) return (0, brepjs.err)(specError("SPACE_ZERO_HEIGHT", "Space height must be positive"));
|
|
@@ -5635,7 +5635,7 @@ function spaceToSolid(spec) {
|
|
|
5635
5635
|
]
|
|
5636
5636
|
]);
|
|
5637
5637
|
if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "SPACE_PROFILE_FAILED", "Failed to create space footprint"));
|
|
5638
|
-
const solidResult = (0, brepjs.extrude)(_usingCtx$
|
|
5638
|
+
const solidResult = (0, brepjs.extrude)(_usingCtx$12.u(profileResult.value), [
|
|
5639
5639
|
0,
|
|
5640
5640
|
0,
|
|
5641
5641
|
height
|
|
@@ -5648,21 +5648,26 @@ function spaceToSolid(spec) {
|
|
|
5648
5648
|
}
|
|
5649
5649
|
return (0, brepjs.ok)(solid);
|
|
5650
5650
|
} catch (_) {
|
|
5651
|
-
_usingCtx$
|
|
5651
|
+
_usingCtx$12.e = _;
|
|
5652
5652
|
} finally {
|
|
5653
|
-
_usingCtx$
|
|
5653
|
+
_usingCtx$12.d();
|
|
5654
5654
|
}
|
|
5655
5655
|
}
|
|
5656
5656
|
//#endregion
|
|
5657
5657
|
//#region src/elementFns/roofFns.ts
|
|
5658
|
-
|
|
5658
|
+
var DEG2RAD = Math.PI / 180;
|
|
5659
|
+
function gate(solid, code) {
|
|
5660
|
+
if (!(0, brepjs.isValidSolid)(solid)) {
|
|
5661
|
+
solid[Symbol.dispose]();
|
|
5662
|
+
return (0, brepjs.err)(geometryError(code, "Roof solid failed validity check"));
|
|
5663
|
+
}
|
|
5664
|
+
return (0, brepjs.ok)(solid);
|
|
5665
|
+
}
|
|
5666
|
+
function flatRoof(spec) {
|
|
5659
5667
|
try {
|
|
5660
|
-
var _usingCtx$
|
|
5661
|
-
if (spec.length <= 0) return (0, brepjs.err)(specError("ROOF_ZERO_LENGTH", "Roof length must be positive"));
|
|
5662
|
-
if (spec.width <= 0) return (0, brepjs.err)(specError("ROOF_ZERO_WIDTH", "Roof width must be positive"));
|
|
5663
|
-
if (spec.thickness <= 0) return (0, brepjs.err)(specError("ROOF_ZERO_THICKNESS", "Roof thickness must be positive"));
|
|
5668
|
+
var _usingCtx$11 = _usingCtx();
|
|
5664
5669
|
const { length, width, thickness } = spec;
|
|
5665
|
-
const
|
|
5670
|
+
const face = (0, brepjs.polygon)([
|
|
5666
5671
|
[
|
|
5667
5672
|
0,
|
|
5668
5673
|
0,
|
|
@@ -5684,30 +5689,212 @@ function roofToSolid(spec) {
|
|
|
5684
5689
|
0
|
|
5685
5690
|
]
|
|
5686
5691
|
]);
|
|
5687
|
-
if (!
|
|
5688
|
-
const
|
|
5692
|
+
if (!face.ok) return (0, brepjs.err)(fromBrepError(face.error, "ROOF_PROFILE_FAILED", "Failed to create roof profile"));
|
|
5693
|
+
const solid = (0, brepjs.extrude)(_usingCtx$11.u(face.value), [
|
|
5689
5694
|
0,
|
|
5690
5695
|
0,
|
|
5691
5696
|
thickness
|
|
5692
5697
|
]);
|
|
5693
|
-
if (!
|
|
5694
|
-
|
|
5695
|
-
if (!(0, brepjs.isValidSolid)(solid)) {
|
|
5696
|
-
solid[Symbol.dispose]();
|
|
5697
|
-
return (0, brepjs.err)(geometryError("ROOF_INVALID_SOLID", "Extruded roof solid failed validity check"));
|
|
5698
|
-
}
|
|
5699
|
-
return (0, brepjs.ok)(solid);
|
|
5698
|
+
if (!solid.ok) return (0, brepjs.err)(fromBrepError(solid.error, "ROOF_EXTRUDE_FAILED", "Failed to extrude roof profile"));
|
|
5699
|
+
return gate(solid.value, "ROOF_INVALID_SOLID");
|
|
5700
5700
|
} catch (_) {
|
|
5701
|
-
_usingCtx$
|
|
5701
|
+
_usingCtx$11.e = _;
|
|
5702
5702
|
} finally {
|
|
5703
|
-
_usingCtx$
|
|
5703
|
+
_usingCtx$11.d();
|
|
5704
|
+
}
|
|
5705
|
+
}
|
|
5706
|
+
function shedRoof(spec, pitch) {
|
|
5707
|
+
try {
|
|
5708
|
+
var _usingCtx3 = _usingCtx();
|
|
5709
|
+
const { length, width, thickness } = spec;
|
|
5710
|
+
const rise = width * Math.tan(pitch * DEG2RAD);
|
|
5711
|
+
const face = (0, brepjs.polygon)([
|
|
5712
|
+
[
|
|
5713
|
+
0,
|
|
5714
|
+
0,
|
|
5715
|
+
0
|
|
5716
|
+
],
|
|
5717
|
+
[
|
|
5718
|
+
0,
|
|
5719
|
+
width,
|
|
5720
|
+
0
|
|
5721
|
+
],
|
|
5722
|
+
[
|
|
5723
|
+
0,
|
|
5724
|
+
width,
|
|
5725
|
+
thickness + rise
|
|
5726
|
+
],
|
|
5727
|
+
[
|
|
5728
|
+
0,
|
|
5729
|
+
0,
|
|
5730
|
+
thickness
|
|
5731
|
+
]
|
|
5732
|
+
]);
|
|
5733
|
+
if (!face.ok) return (0, brepjs.err)(fromBrepError(face.error, "ROOF_PROFILE_FAILED", "Failed to create shed profile"));
|
|
5734
|
+
const solid = (0, brepjs.extrude)(_usingCtx3.u(face.value), [
|
|
5735
|
+
length,
|
|
5736
|
+
0,
|
|
5737
|
+
0
|
|
5738
|
+
]);
|
|
5739
|
+
if (!solid.ok) return (0, brepjs.err)(fromBrepError(solid.error, "ROOF_EXTRUDE_FAILED", "Failed to extrude shed roof"));
|
|
5740
|
+
return gate(solid.value, "ROOF_INVALID_SOLID");
|
|
5741
|
+
} catch (_) {
|
|
5742
|
+
_usingCtx3.e = _;
|
|
5743
|
+
} finally {
|
|
5744
|
+
_usingCtx3.d();
|
|
5745
|
+
}
|
|
5746
|
+
}
|
|
5747
|
+
function gableRoof(spec, pitch) {
|
|
5748
|
+
try {
|
|
5749
|
+
var _usingCtx4 = _usingCtx();
|
|
5750
|
+
const { length, width, thickness } = spec;
|
|
5751
|
+
const ridge = width / 2 * Math.tan(pitch * DEG2RAD);
|
|
5752
|
+
const face = (0, brepjs.polygon)([
|
|
5753
|
+
[
|
|
5754
|
+
0,
|
|
5755
|
+
0,
|
|
5756
|
+
0
|
|
5757
|
+
],
|
|
5758
|
+
[
|
|
5759
|
+
0,
|
|
5760
|
+
width,
|
|
5761
|
+
0
|
|
5762
|
+
],
|
|
5763
|
+
[
|
|
5764
|
+
0,
|
|
5765
|
+
width,
|
|
5766
|
+
thickness
|
|
5767
|
+
],
|
|
5768
|
+
[
|
|
5769
|
+
0,
|
|
5770
|
+
width / 2,
|
|
5771
|
+
thickness + ridge
|
|
5772
|
+
],
|
|
5773
|
+
[
|
|
5774
|
+
0,
|
|
5775
|
+
0,
|
|
5776
|
+
thickness
|
|
5777
|
+
]
|
|
5778
|
+
]);
|
|
5779
|
+
if (!face.ok) return (0, brepjs.err)(fromBrepError(face.error, "ROOF_PROFILE_FAILED", "Failed to create gable profile"));
|
|
5780
|
+
const solid = (0, brepjs.extrude)(_usingCtx4.u(face.value), [
|
|
5781
|
+
length,
|
|
5782
|
+
0,
|
|
5783
|
+
0
|
|
5784
|
+
]);
|
|
5785
|
+
if (!solid.ok) return (0, brepjs.err)(fromBrepError(solid.error, "ROOF_EXTRUDE_FAILED", "Failed to extrude gable roof"));
|
|
5786
|
+
return gate(solid.value, "ROOF_INVALID_SOLID");
|
|
5787
|
+
} catch (_) {
|
|
5788
|
+
_usingCtx4.e = _;
|
|
5789
|
+
} finally {
|
|
5790
|
+
_usingCtx4.d();
|
|
5791
|
+
}
|
|
5792
|
+
}
|
|
5793
|
+
function hipRoof(spec, pitch) {
|
|
5794
|
+
const { length: l, width: w } = spec;
|
|
5795
|
+
const tan = Math.tan(pitch * DEG2RAD);
|
|
5796
|
+
const base = [
|
|
5797
|
+
[
|
|
5798
|
+
0,
|
|
5799
|
+
0,
|
|
5800
|
+
0
|
|
5801
|
+
],
|
|
5802
|
+
[
|
|
5803
|
+
l,
|
|
5804
|
+
0,
|
|
5805
|
+
0
|
|
5806
|
+
],
|
|
5807
|
+
[
|
|
5808
|
+
l,
|
|
5809
|
+
w,
|
|
5810
|
+
0
|
|
5811
|
+
],
|
|
5812
|
+
[
|
|
5813
|
+
0,
|
|
5814
|
+
w,
|
|
5815
|
+
0
|
|
5816
|
+
]
|
|
5817
|
+
];
|
|
5818
|
+
let ridge;
|
|
5819
|
+
if (l >= w) {
|
|
5820
|
+
const h = w / 2 * tan;
|
|
5821
|
+
ridge = [[
|
|
5822
|
+
w / 2,
|
|
5823
|
+
w / 2,
|
|
5824
|
+
h
|
|
5825
|
+
], [
|
|
5826
|
+
l - w / 2,
|
|
5827
|
+
w / 2,
|
|
5828
|
+
h
|
|
5829
|
+
]];
|
|
5830
|
+
} else {
|
|
5831
|
+
const h = l / 2 * tan;
|
|
5832
|
+
ridge = [[
|
|
5833
|
+
l / 2,
|
|
5834
|
+
l / 2,
|
|
5835
|
+
h
|
|
5836
|
+
], [
|
|
5837
|
+
l / 2,
|
|
5838
|
+
w - l / 2,
|
|
5839
|
+
h
|
|
5840
|
+
]];
|
|
5841
|
+
}
|
|
5842
|
+
const solid = (0, brepjs.convexHull)([...base, ...ridge]);
|
|
5843
|
+
if (!solid.ok) return (0, brepjs.err)(fromBrepError(solid.error, "ROOF_HIP_FAILED", "Failed to build hip roof"));
|
|
5844
|
+
return gate(solid.value, "ROOF_INVALID_SOLID");
|
|
5845
|
+
}
|
|
5846
|
+
function domeRoof(spec) {
|
|
5847
|
+
const { length, width } = spec;
|
|
5848
|
+
const r = Math.min(length, width) / 2;
|
|
5849
|
+
const cx = length / 2;
|
|
5850
|
+
const cy = width / 2;
|
|
5851
|
+
const segments = 24;
|
|
5852
|
+
const rings = [
|
|
5853
|
+
0,
|
|
5854
|
+
.4,
|
|
5855
|
+
.7,
|
|
5856
|
+
.9
|
|
5857
|
+
];
|
|
5858
|
+
const pts = [];
|
|
5859
|
+
for (const h of rings) {
|
|
5860
|
+
const z = r * h;
|
|
5861
|
+
const ringR = r * Math.sqrt(1 - h * h);
|
|
5862
|
+
for (let i = 0; i < segments; i++) {
|
|
5863
|
+
const a = 2 * Math.PI * i / segments;
|
|
5864
|
+
pts.push([
|
|
5865
|
+
cx + ringR * Math.cos(a),
|
|
5866
|
+
cy + ringR * Math.sin(a),
|
|
5867
|
+
z
|
|
5868
|
+
]);
|
|
5869
|
+
}
|
|
5870
|
+
}
|
|
5871
|
+
pts.push([
|
|
5872
|
+
cx,
|
|
5873
|
+
cy,
|
|
5874
|
+
r
|
|
5875
|
+
]);
|
|
5876
|
+
const solid = (0, brepjs.convexHull)(pts);
|
|
5877
|
+
if (!solid.ok) return (0, brepjs.err)(fromBrepError(solid.error, "ROOF_DOME_FAILED", "Failed to build dome roof"));
|
|
5878
|
+
return gate(solid.value, "ROOF_INVALID_SOLID");
|
|
5879
|
+
}
|
|
5880
|
+
function roofToSolid(spec) {
|
|
5881
|
+
if (spec.length <= 0) return (0, brepjs.err)(specError("ROOF_ZERO_LENGTH", "Roof length must be positive"));
|
|
5882
|
+
if (spec.width <= 0) return (0, brepjs.err)(specError("ROOF_ZERO_WIDTH", "Roof width must be positive"));
|
|
5883
|
+
if (spec.thickness <= 0) return (0, brepjs.err)(specError("ROOF_ZERO_THICKNESS", "Roof thickness must be positive"));
|
|
5884
|
+
if (spec.pitch === void 0) return flatRoof(spec);
|
|
5885
|
+
switch (spec.predefinedType) {
|
|
5886
|
+
case "SHED_ROOF": return shedRoof(spec, spec.pitch);
|
|
5887
|
+
case "GABLE_ROOF": return gableRoof(spec, spec.pitch);
|
|
5888
|
+
case "HIP_ROOF": return hipRoof(spec, spec.pitch);
|
|
5889
|
+
case "DOME_ROOF": return domeRoof(spec);
|
|
5890
|
+
default: return flatRoof(spec);
|
|
5704
5891
|
}
|
|
5705
5892
|
}
|
|
5706
5893
|
//#endregion
|
|
5707
5894
|
//#region src/elementFns/curtainWallFns.ts
|
|
5708
5895
|
function boxSolid(sizeX, sizeY, sizeZ) {
|
|
5709
5896
|
try {
|
|
5710
|
-
var _usingCtx$
|
|
5897
|
+
var _usingCtx$10 = _usingCtx();
|
|
5711
5898
|
const profileResult = (0, brepjs.polygon)([
|
|
5712
5899
|
[
|
|
5713
5900
|
0,
|
|
@@ -5731,7 +5918,7 @@ function boxSolid(sizeX, sizeY, sizeZ) {
|
|
|
5731
5918
|
]
|
|
5732
5919
|
]);
|
|
5733
5920
|
if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "CURTAIN_WALL_PROFILE_FAILED", "Failed to create component profile"));
|
|
5734
|
-
const solidResult = (0, brepjs.extrude)(_usingCtx$
|
|
5921
|
+
const solidResult = (0, brepjs.extrude)(_usingCtx$10.u(profileResult.value), [
|
|
5735
5922
|
0,
|
|
5736
5923
|
0,
|
|
5737
5924
|
sizeZ
|
|
@@ -5744,9 +5931,9 @@ function boxSolid(sizeX, sizeY, sizeZ) {
|
|
|
5744
5931
|
}
|
|
5745
5932
|
return (0, brepjs.ok)(solid);
|
|
5746
5933
|
} catch (_) {
|
|
5747
|
-
_usingCtx$
|
|
5934
|
+
_usingCtx$10.e = _;
|
|
5748
5935
|
} finally {
|
|
5749
|
-
_usingCtx$
|
|
5936
|
+
_usingCtx$10.d();
|
|
5750
5937
|
}
|
|
5751
5938
|
}
|
|
5752
5939
|
function disposeComponents(components) {
|
|
@@ -5845,7 +6032,7 @@ function curtainWallToGrid(spec) {
|
|
|
5845
6032
|
//#region src/elementFns/foundationFns.ts
|
|
5846
6033
|
function footingToSolid(spec) {
|
|
5847
6034
|
try {
|
|
5848
|
-
var _usingCtx$
|
|
6035
|
+
var _usingCtx$9 = _usingCtx();
|
|
5849
6036
|
if (spec.length <= 0) return (0, brepjs.err)(specError("FOOTING_ZERO_LENGTH", "Footing length must be positive"));
|
|
5850
6037
|
if (spec.width <= 0) return (0, brepjs.err)(specError("FOOTING_ZERO_WIDTH", "Footing width must be positive"));
|
|
5851
6038
|
if (spec.thickness <= 0) return (0, brepjs.err)(specError("FOOTING_ZERO_THICKNESS", "Footing thickness must be positive"));
|
|
@@ -5873,7 +6060,7 @@ function footingToSolid(spec) {
|
|
|
5873
6060
|
]
|
|
5874
6061
|
]);
|
|
5875
6062
|
if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "FOOTING_PROFILE_FAILED", "Failed to create footing profile"));
|
|
5876
|
-
const solidResult = (0, brepjs.extrude)(_usingCtx$
|
|
6063
|
+
const solidResult = (0, brepjs.extrude)(_usingCtx$9.u(profileResult.value), [
|
|
5877
6064
|
0,
|
|
5878
6065
|
0,
|
|
5879
6066
|
thickness
|
|
@@ -5886,9 +6073,9 @@ function footingToSolid(spec) {
|
|
|
5886
6073
|
}
|
|
5887
6074
|
return (0, brepjs.ok)(solid);
|
|
5888
6075
|
} catch (_) {
|
|
5889
|
-
_usingCtx$
|
|
6076
|
+
_usingCtx$9.e = _;
|
|
5890
6077
|
} finally {
|
|
5891
|
-
_usingCtx$
|
|
6078
|
+
_usingCtx$9.d();
|
|
5892
6079
|
}
|
|
5893
6080
|
}
|
|
5894
6081
|
function pileToSolid(spec) {
|
|
@@ -5941,12 +6128,9 @@ function pileToSolid(spec) {
|
|
|
5941
6128
|
}
|
|
5942
6129
|
//#endregion
|
|
5943
6130
|
//#region src/elementFns/railingFns.ts
|
|
5944
|
-
function
|
|
6131
|
+
function panelRailing(spec) {
|
|
5945
6132
|
try {
|
|
5946
|
-
var _usingCtx$
|
|
5947
|
-
if (spec.length <= 0) return (0, brepjs.err)(specError("RAILING_ZERO_LENGTH", "Railing length must be positive"));
|
|
5948
|
-
if (spec.height <= 0) return (0, brepjs.err)(specError("RAILING_ZERO_HEIGHT", "Railing height must be positive"));
|
|
5949
|
-
if (spec.thickness <= 0) return (0, brepjs.err)(specError("RAILING_ZERO_THICKNESS", "Railing thickness must be positive"));
|
|
6133
|
+
var _usingCtx$8 = _usingCtx();
|
|
5950
6134
|
const { length, height, thickness } = spec;
|
|
5951
6135
|
const profileResult = (0, brepjs.polygon)([
|
|
5952
6136
|
[
|
|
@@ -5971,7 +6155,7 @@ function railingToSolid(spec) {
|
|
|
5971
6155
|
]
|
|
5972
6156
|
]);
|
|
5973
6157
|
if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "RAILING_PROFILE_FAILED", "Failed to create railing profile"));
|
|
5974
|
-
const solidResult = (0, brepjs.extrude)(_usingCtx$
|
|
6158
|
+
const solidResult = (0, brepjs.extrude)(_usingCtx$8.u(profileResult.value), [
|
|
5975
6159
|
length,
|
|
5976
6160
|
0,
|
|
5977
6161
|
0
|
|
@@ -5984,16 +6168,72 @@ function railingToSolid(spec) {
|
|
|
5984
6168
|
}
|
|
5985
6169
|
return (0, brepjs.ok)(solid);
|
|
5986
6170
|
} catch (_) {
|
|
5987
|
-
_usingCtx$
|
|
6171
|
+
_usingCtx$8.e = _;
|
|
5988
6172
|
} finally {
|
|
5989
|
-
_usingCtx$
|
|
6173
|
+
_usingCtx$8.d();
|
|
6174
|
+
}
|
|
6175
|
+
}
|
|
6176
|
+
function postedRailing(spec) {
|
|
6177
|
+
const { length, height, thickness: t } = spec;
|
|
6178
|
+
const boxes = [];
|
|
6179
|
+
const postCount = Math.max(2, Math.round(length / 1e3) + 1);
|
|
6180
|
+
for (let i = 0; i < postCount; i++) {
|
|
6181
|
+
const x = t / 2 + (length - t) * (i / (postCount - 1));
|
|
6182
|
+
boxes.push((0, brepjs.box)(t, t, height, {
|
|
6183
|
+
at: [
|
|
6184
|
+
x,
|
|
6185
|
+
t / 2,
|
|
6186
|
+
height / 2
|
|
6187
|
+
],
|
|
6188
|
+
centered: true
|
|
6189
|
+
}));
|
|
6190
|
+
}
|
|
6191
|
+
for (const z of [height - t / 2, t / 2]) boxes.push((0, brepjs.box)(length, t, t, {
|
|
6192
|
+
at: [
|
|
6193
|
+
length / 2,
|
|
6194
|
+
t / 2,
|
|
6195
|
+
z
|
|
6196
|
+
],
|
|
6197
|
+
centered: true
|
|
6198
|
+
}));
|
|
6199
|
+
const scratch = [...boxes];
|
|
6200
|
+
let acc;
|
|
6201
|
+
let failure;
|
|
6202
|
+
for (const b of boxes) {
|
|
6203
|
+
if (acc === void 0) {
|
|
6204
|
+
acc = b;
|
|
6205
|
+
continue;
|
|
6206
|
+
}
|
|
6207
|
+
const fused = (0, brepjs.fuse)(acc, b);
|
|
6208
|
+
if (!fused.ok) {
|
|
6209
|
+
failure = fromBrepError(fused.error, "RAILING_FUSE_FAILED", "Failed to fuse railing parts");
|
|
6210
|
+
break;
|
|
6211
|
+
}
|
|
6212
|
+
acc = fused.value;
|
|
6213
|
+
scratch.push(acc);
|
|
5990
6214
|
}
|
|
6215
|
+
const survivor = failure ? void 0 : acc;
|
|
6216
|
+
for (const s of scratch) if (s !== survivor) s[Symbol.dispose]();
|
|
6217
|
+
if (failure) return (0, brepjs.err)(failure);
|
|
6218
|
+
if (survivor === void 0) return (0, brepjs.err)(geometryError("RAILING_INVALID_SOLID", "Posted railing produced no solid"));
|
|
6219
|
+
const result = survivor;
|
|
6220
|
+
if (!(0, brepjs.isValidSolid)(result)) {
|
|
6221
|
+
result[Symbol.dispose]();
|
|
6222
|
+
return (0, brepjs.err)(geometryError("RAILING_INVALID_SOLID", "Posted railing solid failed validity check"));
|
|
6223
|
+
}
|
|
6224
|
+
return (0, brepjs.ok)(result);
|
|
6225
|
+
}
|
|
6226
|
+
function railingToSolid(spec) {
|
|
6227
|
+
if (spec.length <= 0) return (0, brepjs.err)(specError("RAILING_ZERO_LENGTH", "Railing length must be positive"));
|
|
6228
|
+
if (spec.height <= 0) return (0, brepjs.err)(specError("RAILING_ZERO_HEIGHT", "Railing height must be positive"));
|
|
6229
|
+
if (spec.thickness <= 0) return (0, brepjs.err)(specError("RAILING_ZERO_THICKNESS", "Railing thickness must be positive"));
|
|
6230
|
+
return spec.infill === "POSTED" ? postedRailing(spec) : panelRailing(spec);
|
|
5991
6231
|
}
|
|
5992
6232
|
//#endregion
|
|
5993
6233
|
//#region src/elementFns/coveringFns.ts
|
|
5994
6234
|
function coveringToSolid(spec) {
|
|
5995
6235
|
try {
|
|
5996
|
-
var _usingCtx$
|
|
6236
|
+
var _usingCtx$7 = _usingCtx();
|
|
5997
6237
|
if (spec.length <= 0) return (0, brepjs.err)(specError("COVERING_ZERO_LENGTH", "Covering length must be positive"));
|
|
5998
6238
|
if (spec.width <= 0) return (0, brepjs.err)(specError("COVERING_ZERO_WIDTH", "Covering width must be positive"));
|
|
5999
6239
|
if (spec.thickness <= 0) return (0, brepjs.err)(specError("COVERING_ZERO_THICKNESS", "Covering thickness must be positive"));
|
|
@@ -6021,7 +6261,7 @@ function coveringToSolid(spec) {
|
|
|
6021
6261
|
]
|
|
6022
6262
|
]);
|
|
6023
6263
|
if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "COVERING_PROFILE_FAILED", "Failed to create covering profile"));
|
|
6024
|
-
const solidResult = (0, brepjs.extrude)(_usingCtx$
|
|
6264
|
+
const solidResult = (0, brepjs.extrude)(_usingCtx$7.u(profileResult.value), [
|
|
6025
6265
|
0,
|
|
6026
6266
|
0,
|
|
6027
6267
|
thickness
|
|
@@ -6034,9 +6274,9 @@ function coveringToSolid(spec) {
|
|
|
6034
6274
|
}
|
|
6035
6275
|
return (0, brepjs.ok)(solid);
|
|
6036
6276
|
} catch (_) {
|
|
6037
|
-
_usingCtx$
|
|
6277
|
+
_usingCtx$7.e = _;
|
|
6038
6278
|
} finally {
|
|
6039
|
-
_usingCtx$
|
|
6279
|
+
_usingCtx$7.d();
|
|
6040
6280
|
}
|
|
6041
6281
|
}
|
|
6042
6282
|
//#endregion
|
|
@@ -6466,17 +6706,17 @@ var BimModel = class {
|
|
|
6466
6706
|
}
|
|
6467
6707
|
#cutWallGeometry(wall, openingSpec) {
|
|
6468
6708
|
try {
|
|
6469
|
-
var _usingCtx$
|
|
6709
|
+
var _usingCtx$6 = _usingCtx();
|
|
6470
6710
|
const toolResult = openingToSolid(openingSpec, wall.spec.thickness);
|
|
6471
6711
|
if (!toolResult.ok) return (0, brepjs.err)(toolResult.error);
|
|
6472
|
-
const tool = _usingCtx$
|
|
6712
|
+
const tool = _usingCtx$6.u(toolResult.value);
|
|
6473
6713
|
const cutResult = (0, brepjs.cut)(wall.geometry, tool);
|
|
6474
6714
|
if (!cutResult.ok) return (0, brepjs.err)(fromBrepError(cutResult.error, "WALL_CUT_FAILED", "Boolean cut of wall with opening failed"));
|
|
6475
6715
|
return (0, brepjs.ok)(cutResult.value);
|
|
6476
6716
|
} catch (_) {
|
|
6477
|
-
_usingCtx$
|
|
6717
|
+
_usingCtx$6.e = _;
|
|
6478
6718
|
} finally {
|
|
6479
|
-
_usingCtx$
|
|
6719
|
+
_usingCtx$6.d();
|
|
6480
6720
|
}
|
|
6481
6721
|
}
|
|
6482
6722
|
#replaceWallGeometry(wall, newGeometry) {
|
|
@@ -6713,18 +6953,365 @@ var BimModel = class {
|
|
|
6713
6953
|
this.#elements.set(localId, el);
|
|
6714
6954
|
return localId;
|
|
6715
6955
|
}
|
|
6716
|
-
#makeRel(fields) {
|
|
6717
|
-
const localId = this.#counter.next();
|
|
6718
|
-
const guid = deriveIfcGuidSync(makeRelKey(this.#modelScope, fields.kind, localId));
|
|
6719
|
-
const rel = {
|
|
6720
|
-
...fields,
|
|
6721
|
-
guid,
|
|
6722
|
-
localId
|
|
6723
|
-
};
|
|
6724
|
-
this.#relationships.set(localId, rel);
|
|
6725
|
-
return localId;
|
|
6956
|
+
#makeRel(fields) {
|
|
6957
|
+
const localId = this.#counter.next();
|
|
6958
|
+
const guid = deriveIfcGuidSync(makeRelKey(this.#modelScope, fields.kind, localId));
|
|
6959
|
+
const rel = {
|
|
6960
|
+
...fields,
|
|
6961
|
+
guid,
|
|
6962
|
+
localId
|
|
6963
|
+
};
|
|
6964
|
+
this.#relationships.set(localId, rel);
|
|
6965
|
+
return localId;
|
|
6966
|
+
}
|
|
6967
|
+
};
|
|
6968
|
+
//#endregion
|
|
6969
|
+
//#region src/import/placement.ts
|
|
6970
|
+
/**
|
|
6971
|
+
* Metres-per-file-unit length scale read from the IfcUnitAssignment's
|
|
6972
|
+
* LENGTHUNIT. Multiply a file-unit length by this to get metres, then by 1000
|
|
6973
|
+
* for brepjs millimetres. Returns 1.0 (assume metres) when no length unit is
|
|
6974
|
+
* declared.
|
|
6975
|
+
*/
|
|
6976
|
+
function readLengthScale(reader) {
|
|
6977
|
+
const assignments = reader.getLinesOfType(web_ifc.IFCUNITASSIGNMENT);
|
|
6978
|
+
for (const assignmentId of assignments) {
|
|
6979
|
+
const units = asRefArray$1(reader.getLine(assignmentId)?.["Units"]);
|
|
6980
|
+
for (const unitId of units) {
|
|
6981
|
+
const scale = lengthScaleFromUnit(reader, unitId);
|
|
6982
|
+
if (scale !== null) return scale;
|
|
6983
|
+
}
|
|
6984
|
+
}
|
|
6985
|
+
return 1;
|
|
6986
|
+
}
|
|
6987
|
+
/**
|
|
6988
|
+
* Radians-per-file-unit plane-angle scale read from the IfcUnitAssignment's
|
|
6989
|
+
* PLANEANGLEUNIT (1 for RADIAN, ~0.0174533 for DEGREE). Defaults to 1 (the IFC
|
|
6990
|
+
* default plane-angle unit is the radian).
|
|
6991
|
+
*/
|
|
6992
|
+
function readPlaneAngleScale(reader) {
|
|
6993
|
+
for (const assignmentId of reader.getLinesOfType(web_ifc.IFCUNITASSIGNMENT)) {
|
|
6994
|
+
const units = asRefArray$1(reader.getLine(assignmentId)?.["Units"]);
|
|
6995
|
+
for (const unitId of units) {
|
|
6996
|
+
const s = planeAngleScaleFromUnit(reader, unitId);
|
|
6997
|
+
if (s !== null) return s;
|
|
6998
|
+
}
|
|
6999
|
+
}
|
|
7000
|
+
return 1;
|
|
7001
|
+
}
|
|
7002
|
+
function planeAngleScaleFromUnit(reader, unitId) {
|
|
7003
|
+
const unit = reader.getLine(unitId);
|
|
7004
|
+
if (unit === null) return null;
|
|
7005
|
+
const type = reader.getLineType(unitId);
|
|
7006
|
+
if (type === web_ifc.IFCSIUNIT) {
|
|
7007
|
+
if (enumValue(unit["UnitType"]) !== "PLANEANGLEUNIT") return null;
|
|
7008
|
+
if (enumValue(unit["Name"]) !== "RADIAN") return null;
|
|
7009
|
+
return 1;
|
|
7010
|
+
}
|
|
7011
|
+
if (type === web_ifc.IFCCONVERSIONBASEDUNIT) {
|
|
7012
|
+
if (enumValue(unit["UnitType"]) !== "PLANEANGLEUNIT") return null;
|
|
7013
|
+
const measureId = refValue$2(unit["ConversionFactor"]);
|
|
7014
|
+
if (measureId === null) return null;
|
|
7015
|
+
const factor = numericValue(reader.getLine(measureId)?.["ValueComponent"]);
|
|
7016
|
+
if (factor === null) return null;
|
|
7017
|
+
return factor;
|
|
7018
|
+
}
|
|
7019
|
+
return null;
|
|
7020
|
+
}
|
|
7021
|
+
function lengthScaleFromUnit(reader, unitId) {
|
|
7022
|
+
const unit = reader.getLine(unitId);
|
|
7023
|
+
if (unit === null) return null;
|
|
7024
|
+
const type = reader.getLineType(unitId);
|
|
7025
|
+
if (type === web_ifc.IFCSIUNIT) {
|
|
7026
|
+
if (enumValue(unit["UnitType"]) !== "LENGTHUNIT") return null;
|
|
7027
|
+
if (enumValue(unit["Name"]) !== "METRE") return null;
|
|
7028
|
+
return siPrefixFactor(enumValue(unit["Prefix"]));
|
|
7029
|
+
}
|
|
7030
|
+
if (type === web_ifc.IFCCONVERSIONBASEDUNIT) {
|
|
7031
|
+
if (enumValue(unit["UnitType"]) !== "LENGTHUNIT") return null;
|
|
7032
|
+
const measureId = refValue$2(unit["ConversionFactor"]);
|
|
7033
|
+
if (measureId === null) return null;
|
|
7034
|
+
const measure = reader.getLine(measureId);
|
|
7035
|
+
const factor = numericValue(measure?.["ValueComponent"]);
|
|
7036
|
+
if (factor === null) return null;
|
|
7037
|
+
const baseId = refValue$2(measure?.["UnitComponent"]);
|
|
7038
|
+
return factor * (baseId !== null ? lengthScaleFromUnit(reader, baseId) ?? 1 : 1);
|
|
7039
|
+
}
|
|
7040
|
+
return null;
|
|
7041
|
+
}
|
|
7042
|
+
function siPrefixFactor(prefix) {
|
|
7043
|
+
switch (prefix) {
|
|
7044
|
+
case null: return 1;
|
|
7045
|
+
case "KILO": return 1e3;
|
|
7046
|
+
case "HECTO": return 100;
|
|
7047
|
+
case "DECA": return 10;
|
|
7048
|
+
case "DECI": return .1;
|
|
7049
|
+
case "CENTI": return .01;
|
|
7050
|
+
case "MILLI": return .001;
|
|
7051
|
+
case "MICRO": return 1e-6;
|
|
7052
|
+
default: return 1;
|
|
7053
|
+
}
|
|
7054
|
+
}
|
|
7055
|
+
/**
|
|
7056
|
+
* Builds a row-major MatrixTransform (for brepjs `applyMatrix`) from an
|
|
7057
|
+
* (origin, axisX, axisZ) frame, using the SAME IFC orthonormalization as
|
|
7058
|
+
* {@link readAxis2Placement3D}: z = normalize(axisZ); x = normalize(axisX
|
|
7059
|
+
* projected onto the plane ⊥ z); y = z × x. The basis vectors are the matrix
|
|
7060
|
+
* columns, so the row-major linear array is [Xx,Yx,Zx, Xy,Yy,Zy, Xz,Yz,Zz];
|
|
7061
|
+
* translation = origin (mm). This is the display-side counterpart to the IFC
|
|
7062
|
+
* writer's Axis2Placement3D (Axis=Z, RefDirection=X) so on-screen placement and
|
|
7063
|
+
* the IFC export agree.
|
|
7064
|
+
*/
|
|
7065
|
+
function placementToMatrix(f) {
|
|
7066
|
+
const z = normalize$1(f.axisZ);
|
|
7067
|
+
const dot = z[0] * f.axisX[0] + z[1] * f.axisX[1] + z[2] * f.axisX[2];
|
|
7068
|
+
const projX = [
|
|
7069
|
+
f.axisX[0] - dot * z[0],
|
|
7070
|
+
f.axisX[1] - dot * z[1],
|
|
7071
|
+
f.axisX[2] - dot * z[2]
|
|
7072
|
+
];
|
|
7073
|
+
const x = lengthSq(projX) < 1e-12 ? normalize$1(orthogonal$2(z)) : normalize$1(projX);
|
|
7074
|
+
const y = cross$1(z, x);
|
|
7075
|
+
return {
|
|
7076
|
+
linear: [
|
|
7077
|
+
x[0],
|
|
7078
|
+
y[0],
|
|
7079
|
+
z[0],
|
|
7080
|
+
x[1],
|
|
7081
|
+
y[1],
|
|
7082
|
+
z[1],
|
|
7083
|
+
x[2],
|
|
7084
|
+
y[2],
|
|
7085
|
+
z[2]
|
|
7086
|
+
],
|
|
7087
|
+
translation: [
|
|
7088
|
+
f.origin[0],
|
|
7089
|
+
f.origin[1],
|
|
7090
|
+
f.origin[2]
|
|
7091
|
+
]
|
|
7092
|
+
};
|
|
7093
|
+
}
|
|
7094
|
+
function cross$1(a, b) {
|
|
7095
|
+
return [
|
|
7096
|
+
a[1] * b[2] - a[2] * b[1],
|
|
7097
|
+
a[2] * b[0] - a[0] * b[2],
|
|
7098
|
+
a[0] * b[1] - a[1] * b[0]
|
|
7099
|
+
];
|
|
7100
|
+
}
|
|
7101
|
+
function lengthSq(v) {
|
|
7102
|
+
return v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
|
|
7103
|
+
}
|
|
7104
|
+
function normalize$1(v) {
|
|
7105
|
+
const len = Math.sqrt(lengthSq(v));
|
|
7106
|
+
if (len < 1e-12) return [
|
|
7107
|
+
0,
|
|
7108
|
+
0,
|
|
7109
|
+
1
|
|
7110
|
+
];
|
|
7111
|
+
return [
|
|
7112
|
+
v[0] / len,
|
|
7113
|
+
v[1] / len,
|
|
7114
|
+
v[2] / len
|
|
7115
|
+
];
|
|
7116
|
+
}
|
|
7117
|
+
function orthogonal$2(v) {
|
|
7118
|
+
return Math.abs(v[0]) < .9 ? cross$1(v, [
|
|
7119
|
+
1,
|
|
7120
|
+
0,
|
|
7121
|
+
0
|
|
7122
|
+
]) : cross$1(v, [
|
|
7123
|
+
0,
|
|
7124
|
+
1,
|
|
7125
|
+
0
|
|
7126
|
+
]);
|
|
7127
|
+
}
|
|
7128
|
+
function refValue$2(v) {
|
|
7129
|
+
if (v === null || v === void 0) return null;
|
|
7130
|
+
if (typeof v === "number") return v;
|
|
7131
|
+
const value = v.value;
|
|
7132
|
+
return typeof value === "number" ? value : null;
|
|
7133
|
+
}
|
|
7134
|
+
function asRefArray$1(v) {
|
|
7135
|
+
if (!Array.isArray(v)) return [];
|
|
7136
|
+
const out = [];
|
|
7137
|
+
for (const item of v) {
|
|
7138
|
+
const id = refValue$2(item);
|
|
7139
|
+
if (id !== null) out.push(id);
|
|
7140
|
+
}
|
|
7141
|
+
return out;
|
|
7142
|
+
}
|
|
7143
|
+
function numericValue(v) {
|
|
7144
|
+
if (typeof v === "number") return v;
|
|
7145
|
+
if (v === null || v === void 0) return null;
|
|
7146
|
+
const value = v.value;
|
|
7147
|
+
return typeof value === "number" ? value : null;
|
|
7148
|
+
}
|
|
7149
|
+
function enumValue(v) {
|
|
7150
|
+
if (typeof v === "string") return v;
|
|
7151
|
+
if (v === null || v === void 0) return null;
|
|
7152
|
+
const value = v.value;
|
|
7153
|
+
return typeof value === "string" ? value : null;
|
|
7154
|
+
}
|
|
7155
|
+
//#endregion
|
|
7156
|
+
//#region src/elementFns/stairFns.ts
|
|
7157
|
+
function buildSilhouette$1(numberOfRisers, riserHeight, treadLength) {
|
|
7158
|
+
const pts = [];
|
|
7159
|
+
pts.push([
|
|
7160
|
+
0,
|
|
7161
|
+
0,
|
|
7162
|
+
0
|
|
7163
|
+
]);
|
|
7164
|
+
let x = 0;
|
|
7165
|
+
let z = 0;
|
|
7166
|
+
for (let i = 0; i < numberOfRisers; i++) {
|
|
7167
|
+
z += riserHeight;
|
|
7168
|
+
pts.push([
|
|
7169
|
+
x,
|
|
7170
|
+
0,
|
|
7171
|
+
z
|
|
7172
|
+
]);
|
|
7173
|
+
x += treadLength;
|
|
7174
|
+
pts.push([
|
|
7175
|
+
x,
|
|
7176
|
+
0,
|
|
7177
|
+
z
|
|
7178
|
+
]);
|
|
7179
|
+
}
|
|
7180
|
+
pts.push([
|
|
7181
|
+
x,
|
|
7182
|
+
0,
|
|
7183
|
+
0
|
|
7184
|
+
]);
|
|
7185
|
+
return pts;
|
|
7186
|
+
}
|
|
7187
|
+
function stairFlightToSolid(spec) {
|
|
7188
|
+
try {
|
|
7189
|
+
var _usingCtx$5 = _usingCtx();
|
|
7190
|
+
if (spec.width <= 0) return (0, brepjs.err)(specError("STAIR_FLIGHT_ZERO_WIDTH", "Stair flight width must be positive"));
|
|
7191
|
+
if (spec.riserHeight <= 0) return (0, brepjs.err)(specError("STAIR_FLIGHT_ZERO_RISER", "Stair flight riserHeight must be positive"));
|
|
7192
|
+
if (spec.treadLength <= 0) return (0, brepjs.err)(specError("STAIR_FLIGHT_ZERO_TREAD", "Stair flight treadLength must be positive"));
|
|
7193
|
+
if (!Number.isInteger(spec.numberOfRisers) || spec.numberOfRisers < 1) return (0, brepjs.err)(specError("STAIR_FLIGHT_BAD_RISERS", "Stair flight numberOfRisers must be a positive integer"));
|
|
7194
|
+
const profileResult = (0, brepjs.polygon)(buildSilhouette$1(spec.numberOfRisers, spec.riserHeight, spec.treadLength));
|
|
7195
|
+
if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "STAIR_FLIGHT_PROFILE_FAILED", "Failed to create stair flight silhouette profile"));
|
|
7196
|
+
const solidResult = (0, brepjs.extrude)(_usingCtx$5.u(profileResult.value), [
|
|
7197
|
+
0,
|
|
7198
|
+
spec.width,
|
|
7199
|
+
0
|
|
7200
|
+
]);
|
|
7201
|
+
if (!solidResult.ok) return (0, brepjs.err)(fromBrepError(solidResult.error, "STAIR_FLIGHT_EXTRUDE_FAILED", "Failed to extrude stair flight silhouette"));
|
|
7202
|
+
const solid = solidResult.value;
|
|
7203
|
+
if (!(0, brepjs.isValidSolid)(solid)) {
|
|
7204
|
+
solid[Symbol.dispose]();
|
|
7205
|
+
return (0, brepjs.err)(geometryError("STAIR_FLIGHT_INVALID_SOLID", "Stair flight solid failed validity check"));
|
|
7206
|
+
}
|
|
7207
|
+
return (0, brepjs.ok)({
|
|
7208
|
+
solid,
|
|
7209
|
+
geometrySimplified: false
|
|
7210
|
+
});
|
|
7211
|
+
} catch (_) {
|
|
7212
|
+
_usingCtx$5.e = _;
|
|
7213
|
+
} finally {
|
|
7214
|
+
_usingCtx$5.d();
|
|
7215
|
+
}
|
|
7216
|
+
}
|
|
7217
|
+
//#endregion
|
|
7218
|
+
//#region src/elementFns/placedGeometry.ts
|
|
7219
|
+
function place(solid, frame) {
|
|
7220
|
+
const result = (0, brepjs.applyMatrix)(solid, placementToMatrix(frame));
|
|
7221
|
+
if (!result.ok) return (0, brepjs.err)(fromBrepError(result.error, "PLACED_GEOMETRY_FAILED", "Failed to place element geometry"));
|
|
7222
|
+
return (0, brepjs.ok)(result.value);
|
|
7223
|
+
}
|
|
7224
|
+
function disposeAll(solids) {
|
|
7225
|
+
for (const s of solids) s[Symbol.dispose]();
|
|
7226
|
+
}
|
|
7227
|
+
/**
|
|
7228
|
+
* Returns each element's geometry transformed to its world placement, as fresh
|
|
7229
|
+
* caller-owned solids, wrapped in a `Result` (Layer-2 code prefers `Result` over
|
|
7230
|
+
* throwing). **Dispose the returned solids** (e.g. via `using` / `[Symbol.dispose]`)
|
|
7231
|
+
* when you own their lifetime — they are independent of the model
|
|
7232
|
+
* (`BimModel[Symbol.dispose]` frees only the stored, unplaced `.geometry`). On any
|
|
7233
|
+
* failure the solids already built for this call are disposed before the error is
|
|
7234
|
+
* returned, so no partial array is leaked.
|
|
7235
|
+
*
|
|
7236
|
+
* Stairs carry no element solid (`.geometry` is null), so flight solids are built
|
|
7237
|
+
* from `spec.flights` and placed per flight. Curtain walls return placed panels +
|
|
7238
|
+
* mullions. Elements with no solid geometry (doors/windows/ramps/groups/spatial)
|
|
7239
|
+
* return an empty array.
|
|
7240
|
+
*/
|
|
7241
|
+
function placedSolids(el) {
|
|
7242
|
+
switch (el.category) {
|
|
7243
|
+
case "WALL":
|
|
7244
|
+
case "SLAB":
|
|
7245
|
+
case "BEAM":
|
|
7246
|
+
case "COLUMN":
|
|
7247
|
+
case "SPACE":
|
|
7248
|
+
case "ROOF":
|
|
7249
|
+
case "FOOTING":
|
|
7250
|
+
case "PILE":
|
|
7251
|
+
case "RAILING": {
|
|
7252
|
+
const placed = place(el.geometry, el.spec);
|
|
7253
|
+
if (!placed.ok) return placed;
|
|
7254
|
+
return (0, brepjs.ok)([placed.value]);
|
|
7255
|
+
}
|
|
7256
|
+
case "STAIR": {
|
|
7257
|
+
const out = [];
|
|
7258
|
+
for (const flight of el.spec.flights) try {
|
|
7259
|
+
var _usingCtx$4 = _usingCtx();
|
|
7260
|
+
const built = stairFlightToSolid(flight);
|
|
7261
|
+
if (!built.ok) {
|
|
7262
|
+
disposeAll(out);
|
|
7263
|
+
return (0, brepjs.err)(built.error);
|
|
7264
|
+
}
|
|
7265
|
+
const placed = place(_usingCtx$4.u(built.value.solid), flight);
|
|
7266
|
+
if (!placed.ok) {
|
|
7267
|
+
disposeAll(out);
|
|
7268
|
+
return placed;
|
|
7269
|
+
}
|
|
7270
|
+
out.push(placed.value);
|
|
7271
|
+
} catch (_) {
|
|
7272
|
+
_usingCtx$4.e = _;
|
|
7273
|
+
} finally {
|
|
7274
|
+
_usingCtx$4.d();
|
|
7275
|
+
}
|
|
7276
|
+
return (0, brepjs.ok)(out);
|
|
7277
|
+
}
|
|
7278
|
+
case "CURTAIN_WALL": {
|
|
7279
|
+
const out = [];
|
|
7280
|
+
for (const c of [...el.geometry.panels, ...el.geometry.mullions]) try {
|
|
7281
|
+
var _usingCtx3 = _usingCtx();
|
|
7282
|
+
const componentLocal = place(c.solid, {
|
|
7283
|
+
origin: c.origin,
|
|
7284
|
+
axisX: [
|
|
7285
|
+
1,
|
|
7286
|
+
0,
|
|
7287
|
+
0
|
|
7288
|
+
],
|
|
7289
|
+
axisZ: [
|
|
7290
|
+
0,
|
|
7291
|
+
0,
|
|
7292
|
+
1
|
|
7293
|
+
]
|
|
7294
|
+
});
|
|
7295
|
+
if (!componentLocal.ok) {
|
|
7296
|
+
disposeAll(out);
|
|
7297
|
+
return componentLocal;
|
|
7298
|
+
}
|
|
7299
|
+
const placed = place(_usingCtx3.u(componentLocal.value), el.spec);
|
|
7300
|
+
if (!placed.ok) {
|
|
7301
|
+
disposeAll(out);
|
|
7302
|
+
return placed;
|
|
7303
|
+
}
|
|
7304
|
+
out.push(placed.value);
|
|
7305
|
+
} catch (_) {
|
|
7306
|
+
_usingCtx3.e = _;
|
|
7307
|
+
} finally {
|
|
7308
|
+
_usingCtx3.d();
|
|
7309
|
+
}
|
|
7310
|
+
return (0, brepjs.ok)(out);
|
|
7311
|
+
}
|
|
7312
|
+
default: return (0, brepjs.ok)([]);
|
|
6726
7313
|
}
|
|
6727
|
-
}
|
|
7314
|
+
}
|
|
6728
7315
|
//#endregion
|
|
6729
7316
|
//#region src/ifc-writer/schemaVersion.ts
|
|
6730
7317
|
/**
|
|
@@ -7995,7 +8582,7 @@ function writeSlabGeometry(w, spec, geomSubContextId, parentPlacementId) {
|
|
|
7995
8582
|
productDefinitionShapeId
|
|
7996
8583
|
};
|
|
7997
8584
|
}
|
|
7998
|
-
function writeRoofGeometry(w, spec, geomSubContextId, parentPlacementId) {
|
|
8585
|
+
function writeRoofGeometry(w, spec, solid, geomSubContextId, parentPlacementId) {
|
|
7999
8586
|
const placement3DId = writeAxis2Placement3D(w, spec.origin.map(toIfcLengthM), spec.axisZ, spec.axisX);
|
|
8000
8587
|
const localPlacementId = w.nextId();
|
|
8001
8588
|
w.writeLine({
|
|
@@ -8004,6 +8591,14 @@ function writeRoofGeometry(w, spec, geomSubContextId, parentPlacementId) {
|
|
|
8004
8591
|
PlacementRelTo: parentPlacementId !== null ? w.ref(parentPlacementId) : null,
|
|
8005
8592
|
RelativePlacement: w.ref(placement3DId)
|
|
8006
8593
|
});
|
|
8594
|
+
if (spec.pitch !== void 0) {
|
|
8595
|
+
const tess = writeTessellation(w, solid, geomSubContextId, localPlacementId);
|
|
8596
|
+
return {
|
|
8597
|
+
localPlacementId,
|
|
8598
|
+
productDefinitionShapeId: tess.productDefinitionShapeId,
|
|
8599
|
+
usedFallback: tess.usedFallback
|
|
8600
|
+
};
|
|
8601
|
+
}
|
|
8007
8602
|
const lengthM = toIfcLengthM(spec.length);
|
|
8008
8603
|
const widthM = toIfcLengthM(spec.width);
|
|
8009
8604
|
const thicknessM = toIfcLengthM(spec.thickness);
|
|
@@ -8071,7 +8666,8 @@ function writeRoofGeometry(w, spec, geomSubContextId, parentPlacementId) {
|
|
|
8071
8666
|
});
|
|
8072
8667
|
return {
|
|
8073
8668
|
localPlacementId,
|
|
8074
|
-
productDefinitionShapeId
|
|
8669
|
+
productDefinitionShapeId,
|
|
8670
|
+
usedFallback: false
|
|
8075
8671
|
};
|
|
8076
8672
|
}
|
|
8077
8673
|
function writeAxis2Placement2D$1(w) {
|
|
@@ -8774,68 +9370,6 @@ function writeRelContainedInSpatialStructure(w, guid, ownerHistoryId, relatingSt
|
|
|
8774
9370
|
});
|
|
8775
9371
|
}
|
|
8776
9372
|
//#endregion
|
|
8777
|
-
//#region src/elementFns/stairFns.ts
|
|
8778
|
-
function buildSilhouette$1(numberOfRisers, riserHeight, treadLength) {
|
|
8779
|
-
const pts = [];
|
|
8780
|
-
pts.push([
|
|
8781
|
-
0,
|
|
8782
|
-
0,
|
|
8783
|
-
0
|
|
8784
|
-
]);
|
|
8785
|
-
let x = 0;
|
|
8786
|
-
let z = 0;
|
|
8787
|
-
for (let i = 0; i < numberOfRisers; i++) {
|
|
8788
|
-
z += riserHeight;
|
|
8789
|
-
pts.push([
|
|
8790
|
-
x,
|
|
8791
|
-
0,
|
|
8792
|
-
z
|
|
8793
|
-
]);
|
|
8794
|
-
x += treadLength;
|
|
8795
|
-
pts.push([
|
|
8796
|
-
x,
|
|
8797
|
-
0,
|
|
8798
|
-
z
|
|
8799
|
-
]);
|
|
8800
|
-
}
|
|
8801
|
-
pts.push([
|
|
8802
|
-
x,
|
|
8803
|
-
0,
|
|
8804
|
-
0
|
|
8805
|
-
]);
|
|
8806
|
-
return pts;
|
|
8807
|
-
}
|
|
8808
|
-
function stairFlightToSolid(spec) {
|
|
8809
|
-
try {
|
|
8810
|
-
var _usingCtx$4 = _usingCtx();
|
|
8811
|
-
if (spec.width <= 0) return (0, brepjs.err)(specError("STAIR_FLIGHT_ZERO_WIDTH", "Stair flight width must be positive"));
|
|
8812
|
-
if (spec.riserHeight <= 0) return (0, brepjs.err)(specError("STAIR_FLIGHT_ZERO_RISER", "Stair flight riserHeight must be positive"));
|
|
8813
|
-
if (spec.treadLength <= 0) return (0, brepjs.err)(specError("STAIR_FLIGHT_ZERO_TREAD", "Stair flight treadLength must be positive"));
|
|
8814
|
-
if (!Number.isInteger(spec.numberOfRisers) || spec.numberOfRisers < 1) return (0, brepjs.err)(specError("STAIR_FLIGHT_BAD_RISERS", "Stair flight numberOfRisers must be a positive integer"));
|
|
8815
|
-
const profileResult = (0, brepjs.polygon)(buildSilhouette$1(spec.numberOfRisers, spec.riserHeight, spec.treadLength));
|
|
8816
|
-
if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "STAIR_FLIGHT_PROFILE_FAILED", "Failed to create stair flight silhouette profile"));
|
|
8817
|
-
const solidResult = (0, brepjs.extrude)(_usingCtx$4.u(profileResult.value), [
|
|
8818
|
-
0,
|
|
8819
|
-
spec.width,
|
|
8820
|
-
0
|
|
8821
|
-
]);
|
|
8822
|
-
if (!solidResult.ok) return (0, brepjs.err)(fromBrepError(solidResult.error, "STAIR_FLIGHT_EXTRUDE_FAILED", "Failed to extrude stair flight silhouette"));
|
|
8823
|
-
const solid = solidResult.value;
|
|
8824
|
-
if (!(0, brepjs.isValidSolid)(solid)) {
|
|
8825
|
-
solid[Symbol.dispose]();
|
|
8826
|
-
return (0, brepjs.err)(geometryError("STAIR_FLIGHT_INVALID_SOLID", "Stair flight solid failed validity check"));
|
|
8827
|
-
}
|
|
8828
|
-
return (0, brepjs.ok)({
|
|
8829
|
-
solid,
|
|
8830
|
-
geometrySimplified: false
|
|
8831
|
-
});
|
|
8832
|
-
} catch (_) {
|
|
8833
|
-
_usingCtx$4.e = _;
|
|
8834
|
-
} finally {
|
|
8835
|
-
_usingCtx$4.d();
|
|
8836
|
-
}
|
|
8837
|
-
}
|
|
8838
|
-
//#endregion
|
|
8839
9373
|
//#region src/elementFns/rampFns.ts
|
|
8840
9374
|
function buildSilhouette(length, rise, thickness) {
|
|
8841
9375
|
return [
|
|
@@ -9146,7 +9680,7 @@ function writeRampAssembly(w, spec, rampKey, ownerHistoryId, geomSubContextId, p
|
|
|
9146
9680
|
}
|
|
9147
9681
|
//#endregion
|
|
9148
9682
|
//#region src/ifc-writer/railingWriter.ts
|
|
9149
|
-
function writeRailingGeometry(w, spec, geomSubContextId, parentPlacementId) {
|
|
9683
|
+
function writeRailingGeometry(w, spec, solid, geomSubContextId, parentPlacementId) {
|
|
9150
9684
|
const placement3DId = writeAxis2Placement3D(w, spec.origin.map(toIfcLengthM), spec.axisZ, spec.axisX);
|
|
9151
9685
|
const localPlacementId = w.nextId();
|
|
9152
9686
|
w.writeLine({
|
|
@@ -9155,6 +9689,15 @@ function writeRailingGeometry(w, spec, geomSubContextId, parentPlacementId) {
|
|
|
9155
9689
|
PlacementRelTo: parentPlacementId !== null ? w.ref(parentPlacementId) : null,
|
|
9156
9690
|
RelativePlacement: w.ref(placement3DId)
|
|
9157
9691
|
});
|
|
9692
|
+
if (spec.infill === "POSTED") {
|
|
9693
|
+
const tess = writeTessellation(w, solid, geomSubContextId, localPlacementId);
|
|
9694
|
+
return {
|
|
9695
|
+
localPlacementId,
|
|
9696
|
+
productDefinitionShapeId: tess.productDefinitionShapeId,
|
|
9697
|
+
bodyItemId: null,
|
|
9698
|
+
usedFallback: tess.usedFallback
|
|
9699
|
+
};
|
|
9700
|
+
}
|
|
9158
9701
|
const thicknessM = toIfcLengthM(spec.thickness);
|
|
9159
9702
|
const heightM = toIfcLengthM(spec.height);
|
|
9160
9703
|
const lengthM = toIfcLengthM(spec.length);
|
|
@@ -9231,7 +9774,8 @@ function writeRailingGeometry(w, spec, geomSubContextId, parentPlacementId) {
|
|
|
9231
9774
|
return {
|
|
9232
9775
|
localPlacementId,
|
|
9233
9776
|
productDefinitionShapeId,
|
|
9234
|
-
bodyItemId: extrusionId
|
|
9777
|
+
bodyItemId: extrusionId,
|
|
9778
|
+
usedFallback: false
|
|
9235
9779
|
};
|
|
9236
9780
|
}
|
|
9237
9781
|
function writeRailingEntity(w, guid, name, predefinedType, ownerHistoryId, localPlacementId, productDefinitionShapeId) {
|
|
@@ -11602,7 +12146,8 @@ async function toIfc(model, meta) {
|
|
|
11602
12146
|
for (const [i, roof] of roofs.entries()) {
|
|
11603
12147
|
const containingId = findContainerOf(roof.localId, relationships);
|
|
11604
12148
|
const storeyPlacementId = containingId !== null ? placementMap.get(containingId) ?? null : null;
|
|
11605
|
-
const { localPlacementId, productDefinitionShapeId } = writeRoofGeometry(w, roof.spec, geomSubContextId, storeyPlacementId);
|
|
12149
|
+
const { localPlacementId, productDefinitionShapeId, usedFallback } = writeRoofGeometry(w, roof.spec, roof.geometry, geomSubContextId, storeyPlacementId);
|
|
12150
|
+
if (usedFallback) console.warn(`Roof ${i + 1} tessellation failed; IFC body is a degenerate fallback.`);
|
|
11606
12151
|
const roofExpressId = writeRoofEntity(w, roof.guid, `Roof ${i + 1}`, roof.spec.predefinedType, ownerHistoryId, localPlacementId, productDefinitionShapeId);
|
|
11607
12152
|
idMap.set(roof.localId, roofExpressId);
|
|
11608
12153
|
placementMap.set(roof.localId, localPlacementId);
|
|
@@ -11674,14 +12219,15 @@ async function toIfc(model, meta) {
|
|
|
11674
12219
|
for (const [i, railing] of railings.entries()) {
|
|
11675
12220
|
const containingId = findContainerOf(railing.localId, relationships);
|
|
11676
12221
|
const storeyPlacementId = containingId !== null ? placementMap.get(containingId) ?? null : null;
|
|
11677
|
-
const { localPlacementId, productDefinitionShapeId, bodyItemId } = writeRailingGeometry(w, railing.spec, geomSubContextId, storeyPlacementId);
|
|
12222
|
+
const { localPlacementId, productDefinitionShapeId, bodyItemId, usedFallback } = writeRailingGeometry(w, railing.spec, railing.geometry, geomSubContextId, storeyPlacementId);
|
|
12223
|
+
if (usedFallback) console.warn(`Railing ${i + 1} tessellation failed; IFC body is a degenerate fallback.`);
|
|
11678
12224
|
const railingExpressId = writeRailingEntity(w, railing.guid, `Railing ${i + 1}`, railing.spec.predefinedType ?? "NOTDEFINED", ownerHistoryId, localPlacementId, productDefinitionShapeId);
|
|
11679
12225
|
idMap.set(railing.localId, railingExpressId);
|
|
11680
12226
|
placementMap.set(railing.localId, localPlacementId);
|
|
11681
12227
|
writeRailingCommonPset(w, ownerHistoryId, railingExpressId, railing.spec);
|
|
11682
12228
|
writeManufacturerPset(w, ownerHistoryId, railingExpressId, railing.spec);
|
|
11683
12229
|
if (railing.spec.customProperties !== void 0) writeCustomPsets(w, ownerHistoryId, railingExpressId, railing.spec.customProperties);
|
|
11684
|
-
applySurfaceStyle(w, model, railing.localId, bodyItemId);
|
|
12230
|
+
if (bodyItemId !== null) applySurfaceStyle(w, model, railing.localId, bodyItemId);
|
|
11685
12231
|
}
|
|
11686
12232
|
for (const [i, covering] of coverings.entries()) {
|
|
11687
12233
|
const containingId = findContainerOf(covering.localId, relationships);
|
|
@@ -12209,120 +12755,6 @@ var SpfReader = class SpfReader {
|
|
|
12209
12755
|
}
|
|
12210
12756
|
};
|
|
12211
12757
|
//#endregion
|
|
12212
|
-
//#region src/import/placement.ts
|
|
12213
|
-
/**
|
|
12214
|
-
* Metres-per-file-unit length scale read from the IfcUnitAssignment's
|
|
12215
|
-
* LENGTHUNIT. Multiply a file-unit length by this to get metres, then by 1000
|
|
12216
|
-
* for brepjs millimetres. Returns 1.0 (assume metres) when no length unit is
|
|
12217
|
-
* declared.
|
|
12218
|
-
*/
|
|
12219
|
-
function readLengthScale(reader) {
|
|
12220
|
-
const assignments = reader.getLinesOfType(web_ifc.IFCUNITASSIGNMENT);
|
|
12221
|
-
for (const assignmentId of assignments) {
|
|
12222
|
-
const units = asRefArray$1(reader.getLine(assignmentId)?.["Units"]);
|
|
12223
|
-
for (const unitId of units) {
|
|
12224
|
-
const scale = lengthScaleFromUnit(reader, unitId);
|
|
12225
|
-
if (scale !== null) return scale;
|
|
12226
|
-
}
|
|
12227
|
-
}
|
|
12228
|
-
return 1;
|
|
12229
|
-
}
|
|
12230
|
-
/**
|
|
12231
|
-
* Radians-per-file-unit plane-angle scale read from the IfcUnitAssignment's
|
|
12232
|
-
* PLANEANGLEUNIT (1 for RADIAN, ~0.0174533 for DEGREE). Defaults to 1 (the IFC
|
|
12233
|
-
* default plane-angle unit is the radian).
|
|
12234
|
-
*/
|
|
12235
|
-
function readPlaneAngleScale(reader) {
|
|
12236
|
-
for (const assignmentId of reader.getLinesOfType(web_ifc.IFCUNITASSIGNMENT)) {
|
|
12237
|
-
const units = asRefArray$1(reader.getLine(assignmentId)?.["Units"]);
|
|
12238
|
-
for (const unitId of units) {
|
|
12239
|
-
const s = planeAngleScaleFromUnit(reader, unitId);
|
|
12240
|
-
if (s !== null) return s;
|
|
12241
|
-
}
|
|
12242
|
-
}
|
|
12243
|
-
return 1;
|
|
12244
|
-
}
|
|
12245
|
-
function planeAngleScaleFromUnit(reader, unitId) {
|
|
12246
|
-
const unit = reader.getLine(unitId);
|
|
12247
|
-
if (unit === null) return null;
|
|
12248
|
-
const type = reader.getLineType(unitId);
|
|
12249
|
-
if (type === web_ifc.IFCSIUNIT) {
|
|
12250
|
-
if (enumValue(unit["UnitType"]) !== "PLANEANGLEUNIT") return null;
|
|
12251
|
-
if (enumValue(unit["Name"]) !== "RADIAN") return null;
|
|
12252
|
-
return 1;
|
|
12253
|
-
}
|
|
12254
|
-
if (type === web_ifc.IFCCONVERSIONBASEDUNIT) {
|
|
12255
|
-
if (enumValue(unit["UnitType"]) !== "PLANEANGLEUNIT") return null;
|
|
12256
|
-
const measureId = refValue$2(unit["ConversionFactor"]);
|
|
12257
|
-
if (measureId === null) return null;
|
|
12258
|
-
const factor = numericValue(reader.getLine(measureId)?.["ValueComponent"]);
|
|
12259
|
-
if (factor === null) return null;
|
|
12260
|
-
return factor;
|
|
12261
|
-
}
|
|
12262
|
-
return null;
|
|
12263
|
-
}
|
|
12264
|
-
function lengthScaleFromUnit(reader, unitId) {
|
|
12265
|
-
const unit = reader.getLine(unitId);
|
|
12266
|
-
if (unit === null) return null;
|
|
12267
|
-
const type = reader.getLineType(unitId);
|
|
12268
|
-
if (type === web_ifc.IFCSIUNIT) {
|
|
12269
|
-
if (enumValue(unit["UnitType"]) !== "LENGTHUNIT") return null;
|
|
12270
|
-
if (enumValue(unit["Name"]) !== "METRE") return null;
|
|
12271
|
-
return siPrefixFactor(enumValue(unit["Prefix"]));
|
|
12272
|
-
}
|
|
12273
|
-
if (type === web_ifc.IFCCONVERSIONBASEDUNIT) {
|
|
12274
|
-
if (enumValue(unit["UnitType"]) !== "LENGTHUNIT") return null;
|
|
12275
|
-
const measureId = refValue$2(unit["ConversionFactor"]);
|
|
12276
|
-
if (measureId === null) return null;
|
|
12277
|
-
const measure = reader.getLine(measureId);
|
|
12278
|
-
const factor = numericValue(measure?.["ValueComponent"]);
|
|
12279
|
-
if (factor === null) return null;
|
|
12280
|
-
const baseId = refValue$2(measure?.["UnitComponent"]);
|
|
12281
|
-
return factor * (baseId !== null ? lengthScaleFromUnit(reader, baseId) ?? 1 : 1);
|
|
12282
|
-
}
|
|
12283
|
-
return null;
|
|
12284
|
-
}
|
|
12285
|
-
function siPrefixFactor(prefix) {
|
|
12286
|
-
switch (prefix) {
|
|
12287
|
-
case null: return 1;
|
|
12288
|
-
case "KILO": return 1e3;
|
|
12289
|
-
case "HECTO": return 100;
|
|
12290
|
-
case "DECA": return 10;
|
|
12291
|
-
case "DECI": return .1;
|
|
12292
|
-
case "CENTI": return .01;
|
|
12293
|
-
case "MILLI": return .001;
|
|
12294
|
-
case "MICRO": return 1e-6;
|
|
12295
|
-
default: return 1;
|
|
12296
|
-
}
|
|
12297
|
-
}
|
|
12298
|
-
function refValue$2(v) {
|
|
12299
|
-
if (v === null || v === void 0) return null;
|
|
12300
|
-
if (typeof v === "number") return v;
|
|
12301
|
-
const value = v.value;
|
|
12302
|
-
return typeof value === "number" ? value : null;
|
|
12303
|
-
}
|
|
12304
|
-
function asRefArray$1(v) {
|
|
12305
|
-
if (!Array.isArray(v)) return [];
|
|
12306
|
-
const out = [];
|
|
12307
|
-
for (const item of v) {
|
|
12308
|
-
const id = refValue$2(item);
|
|
12309
|
-
if (id !== null) out.push(id);
|
|
12310
|
-
}
|
|
12311
|
-
return out;
|
|
12312
|
-
}
|
|
12313
|
-
function numericValue(v) {
|
|
12314
|
-
if (typeof v === "number") return v;
|
|
12315
|
-
if (v === null || v === void 0) return null;
|
|
12316
|
-
const value = v.value;
|
|
12317
|
-
return typeof value === "number" ? value : null;
|
|
12318
|
-
}
|
|
12319
|
-
function enumValue(v) {
|
|
12320
|
-
if (typeof v === "string") return v;
|
|
12321
|
-
if (v === null || v === void 0) return null;
|
|
12322
|
-
const value = v.value;
|
|
12323
|
-
return typeof value === "string" ? value : null;
|
|
12324
|
-
}
|
|
12325
|
-
//#endregion
|
|
12326
12758
|
//#region src/import/spatialTree.ts
|
|
12327
12759
|
var CATEGORY_BY_TYPE = new Map([
|
|
12328
12760
|
[web_ifc.IFCPROJECT, "PROJECT"],
|
|
@@ -13948,6 +14380,7 @@ var RoofSpecSchema = object({
|
|
|
13948
14380
|
fireRating: string().optional(),
|
|
13949
14381
|
thermalTransmittance: number().positive().optional(),
|
|
13950
14382
|
status: string().optional(),
|
|
14383
|
+
pitch: number().positive().max(89).optional(),
|
|
13951
14384
|
materialLayers: array(MaterialLayerSchema).optional(),
|
|
13952
14385
|
layerSetName: string().optional(),
|
|
13953
14386
|
classification: ClassificationRefSchema.optional(),
|
|
@@ -14279,6 +14712,7 @@ var RailingSpecSchema = object({
|
|
|
14279
14712
|
"HANDRAIL",
|
|
14280
14713
|
"NOTDEFINED"
|
|
14281
14714
|
]).optional(),
|
|
14715
|
+
infill: _enum(["PANEL", "POSTED"]).optional(),
|
|
14282
14716
|
materialName: string().min(1),
|
|
14283
14717
|
isExternal: boolean().optional(),
|
|
14284
14718
|
fireRating: string().optional(),
|
|
@@ -15545,24 +15979,24 @@ var XML_DECLARATION = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
|
|
|
15545
15979
|
function xmlDocument(rootXml) {
|
|
15546
15980
|
return `${XML_DECLARATION}\n${rootXml}\n`;
|
|
15547
15981
|
}
|
|
15548
|
-
function
|
|
15549
|
-
|
|
15550
|
-
|
|
15551
|
-
|
|
15552
|
-
|
|
15553
|
-
const key = m[1];
|
|
15554
|
-
const val = m[2];
|
|
15555
|
-
if (key !== void 0 && val !== void 0) attrs[key] = unescapeXml(val);
|
|
15556
|
-
}
|
|
15557
|
-
return attrs;
|
|
15982
|
+
function isNameChar(c) {
|
|
15983
|
+
return /[\w:.-]/.test(c);
|
|
15984
|
+
}
|
|
15985
|
+
function isWhitespace(c) {
|
|
15986
|
+
return /\s/.test(c);
|
|
15558
15987
|
}
|
|
15559
15988
|
/**
|
|
15560
|
-
* Parse an XML string into a tree. Tolerant of the XML declaration,
|
|
15561
|
-
* whitespace, self-closing tags, and CDATA-free text.
|
|
15562
|
-
*
|
|
15989
|
+
* Parse an XML string into a tree. Tolerant of the XML declaration, processing
|
|
15990
|
+
* instructions, comments, whitespace, self-closing tags, and CDATA-free text.
|
|
15991
|
+
* Throws on malformed or unbalanced structure; callers wrap this in a `Result`.
|
|
15992
|
+
*
|
|
15993
|
+
* This is a hand-written cursor scan rather than a single tokenizing regex: the
|
|
15994
|
+
* input is an untrusted `.bcfzip` payload, and a backtracking regex over
|
|
15995
|
+
* uncontrolled data is a polynomial-ReDoS vector. Every construct here is
|
|
15996
|
+
* consumed by an `indexOf` or a single-character advance, so the parse is linear
|
|
15997
|
+
* in the input length. The sibling `ids/idsXml.ts` parser scans the same way.
|
|
15563
15998
|
*/
|
|
15564
15999
|
function parseXml(xml) {
|
|
15565
|
-
const tokenRe = /<!--[\s\S]*?-->|<\?[\s\S]*?\?>|<\/([\w:.-]+)\s*>|<([\w:.-]+)((?:\s+[\w:.-]+\s*=\s*"[^"]*")*)\s*(\/?)>|([^<]+)/g;
|
|
15566
16000
|
const root = {
|
|
15567
16001
|
tag: "#root",
|
|
15568
16002
|
attrs: {},
|
|
@@ -15570,36 +16004,84 @@ function parseXml(xml) {
|
|
|
15570
16004
|
text: ""
|
|
15571
16005
|
};
|
|
15572
16006
|
const stack = [root];
|
|
15573
|
-
|
|
15574
|
-
|
|
15575
|
-
|
|
15576
|
-
|
|
15577
|
-
|
|
15578
|
-
|
|
15579
|
-
|
|
15580
|
-
|
|
15581
|
-
|
|
15582
|
-
|
|
15583
|
-
|
|
15584
|
-
|
|
15585
|
-
|
|
15586
|
-
|
|
15587
|
-
|
|
15588
|
-
|
|
15589
|
-
|
|
15590
|
-
const
|
|
15591
|
-
if (
|
|
15592
|
-
|
|
15593
|
-
if (
|
|
15594
|
-
|
|
16007
|
+
const len = xml.length;
|
|
16008
|
+
let i = 0;
|
|
16009
|
+
const fail = (msg) => {
|
|
16010
|
+
throw new Error(`Malformed XML: ${msg} at offset ${String(i)}`);
|
|
16011
|
+
};
|
|
16012
|
+
const skipWhitespace = () => {
|
|
16013
|
+
while (i < len && isWhitespace(xml.charAt(i))) i += 1;
|
|
16014
|
+
};
|
|
16015
|
+
const readName = () => {
|
|
16016
|
+
const start = i;
|
|
16017
|
+
while (i < len && isNameChar(xml.charAt(i))) i += 1;
|
|
16018
|
+
return xml.slice(start, i);
|
|
16019
|
+
};
|
|
16020
|
+
const readAttrs = () => {
|
|
16021
|
+
const attrs = {};
|
|
16022
|
+
for (;;) {
|
|
16023
|
+
skipWhitespace();
|
|
16024
|
+
const c = xml.charAt(i);
|
|
16025
|
+
if (i >= len || c === ">" || c === "/") return attrs;
|
|
16026
|
+
const name = readName();
|
|
16027
|
+
if (name.length === 0) fail("expected attribute name");
|
|
16028
|
+
skipWhitespace();
|
|
16029
|
+
if (xml.charAt(i) !== "=") fail(`expected '=' after attribute "${name}"`);
|
|
16030
|
+
i += 1;
|
|
16031
|
+
skipWhitespace();
|
|
16032
|
+
if (xml.charAt(i) !== "\"") fail(`expected '"' opening attribute "${name}"`);
|
|
16033
|
+
i += 1;
|
|
16034
|
+
const end = xml.indexOf("\"", i);
|
|
16035
|
+
if (end === -1) fail(`unterminated value for attribute "${name}"`);
|
|
16036
|
+
attrs[name] = unescapeXml(xml.slice(i, end));
|
|
16037
|
+
i = end + 1;
|
|
15595
16038
|
}
|
|
15596
|
-
|
|
15597
|
-
|
|
15598
|
-
|
|
15599
|
-
|
|
15600
|
-
|
|
15601
|
-
|
|
16039
|
+
};
|
|
16040
|
+
while (i < len) if (xml.startsWith("<!--", i)) {
|
|
16041
|
+
const end = xml.indexOf("-->", i + 4);
|
|
16042
|
+
if (end === -1) fail("unterminated comment");
|
|
16043
|
+
i = end + 3;
|
|
16044
|
+
} else if (xml.startsWith("<?", i)) {
|
|
16045
|
+
const end = xml.indexOf("?>", i + 2);
|
|
16046
|
+
if (end === -1) fail("unterminated processing instruction");
|
|
16047
|
+
i = end + 2;
|
|
16048
|
+
} else if (xml.startsWith("</", i)) {
|
|
16049
|
+
i += 2;
|
|
16050
|
+
const name = readName();
|
|
16051
|
+
skipWhitespace();
|
|
16052
|
+
if (xml.charAt(i) !== ">") fail(`expected '>' closing </${name}>`);
|
|
16053
|
+
i += 1;
|
|
16054
|
+
const top = stack[stack.length - 1];
|
|
16055
|
+
if (top === void 0 || top.tag !== name) throw new Error(`Unbalanced XML: unexpected </${name}>`);
|
|
16056
|
+
stack.pop();
|
|
16057
|
+
} else if (xml.charAt(i) === "<") {
|
|
16058
|
+
i += 1;
|
|
16059
|
+
const tag = readName();
|
|
16060
|
+
if (tag.length === 0) fail("expected element name");
|
|
16061
|
+
const node = {
|
|
16062
|
+
tag,
|
|
16063
|
+
attrs: readAttrs(),
|
|
16064
|
+
children: [],
|
|
16065
|
+
text: ""
|
|
16066
|
+
};
|
|
16067
|
+
const parent = stack[stack.length - 1];
|
|
16068
|
+
if (parent === void 0) throw new Error("Unbalanced XML: empty stack");
|
|
16069
|
+
parent.children.push(node);
|
|
16070
|
+
skipWhitespace();
|
|
16071
|
+
if (xml.startsWith("/>", i)) i += 2;
|
|
16072
|
+
else if (xml.charAt(i) === ">") {
|
|
16073
|
+
i += 1;
|
|
16074
|
+
stack.push(node);
|
|
16075
|
+
} else fail(`expected '>' in <${tag}>`);
|
|
16076
|
+
} else {
|
|
16077
|
+
const next = xml.indexOf("<", i);
|
|
16078
|
+
const end = next === -1 ? len : next;
|
|
16079
|
+
const decoded = unescapeXml(xml.slice(i, end));
|
|
16080
|
+
if (decoded.trim().length > 0) {
|
|
16081
|
+
const top = stack[stack.length - 1];
|
|
16082
|
+
if (top !== void 0) top.text += decoded;
|
|
15602
16083
|
}
|
|
16084
|
+
i = end;
|
|
15603
16085
|
}
|
|
15604
16086
|
if (stack.length !== 1) throw new Error("Unbalanced XML: unclosed elements remain");
|
|
15605
16087
|
const top = root.children[0];
|
|
@@ -15996,6 +16478,7 @@ exports.parseSystemSpec = parseSystemSpec;
|
|
|
15996
16478
|
exports.parseWallSpec = parseWallSpec;
|
|
15997
16479
|
exports.parseWindowSpec = parseWindowSpec;
|
|
15998
16480
|
exports.parseZoneSpec = parseZoneSpec;
|
|
16481
|
+
exports.placedSolids = placedSolids;
|
|
15999
16482
|
exports.schemaSupports = schemaSupports;
|
|
16000
16483
|
exports.serializeBcfFiles = serializeBcfFiles;
|
|
16001
16484
|
exports.serializeCobieToCsv = serializeCobieToCsv;
|