brepjs-bim 0.16.1 → 0.17.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/README.md CHANGED
@@ -23,7 +23,8 @@ curtain walls, a panel/mullion grid). Element geometry is **unplaced template ge
23
23
  coordinates — placement (`origin` / `axisX` / `axisZ`) is applied by the IFC layer via
24
24
  `IfcLocalPlacement`, not baked into the brepjs solid. Use `placedSolids(element)` to read an
25
25
  element's geometry already transformed to its world placement as fresh, caller-owned solids
26
- (stairs return one solid per flight) handy for display so the on-screen scene matches the IFC
26
+ (stairs and ramps return one solid per flight, curtain walls their panels and mullions) handy
27
+ for display so the on-screen scene matches the IFC
27
28
  export.
28
29
 
29
30
  - Units default to mm; IFC export emits SI metres.
@@ -35,18 +36,18 @@ export.
35
36
 
36
37
  ## Status
37
38
 
38
- | Area | State |
39
- | ----------------- | -------------------------------------------------------------------------------------------------------- |
40
- | Elements | wall, slab, beam, column, roof, curtain wall, space, footing/pile, stair, ramp, railing, covering, proxy |
41
- | Profiles | rectangular / circular / I-shape cores + extended L/T/U/Z/C, hollow, ellipse, arbitrary-with-voids |
42
- | Openings | door / window / slab openings cut as boolean voids; `FillsOpening` / `Voids*` relationships |
43
- | Spatial structure | project → site → building → storey aggregation; `placeIn` to assign elements to a storey |
44
- | Property sets | IFC pset templates + measure types; quantity sets for takeoff |
45
- | Data layers | materials (layer/profile/simple sets), classification refs, surface styles, zones/systems |
46
- | IFC export | `toIfc` → IFC-SPF (`Uint8Array`); IFC4 / IFC4X3 schema selection; owner history |
47
- | IFC import | `fromIfc` / `SpfReader` → `ImportedModel` (elements, geometry, psets, materials, spatial tree) |
48
- | Validation | referential integrity, schema check, geometry validity, IFC round-trip report |
49
- | Interop | COBie 2.4 export (CSV/JSON), IDS 1.0 checking, BCF 3.0 read/write |
39
+ | Area | State |
40
+ | ----------------- | ---------------------------------------------------------------------------------------------------------- |
41
+ | Elements | wall, slab, beam, column, roof, curtain wall, space, footing/pile, stair, ramp, railing, covering, proxy |
42
+ | Profiles | rectangular / circular / I-shape cores + extended L/T/U/Z/C, hollow, ellipse, arbitrary-with-voids |
43
+ | Openings | door / window / slab openings cut as boolean voids; `FillsOpening` / `Voids*` relationships |
44
+ | Spatial structure | project → site → building → storey aggregation; `placeIn` to assign elements to a storey |
45
+ | Property sets | IFC pset templates + measure types; quantity sets for takeoff |
46
+ | Data layers | materials (layer/profile/simple sets), classification refs, surface styles, zones/systems |
47
+ | IFC export | `toIfc` → IFC-SPF (`Uint8Array`); IFC4 / IFC4X3 schema selection; owner history |
48
+ | IFC import | `fromIfc` / `SpfReader` → `ImportedModel` (elements, geometry, psets, materials, spatial tree) |
49
+ | Validation | referential integrity, schema check, geometry validity, IFC round-trip report, buildingSMART gherkin rules |
50
+ | Interop | COBie 2.4 export (CSV/JSON), IDS 1.0 checking, BCF 3.0 read/write |
50
51
 
51
52
  ### Independent validation
52
53
 
@@ -56,9 +57,13 @@ web-ifc parser used internally), not just self-checked. The committed sample
56
57
  validator and generates geometry for every product. See [VALIDATION.md](./VALIDATION.md)
57
58
  to reproduce, and `examples/sampleBuilding.mjs` for the model it validates.
58
59
 
