brepjs-bim 0.10.0 → 0.12.0
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/dist/brepjs-bim.cjs +89 -19
- package/dist/brepjs-bim.js +89 -19
- package/dist/ifc-writer/stairWriter.d.ts +5 -3
- package/dist/model/bimModel.d.ts +4 -4
- package/package.json +2 -1
package/dist/brepjs-bim.cjs
CHANGED
|
@@ -6378,10 +6378,12 @@ var BimModel = class {
|
|
|
6378
6378
|
this.#associateClassification(id, spec);
|
|
6379
6379
|
return (0, brepjs.ok)(id);
|
|
6380
6380
|
}
|
|
6381
|
-
addBeam(spec) {
|
|
6381
|
+
addBeam(spec, options) {
|
|
6382
|
+
const keyCheck = this.#checkStableKey(options);
|
|
6383
|
+
if (!keyCheck.ok) return keyCheck;
|
|
6382
6384
|
const geomResult = beamToSolid(spec);
|
|
6383
6385
|
if (!geomResult.ok) return (0, brepjs.err)(geomResult.error);
|
|
6384
|
-
const id = this.#makeElement("BEAM", spec, geomResult.value);
|
|
6386
|
+
const id = this.#makeElement("BEAM", spec, geomResult.value, options?.stableKey);
|
|
6385
6387
|
this.#associateMaterial(id, spec);
|
|
6386
6388
|
this.#associateClassification(id, spec);
|
|
6387
6389
|
return (0, brepjs.ok)(id);
|
|
@@ -6404,10 +6406,12 @@ var BimModel = class {
|
|
|
6404
6406
|
this.#associateClassification(id, spec);
|
|
6405
6407
|
return (0, brepjs.ok)(id);
|
|
6406
6408
|
}
|
|
6407
|
-
addRoof(spec) {
|
|
6409
|
+
addRoof(spec, options) {
|
|
6410
|
+
const keyCheck = this.#checkStableKey(options);
|
|
6411
|
+
if (!keyCheck.ok) return keyCheck;
|
|
6408
6412
|
const geomResult = roofToSolid(spec);
|
|
6409
6413
|
if (!geomResult.ok) return (0, brepjs.err)(geomResult.error);
|
|
6410
|
-
const id = this.#makeElement("ROOF", spec, geomResult.value);
|
|
6414
|
+
const id = this.#makeElement("ROOF", spec, geomResult.value, options?.stableKey);
|
|
6411
6415
|
this.#associateMaterial(id, spec);
|
|
6412
6416
|
this.#associateClassification(id, spec);
|
|
6413
6417
|
return (0, brepjs.ok)(id);
|
|
@@ -6441,8 +6445,10 @@ var BimModel = class {
|
|
|
6441
6445
|
* the IFC layer from `spec.flights`; the STAIR element itself carries no solid
|
|
6442
6446
|
* (the assembly container's Representation is null, valid per IFC4).
|
|
6443
6447
|
*/
|
|
6444
|
-
addStair(spec) {
|
|
6445
|
-
const
|
|
6448
|
+
addStair(spec, options) {
|
|
6449
|
+
const keyCheck = this.#checkStableKey(options);
|
|
6450
|
+
if (!keyCheck.ok) return keyCheck;
|
|
6451
|
+
const id = this.#makeElement("STAIR", spec, null, options?.stableKey);
|
|
6446
6452
|
this.#associateMaterial(id, spec);
|
|
6447
6453
|
this.#associateClassification(id, spec);
|
|
6448
6454
|
return (0, brepjs.ok)(id);
|
|
@@ -6451,8 +6457,10 @@ var BimModel = class {
|
|
|
6451
6457
|
* Adds an IfcRamp assembly. Geometry for each flight is built and written by the
|
|
6452
6458
|
* IFC layer from `spec.flights`; the RAMP element carries no solid of its own.
|
|
6453
6459
|
*/
|
|
6454
|
-
addRamp(spec) {
|
|
6455
|
-
const
|
|
6460
|
+
addRamp(spec, options) {
|
|
6461
|
+
const keyCheck = this.#checkStableKey(options);
|
|
6462
|
+
if (!keyCheck.ok) return keyCheck;
|
|
6463
|
+
const id = this.#makeElement("RAMP", spec, null, options?.stableKey);
|
|
6456
6464
|
this.#associateMaterial(id, spec);
|
|
6457
6465
|
this.#associateClassification(id, spec);
|
|
6458
6466
|
return (0, brepjs.ok)(id);
|
|
@@ -9628,13 +9636,15 @@ function writeRampEntity(w, guid, name, predefinedType, ownerHistoryId, localPla
|
|
|
9628
9636
|
* per `spec.flights[i]` (each with a tessellated stepped-solid body), and a single
|
|
9629
9637
|
* IfcRelAggregates linking the flights to the stair. Flight placements are
|
|
9630
9638
|
* relative to the stair placement, which is relative to `parentPlacementId`
|
|
9631
|
-
* (typically the storey).
|
|
9639
|
+
* (typically the storey). The assembly's GlobalId is the element's stored guid
|
|
9640
|
+
* (stableKey-derived when the caller provided one); flight, type, and
|
|
9641
|
+
* relationship GUIDs are deterministic, keyed on `stairKey`/index so
|
|
9632
9642
|
* re-serializing an identical model is byte-stable.
|
|
9633
9643
|
*
|
|
9634
9644
|
* Returns a BimError if any flight solid cannot be built. Stair flights are real
|
|
9635
9645
|
* stepped solids; tessellation failure is flagged via `geometrySimplified`.
|
|
9636
9646
|
*/
|
|
9637
|
-
function writeStairAssembly(w, spec, stairKey, ownerHistoryId, geomSubContextId, parentPlacementId) {
|
|
9647
|
+
function writeStairAssembly(w, spec, stairKey, assemblyGuid, ownerHistoryId, geomSubContextId, parentPlacementId) {
|
|
9638
9648
|
const predefinedType = spec.predefinedType ?? "NOTDEFINED";
|
|
9639
9649
|
const stairName = spec.name ?? "Stair";
|
|
9640
9650
|
if (spec.flights[0] === void 0) return {
|
|
@@ -9654,7 +9664,7 @@ function writeStairAssembly(w, spec, stairKey, ownerHistoryId, geomSubContextId,
|
|
|
9654
9664
|
0,
|
|
9655
9665
|
0
|
|
9656
9666
|
], parentPlacementId);
|
|
9657
|
-
const assemblyExpressId = writeStairEntity(w,
|
|
9667
|
+
const assemblyExpressId = writeStairEntity(w, assemblyGuid, stairName, predefinedType, ownerHistoryId, stairPlacementId);
|
|
9658
9668
|
const flightExpressIds = [];
|
|
9659
9669
|
let geometrySimplified = false;
|
|
9660
9670
|
for (const [i, flight] of spec.flights.entries()) try {
|
|
@@ -9694,7 +9704,7 @@ function writeStairAssembly(w, spec, stairKey, ownerHistoryId, geomSubContextId,
|
|
|
9694
9704
|
* inclined-slab solids, so `geometrySimplified` is always true. GUIDs are
|
|
9695
9705
|
* deterministic keyed on `rampKey`.
|
|
9696
9706
|
*/
|
|
9697
|
-
function writeRampAssembly(w, spec, rampKey, ownerHistoryId, geomSubContextId, parentPlacementId) {
|
|
9707
|
+
function writeRampAssembly(w, spec, rampKey, assemblyGuid, ownerHistoryId, geomSubContextId, parentPlacementId) {
|
|
9698
9708
|
const predefinedType = spec.predefinedType ?? "NOTDEFINED";
|
|
9699
9709
|
const rampName = spec.name ?? "Ramp";
|
|
9700
9710
|
if (spec.flights[0] === void 0) return {
|
|
@@ -9714,7 +9724,7 @@ function writeRampAssembly(w, spec, rampKey, ownerHistoryId, geomSubContextId, p
|
|
|
9714
9724
|
0,
|
|
9715
9725
|
0
|
|
9716
9726
|
], parentPlacementId);
|
|
9717
|
-
const assemblyExpressId = writeRampEntity(w,
|
|
9727
|
+
const assemblyExpressId = writeRampEntity(w, assemblyGuid, rampName, predefinedType, ownerHistoryId, rampPlacementId);
|
|
9718
9728
|
const flightExpressIds = [];
|
|
9719
9729
|
const geometrySimplified = true;
|
|
9720
9730
|
for (const [i, flight] of spec.flights.entries()) try {
|
|
@@ -12273,7 +12283,7 @@ async function toIfc(model, meta) {
|
|
|
12273
12283
|
for (const stair of stairs) {
|
|
12274
12284
|
const containingId = findContainerOf(stair.localId, relationships);
|
|
12275
12285
|
const storeyPlacementId = containingId !== null ? placementMap.get(containingId) ?? null : null;
|
|
12276
|
-
const result = writeStairAssembly(w, stair.spec, `${stair.localId}`, ownerHistoryId, geomSubContextId, storeyPlacementId);
|
|
12286
|
+
const result = writeStairAssembly(w, stair.spec, `${stair.localId}`, stair.guid, ownerHistoryId, geomSubContextId, storeyPlacementId);
|
|
12277
12287
|
if (!result.ok) return (0, brepjs.err)(result.error);
|
|
12278
12288
|
idMap.set(stair.localId, result.value.assemblyExpressId);
|
|
12279
12289
|
writeStairCommonPset(w, ownerHistoryId, result.value.assemblyExpressId, stair.spec);
|
|
@@ -12281,7 +12291,7 @@ async function toIfc(model, meta) {
|
|
|
12281
12291
|
for (const ramp of ramps) {
|
|
12282
12292
|
const containingId = findContainerOf(ramp.localId, relationships);
|
|
12283
12293
|
const storeyPlacementId = containingId !== null ? placementMap.get(containingId) ?? null : null;
|
|
12284
|
-
const result = writeRampAssembly(w, ramp.spec, `${ramp.localId}`, ownerHistoryId, geomSubContextId, storeyPlacementId);
|
|
12294
|
+
const result = writeRampAssembly(w, ramp.spec, `${ramp.localId}`, ramp.guid, ownerHistoryId, geomSubContextId, storeyPlacementId);
|
|
12285
12295
|
if (!result.ok) return (0, brepjs.err)(result.error);
|
|
12286
12296
|
idMap.set(ramp.localId, result.value.assemblyExpressId);
|
|
12287
12297
|
writeRampCommonPset(w, ownerHistoryId, result.value.assemblyExpressId, ramp.spec);
|
|
@@ -16495,7 +16505,7 @@ function assignNum(target, key, value) {
|
|
|
16495
16505
|
* while the IR path serves the viewport and dedup. GlobalIds derive from
|
|
16496
16506
|
* families key paths (stable under reordering), not insertion order.
|
|
16497
16507
|
*
|
|
16498
|
-
* Scope: Storey containers, Wall/Slab/Column elements, and wall openings — a
|
|
16508
|
+
* Scope: Storey containers, Wall/Slab/Column/Beam/Roof/Stair elements, and wall openings — a
|
|
16499
16509
|
* fill-role void (Door/Window family) maps onto addDoor/addWindow, which cut
|
|
16500
16510
|
* the wall and wire IfcRelVoidsElement + IfcRelFillsElement; the opening and
|
|
16501
16511
|
* filler GlobalIds derive from the synthesized key paths. Anonymous (non-fill)
|
|
@@ -16525,6 +16535,65 @@ var GEOMETRY_PROPS = /* @__PURE__ */ new Set([
|
|
|
16525
16535
|
"transform",
|
|
16526
16536
|
"psets"
|
|
16527
16537
|
]);
|
|
16538
|
+
var SPEC_ROUTES = {
|
|
16539
|
+
Wall: {
|
|
16540
|
+
parse: parseWallSpec,
|
|
16541
|
+
add: (m, spec, key) => m.addWall(spec, { stableKey: key })
|
|
16542
|
+
},
|
|
16543
|
+
Slab: {
|
|
16544
|
+
parse: parseSlabSpec,
|
|
16545
|
+
add: (m, spec, key) => m.addSlab(spec, { stableKey: key })
|
|
16546
|
+
},
|
|
16547
|
+
Column: {
|
|
16548
|
+
parse: parseColumnSpec,
|
|
16549
|
+
add: (m, spec, key) => m.addColumn(spec, { stableKey: key })
|
|
16550
|
+
},
|
|
16551
|
+
Beam: {
|
|
16552
|
+
parse: parseBeamSpec,
|
|
16553
|
+
add: (m, spec, key) => m.addBeam(spec, { stableKey: key })
|
|
16554
|
+
},
|
|
16555
|
+
Roof: {
|
|
16556
|
+
parse: parseRoofSpec,
|
|
16557
|
+
add: (m, spec, key) => m.addRoof(spec, { stableKey: key })
|
|
16558
|
+
},
|
|
16559
|
+
Stair: {
|
|
16560
|
+
parse: parseStairSpec,
|
|
16561
|
+
add: (m, spec, key) => m.addStair(spec, { stableKey: key }),
|
|
16562
|
+
input: stairSpecInput
|
|
16563
|
+
}
|
|
16564
|
+
};
|
|
16565
|
+
/** StairSpec has no top-level origin — placement lives per flight — so the
|
|
16566
|
+
* element's folded translate lands on every flight's origin instead. */
|
|
16567
|
+
function stairSpecInput(el) {
|
|
16568
|
+
const base = specInput(el);
|
|
16569
|
+
const fold = base["origin"] ?? [
|
|
16570
|
+
0,
|
|
16571
|
+
0,
|
|
16572
|
+
0
|
|
16573
|
+
];
|
|
16574
|
+
const flights = Array.isArray(base["flights"]) ? base["flights"] : [];
|
|
16575
|
+
return {
|
|
16576
|
+
...base,
|
|
16577
|
+
flights: flights.map((f) => {
|
|
16578
|
+
const fo = f["origin"] ?? [
|
|
16579
|
+
0,
|
|
16580
|
+
0,
|
|
16581
|
+
0
|
|
16582
|
+
];
|
|
16583
|
+
return {
|
|
16584
|
+
...f,
|
|
16585
|
+
origin: [
|
|
16586
|
+
fo[0] + fold[0],
|
|
16587
|
+
fo[1] + fold[1],
|
|
16588
|
+
fo[2] + fold[2]
|
|
16589
|
+
]
|
|
16590
|
+
};
|
|
16591
|
+
})
|
|
16592
|
+
};
|
|
16593
|
+
}
|
|
16594
|
+
function specRoute(type) {
|
|
16595
|
+
return Object.hasOwn(SPEC_ROUTES, type) ? SPEC_ROUTES[type] : void 0;
|
|
16596
|
+
}
|
|
16528
16597
|
/** Total of the resolved geometry's OUTER literal translate chain. The
|
|
16529
16598
|
* transform vocabulary is translate-only, so frame differences are exact
|
|
16530
16599
|
* subtractions. Parameter-driven translations stop the peel. */
|
|
@@ -16670,6 +16739,7 @@ function familiesToBim(root, options) {
|
|
|
16670
16739
|
const idByKeyPath = /* @__PURE__ */ new Map();
|
|
16671
16740
|
const walk = (el, storeyId) => {
|
|
16672
16741
|
let containerId = storeyId;
|
|
16742
|
+
const route = specRoute(el.type);
|
|
16673
16743
|
if (el.type === "Storey") {
|
|
16674
16744
|
const keyed = requireKeyed(el);
|
|
16675
16745
|
if (!keyed.ok) return keyed;
|
|
@@ -16680,12 +16750,12 @@ function familiesToBim(root, options) {
|
|
|
16680
16750
|
model.aggregate(buildingId, id);
|
|
16681
16751
|
idByKeyPath.set(el.keyPath, id);
|
|
16682
16752
|
containerId = id;
|
|
16683
|
-
} else if (
|
|
16753
|
+
} else if (route !== void 0) {
|
|
16684
16754
|
const keyed = requireKeyed(el);
|
|
16685
16755
|
if (!keyed.ok) return keyed;
|
|
16686
|
-
const parsed =
|
|
16756
|
+
const parsed = route.parse(("input" in route ? route.input : specInput)(el));
|
|
16687
16757
|
if (!parsed.ok) return parsed;
|
|
16688
|
-
const added =
|
|
16758
|
+
const added = route.add(model, parsed.value, el.keyPath);
|
|
16689
16759
|
if (!added.ok) return added;
|
|
16690
16760
|
idByKeyPath.set(el.keyPath, added.value);
|
|
16691
16761
|
if (containerId === null) return (0, brepjs.err)(specError("FAMILIES_NO_STOREY", `familiesToBim: '${el.keyPath}' has no Storey ancestor — IFC elements need spatial containment`));
|
package/dist/brepjs-bim.js
CHANGED
|
@@ -6355,10 +6355,12 @@ var BimModel = class {
|
|
|
6355
6355
|
this.#associateClassification(id, spec);
|
|
6356
6356
|
return ok(id);
|
|
6357
6357
|
}
|
|
6358
|
-
addBeam(spec) {
|
|
6358
|
+
addBeam(spec, options) {
|
|
6359
|
+
const keyCheck = this.#checkStableKey(options);
|
|
6360
|
+
if (!keyCheck.ok) return keyCheck;
|
|
6359
6361
|
const geomResult = beamToSolid(spec);
|
|
6360
6362
|
if (!geomResult.ok) return err(geomResult.error);
|
|
6361
|
-
const id = this.#makeElement("BEAM", spec, geomResult.value);
|
|
6363
|
+
const id = this.#makeElement("BEAM", spec, geomResult.value, options?.stableKey);
|
|
6362
6364
|
this.#associateMaterial(id, spec);
|
|
6363
6365
|
this.#associateClassification(id, spec);
|
|
6364
6366
|
return ok(id);
|
|
@@ -6381,10 +6383,12 @@ var BimModel = class {
|
|
|
6381
6383
|
this.#associateClassification(id, spec);
|
|
6382
6384
|
return ok(id);
|
|
6383
6385
|
}
|
|
6384
|
-
addRoof(spec) {
|
|
6386
|
+
addRoof(spec, options) {
|
|
6387
|
+
const keyCheck = this.#checkStableKey(options);
|
|
6388
|
+
if (!keyCheck.ok) return keyCheck;
|
|
6385
6389
|
const geomResult = roofToSolid(spec);
|
|
6386
6390
|
if (!geomResult.ok) return err(geomResult.error);
|
|
6387
|
-
const id = this.#makeElement("ROOF", spec, geomResult.value);
|
|
6391
|
+
const id = this.#makeElement("ROOF", spec, geomResult.value, options?.stableKey);
|
|
6388
6392
|
this.#associateMaterial(id, spec);
|
|
6389
6393
|
this.#associateClassification(id, spec);
|
|
6390
6394
|
return ok(id);
|
|
@@ -6418,8 +6422,10 @@ var BimModel = class {
|
|
|
6418
6422
|
* the IFC layer from `spec.flights`; the STAIR element itself carries no solid
|
|
6419
6423
|
* (the assembly container's Representation is null, valid per IFC4).
|
|
6420
6424
|
*/
|
|
6421
|
-
addStair(spec) {
|
|
6422
|
-
const
|
|
6425
|
+
addStair(spec, options) {
|
|
6426
|
+
const keyCheck = this.#checkStableKey(options);
|
|
6427
|
+
if (!keyCheck.ok) return keyCheck;
|
|
6428
|
+
const id = this.#makeElement("STAIR", spec, null, options?.stableKey);
|
|
6423
6429
|
this.#associateMaterial(id, spec);
|
|
6424
6430
|
this.#associateClassification(id, spec);
|
|
6425
6431
|
return ok(id);
|
|
@@ -6428,8 +6434,10 @@ var BimModel = class {
|
|
|
6428
6434
|
* Adds an IfcRamp assembly. Geometry for each flight is built and written by the
|
|
6429
6435
|
* IFC layer from `spec.flights`; the RAMP element carries no solid of its own.
|
|
6430
6436
|
*/
|
|
6431
|
-
addRamp(spec) {
|
|
6432
|
-
const
|
|
6437
|
+
addRamp(spec, options) {
|
|
6438
|
+
const keyCheck = this.#checkStableKey(options);
|
|
6439
|
+
if (!keyCheck.ok) return keyCheck;
|
|
6440
|
+
const id = this.#makeElement("RAMP", spec, null, options?.stableKey);
|
|
6433
6441
|
this.#associateMaterial(id, spec);
|
|
6434
6442
|
this.#associateClassification(id, spec);
|
|
6435
6443
|
return ok(id);
|
|
@@ -9605,13 +9613,15 @@ function writeRampEntity(w, guid, name, predefinedType, ownerHistoryId, localPla
|
|
|
9605
9613
|
* per `spec.flights[i]` (each with a tessellated stepped-solid body), and a single
|
|
9606
9614
|
* IfcRelAggregates linking the flights to the stair. Flight placements are
|
|
9607
9615
|
* relative to the stair placement, which is relative to `parentPlacementId`
|
|
9608
|
-
* (typically the storey).
|
|
9616
|
+
* (typically the storey). The assembly's GlobalId is the element's stored guid
|
|
9617
|
+
* (stableKey-derived when the caller provided one); flight, type, and
|
|
9618
|
+
* relationship GUIDs are deterministic, keyed on `stairKey`/index so
|
|
9609
9619
|
* re-serializing an identical model is byte-stable.
|
|
9610
9620
|
*
|
|
9611
9621
|
* Returns a BimError if any flight solid cannot be built. Stair flights are real
|
|
9612
9622
|
* stepped solids; tessellation failure is flagged via `geometrySimplified`.
|
|
9613
9623
|
*/
|
|
9614
|
-
function writeStairAssembly(w, spec, stairKey, ownerHistoryId, geomSubContextId, parentPlacementId) {
|
|
9624
|
+
function writeStairAssembly(w, spec, stairKey, assemblyGuid, ownerHistoryId, geomSubContextId, parentPlacementId) {
|
|
9615
9625
|
const predefinedType = spec.predefinedType ?? "NOTDEFINED";
|
|
9616
9626
|
const stairName = spec.name ?? "Stair";
|
|
9617
9627
|
if (spec.flights[0] === void 0) return {
|
|
@@ -9631,7 +9641,7 @@ function writeStairAssembly(w, spec, stairKey, ownerHistoryId, geomSubContextId,
|
|
|
9631
9641
|
0,
|
|
9632
9642
|
0
|
|
9633
9643
|
], parentPlacementId);
|
|
9634
|
-
const assemblyExpressId = writeStairEntity(w,
|
|
9644
|
+
const assemblyExpressId = writeStairEntity(w, assemblyGuid, stairName, predefinedType, ownerHistoryId, stairPlacementId);
|
|
9635
9645
|
const flightExpressIds = [];
|
|
9636
9646
|
let geometrySimplified = false;
|
|
9637
9647
|
for (const [i, flight] of spec.flights.entries()) try {
|
|
@@ -9671,7 +9681,7 @@ function writeStairAssembly(w, spec, stairKey, ownerHistoryId, geomSubContextId,
|
|
|
9671
9681
|
* inclined-slab solids, so `geometrySimplified` is always true. GUIDs are
|
|
9672
9682
|
* deterministic keyed on `rampKey`.
|
|
9673
9683
|
*/
|
|
9674
|
-
function writeRampAssembly(w, spec, rampKey, ownerHistoryId, geomSubContextId, parentPlacementId) {
|
|
9684
|
+
function writeRampAssembly(w, spec, rampKey, assemblyGuid, ownerHistoryId, geomSubContextId, parentPlacementId) {
|
|
9675
9685
|
const predefinedType = spec.predefinedType ?? "NOTDEFINED";
|
|
9676
9686
|
const rampName = spec.name ?? "Ramp";
|
|
9677
9687
|
if (spec.flights[0] === void 0) return {
|
|
@@ -9691,7 +9701,7 @@ function writeRampAssembly(w, spec, rampKey, ownerHistoryId, geomSubContextId, p
|
|
|
9691
9701
|
0,
|
|
9692
9702
|
0
|
|
9693
9703
|
], parentPlacementId);
|
|
9694
|
-
const assemblyExpressId = writeRampEntity(w,
|
|
9704
|
+
const assemblyExpressId = writeRampEntity(w, assemblyGuid, rampName, predefinedType, ownerHistoryId, rampPlacementId);
|
|
9695
9705
|
const flightExpressIds = [];
|
|
9696
9706
|
const geometrySimplified = true;
|
|
9697
9707
|
for (const [i, flight] of spec.flights.entries()) try {
|
|
@@ -12250,7 +12260,7 @@ async function toIfc(model, meta) {
|
|
|
12250
12260
|
for (const stair of stairs) {
|
|
12251
12261
|
const containingId = findContainerOf(stair.localId, relationships);
|
|
12252
12262
|
const storeyPlacementId = containingId !== null ? placementMap.get(containingId) ?? null : null;
|
|
12253
|
-
const result = writeStairAssembly(w, stair.spec, `${stair.localId}`, ownerHistoryId, geomSubContextId, storeyPlacementId);
|
|
12263
|
+
const result = writeStairAssembly(w, stair.spec, `${stair.localId}`, stair.guid, ownerHistoryId, geomSubContextId, storeyPlacementId);
|
|
12254
12264
|
if (!result.ok) return err(result.error);
|
|
12255
12265
|
idMap.set(stair.localId, result.value.assemblyExpressId);
|
|
12256
12266
|
writeStairCommonPset(w, ownerHistoryId, result.value.assemblyExpressId, stair.spec);
|
|
@@ -12258,7 +12268,7 @@ async function toIfc(model, meta) {
|
|
|
12258
12268
|
for (const ramp of ramps) {
|
|
12259
12269
|
const containingId = findContainerOf(ramp.localId, relationships);
|
|
12260
12270
|
const storeyPlacementId = containingId !== null ? placementMap.get(containingId) ?? null : null;
|
|
12261
|
-
const result = writeRampAssembly(w, ramp.spec, `${ramp.localId}`, ownerHistoryId, geomSubContextId, storeyPlacementId);
|
|
12271
|
+
const result = writeRampAssembly(w, ramp.spec, `${ramp.localId}`, ramp.guid, ownerHistoryId, geomSubContextId, storeyPlacementId);
|
|
12262
12272
|
if (!result.ok) return err(result.error);
|
|
12263
12273
|
idMap.set(ramp.localId, result.value.assemblyExpressId);
|
|
12264
12274
|
writeRampCommonPset(w, ownerHistoryId, result.value.assemblyExpressId, ramp.spec);
|
|
@@ -16472,7 +16482,7 @@ function assignNum(target, key, value) {
|
|
|
16472
16482
|
* while the IR path serves the viewport and dedup. GlobalIds derive from
|
|
16473
16483
|
* families key paths (stable under reordering), not insertion order.
|
|
16474
16484
|
*
|
|
16475
|
-
* Scope: Storey containers, Wall/Slab/Column elements, and wall openings — a
|
|
16485
|
+
* Scope: Storey containers, Wall/Slab/Column/Beam/Roof/Stair elements, and wall openings — a
|
|
16476
16486
|
* fill-role void (Door/Window family) maps onto addDoor/addWindow, which cut
|
|
16477
16487
|
* the wall and wire IfcRelVoidsElement + IfcRelFillsElement; the opening and
|
|
16478
16488
|
* filler GlobalIds derive from the synthesized key paths. Anonymous (non-fill)
|
|
@@ -16502,6 +16512,65 @@ var GEOMETRY_PROPS = /* @__PURE__ */ new Set([
|
|
|
16502
16512
|
"transform",
|
|
16503
16513
|
"psets"
|
|
16504
16514
|
]);
|
|
16515
|
+
var SPEC_ROUTES = {
|
|
16516
|
+
Wall: {
|
|
16517
|
+
parse: parseWallSpec,
|
|
16518
|
+
add: (m, spec, key) => m.addWall(spec, { stableKey: key })
|
|
16519
|
+
},
|
|
16520
|
+
Slab: {
|
|
16521
|
+
parse: parseSlabSpec,
|
|
16522
|
+
add: (m, spec, key) => m.addSlab(spec, { stableKey: key })
|
|
16523
|
+
},
|
|
16524
|
+
Column: {
|
|
16525
|
+
parse: parseColumnSpec,
|
|
16526
|
+
add: (m, spec, key) => m.addColumn(spec, { stableKey: key })
|
|
16527
|
+
},
|
|
16528
|
+
Beam: {
|
|
16529
|
+
parse: parseBeamSpec,
|
|
16530
|
+
add: (m, spec, key) => m.addBeam(spec, { stableKey: key })
|
|
16531
|
+
},
|
|
16532
|
+
Roof: {
|
|
16533
|
+
parse: parseRoofSpec,
|
|
16534
|
+
add: (m, spec, key) => m.addRoof(spec, { stableKey: key })
|
|
16535
|
+
},
|
|
16536
|
+
Stair: {
|
|
16537
|
+
parse: parseStairSpec,
|
|
16538
|
+
add: (m, spec, key) => m.addStair(spec, { stableKey: key }),
|
|
16539
|
+
input: stairSpecInput
|
|
16540
|
+
}
|
|
16541
|
+
};
|
|
16542
|
+
/** StairSpec has no top-level origin — placement lives per flight — so the
|
|
16543
|
+
* element's folded translate lands on every flight's origin instead. */
|
|
16544
|
+
function stairSpecInput(el) {
|
|
16545
|
+
const base = specInput(el);
|
|
16546
|
+
const fold = base["origin"] ?? [
|
|
16547
|
+
0,
|
|
16548
|
+
0,
|
|
16549
|
+
0
|
|
16550
|
+
];
|
|
16551
|
+
const flights = Array.isArray(base["flights"]) ? base["flights"] : [];
|
|
16552
|
+
return {
|
|
16553
|
+
...base,
|
|
16554
|
+
flights: flights.map((f) => {
|
|
16555
|
+
const fo = f["origin"] ?? [
|
|
16556
|
+
0,
|
|
16557
|
+
0,
|
|
16558
|
+
0
|
|
16559
|
+
];
|
|
16560
|
+
return {
|
|
16561
|
+
...f,
|
|
16562
|
+
origin: [
|
|
16563
|
+
fo[0] + fold[0],
|
|
16564
|
+
fo[1] + fold[1],
|
|
16565
|
+
fo[2] + fold[2]
|
|
16566
|
+
]
|
|
16567
|
+
};
|
|
16568
|
+
})
|
|
16569
|
+
};
|
|
16570
|
+
}
|
|
16571
|
+
function specRoute(type) {
|
|
16572
|
+
return Object.hasOwn(SPEC_ROUTES, type) ? SPEC_ROUTES[type] : void 0;
|
|
16573
|
+
}
|
|
16505
16574
|
/** Total of the resolved geometry's OUTER literal translate chain. The
|
|
16506
16575
|
* transform vocabulary is translate-only, so frame differences are exact
|
|
16507
16576
|
* subtractions. Parameter-driven translations stop the peel. */
|
|
@@ -16647,6 +16716,7 @@ function familiesToBim(root, options) {
|
|
|
16647
16716
|
const idByKeyPath = /* @__PURE__ */ new Map();
|
|
16648
16717
|
const walk = (el, storeyId) => {
|
|
16649
16718
|
let containerId = storeyId;
|
|
16719
|
+
const route = specRoute(el.type);
|
|
16650
16720
|
if (el.type === "Storey") {
|
|
16651
16721
|
const keyed = requireKeyed(el);
|
|
16652
16722
|
if (!keyed.ok) return keyed;
|
|
@@ -16657,12 +16727,12 @@ function familiesToBim(root, options) {
|
|
|
16657
16727
|
model.aggregate(buildingId, id);
|
|
16658
16728
|
idByKeyPath.set(el.keyPath, id);
|
|
16659
16729
|
containerId = id;
|
|
16660
|
-
} else if (
|
|
16730
|
+
} else if (route !== void 0) {
|
|
16661
16731
|
const keyed = requireKeyed(el);
|
|
16662
16732
|
if (!keyed.ok) return keyed;
|
|
16663
|
-
const parsed =
|
|
16733
|
+
const parsed = route.parse(("input" in route ? route.input : specInput)(el));
|
|
16664
16734
|
if (!parsed.ok) return parsed;
|
|
16665
|
-
const added =
|
|
16735
|
+
const added = route.add(model, parsed.value, el.keyPath);
|
|
16666
16736
|
if (!added.ok) return added;
|
|
16667
16737
|
idByKeyPath.set(el.keyPath, added.value);
|
|
16668
16738
|
if (containerId === null) return err(specError("FAMILIES_NO_STOREY", `familiesToBim: '${el.keyPath}' has no Storey ancestor — IFC elements need spatial containment`));
|
|
@@ -20,13 +20,15 @@ export interface AssemblyWriteResult {
|
|
|
20
20
|
* per `spec.flights[i]` (each with a tessellated stepped-solid body), and a single
|
|
21
21
|
* IfcRelAggregates linking the flights to the stair. Flight placements are
|
|
22
22
|
* relative to the stair placement, which is relative to `parentPlacementId`
|
|
23
|
-
* (typically the storey).
|
|
23
|
+
* (typically the storey). The assembly's GlobalId is the element's stored guid
|
|
24
|
+
* (stableKey-derived when the caller provided one); flight, type, and
|
|
25
|
+
* relationship GUIDs are deterministic, keyed on `stairKey`/index so
|
|
24
26
|
* re-serializing an identical model is byte-stable.
|
|
25
27
|
*
|
|
26
28
|
* Returns a BimError if any flight solid cannot be built. Stair flights are real
|
|
27
29
|
* stepped solids; tessellation failure is flagged via `geometrySimplified`.
|
|
28
30
|
*/
|
|
29
|
-
export declare function writeStairAssembly(w: IfcWriter, spec: StairSpec, stairKey: string, ownerHistoryId: number, geomSubContextId: number, parentPlacementId: number | null): {
|
|
31
|
+
export declare function writeStairAssembly(w: IfcWriter, spec: StairSpec, stairKey: string, assemblyGuid: string, ownerHistoryId: number, geomSubContextId: number, parentPlacementId: number | null): {
|
|
30
32
|
ok: true;
|
|
31
33
|
value: AssemblyWriteResult;
|
|
32
34
|
} | {
|
|
@@ -40,7 +42,7 @@ export declare function writeStairAssembly(w: IfcWriter, spec: StairSpec, stairK
|
|
|
40
42
|
* inclined-slab solids, so `geometrySimplified` is always true. GUIDs are
|
|
41
43
|
* deterministic keyed on `rampKey`.
|
|
42
44
|
*/
|
|
43
|
-
export declare function writeRampAssembly(w: IfcWriter, spec: RampSpec, rampKey: string, ownerHistoryId: number, geomSubContextId: number, parentPlacementId: number | null): {
|
|
45
|
+
export declare function writeRampAssembly(w: IfcWriter, spec: RampSpec, rampKey: string, assemblyGuid: string, ownerHistoryId: number, geomSubContextId: number, parentPlacementId: number | null): {
|
|
44
46
|
ok: true;
|
|
45
47
|
value: AssemblyWriteResult;
|
|
46
48
|
} | {
|
package/dist/model/bimModel.d.ts
CHANGED
|
@@ -42,10 +42,10 @@ export declare class BimModel {
|
|
|
42
42
|
addStorey(spec: StoreySpec, options?: ElementIdentityOptions): LocalId;
|
|
43
43
|
addWall(spec: WallSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
|
|
44
44
|
addSlab(spec: SlabSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
|
|
45
|
-
addBeam(spec: BeamSpec): Result<LocalId, BimError>;
|
|
45
|
+
addBeam(spec: BeamSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
|
|
46
46
|
addColumn(spec: ColumnSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
|
|
47
47
|
addSpace(spec: SpaceSpec): Result<LocalId, BimError>;
|
|
48
|
-
addRoof(spec: RoofSpec): Result<LocalId, BimError>;
|
|
48
|
+
addRoof(spec: RoofSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
|
|
49
49
|
addCurtainWall(spec: CurtainWallSpec): Result<LocalId, BimError>;
|
|
50
50
|
addFooting(spec: FootingSpec): Result<LocalId, BimError>;
|
|
51
51
|
addPile(spec: PileSpec): Result<LocalId, BimError>;
|
|
@@ -54,12 +54,12 @@ export declare class BimModel {
|
|
|
54
54
|
* the IFC layer from `spec.flights`; the STAIR element itself carries no solid
|
|
55
55
|
* (the assembly container's Representation is null, valid per IFC4).
|
|
56
56
|
*/
|
|
57
|
-
addStair(spec: StairSpec): Result<LocalId, BimError>;
|
|
57
|
+
addStair(spec: StairSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
|
|
58
58
|
/**
|
|
59
59
|
* Adds an IfcRamp assembly. Geometry for each flight is built and written by the
|
|
60
60
|
* IFC layer from `spec.flights`; the RAMP element carries no solid of its own.
|
|
61
61
|
*/
|
|
62
|
-
addRamp(spec: RampSpec): Result<LocalId, BimError>;
|
|
62
|
+
addRamp(spec: RampSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
|
|
63
63
|
addRailing(spec: RailingSpec): Result<LocalId, BimError>;
|
|
64
64
|
/**
|
|
65
65
|
* Adds an IfcCovering. When `hostLocalId` is supplied, an
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brepjs-bim",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "BIM layer for brepjs — IFC4-aligned parametric building elements",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bim",
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"build": "vite build",
|
|
44
44
|
"typecheck": "tsgo --noEmit",
|
|
45
45
|
"test": "vitest run",
|
|
46
|
+
"test:coverage": "vitest run --coverage",
|
|
46
47
|
"lint": "eslint src tests"
|
|
47
48
|
},
|
|
48
49
|
"peerDependencies": {
|