brepjs-bim 0.5.0 → 0.7.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.
@@ -16615,13 +16615,25 @@ function addOpenings(model, host, wallId, containerId, idByKeyPath) {
16615
16615
  if (opening.type !== "Opening") continue;
16616
16616
  const fill = opening.children[0];
16617
16617
  if (fill === void 0) return (0, brepjs.err)(specError("FAMILIES_OPENING_NO_FILL", `familiesToBim: opening '${opening.keyPath}' has no fill element`));
16618
+ const keyed = requireKeyed(opening);
16619
+ if (!keyed.ok) return keyed;
16618
16620
  const fillT = peelTranslates(opening.geometry).total;
16621
+ const axisX = host.props["axisX"] ?? [
16622
+ 1,
16623
+ 0,
16624
+ 0
16625
+ ];
16626
+ const delta = [
16627
+ fillT[0] - hostT[0],
16628
+ fillT[1] - hostT[1],
16629
+ fillT[2] - hostT[2]
16630
+ ];
16619
16631
  const added = addFill(model, fill, {
16620
16632
  materialName: SPEC_DEFAULTS.materialName,
16621
16633
  ...stripGeometryProps(fill.props),
16622
16634
  wallLocalId: wallId,
16623
- offsetAlongWall: fillT[0] - hostT[0],
16624
- offsetFromFloor: fillT[2] - hostT[2]
16635
+ offsetAlongWall: delta[0] * axisX[0] + delta[1] * axisX[1] + delta[2] * axisX[2],
16636
+ offsetFromFloor: delta[2]
16625
16637
  }, {
16626
16638
  stableKey: fill.keyPath,
16627
16639
  openingStableKey: opening.keyPath
@@ -16634,6 +16646,13 @@ function addOpenings(model, host, wallId, containerId, idByKeyPath) {
16634
16646
  }
16635
16647
  return (0, brepjs.ok)(void 0);
16636
16648
  }
16649
+ /** Every element that mints an IFC identity needs an explicit key: an
16650
+ * index-fallback path is order-dependent, which would silently break the
16651
+ * reorder-stable GlobalId contract. */
16652
+ function requireKeyed(el) {
16653
+ if (el.keyed) return (0, brepjs.ok)(void 0);
16654
+ return (0, brepjs.err)(specError("FAMILIES_UNKEYED_ELEMENT", `familiesToBim: '${el.keyPath}' has no explicit key — IFC identity needs order-independent key paths (add a key to the element)`));
16655
+ }
16637
16656
  /**
16638
16657
  * Project a resolved families tree into an eager BimModel. The caller owns
16639
16658
  * the returned model (`using`); families stays domain-neutral — this adapter
@@ -16650,6 +16669,8 @@ function familiesToBim(root, options) {
16650
16669
  const walk = (el, storeyId) => {
16651
16670
  let containerId = storeyId;
16652
16671
  if (el.type === "Storey") {
16672
+ const keyed = requireKeyed(el);
16673
+ if (!keyed.ok) return keyed;
16653
16674
  const id = model.addStorey({
16654
16675
  name: el.attributes["name"] ?? el.keyPath,
16655
16676
  elevation: el.props["elevation"] ?? 0
@@ -16658,6 +16679,8 @@ function familiesToBim(root, options) {
16658
16679
  idByKeyPath.set(el.keyPath, id);
16659
16680
  containerId = id;
16660
16681
  } else if (el.type === "Wall" || el.type === "Slab") {
16682
+ const keyed = requireKeyed(el);
16683
+ if (!keyed.ok) return keyed;
16661
16684
  const parsed = el.type === "Wall" ? parseWallSpec(specInput(el)) : parseSlabSpec(specInput(el));
16662
16685
  if (!parsed.ok) return parsed;
16663
16686
  const added = el.type === "Wall" ? model.addWall(parsed.value, { stableKey: el.keyPath }) : model.addSlab(parsed.value, { stableKey: el.keyPath });
@@ -16592,13 +16592,25 @@ function addOpenings(model, host, wallId, containerId, idByKeyPath) {
16592
16592
  if (opening.type !== "Opening") continue;
16593
16593
  const fill = opening.children[0];
16594
16594
  if (fill === void 0) return err(specError("FAMILIES_OPENING_NO_FILL", `familiesToBim: opening '${opening.keyPath}' has no fill element`));
16595
+ const keyed = requireKeyed(opening);
16596
+ if (!keyed.ok) return keyed;
16595
16597
  const fillT = peelTranslates(opening.geometry).total;
16598
+ const axisX = host.props["axisX"] ?? [
16599
+ 1,
16600
+ 0,
16601
+ 0
16602
+ ];
16603
+ const delta = [
16604
+ fillT[0] - hostT[0],
16605
+ fillT[1] - hostT[1],
16606
+ fillT[2] - hostT[2]
16607
+ ];
16596
16608
  const added = addFill(model, fill, {
16597
16609
  materialName: SPEC_DEFAULTS.materialName,
16598
16610
  ...stripGeometryProps(fill.props),
16599
16611
  wallLocalId: wallId,
16600
- offsetAlongWall: fillT[0] - hostT[0],
16601
- offsetFromFloor: fillT[2] - hostT[2]
16612
+ offsetAlongWall: delta[0] * axisX[0] + delta[1] * axisX[1] + delta[2] * axisX[2],
16613
+ offsetFromFloor: delta[2]
16602
16614
  }, {
16603
16615
  stableKey: fill.keyPath,
16604
16616
  openingStableKey: opening.keyPath
@@ -16611,6 +16623,13 @@ function addOpenings(model, host, wallId, containerId, idByKeyPath) {
16611
16623
  }
16612
16624
  return ok(void 0);
16613
16625
  }
16626
+ /** Every element that mints an IFC identity needs an explicit key: an
16627
+ * index-fallback path is order-dependent, which would silently break the
16628
+ * reorder-stable GlobalId contract. */
16629
+ function requireKeyed(el) {
16630
+ if (el.keyed) return ok(void 0);
16631
+ return err(specError("FAMILIES_UNKEYED_ELEMENT", `familiesToBim: '${el.keyPath}' has no explicit key — IFC identity needs order-independent key paths (add a key to the element)`));
16632
+ }
16614
16633
  /**
16615
16634
  * Project a resolved families tree into an eager BimModel. The caller owns
16616
16635
  * the returned model (`using`); families stays domain-neutral — this adapter
@@ -16627,6 +16646,8 @@ function familiesToBim(root, options) {
16627
16646
  const walk = (el, storeyId) => {
16628
16647
  let containerId = storeyId;
16629
16648
  if (el.type === "Storey") {
16649
+ const keyed = requireKeyed(el);
16650
+ if (!keyed.ok) return keyed;
16630
16651
  const id = model.addStorey({
16631
16652
  name: el.attributes["name"] ?? el.keyPath,
16632
16653
  elevation: el.props["elevation"] ?? 0
@@ -16635,6 +16656,8 @@ function familiesToBim(root, options) {
16635
16656
  idByKeyPath.set(el.keyPath, id);
16636
16657
  containerId = id;
16637
16658
  } else if (el.type === "Wall" || el.type === "Slab") {
16659
+ const keyed = requireKeyed(el);
16660
+ if (!keyed.ok) return keyed;
16638
16661
  const parsed = el.type === "Wall" ? parseWallSpec(specInput(el)) : parseSlabSpec(specInput(el));
16639
16662
  if (!parsed.ok) return parsed;
16640
16663
  const added = el.type === "Wall" ? model.addWall(parsed.value, { stableKey: el.keyPath }) : model.addSlab(parsed.value, { stableKey: el.keyPath });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brepjs-bim",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "BIM layer for brepjs — IFC4-aligned parametric building elements",
5
5
  "keywords": [
6
6
  "bim",