59
- > **Not yet:** the official buildingSMART Validation Service and desktop-tool
60
- > interop (Revit / Solibri) are unverified the fixtures and per-tool
61
- > checklists are ready in [VALIDATION.md](./VALIDATION.md). This is an
60
+ The buildingSMART Validation Service's complete normative rule catalog also runs
61
+ locally (`scripts/setupGherkinRunner.sh` builds the service's own engine; all three
62
+ committed fixtures pass 950 scenarios with zero failures), so service findings are
63
+ reproducible before upload.
64
+
65
+ > **Not yet:** desktop-tool interop (Revit / Solibri) is unverified. The fixtures
66
+ > and per-tool checklists are ready in [VALIDATION.md](./VALIDATION.md). This is an
62
67
  > experimental pre-1.0 package and the API may change.
63
68
 
64
69
  ## Usage
@@ -98,7 +103,7 @@ if (wall.ok) model.placeIn(wall.value, storeyId);
98
103
  const solid = model.getWalls()[0]?.geometry;
99
104
 
100
105
  // Serialize to an IFC-SPF byte buffer.
101
- const ifc = await toIfc(model, { name: 'Example', author: 'brepjs-bim' });
106
+ const ifc = await toIfc(model, { applicationName: 'brepjs-bim', applicationVersion: '1.0' });
102
107
  // ifc.ok && ifc.value instanceof Uint8Array
