brepjs-bim 0.14.0 → 0.15.1
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 +4 -3
- package/dist/brepjs-bim.cjs +48 -20
- package/dist/brepjs-bim.js +48 -20
- package/dist/model/bimModel.d.ts +8 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -67,15 +67,16 @@ Author a small model and export IFC:
|
|
|
67
67
|
|
|
68
68
|
```ts
|
|
69
69
|
import { BimModel, toIfc } from 'brepjs-bim';
|
|
70
|
+
import { unwrap } from 'brepjs';
|
|
70
71
|
|
|
71
72
|
const model = new BimModel();
|
|
72
73
|
model.init({ name: 'Example' });
|
|
73
74
|
|
|
74
75
|
// Spatial structure: project → site → building → storey.
|
|
75
76
|
const project = model.getProject();
|
|
76
|
-
const siteId = model.addSite({ name: 'Site' });
|
|
77
|
-
const buildingId = model.addBuilding({ name: 'Building' });
|
|
78
|
-
const storeyId = model.addStorey({ name: 'Level 1', elevation: 0 });
|
|
77
|
+
const siteId = unwrap(model.addSite({ name: 'Site' }));
|
|
78
|
+
const buildingId = unwrap(model.addBuilding({ name: 'Building' }));
|
|
79
|
+
const storeyId = unwrap(model.addStorey({ name: 'Level 1', elevation: 0 }));
|
|
79
80
|
if (project) model.aggregate(project.localId, siteId);
|
|
80
81
|
model.aggregate(siteId, buildingId);
|
|
81
82
|
model.aggregate(buildingId, storeyId);
|
package/dist/brepjs-bim.cjs
CHANGED
|
@@ -6334,14 +6334,20 @@ var BimModel = class {
|
|
|
6334
6334
|
for (const mullion of el.geometry.mullions) mullion.solid[Symbol.dispose]();
|
|
6335
6335
|
}
|
|
6336
6336
|
}
|
|
6337
|
-
addSite(spec) {
|
|
6338
|
-
|
|
6337
|
+
addSite(spec, options) {
|
|
6338
|
+
const keyCheck = this.#checkStableKey(options);
|
|
6339
|
+
if (!keyCheck.ok) return keyCheck;
|
|
6340
|
+
return (0, brepjs.ok)(this.#makeElement("SITE", spec, null, options?.stableKey));
|
|
6339
6341
|
}
|
|
6340
6342
|
addBuilding(spec, options) {
|
|
6341
|
-
|
|
6343
|
+
const keyCheck = this.#checkStableKey(options);
|
|
6344
|
+
if (!keyCheck.ok) return keyCheck;
|
|
6345
|
+
return (0, brepjs.ok)(this.#makeElement("BUILDING", spec, null, options?.stableKey));
|
|
6342
6346
|
}
|
|
6343
6347
|
addStorey(spec, options) {
|
|
6344
|
-
|
|
6348
|
+
const keyCheck = this.#checkStableKey(options);
|
|
6349
|
+
if (!keyCheck.ok) return keyCheck;
|
|
6350
|
+
return (0, brepjs.ok)(this.#makeElement("STOREY", spec, null, options?.stableKey));
|
|
6345
6351
|
}
|
|
6346
6352
|
/** Reject a duplicate stableKey BEFORE any geometry is built, so the
|
|
6347
6353
|
* Result-returning adders never allocate a solid they cannot store. */
|
|
@@ -6508,24 +6514,30 @@ var BimModel = class {
|
|
|
6508
6514
|
* attach parts with {@link aggregate} (IfcRelAggregates) or {@link nest}
|
|
6509
6515
|
* (IfcRelNests, order-preserving). Returns the assembly's localId.
|
|
6510
6516
|
*/
|
|
6511
|
-
addElementAssembly(spec) {
|
|
6512
|
-
|
|
6517
|
+
addElementAssembly(spec, options) {
|
|
6518
|
+
const keyCheck = this.#checkStableKey(options);
|
|
6519
|
+
if (!keyCheck.ok) return keyCheck;
|
|
6520
|
+
return (0, brepjs.ok)(this.#makeElement("ELEMENT_ASSEMBLY", spec, null, options?.stableKey));
|
|
6513
6521
|
}
|
|
6514
6522
|
/**
|
|
6515
6523
|
* Adds an IfcZone grouping object (a thermal/fire/occupancy zone). The zone
|
|
6516
6524
|
* carries no geometry; attach members (spaces or other elements) with
|
|
6517
|
-
* {@link assignToGroup}. Returns the zone's localId.
|
|
6525
|
+
* {@link assignToGroup}. Returns the zone's localId as a Result.
|
|
6518
6526
|
*/
|
|
6519
|
-
addZone(spec) {
|
|
6520
|
-
|
|
6527
|
+
addZone(spec, options) {
|
|
6528
|
+
const keyCheck = this.#checkStableKey(options);
|
|
6529
|
+
if (!keyCheck.ok) return keyCheck;
|
|
6530
|
+
return (0, brepjs.ok)(this.#makeElement("ZONE", spec, null, options?.stableKey));
|
|
6521
6531
|
}
|
|
6522
6532
|
/**
|
|
6523
6533
|
* Adds an IfcSystem grouping object (an HVAC/electrical/plumbing system). The
|
|
6524
6534
|
* system carries no geometry; attach members with {@link assignToGroup}.
|
|
6525
|
-
* Returns the system's localId.
|
|
6535
|
+
* Returns the system's localId as a Result.
|
|
6526
6536
|
*/
|
|
6527
|
-
addSystem(spec) {
|
|
6528
|
-
|
|
6537
|
+
addSystem(spec, options) {
|
|
6538
|
+
const keyCheck = this.#checkStableKey(options);
|
|
6539
|
+
if (!keyCheck.ok) return keyCheck;
|
|
6540
|
+
return (0, brepjs.ok)(this.#makeElement("SYSTEM", spec, null, options?.stableKey));
|
|
6529
6541
|
}
|
|
6530
6542
|
/**
|
|
6531
6543
|
* Assigns members to a zone or system via IfcRelAssignsToGroup. Repeated calls
|
|
@@ -7496,6 +7508,12 @@ var FILE_NAME_RE = /(FILE_NAME\('[^']*','[^']*',)(?:\$|\(\$\)),(?:\$|\(\$\)),('[
|
|
|
7496
7508
|
function stepString(value) {
|
|
7497
7509
|
return `'${value.replace(/'/g, "''")}'`;
|
|
7498
7510
|
}
|
|
7511
|
+
var STRING_OR_BARE_REAL_RE = /'(?:[^']|'')*'|(?<![\d.])(-?\d+)E([+-]?\d+)/g;
|
|
7512
|
+
function normalizeStepReals(bytes) {
|
|
7513
|
+
const text = new TextDecoder().decode(bytes);
|
|
7514
|
+
const fixed = text.replace(STRING_OR_BARE_REAL_RE, (match, mantissa, exponent) => mantissa === void 0 || exponent === void 0 ? match : `${mantissa}.E${exponent}`);
|
|
7515
|
+
return fixed === text ? bytes : new TextEncoder().encode(fixed);
|
|
7516
|
+
}
|
|
7499
7517
|
var IfcWriter = class IfcWriter {
|
|
7500
7518
|
#api;
|
|
7501
7519
|
#modelId;
|
|
@@ -7551,7 +7569,7 @@ var IfcWriter = class IfcWriter {
|
|
|
7551
7569
|
if (this.#closed) return (0, brepjs.err)(ifcError("IFC_ALREADY_SAVED", "Model has already been saved and closed"));
|
|
7552
7570
|
try {
|
|
7553
7571
|
const bytes = this.#api.SaveModel(this.#modelId);
|
|
7554
|
-
return (0, brepjs.ok)(this.#patchHeader(bytes));
|
|
7572
|
+
return (0, brepjs.ok)(normalizeStepReals(this.#patchHeader(bytes)));
|
|
7555
7573
|
} catch (e) {
|
|
7556
7574
|
return (0, brepjs.err)(ifcError("IFC_SAVE_FAILED", "Failed to serialize IFC model", e));
|
|
7557
7575
|
} finally {
|
|
@@ -16747,9 +16765,18 @@ function familiesToBim(root, options) {
|
|
|
16747
16765
|
const model = new BimModel();
|
|
16748
16766
|
const initResult = model.init(options.project);
|
|
16749
16767
|
if (!initResult.ok) return initResult;
|
|
16750
|
-
const
|
|
16751
|
-
|
|
16752
|
-
|
|
16768
|
+
const siteResult = model.addSite({ name: options.siteName ?? "Site" });
|
|
16769
|
+
if (!siteResult.ok) {
|
|
16770
|
+
model[Symbol.dispose]();
|
|
16771
|
+
return siteResult;
|
|
16772
|
+
}
|
|
16773
|
+
const buildingResult = model.addBuilding({ name: options.buildingName ?? "Building" });
|
|
16774
|
+
if (!buildingResult.ok) {
|
|
16775
|
+
model[Symbol.dispose]();
|
|
16776
|
+
return buildingResult;
|
|
16777
|
+
}
|
|
16778
|
+
const buildingId = buildingResult.value;
|
|
16779
|
+
model.aggregate(siteResult.value, buildingId);
|
|
16753
16780
|
const idByKeyPath = /* @__PURE__ */ new Map();
|
|
16754
16781
|
const walk = (el, storeyId) => {
|
|
16755
16782
|
let containerId = storeyId;
|
|
@@ -16757,13 +16784,14 @@ function familiesToBim(root, options) {
|
|
|
16757
16784
|
if (el.type === "Storey") {
|
|
16758
16785
|
const keyed = requireKeyed(el);
|
|
16759
16786
|
if (!keyed.ok) return keyed;
|
|
16760
|
-
const
|
|
16787
|
+
const storeyResult = model.addStorey({
|
|
16761
16788
|
name: el.attributes["name"] ?? el.keyPath,
|
|
16762
16789
|
elevation: el.props["elevation"] ?? 0
|
|
16763
16790
|
}, { stableKey: el.keyPath });
|
|
16764
|
-
|
|
16765
|
-
|
|
16766
|
-
|
|
16791
|
+
if (!storeyResult.ok) return storeyResult;
|
|
16792
|
+
model.aggregate(buildingId, storeyResult.value);
|
|
16793
|
+
idByKeyPath.set(el.keyPath, storeyResult.value);
|
|
16794
|
+
containerId = storeyResult.value;
|
|
16767
16795
|
} else if (route !== void 0) {
|
|
16768
16796
|
const keyed = requireKeyed(el);
|
|
16769
16797
|
if (!keyed.ok) return keyed;
|
package/dist/brepjs-bim.js
CHANGED
|
@@ -6311,14 +6311,20 @@ var BimModel = class {
|
|
|
6311
6311
|
for (const mullion of el.geometry.mullions) mullion.solid[Symbol.dispose]();
|
|
6312
6312
|
}
|
|
6313
6313
|
}
|
|
6314
|
-
addSite(spec) {
|
|
6315
|
-
|
|
6314
|
+
addSite(spec, options) {
|
|
6315
|
+
const keyCheck = this.#checkStableKey(options);
|
|
6316
|
+
if (!keyCheck.ok) return keyCheck;
|
|
6317
|
+
return ok(this.#makeElement("SITE", spec, null, options?.stableKey));
|
|
6316
6318
|
}
|
|
6317
6319
|
addBuilding(spec, options) {
|
|
6318
|
-
|
|
6320
|
+
const keyCheck = this.#checkStableKey(options);
|
|
6321
|
+
if (!keyCheck.ok) return keyCheck;
|
|
6322
|
+
return ok(this.#makeElement("BUILDING", spec, null, options?.stableKey));
|
|
6319
6323
|
}
|
|
6320
6324
|
addStorey(spec, options) {
|
|
6321
|
-
|
|
6325
|
+
const keyCheck = this.#checkStableKey(options);
|
|
6326
|
+
if (!keyCheck.ok) return keyCheck;
|
|
6327
|
+
return ok(this.#makeElement("STOREY", spec, null, options?.stableKey));
|
|
6322
6328
|
}
|
|
6323
6329
|
/** Reject a duplicate stableKey BEFORE any geometry is built, so the
|
|
6324
6330
|
* Result-returning adders never allocate a solid they cannot store. */
|
|
@@ -6485,24 +6491,30 @@ var BimModel = class {
|
|
|
6485
6491
|
* attach parts with {@link aggregate} (IfcRelAggregates) or {@link nest}
|
|
6486
6492
|
* (IfcRelNests, order-preserving). Returns the assembly's localId.
|
|
6487
6493
|
*/
|
|
6488
|
-
addElementAssembly(spec) {
|
|
6489
|
-
|
|
6494
|
+
addElementAssembly(spec, options) {
|
|
6495
|
+
const keyCheck = this.#checkStableKey(options);
|
|
6496
|
+
if (!keyCheck.ok) return keyCheck;
|
|
6497
|
+
return ok(this.#makeElement("ELEMENT_ASSEMBLY", spec, null, options?.stableKey));
|
|
6490
6498
|
}
|
|
6491
6499
|
/**
|
|
6492
6500
|
* Adds an IfcZone grouping object (a thermal/fire/occupancy zone). The zone
|
|
6493
6501
|
* carries no geometry; attach members (spaces or other elements) with
|
|
6494
|
-
* {@link assignToGroup}. Returns the zone's localId.
|
|
6502
|
+
* {@link assignToGroup}. Returns the zone's localId as a Result.
|
|
6495
6503
|
*/
|
|
6496
|
-
addZone(spec) {
|
|
6497
|
-
|
|
6504
|
+
addZone(spec, options) {
|
|
6505
|
+
const keyCheck = this.#checkStableKey(options);
|
|
6506
|
+
if (!keyCheck.ok) return keyCheck;
|
|
6507
|
+
return ok(this.#makeElement("ZONE", spec, null, options?.stableKey));
|
|
6498
6508
|
}
|
|
6499
6509
|
/**
|
|
6500
6510
|
* Adds an IfcSystem grouping object (an HVAC/electrical/plumbing system). The
|
|
6501
6511
|
* system carries no geometry; attach members with {@link assignToGroup}.
|
|
6502
|
-
* Returns the system's localId.
|
|
6512
|
+
* Returns the system's localId as a Result.
|
|
6503
6513
|
*/
|
|
6504
|
-
addSystem(spec) {
|
|
6505
|
-
|
|
6514
|
+
addSystem(spec, options) {
|
|
6515
|
+
const keyCheck = this.#checkStableKey(options);
|
|
6516
|
+
if (!keyCheck.ok) return keyCheck;
|
|
6517
|
+
return ok(this.#makeElement("SYSTEM", spec, null, options?.stableKey));
|
|
6506
6518
|
}
|
|
6507
6519
|
/**
|
|
6508
6520
|
* Assigns members to a zone or system via IfcRelAssignsToGroup. Repeated calls
|
|
@@ -7473,6 +7485,12 @@ var FILE_NAME_RE = /(FILE_NAME\('[^']*','[^']*',)(?:\$|\(\$\)),(?:\$|\(\$\)),('[
|
|
|
7473
7485
|
function stepString(value) {
|
|
7474
7486
|
return `'${value.replace(/'/g, "''")}'`;
|
|
7475
7487
|
}
|
|
7488
|
+
var STRING_OR_BARE_REAL_RE = /'(?:[^']|'')*'|(?<![\d.])(-?\d+)E([+-]?\d+)/g;
|
|
7489
|
+
function normalizeStepReals(bytes) {
|
|
7490
|
+
const text = new TextDecoder().decode(bytes);
|
|
7491
|
+
const fixed = text.replace(STRING_OR_BARE_REAL_RE, (match, mantissa, exponent) => mantissa === void 0 || exponent === void 0 ? match : `${mantissa}.E${exponent}`);
|
|
7492
|
+
return fixed === text ? bytes : new TextEncoder().encode(fixed);
|
|
7493
|
+
}
|
|
7476
7494
|
var IfcWriter = class IfcWriter {
|
|
7477
7495
|
#api;
|
|
7478
7496
|
#modelId;
|
|
@@ -7528,7 +7546,7 @@ var IfcWriter = class IfcWriter {
|
|
|
7528
7546
|
if (this.#closed) return err(ifcError("IFC_ALREADY_SAVED", "Model has already been saved and closed"));
|
|
7529
7547
|
try {
|
|
7530
7548
|
const bytes = this.#api.SaveModel(this.#modelId);
|
|
7531
|
-
return ok(this.#patchHeader(bytes));
|
|
7549
|
+
return ok(normalizeStepReals(this.#patchHeader(bytes)));
|
|
7532
7550
|
} catch (e) {
|
|
7533
7551
|
return err(ifcError("IFC_SAVE_FAILED", "Failed to serialize IFC model", e));
|
|
7534
7552
|
} finally {
|
|
@@ -16724,9 +16742,18 @@ function familiesToBim(root, options) {
|
|
|
16724
16742
|
const model = new BimModel();
|
|
16725
16743
|
const initResult = model.init(options.project);
|
|
16726
16744
|
if (!initResult.ok) return initResult;
|
|
16727
|
-
const
|
|
16728
|
-
|
|
16729
|
-
|
|
16745
|
+
const siteResult = model.addSite({ name: options.siteName ?? "Site" });
|
|
16746
|
+
if (!siteResult.ok) {
|
|
16747
|
+
model[Symbol.dispose]();
|
|
16748
|
+
return siteResult;
|
|
16749
|
+
}
|
|
16750
|
+
const buildingResult = model.addBuilding({ name: options.buildingName ?? "Building" });
|
|
16751
|
+
if (!buildingResult.ok) {
|
|
16752
|
+
model[Symbol.dispose]();
|
|
16753
|
+
return buildingResult;
|
|
16754
|
+
}
|
|
16755
|
+
const buildingId = buildingResult.value;
|
|
16756
|
+
model.aggregate(siteResult.value, buildingId);
|
|
16730
16757
|
const idByKeyPath = /* @__PURE__ */ new Map();
|
|
16731
16758
|
const walk = (el, storeyId) => {
|
|
16732
16759
|
let containerId = storeyId;
|
|
@@ -16734,13 +16761,14 @@ function familiesToBim(root, options) {
|
|
|
16734
16761
|
if (el.type === "Storey") {
|
|
16735
16762
|
const keyed = requireKeyed(el);
|
|
16736
16763
|
if (!keyed.ok) return keyed;
|
|
16737
|
-
const
|
|
16764
|
+
const storeyResult = model.addStorey({
|
|
16738
16765
|
name: el.attributes["name"] ?? el.keyPath,
|
|
16739
16766
|
elevation: el.props["elevation"] ?? 0
|
|
16740
16767
|
}, { stableKey: el.keyPath });
|
|
16741
|
-
|
|
16742
|
-
|
|
16743
|
-
|
|
16768
|
+
if (!storeyResult.ok) return storeyResult;
|
|
16769
|
+
model.aggregate(buildingId, storeyResult.value);
|
|
16770
|
+
idByKeyPath.set(el.keyPath, storeyResult.value);
|
|
16771
|
+
containerId = storeyResult.value;
|
|
16744
16772
|
} else if (route !== void 0) {
|
|
16745
16773
|
const keyed = requireKeyed(el);
|
|
16746
16774
|
if (!keyed.ok) return keyed;
|
package/dist/model/bimModel.d.ts
CHANGED
|
@@ -37,9 +37,9 @@ export declare class BimModel {
|
|
|
37
37
|
#private;
|
|
38
38
|
init(spec: ProjectSpec): Result<LocalId, BimError>;
|
|
39
39
|
[Symbol.dispose](): void;
|
|
40
|
-
addSite(spec: SiteSpec): LocalId
|
|
41
|
-
addBuilding(spec: BuildingSpec, options?: ElementIdentityOptions): LocalId
|
|
42
|
-
addStorey(spec: StoreySpec, options?: ElementIdentityOptions): LocalId
|
|
40
|
+
addSite(spec: SiteSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
|
|
41
|
+
addBuilding(spec: BuildingSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
|
|
42
|
+
addStorey(spec: StoreySpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
|
|
43
43
|
addWall(spec: WallSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
|
|
44
44
|
addSlab(spec: SlabSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
|
|
45
45
|
addBeam(spec: BeamSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
|
|
@@ -72,19 +72,19 @@ export declare class BimModel {
|
|
|
72
72
|
* attach parts with {@link aggregate} (IfcRelAggregates) or {@link nest}
|
|
73
73
|
* (IfcRelNests, order-preserving). Returns the assembly's localId.
|
|
74
74
|
*/
|
|
75
|
-
addElementAssembly(spec: ElementAssemblySpec): LocalId
|
|
75
|
+
addElementAssembly(spec: ElementAssemblySpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
|
|
76
76
|
/**
|
|
77
77
|
* Adds an IfcZone grouping object (a thermal/fire/occupancy zone). The zone
|
|
78
78
|
* carries no geometry; attach members (spaces or other elements) with
|
|
79
|
-
* {@link assignToGroup}. Returns the zone's localId.
|
|
79
|
+
* {@link assignToGroup}. Returns the zone's localId as a Result.
|
|
80
80
|
*/
|
|
81
|
-
addZone(spec: ZoneSpec): LocalId
|
|
81
|
+
addZone(spec: ZoneSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
|
|
82
82
|
/**
|
|
83
83
|
* Adds an IfcSystem grouping object (an HVAC/electrical/plumbing system). The
|
|
84
84
|
* system carries no geometry; attach members with {@link assignToGroup}.
|
|
85
|
-
* Returns the system's localId.
|
|
85
|
+
* Returns the system's localId as a Result.
|
|
86
86
|
*/
|
|
87
|
-
addSystem(spec: SystemSpec): LocalId
|
|
87
|
+
addSystem(spec: SystemSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
|
|
88
88
|
/**
|
|
89
89
|
* Assigns members to a zone or system via IfcRelAssignsToGroup. Repeated calls
|
|
90
90
|
* for the same group extend the single relationship in call order. Returns the
|