brepjs-bim 0.24.3 → 0.24.5

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.
@@ -266,7 +266,7 @@ function _usingCtx() {
266
266
  //#region src/elementFns/wallFns.ts
267
267
  function wallToSolid(spec) {
268
268
  try {
269
- var _usingCtx$20 = _usingCtx();
269
+ var _usingCtx$21 = _usingCtx();
270
270
  if (spec.length <= 0) return (0, brepjs.err)(specError("WALL_ZERO_LENGTH", "Wall length must be positive"));
271
271
  if (spec.height <= 0) return (0, brepjs.err)(specError("WALL_ZERO_HEIGHT", "Wall height must be positive"));
272
272
  if (spec.thickness <= 0) return (0, brepjs.err)(specError("WALL_ZERO_THICKNESS", "Wall thickness must be positive"));
@@ -294,7 +294,7 @@ function wallToSolid(spec) {
294
294
  ]
295
295
  ]);
296
296
  if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "WALL_PROFILE_FAILED", "Failed to create wall profile"));
297
- const profile = _usingCtx$20.u(profileResult.value);
297
+ const profile = _usingCtx$21.u(profileResult.value);
298
298
  const solidResult = (0, brepjs.extrude)(profile, [
299
299
  length,
300
300
  0,
@@ -308,16 +308,16 @@ function wallToSolid(spec) {
308
308
  }
309
309
  return (0, brepjs.ok)(solid);
310
310
  } catch (_) {
311
- _usingCtx$20.e = _;
311
+ _usingCtx$21.e = _;
312
312
  } finally {
313
- _usingCtx$20.d();
313
+ _usingCtx$21.d();
314
314
  }
315
315
  }
316
316
  //#endregion
317
317
  //#region src/elementFns/slabFns.ts
318
318
  function slabToSolid(spec) {
319
319
  try {
320
- var _usingCtx$19 = _usingCtx();
320
+ var _usingCtx$20 = _usingCtx();
321
321
  if (spec.length <= 0) return (0, brepjs.err)(specError("SLAB_ZERO_LENGTH", "Slab length must be positive"));
322
322
  if (spec.width <= 0) return (0, brepjs.err)(specError("SLAB_ZERO_WIDTH", "Slab width must be positive"));
323
323
  if (spec.thickness <= 0) return (0, brepjs.err)(specError("SLAB_ZERO_THICKNESS", "Slab thickness must be positive"));
@@ -345,7 +345,7 @@ function slabToSolid(spec) {
345
345
  ]
346
346
  ]);
347
347
  if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "SLAB_PROFILE_FAILED", "Failed to create slab profile"));
348
- const profile = _usingCtx$19.u(profileResult.value);
348
+ const profile = _usingCtx$20.u(profileResult.value);
349
349
  const solidResult = (0, brepjs.extrude)(profile, [
350
350
  0,
351
351
  0,
@@ -359,9 +359,9 @@ function slabToSolid(spec) {
359
359
  }
360
360
  return (0, brepjs.ok)(solid);
361
361
  } catch (_) {
362
- _usingCtx$19.e = _;
362
+ _usingCtx$20.e = _;
363
363
  } finally {
364
- _usingCtx$19.d();
364
+ _usingCtx$20.d();
365
365
  }
366
366
  }
367
367
  //#endregion
