brepjs-bim 0.18.0 → 0.20.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 +97 -27
- package/dist/brepjs-bim.js +98 -28
- package/dist/familiesAdapter.d.ts +24 -1
- package/dist/index.d.ts +1 -1
- package/package.json +1 -1
package/dist/brepjs-bim.cjs
CHANGED
|
@@ -535,7 +535,7 @@ var propertyKeyTypes = /* @__PURE__*/ new Set([
|
|
|
535
535
|
function escapeRegex(str) {
|
|
536
536
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
537
537
|
}
|
|
538
|
-
function clone(inst, def, params) {
|
|
538
|
+
function clone$1(inst, def, params) {
|
|
539
539
|
const cl = new inst._zod.constr(def ?? inst._zod.def);
|
|
540
540
|
if (!def || params?.parent) cl._zod.parent = inst;
|
|
541
541
|
return cl;
|
|
@@ -571,7 +571,7 @@ function pick(schema, mask) {
|
|
|
571
571
|
const currDef = schema._zod.def;
|
|
572
572
|
const checks = currDef.checks;
|
|
573
573
|
if (checks && checks.length > 0) throw new Error(".pick() cannot be used on object schemas containing refinements");
|
|
574
|
-
return clone(schema, mergeDefs(schema._zod.def, {
|
|
574
|
+
return clone$1(schema, mergeDefs(schema._zod.def, {
|
|
575
575
|
get shape() {
|
|
576
576
|
const newShape = {};
|
|
577
577
|
for (const key in mask) {
|
|
@@ -589,7 +589,7 @@ function omit(schema, mask) {
|
|
|
589
589
|
const currDef = schema._zod.def;
|
|
590
590
|
const checks = currDef.checks;
|
|
591
591
|
if (checks && checks.length > 0) throw new Error(".omit() cannot be used on object schemas containing refinements");
|
|
592
|
-
return clone(schema, mergeDefs(schema._zod.def, {
|
|
592
|
+
return clone$1(schema, mergeDefs(schema._zod.def, {
|
|
593
593
|
get shape() {
|
|
594
594
|
const newShape = { ...schema._zod.def.shape };
|
|
595
595
|
for (const key in mask) {
|
|
@@ -610,7 +610,7 @@ function extend(schema, shape) {
|
|
|
610
610
|
const existingShape = schema._zod.def.shape;
|
|
611
611
|
for (const key in shape) if (Object.getOwnPropertyDescriptor(existingShape, key) !== void 0) throw new Error("Cannot overwrite keys on object schemas containing refinements. Use `.safeExtend()` instead.");
|
|
612
612
|
}
|
|
613
|
-
return clone(schema, mergeDefs(schema._zod.def, { get shape() {
|
|
613
|
+
return clone$1(schema, mergeDefs(schema._zod.def, { get shape() {
|
|
614
614
|
const _shape = {
|
|
615
615
|
...schema._zod.def.shape,
|
|
616
616
|
...shape
|
|
@@ -621,7 +621,7 @@ function extend(schema, shape) {
|
|
|
621
621
|
}
|
|
622
622
|
function safeExtend(schema, shape) {
|
|
623
623
|
if (!isPlainObject(shape)) throw new Error("Invalid input to safeExtend: expected a plain object");
|
|
624
|
-
return clone(schema, mergeDefs(schema._zod.def, { get shape() {
|
|
624
|
+
return clone$1(schema, mergeDefs(schema._zod.def, { get shape() {
|
|
625
625
|
const _shape = {
|
|
626
626
|
...schema._zod.def.shape,
|
|
627
627
|
...shape
|
|
@@ -632,7 +632,7 @@ function safeExtend(schema, shape) {
|
|
|
632
632
|
}
|
|
633
633
|
function merge(a, b) {
|
|
634
634
|
if (a._zod.def.checks?.length) throw new Error(".merge() cannot be used on object schemas containing refinements. Use .safeExtend() instead.");
|
|
635
|
-
return clone(a, mergeDefs(a._zod.def, {
|
|
635
|
+
return clone$1(a, mergeDefs(a._zod.def, {
|
|
636
636
|
get shape() {
|
|
637
637
|
const _shape = {
|
|
638
638
|
...a._zod.def.shape,
|
|
@@ -650,7 +650,7 @@ function merge(a, b) {
|
|
|
650
650
|
function partial(Class, schema, mask) {
|
|
651
651
|
const checks = schema._zod.def.checks;
|
|
652
652
|
if (checks && checks.length > 0) throw new Error(".partial() cannot be used on object schemas containing refinements");
|
|
653
|
-
return clone(schema, mergeDefs(schema._zod.def, {
|
|
653
|
+
return clone$1(schema, mergeDefs(schema._zod.def, {
|
|
654
654
|
get shape() {
|
|
655
655
|
const oldShape = schema._zod.def.shape;
|
|
656
656
|
const shape = { ...oldShape };
|
|
@@ -673,7 +673,7 @@ function partial(Class, schema, mask) {
|
|
|
673
673
|
}));
|
|
674
674
|
}
|
|
675
675
|
function required(Class, schema, mask) {
|
|
676
|
-
return clone(schema, mergeDefs(schema._zod.def, { get shape() {
|
|
676
|
+
return clone$1(schema, mergeDefs(schema._zod.def, { get shape() {
|
|
677
677
|
const oldShape = schema._zod.def.shape;
|
|
678
678
|
const shape = { ...oldShape };
|
|
679
679
|
if (mask) for (const key in mask) {
|
|
@@ -4042,7 +4042,7 @@ var ZodType = /*@__PURE__*/ $constructor("ZodType", (inst, def) => {
|
|
|
4042
4042
|
return this.check(...chks);
|
|
4043
4043
|
},
|
|
4044
4044
|
clone(def, params) {
|
|
4045
|
-
return clone(this, def, params);
|
|
4045
|
+
return clone$1(this, def, params);
|
|
4046
4046
|
},
|
|
4047
4047
|
brand() {
|
|
4048
4048
|
return this;
|
|
@@ -27652,27 +27652,27 @@ var GEOMETRY_PROPS = /* @__PURE__ */ new Set([
|
|
|
27652
27652
|
"psets"
|
|
27653
27653
|
]);
|
|
27654
27654
|
var SPEC_ROUTES = {
|
|
27655
|
-
|
|
27655
|
+
wall: {
|
|
27656
27656
|
parse: parseWallSpec,
|
|
27657
27657
|
add: (m, spec, key) => m.addWall(spec, { stableKey: key })
|
|
27658
27658
|
},
|
|
27659
|
-
|
|
27659
|
+
slab: {
|
|
27660
27660
|
parse: parseSlabSpec,
|
|
27661
27661
|
add: (m, spec, key) => m.addSlab(spec, { stableKey: key })
|
|
27662
27662
|
},
|
|
27663
|
-
|
|
27663
|
+
column: {
|
|
27664
27664
|
parse: parseColumnSpec,
|
|
27665
27665
|
add: (m, spec, key) => m.addColumn(spec, { stableKey: key })
|
|
27666
27666
|
},
|
|
27667
|
-
|
|
27667
|
+
beam: {
|
|
27668
27668
|
parse: parseBeamSpec,
|
|
27669
27669
|
add: (m, spec, key) => m.addBeam(spec, { stableKey: key })
|
|
27670
27670
|
},
|
|
27671
|
-
|
|
27671
|
+
roof: {
|
|
27672
27672
|
parse: parseRoofSpec,
|
|
27673
27673
|
add: (m, spec, key) => m.addRoof(spec, { stableKey: key })
|
|
27674
27674
|
},
|
|
27675
|
-
|
|
27675
|
+
stair: {
|
|
27676
27676
|
parse: parseStairSpec,
|
|
27677
27677
|
add: (m, spec, key) => m.addStair(spec, { stableKey: key }),
|
|
27678
27678
|
input: stairSpecInput
|
|
@@ -27707,8 +27707,28 @@ function stairSpecInput(el) {
|
|
|
27707
27707
|
})
|
|
27708
27708
|
};
|
|
27709
27709
|
}
|
|
27710
|
-
|
|
27711
|
-
|
|
27710
|
+
/**
|
|
27711
|
+
* Families predating `archetype` are routed by their display name. Keeping
|
|
27712
|
+
* this fallback makes the declaration purely additive, at the cost of the
|
|
27713
|
+
* original trap surviving for undeclared families: rename one and it stops
|
|
27714
|
+
* routing.
|
|
27715
|
+
*/
|
|
27716
|
+
var NAME_ARCHETYPES = {
|
|
27717
|
+
Storey: "storey",
|
|
27718
|
+
Wall: "wall",
|
|
27719
|
+
Slab: "slab",
|
|
27720
|
+
Column: "column",
|
|
27721
|
+
Beam: "beam",
|
|
27722
|
+
Roof: "roof",
|
|
27723
|
+
Stair: "stair",
|
|
27724
|
+
Door: "door",
|
|
27725
|
+
Window: "window"
|
|
27726
|
+
};
|
|
27727
|
+
function archetypeFor(el) {
|
|
27728
|
+
return el.archetype ?? NAME_ARCHETYPES[el.type];
|
|
27729
|
+
}
|
|
27730
|
+
function specRoute(archetype) {
|
|
27731
|
+
return archetype !== void 0 && Object.hasOwn(SPEC_ROUTES, archetype) ? SPEC_ROUTES[archetype] : void 0;
|
|
27712
27732
|
}
|
|
27713
27733
|
/** Total of the resolved geometry's OUTER literal translate chain. The
|
|
27714
27734
|
* transform vocabulary is translate-only, so frame differences are exact
|
|
@@ -27816,17 +27836,48 @@ function collectSpecProps(el) {
|
|
|
27816
27836
|
return out;
|
|
27817
27837
|
}
|
|
27818
27838
|
function addFill(model, fill, input, identity) {
|
|
27819
|
-
|
|
27839
|
+
const archetype = archetypeFor(fill);
|
|
27840
|
+
if (archetype === "door") {
|
|
27820
27841
|
const parsed = parseDoorSpec(input);
|
|
27821
27842
|
if (!parsed.ok) return parsed;
|
|
27822
27843
|
return model.addDoor(parsed.value, identity);
|
|
27823
27844
|
}
|
|
27824
|
-
if (
|
|
27845
|
+
if (archetype === "window") {
|
|
27825
27846
|
const parsed = parseWindowSpec(input);
|
|
27826
27847
|
if (!parsed.ok) return parsed;
|
|
27827
27848
|
return model.addWindow(parsed.value, identity);
|
|
27828
27849
|
}
|
|
27829
|
-
return (0, brepjs.err)(specError("FAMILIES_UNSUPPORTED_FILL", `familiesToBim: no fill mapping for element type '${fill.type}' at '${fill.keyPath}'`));
|
|
27850
|
+
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'`));
|
|
27851
|
+
}
|
|
27852
|
+
/** Materialize an unrouted element's IR and add it as a proxy. The body is
|
|
27853
|
+
* authoritative for a proxy (no parametric spec to diverge from), so baked
|
|
27854
|
+
* transforms — rotations included — are fine here. */
|
|
27855
|
+
function addProxyElement(model, el, evaluator) {
|
|
27856
|
+
const evaluated = evaluator.evaluate(el.geometry);
|
|
27857
|
+
if (!evaluated.ok) return (0, brepjs.err)(specError("FAMILIES_PROXY_EVAL_FAILED", `familiesToBim: '${el.keyPath}' failed to materialize for the proxy route: ${evaluated.error.message}`, evaluated.error));
|
|
27858
|
+
let source = evaluated.value;
|
|
27859
|
+
if (!(0, brepjs.isSolid)(source)) {
|
|
27860
|
+
const solids = (0, brepjs.getSolids)(source);
|
|
27861
|
+
const only = solids.length === 1 ? solids[0] : void 0;
|
|
27862
|
+
if (only === void 0) return (0, brepjs.err)(specError("FAMILIES_PROXY_NOT_SOLID", `familiesToBim: '${el.keyPath}' materialized to ${solids.length} solids — a proxy body must be exactly one`));
|
|
27863
|
+
source = only;
|
|
27864
|
+
}
|
|
27865
|
+
const copy = (0, brepjs.clone)(source);
|
|
27866
|
+
if (!copy.ok) return (0, brepjs.err)(specError("FAMILIES_PROXY_EVAL_FAILED", `familiesToBim: '${el.keyPath}' could not copy the materialized body`, copy.error));
|
|
27867
|
+
const valid = (0, brepjs.validSolid)(copy.value);
|
|
27868
|
+
if (!valid.ok) {
|
|
27869
|
+
copy.value[Symbol.dispose]();
|
|
27870
|
+
return (0, brepjs.err)(specError("FAMILIES_PROXY_INVALID", `familiesToBim: '${el.keyPath}' materialized to an invalid solid: ${valid.error}`));
|
|
27871
|
+
}
|
|
27872
|
+
const nameAttr = el.attributes["name"];
|
|
27873
|
+
const materialProp = el.props["materialName"];
|
|
27874
|
+
const specProps = collectSpecProps(el);
|
|
27875
|
+
return model.addProxy({
|
|
27876
|
+
name: typeof nameAttr === "string" ? nameAttr : el.type,
|
|
27877
|
+
solid: valid.value,
|
|
27878
|
+
materialName: typeof materialProp === "string" ? materialProp : specProps["materialName"],
|
|
27879
|
+
customProperties: specProps["customProperties"]
|
|
27880
|
+
}, { stableKey: el.keyPath });
|
|
27830
27881
|
}
|
|
27831
27882
|
/** Map a wall's synthesized Opening children onto addDoor/addWindow. The
|
|
27832
27883
|
* wall-relative offsets come from the void geometry's frame minus the host's:
|
|
@@ -27900,11 +27951,14 @@ function familiesToBim(root, options) {
|
|
|
27900
27951
|
if (project !== null) model.aggregate(project.localId, siteResult.value);
|
|
27901
27952
|
model.aggregate(siteResult.value, buildingId);
|
|
27902
27953
|
const idByKeyPath = /* @__PURE__ */ new Map();
|
|
27954
|
+
const proxied = [];
|
|
27903
27955
|
const walk = (el, storeyId, rotated) => {
|
|
27904
27956
|
const rotatedHere = rotated || hasRotateOp(el);
|
|
27957
|
+
let proxiedHere = false;
|
|
27905
27958
|
let containerId = storeyId;
|
|
27906
|
-
const
|
|
27907
|
-
|
|
27959
|
+
const archetype = archetypeFor(el);
|
|
27960
|
+
const route = specRoute(archetype);
|
|
27961
|
+
if (archetype === "storey") {
|
|
27908
27962
|
const keyed = requireKeyed(el);
|
|
27909
27963
|
if (!keyed.ok) return keyed;
|
|
27910
27964
|
const storeyResult = model.addStorey({
|
|
@@ -27929,16 +27983,31 @@ function familiesToBim(root, options) {
|
|
|
27929
27983
|
const added = route.add(model, parsed.value, el.keyPath);
|
|
27930
27984
|
if (!added.ok) return added;
|
|
27931
27985
|
idByKeyPath.set(el.keyPath, added.value);
|
|
27932
|
-
if (containerId === null) return (0, brepjs.err)(specError("FAMILIES_NO_STOREY", `familiesToBim: '${el.keyPath}' has no Storey ancestor — IFC elements need spatial containment`));
|
|
27986
|
+
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`));
|
|
27933
27987
|
model.placeIn(added.value, containerId);
|
|
27934
|
-
if (
|
|
27988
|
+
if (archetype === "wall") {
|
|
27935
27989
|
const opened = addOpenings(model, el, added.value, containerId, idByKeyPath);
|
|
27936
27990
|
if (!opened.ok) return opened;
|
|
27937
27991
|
}
|
|
27938
27992
|
} 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`));
|
|
27939
|
-
else if (el.type !== "Group" && el.geometry.kind !== "Empty")
|
|
27993
|
+
else if (el.type !== "Group" && el.geometry.kind !== "Empty") {
|
|
27994
|
+
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`));
|
|
27995
|
+
const keyed = requireKeyed(el);
|
|
27996
|
+
if (!keyed.ok) return keyed;
|
|
27997
|
+
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`));
|
|
27998
|
+
const added = addProxyElement(model, el, options.proxyEvaluator);
|
|
27999
|
+
if (!added.ok) return added;
|
|
28000
|
+
model.placeIn(added.value, containerId);
|
|
28001
|
+
idByKeyPath.set(el.keyPath, added.value);
|
|
28002
|
+
proxied.push({
|
|
28003
|
+
keyPath: el.keyPath,
|
|
28004
|
+
type: el.type,
|
|
28005
|
+
archetype: el.archetype
|
|
28006
|
+
});
|
|
28007
|
+
proxiedHere = true;
|
|
28008
|
+
}
|
|
27940
28009
|
for (const child of el.children) {
|
|
27941
|
-
if (
|
|
28010
|
+
if ((archetype === "wall" || proxiedHere) && child.type === "Opening") continue;
|
|
27942
28011
|
const r = walk(child, containerId, rotatedHere);
|
|
27943
28012
|
if (!r.ok) return r;
|
|
27944
28013
|
}
|
|
@@ -27951,7 +28020,8 @@ function familiesToBim(root, options) {
|
|
|
27951
28020
|
}
|
|
27952
28021
|
return (0, brepjs.ok)({
|
|
27953
28022
|
model,
|
|
27954
|
-
idByKeyPath
|
|
28023
|
+
idByKeyPath,
|
|
28024
|
+
proxied
|
|
27955
28025
|
});
|
|
27956
28026
|
}
|
|
27957
28027
|
//#endregion
|
package/dist/brepjs-bim.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { addHoles, applyMatrix, autoHeal, box, castShape, convexHull, cut, err, extrude, fuse, getKernel, isClosedWire, isOk, isPlanarWire, isSolid, isValid, isValidSolid, measureVolume, mesh, ok, outerWire, polygon, revolve, rotate, validSolid } from "brepjs";
|
|
1
|
+
import { addHoles, applyMatrix, autoHeal, box, castShape, clone, convexHull, cut, err, extrude, fuse, getKernel, getSolids, isClosedWire, isOk, isPlanarWire, isSolid, isValid, isValidSolid, measureVolume, mesh, ok, outerWire, polygon, revolve, rotate, validSolid } from "brepjs";
|
|
2
2
|
import * as WebIFC from "web-ifc";
|
|
3
3
|
import { Handle, IfcAPI } from "web-ifc";
|
|
4
4
|
//#region src/identity/ifcGuid.ts
|
|
@@ -512,7 +512,7 @@ var propertyKeyTypes = /* @__PURE__*/ new Set([
|
|
|
512
512
|
function escapeRegex(str) {
|
|
513
513
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
514
514
|
}
|
|
515
|
-
function clone(inst, def, params) {
|
|
515
|
+
function clone$1(inst, def, params) {
|
|
516
516
|
const cl = new inst._zod.constr(def ?? inst._zod.def);
|
|
517
517
|
if (!def || params?.parent) cl._zod.parent = inst;
|
|
518
518
|
return cl;
|
|
@@ -548,7 +548,7 @@ function pick(schema, mask) {
|
|
|
548
548
|
const currDef = schema._zod.def;
|
|
549
549
|
const checks = currDef.checks;
|
|
550
550
|
if (checks && checks.length > 0) throw new Error(".pick() cannot be used on object schemas containing refinements");
|
|
551
|
-
return clone(schema, mergeDefs(schema._zod.def, {
|
|
551
|
+
return clone$1(schema, mergeDefs(schema._zod.def, {
|
|
552
552
|
get shape() {
|
|
553
553
|
const newShape = {};
|
|
554
554
|
for (const key in mask) {
|
|
@@ -566,7 +566,7 @@ function omit(schema, mask) {
|
|
|
566
566
|
const currDef = schema._zod.def;
|
|
567
567
|
const checks = currDef.checks;
|
|
568
568
|
if (checks && checks.length > 0) throw new Error(".omit() cannot be used on object schemas containing refinements");
|
|
569
|
-
return clone(schema, mergeDefs(schema._zod.def, {
|
|
569
|
+
return clone$1(schema, mergeDefs(schema._zod.def, {
|
|
570
570
|
get shape() {
|
|
571
571
|
const newShape = { ...schema._zod.def.shape };
|
|
572
572
|
for (const key in mask) {
|
|
@@ -587,7 +587,7 @@ function extend(schema, shape) {
|
|
|
587
587
|
const existingShape = schema._zod.def.shape;
|
|
588
588
|
for (const key in shape) if (Object.getOwnPropertyDescriptor(existingShape, key) !== void 0) throw new Error("Cannot overwrite keys on object schemas containing refinements. Use `.safeExtend()` instead.");
|
|
589
589
|
}
|
|
590
|
-
return clone(schema, mergeDefs(schema._zod.def, { get shape() {
|
|
590
|
+
return clone$1(schema, mergeDefs(schema._zod.def, { get shape() {
|
|
591
591
|
const _shape = {
|
|
592
592
|
...schema._zod.def.shape,
|
|
593
593
|
...shape
|
|
@@ -598,7 +598,7 @@ function extend(schema, shape) {
|
|
|
598
598
|
}
|
|
599
599
|
function safeExtend(schema, shape) {
|
|
600
600
|
if (!isPlainObject(shape)) throw new Error("Invalid input to safeExtend: expected a plain object");
|
|
601
|
-
return clone(schema, mergeDefs(schema._zod.def, { get shape() {
|
|
601
|
+
return clone$1(schema, mergeDefs(schema._zod.def, { get shape() {
|
|
602
602
|
const _shape = {
|
|
603
603
|
...schema._zod.def.shape,
|
|
604
604
|
...shape
|
|
@@ -609,7 +609,7 @@ function safeExtend(schema, shape) {
|
|
|
609
609
|
}
|
|
610
610
|
function merge(a, b) {
|
|
611
611
|
if (a._zod.def.checks?.length) throw new Error(".merge() cannot be used on object schemas containing refinements. Use .safeExtend() instead.");
|
|
612
|
-
return clone(a, mergeDefs(a._zod.def, {
|
|
612
|
+
return clone$1(a, mergeDefs(a._zod.def, {
|
|
613
613
|
get shape() {
|
|
614
614
|
const _shape = {
|
|
615
615
|
...a._zod.def.shape,
|
|
@@ -627,7 +627,7 @@ function merge(a, b) {
|
|
|
627
627
|
function partial(Class, schema, mask) {
|
|
628
628
|
const checks = schema._zod.def.checks;
|
|
629
629
|
if (checks && checks.length > 0) throw new Error(".partial() cannot be used on object schemas containing refinements");
|
|
630
|
-
return clone(schema, mergeDefs(schema._zod.def, {
|
|
630
|
+
return clone$1(schema, mergeDefs(schema._zod.def, {
|
|
631
631
|
get shape() {
|
|
632
632
|
const oldShape = schema._zod.def.shape;
|
|
633
633
|
const shape = { ...oldShape };
|
|
@@ -650,7 +650,7 @@ function partial(Class, schema, mask) {
|
|
|
650
650
|
}));
|
|
651
651
|
}
|
|
652
652
|
function required(Class, schema, mask) {
|
|
653
|
-
return clone(schema, mergeDefs(schema._zod.def, { get shape() {
|
|
653
|
+
return clone$1(schema, mergeDefs(schema._zod.def, { get shape() {
|
|
654
654
|
const oldShape = schema._zod.def.shape;
|
|
655
655
|
const shape = { ...oldShape };
|
|
656
656
|
if (mask) for (const key in mask) {
|
|
@@ -4019,7 +4019,7 @@ var ZodType = /*@__PURE__*/ $constructor("ZodType", (inst, def) => {
|
|
|
4019
4019
|
return this.check(...chks);
|
|
4020
4020
|
},
|
|
4021
4021
|
clone(def, params) {
|
|
4022
|
-
return clone(this, def, params);
|
|
4022
|
+
return clone$1(this, def, params);
|
|
4023
4023
|
},
|
|
4024
4024
|
brand() {
|
|
4025
4025
|
return this;
|
|
@@ -27629,27 +27629,27 @@ var GEOMETRY_PROPS = /* @__PURE__ */ new Set([
|
|
|
27629
27629
|
"psets"
|
|
27630
27630
|
]);
|
|
27631
27631
|
var SPEC_ROUTES = {
|
|
27632
|
-
|
|
27632
|
+
wall: {
|
|
27633
27633
|
parse: parseWallSpec,
|
|
27634
27634
|
add: (m, spec, key) => m.addWall(spec, { stableKey: key })
|
|
27635
27635
|
},
|
|
27636
|
-
|
|
27636
|
+
slab: {
|
|
27637
27637
|
parse: parseSlabSpec,
|
|
27638
27638
|
add: (m, spec, key) => m.addSlab(spec, { stableKey: key })
|
|
27639
27639
|
},
|
|
27640
|
-
|
|
27640
|
+
column: {
|
|
27641
27641
|
parse: parseColumnSpec,
|
|
27642
27642
|
add: (m, spec, key) => m.addColumn(spec, { stableKey: key })
|
|
27643
27643
|
},
|
|
27644
|
-
|
|
27644
|
+
beam: {
|
|
27645
27645
|
parse: parseBeamSpec,
|
|
27646
27646
|
add: (m, spec, key) => m.addBeam(spec, { stableKey: key })
|
|
27647
27647
|
},
|
|
27648
|
-
|
|
27648
|
+
roof: {
|
|
27649
27649
|
parse: parseRoofSpec,
|
|
27650
27650
|
add: (m, spec, key) => m.addRoof(spec, { stableKey: key })
|
|
27651
27651
|
},
|
|
27652
|
-
|
|
27652
|
+
stair: {
|
|
27653
27653
|
parse: parseStairSpec,
|
|
27654
27654
|
add: (m, spec, key) => m.addStair(spec, { stableKey: key }),
|
|
27655
27655
|
input: stairSpecInput
|
|
@@ -27684,8 +27684,28 @@ function stairSpecInput(el) {
|
|
|
27684
27684
|
})
|
|
27685
27685
|
};
|
|
27686
27686
|
}
|
|
27687
|
-
|
|
27688
|
-
|
|
27687
|
+
/**
|
|
27688
|
+
* Families predating `archetype` are routed by their display name. Keeping
|
|
27689
|
+
* this fallback makes the declaration purely additive, at the cost of the
|
|
27690
|
+
* original trap surviving for undeclared families: rename one and it stops
|
|
27691
|
+
* routing.
|
|
27692
|
+
*/
|
|
27693
|
+
var NAME_ARCHETYPES = {
|
|
27694
|
+
Storey: "storey",
|
|
27695
|
+
Wall: "wall",
|
|
27696
|
+
Slab: "slab",
|
|
27697
|
+
Column: "column",
|
|
27698
|
+
Beam: "beam",
|
|
27699
|
+
Roof: "roof",
|
|
27700
|
+
Stair: "stair",
|
|
27701
|
+
Door: "door",
|
|
27702
|
+
Window: "window"
|
|
27703
|
+
};
|
|
27704
|
+
function archetypeFor(el) {
|
|
27705
|
+
return el.archetype ?? NAME_ARCHETYPES[el.type];
|
|
27706
|
+
}
|
|
27707
|
+
function specRoute(archetype) {
|
|
27708
|
+
return archetype !== void 0 && Object.hasOwn(SPEC_ROUTES, archetype) ? SPEC_ROUTES[archetype] : void 0;
|
|
27689
27709
|
}
|
|
27690
27710
|
/** Total of the resolved geometry's OUTER literal translate chain. The
|
|
27691
27711
|
* transform vocabulary is translate-only, so frame differences are exact
|
|
@@ -27793,17 +27813,48 @@ function collectSpecProps(el) {
|
|
|
27793
27813
|
return out;
|
|
27794
27814
|
}
|
|
27795
27815
|
function addFill(model, fill, input, identity) {
|
|
27796
|
-
|
|
27816
|
+
const archetype = archetypeFor(fill);
|
|
27817
|
+
if (archetype === "door") {
|
|
27797
27818
|
const parsed = parseDoorSpec(input);
|
|
27798
27819
|
if (!parsed.ok) return parsed;
|
|
27799
27820
|
return model.addDoor(parsed.value, identity);
|
|
27800
27821
|
}
|
|
27801
|
-
if (
|
|
27822
|
+
if (archetype === "window") {
|
|
27802
27823
|
const parsed = parseWindowSpec(input);
|
|
27803
27824
|
if (!parsed.ok) return parsed;
|
|
27804
27825
|
return model.addWindow(parsed.value, identity);
|
|
27805
27826
|
}
|
|
27806
|
-
return err(specError("FAMILIES_UNSUPPORTED_FILL", `familiesToBim: no fill mapping for element type '${fill.type}' at '${fill.keyPath}'`));
|
|
27827
|
+
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'`));
|
|
27828
|
+
}
|
|
27829
|
+
/** Materialize an unrouted element's IR and add it as a proxy. The body is
|
|
27830
|
+
* authoritative for a proxy (no parametric spec to diverge from), so baked
|
|
27831
|
+
* transforms — rotations included — are fine here. */
|
|
27832
|
+
function addProxyElement(model, el, evaluator) {
|
|
27833
|
+
const evaluated = evaluator.evaluate(el.geometry);
|
|
27834
|
+
if (!evaluated.ok) return err(specError("FAMILIES_PROXY_EVAL_FAILED", `familiesToBim: '${el.keyPath}' failed to materialize for the proxy route: ${evaluated.error.message}`, evaluated.error));
|
|
27835
|
+
let source = evaluated.value;
|
|
27836
|
+
if (!isSolid(source)) {
|
|
27837
|
+
const solids = getSolids(source);
|
|
27838
|
+
const only = solids.length === 1 ? solids[0] : void 0;
|
|
27839
|
+
if (only === void 0) return err(specError("FAMILIES_PROXY_NOT_SOLID", `familiesToBim: '${el.keyPath}' materialized to ${solids.length} solids — a proxy body must be exactly one`));
|
|
27840
|
+
source = only;
|
|
27841
|
+
}
|
|
27842
|
+
const copy = clone(source);
|
|
27843
|
+
if (!copy.ok) return err(specError("FAMILIES_PROXY_EVAL_FAILED", `familiesToBim: '${el.keyPath}' could not copy the materialized body`, copy.error));
|
|
27844
|
+
const valid = validSolid(copy.value);
|
|
27845
|
+
if (!valid.ok) {
|
|
27846
|
+
copy.value[Symbol.dispose]();
|
|
27847
|
+
return err(specError("FAMILIES_PROXY_INVALID", `familiesToBim: '${el.keyPath}' materialized to an invalid solid: ${valid.error}`));
|
|
27848
|
+
}
|
|
27849
|
+
const nameAttr = el.attributes["name"];
|
|
27850
|
+
const materialProp = el.props["materialName"];
|
|
27851
|
+
const specProps = collectSpecProps(el);
|
|
27852
|
+
return model.addProxy({
|
|
27853
|
+
name: typeof nameAttr === "string" ? nameAttr : el.type,
|
|
27854
|
+
solid: valid.value,
|
|
27855
|
+
materialName: typeof materialProp === "string" ? materialProp : specProps["materialName"],
|
|
27856
|
+
customProperties: specProps["customProperties"]
|
|
27857
|
+
}, { stableKey: el.keyPath });
|
|
27807
27858
|
}
|
|
27808
27859
|
/** Map a wall's synthesized Opening children onto addDoor/addWindow. The
|
|
27809
27860
|
* wall-relative offsets come from the void geometry's frame minus the host's:
|
|
@@ -27877,11 +27928,14 @@ function familiesToBim(root, options) {
|
|
|
27877
27928
|
if (project !== null) model.aggregate(project.localId, siteResult.value);
|
|
27878
27929
|
model.aggregate(siteResult.value, buildingId);
|
|
27879
27930
|
const idByKeyPath = /* @__PURE__ */ new Map();
|
|
27931
|
+
const proxied = [];
|
|
27880
27932
|
const walk = (el, storeyId, rotated) => {
|
|
27881
27933
|
const rotatedHere = rotated || hasRotateOp(el);
|
|
27934
|
+
let proxiedHere = false;
|
|
27882
27935
|
let containerId = storeyId;
|
|
27883
|
-
const
|
|
27884
|
-
|
|
27936
|
+
const archetype = archetypeFor(el);
|
|
27937
|
+
const route = specRoute(archetype);
|
|
27938
|
+
if (archetype === "storey") {
|
|
27885
27939
|
const keyed = requireKeyed(el);
|
|
27886
27940
|
if (!keyed.ok) return keyed;
|
|
27887
27941
|
const storeyResult = model.addStorey({
|
|
@@ -27906,16 +27960,31 @@ function familiesToBim(root, options) {
|
|
|
27906
27960
|
const added = route.add(model, parsed.value, el.keyPath);
|
|
27907
27961
|
if (!added.ok) return added;
|
|
27908
27962
|
idByKeyPath.set(el.keyPath, added.value);
|
|
27909
|
-
if (containerId === null) return err(specError("FAMILIES_NO_STOREY", `familiesToBim: '${el.keyPath}' has no Storey ancestor — IFC elements need spatial containment`));
|
|
27963
|
+
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`));
|
|
27910
27964
|
model.placeIn(added.value, containerId);
|
|
27911
|
-
if (
|
|
27965
|
+
if (archetype === "wall") {
|
|
27912
27966
|
const opened = addOpenings(model, el, added.value, containerId, idByKeyPath);
|
|
27913
27967
|
if (!opened.ok) return opened;
|
|
27914
27968
|
}
|
|
27915
27969
|
} 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`));
|
|
27916
|
-
else if (el.type !== "Group" && el.geometry.kind !== "Empty")
|
|
27970
|
+
else if (el.type !== "Group" && el.geometry.kind !== "Empty") {
|
|
27971
|
+
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`));
|
|
27972
|
+
const keyed = requireKeyed(el);
|
|
27973
|
+
if (!keyed.ok) return keyed;
|
|
27974
|
+
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`));
|
|
27975
|
+
const added = addProxyElement(model, el, options.proxyEvaluator);
|
|
27976
|
+
if (!added.ok) return added;
|
|
27977
|
+
model.placeIn(added.value, containerId);
|
|
27978
|
+
idByKeyPath.set(el.keyPath, added.value);
|
|
27979
|
+
proxied.push({
|
|
27980
|
+
keyPath: el.keyPath,
|
|
27981
|
+
type: el.type,
|
|
27982
|
+
archetype: el.archetype
|
|
27983
|
+
});
|
|
27984
|
+
proxiedHere = true;
|
|
27985
|
+
}
|
|
27917
27986
|
for (const child of el.children) {
|
|
27918
|
-
if (
|
|
27987
|
+
if ((archetype === "wall" || proxiedHere) && child.type === "Opening") continue;
|
|
27919
27988
|
const r = walk(child, containerId, rotatedHere);
|
|
27920
27989
|
if (!r.ok) return r;
|
|
27921
27990
|
}
|
|
@@ -27928,7 +27997,8 @@ function familiesToBim(root, options) {
|
|
|
27928
27997
|
}
|
|
27929
27998
|
return ok({
|
|
27930
27999
|
model,
|
|
27931
|
-
idByKeyPath
|
|
28000
|
+
idByKeyPath,
|
|
28001
|
+
proxied
|
|
27932
28002
|
});
|
|
27933
28003
|
}
|
|
27934
28004
|
//#endregion
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Result } from 'brepjs';
|
|
1
|
+
import { Result, csg } from 'brepjs';
|
|
2
2
|
import { ResolvedElement } from 'brepjs-families';
|
|
3
3
|
import { BimModel } from './model/bimModel.js';
|
|
4
4
|
import { LocalId } from './identity/localId.js';
|
|
@@ -8,11 +8,34 @@ export interface FamiliesToBimOptions {
|
|
|
8
8
|
readonly project: ProjectSpec;
|
|
9
9
|
readonly siteName?: string | undefined;
|
|
10
10
|
readonly buildingName?: string | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Enables the proxy route: an unrouted geometry-bearing element is
|
|
13
|
+
* materialized through this evaluator and exported as an
|
|
14
|
+
* IfcBuildingElementProxy (tessellated, world-frame body). Without it,
|
|
15
|
+
* unrouted types stay a hard FAMILIES_UNSUPPORTED_TYPE error. The
|
|
16
|
+
* evaluator's handles stay borrowed; the adapter clones what it hands the
|
|
17
|
+
* model.
|
|
18
|
+
*/
|
|
19
|
+
readonly proxyEvaluator?: csg.Evaluator | undefined;
|
|
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;
|
|
11
26
|
}
|
|
12
27
|
export interface FamiliesBimResult {
|
|
13
28
|
readonly model: BimModel;
|
|
14
29
|
/** LocalId per geometry-bearing families key path. */
|
|
15
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[];
|
|
16
39
|
}
|
|
17
40
|
/**
|
|
18
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';
|