103
108
  ```
104
109
 
@@ -7314,6 +7314,65 @@ function stairFlightToSolid(spec) {
7314
7314
  }
7315
7315
  }
7316
7316
  //#endregion
7317
+ //#region src/elementFns/rampFns.ts
7318
+ function buildSilhouette(length, rise, thickness) {
7319
+ return [
7320
+ [
7321
+ 0,
7322
+ 0,
7323
+ -thickness
7324
+ ],
7325
+ [
7326
+ length,
7327
+ 0,
7328
+ rise - thickness
7329
+ ],
7330
+ [
7331
+ length,
7332
+ 0,
7333
+ rise
7334
+ ],
7335
+ [
7336
+ 0,
7337
+ 0,
7338
+ 0
7339
+ ]
7340
+ ];
7341
+ }
7342
+ function rampFlightToSolid(spec) {
7343
+ try {
7344
+ var _usingCtx$4 = _usingCtx();
7345
+ if (spec.width <= 0) return (0, brepjs.err)(specError("RAMP_FLIGHT_ZERO_WIDTH", "Ramp flight width must be positive"));
7346
+ if (spec.length <= 0) return (0, brepjs.err)(specError("RAMP_FLIGHT_ZERO_LENGTH", "Ramp flight length must be positive"));
7347
+ if (spec.slope <= 0) return (0, brepjs.err)(specError("RAMP_FLIGHT_ZERO_SLOPE", "Ramp flight slope must be positive"));
7348
+ if (spec.thickness <= 0) return (0, brepjs.err)(specError("RAMP_FLIGHT_ZERO_THICKNESS", "Ramp flight thickness must be positive"));
7349
+ const rise = spec.length * spec.slope;
7350
+ const silhouette = buildSilhouette(spec.length, rise, spec.thickness);
7351
+ const profileResult = (0, brepjs.polygon)(silhouette);
7352
+ if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "RAMP_FLIGHT_PROFILE_FAILED", "Failed to create ramp flight silhouette profile"));
7353
+ const profile = _usingCtx$4.u(profileResult.value);
7354
+ const solidResult = (0, brepjs.extrude)(profile, [
7355
+ 0,
7356
+ spec.width,
7357
+ 0
7358
+ ]);
7359
+ if (!solidResult.ok) return (0, brepjs.err)(fromBrepError(solidResult.error, "RAMP_FLIGHT_EXTRUDE_FAILED", "Failed to extrude ramp flight silhouette"));
7360
+ const solid = solidResult.value;
7361
+ if (!(0, brepjs.isValidSolid)(solid)) {
7362
+ solid[Symbol.dispose]();
7363
+ return (0, brepjs.err)(geometryError("RAMP_FLIGHT_INVALID_SOLID", "Ramp flight solid failed validity check"));
7364
+ }
7365
+ return (0, brepjs.ok)({
7366
+ solid,
7367
+ geometrySimplified: true
7368
+ });
7369
+ } catch (_) {
7370
+ _usingCtx$4.e = _;
7371
+ } finally {
7372
+ _usingCtx$4.d();
7373
+ }
7374
+ }
7375
+ //#endregion
7317
7376
  //#region src/elementFns/placedGeometry.ts
7318
7377
  function place(solid, frame) {
7319
7378
  const result = (0, brepjs.applyMatrix)(solid, placementToMatrix(frame));
@@ -7332,10 +7391,10 @@ function disposeAll(solids) {
7332
7391
  * failure the solids already built for this call are disposed before the error is
7333
7392
  * returned, so no partial array is leaked.
7334
7393
  *
7335
- * Stairs carry no element solid (`.geometry` is null), so flight solids are built
7336
- * from `spec.flights` and placed per flight. Curtain walls return placed panels +
7337
- * mullions. Elements with no solid geometry (doors/windows/ramps/groups/spatial)
7338
- * return an empty array.
7394
+ * Stairs and ramps carry no element solid (`.geometry` is null), so flight
7395
+ * solids are built from `spec.flights` and placed per flight. Curtain walls
7396
+ * return placed panels + mullions. Elements with no solid geometry
7397
+ * (doors/windows/groups/spatial) return an empty array.
7339
7398
  */
7340
7399
  function placedSolids(el) {
7341
7400
  switch (el.category) {
@@ -7347,6 +7406,7 @@ function placedSolids(el) {
7347
7406
  case "ROOF":
7348
7407
  case "FOOTING":
7349
7408
  case "PILE":
7409
+ case "COVERING":
7350
7410
  case "RAILING": {
7351
7411
  const placed = place(el.geometry, el.spec);
7352
7412
  if (!placed.ok) return placed;
@@ -7355,29 +7415,51 @@ function placedSolids(el) {
7355
7415
  case "STAIR": {
7356
7416
  const out = [];
7357
7417
  for (const flight of el.spec.flights) try {
7358
- var _usingCtx$4 = _usingCtx();
7418
+ var _usingCtx$3 = _usingCtx();
7359
7419
  const built = stairFlightToSolid(flight);
7360
7420
  if (!built.ok) {
7361
7421
  disposeAll(out);
7362
7422
  return (0, brepjs.err)(built.error);
7363
7423
  }
7364
- const placed = place(_usingCtx$4.u(built.value.solid), flight);
7424
+ const placed = place(_usingCtx$3.u(built.value.solid), flight);
7425
+ if (!placed.ok) {
7426
+ disposeAll(out);
7427
+ return placed;
7428
+ }
7429
+ out.push(placed.value);
7430
+ } catch (_) {
7431
+ _usingCtx$3.e = _;
7432
+ } finally {
7433
+ _usingCtx$3.d();
7434
+ }
7435
+ return (0, brepjs.ok)(out);
7436
+ }
7437
+ case "RAMP": {
7438
+ const out = [];
7439
+ for (const flight of el.spec.flights) try {
7440
+ var _usingCtx3 = _usingCtx();
7441
+ const built = rampFlightToSolid(flight);
7442
+ if (!built.ok) {
7443
+ disposeAll(out);
7444
+ return (0, brepjs.err)(built.error);
7445
+ }
7446
+ const placed = place(_usingCtx3.u(built.value.solid), flight);
7365
7447
  if (!placed.ok) {
7366
7448
  disposeAll(out);
7367
7449
  return placed;
7368
7450
  }
7369
7451
  out.push(placed.value);
7370
7452
  } catch (_) {
7371
- _usingCtx$4.e = _;
7453
+ _usingCtx3.e = _;
7372
7454
  } finally {
7373
- _usingCtx$4.d();
7455
+ _usingCtx3.d();
7374
7456
  }
7375
7457
  return (0, brepjs.ok)(out);
7376
7458
  }
7377
7459
  case "CURTAIN_WALL": {
7378
7460
  const out = [];
7379
7461
  for (const c of [...el.geometry.panels, ...el.geometry.mullions]) try {
7380
- var _usingCtx3 = _usingCtx();
7462
+ var _usingCtx4 = _usingCtx();
7381
7463
  const componentLocal = place(c.solid, {
7382
7464
  origin: c.origin,
7383
7465
  axisX: [
@@ -7395,16 +7477,16 @@ function placedSolids(el) {
7395
7477
  disposeAll(out);
7396
7478
  return componentLocal;
7397
7479
  }
7398
- const placed = place(_usingCtx3.u(componentLocal.value), el.spec);
7480
+ const placed = place(_usingCtx4.u(componentLocal.value), el.spec);
7399
7481
  if (!placed.ok) {
7400
7482
  disposeAll(out);
7401
7483
  return placed;
7402
7484
  }
7403
7485
  out.push(placed.value);
7404
7486
  } catch (_) {
7405
- _usingCtx3.e = _;
7487
+ _usingCtx4.e = _;
7406
7488
  } finally {
7407
- _usingCtx3.d();
7489
+ _usingCtx4.d();
7408
7490
  }
7409
7491
  return (0, brepjs.ok)(out);
7410
7492
  }
@@ -9491,65 +9573,6 @@ function writeRelContainedInSpatialStructure(w, guid, ownerHistoryId, relatingSt
9491
9573
  });
9492
9574
  }
9493
9575
  //#endregion
9494
- //#region src/elementFns/rampFns.ts
9495
- function buildSilhouette(length, rise, thickness) {
9496
- return [
9497
- [
9498
- 0,
9499
- 0,
9500
- -thickness
9501
- ],
9502
- [
9503
- length,
9504
- 0,
9505
- rise - thickness
9506
- ],
9507
- [
9508
- length,
9509
- 0,
9510
- rise
9511
- ],
9512
- [
9513
- 0,
9514
- 0,
9515
- 0
9516
- ]
9517
- ];
9518
- }
9519
- function rampFlightToSolid(spec) {
9520
- try {
9521
- var _usingCtx$3 = _usingCtx();
9522
- if (spec.width <= 0) return (0, brepjs.err)(specError("RAMP_FLIGHT_ZERO_WIDTH", "Ramp flight width must be positive"));
9523
- if (spec.length <= 0) return (0, brepjs.err)(specError("RAMP_FLIGHT_ZERO_LENGTH", "Ramp flight length must be positive"));
9524
- if (spec.slope <= 0) return (0, brepjs.err)(specError("RAMP_FLIGHT_ZERO_SLOPE", "Ramp flight slope must be positive"));
9525
- if (spec.thickness <= 0) return (0, brepjs.err)(specError("RAMP_FLIGHT_ZERO_THICKNESS", "Ramp flight thickness must be positive"));
9526
- const rise = spec.length * spec.slope;
9527
- const silhouette = buildSilhouette(spec.length, rise, spec.thickness);
9528
- const profileResult = (0, brepjs.polygon)(silhouette);
9529
- if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "RAMP_FLIGHT_PROFILE_FAILED", "Failed to create ramp flight silhouette profile"));
9530
- const profile = _usingCtx$3.u(profileResult.value);
9531
- const solidResult = (0, brepjs.extrude)(profile, [
9532
- 0,
9533
- spec.width,
9534
- 0
9535
- ]);
9536
- if (!solidResult.ok) return (0, brepjs.err)(fromBrepError(solidResult.error, "RAMP_FLIGHT_EXTRUDE_FAILED", "Failed to extrude ramp flight silhouette"));
9537
- const solid = solidResult.value;
9538
- if (!(0, brepjs.isValidSolid)(solid)) {
9539
- solid[Symbol.dispose]();
9540
- return (0, brepjs.err)(geometryError("RAMP_FLIGHT_INVALID_SOLID", "Ramp flight solid failed validity check"));
9541
- }
9542
- return (0, brepjs.ok)({
9543
- solid,
9544
- geometrySimplified: true
9545
- });
9546
- } catch (_) {
9547
- _usingCtx$3.e = _;
9548
- } finally {
9549
- _usingCtx$3.d();
9550
- }
9551
- }
9552
- //#endregion
9553
9576
  //#region src/ifc-writer/stairWriter.ts
9554
9577
  function writeLocalPlacement(w, origin, axisZ, axisX, parentPlacementId) {
9555
9578
  const placement3DId = writeAxis2Placement3D(w, origin.map(toIfcLengthM), axisZ, axisX);
@@ -7291,6 +7291,65 @@ function stairFlightToSolid(spec) {
7291
7291
  }
7292
7292
  }
7293
7293
  //#endregion
7294
+ //#region src/elementFns/rampFns.ts
7295
+ function buildSilhouette(length, rise, thickness) {
7296
+ return [
7297
+ [
7298
+ 0,
7299
+ 0,
7300
+ -thickness
7301
+ ],
7302
+ [
7303
+ length,
7304
+ 0,
7305
+ rise - thickness
7306
+ ],
7307
+ [
7308
+ length,
7309
+ 0,
7310
+ rise
7311
+ ],
7312
+ [
7313
+ 0,
7314
+ 0,
7315
+ 0
7316
+ ]
7317
+ ];
7318
+ }
7319
+ function rampFlightToSolid(spec) {
7320
+ try {
7321
+ var _usingCtx$4 = _usingCtx();
7322
+ if (spec.width <= 0) return err(specError("RAMP_FLIGHT_ZERO_WIDTH", "Ramp flight width must be positive"));
7323
+ if (spec.length <= 0) return err(specError("RAMP_FLIGHT_ZERO_LENGTH", "Ramp flight length must be positive"));
7324
+ if (spec.slope <= 0) return err(specError("RAMP_FLIGHT_ZERO_SLOPE", "Ramp flight slope must be positive"));
7325
+ if (spec.thickness <= 0) return err(specError("RAMP_FLIGHT_ZERO_THICKNESS", "Ramp flight thickness must be positive"));
7326
+ const rise = spec.length * spec.slope;
7327
+ const silhouette = buildSilhouette(spec.length, rise, spec.thickness);
7328
+ const profileResult = polygon(silhouette);
7329
+ if (!profileResult.ok) return err(fromBrepError(profileResult.error, "RAMP_FLIGHT_PROFILE_FAILED", "Failed to create ramp flight silhouette profile"));
7330
+ const profile = _usingCtx$4.u(profileResult.value);
7331
+ const solidResult = extrude(profile, [
7332
+ 0,
7333
+ spec.width,
7334
+ 0
7335
+ ]);
7336
+ if (!solidResult.ok) return err(fromBrepError(solidResult.error, "RAMP_FLIGHT_EXTRUDE_FAILED", "Failed to extrude ramp flight silhouette"));
7337
+ const solid = solidResult.value;
7338
+ if (!isValidSolid(solid)) {
7339
+ solid[Symbol.dispose]();
7340
+ return err(geometryError("RAMP_FLIGHT_INVALID_SOLID", "Ramp flight solid failed validity check"));
7341
+ }
7342
+ return ok({
7343
+ solid,
7344
+ geometrySimplified: true
7345
+ });
7346
+ } catch (_) {
7347
+ _usingCtx$4.e = _;
7348
+ } finally {
7349
+ _usingCtx$4.d();
7350
+ }
7351
+ }
7352
+ //#endregion
7294
7353
  //#region src/elementFns/placedGeometry.ts
7295
7354
  function place(solid, frame) {
7296
7355
  const result = applyMatrix(solid, placementToMatrix(frame));
@@ -7309,10 +7368,10 @@ function disposeAll(solids) {
7309
7368
  * failure the solids already built for this call are disposed before the error is
7310
7369
  * returned, so no partial array is leaked.
7311
7370
  *
7312
- * Stairs carry no element solid (`.geometry` is null), so flight solids are built
7313
- * from `spec.flights` and placed per flight. Curtain walls return placed panels +
7314
- * mullions. Elements with no solid geometry (doors/windows/ramps/groups/spatial)
7315
- * return an empty array.
7371
+ * Stairs and ramps carry no element solid (`.geometry` is null), so flight
7372
+ * solids are built from `spec.flights` and placed per flight. Curtain walls
7373
+ * return placed panels + mullions. Elements with no solid geometry
7374
+ * (doors/windows/groups/spatial) return an empty array.
7316
7375
  */
7317
7376
  function placedSolids(el) {
7318
7377
  switch (el.category) {
@@ -7324,6 +7383,7 @@ function placedSolids(el) {
7324
7383
  case "ROOF":
7325
7384
  case "FOOTING":
7326
7385
  case "PILE":
7386
+ case "COVERING":
7327
7387
  case "RAILING": {
7328
7388
  const placed = place(el.geometry, el.spec);
7329
7389
  if (!placed.ok) return placed;
@@ -7332,29 +7392,51 @@ function placedSolids(el) {
7332
7392
  case "STAIR": {
7333
7393
  const out = [];
7334
7394
  for (const flight of el.spec.flights) try {
7335
- var _usingCtx$4 = _usingCtx();
7395
+ var _usingCtx$3 = _usingCtx();
7336
7396
  const built = stairFlightToSolid(flight);
7337
7397
  if (!built.ok) {
7338
7398
  disposeAll(out);
7339
7399
  return err(built.error);
7340
7400
  }
7341
- const placed = place(_usingCtx$4.u(built.value.solid), flight);
7401
+ const placed = place(_usingCtx$3.u(built.value.solid), flight);
7402
+ if (!placed.ok) {
7403
+ disposeAll(out);
7404
+ return placed;
7405
+ }
7406
+ out.push(placed.value);
7407
+ } catch (_) {
7408
+ _usingCtx$3.e = _;
7409
+ } finally {
7410
+ _usingCtx$3.d();
7411
+ }
7412
+ return ok(out);
7413
+ }
7414
+ case "RAMP": {
7415
+ const out = [];
7416
+ for (const flight of el.spec.flights) try {
7417
+ var _usingCtx3 = _usingCtx();
7418
+ const built = rampFlightToSolid(flight);
7419
+ if (!built.ok) {
7420
+ disposeAll(out);
7421
+ return err(built.error);
7422
+ }
7423
+ const placed = place(_usingCtx3.u(built.value.solid), flight);
7342
7424
  if (!placed.ok) {
7343
7425
  disposeAll(out);
7344
7426
  return placed;
7345
7427
  }
7346
7428
  out.push(placed.value);
7347
7429
  } catch (_) {
7348
- _usingCtx$4.e = _;
7430
+ _usingCtx3.e = _;
7349
7431
  } finally {
7350
- _usingCtx$4.d();
7432
+ _usingCtx3.d();
7351
7433
  }
7352
7434
  return ok(out);
7353
7435
  }
7354
7436
  case "CURTAIN_WALL": {
7355
7437
  const out = [];
7356
7438
  for (const c of [...el.geometry.panels, ...el.geometry.mullions]) try {
7357
- var _usingCtx3 = _usingCtx();
7439
+ var _usingCtx4 = _usingCtx();
7358
7440
  const componentLocal = place(c.solid, {
7359
7441
  origin: c.origin,
7360
7442
  axisX: [
@@ -7372,16 +7454,16 @@ function placedSolids(el) {
7372
7454
  disposeAll(out);
7373
7455
  return componentLocal;
7374
7456
  }
7375
- const placed = place(_usingCtx3.u(componentLocal.value), el.spec);
7457
+ const placed = place(_usingCtx4.u(componentLocal.value), el.spec);
7376
7458
  if (!placed.ok) {
7377
7459
  disposeAll(out);
7378
7460
  return placed;
7379
7461
  }
7380
7462
  out.push(placed.value);
7381
7463
  } catch (_) {
7382
- _usingCtx3.e = _;
7464
+ _usingCtx4.e = _;
7383
7465
  } finally {
7384
- _usingCtx3.d();
7466
+ _usingCtx4.d();
7385
7467
  }
7386
7468
  return ok(out);
7387
7469
  }
@@ -9468,65 +9550,6 @@ function writeRelContainedInSpatialStructure(w, guid, ownerHistoryId, relatingSt
9468
9550
  });
9469
9551
  }
9470
9552
  //#endregion
9471
- //#region src/elementFns/rampFns.ts
9472
- function buildSilhouette(length, rise, thickness) {
9473
- return [
9474
- [
9475
- 0,
9476
- 0,
9477
- -thickness
9478
- ],
9479
- [
9480
- length,
9481
- 0,
9482
- rise - thickness
9483
- ],
9484
- [
9485
- length,
9486
- 0,
9487
- rise
9488
- ],
9489
- [
9490
- 0,
9491
- 0,
9492
- 0
9493
- ]
9494
- ];
9495
- }
9496
- function rampFlightToSolid(spec) {
9497
- try {
9498
- var _usingCtx$3 = _usingCtx();
9499
- if (spec.width <= 0) return err(specError("RAMP_FLIGHT_ZERO_WIDTH", "Ramp flight width must be positive"));
9500
- if (spec.length <= 0) return err(specError("RAMP_FLIGHT_ZERO_LENGTH", "Ramp flight length must be positive"));
9501
- if (spec.slope <= 0) return err(specError("RAMP_FLIGHT_ZERO_SLOPE", "Ramp flight slope must be positive"));
9502
- if (spec.thickness <= 0) return err(specError("RAMP_FLIGHT_ZERO_THICKNESS", "Ramp flight thickness must be positive"));
9503
- const rise = spec.length * spec.slope;
9504
- const silhouette = buildSilhouette(spec.length, rise, spec.thickness);
9505
- const profileResult = polygon(silhouette);
9506
- if (!profileResult.ok) return err(fromBrepError(profileResult.error, "RAMP_FLIGHT_PROFILE_FAILED", "Failed to create ramp flight silhouette profile"));
9507
- const profile = _usingCtx$3.u(profileResult.value);
9508
- const solidResult = extrude(profile, [
9509
- 0,
9510
- spec.width,
9511
- 0
9512
- ]);
9513
- if (!solidResult.ok) return err(fromBrepError(solidResult.error, "RAMP_FLIGHT_EXTRUDE_FAILED", "Failed to extrude ramp flight silhouette"));
9514
- const solid = solidResult.value;
9515
- if (!isValidSolid(solid)) {
9516
- solid[Symbol.dispose]();
9517
- return err(geometryError("RAMP_FLIGHT_INVALID_SOLID", "Ramp flight solid failed validity check"));
9518
- }
9519
- return ok({
9520
- solid,
9521
- geometrySimplified: true
9522
- });
9523
- } catch (_) {
9524
- _usingCtx$3.e = _;
9525
- } finally {
9526
- _usingCtx$3.d();
9527
- }
9528
- }
9529
- //#endregion
9530
9553
  //#region src/ifc-writer/stairWriter.ts
9531
9554
  function writeLocalPlacement(w, origin, axisZ, axisX, parentPlacementId) {
9532
9555
  const placement3DId = writeAxis2Placement3D(w, origin.map(toIfcLengthM), axisZ, axisX);
@@ -10,9 +10,9 @@ import { BimError } from '../errors/bimError.js';
10
10
  * failure the solids already built for this call are disposed before the error is
11
11
  * returned, so no partial array is leaked.
12
12
  *
13
- * Stairs carry no element solid (`.geometry` is null), so flight solids are built
14
- * from `spec.flights` and placed per flight. Curtain walls return placed panels +
15
- * mullions. Elements with no solid geometry (doors/windows/ramps/groups/spatial)
16
- * return an empty array.
13
+ * Stairs and ramps carry no element solid (`.geometry` is null), so flight
14
+ * solids are built from `spec.flights` and placed per flight. Curtain walls
15
+ * return placed panels + mullions. Elements with no solid geometry
16
+ * (doors/windows/groups/spatial) return an empty array.
17
17
  */
18
18
  export declare function placedSolids(el: AnyBimElement): Result<readonly ValidSolid[], BimError>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brepjs-bim",
3
- "version": "0.16.1",
3
+ "version": "0.17.0",
4
4
  "description": "BIM layer for brepjs — IFC4-aligned parametric building elements",
5
5
  "keywords": [
6
6
  "bim",