@@ -522,7 +522,7 @@ var propertyKeyTypes = /* @__PURE__*/ new Set([
522
522
  function escapeRegex(str) {
523
523
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
524
524
  }
525
- function clone$3(inst, def, params) {
525
+ function clone$4(inst, def, params) {
526
526
  const cl = new inst._zod.constr(def ?? inst._zod.def);
527
527
  if (!def || params?.parent) cl._zod.parent = inst;
528
528
  return cl;
@@ -569,7 +569,7 @@ function pick(schema, mask) {
569
569
  if (checks && checks.length > 0) throw new Error(".pick() cannot be used on object schemas containing refinements");
570
570
  const newShape = {};
571
571
  mirrorShape(newShape, schema, maskedKeys(schema, mask));
572
- return clone$3(schema, mergeDefs(currDef, {
572
+ return clone$4(schema, mergeDefs(currDef, {
573
573
  shape: newShape,
574
574
  checks: []
575
575
  }));
@@ -590,7 +590,7 @@ function omit(schema, mask) {
590
590
  const omitted = new Set(maskedKeys(schema, mask));
591
591
  const newShape = {};
592
592
  mirrorShape(newShape, schema, Reflect.ownKeys(sourceShape(schema)).filter((key) => !omitted.has(key)));
593
- return clone$3(schema, mergeDefs(currDef, {
593
+ return clone$4(schema, mergeDefs(currDef, {
594
594
  shape: newShape,
595
595
  checks: []
596
596
  }));
@@ -602,7 +602,7 @@ function extend(schema, shape) {
602
602
  const existingShape = sourceShape(schema);
603
603
  for (const key of Reflect.ownKeys(shape)) if (Object.getOwnPropertyDescriptor(existingShape, key) !== void 0) throw new Error("Cannot overwrite keys on object schemas containing refinements. Use `.safeExtend()` instead.");
604
604
  }
605
- return clone$3(schema, mergeDefs(schema._zod.def, { shape: extended(schema, shape) }));
605
+ return clone$4(schema, mergeDefs(schema._zod.def, { shape: extended(schema, shape) }));
606
606
  }
607
607
  function extended(schema, shape) {
608
608
  const newShape = {};
@@ -612,7 +612,7 @@ function extended(schema, shape) {
612
612
  }
613
613
  function safeExtend(schema, shape) {
614
614
  if (!isPlainObject(shape)) throw new Error("Invalid input to safeExtend: expected a plain object");
615
- return clone$3(schema, mergeDefs(schema._zod.def, { shape: extended(schema, shape) }));
615
+ return clone$4(schema, mergeDefs(schema._zod.def, { shape: extended(schema, shape) }));
616
616
  }
617
617
  function merge(a, b) {
618
618
  if (!b?._zod?.def) throw new Error("Invalid input to merge: expected an object schema. To merge a plain shape, use `.extend()`.");
@@ -620,7 +620,7 @@ function merge(a, b) {
620
620
  const newShape = {};
621
621
  mirrorShape(newShape, a, Reflect.ownKeys(sourceShape(a)));
622
622
  mirrorShape(newShape, b, Reflect.ownKeys(sourceShape(b)));
623
- return clone$3(a, mergeDefs(a._zod.def, {
623
+ return clone$4(a, mergeDefs(a._zod.def, {
624
624
  shape: newShape,
625
625
  get catchall() {
626
626
  return b._zod.def.catchall;
@@ -637,7 +637,7 @@ function partial(Class, schema, mask, name = "partial") {
637
637
  type: "optional",
638
638
  innerType: value
639
639
  })));
640
- return clone$3(schema, mergeDefs(schema._zod.def, {
640
+ return clone$4(schema, mergeDefs(schema._zod.def, {
641
641
  shape: newShape,
642
642
  checks: []
643
643
  }));
@@ -649,7 +649,7 @@ function required(Class, schema, mask) {
649
649
  type: "nonoptional",
650
650
  innerType: value
651
651
  }));
652
- return clone$3(schema, mergeDefs(schema._zod.def, { shape: newShape }));
652
+ return clone$4(schema, mergeDefs(schema._zod.def, { shape: newShape }));
653
653
  }
654
654
  function aborted(x, startIndex = 0) {
655
655
  if (x.aborted === true) return true;
@@ -5215,7 +5215,7 @@ var ZodType = /*@__PURE__*/ $constructor("ZodType", (inst, def) => {
5215
5215
  return this.check(...chks);
5216
5216
  },
5217
5217
  clone(def, params) {
5218
- return clone$3(this, def, params);
5218
+ return clone$4(this, def, params);
5219
5219
  },
5220
5220
  brand() {
5221
5221
  return this;
@@ -6358,14 +6358,14 @@ function to3D(points) {
6358
6358
  }
6359
6359
  function extendedProfileToFace(profile) {
6360
6360
  try {
6361
- var _usingCtx$18 = _usingCtx();
6361
+ var _usingCtx$19 = _usingCtx();
6362
6362
  const invalid = validateProfile(profile);
6363
6363
  if (invalid !== null) return (0, brepjs.err)(invalid);
6364
6364
  const outerResult = (0, brepjs.polygon)(to3D(outerLoop(profile)));
6365
6365
  if (!outerResult.ok) return (0, brepjs.err)(fromBrepError(outerResult.error, "PROFILE_FACE_FAILED", "Failed to build profile outer face"));
6366
6366
  const holes = holeLoops(profile);
6367
6367
  if (holes.length === 0) return (0, brepjs.ok)(outerResult.value);
6368
- const outerFace = _usingCtx$18.u(outerResult.value);
6368
+ const outerFace = _usingCtx$19.u(outerResult.value);
6369
6369
  const holeFaces = [];
6370
6370
  const holeWires = [];
6371
6371
  const disposeHoleFaces = () => {
@@ -6390,9 +6390,9 @@ function extendedProfileToFace(profile) {
6390
6390
  disposeHoleFaces();
6391
6391
  return (0, brepjs.ok)(faceWithHoles);
6392
6392
  } catch (_) {
6393
- _usingCtx$18.e = _;
6393
+ _usingCtx$19.e = _;
6394
6394
  } finally {
6395
- _usingCtx$18.d();
6395
+ _usingCtx$19.d();
6396
6396
  }
6397
6397
  }
6398
6398
  //#endregion
@@ -6714,7 +6714,7 @@ function profileToPolygon(profile, circleSegments = 32) {
6714
6714
  //#region src/elementFns/beamFns.ts
6715
6715
  function beamToSolid(spec) {
6716
6716
  try {
6717
- var _usingCtx$17 = _usingCtx();
6717
+ var _usingCtx$18 = _usingCtx();
6718
6718
  if (spec.length <= 0) return (0, brepjs.err)(specError("BEAM_ZERO_LENGTH", "Beam length must be positive"));
6719
6719
  if (isExtendedProfile(spec.profile)) try {
6720
6720
  var _usingCtx3 = _usingCtx();
@@ -6752,7 +6752,7 @@ function beamToSolid(spec) {
6752
6752
  ]);
6753
6753
  const profileResult = (0, brepjs.polygon)(profilePts);
6754
6754
  if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "BEAM_PROFILE_FAILED", "Failed to create beam profile"));
6755
- const profile = _usingCtx$17.u(profileResult.value);
6755
+ const profile = _usingCtx$18.u(profileResult.value);
6756
6756
  const solidResult = (0, brepjs.extrude)(profile, [
6757
6757
  spec.length,
6758
6758
  0,
@@ -6766,16 +6766,16 @@ function beamToSolid(spec) {
6766
6766
  }
6767
6767
  return (0, brepjs.ok)(solid);
6768
6768
  } catch (_) {
6769
- _usingCtx$17.e = _;
6769
+ _usingCtx$18.e = _;
6770
6770
  } finally {
6771
- _usingCtx$17.d();
6771
+ _usingCtx$18.d();
6772
6772
  }
6773
6773
  }
6774
6774
  //#endregion
6775
6775
  //#region src/elementFns/columnFns.ts
6776
6776
  function columnToSolid(spec) {
6777
6777
  try {
6778
- var _usingCtx$16 = _usingCtx();
6778
+ var _usingCtx$17 = _usingCtx();
6779
6779
  if (spec.height <= 0) return (0, brepjs.err)(specError("COLUMN_ZERO_HEIGHT", "Column height must be positive"));
6780
6780
  if (isExtendedProfile(spec.profile)) try {
6781
6781
  var _usingCtx3 = _usingCtx();
@@ -6804,7 +6804,7 @@ function columnToSolid(spec) {
6804
6804
  const profilePts = profilePtsResult.value;
6805
6805
  const profileResult = (0, brepjs.polygon)(profilePts);
6806
6806
  if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "COLUMN_PROFILE_FAILED", "Failed to create column profile"));
6807
- const profile = _usingCtx$16.u(profileResult.value);
6807
+ const profile = _usingCtx$17.u(profileResult.value);
6808
6808
  const solidResult = (0, brepjs.extrude)(profile, [
6809
6809
  0,
6810
6810
  0,
@@ -6818,9 +6818,9 @@ function columnToSolid(spec) {
6818
6818
  }
6819
6819
  return (0, brepjs.ok)(solid);
6820
6820
  } catch (_) {
6821
- _usingCtx$16.e = _;
6821
+ _usingCtx$17.e = _;
6822
6822
  } finally {
6823
- _usingCtx$16.d();
6823
+ _usingCtx$17.d();
6824
6824
  }
6825
6825
  }
6826
6826
  //#endregion
@@ -6828,7 +6828,7 @@ function columnToSolid(spec) {
6828
6828
  var EPSILON_MM = 1;
6829
6829
  function openingToSolid(spec, wallThickness) {
6830
6830
  try {
6831
- var _usingCtx$15 = _usingCtx();
6831
+ var _usingCtx$16 = _usingCtx();
6832
6832
  if (spec.width <= 0) return (0, brepjs.err)(specError("OPENING_ZERO_WIDTH", "Opening width must be positive"));
6833
6833
  if (spec.height <= 0) return (0, brepjs.err)(specError("OPENING_ZERO_HEIGHT", "Opening height must be positive"));
6834
6834
  if (wallThickness <= 0) return (0, brepjs.err)(specError("OPENING_ZERO_WALL_THICKNESS", "Wall thickness must be positive"));
@@ -6860,7 +6860,7 @@ function openingToSolid(spec, wallThickness) {
6860
6860
  ]
6861
6861
  ]);
6862
6862
  if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "OPENING_PROFILE_FAILED", "Failed to create opening profile"));
6863
- const profile = _usingCtx$15.u(profileResult.value);
6863
+ const profile = _usingCtx$16.u(profileResult.value);
6864
6864
  const solidResult = (0, brepjs.extrude)(profile, [
6865
6865
  spec.width,
6866
6866
  0,
@@ -6874,16 +6874,16 @@ function openingToSolid(spec, wallThickness) {
6874
6874
  }
6875
6875
  return (0, brepjs.ok)(solid);
6876
6876
  } catch (_) {
6877
- _usingCtx$15.e = _;
6877
+ _usingCtx$16.e = _;
6878
6878
  } finally {
6879
- _usingCtx$15.d();
6879
+ _usingCtx$16.d();
6880
6880
  }
6881
6881
  }
6882
6882
  //#endregion
6883
6883
  //#region src/elementFns/slabOpeningFns.ts
6884
6884
  function slabOpeningToSolid(spec, slabThickness) {
6885
6885
  try {
6886
- var _usingCtx$14 = _usingCtx();
6886
+ var _usingCtx$15 = _usingCtx();
6887
6887
  if (spec.sizeX <= 0) return (0, brepjs.err)(specError("SLAB_OPENING_ZERO_SIZE_X", "Slab opening sizeX must be positive"));
6888
6888
  if (spec.sizeY <= 0) return (0, brepjs.err)(specError("SLAB_OPENING_ZERO_SIZE_Y", "Slab opening sizeY must be positive"));
6889
6889
  if (slabThickness <= 0) return (0, brepjs.err)(specError("SLAB_OPENING_ZERO_SLAB_THICKNESS", "Slab thickness must be positive"));
@@ -6915,7 +6915,7 @@ function slabOpeningToSolid(spec, slabThickness) {
6915
6915
  ]
6916
6916
  ]);
6917
6917
  if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "SLAB_OPENING_PROFILE_FAILED", "Failed to create slab opening profile"));
6918
- const profile = _usingCtx$14.u(profileResult.value);
6918
+ const profile = _usingCtx$15.u(profileResult.value);
6919
6919
  const solidResult = (0, brepjs.extrude)(profile, [
6920
6920
  0,
6921
6921
  0,
@@ -6929,16 +6929,16 @@ function slabOpeningToSolid(spec, slabThickness) {
6929
6929
  }
6930
6930
  return (0, brepjs.ok)(solid);
6931
6931
  } catch (_) {
6932
- _usingCtx$14.e = _;
6932
+ _usingCtx$15.e = _;
6933
6933
  } finally {
6934
- _usingCtx$14.d();
6934
+ _usingCtx$15.d();
6935
6935
  }
6936
6936
  }
6937
6937
  //#endregion
6938
6938
  //#region src/elementFns/spaceFns.ts
6939
6939
  function spaceToSolid(spec) {
6940
6940
  try {
6941
- var _usingCtx$13 = _usingCtx();
6941
+ var _usingCtx$14 = _usingCtx();
6942
6942
  if (spec.length <= 0) return (0, brepjs.err)(specError("SPACE_ZERO_LENGTH", "Space length must be positive"));
6943
6943
  if (spec.width <= 0) return (0, brepjs.err)(specError("SPACE_ZERO_WIDTH", "Space width must be positive"));
6944
6944
  if (spec.height <= 0) return (0, brepjs.err)(specError("SPACE_ZERO_HEIGHT", "Space height must be positive"));
@@ -6966,7 +6966,7 @@ function spaceToSolid(spec) {
6966
6966
  ]
6967
6967
  ]);
6968
6968
  if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "SPACE_PROFILE_FAILED", "Failed to create space footprint"));
6969
- const profile = _usingCtx$13.u(profileResult.value);
6969
+ const profile = _usingCtx$14.u(profileResult.value);
6970
6970
  const solidResult = (0, brepjs.extrude)(profile, [
6971
6971
  0,
6972
6972
  0,
@@ -6980,9 +6980,9 @@ function spaceToSolid(spec) {
6980
6980
  }
6981
6981
  return (0, brepjs.ok)(solid);
6982
6982
  } catch (_) {
6983
- _usingCtx$13.e = _;
6983
+ _usingCtx$14.e = _;
6984
6984
  } finally {
6985
- _usingCtx$13.d();
6985
+ _usingCtx$14.d();
6986
6986
  }
6987
6987
  }
6988
6988
  //#endregion
@@ -6997,7 +6997,7 @@ function gate(solid, code) {
6997
6997
  }
6998
6998
  function flatRoof(spec) {
6999
6999
  try {
7000
- var _usingCtx$12 = _usingCtx();
7000
+ var _usingCtx$13 = _usingCtx();
7001
7001
  const { length, width, thickness } = spec;
7002
7002
  const face = (0, brepjs.polygon)([
7003
7003
  [
@@ -7022,7 +7022,7 @@ function flatRoof(spec) {
7022
7022
  ]
7023
7023
  ]);
7024
7024
  if (!face.ok) return (0, brepjs.err)(fromBrepError(face.error, "ROOF_PROFILE_FAILED", "Failed to create roof profile"));
7025
- const profile = _usingCtx$12.u(face.value);
7025
+ const profile = _usingCtx$13.u(face.value);
7026
7026
  const solid = (0, brepjs.extrude)(profile, [
7027
7027
  0,
7028
7028
  0,
@@ -7031,9 +7031,9 @@ function flatRoof(spec) {
7031
7031
  if (!solid.ok) return (0, brepjs.err)(fromBrepError(solid.error, "ROOF_EXTRUDE_FAILED", "Failed to extrude roof profile"));
7032
7032
  return gate(solid.value, "ROOF_INVALID_SOLID");
7033
7033
  } catch (_) {
7034
- _usingCtx$12.e = _;
7034
+ _usingCtx$13.e = _;
7035
7035
  } finally {
7036
- _usingCtx$12.d();
7036
+ _usingCtx$13.d();
7037
7037
  }
7038
7038
  }
7039
7039
  function shedRoof(spec, pitch) {
@@ -7229,7 +7229,7 @@ function roofToSolid(spec) {
7229
7229
  //#region src/elementFns/curtainWallFns.ts
7230
7230
  function boxSolid(sizeX, sizeY, sizeZ) {
7231
7231
  try {
7232
- var _usingCtx$11 = _usingCtx();
7232
+ var _usingCtx$12 = _usingCtx();
7233
7233
  const profileResult = (0, brepjs.polygon)([
7234
7234
  [
7235
7235
  0,
@@ -7253,7 +7253,7 @@ function boxSolid(sizeX, sizeY, sizeZ) {
7253
7253
  ]
7254
7254
  ]);
7255
7255
  if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "CURTAIN_WALL_PROFILE_FAILED", "Failed to create component profile"));
7256
- const profile = _usingCtx$11.u(profileResult.value);
7256
+ const profile = _usingCtx$12.u(profileResult.value);
7257
7257
  const solidResult = (0, brepjs.extrude)(profile, [
7258
7258
  0,
7259
7259
  0,
@@ -7267,9 +7267,9 @@ function boxSolid(sizeX, sizeY, sizeZ) {
7267
7267
  }
7268
7268
  return (0, brepjs.ok)(solid);
7269
7269
  } catch (_) {
7270
- _usingCtx$11.e = _;
7270
+ _usingCtx$12.e = _;
7271
7271
  } finally {
7272
- _usingCtx$11.d();
7272
+ _usingCtx$12.d();
7273
7273
  }
7274
7274
  }
7275
7275
  function disposeComponents(components) {
@@ -7368,7 +7368,7 @@ function curtainWallToGrid(spec) {
7368
7368
  //#region src/elementFns/foundationFns.ts
7369
7369
  function footingToSolid(spec) {
7370
7370
  try {
7371
- var _usingCtx$10 = _usingCtx();
7371
+ var _usingCtx$11 = _usingCtx();
7372
7372
  if (spec.length <= 0) return (0, brepjs.err)(specError("FOOTING_ZERO_LENGTH", "Footing length must be positive"));
7373
7373
  if (spec.width <= 0) return (0, brepjs.err)(specError("FOOTING_ZERO_WIDTH", "Footing width must be positive"));
7374
7374
  if (spec.thickness <= 0) return (0, brepjs.err)(specError("FOOTING_ZERO_THICKNESS", "Footing thickness must be positive"));
@@ -7396,7 +7396,7 @@ function footingToSolid(spec) {
7396
7396
  ]
7397
7397
  ]);
7398
7398
  if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "FOOTING_PROFILE_FAILED", "Failed to create footing profile"));
7399
- const profile = _usingCtx$10.u(profileResult.value);
7399
+ const profile = _usingCtx$11.u(profileResult.value);
7400
7400
  const solidResult = (0, brepjs.extrude)(profile, [
7401
7401
  0,
7402
7402
  0,
@@ -7410,9 +7410,9 @@ function footingToSolid(spec) {
7410
7410
  }
7411
7411
  return (0, brepjs.ok)(solid);
7412
7412
  } catch (_) {
7413
- _usingCtx$10.e = _;
7413
+ _usingCtx$11.e = _;
7414
7414
  } finally {
7415
- _usingCtx$10.d();
7415
+ _usingCtx$11.d();
7416
7416
  }
7417
7417
  }
7418
7418
  function pileToSolid(spec) {
@@ -7469,7 +7469,7 @@ function pileToSolid(spec) {
7469
7469
  //#region src/elementFns/railingFns.ts
7470
7470
  function panelRailing(spec) {
7471
7471
  try {
7472
- var _usingCtx$9 = _usingCtx();
7472
+ var _usingCtx$10 = _usingCtx();
7473
7473
  const { length, height, thickness } = spec;
7474
7474
  const profileResult = (0, brepjs.polygon)([
7475
7475
  [
@@ -7494,7 +7494,7 @@ function panelRailing(spec) {
7494
7494
  ]
7495
7495
  ]);
7496
7496
  if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "RAILING_PROFILE_FAILED", "Failed to create railing profile"));
7497
- const profile = _usingCtx$9.u(profileResult.value);
7497
+ const profile = _usingCtx$10.u(profileResult.value);
7498
7498
  const solidResult = (0, brepjs.extrude)(profile, [
7499
7499
  length,
7500
7500
  0,
@@ -7508,9 +7508,9 @@ function panelRailing(spec) {
7508
7508
  }
7509
7509
  return (0, brepjs.ok)(solid);
7510
7510
  } catch (_) {
7511
- _usingCtx$9.e = _;
7511
+ _usingCtx$10.e = _;
7512
7512
  } finally {
7513
- _usingCtx$9.d();
7513
+ _usingCtx$10.d();
7514
7514
  }
7515
7515
  }
7516
7516
  function postedRailing(spec) {
@@ -7573,7 +7573,7 @@ function railingToSolid(spec) {
7573
7573
  //#region src/elementFns/coveringFns.ts
7574
7574
  function coveringToSolid(spec) {
7575
7575
  try {
7576
- var _usingCtx$8 = _usingCtx();
7576
+ var _usingCtx$9 = _usingCtx();
7577
7577
  if (spec.length <= 0) return (0, brepjs.err)(specError("COVERING_ZERO_LENGTH", "Covering length must be positive"));
7578
7578
  if (spec.width <= 0) return (0, brepjs.err)(specError("COVERING_ZERO_WIDTH", "Covering width must be positive"));
7579
7579
  if (spec.thickness <= 0) return (0, brepjs.err)(specError("COVERING_ZERO_THICKNESS", "Covering thickness must be positive"));
@@ -7601,7 +7601,7 @@ function coveringToSolid(spec) {
7601
7601
  ]
7602
7602
  ]);
7603
7603
  if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "COVERING_PROFILE_FAILED", "Failed to create covering profile"));
7604
- const profile = _usingCtx$8.u(profileResult.value);
7604
+ const profile = _usingCtx$9.u(profileResult.value);
7605
7605
  const solidResult = (0, brepjs.extrude)(profile, [
7606
7606
  0,
7607
7607
  0,
@@ -7615,9 +7615,9 @@ function coveringToSolid(spec) {
7615
7615
  }
7616
7616
  return (0, brepjs.ok)(solid);
7617
7617
  } catch (_) {
7618
- _usingCtx$8.e = _;
7618
+ _usingCtx$9.e = _;
7619
7619
  } finally {
7620
- _usingCtx$8.d();
7620
+ _usingCtx$9.d();
7621
7621
  }
7622
7622
  }
7623
7623
  //#endregion
@@ -7805,6 +7805,31 @@ function measureProductBodyMaterial(solids) {
7805
7805
  return measured;
7806
7806
  });
7807
7807
  }
7808
+ /** Borrow all items and query their tight bounds in their existing coordinates. */
7809
+ function productBodyBounds(solids) {
7810
+ const items = validateItems(solids, "productBodyBounds");
7811
+ if (!items.ok) return items;
7812
+ return ownedOperation("productBodyBounds", (scope) => {
7813
+ let bounds;
7814
+ for (const [itemIndex, solid] of items.value.entries()) {
7815
+ scope.itemIndex = itemIndex;
7816
+ const ready = before("bounds", itemIndex);
7817
+ if (!ready.ok) return ready;
7818
+ const current = (productBodyTestHooks()?.bounds ?? brepjs.getBounds)(solid);
7819
+ if (!Object.values(current).every(Number.isFinite) || current.xMin > current.xMax || current.yMin > current.yMax || current.zMin > current.zMax) return (0, brepjs.err)(bodyError("productBodyBounds", "BODY_INVALID_BOUNDS", "Expected finite ordered bounds", current, itemIndex));
7820
+ bounds = bounds === void 0 ? { ...current } : {
7821
+ xMin: Math.min(bounds.xMin, current.xMin),
7822
+ xMax: Math.max(bounds.xMax, current.xMax),
7823
+ yMin: Math.min(bounds.yMin, current.yMin),
7824
+ yMax: Math.max(bounds.yMax, current.yMax),
7825
+ zMin: Math.min(bounds.zMin, current.zMin),
7826
+ zMax: Math.max(bounds.zMax, current.zMax)
7827
+ };
7828
+ }
7829
+ if (bounds === void 0) throw new Error("Validated Body produced no bounds");
7830
+ return (0, brepjs.ok)(Object.freeze({ bounds: Object.freeze(bounds) }));
7831
+ });
7832
+ }
7808
7833
  //#endregion
7809
7834
  //#region src/model/bimModel.ts
7810
7835
  function exactWallBodyImmutable() {
@@ -8360,18 +8385,18 @@ var BimModel = class {
8360
8385
  }
8361
8386
  #cutWallGeometry(wall, openingSpec) {
8362
8387
  try {
8363
- var _usingCtx$7 = _usingCtx();
8388
+ var _usingCtx$8 = _usingCtx();
8364
8389
  if (wall.geometry.kind === "EXACT") return exactWallBodyImmutable();
8365
8390
  const toolResult = openingToSolid(openingSpec, wall.spec.thickness);
8366
8391
  if (!toolResult.ok) return (0, brepjs.err)(toolResult.error);
8367
- const tool = _usingCtx$7.u(toolResult.value);
8392
+ const tool = _usingCtx$8.u(toolResult.value);
8368
8393
  const cutResult = (0, brepjs.cut)(wall.geometry.solid, tool);
8369
8394
  if (!cutResult.ok) return (0, brepjs.err)(fromBrepError(cutResult.error, "WALL_CUT_FAILED", "Boolean cut of wall with opening failed"));
8370
8395
  return (0, brepjs.ok)(cutResult.value);
8371
8396
  } catch (_) {
8372
- _usingCtx$7.e = _;
8397
+ _usingCtx$8.e = _;
8373
8398
  } finally {
8374
- _usingCtx$7.d();
8399
+ _usingCtx$8.d();
8375
8400
  }
8376
8401
  }
8377
8402
  #replaceWallGeometry(wall, newGeometry) {
@@ -8986,7 +9011,7 @@ function buildSilhouette$1(numberOfRisers, riserHeight, treadLength) {
8986
9011
  }
8987
9012
  function stairFlightToSolid(spec) {
8988
9013
  try {
8989
- var _usingCtx$6 = _usingCtx();
9014
+ var _usingCtx$7 = _usingCtx();
8990
9015
  if (spec.width <= 0) return (0, brepjs.err)(specError("STAIR_FLIGHT_ZERO_WIDTH", "Stair flight width must be positive"));
8991
9016
  if (spec.riserHeight <= 0) return (0, brepjs.err)(specError("STAIR_FLIGHT_ZERO_RISER", "Stair flight riserHeight must be positive"));
8992
9017
  if (spec.treadLength <= 0) return (0, brepjs.err)(specError("STAIR_FLIGHT_ZERO_TREAD", "Stair flight treadLength must be positive"));
@@ -8994,7 +9019,7 @@ function stairFlightToSolid(spec) {
8994
9019
  const silhouette = buildSilhouette$1(spec.numberOfRisers, spec.riserHeight, spec.treadLength);
8995
9020
  const profileResult = (0, brepjs.polygon)(silhouette);
8996
9021
  if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "STAIR_FLIGHT_PROFILE_FAILED", "Failed to create stair flight silhouette profile"));
8997
- const profile = _usingCtx$6.u(profileResult.value);
9022
+ const profile = _usingCtx$7.u(profileResult.value);
8998
9023
  const solidResult = (0, brepjs.extrude)(profile, [
8999
9024
  0,
9000
9025
  spec.width,
@@ -9011,9 +9036,9 @@ function stairFlightToSolid(spec) {
9011
9036
  geometrySimplified: false
9012
9037
  });
9013
9038
  } catch (_) {
9014
- _usingCtx$6.e = _;
9039
+ _usingCtx$7.e = _;
9015
9040
  } finally {
9016
- _usingCtx$6.d();
9041
+ _usingCtx$7.d();
9017
9042
  }
9018
9043
  }
9019
9044
  //#endregion
@@ -9044,7 +9069,7 @@ function buildSilhouette(length, rise, thickness) {
9044
9069
  }
9045
9070
  function rampFlightToSolid(spec) {
9046
9071
  try {
9047
- var _usingCtx$5 = _usingCtx();
9072
+ var _usingCtx$6 = _usingCtx();
9048
9073
  if (spec.width <= 0) return (0, brepjs.err)(specError("RAMP_FLIGHT_ZERO_WIDTH", "Ramp flight width must be positive"));
9049
9074
  if (spec.length <= 0) return (0, brepjs.err)(specError("RAMP_FLIGHT_ZERO_LENGTH", "Ramp flight length must be positive"));
9050
9075
  if (spec.slope <= 0) return (0, brepjs.err)(specError("RAMP_FLIGHT_ZERO_SLOPE", "Ramp flight slope must be positive"));
@@ -9053,7 +9078,7 @@ function rampFlightToSolid(spec) {
9053
9078
  const silhouette = buildSilhouette(spec.length, rise, spec.thickness);
9054
9079
  const profileResult = (0, brepjs.polygon)(silhouette);
9055
9080
  if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "RAMP_FLIGHT_PROFILE_FAILED", "Failed to create ramp flight silhouette profile"));
9056
- const profile = _usingCtx$5.u(profileResult.value);
9081
+ const profile = _usingCtx$6.u(profileResult.value);
9057
9082
  const solidResult = (0, brepjs.extrude)(profile, [
9058
9083
  0,
9059
9084
  spec.width,
@@ -9070,9 +9095,9 @@ function rampFlightToSolid(spec) {
9070
9095
  geometrySimplified: true
9071
9096
  });
9072
9097
  } catch (_) {
9073
- _usingCtx$5.e = _;
9098
+ _usingCtx$6.e = _;
9074
9099
  } finally {
9075
- _usingCtx$5.d();
9100
+ _usingCtx$6.d();
9076
9101
  }
9077
9102
  }
9078
9103
  //#endregion
@@ -9215,22 +9240,22 @@ function placedSolids(el, options = {}) {
9215
9240
  case "STAIR": {
9216
9241
  const out = [];
9217
9242
  for (const flight of el.spec.flights) try {
9218
- var _usingCtx$4 = _usingCtx();
9243
+ var _usingCtx$5 = _usingCtx();
9219
9244
  const built = stairFlightToSolid(flight);
9220
9245
  if (!built.ok) {
9221
9246
  disposeAll$1(out);
9222
9247
  return (0, brepjs.err)(built.error);
9223
9248
  }
9224
- const placed = placeWithinParent(_usingCtx$4.u(built.value.solid), flight, parentFrame);
9249
+ const placed = placeWithinParent(_usingCtx$5.u(built.value.solid), flight, parentFrame);
9225
9250
  if (!placed.ok) {
9226
9251
  disposeAll$1(out);
9227
9252
  return placed;
9228
9253
  }
9229
9254
  out.push(placed.value);
9230
9255
  } catch (_) {
9231
- _usingCtx$4.e = _;
9256
+ _usingCtx$5.e = _;
9232
9257
  } finally {
9233
- _usingCtx$4.d();
9258
+ _usingCtx$5.d();
9234
9259
  }
9235
9260
  return (0, brepjs.ok)(out);
9236
9261
  }
@@ -11714,22 +11739,22 @@ function writeStairAssembly(w, spec, stairKey, assemblyGuid, ownerHistoryId, geo
11714
11739
  const flightExpressIds = [];
11715
11740
  let geometrySimplified = false;
11716
11741
  for (const [i, flight] of spec.flights.entries()) try {
11717
- var _usingCtx$3 = _usingCtx();
11742
+ var _usingCtx$4 = _usingCtx();
11718
11743
  const built = stairFlightToSolid(flight);
11719
11744
  if (!built.ok) return {
11720
11745
  ok: false,
11721
11746
  error: built.error
11722
11747
  };
11723
- const flightSolid = _usingCtx$3.u(built.value.solid);
11748
+ const flightSolid = _usingCtx$4.u(built.value.solid);
11724
11749
  const flightPlacementId = writeLocalPlacement(w, flight.origin, flight.axisZ, flight.axisX, stairPlacementId);
11725
11750
  const tess = writeTessellation(w, flightSolid, geomSubContextId, flightPlacementId);
11726
11751
  if (tess.usedFallback) geometrySimplified = true;
11727
11752
  const flightExpressId = writeStairFlightEntity(w, deriveIfcGuidSync(`elem:STAIR_FLIGHT:${stairKey}:${i}`), `${stairName} Flight ${i + 1}`, flight, ownerHistoryId, flightPlacementId, tess.productDefinitionShapeId);
11728
11753
  flightExpressIds.push(flightExpressId);
11729
11754
  } catch (_) {
11730
- _usingCtx$3.e = _;
11755
+ _usingCtx$4.e = _;
11731
11756
  } finally {
11732
- _usingCtx$3.d();
11757
+ _usingCtx$4.d();
11733
11758
  }
11734
11759
  writeRelAggregates(w, deriveIfcGuidSync(`rel:AGGREGATES:STAIR:${stairKey}`), ownerHistoryId, assemblyExpressId, flightExpressIds);
11735
11760
  writeAssemblyType(w, web_ifc.IFCSTAIRTYPE, "Stair Type", deriveIfcGuidSync(`type:STAIR:${stairKey}`), deriveIfcGuidSync(`rel-type:STAIR:${stairKey}`), predefinedType, ownerHistoryId, [assemblyExpressId]);
@@ -13092,7 +13117,7 @@ function pushWeightQuantity(w, qtyIds, volumeM3, densityKgM3) {
13092
13117
  if (densityKgM3 === void 0) return;
13093
13118
  qtyIds.push(writeWeightQuantity(w, "GrossWeight", volumeM3, densityKgM3));
13094
13119
  }
13095
- function writeWallBaseQuantities(w, ownerHistoryId, wallExpressId, spec, openings, densityKgM3) {
13120
+ function writeWallBaseQuantities(w, ownerHistoryId, wallExpressId, spec, openings, netVolumeM3, densityKgM3) {
13096
13121
  const lengthM = toIfcLengthM(spec.length);
13097
13122
  const widthM = toIfcLengthM(spec.thickness);
13098
13123
  const heightM = toIfcLengthM(spec.height);
@@ -13108,7 +13133,6 @@ function writeWallBaseQuantities(w, ownerHistoryId, wallExpressId, spec, opening
13108
13133
  if (toIfcLengthM(op.offsetFromFloor) < FLOOR_TOUCH_EPSILON_M) sumFloorTouchingFootprintM2 += opWidthM * widthM;
13109
13134
  }
13110
13135
  const netSideAreaM2 = grossSideAreaM2 - sumOpeningAreaM2;
13111
- const netVolumeM3 = grossVolumeM3 - sumOpeningAreaM2 * widthM;
13112
13136
  const netFootprintM2 = grossFootprintM2 - sumFloorTouchingFootprintM2;
13113
13137
  const qtyIds = [
13114
13138
  writeQtyLength(w, "Length", lengthM),
@@ -13124,7 +13148,7 @@ function writeWallBaseQuantities(w, ownerHistoryId, wallExpressId, spec, opening
13124
13148
  pushWeightQuantity(w, qtyIds, netVolumeM3, densityKgM3);
13125
13149
  writeRelDefinesByProperties(w, ownerHistoryId, wallExpressId, writeElementQuantity(w, ownerHistoryId, "Qto_WallBaseQuantities", qtyIds));
13126
13150
  }
13127
- function writeExactWallBaseQuantities(w, ownerHistoryId, wallExpressId, values) {
13151
+ function writeWallBodyQuantities(w, ownerHistoryId, wallExpressId, values) {
13128
13152
  writeRelDefinesByProperties(w, ownerHistoryId, wallExpressId, writeElementQuantity(w, ownerHistoryId, "Qto_WallBaseQuantities", [
13129
13153
  writeQtyLength(w, "Length", values.lengthM),
13130
13154
  writeQtyLength(w, "Width", values.widthM),
@@ -15188,10 +15212,25 @@ function preflightExactBody(input) {
15188
15212
  return (0, brepjs.ok)([first.value, ...remainingPrepared]);
15189
15213
  }
15190
15214
  //#endregion
15191
- //#region src/serialize/exactWallQuantities.ts
15192
- function deriveExactWallQuantities(input) {
15215
+ //#region src/serialize/wallQuantities.ts
15216
+ function deriveWallQuantities(input) {
15193
15217
  try {
15194
- const measured = measureProductBodyMaterial(input.solids);
15218
+ const items = [];
15219
+ for (const retained of input.solids) {
15220
+ if ((0, brepjs.getKernel)().shapeType(retained.wrapped) !== "compound") {
15221
+ items.push(retained);
15222
+ continue;
15223
+ }
15224
+ const cardinality = singleWrapperChild(retained);
15225
+ if (!cardinality.ok) return cardinality;
15226
+ const children = (0, brepjs.getSolids)(retained);
15227
+ const [child] = children;
15228
+ if (children.length !== 1 || child === void 0 || !(0, brepjs.isValidSolid)(child)) return wallVolumeError(/* @__PURE__ */ new Error("Expected one valid solid in a retained recipe wrapper"));
15229
+ items.push(child);
15230
+ }
15231
+ const [first, ...rest] = items;
15232
+ if (first === void 0) return wallVolumeError(/* @__PURE__ */ new Error("Expected retained Wall material"));
15233
+ const measured = measureProductBodyMaterial([first, ...rest]);
15195
15234
  if (!measured.ok) return wallVolumeError(measured.error);
15196
15235
  return (0, brepjs.ok)({
15197
15236
  lengthM: toIfcLengthM(input.spec.length),
@@ -15203,8 +15242,24 @@ function deriveExactWallQuantities(input) {
15203
15242
  return wallVolumeError(cause);
15204
15243
  }
15205
15244
  }
15245
+ /** Count before cached extraction: a failed later cast cannot strand earlier children. */
15246
+ function singleWrapperChild(retained) {
15247
+ const kernel = (0, brepjs.getKernel)();
15248
+ let count;
15249
+ if (kernel.subShapeCount !== void 0) count = kernel.subShapeCount(retained.wrapped, "solid");
15250
+ else {
15251
+ const rawChildren = kernel.iterShapes(retained.wrapped, "solid");
15252
+ const cleanup = cleanupOwnedResources(rawChildren.map((raw, itemIndex) => ({
15253
+ resource: { [Symbol.dispose]: () => kernel.dispose(raw) },
15254
+ itemIndex
15255
+ })), { operation: "wallQuantityWrapperCount" });
15256
+ if (cleanup.kind === "FAILED") return wallVolumeError({ cleanup });
15257
+ count = rawChildren.length;
15258
+ }
15259
+ return count === 1 ? (0, brepjs.ok)(void 0) : wallVolumeError(/* @__PURE__ */ new Error("Expected one valid solid in a retained recipe wrapper"));
15260
+ }
15206
15261
  function wallVolumeError(cause) {
15207
- return (0, brepjs.err)(ifcError("IFC_EXACT_WALL_QUANTITY_DERIVATION_FAILED", "Failed to derive a positive finite NetVolume for the retained Wall Body", cause));
15262
+ return (0, brepjs.err)(ifcError("IFC_WALL_QUANTITY_DERIVATION_FAILED", "Failed to derive a positive finite NetVolume for the retained Wall Body", cause));
15208
15263
  }
15209
15264
  //#endregion
15210
15265
  //#region src/serialize/toIfc.ts
@@ -15235,8 +15290,13 @@ function preflightProductBodies(elements) {
15235
15290
  return (0, brepjs.ok)(preflighted);
15236
15291
  }
15237
15292
  async function toIfc(model, meta) {
15293
+ const serialized = await serializeIfc(model, meta);
15294
+ return serialized.ok ? (0, brepjs.ok)(serialized.value.bytes) : serialized;
15295
+ }
15296
+ async function serializeIfc(model, meta) {
15238
15297
  try {
15239
- var _usingCtx$2 = _usingCtx();
15298
+ var _usingCtx$3 = _usingCtx();
15299
+ const issues = [];
15240
15300
  const project = model.getProject();
15241
15301
  if (!project) return (0, brepjs.err)(ifcError("NO_PROJECT", "BimModel has no project — call model.init() first"));
15242
15302
  if ((model.getBridges().length > 0 || model.getBridgeParts().length > 0 || model.getEarthworksFills().length > 0) && (meta.ifcSchema ?? "IFC4") !== "IFC4X3") return (0, brepjs.err)(ifcError("IFC4X3_REQUIRED", "Bridge, Bridge Part, and Earthworks Fill entities require IFC4X3 serialization"));
@@ -15246,7 +15306,7 @@ async function toIfc(model, meta) {
15246
15306
  organization: meta.organizationName
15247
15307
  });
15248
15308
  if (!writerResult.ok) return writerResult;
15249
- const w = _usingCtx$2.u(writerResult.value);
15309
+ const w = _usingCtx$3.u(writerResult.value);
15250
15310
  w.setModelScope(project.guid);
15251
15311
  const elements = model.getAllElements();
15252
15312
  const relationships = model.getAllRelationships();
@@ -15354,10 +15414,10 @@ async function toIfc(model, meta) {
15354
15414
  const wall = preflighted.element;
15355
15415
  const containingId = findContainerOf(wall.localId, relationships);
15356
15416
  const storeyPlacementId = containingId !== null ? placementMap.get(containingId) ?? null : null;
15357
- const exactQuantities = preflighted.kind === "EXACT" ? deriveExactWallQuantities({
15417
+ const bodyQuantities = deriveWallQuantities({
15358
15418
  spec: wall.spec,
15359
- solids: preflighted.solids
15360
- }) : null;
15419
+ solids: bodySolids(wall.geometry)
15420
+ });
15361
15421
  const { localPlacementId, productDefinitionShapeId } = preflighted.kind === "EXACT" ? writeExactBodyGeometry(w, wall.spec, preflighted.items, geomSubContextId, storeyPlacementId) : writeWallGeometry(w, wall.spec, geomSubContextId, storeyPlacementId);
15362
15422
  const wallExpressId = writeWallEntity(w, wall.guid, `Wall ${i + 1}`, ownerHistoryId, localPlacementId, productDefinitionShapeId);
15363
15423
  idMap.set(wall.localId, wallExpressId);
@@ -15365,9 +15425,12 @@ async function toIfc(model, meta) {
15365
15425
  writeWallCommonPset(w, ownerHistoryId, wallExpressId, wall.spec);
15366
15426
  writeManufacturerPset(w, ownerHistoryId, wallExpressId, wall.spec);
15367
15427
  if (wall.spec.customProperties !== void 0) writeCustomPsets(w, ownerHistoryId, wallExpressId, wall.spec.customProperties);
15368
- if (preflighted.kind === "EXACT") {
15369
- if (exactQuantities !== null && exactQuantities.ok) writeExactWallBaseQuantities(w, ownerHistoryId, wallExpressId, exactQuantities.value);
15370
- } else writeWallBaseQuantities(w, ownerHistoryId, wallExpressId, wall.spec, openingsByWall.get(wall.localId) ?? [], densityByElement.get(wall.localId));
15428
+ if (!bodyQuantities.ok) issues.push(issue("warning", "WALL_QUANTITY_OMITTED", "Wall quantities omitted because occupied material volume could not be measured", wall.localId, {
15429
+ guid: wall.guid,
15430
+ cause: bodyQuantities.error
15431
+ }));
15432
+ else if (wall.geometry.kind === "PARAMETRIC") writeWallBaseQuantities(w, ownerHistoryId, wallExpressId, wall.spec, openingsByWall.get(wall.localId) ?? [], bodyQuantities.value.netVolumeM3, densityByElement.get(wall.localId));
15433
+ else writeWallBodyQuantities(w, ownerHistoryId, wallExpressId, bodyQuantities.value);
15371
15434
  }
15372
15435
  for (const [i, slab] of slabs.entries()) {
15373
15436
  const containingId = findContainerOf(slab.localId, relationships);
@@ -15711,11 +15774,15 @@ async function toIfc(model, meta) {
15711
15774
  for (const { ref, ids } of classByKey.values()) byClassification.set(ref, ids);
15712
15775
  if (byClassification.size > 0) writeClassificationRefs(w, ownerHistoryId, byClassification);
15713
15776
  writeTypeLayer(w, ownerHistoryId, model, idMap);
15714
- return w.save();
15777
+ const saved = w.save();
15778
+ return saved.ok ? (0, brepjs.ok)({
15779
+ bytes: saved.value,
15780
+ issues
15781
+ }) : saved;
15715
15782
  } catch (_) {
15716
- _usingCtx$2.e = _;
15783
+ _usingCtx$3.e = _;
15717
15784
  } finally {
15718
- _usingCtx$2.d();
15785
+ _usingCtx$3.d();
15719
15786
  }
15720
15787
  }
15721
15788
  /**
@@ -15831,15 +15898,16 @@ function toOccurrences(elements, predefined) {
15831
15898
  async function toIfcValidated(model, meta) {
15832
15899
  const integrity = checkReferentialIntegrity(model);
15833
15900
  if (hasErrors(integrity)) return (0, brepjs.err)(ifcError("INTEGRITY_FAILURE", "Model failed referential integrity check", integrity.issues.filter((i) => i.severity === "error")));
15834
- const bytesResult = await toIfc(model, meta);
15835
- if (!bytesResult.ok) return bytesResult;
15836
- const bytes = bytesResult.value;
15901
+ const serialized = await serializeIfc(model, meta);
15902
+ if (!serialized.ok) return serialized;
15903
+ const { bytes } = serialized.value;
15837
15904
  const geometry = collectGeometryIssues(model);
15838
15905
  const schema = await checkSchema(bytes);
15839
15906
  const roundTrip = await checkRoundTrip(bytes);
15840
15907
  const gherkin = await checkGherkinRules(bytes);
15841
15908
  const report = { issues: [
15842
15909
  ...integrity.issues,
15910
+ ...serialized.value.issues,
15843
15911
  ...geometry.issues,
15844
15912
  ...schema.issues,
15845
15913
  ...roundTrip.issues,
@@ -16432,13 +16500,13 @@ function reconstructExtrusion(reader, extrusionId, scale, worldTransform, diagno
16432
16500
  ];
16433
16501
  const solidResult = (() => {
16434
16502
  try {
16435
- var _usingCtx$1 = _usingCtx();
16436
- const face = _usingCtx$1.u(faceResult.value);
16503
+ var _usingCtx$2 = _usingCtx();
16504
+ const face = _usingCtx$2.u(faceResult.value);
16437
16505
  return (0, brepjs.extrude)(face, extrudeVec);
16438
16506
  } catch (_) {
16439
- _usingCtx$1.e = _;
16507
+ _usingCtx$2.e = _;
16440
16508
  } finally {
16441
- _usingCtx$1.d();
16509
+ _usingCtx$2.d();
16442
16510
  }
16443
16511
  })();
16444
16512
  if (!solidResult.ok) {
@@ -17160,6 +17228,161 @@ function errMsg$1(e) {
17160
17228
  return e instanceof Error ? e.message : String(e);
17161
17229
  }
17162
17230
  //#endregion
17231
+ //#region src/geometryCleanupDiagnostics.ts
17232
+ var diagnosticSchema = object({
17233
+ operation: string(),
17234
+ itemIndex: number().int().nonnegative(),
17235
+ resourceKind: _enum(["SHAPE", "TRANSFORM"]),
17236
+ localId: number().optional(),
17237
+ cause: unknown()
17238
+ });
17239
+ var failedCleanup = object({
17240
+ kind: literal("FAILED"),
17241
+ diagnostics: array(unknown()).nonempty()
17242
+ });
17243
+ var errorMetadata = object({ cleanup: unknown().optional() });
17244
+ var cleanupAttempt = Symbol("geometryCleanupAttempt");
17245
+ var bodyOperation = _enum(["productBodyBounds", "measureProductBodyMaterial"]);
17246
+ function attemptIdentity(source) {
17247
+ const identity = cleanupAttempt in source ? source[cleanupAttempt] : source;
17248
+ return typeof identity === "object" && identity !== null ? identity : source;
17249
+ }
17250
+ function errorChildren(value) {
17251
+ const children = [];
17252
+ if (value instanceof AggregateError) {
17253
+ const errors = value.errors;
17254
+ children.push(...errors);
17255
+ }
17256
+ if ("cause" in value) children.push(value.cause);
17257
+ if ("error" in value && "suppressed" in value) children.push(value.error, value.suppressed);
17258
+ return children;
17259
+ }
17260
+ /** Keep the actual failed-attempt markers; their causes need not be unique. */
17261
+ function nativeCleanupAttempts(error) {
17262
+ const attempts = [];
17263
+ const seen = /* @__PURE__ */ new Set();
17264
+ const visit = (value) => {
17265
+ if (typeof value !== "object" || value === null || seen.has(value)) return;
17266
+ seen.add(value);
17267
+ if (value instanceof brepjs.GeometryCleanupError) attempts.push(value);
17268
+ else errorChildren(value).forEach(visit);
17269
+ };
17270
+ visit(error);
17271
+ return attempts;
17272
+ }
17273
+ /** Read prior owner attempts without retrying releases or merging distinct failures. */
17274
+ function reportedGeometryCleanup(error, operation, context = {}) {
17275
+ const diagnostics = [];
17276
+ const seenErrors = /* @__PURE__ */ new Set();
17277
+ const seenAttempts = /* @__PURE__ */ new Set();
17278
+ const add = (diagnostic, identity) => {
17279
+ if (seenAttempts.has(identity)) return;
17280
+ seenAttempts.add(identity);
17281
+ diagnostics.push(Object.freeze({
17282
+ operation: diagnostic.operation,
17283
+ itemIndex: diagnostic.itemIndex,
17284
+ resourceKind: diagnostic.resourceKind,
17285
+ cause: diagnostic.cause,
17286
+ ...diagnostic.localId === void 0 ? {} : { localId: diagnostic.localId },
17287
+ [cleanupAttempt]: identity
17288
+ }));
17289
+ };
17290
+ const visit = (value) => {
17291
+ if (typeof value !== "object" || value === null || seenErrors.has(value)) return;
17292
+ seenErrors.add(value);
17293
+ const metadata = errorMetadata.safeParse("metadata" in value ? value.metadata : void 0);
17294
+ const reports = [metadata.success ? metadata.data.cleanup : void 0, "cleanup" in value ? value.cleanup : void 0];
17295
+ const nativeAttempts = bodyOperation.safeParse("operation" in value ? value.operation : void 0).success ? nativeCleanupAttempts(value) : [];
17296
+ const matched = /* @__PURE__ */ new Set();
17297
+ const seenEntries = /* @__PURE__ */ new Set();
17298
+ for (const report of reports) {
17299
+ const parsed = failedCleanup.safeParse(report);
17300
+ if (!parsed.success) continue;
17301
+ for (const source of parsed.data.diagnostics) {
17302
+ if (typeof source !== "object" || source === null || seenEntries.has(source)) continue;
17303
+ const diagnostic = diagnosticSchema.safeParse(source);
17304
+ if (!diagnostic.success) continue;
17305
+ seenEntries.add(source);
17306
+ let identity = attemptIdentity(source);
17307
+ if (identity === source) {
17308
+ const native = nativeAttempts.find((attempt) => !matched.has(attempt) && attempt.resourceKind === diagnostic.data.resourceKind && attempt.cause === diagnostic.data.cause);
17309
+ if (native !== void 0) identity = native;
17310
+ }
17311
+ if (identity instanceof brepjs.GeometryCleanupError) matched.add(identity);
17312
+ add(diagnostic.data, identity);
17313
+ }
17314
+ }
17315
+ if (value instanceof brepjs.GeometryCleanupError) add({
17316
+ operation,
17317
+ itemIndex: context.itemIndex ?? 0,
17318
+ resourceKind: value.resourceKind,
17319
+ cause: value.cause
17320
+ }, value);
17321
+ else errorChildren(value).forEach(visit);
17322
+ };
17323
+ visit(error);
17324
+ return diagnostics;
17325
+ }
17326
+ //#endregion
17327
+ //#region src/import/cutImportedSolids.ts
17328
+ /** Borrow World-placed inputs; own every disconnected result independently of the cut's cache. */
17329
+ function cutImportedSolids(host, opening) {
17330
+ const context = { operation: "cutImportedSolids" };
17331
+ const temporaries = [];
17332
+ const outputs = [];
17333
+ const build = () => {
17334
+ const cutResult = (0, brepjs.cut)(host, opening);
17335
+ if (!cutResult.ok) return (0, brepjs.err)(fromBrepError(cutResult.error, "VOID_CUT_FAILED", "Opening cut failed"));
17336
+ temporaries.push({
17337
+ resource: cutResult.value,
17338
+ itemIndex: 0
17339
+ });
17340
+ const children = (0, brepjs.getKernel)().iterShapes(cutResult.value.wrapped, "solid").map(brepjs.createSolid);
17341
+ temporaries.push(...children.map((resource, itemIndex) => ({
17342
+ resource,
17343
+ itemIndex
17344
+ })));
17345
+ for (const solid of children) {
17346
+ const copied = (0, brepjs.clone)(solid);
17347
+ if (!copied.ok) return (0, brepjs.err)(fromBrepError(copied.error, "VOID_COPY_FAILED", "Could not retain opening result"));
17348
+ const candidate = copied.value;
17349
+ temporaries.push({
17350
+ resource: candidate,
17351
+ itemIndex: temporaries.length
17352
+ });
17353
+ const validated = (0, brepjs.validSolid)(candidate);
17354
+ if (!validated.ok) return (0, brepjs.err)(importError("VOID_INVALID_SOLID", "Opening result is not valid", validated.error));
17355
+ outputs.push(validated.value);
17356
+ }
17357
+ return (0, brepjs.ok)(outputs);
17358
+ };
17359
+ let result;
17360
+ try {
17361
+ result = build();
17362
+ } catch (cause) {
17363
+ result = (0, brepjs.err)(importError("VOID_CUT_FAILED", "Opening cut failed", cause));
17364
+ }
17365
+ const survivors = new Set(result.ok ? outputs : []);
17366
+ const cleanup = cleanupOwnedResources(temporaries.filter(({ resource }) => !survivors.has(resource)).reverse(), context);
17367
+ const diagnostics = [...result.ok ? [] : reportedGeometryCleanup(result.error, context.operation), ...cleanup.kind === "FAILED" ? cleanup.diagnostics : []];
17368
+ if (result.ok && diagnostics.length === 0) return result;
17369
+ if (result.ok) {
17370
+ const outputCleanup = cleanupOwnedResources(outputs.map((resource, itemIndex) => ({
17371
+ resource,
17372
+ itemIndex
17373
+ })), context);
17374
+ if (outputCleanup.kind === "FAILED") diagnostics.push(...outputCleanup.diagnostics);
17375
+ }
17376
+ const failure = result.ok ? importError("VOID_CLEANUP_FAILED", "Opening result cleanup failed") : result.error;
17377
+ return (0, brepjs.err)({
17378
+ ...failure,
17379
+ metadata: {
17380
+ ...failure.metadata,
17381
+ cleanup: cleanupReport(diagnostics)
17382
+ }
17383
+ });
17384
+ }
17385
+ //#endregion
17163
17386
  //#region src/import/dataRead.ts
17164
17387
  /** Narrows an unknown line attribute to the `{ type, value }` wrapper shape. */
17165
17388
  function asTyped(v) {
@@ -17515,7 +17738,7 @@ var ELEMENT_TYPES = [
17515
17738
  * fatal failures — bad bytes, unsupported schema, WASM open failure — return
17516
17739
  * `err`. Inspect {@link ImportedModel.diagnostics} for per-element quality.
17517
17740
  *
17518
- * The web-ifc model handle is always closed in a `finally` block.
17741
+ * The web-ifc model handle is closed before handing reconstructed owners to the caller.
17519
17742
  */
17520
17743
  async function fromIfc(bytes, options = {}) {
17521
17744
  const settings = { coordinateToOrigin: options.coordinateToOrigin ?? false };
@@ -17523,6 +17746,7 @@ async function fromIfc(bytes, options = {}) {
17523
17746
  if (!readerResult.ok) return (0, brepjs.err)(readerResult.error);
17524
17747
  const reader = readerResult.value;
17525
17748
  const elements = [];
17749
+ let result;
17526
17750
  try {
17527
17751
  reader.buildGuidMap();
17528
17752
  const diagnostics = [];
@@ -17549,13 +17773,23 @@ async function fromIfc(bytes, options = {}) {
17549
17773
  diagnostics: report,
17550
17774
  ...applicationName !== void 0 ? { applicationName } : {}
17551
17775
  };
17552
- return (0, brepjs.ok)(model);
17776
+ result = (0, brepjs.ok)(model);
17553
17777
  } catch (e) {
17554
- disposeElements(elements);
17555
- return (0, brepjs.err)(importError("IMPORT_FAILED", "Unexpected failure during IFC import", e));
17556
- } finally {
17778
+ result = (0, brepjs.err)(importError("IMPORT_FAILED", "Unexpected failure during IFC import", e));
17779
+ }
17780
+ try {
17557
17781
  reader.close();
17782
+ } catch (cause) {
17783
+ result = (0, brepjs.err)(result.ok ? importError("IMPORT_CLOSE_FAILED", "Failed to close IFC reader", cause) : {
17784
+ ...result.error,
17785
+ metadata: {
17786
+ ...result.error.metadata,
17787
+ readerCloseCause: cause
17788
+ }
17789
+ });
17558
17790
  }
17791
+ if (!result.ok) return (0, brepjs.err)(withCleanup(result.error, disposeElements(elements), "fromIfc"));
17792
+ return result;
17559
17793
  }
17560
17794
  /**
17561
17795
  * Reads one product into an {@link ImportedElement}. Returns null only when the
@@ -17606,8 +17840,8 @@ function readElement(reader, expressId, category, scale, containment, typeEnums,
17606
17840
  ...fills !== void 0 ? { fills } : {}
17607
17841
  };
17608
17842
  } catch (e) {
17609
- if (geometry !== null) disposeGeometry(geometry);
17610
- diagnostics.push(issue("error", "ELEMENT_READ_FAILED", `Element ${expressId} reconstruction threw: ${errMsg(e)}`, expressId));
17843
+ const failure = geometry === null ? e : withCleanup(importError("ELEMENT_READ_FAILED", "Element read failed", e), disposeGeometry(geometry), "readElement");
17844
+ diagnostics.push(issue("error", "ELEMENT_READ_FAILED", `Element ${expressId} reconstruction threw: ${errMsg(e)}`, expressId, { cause: failure }));
17611
17845
  return null;
17612
17846
  }
17613
17847
  }
@@ -17623,36 +17857,79 @@ function findFills(reader, elementExpressId) {
17623
17857
  }
17624
17858
  /**
17625
17859
  * Reconstructs a host element's body geometry and, per IFC `IfcRelVoidsElement`
17626
- * semantics, subtracts the reconstructed solid of every opening that voids it —
17860
+ * semantics, subtracts each opening's Body representation from a parametric host —
17627
17861
  * so a wall with a door hole comes back as the cut solid, matching the source
17628
17862
  * model. Falls back to the uncut solid (with a diagnostic) if a cut fails.
17629
17863
  */
17630
17864
  function reconstructGeometry(reader, expressId, scale, voidedBy, diagnostics) {
17631
17865
  const base = toImportedGeometry(reader, expressId, scale, diagnostics);
17632
17866
  if (base.fidelity !== "PARAMETRIC" || base.completeness !== "COMPLETE" || voidedBy.length === 0) return base;
17633
- const firstHost = base.solids[0];
17634
- if (firstHost === void 0) return base;
17635
- const hosts = [firstHost, ...base.solids.slice(1)];
17636
- for (const openingId of voidedBy) {
17637
- const opening = readBodyGeometry(reader, openingId, scale, diagnostics);
17638
- if (opening.kind !== "SOLID") continue;
17639
- try {
17640
- for (let hostIndex = 0; hostIndex < hosts.length; hostIndex++) {
17867
+ if (base.solids[0] === void 0) return base;
17868
+ const hosts = [...base.solids];
17869
+ try {
17870
+ for (const openingId of voidedBy) try {
17871
+ var _usingCtx$1 = _usingCtx();
17872
+ const opening = readBodyGeometry(reader, openingId, scale, diagnostics);
17873
+ if (opening.kind !== "SOLID") continue;
17874
+ const openingOwner = _usingCtx$1.u(ownOpening(opening.solid, openingId));
17875
+ for (let hostIndex = 0; hostIndex < hosts.length;) {
17641
17876
  const host = hosts[hostIndex];
17642
- if (host === void 0) continue;
17643
- const cutResult = (0, brepjs.cut)(host, opening.solid);
17877
+ if (host === void 0) break;
17878
+ const cutResult = cutImportedSolids(host, openingOwner.solid);
17644
17879
  if (!cutResult.ok) {
17645
- diagnostics.push(issue("warning", "VOID_SUBTRACTION_FAILED", `Opening ${openingId} could not be subtracted from element ${expressId}: ${cutResult.error.message}`, expressId));
17880
+ diagnostics.push(issue("warning", "VOID_SUBTRACTION_FAILED", `Opening ${openingId} could not be subtracted from element ${expressId}: ${cutResult.error.message}`, expressId, { cause: cutResult.error }));
17881
+ hostIndex++;
17646
17882
  continue;
17647
17883
  }
17648
- host[Symbol.dispose]();
17649
- hosts[hostIndex] = cutResult.value;
17884
+ hosts.splice(hostIndex, 1, ...cutResult.value);
17885
+ const cleanup = cleanupOwnedResources([{
17886
+ resource: host,
17887
+ itemIndex: hostIndex
17888
+ }], { operation: "importOpening" });
17889
+ if (cleanup.kind === "FAILED") diagnostics.push(issue("warning", "VOID_HOST_CLEANUP_FAILED", "Opening result retained, but previous host release failed", expressId, { cleanup }));
17890
+ hostIndex += cutResult.value.length;
17650
17891
  }
17892
+ } catch (_) {
17893
+ _usingCtx$1.e = _;
17651
17894
  } finally {
17652
- opening.solid[Symbol.dispose]();
17895
+ _usingCtx$1.d();
17653
17896
  }
17897
+ return completeImportedGeometry("PARAMETRIC", hosts, expressId, diagnostics);
17898
+ } catch (cause) {
17899
+ const failure = importError("GEOMETRY_RECONSTRUCTION_FAILED", "Opening reconstruction failed", cause);
17900
+ const cleanup = cleanupOwnedResources(hosts.map((resource, itemIndex) => ({
17901
+ resource,
17902
+ itemIndex
17903
+ })), { operation: "reconstructGeometry" });
17904
+ throw Object.assign(new Error(failure.message, { cause }), {
17905
+ code: failure.code,
17906
+ metadata: withCleanup(failure, cleanup, "reconstructGeometry").metadata
17907
+ });
17654
17908
  }
17655
- return completeImportedGeometry("PARAMETRIC", hosts, expressId, diagnostics);
17909
+ }
17910
+ function ownOpening(solid, openingId) {
17911
+ return {
17912
+ solid,
17913
+ [Symbol.dispose]() {
17914
+ const cleanup = cleanupOwnedResources([{
17915
+ resource: solid,
17916
+ itemIndex: 0
17917
+ }], { operation: "importOpeningTool" });
17918
+ if (cleanup.kind === "FAILED") throw new Error(`Opening ${openingId} cleanup failed`, { cause: {
17919
+ ...importError("OPENING_CLEANUP_FAILED", "Temporary opening release failed"),
17920
+ metadata: { cleanup }
17921
+ } });
17922
+ }
17923
+ };
17924
+ }
17925
+ function withCleanup(error, cleanup, operation) {
17926
+ return {
17927
+ ...error,
17928
+ metadata: {
17929
+ ...error.metadata,
17930
+ cleanup: cleanupReport([...reportedGeometryCleanup(error, operation), ...cleanup.kind === "FAILED" ? cleanup.diagnostics : []])
17931
+ }
17932
+ };
17656
17933
  }
17657
17934
  function toImportedGeometry(reader, expressId, scale, diagnostics) {
17658
17935
  const body = readBodyItems(reader, expressId, scale, diagnostics);
@@ -17700,61 +17977,48 @@ function completeImportedGeometry(fidelity, solids, expressId, diagnostics) {
17700
17977
  fidelity,
17701
17978
  completeness: "COMPLETE",
17702
17979
  solids,
17703
- solid: solids.length === 1 ? solids[0] : null,
17980
+ solid: solids.length === 1 ? solids[0] ?? null : null,
17704
17981
  ...measureCompleteBody(solids, expressId, diagnostics)
17705
17982
  };
17706
17983
  }
17707
17984
  function measureCompleteBody(solids, expressId, diagnostics) {
17985
+ const unavailable = (cause, message = errMsg(cause)) => {
17986
+ diagnostics.push(issue("warning", "BODY_AGGREGATE_MEASUREMENT_FAILED", `Complete Body aggregate measurement failed: ${message}`, expressId, { cause }));
17987
+ return {
17988
+ bounds: null,
17989
+ volumeMm3: null
17990
+ };
17991
+ };
17708
17992
  try {
17709
- const first = solids[0];
17993
+ const [first, ...rest] = solids;
17710
17994
  if (first === void 0) return {
17711
17995
  bounds: null,
17712
17996
  volumeMm3: null
17713
17997
  };
17714
- const initial = (0, brepjs.getBounds)(first);
17715
- let xMin = initial.xMin;
17716
- let xMax = initial.xMax;
17717
- let yMin = initial.yMin;
17718
- let yMax = initial.yMax;
17719
- let zMin = initial.zMin;
17720
- let zMax = initial.zMax;
17721
- let volumeMm3 = 0;
17722
- for (const solid of solids) {
17723
- const measured = (0, brepjs.measureVolume)(solid);
17724
- if (!measured.ok) throw new Error(measured.error.message);
17725
- volumeMm3 += measured.value;
17726
- const itemBounds = (0, brepjs.getBounds)(solid);
17727
- xMin = Math.min(xMin, itemBounds.xMin);
17728
- xMax = Math.max(xMax, itemBounds.xMax);
17729
- yMin = Math.min(yMin, itemBounds.yMin);
17730
- yMax = Math.max(yMax, itemBounds.yMax);
17731
- zMin = Math.min(zMin, itemBounds.zMin);
17732
- zMax = Math.max(zMax, itemBounds.zMax);
17733
- }
17998
+ const items = [first, ...rest];
17999
+ const bounds = productBodyBounds(items);
18000
+ if (!bounds.ok) return unavailable(bounds.error, bounds.error.message);
18001
+ const volume = measureProductBodyMaterial(items);
18002
+ if (!volume.ok) return unavailable(volume.error, volume.error.message);
17734
18003
  return {
17735
- bounds: {
17736
- xMin,
17737
- xMax,
17738
- yMin,
17739
- yMax,
17740
- zMin,
17741
- zMax
17742
- },
17743
- volumeMm3
18004
+ bounds: bounds.value.bounds,
18005
+ volumeMm3: volume.value
17744
18006
  };
17745
18007
  } catch (cause) {
17746
- diagnostics.push(issue("warning", "BODY_AGGREGATE_MEASUREMENT_FAILED", `Complete Body aggregate measurement failed: ${errMsg(cause)}`, expressId));
17747
- return {
17748
- bounds: null,
17749
- volumeMm3: null
17750
- };
18008
+ return unavailable(cause);
17751
18009
  }
17752
18010
  }
17753
18011
  function disposeGeometry(geometry) {
17754
- for (const solid of geometry.solids) solid[Symbol.dispose]();
18012
+ return cleanupOwnedResources(geometry.solids.map((resource, itemIndex) => ({
18013
+ resource,
18014
+ itemIndex
18015
+ })), { operation: "disposeImportedGeometry" });
17755
18016
  }
17756
18017
  function disposeElements(elements) {
17757
- for (const element of elements) disposeGeometry(element.geometry);
18018
+ return cleanupOwnedResources(elements.flatMap(({ geometry }) => geometry.solids).map((resource, itemIndex) => ({
18019
+ resource,
18020
+ itemIndex
18021
+ })), { operation: "disposeImportedElements" });
17758
18022
  }
17759
18023
  function toImportedPset(pset) {
17760
18024
  return {