brepjs-bim 0.19.0 → 0.21.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 +92 -26
- package/dist/brepjs-bim.js +92 -26
- package/dist/familiesAdapter.d.ts +14 -0
- package/dist/index.d.ts +1 -1
- package/package.json +1 -1
package/dist/brepjs-bim.cjs
CHANGED
|
@@ -27620,7 +27620,8 @@ function assignNum(target, key, value) {
|
|
|
27620
27620
|
* while the IR path serves the viewport and dedup. GlobalIds derive from
|
|
27621
27621
|
* families key paths (stable under reordering), not insertion order.
|
|
27622
27622
|
*
|
|
27623
|
-
* Scope: Storey containers
|
|
27623
|
+
* Scope: Storey containers; Wall/Slab/Column/Beam/Roof/Stair, Footing/Pile,
|
|
27624
|
+
* Railing/Ramp, Covering/CurtainWall, and Space elements; and wall openings — a
|
|
27624
27625
|
* fill-role void (Door/Window family) maps onto addDoor/addWindow, which cut
|
|
27625
27626
|
* the wall and wire IfcRelVoidsElement + IfcRelFillsElement; the opening and
|
|
27626
27627
|
* filler GlobalIds derive from the synthesized key paths. Anonymous (non-fill)
|
|
@@ -27652,35 +27653,64 @@ var GEOMETRY_PROPS = /* @__PURE__ */ new Set([
|
|
|
27652
27653
|
"psets"
|
|
27653
27654
|
]);
|
|
27654
27655
|
var SPEC_ROUTES = {
|
|
27655
|
-
|
|
27656
|
+
wall: {
|
|
27656
27657
|
parse: parseWallSpec,
|
|
27657
27658
|
add: (m, spec, key) => m.addWall(spec, { stableKey: key })
|
|
27658
27659
|
},
|
|
27659
|
-
|
|
27660
|
+
slab: {
|
|
27660
27661
|
parse: parseSlabSpec,
|
|
27661
27662
|
add: (m, spec, key) => m.addSlab(spec, { stableKey: key })
|
|
27662
27663
|
},
|
|
27663
|
-
|
|
27664
|
+
column: {
|
|
27664
27665
|
parse: parseColumnSpec,
|
|
27665
27666
|
add: (m, spec, key) => m.addColumn(spec, { stableKey: key })
|
|
27666
27667
|
},
|
|
27667
|
-
|
|
27668
|
+
beam: {
|
|
27668
27669
|
parse: parseBeamSpec,
|
|
27669
27670
|
add: (m, spec, key) => m.addBeam(spec, { stableKey: key })
|
|
27670
27671
|
},
|
|
27671
|
-
|
|
27672
|
+
roof: {
|
|
27672
27673
|
parse: parseRoofSpec,
|
|
27673
27674
|
add: (m, spec, key) => m.addRoof(spec, { stableKey: key })
|
|
27674
27675
|
},
|
|
27675
|
-
|
|
27676
|
+
stair: {
|
|
27676
27677
|
parse: parseStairSpec,
|
|
27677
27678
|
add: (m, spec, key) => m.addStair(spec, { stableKey: key }),
|
|
27678
|
-
input:
|
|
27679
|
+
input: flightsSpecInput
|
|
27680
|
+
},
|
|
27681
|
+
footing: {
|
|
27682
|
+
parse: parseFootingSpec,
|
|
27683
|
+
add: (m, spec, key) => m.addFooting(spec, { stableKey: key })
|
|
27684
|
+
},
|
|
27685
|
+
pile: {
|
|
27686
|
+
parse: parsePileSpec,
|
|
27687
|
+
add: (m, spec, key) => m.addPile(spec, { stableKey: key })
|
|
27688
|
+
},
|
|
27689
|
+
railing: {
|
|
27690
|
+
parse: parseRailingSpec,
|
|
27691
|
+
add: (m, spec, key) => m.addRailing(spec, { stableKey: key })
|
|
27692
|
+
},
|
|
27693
|
+
ramp: {
|
|
27694
|
+
parse: parseRampSpec,
|
|
27695
|
+
add: (m, spec, key) => m.addRamp(spec, { stableKey: key }),
|
|
27696
|
+
input: flightsSpecInput
|
|
27697
|
+
},
|
|
27698
|
+
covering: {
|
|
27699
|
+
parse: parseCoveringSpec,
|
|
27700
|
+
add: (m, spec, key) => m.addCovering(spec, void 0, { stableKey: key })
|
|
27701
|
+
},
|
|
27702
|
+
curtainWall: {
|
|
27703
|
+
parse: parseCurtainWallSpec,
|
|
27704
|
+
add: (m, spec, key) => m.addCurtainWall(spec, { stableKey: key })
|
|
27705
|
+
},
|
|
27706
|
+
space: {
|
|
27707
|
+
parse: parseSpaceSpec,
|
|
27708
|
+
add: (m, spec, key) => m.addSpace(spec, { stableKey: key })
|
|
27679
27709
|
}
|
|
27680
27710
|
};
|
|
27681
|
-
/**
|
|
27682
|
-
* element's folded translate lands on every flight's origin instead. */
|
|
27683
|
-
function
|
|
27711
|
+
/** Stair and ramp specs have no top-level origin — placement lives per flight —
|
|
27712
|
+
* so the element's folded translate lands on every flight's origin instead. */
|
|
27713
|
+
function flightsSpecInput(el) {
|
|
27684
27714
|
const base = specInput(el);
|
|
27685
27715
|
const fold = base["origin"] ?? [
|
|
27686
27716
|
0,
|
|
@@ -27707,8 +27737,35 @@ function stairSpecInput(el) {
|
|
|
27707
27737
|
})
|
|
27708
27738
|
};
|
|
27709
27739
|
}
|
|
27710
|
-
|
|
27711
|
-
|
|
27740
|
+
/**
|
|
27741
|
+
* Families predating `archetype` are routed by their display name. Keeping
|
|
27742
|
+
* this fallback makes the declaration purely additive, at the cost of the
|
|
27743
|
+
* original trap surviving for undeclared families: rename one and it stops
|
|
27744
|
+
* routing.
|
|
27745
|
+
*/
|
|
27746
|
+
var NAME_ARCHETYPES = {
|
|
27747
|
+
Storey: "storey",
|
|
27748
|
+
Wall: "wall",
|
|
27749
|
+
Slab: "slab",
|
|
27750
|
+
Column: "column",
|
|
27751
|
+
Beam: "beam",
|
|
27752
|
+
Roof: "roof",
|
|
27753
|
+
Stair: "stair",
|
|
27754
|
+
Door: "door",
|
|
27755
|
+
Window: "window",
|
|
27756
|
+
Footing: "footing",
|
|
27757
|
+
Pile: "pile",
|
|
27758
|
+
Railing: "railing",
|
|
27759
|
+
Ramp: "ramp",
|
|
27760
|
+
Covering: "covering",
|
|
27761
|
+
CurtainWall: "curtainWall",
|
|
27762
|
+
Space: "space"
|
|
27763
|
+
};
|
|
27764
|
+
function archetypeFor(el) {
|
|
27765
|
+
return el.archetype ?? NAME_ARCHETYPES[el.type];
|
|
27766
|
+
}
|
|
27767
|
+
function specRoute(archetype) {
|
|
27768
|
+
return archetype !== void 0 && Object.hasOwn(SPEC_ROUTES, archetype) ? SPEC_ROUTES[archetype] : void 0;
|
|
27712
27769
|
}
|
|
27713
27770
|
/** Total of the resolved geometry's OUTER literal translate chain. The
|
|
27714
27771
|
* transform vocabulary is translate-only, so frame differences are exact
|
|
@@ -27816,17 +27873,18 @@ function collectSpecProps(el) {
|
|
|
27816
27873
|
return out;
|
|
27817
27874
|
}
|
|
27818
27875
|
function addFill(model, fill, input, identity) {
|
|
27819
|
-
|
|
27876
|
+
const archetype = archetypeFor(fill);
|
|
27877
|
+
if (archetype === "door") {
|
|
27820
27878
|
const parsed = parseDoorSpec(input);
|
|
27821
27879
|
if (!parsed.ok) return parsed;
|
|
27822
27880
|
return model.addDoor(parsed.value, identity);
|
|
27823
27881
|
}
|
|
27824
|
-
if (
|
|
27882
|
+
if (archetype === "window") {
|
|
27825
27883
|
const parsed = parseWindowSpec(input);
|
|
27826
27884
|
if (!parsed.ok) return parsed;
|
|
27827
27885
|
return model.addWindow(parsed.value, identity);
|
|
27828
27886
|
}
|
|
27829
|
-
return (0, brepjs.err)(specError("FAMILIES_UNSUPPORTED_FILL", `familiesToBim: no fill mapping for element type '${fill.type}' at '${fill.keyPath}'`));
|
|
27887
|
+
return (0, brepjs.err)(specError("FAMILIES_UNSUPPORTED_FILL", `familiesToBim: no fill mapping for element type '${fill.type}' at '${fill.keyPath}' (archetype: ${archetype ?? "none"}) — a filler needs archetype: 'door' or 'window'`));
|
|
27830
27888
|
}
|
|
27831
27889
|
/** Materialize an unrouted element's IR and add it as a proxy. The body is
|
|
27832
27890
|
* authoritative for a proxy (no parametric spec to diverge from), so baked
|
|
@@ -27930,12 +27988,14 @@ function familiesToBim(root, options) {
|
|
|
27930
27988
|
if (project !== null) model.aggregate(project.localId, siteResult.value);
|
|
27931
27989
|
model.aggregate(siteResult.value, buildingId);
|
|
27932
27990
|
const idByKeyPath = /* @__PURE__ */ new Map();
|
|
27991
|
+
const proxied = [];
|
|
27933
27992
|
const walk = (el, storeyId, rotated) => {
|
|
27934
27993
|
const rotatedHere = rotated || hasRotateOp(el);
|
|
27935
|
-
let
|
|
27994
|
+
let proxiedHere = false;
|
|
27936
27995
|
let containerId = storeyId;
|
|
27937
|
-
const
|
|
27938
|
-
|
|
27996
|
+
const archetype = archetypeFor(el);
|
|
27997
|
+
const route = specRoute(archetype);
|
|
27998
|
+
if (archetype === "storey") {
|
|
27939
27999
|
const keyed = requireKeyed(el);
|
|
27940
28000
|
if (!keyed.ok) return keyed;
|
|
27941
28001
|
const storeyResult = model.addStorey({
|
|
@@ -27960,26 +28020,31 @@ function familiesToBim(root, options) {
|
|
|
27960
28020
|
const added = route.add(model, parsed.value, el.keyPath);
|
|
27961
28021
|
if (!added.ok) return added;
|
|
27962
28022
|
idByKeyPath.set(el.keyPath, added.value);
|
|
27963
|
-
if (containerId === null) return (0, brepjs.err)(specError("FAMILIES_NO_STOREY", `familiesToBim: '${el.keyPath}' has no Storey ancestor — IFC elements need spatial containment`));
|
|
28023
|
+
if (containerId === null) return (0, brepjs.err)(specError("FAMILIES_NO_STOREY", `familiesToBim: '${el.keyPath}' has no Storey ancestor — IFC elements need spatial containment; a container family needs archetype: 'storey' to be recognised under any name`));
|
|
27964
28024
|
model.placeIn(added.value, containerId);
|
|
27965
|
-
if (
|
|
28025
|
+
if (archetype === "wall") {
|
|
27966
28026
|
const opened = addOpenings(model, el, added.value, containerId, idByKeyPath);
|
|
27967
28027
|
if (!opened.ok) return opened;
|
|
27968
28028
|
}
|
|
27969
28029
|
} else if (el.type === "Opening") return (0, brepjs.err)(specError("FAMILIES_OPENING_OUTSIDE_WALL", `familiesToBim: opening '${el.keyPath}' is not hosted by a Wall — only wall openings are mapped`));
|
|
27970
28030
|
else if (el.type !== "Group" && el.geometry.kind !== "Empty") {
|
|
27971
|
-
if (options.proxyEvaluator === void 0) return (0, brepjs.err)(specError("FAMILIES_UNSUPPORTED_TYPE", `familiesToBim: no spec mapping for element type '${el.type}' at '${el.keyPath}' — add a spec route, or pass proxyEvaluator to export it as an IfcBuildingElementProxy`));
|
|
28031
|
+
if (options.proxyEvaluator === void 0) return (0, brepjs.err)(specError("FAMILIES_UNSUPPORTED_TYPE", `familiesToBim: no spec mapping for element type '${el.type}' at '${el.keyPath}' (archetype: ${el.archetype ?? "none"}) — routing is by archetype, so declare one on the family, add a spec route, or pass proxyEvaluator to export it as an IfcBuildingElementProxy`));
|
|
27972
28032
|
const keyed = requireKeyed(el);
|
|
27973
28033
|
if (!keyed.ok) return keyed;
|
|
27974
|
-
if (containerId === null) return (0, brepjs.err)(specError("FAMILIES_NO_STOREY", `familiesToBim: '${el.keyPath}' has no Storey ancestor — IFC elements need spatial containment`));
|
|
28034
|
+
if (containerId === null) return (0, brepjs.err)(specError("FAMILIES_NO_STOREY", `familiesToBim: '${el.keyPath}' has no Storey ancestor — IFC elements need spatial containment; a container family needs archetype: 'storey' to be recognised under any name`));
|
|
27975
28035
|
const added = addProxyElement(model, el, options.proxyEvaluator);
|
|
27976
28036
|
if (!added.ok) return added;
|
|
27977
28037
|
model.placeIn(added.value, containerId);
|
|
27978
28038
|
idByKeyPath.set(el.keyPath, added.value);
|
|
27979
|
-
proxied
|
|
28039
|
+
proxied.push({
|
|
28040
|
+
keyPath: el.keyPath,
|
|
28041
|
+
type: el.type,
|
|
28042
|
+
archetype: el.archetype
|
|
28043
|
+
});
|
|
28044
|
+
proxiedHere = true;
|
|
27980
28045
|
}
|
|
27981
28046
|
for (const child of el.children) {
|
|
27982
|
-
if ((
|
|
28047
|
+
if ((archetype === "wall" || proxiedHere) && child.type === "Opening") continue;
|
|
27983
28048
|
const r = walk(child, containerId, rotatedHere);
|
|
27984
28049
|
if (!r.ok) return r;
|
|
27985
28050
|
}
|
|
@@ -27992,7 +28057,8 @@ function familiesToBim(root, options) {
|
|
|
27992
28057
|
}
|
|
27993
28058
|
return (0, brepjs.ok)({
|
|
27994
28059
|
model,
|
|
27995
|
-
idByKeyPath
|
|
28060
|
+
idByKeyPath,
|
|
28061
|
+
proxied
|
|
27996
28062
|
});
|
|
27997
28063
|
}
|
|
27998
28064
|
//#endregion
|
package/dist/brepjs-bim.js
CHANGED
|
@@ -27597,7 +27597,8 @@ function assignNum(target, key, value) {
|
|
|
27597
27597
|
* while the IR path serves the viewport and dedup. GlobalIds derive from
|
|
27598
27598
|
* families key paths (stable under reordering), not insertion order.
|
|
27599
27599
|
*
|
|
27600
|
-
* Scope: Storey containers
|
|
27600
|
+
* Scope: Storey containers; Wall/Slab/Column/Beam/Roof/Stair, Footing/Pile,
|
|
27601
|
+
* Railing/Ramp, Covering/CurtainWall, and Space elements; and wall openings — a
|
|
27601
27602
|
* fill-role void (Door/Window family) maps onto addDoor/addWindow, which cut
|
|
27602
27603
|
* the wall and wire IfcRelVoidsElement + IfcRelFillsElement; the opening and
|
|
27603
27604
|
* filler GlobalIds derive from the synthesized key paths. Anonymous (non-fill)
|
|
@@ -27629,35 +27630,64 @@ var GEOMETRY_PROPS = /* @__PURE__ */ new Set([
|
|
|
27629
27630
|
"psets"
|
|
27630
27631
|
]);
|
|
27631
27632
|
var SPEC_ROUTES = {
|
|
27632
|
-
|
|
27633
|
+
wall: {
|
|
27633
27634
|
parse: parseWallSpec,
|
|
27634
27635
|
add: (m, spec, key) => m.addWall(spec, { stableKey: key })
|
|
27635
27636
|
},
|
|
27636
|
-
|
|
27637
|
+
slab: {
|
|
27637
27638
|
parse: parseSlabSpec,
|
|
27638
27639
|
add: (m, spec, key) => m.addSlab(spec, { stableKey: key })
|
|
27639
27640
|
},
|
|
27640
|
-
|
|
27641
|
+
column: {
|
|
27641
27642
|
parse: parseColumnSpec,
|
|
27642
27643
|
add: (m, spec, key) => m.addColumn(spec, { stableKey: key })
|
|
27643
27644
|
},
|
|
27644
|
-
|
|
27645
|
+
beam: {
|
|
27645
27646
|
parse: parseBeamSpec,
|
|
27646
27647
|
add: (m, spec, key) => m.addBeam(spec, { stableKey: key })
|
|
27647
27648
|
},
|
|
27648
|
-
|
|
27649
|
+
roof: {
|
|
27649
27650
|
parse: parseRoofSpec,
|
|
27650
27651
|
add: (m, spec, key) => m.addRoof(spec, { stableKey: key })
|
|
27651
27652
|
},
|
|
27652
|
-
|
|
27653
|
+
stair: {
|
|
27653
27654
|
parse: parseStairSpec,
|
|
27654
27655
|
add: (m, spec, key) => m.addStair(spec, { stableKey: key }),
|
|
27655
|
-
input:
|
|
27656
|
+
input: flightsSpecInput
|
|
27657
|
+
},
|
|
27658
|
+
footing: {
|
|
27659
|
+
parse: parseFootingSpec,
|
|
27660
|
+
add: (m, spec, key) => m.addFooting(spec, { stableKey: key })
|
|
27661
|
+
},
|
|
27662
|
+
pile: {
|
|
27663
|
+
parse: parsePileSpec,
|
|
27664
|
+
add: (m, spec, key) => m.addPile(spec, { stableKey: key })
|
|
27665
|
+
},
|
|
27666
|
+
railing: {
|
|
27667
|
+
parse: parseRailingSpec,
|
|
27668
|
+
add: (m, spec, key) => m.addRailing(spec, { stableKey: key })
|
|
27669
|
+
},
|
|
27670
|
+
ramp: {
|
|
27671
|
+
parse: parseRampSpec,
|
|
27672
|
+
add: (m, spec, key) => m.addRamp(spec, { stableKey: key }),
|
|
27673
|
+
input: flightsSpecInput
|
|
27674
|
+
},
|
|
27675
|
+
covering: {
|
|
27676
|
+
parse: parseCoveringSpec,
|
|
27677
|
+
add: (m, spec, key) => m.addCovering(spec, void 0, { stableKey: key })
|
|
27678
|
+
},
|
|
27679
|
+
curtainWall: {
|
|
27680
|
+
parse: parseCurtainWallSpec,
|
|
27681
|
+
add: (m, spec, key) => m.addCurtainWall(spec, { stableKey: key })
|
|
27682
|
+
},
|
|
27683
|
+
space: {
|
|
27684
|
+
parse: parseSpaceSpec,
|
|
27685
|
+
add: (m, spec, key) => m.addSpace(spec, { stableKey: key })
|
|
27656
27686
|
}
|
|
27657
27687
|
};
|
|
27658
|
-
/**
|
|
27659
|
-
* element's folded translate lands on every flight's origin instead. */
|
|
27660
|
-
function
|
|
27688
|
+
/** Stair and ramp specs have no top-level origin — placement lives per flight —
|
|
27689
|
+
* so the element's folded translate lands on every flight's origin instead. */
|
|
27690
|
+
function flightsSpecInput(el) {
|
|
27661
27691
|
const base = specInput(el);
|
|
27662
27692
|
const fold = base["origin"] ?? [
|
|
27663
27693
|
0,
|
|
@@ -27684,8 +27714,35 @@ function stairSpecInput(el) {
|
|
|
27684
27714
|
})
|
|
27685
27715
|
};
|
|
27686
27716
|
}
|
|
27687
|
-
|
|
27688
|
-
|
|
27717
|
+
/**
|
|
27718
|
+
* Families predating `archetype` are routed by their display name. Keeping
|
|
27719
|
+
* this fallback makes the declaration purely additive, at the cost of the
|
|
27720
|
+
* original trap surviving for undeclared families: rename one and it stops
|
|
27721
|
+
* routing.
|
|
27722
|
+
*/
|
|
27723
|
+
var NAME_ARCHETYPES = {
|
|
27724
|
+
Storey: "storey",
|
|
27725
|
+
Wall: "wall",
|
|
27726
|
+
Slab: "slab",
|
|
27727
|
+
Column: "column",
|
|
27728
|
+
Beam: "beam",
|
|
27729
|
+
Roof: "roof",
|
|
27730
|
+
Stair: "stair",
|
|
27731
|
+
Door: "door",
|
|
27732
|
+
Window: "window",
|
|
27733
|
+
Footing: "footing",
|
|
27734
|
+
Pile: "pile",
|
|
27735
|
+
Railing: "railing",
|
|
27736
|
+
Ramp: "ramp",
|
|
27737
|
+
Covering: "covering",
|
|
27738
|
+
CurtainWall: "curtainWall",
|
|
27739
|
+
Space: "space"
|
|
27740
|
+
};
|
|
27741
|
+
function archetypeFor(el) {
|
|
27742
|
+
return el.archetype ?? NAME_ARCHETYPES[el.type];
|
|
27743
|
+
}
|
|
27744
|
+
function specRoute(archetype) {
|
|
27745
|
+
return archetype !== void 0 && Object.hasOwn(SPEC_ROUTES, archetype) ? SPEC_ROUTES[archetype] : void 0;
|
|
27689
27746
|
}
|
|
27690
27747
|
/** Total of the resolved geometry's OUTER literal translate chain. The
|
|
27691
27748
|
* transform vocabulary is translate-only, so frame differences are exact
|
|
@@ -27793,17 +27850,18 @@ function collectSpecProps(el) {
|
|
|
27793
27850
|
return out;
|
|
27794
27851
|
}
|
|
27795
27852
|
function addFill(model, fill, input, identity) {
|
|
27796
|
-
|
|
27853
|
+
const archetype = archetypeFor(fill);
|
|
27854
|
+
if (archetype === "door") {
|
|
27797
27855
|
const parsed = parseDoorSpec(input);
|
|
27798
27856
|
if (!parsed.ok) return parsed;
|
|
27799
27857
|
return model.addDoor(parsed.value, identity);
|
|
27800
27858
|
}
|
|
27801
|
-
if (
|
|
27859
|
+
if (archetype === "window") {
|
|
27802
27860
|
const parsed = parseWindowSpec(input);
|
|
27803
27861
|
if (!parsed.ok) return parsed;
|
|
27804
27862
|
return model.addWindow(parsed.value, identity);
|
|
27805
27863
|
}
|
|
27806
|
-
return err(specError("FAMILIES_UNSUPPORTED_FILL", `familiesToBim: no fill mapping for element type '${fill.type}' at '${fill.keyPath}'`));
|
|
27864
|
+
return err(specError("FAMILIES_UNSUPPORTED_FILL", `familiesToBim: no fill mapping for element type '${fill.type}' at '${fill.keyPath}' (archetype: ${archetype ?? "none"}) — a filler needs archetype: 'door' or 'window'`));
|
|
27807
27865
|
}
|
|
27808
27866
|
/** Materialize an unrouted element's IR and add it as a proxy. The body is
|
|
27809
27867
|
* authoritative for a proxy (no parametric spec to diverge from), so baked
|
|
@@ -27907,12 +27965,14 @@ function familiesToBim(root, options) {
|
|
|
27907
27965
|
if (project !== null) model.aggregate(project.localId, siteResult.value);
|
|
27908
27966
|
model.aggregate(siteResult.value, buildingId);
|
|
27909
27967
|
const idByKeyPath = /* @__PURE__ */ new Map();
|
|
27968
|
+
const proxied = [];
|
|
27910
27969
|
const walk = (el, storeyId, rotated) => {
|
|
27911
27970
|
const rotatedHere = rotated || hasRotateOp(el);
|
|
27912
|
-
let
|
|
27971
|
+
let proxiedHere = false;
|
|
27913
27972
|
let containerId = storeyId;
|
|
27914
|
-
const
|
|
27915
|
-
|
|
27973
|
+
const archetype = archetypeFor(el);
|
|
27974
|
+
const route = specRoute(archetype);
|
|
27975
|
+
if (archetype === "storey") {
|
|
27916
27976
|
const keyed = requireKeyed(el);
|
|
27917
27977
|
if (!keyed.ok) return keyed;
|
|
27918
27978
|
const storeyResult = model.addStorey({
|
|
@@ -27937,26 +27997,31 @@ function familiesToBim(root, options) {
|
|
|
27937
27997
|
const added = route.add(model, parsed.value, el.keyPath);
|
|
27938
27998
|
if (!added.ok) return added;
|
|
27939
27999
|
idByKeyPath.set(el.keyPath, added.value);
|
|
27940
|
-
if (containerId === null) return err(specError("FAMILIES_NO_STOREY", `familiesToBim: '${el.keyPath}' has no Storey ancestor — IFC elements need spatial containment`));
|
|
28000
|
+
if (containerId === null) return err(specError("FAMILIES_NO_STOREY", `familiesToBim: '${el.keyPath}' has no Storey ancestor — IFC elements need spatial containment; a container family needs archetype: 'storey' to be recognised under any name`));
|
|
27941
28001
|
model.placeIn(added.value, containerId);
|
|
27942
|
-
if (
|
|
28002
|
+
if (archetype === "wall") {
|
|
27943
28003
|
const opened = addOpenings(model, el, added.value, containerId, idByKeyPath);
|
|
27944
28004
|
if (!opened.ok) return opened;
|
|
27945
28005
|
}
|
|
27946
28006
|
} else if (el.type === "Opening") return err(specError("FAMILIES_OPENING_OUTSIDE_WALL", `familiesToBim: opening '${el.keyPath}' is not hosted by a Wall — only wall openings are mapped`));
|
|
27947
28007
|
else if (el.type !== "Group" && el.geometry.kind !== "Empty") {
|
|
27948
|
-
if (options.proxyEvaluator === void 0) return err(specError("FAMILIES_UNSUPPORTED_TYPE", `familiesToBim: no spec mapping for element type '${el.type}' at '${el.keyPath}' — add a spec route, or pass proxyEvaluator to export it as an IfcBuildingElementProxy`));
|
|
28008
|
+
if (options.proxyEvaluator === void 0) return err(specError("FAMILIES_UNSUPPORTED_TYPE", `familiesToBim: no spec mapping for element type '${el.type}' at '${el.keyPath}' (archetype: ${el.archetype ?? "none"}) — routing is by archetype, so declare one on the family, add a spec route, or pass proxyEvaluator to export it as an IfcBuildingElementProxy`));
|
|
27949
28009
|
const keyed = requireKeyed(el);
|
|
27950
28010
|
if (!keyed.ok) return keyed;
|
|
27951
|
-
if (containerId === null) return err(specError("FAMILIES_NO_STOREY", `familiesToBim: '${el.keyPath}' has no Storey ancestor — IFC elements need spatial containment`));
|
|
28011
|
+
if (containerId === null) return err(specError("FAMILIES_NO_STOREY", `familiesToBim: '${el.keyPath}' has no Storey ancestor — IFC elements need spatial containment; a container family needs archetype: 'storey' to be recognised under any name`));
|
|
27952
28012
|
const added = addProxyElement(model, el, options.proxyEvaluator);
|
|
27953
28013
|
if (!added.ok) return added;
|
|
27954
28014
|
model.placeIn(added.value, containerId);
|
|
27955
28015
|
idByKeyPath.set(el.keyPath, added.value);
|
|
27956
|
-
proxied
|
|
28016
|
+
proxied.push({
|
|
28017
|
+
keyPath: el.keyPath,
|
|
28018
|
+
type: el.type,
|
|
28019
|
+
archetype: el.archetype
|
|
28020
|
+
});
|
|
28021
|
+
proxiedHere = true;
|
|
27957
28022
|
}
|
|
27958
28023
|
for (const child of el.children) {
|
|
27959
|
-
if ((
|
|
28024
|
+
if ((archetype === "wall" || proxiedHere) && child.type === "Opening") continue;
|
|
27960
28025
|
const r = walk(child, containerId, rotatedHere);
|
|
27961
28026
|
if (!r.ok) return r;
|
|
27962
28027
|
}
|
|
@@ -27969,7 +28034,8 @@ function familiesToBim(root, options) {
|
|
|
27969
28034
|
}
|
|
27970
28035
|
return ok({
|
|
27971
28036
|
model,
|
|
27972
|
-
idByKeyPath
|
|
28037
|
+
idByKeyPath,
|
|
28038
|
+
proxied
|
|
27973
28039
|
});
|
|
27974
28040
|
}
|
|
27975
28041
|
//#endregion
|
|
@@ -18,10 +18,24 @@ export interface FamiliesToBimOptions {
|
|
|
18
18
|
*/
|
|
19
19
|
readonly proxyEvaluator?: csg.Evaluator | undefined;
|
|
20
20
|
}
|
|
21
|
+
export interface ProxiedElement {
|
|
22
|
+
readonly keyPath: string;
|
|
23
|
+
/** The family's display name, as resolved. */
|
|
24
|
+
readonly type: string;
|
|
25
|
+
readonly archetype: string | undefined;
|
|
26
|
+
}
|
|
21
27
|
export interface FamiliesBimResult {
|
|
22
28
|
readonly model: BimModel;
|
|
23
29
|
/** LocalId per geometry-bearing families key path. */
|
|
24
30
|
readonly idByKeyPath: ReadonlyMap<string, LocalId>;
|
|
31
|
+
/**
|
|
32
|
+
* Elements exported as IfcBuildingElementProxy because no spec route
|
|
33
|
+
* matched, in walk order. Only ever non-empty when `proxyEvaluator` is set:
|
|
34
|
+
* without it an unrouted element is a hard error instead. A renamed family
|
|
35
|
+
* that has lost its routing lands here rather than in the file as the type
|
|
36
|
+
* you meant, so check this before trusting an export.
|
|
37
|
+
*/
|
|
38
|
+
readonly proxied: readonly ProxiedElement[];
|
|
25
39
|
}
|
|
26
40
|
/**
|
|
27
41
|
* Project a resolved families tree into an eager BimModel. The caller owns
|
package/dist/index.d.ts
CHANGED
|
@@ -97,4 +97,4 @@ export type { IdsDocument, IdsSpecification, IdsFacet, IdsRestriction, IdsCardin
|
|
|
97
97
|
export { serializeBcfFiles, parseBcfFiles } from './bcf/index.js';
|
|
98
98
|
export type { BcfColoring, BcfComment, BcfComponent, BcfComponents, BcfContainerData, BcfFiles, BcfProject, BcfTopic, BcfVersion, BcfViewpoint, BcfVisibility, } from './bcf/index.js';
|
|
99
99
|
export { bcfError, idsError } from './errors/bimError.js';
|
|
100
|
-
export { familiesToBim, type FamiliesToBimOptions, type FamiliesBimResult, } from './familiesAdapter.js';
|
|
100
|
+
export { familiesToBim, type FamiliesToBimOptions, type FamiliesBimResult, type ProxiedElement, } from './familiesAdapter.js';
|