brepjs-bim 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/brepjs-bim.cjs +288 -97
- package/dist/brepjs-bim.js +287 -97
- package/dist/familiesAdapter.d.ts +22 -0
- package/dist/index.d.ts +1 -0
- package/dist/model/bimModel.d.ts +9 -4
- package/package.json +5 -2
package/dist/brepjs-bim.js
CHANGED
|
@@ -4,7 +4,7 @@ import { Handle, IfcAPI } from "web-ifc";
|
|
|
4
4
|
//#region src/identity/ifcGuid.ts
|
|
5
5
|
var IFC_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_$";
|
|
6
6
|
function newIfcGuid() {
|
|
7
|
-
const bytes = crypto.getRandomValues(new Uint8Array(16));
|
|
7
|
+
const bytes = crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(16));
|
|
8
8
|
bytes[6] = (bytes[6] ?? 0) & 15 | 64;
|
|
9
9
|
bytes[8] = (bytes[8] ?? 0) & 63 | 128;
|
|
10
10
|
return encodeIfcGuid(bytes);
|
|
@@ -46,7 +46,7 @@ function fnv1a(text) {
|
|
|
46
46
|
}
|
|
47
47
|
function digest16(stableKey) {
|
|
48
48
|
const seed = `${NAMESPACE}::${stableKey}`;
|
|
49
|
-
const bytes = new Uint8Array(16);
|
|
49
|
+
const bytes = /* @__PURE__ */ new Uint8Array(16);
|
|
50
50
|
for (let block = 0; block < 4; block++) {
|
|
51
51
|
const h = fnv1a(`b${block}:${seed}`);
|
|
52
52
|
bytes[block * 4 + 0] = h >>> 24 & 255;
|
|
@@ -183,7 +183,7 @@ function fromBrepError(inner, code, message) {
|
|
|
183
183
|
};
|
|
184
184
|
}
|
|
185
185
|
//#endregion
|
|
186
|
-
//#region \0@oxc-project+runtime@0.
|
|
186
|
+
//#region \0@oxc-project+runtime@0.143.0/helpers/esm/usingCtx.js
|
|
187
187
|
function _usingCtx() {
|
|
188
188
|
var r = "function" == typeof SuppressedError ? SuppressedError : function(r, e) {
|
|
189
189
|
var n = Error();
|
|
@@ -270,7 +270,8 @@ function wallToSolid(spec) {
|
|
|
270
270
|
]
|
|
271
271
|
]);
|
|
272
272
|
if (!profileResult.ok) return err(fromBrepError(profileResult.error, "WALL_PROFILE_FAILED", "Failed to create wall profile"));
|
|
273
|
-
const
|
|
273
|
+
const profile = _usingCtx$19.u(profileResult.value);
|
|
274
|
+
const solidResult = extrude(profile, [
|
|
274
275
|
length,
|
|
275
276
|
0,
|
|
276
277
|
0
|
|
@@ -320,7 +321,8 @@ function slabToSolid(spec) {
|
|
|
320
321
|
]
|
|
321
322
|
]);
|
|
322
323
|
if (!profileResult.ok) return err(fromBrepError(profileResult.error, "SLAB_PROFILE_FAILED", "Failed to create slab profile"));
|
|
323
|
-
const
|
|
324
|
+
const profile = _usingCtx$18.u(profileResult.value);
|
|
325
|
+
const solidResult = extrude(profile, [
|
|
324
326
|
0,
|
|
325
327
|
0,
|
|
326
328
|
thickness
|
|
@@ -414,7 +416,6 @@ function cached(getter) {
|
|
|
414
416
|
Object.defineProperty(this, "value", { value });
|
|
415
417
|
return value;
|
|
416
418
|
}
|
|
417
|
-
throw new Error("cached value already set");
|
|
418
419
|
} };
|
|
419
420
|
}
|
|
420
421
|
function nullish(input) {
|
|
@@ -460,7 +461,10 @@ function assignProp(target, prop, value) {
|
|
|
460
461
|
}
|
|
461
462
|
function mergeDefs(...defs) {
|
|
462
463
|
const mergedDescriptors = {};
|
|
463
|
-
for (const def of defs)
|
|
464
|
+
for (const def of defs) {
|
|
465
|
+
const descriptors = Object.getOwnPropertyDescriptors(def);
|
|
466
|
+
Object.assign(mergedDescriptors, descriptors);
|
|
467
|
+
}
|
|
464
468
|
return Object.defineProperties({}, mergedDescriptors);
|
|
465
469
|
}
|
|
466
470
|
function esc(str) {
|
|
@@ -782,7 +786,7 @@ var _parse = (_Err) => (schema, value, _ctx, _params) => {
|
|
|
782
786
|
}, ctx);
|
|
783
787
|
if (result instanceof Promise) throw new $ZodAsyncError();
|
|
784
788
|
if (result.issues.length) {
|
|
785
|
-
const e = new (_params?.Err ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config())));
|
|
789
|
+
const e = new ((_params?.Err) ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config())));
|
|
786
790
|
captureStackTrace(e, _params?.callee);
|
|
787
791
|
throw e;
|
|
788
792
|
}
|
|
@@ -799,7 +803,7 @@ var _parseAsync = (_Err) => async (schema, value, _ctx, params) => {
|
|
|
799
803
|
}, ctx);
|
|
800
804
|
if (result instanceof Promise) result = await result;
|
|
801
805
|
if (result.issues.length) {
|
|
802
|
-
const e = new (params?.Err ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config())));
|
|
806
|
+
const e = new ((params?.Err) ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config())));
|
|
803
807
|
captureStackTrace(e, params?.callee);
|
|
804
808
|
throw e;
|
|
805
809
|
}
|
|
@@ -966,8 +970,10 @@ var $ZodCheckLessThan = /*@__PURE__*/ $constructor("$ZodCheckLessThan", (inst, d
|
|
|
966
970
|
inst._zod.onattach.push((inst) => {
|
|
967
971
|
const bag = inst._zod.bag;
|
|
968
972
|
const curr = (def.inclusive ? bag.maximum : bag.exclusiveMaximum) ?? Number.POSITIVE_INFINITY;
|
|
969
|
-
if (def.value < curr)
|
|
970
|
-
|
|
973
|
+
if (def.value < curr) {
|
|
974
|
+
if (def.inclusive) bag.maximum = def.value;
|
|
975
|
+
else bag.exclusiveMaximum = def.value;
|
|
976
|
+
}
|
|
971
977
|
});
|
|
972
978
|
inst._zod.check = (payload) => {
|
|
973
979
|
if (def.inclusive ? payload.value <= def.value : payload.value < def.value) return;
|
|
@@ -988,8 +994,10 @@ var $ZodCheckGreaterThan = /*@__PURE__*/ $constructor("$ZodCheckGreaterThan", (i
|
|
|
988
994
|
inst._zod.onattach.push((inst) => {
|
|
989
995
|
const bag = inst._zod.bag;
|
|
990
996
|
const curr = (def.inclusive ? bag.minimum : bag.exclusiveMinimum) ?? Number.NEGATIVE_INFINITY;
|
|
991
|
-
if (def.value > curr)
|
|
992
|
-
|
|
997
|
+
if (def.value > curr) {
|
|
998
|
+
if (def.inclusive) bag.minimum = def.value;
|
|
999
|
+
else bag.exclusiveMinimum = def.value;
|
|
1000
|
+
}
|
|
993
1001
|
});
|
|
994
1002
|
inst._zod.check = (payload) => {
|
|
995
1003
|
if (def.inclusive ? payload.value >= def.value : payload.value > def.value) return;
|
|
@@ -2522,7 +2530,7 @@ var $ZodOptional = /*@__PURE__*/ $constructor("$ZodOptional", (inst, def) => {
|
|
|
2522
2530
|
inst._zod.optin = "optional";
|
|
2523
2531
|
inst._zod.optout = "optional";
|
|
2524
2532
|
defineLazy(inst._zod, "values", () => {
|
|
2525
|
-
return def.innerType._zod.values ? new Set([...def.innerType._zod.values, void 0]) : void 0;
|
|
2533
|
+
return def.innerType._zod.values ? /* @__PURE__ */ new Set([...def.innerType._zod.values, void 0]) : void 0;
|
|
2526
2534
|
});
|
|
2527
2535
|
defineLazy(inst._zod, "pattern", () => {
|
|
2528
2536
|
const pattern = def.innerType._zod.pattern;
|
|
@@ -2556,7 +2564,7 @@ var $ZodNullable = /*@__PURE__*/ $constructor("$ZodNullable", (inst, def) => {
|
|
|
2556
2564
|
return pattern ? new RegExp(`^(${cleanRegex(pattern.source)}|null)$`) : void 0;
|
|
2557
2565
|
});
|
|
2558
2566
|
defineLazy(inst._zod, "values", () => {
|
|
2559
|
-
return def.innerType._zod.values ? new Set([...def.innerType._zod.values, null]) : void 0;
|
|
2567
|
+
return def.innerType._zod.values ? /* @__PURE__ */ new Set([...def.innerType._zod.values, null]) : void 0;
|
|
2560
2568
|
});
|
|
2561
2569
|
inst._zod.parse = (payload, ctx) => {
|
|
2562
2570
|
if (payload.value === null) return payload;
|
|
@@ -3490,8 +3498,10 @@ function finalize$1(ctx, schema) {
|
|
|
3490
3498
|
defs[seen.defId] = seen.def;
|
|
3491
3499
|
}
|
|
3492
3500
|
}
|
|
3493
|
-
if (ctx.external) {} else if (Object.keys(defs).length > 0)
|
|
3494
|
-
|
|
3501
|
+
if (ctx.external) {} else if (Object.keys(defs).length > 0) {
|
|
3502
|
+
if (ctx.target === "draft-2020-12") result.$defs = defs;
|
|
3503
|
+
else result.definitions = defs;
|
|
3504
|
+
}
|
|
3495
3505
|
try {
|
|
3496
3506
|
const finalized = JSON.parse(JSON.stringify(result));
|
|
3497
3507
|
Object.defineProperty(finalized, "~standard", {
|
|
@@ -3604,16 +3614,18 @@ var numberProcessor = (schema, ctx, _json, _params) => {
|
|
|
3604
3614
|
const exMin = typeof exclusiveMinimum === "number" && exclusiveMinimum >= (minimum ?? Number.NEGATIVE_INFINITY);
|
|
3605
3615
|
const exMax = typeof exclusiveMaximum === "number" && exclusiveMaximum <= (maximum ?? Number.POSITIVE_INFINITY);
|
|
3606
3616
|
const legacy = ctx.target === "draft-04" || ctx.target === "openapi-3.0";
|
|
3607
|
-
if (exMin)
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
if (
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
+
if (exMin) {
|
|
3618
|
+
if (legacy) {
|
|
3619
|
+
json.minimum = exclusiveMinimum;
|
|
3620
|
+
json.exclusiveMinimum = true;
|
|
3621
|
+
} else json.exclusiveMinimum = exclusiveMinimum;
|
|
3622
|
+
} else if (typeof minimum === "number") json.minimum = minimum;
|
|
3623
|
+
if (exMax) {
|
|
3624
|
+
if (legacy) {
|
|
3625
|
+
json.maximum = exclusiveMaximum;
|
|
3626
|
+
json.exclusiveMaximum = true;
|
|
3627
|
+
} else json.exclusiveMaximum = exclusiveMaximum;
|
|
3628
|
+
} else if (typeof maximum === "number") json.maximum = maximum;
|
|
3617
3629
|
if (typeof multipleOf === "number") json.multipleOf = multipleOf;
|
|
3618
3630
|
};
|
|
3619
3631
|
var booleanProcessor = (_schema, _ctx, json, _params) => {
|
|
@@ -3634,9 +3646,10 @@ var literalProcessor = (schema, ctx, json, _params) => {
|
|
|
3634
3646
|
const vals = [];
|
|
3635
3647
|
for (const val of def.values) if (val === void 0) {
|
|
3636
3648
|
if (ctx.unrepresentable === "throw") throw new Error("Literal `undefined` cannot be represented in JSON Schema");
|
|
3637
|
-
} else if (typeof val === "bigint")
|
|
3638
|
-
|
|
3639
|
-
|
|
3649
|
+
} else if (typeof val === "bigint") {
|
|
3650
|
+
if (ctx.unrepresentable === "throw") throw new Error("BigInt literals cannot be represented in JSON Schema");
|
|
3651
|
+
else vals.push(Number(val));
|
|
3652
|
+
} else vals.push(val);
|
|
3640
3653
|
if (vals.length === 0) {} else if (vals.length === 1) {
|
|
3641
3654
|
const val = vals[0];
|
|
3642
3655
|
json.type = val === null ? "null" : typeof val;
|
|
@@ -5051,7 +5064,7 @@ function extendedProfileToFace(profile) {
|
|
|
5051
5064
|
}
|
|
5052
5065
|
//#endregion
|
|
5053
5066
|
//#region src/specs/profile.ts
|
|
5054
|
-
var EXTENDED_PROFILE_KIND_SET = new Set([
|
|
5067
|
+
var EXTENDED_PROFILE_KIND_SET = /* @__PURE__ */ new Set([
|
|
5055
5068
|
"L_SHAPE",
|
|
5056
5069
|
"T_SHAPE",
|
|
5057
5070
|
"U_SHAPE",
|
|
@@ -5275,7 +5288,7 @@ function profileToPolygon(profile, circleSegments = 32) {
|
|
|
5275
5288
|
case "RECTANGULAR": {
|
|
5276
5289
|
const halfW = profile.width / 2;
|
|
5277
5290
|
const halfH = profile.height / 2;
|
|
5278
|
-
|
|
5291
|
+
const pts = [
|
|
5279
5292
|
[
|
|
5280
5293
|
-halfW,
|
|
5281
5294
|
-halfH,
|
|
@@ -5296,7 +5309,8 @@ function profileToPolygon(profile, circleSegments = 32) {
|
|
|
5296
5309
|
halfH,
|
|
5297
5310
|
0
|
|
5298
5311
|
]
|
|
5299
|
-
]
|
|
5312
|
+
];
|
|
5313
|
+
return ok(pts);
|
|
5300
5314
|
}
|
|
5301
5315
|
case "CIRCULAR": {
|
|
5302
5316
|
if (circleSegments < 3) return err(specError("PROFILE_CIRCLE_SEGMENTS", `profileToPolygon: circleSegments must be >= 3, got ${circleSegments}`));
|
|
@@ -5331,7 +5345,7 @@ function profileToPolygon(profile, circleSegments = 32) {
|
|
|
5331
5345
|
[-halfW, -flangeInnerY]
|
|
5332
5346
|
];
|
|
5333
5347
|
const r = profile.filletRadius ?? 0;
|
|
5334
|
-
const rootCorners = new Set([
|
|
5348
|
+
const rootCorners = /* @__PURE__ */ new Set([
|
|
5335
5349
|
3,
|
|
5336
5350
|
4,
|
|
5337
5351
|
9,
|
|
@@ -5373,13 +5387,15 @@ function beamToSolid(spec) {
|
|
|
5373
5387
|
var _usingCtx3 = _usingCtx();
|
|
5374
5388
|
const faceResult = extendedProfileToFace(spec.profile);
|
|
5375
5389
|
if (!faceResult.ok) return err(faceResult.error);
|
|
5376
|
-
const
|
|
5390
|
+
const face = _usingCtx3.u(faceResult.value);
|
|
5391
|
+
const prismResult = extrude(face, [
|
|
5377
5392
|
0,
|
|
5378
5393
|
0,
|
|
5379
5394
|
spec.length
|
|
5380
5395
|
]);
|
|
5381
5396
|
if (!prismResult.ok) return err(fromBrepError(prismResult.error, "BEAM_EXTRUDE_FAILED", "Failed to extrude beam profile"));
|
|
5382
|
-
const
|
|
5397
|
+
const prism = _usingCtx3.u(prismResult.value);
|
|
5398
|
+
const solid = rotate(prism, 90, { axis: [
|
|
5383
5399
|
0,
|
|
5384
5400
|
1,
|
|
5385
5401
|
0
|
|
@@ -5396,13 +5412,15 @@ function beamToSolid(spec) {
|
|
|
5396
5412
|
}
|
|
5397
5413
|
const profilePtsResult = profileToPolygon(spec.profile);
|
|
5398
5414
|
if (!profilePtsResult.ok) return err(profilePtsResult.error);
|
|
5399
|
-
const
|
|
5415
|
+
const profilePts = profilePtsResult.value.map(([px, py]) => [
|
|
5400
5416
|
0,
|
|
5401
5417
|
px,
|
|
5402
5418
|
py
|
|
5403
|
-
])
|
|
5419
|
+
]);
|
|
5420
|
+
const profileResult = polygon(profilePts);
|
|
5404
5421
|
if (!profileResult.ok) return err(fromBrepError(profileResult.error, "BEAM_PROFILE_FAILED", "Failed to create beam profile"));
|
|
5405
|
-
const
|
|
5422
|
+
const profile = _usingCtx$16.u(profileResult.value);
|
|
5423
|
+
const solidResult = extrude(profile, [
|
|
5406
5424
|
spec.length,
|
|
5407
5425
|
0,
|
|
5408
5426
|
0
|
|
@@ -5430,7 +5448,8 @@ function columnToSolid(spec) {
|
|
|
5430
5448
|
var _usingCtx3 = _usingCtx();
|
|
5431
5449
|
const faceResult = extendedProfileToFace(spec.profile);
|
|
5432
5450
|
if (!faceResult.ok) return err(faceResult.error);
|
|
5433
|
-
const
|
|
5451
|
+
const face = _usingCtx3.u(faceResult.value);
|
|
5452
|
+
const extResult = extrude(face, [
|
|
5434
5453
|
0,
|
|
5435
5454
|
0,
|
|
5436
5455
|
spec.height
|
|
@@ -5452,7 +5471,8 @@ function columnToSolid(spec) {
|
|
|
5452
5471
|
const profilePts = profilePtsResult.value;
|
|
5453
5472
|
const profileResult = polygon(profilePts);
|
|
5454
5473
|
if (!profileResult.ok) return err(fromBrepError(profileResult.error, "COLUMN_PROFILE_FAILED", "Failed to create column profile"));
|
|
5455
|
-
const
|
|
5474
|
+
const profile = _usingCtx$15.u(profileResult.value);
|
|
5475
|
+
const solidResult = extrude(profile, [
|
|
5456
5476
|
0,
|
|
5457
5477
|
0,
|
|
5458
5478
|
spec.height
|
|
@@ -5472,7 +5492,7 @@ function columnToSolid(spec) {
|
|
|
5472
5492
|
}
|
|
5473
5493
|
//#endregion
|
|
5474
5494
|
//#region src/elementFns/openingFns.ts
|
|
5475
|
-
var EPSILON_MM
|
|
5495
|
+
var EPSILON_MM = 1;
|
|
5476
5496
|
function openingToSolid(spec, wallThickness) {
|
|
5477
5497
|
try {
|
|
5478
5498
|
var _usingCtx$14 = _usingCtx();
|
|
@@ -5481,7 +5501,7 @@ function openingToSolid(spec, wallThickness) {
|
|
|
5481
5501
|
if (wallThickness <= 0) return err(specError("OPENING_ZERO_WALL_THICKNESS", "Wall thickness must be positive"));
|
|
5482
5502
|
const x0 = spec.offsetAlongWall;
|
|
5483
5503
|
const yLow = -1;
|
|
5484
|
-
const yHigh = wallThickness + EPSILON_MM
|
|
5504
|
+
const yHigh = wallThickness + EPSILON_MM;
|
|
5485
5505
|
const zLow = spec.offsetFromFloor;
|
|
5486
5506
|
const zHigh = spec.offsetFromFloor + spec.height;
|
|
5487
5507
|
const profileResult = polygon([
|
|
@@ -5507,7 +5527,8 @@ function openingToSolid(spec, wallThickness) {
|
|
|
5507
5527
|
]
|
|
5508
5528
|
]);
|
|
5509
5529
|
if (!profileResult.ok) return err(fromBrepError(profileResult.error, "OPENING_PROFILE_FAILED", "Failed to create opening profile"));
|
|
5510
|
-
const
|
|
5530
|
+
const profile = _usingCtx$14.u(profileResult.value);
|
|
5531
|
+
const solidResult = extrude(profile, [
|
|
5511
5532
|
spec.width,
|
|
5512
5533
|
0,
|
|
5513
5534
|
0
|
|
@@ -5527,7 +5548,6 @@ function openingToSolid(spec, wallThickness) {
|
|
|
5527
5548
|
}
|
|
5528
5549
|
//#endregion
|
|
5529
5550
|
//#region src/elementFns/slabOpeningFns.ts
|
|
5530
|
-
var EPSILON_MM = 1;
|
|
5531
5551
|
function slabOpeningToSolid(spec, slabThickness) {
|
|
5532
5552
|
try {
|
|
5533
5553
|
var _usingCtx$13 = _usingCtx();
|
|
@@ -5562,10 +5582,11 @@ function slabOpeningToSolid(spec, slabThickness) {
|
|
|
5562
5582
|
]
|
|
5563
5583
|
]);
|
|
5564
5584
|
if (!profileResult.ok) return err(fromBrepError(profileResult.error, "SLAB_OPENING_PROFILE_FAILED", "Failed to create slab opening profile"));
|
|
5565
|
-
const
|
|
5585
|
+
const profile = _usingCtx$13.u(profileResult.value);
|
|
5586
|
+
const solidResult = extrude(profile, [
|
|
5566
5587
|
0,
|
|
5567
5588
|
0,
|
|
5568
|
-
slabThickness + 2
|
|
5589
|
+
slabThickness + 2
|
|
5569
5590
|
]);
|
|
5570
5591
|
if (!solidResult.ok) return err(fromBrepError(solidResult.error, "SLAB_OPENING_EXTRUDE_FAILED", "Failed to extrude slab opening profile"));
|
|
5571
5592
|
const solid = solidResult.value;
|
|
@@ -5612,7 +5633,8 @@ function spaceToSolid(spec) {
|
|
|
5612
5633
|
]
|
|
5613
5634
|
]);
|
|
5614
5635
|
if (!profileResult.ok) return err(fromBrepError(profileResult.error, "SPACE_PROFILE_FAILED", "Failed to create space footprint"));
|
|
5615
|
-
const
|
|
5636
|
+
const profile = _usingCtx$12.u(profileResult.value);
|
|
5637
|
+
const solidResult = extrude(profile, [
|
|
5616
5638
|
0,
|
|
5617
5639
|
0,
|
|
5618
5640
|
height
|
|
@@ -5667,7 +5689,8 @@ function flatRoof(spec) {
|
|
|
5667
5689
|
]
|
|
5668
5690
|
]);
|
|
5669
5691
|
if (!face.ok) return err(fromBrepError(face.error, "ROOF_PROFILE_FAILED", "Failed to create roof profile"));
|
|
5670
|
-
const
|
|
5692
|
+
const profile = _usingCtx$11.u(face.value);
|
|
5693
|
+
const solid = extrude(profile, [
|
|
5671
5694
|
0,
|
|
5672
5695
|
0,
|
|
5673
5696
|
thickness
|
|
@@ -5708,7 +5731,8 @@ function shedRoof(spec, pitch) {
|
|
|
5708
5731
|
]
|
|
5709
5732
|
]);
|
|
5710
5733
|
if (!face.ok) return err(fromBrepError(face.error, "ROOF_PROFILE_FAILED", "Failed to create shed profile"));
|
|
5711
|
-
const
|
|
5734
|
+
const profile = _usingCtx3.u(face.value);
|
|
5735
|
+
const solid = extrude(profile, [
|
|
5712
5736
|
length,
|
|
5713
5737
|
0,
|
|
5714
5738
|
0
|
|
@@ -5754,7 +5778,8 @@ function gableRoof(spec, pitch) {
|
|
|
5754
5778
|
]
|
|
5755
5779
|
]);
|
|
5756
5780
|
if (!face.ok) return err(fromBrepError(face.error, "ROOF_PROFILE_FAILED", "Failed to create gable profile"));
|
|
5757
|
-
const
|
|
5781
|
+
const profile = _usingCtx4.u(face.value);
|
|
5782
|
+
const solid = extrude(profile, [
|
|
5758
5783
|
length,
|
|
5759
5784
|
0,
|
|
5760
5785
|
0
|
|
@@ -5895,7 +5920,8 @@ function boxSolid(sizeX, sizeY, sizeZ) {
|
|
|
5895
5920
|
]
|
|
5896
5921
|
]);
|
|
5897
5922
|
if (!profileResult.ok) return err(fromBrepError(profileResult.error, "CURTAIN_WALL_PROFILE_FAILED", "Failed to create component profile"));
|
|
5898
|
-
const
|
|
5923
|
+
const profile = _usingCtx$10.u(profileResult.value);
|
|
5924
|
+
const solidResult = extrude(profile, [
|
|
5899
5925
|
0,
|
|
5900
5926
|
0,
|
|
5901
5927
|
sizeZ
|
|
@@ -6037,7 +6063,8 @@ function footingToSolid(spec) {
|
|
|
6037
6063
|
]
|
|
6038
6064
|
]);
|
|
6039
6065
|
if (!profileResult.ok) return err(fromBrepError(profileResult.error, "FOOTING_PROFILE_FAILED", "Failed to create footing profile"));
|
|
6040
|
-
const
|
|
6066
|
+
const profile = _usingCtx$9.u(profileResult.value);
|
|
6067
|
+
const solidResult = extrude(profile, [
|
|
6041
6068
|
0,
|
|
6042
6069
|
0,
|
|
6043
6070
|
thickness
|
|
@@ -6063,7 +6090,8 @@ function pileToSolid(spec) {
|
|
|
6063
6090
|
var _usingCtx4 = _usingCtx();
|
|
6064
6091
|
const faceResult = extendedProfileToFace(spec.profile);
|
|
6065
6092
|
if (!faceResult.ok) return err(faceResult.error);
|
|
6066
|
-
const
|
|
6093
|
+
const face = _usingCtx4.u(faceResult.value);
|
|
6094
|
+
const extResult = extrude(face, [
|
|
6067
6095
|
0,
|
|
6068
6096
|
0,
|
|
6069
6097
|
spec.length
|
|
@@ -6085,7 +6113,8 @@ function pileToSolid(spec) {
|
|
|
6085
6113
|
const profilePts = profilePtsResult.value;
|
|
6086
6114
|
const profileResult = polygon(profilePts);
|
|
6087
6115
|
if (!profileResult.ok) return err(fromBrepError(profileResult.error, "PILE_PROFILE_FAILED", "Failed to create pile profile"));
|
|
6088
|
-
const
|
|
6116
|
+
const profile = _usingCtx3.u(profileResult.value);
|
|
6117
|
+
const solidResult = extrude(profile, [
|
|
6089
6118
|
0,
|
|
6090
6119
|
0,
|
|
6091
6120
|
spec.length
|
|
@@ -6132,7 +6161,8 @@ function panelRailing(spec) {
|
|
|
6132
6161
|
]
|
|
6133
6162
|
]);
|
|
6134
6163
|
if (!profileResult.ok) return err(fromBrepError(profileResult.error, "RAILING_PROFILE_FAILED", "Failed to create railing profile"));
|
|
6135
|
-
const
|
|
6164
|
+
const profile = _usingCtx$8.u(profileResult.value);
|
|
6165
|
+
const solidResult = extrude(profile, [
|
|
6136
6166
|
length,
|
|
6137
6167
|
0,
|
|
6138
6168
|
0
|
|
@@ -6238,7 +6268,8 @@ function coveringToSolid(spec) {
|
|
|
6238
6268
|
]
|
|
6239
6269
|
]);
|
|
6240
6270
|
if (!profileResult.ok) return err(fromBrepError(profileResult.error, "COVERING_PROFILE_FAILED", "Failed to create covering profile"));
|
|
6241
|
-
const
|
|
6271
|
+
const profile = _usingCtx$7.u(profileResult.value);
|
|
6272
|
+
const solidResult = extrude(profile, [
|
|
6242
6273
|
0,
|
|
6243
6274
|
0,
|
|
6244
6275
|
thickness
|
|
@@ -6265,6 +6296,7 @@ var BimModel = class {
|
|
|
6265
6296
|
#counter = makeLocalIdCounter();
|
|
6266
6297
|
#projectId = null;
|
|
6267
6298
|
#modelScope = "";
|
|
6299
|
+
#usedStableKeys = /* @__PURE__ */ new Set();
|
|
6268
6300
|
init(spec) {
|
|
6269
6301
|
if (this.#projectId !== null) return err(specError("DUPLICATE_PROJECT", "BimModel.init() called twice — only one project per model"));
|
|
6270
6302
|
this.#modelScope = spec.projectId ?? `${spec.name}::${spec.description ?? ""}`;
|
|
@@ -6282,24 +6314,35 @@ var BimModel = class {
|
|
|
6282
6314
|
addSite(spec) {
|
|
6283
6315
|
return this.#makeElement("SITE", spec, null);
|
|
6284
6316
|
}
|
|
6285
|
-
addBuilding(spec) {
|
|
6286
|
-
return this.#makeElement("BUILDING", spec, null);
|
|
6317
|
+
addBuilding(spec, options) {
|
|
6318
|
+
return this.#makeElement("BUILDING", spec, null, options?.stableKey);
|
|
6287
6319
|
}
|
|
6288
|
-
addStorey(spec) {
|
|
6289
|
-
return this.#makeElement("STOREY", spec, null);
|
|
6320
|
+
addStorey(spec, options) {
|
|
6321
|
+
return this.#makeElement("STOREY", spec, null, options?.stableKey);
|
|
6290
6322
|
}
|
|
6291
|
-
|
|
6323
|
+
/** Reject a duplicate stableKey BEFORE any geometry is built, so the
|
|
6324
|
+
* Result-returning adders never allocate a solid they cannot store. */
|
|
6325
|
+
#checkStableKey(options) {
|
|
6326
|
+
const key = options?.stableKey;
|
|
6327
|
+
if (key !== void 0 && this.#usedStableKeys.has(key)) return err(specError("DUPLICATE_STABLE_KEY", `BimModel: duplicate stableKey '${key}'`));
|
|
6328
|
+
return ok(void 0);
|
|
6329
|
+
}
|
|
6330
|
+
addWall(spec, options) {
|
|
6331
|
+
const keyCheck = this.#checkStableKey(options);
|
|
6332
|
+
if (!keyCheck.ok) return keyCheck;
|
|
6292
6333
|
const geomResult = wallToSolid(spec);
|
|
6293
6334
|
if (!geomResult.ok) return err(geomResult.error);
|
|
6294
|
-
const id = this.#makeElement("WALL", spec, geomResult.value);
|
|
6335
|
+
const id = this.#makeElement("WALL", spec, geomResult.value, options?.stableKey);
|
|
6295
6336
|
this.#associateMaterial(id, spec);
|
|
6296
6337
|
this.#associateClassification(id, spec);
|
|
6297
6338
|
return ok(id);
|
|
6298
6339
|
}
|
|
6299
|
-
addSlab(spec) {
|
|
6340
|
+
addSlab(spec, options) {
|
|
6341
|
+
const keyCheck = this.#checkStableKey(options);
|
|
6342
|
+
if (!keyCheck.ok) return keyCheck;
|
|
6300
6343
|
const geomResult = slabToSolid(spec);
|
|
6301
6344
|
if (!geomResult.ok) return err(geomResult.error);
|
|
6302
|
-
const id = this.#makeElement("SLAB", spec, geomResult.value);
|
|
6345
|
+
const id = this.#makeElement("SLAB", spec, geomResult.value, options?.stableKey);
|
|
6303
6346
|
this.#associateMaterial(id, spec);
|
|
6304
6347
|
this.#associateClassification(id, spec);
|
|
6305
6348
|
return ok(id);
|
|
@@ -6918,10 +6961,14 @@ var BimModel = class {
|
|
|
6918
6961
|
getAllRelationships() {
|
|
6919
6962
|
return [...this.#relationships.values()];
|
|
6920
6963
|
}
|
|
6921
|
-
#makeElement(category, spec, geometry) {
|
|
6964
|
+
#makeElement(category, spec, geometry, stableKey) {
|
|
6922
6965
|
const localId = this.#counter.next();
|
|
6966
|
+
if (stableKey !== void 0) {
|
|
6967
|
+
if (this.#usedStableKeys.has(stableKey)) throw new Error(`BimModel: duplicate stableKey '${stableKey}'`);
|
|
6968
|
+
this.#usedStableKeys.add(stableKey);
|
|
6969
|
+
}
|
|
6923
6970
|
const el = {
|
|
6924
|
-
guid: deriveIfcGuidSync(makeElementKey(this.#modelScope, category, localId)),
|
|
6971
|
+
guid: deriveIfcGuidSync(stableKey !== void 0 ? `elem:${this.#modelScope}:${stableKey}` : makeElementKey(this.#modelScope, category, localId)),
|
|
6925
6972
|
localId,
|
|
6926
6973
|
category,
|
|
6927
6974
|
spec,
|
|
@@ -7168,9 +7215,11 @@ function stairFlightToSolid(spec) {
|
|
|
7168
7215
|
if (spec.riserHeight <= 0) return err(specError("STAIR_FLIGHT_ZERO_RISER", "Stair flight riserHeight must be positive"));
|
|
7169
7216
|
if (spec.treadLength <= 0) return err(specError("STAIR_FLIGHT_ZERO_TREAD", "Stair flight treadLength must be positive"));
|
|
7170
7217
|
if (!Number.isInteger(spec.numberOfRisers) || spec.numberOfRisers < 1) return err(specError("STAIR_FLIGHT_BAD_RISERS", "Stair flight numberOfRisers must be a positive integer"));
|
|
7171
|
-
const
|
|
7218
|
+
const silhouette = buildSilhouette$1(spec.numberOfRisers, spec.riserHeight, spec.treadLength);
|
|
7219
|
+
const profileResult = polygon(silhouette);
|
|
7172
7220
|
if (!profileResult.ok) return err(fromBrepError(profileResult.error, "STAIR_FLIGHT_PROFILE_FAILED", "Failed to create stair flight silhouette profile"));
|
|
7173
|
-
const
|
|
7221
|
+
const profile = _usingCtx$5.u(profileResult.value);
|
|
7222
|
+
const solidResult = extrude(profile, [
|
|
7174
7223
|
0,
|
|
7175
7224
|
spec.width,
|
|
7176
7225
|
0
|
|
@@ -7326,7 +7375,7 @@ function isIfcSchema(value) {
|
|
|
7326
7375
|
* linear-infrastructure entities). Entities absent from every per-schema set are
|
|
7327
7376
|
* treated as schema-agnostic and supported everywhere (open-world default).
|
|
7328
7377
|
*/
|
|
7329
|
-
var IFC4X3_ONLY_ENTITIES = new Set([
|
|
7378
|
+
var IFC4X3_ONLY_ENTITIES = /* @__PURE__ */ new Set([
|
|
7330
7379
|
"IfcAlignment",
|
|
7331
7380
|
"IfcAlignmentHorizontal",
|
|
7332
7381
|
"IfcAlignmentVertical",
|
|
@@ -7406,7 +7455,8 @@ var IfcWriter = class IfcWriter {
|
|
|
7406
7455
|
try {
|
|
7407
7456
|
const api = new IfcAPI();
|
|
7408
7457
|
await initIfcApi(api);
|
|
7409
|
-
|
|
7458
|
+
const modelId = api.CreateModel({ schema: fileSchemaString(ifcSchema) });
|
|
7459
|
+
return ok(new IfcWriter(api, modelId, mvdViewDefinition, header));
|
|
7410
7460
|
} catch (e) {
|
|
7411
7461
|
return err(ifcError("IFC_INIT_FAILED", "Failed to initialize web-ifc", e));
|
|
7412
7462
|
}
|
|
@@ -7460,8 +7510,10 @@ var IfcWriter = class IfcWriter {
|
|
|
7460
7510
|
let head = new TextDecoder().decode(bytes.subarray(0, HEADER_SCAN));
|
|
7461
7511
|
if (FILE_NAME_RE.test(head)) head = head.replace(FILE_NAME_RE, (_m, prefix, systems) => `${prefix}(${stepString(this.#author)}),(${stepString(this.#organization)}),${systems},${stepString("")})`);
|
|
7462
7512
|
else console.warn("IfcWriter: FILE_NAME null-field pattern not found; author/organization/authorization left unpatched");
|
|
7463
|
-
if (this.#mvdViewDefinition.length > 0)
|
|
7464
|
-
|
|
7513
|
+
if (this.#mvdViewDefinition.length > 0) {
|
|
7514
|
+
if (VIEW_DEFINITION_RE.test(head)) head = head.replace(VIEW_DEFINITION_RE, `ViewDefinition [${this.#mvdViewDefinition}]`);
|
|
7515
|
+
else console.warn(`IfcWriter: FILE_DESCRIPTION ViewDefinition not found; MVD "${this.#mvdViewDefinition}" not declared`);
|
|
7516
|
+
}
|
|
7465
7517
|
const patchedHeadBytes = new TextEncoder().encode(head);
|
|
7466
7518
|
const tail = bytes.subarray(HEADER_SCAN);
|
|
7467
7519
|
const out = new Uint8Array(patchedHeadBytes.byteLength + tail.byteLength);
|
|
@@ -9380,9 +9432,11 @@ function rampFlightToSolid(spec) {
|
|
|
9380
9432
|
if (spec.slope <= 0) return err(specError("RAMP_FLIGHT_ZERO_SLOPE", "Ramp flight slope must be positive"));
|
|
9381
9433
|
if (spec.thickness <= 0) return err(specError("RAMP_FLIGHT_ZERO_THICKNESS", "Ramp flight thickness must be positive"));
|
|
9382
9434
|
const rise = spec.length * spec.slope;
|
|
9383
|
-
const
|
|
9435
|
+
const silhouette = buildSilhouette(spec.length, rise, spec.thickness);
|
|
9436
|
+
const profileResult = polygon(silhouette);
|
|
9384
9437
|
if (!profileResult.ok) return err(fromBrepError(profileResult.error, "RAMP_FLIGHT_PROFILE_FAILED", "Failed to create ramp flight silhouette profile"));
|
|
9385
|
-
const
|
|
9438
|
+
const profile = _usingCtx$3.u(profileResult.value);
|
|
9439
|
+
const solidResult = extrude(profile, [
|
|
9386
9440
|
0,
|
|
9387
9441
|
spec.width,
|
|
9388
9442
|
0
|
|
@@ -11708,7 +11762,7 @@ function isSlabOpening(spec) {
|
|
|
11708
11762
|
* instead, and OPENINGs are tied to their host through VOIDS rels — neither
|
|
11709
11763
|
* participates in containment, so excluding them here avoids false orphans.
|
|
11710
11764
|
*/
|
|
11711
|
-
var CONTAINABLE_CATEGORIES = new Set([
|
|
11765
|
+
var CONTAINABLE_CATEGORIES = /* @__PURE__ */ new Set([
|
|
11712
11766
|
"WALL",
|
|
11713
11767
|
"SLAB",
|
|
11714
11768
|
"BEAM",
|
|
@@ -12505,14 +12559,15 @@ async function toIfcValidated(model, meta) {
|
|
|
12505
12559
|
const geometry = collectGeometryIssues(model);
|
|
12506
12560
|
const schema = await checkSchema(bytes);
|
|
12507
12561
|
const roundTrip = await checkRoundTrip(bytes);
|
|
12562
|
+
const report = { issues: [
|
|
12563
|
+
...integrity.issues,
|
|
12564
|
+
...geometry.issues,
|
|
12565
|
+
...schema.issues,
|
|
12566
|
+
...roundTrip.issues
|
|
12567
|
+
] };
|
|
12508
12568
|
return ok({
|
|
12509
12569
|
bytes,
|
|
12510
|
-
report
|
|
12511
|
-
...integrity.issues,
|
|
12512
|
-
...geometry.issues,
|
|
12513
|
-
...schema.issues,
|
|
12514
|
-
...roundTrip.issues
|
|
12515
|
-
] }
|
|
12570
|
+
report
|
|
12516
12571
|
});
|
|
12517
12572
|
}
|
|
12518
12573
|
/**
|
|
@@ -12733,7 +12788,7 @@ var SpfReader = class SpfReader {
|
|
|
12733
12788
|
};
|
|
12734
12789
|
//#endregion
|
|
12735
12790
|
//#region src/import/spatialTree.ts
|
|
12736
|
-
var CATEGORY_BY_TYPE = new Map([
|
|
12791
|
+
var CATEGORY_BY_TYPE = /* @__PURE__ */ new Map([
|
|
12737
12792
|
[WebIFC.IFCPROJECT, "PROJECT"],
|
|
12738
12793
|
[WebIFC.IFCSITE, "SITE"],
|
|
12739
12794
|
[WebIFC.IFCBUILDING, "BUILDING"],
|
|
@@ -12915,7 +12970,8 @@ function reconstructExtrusion(reader, extrusionId, scale, worldTransform, diagno
|
|
|
12915
12970
|
const solidResult = (() => {
|
|
12916
12971
|
try {
|
|
12917
12972
|
var _usingCtx$1 = _usingCtx();
|
|
12918
|
-
|
|
12973
|
+
const face = _usingCtx$1.u(faceResult.value);
|
|
12974
|
+
return extrude(face, extrudeVec);
|
|
12919
12975
|
} catch (_) {
|
|
12920
12976
|
_usingCtx$1.e = _;
|
|
12921
12977
|
} finally {
|
|
@@ -12968,10 +13024,12 @@ function reconstructRevolution(reader, revolutionId, scale, worldTransform, diag
|
|
|
12968
13024
|
const revolved = (() => {
|
|
12969
13025
|
try {
|
|
12970
13026
|
var _usingCtx3 = _usingCtx();
|
|
12971
|
-
|
|
13027
|
+
const face = _usingCtx3.u(faceResult.value);
|
|
13028
|
+
const angleDeg = angleRaw * readPlaneAngleScale(reader) * (180 / Math.PI);
|
|
13029
|
+
return revolve(face, {
|
|
12972
13030
|
at: center,
|
|
12973
13031
|
axis: direction,
|
|
12974
|
-
angle:
|
|
13032
|
+
angle: angleDeg
|
|
12975
13033
|
});
|
|
12976
13034
|
} catch (_) {
|
|
12977
13035
|
_usingCtx3.e = _;
|
|
@@ -13086,7 +13144,7 @@ function packBinaryStl(vertices, indices, scaleToMm) {
|
|
|
13086
13144
|
}
|
|
13087
13145
|
return new Uint8Array(buffer);
|
|
13088
13146
|
}
|
|
13089
|
-
var PARAMETRIC_PROFILE_BUILDERS = new Map([
|
|
13147
|
+
var PARAMETRIC_PROFILE_BUILDERS = /* @__PURE__ */ new Map([
|
|
13090
13148
|
[WebIFC.IFCRECTANGLEPROFILEDEF, (f) => ({
|
|
13091
13149
|
kind: "RECTANGULAR",
|
|
13092
13150
|
width: f("XDim"),
|
|
@@ -13854,14 +13912,15 @@ async function fromIfc(bytes, options = {}) {
|
|
|
13854
13912
|
}
|
|
13855
13913
|
const report = appendIssues(emptyReport(), diagnostics);
|
|
13856
13914
|
const applicationName = readApplicationName(reader);
|
|
13857
|
-
|
|
13915
|
+
const model = {
|
|
13858
13916
|
schema: reader.schema,
|
|
13859
13917
|
spatialTree: spatialRoot === null ? null : mapSpatialNode(spatialRoot),
|
|
13860
13918
|
elements,
|
|
13861
13919
|
byExpressId,
|
|
13862
13920
|
diagnostics: report,
|
|
13863
13921
|
...applicationName !== void 0 ? { applicationName } : {}
|
|
13864
|
-
}
|
|
13922
|
+
};
|
|
13923
|
+
return ok(model);
|
|
13865
13924
|
} catch (e) {
|
|
13866
13925
|
return err(importError("IMPORT_FAILED", "Unexpected failure during IFC import", e));
|
|
13867
13926
|
} finally {
|
|
@@ -14888,7 +14947,7 @@ function parseSlabOpeningInput(input) {
|
|
|
14888
14947
|
* containers (PROJECT/SITE/BUILDING/STOREY), abstract groupings, and the SPACE
|
|
14889
14948
|
* category (which maps to the Space sheet, not Component) are excluded.
|
|
14890
14949
|
*/
|
|
14891
|
-
var COMPONENT_CATEGORIES = new Set([
|
|
14950
|
+
var COMPONENT_CATEGORIES = /* @__PURE__ */ new Set([
|
|
14892
14951
|
"WALL",
|
|
14893
14952
|
"SLAB",
|
|
14894
14953
|
"BEAM",
|
|
@@ -15513,9 +15572,10 @@ function parseIdsXml(xml) {
|
|
|
15513
15572
|
const title = info ? firstChild(info, "title")?.text ?? "" : "";
|
|
15514
15573
|
const specsContainer = firstChild(root, "specifications");
|
|
15515
15574
|
if (specsContainer === void 0) return err(idsError("IDS_INVALID_SCHEMA", "IDS document has no <specifications> element"));
|
|
15575
|
+
const specifications = childrenNamed(specsContainer, "specification").map(parseSpecification);
|
|
15516
15576
|
return ok({
|
|
15517
15577
|
title,
|
|
15518
|
-
specifications
|
|
15578
|
+
specifications
|
|
15519
15579
|
});
|
|
15520
15580
|
}
|
|
15521
15581
|
function parseSpecification(el) {
|
|
@@ -15872,10 +15932,7 @@ function restrictionsOf(facet) {
|
|
|
15872
15932
|
push(facet.system);
|
|
15873
15933
|
push(facet.value);
|
|
15874
15934
|
break;
|
|
15875
|
-
case "Material":
|
|
15876
|
-
push(facet.value);
|
|
15877
|
-
break;
|
|
15878
|
-
case "PartOf": break;
|
|
15935
|
+
case "Material": push(facet.value);
|
|
15879
15936
|
}
|
|
15880
15937
|
return out;
|
|
15881
15938
|
}
|
|
@@ -16275,7 +16332,8 @@ function parseBcfFiles(files) {
|
|
|
16275
16332
|
topics
|
|
16276
16333
|
});
|
|
16277
16334
|
} catch (cause) {
|
|
16278
|
-
|
|
16335
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
16336
|
+
return err(bcfError("BCF_PARSE_FAILED", `Failed to parse BCF container: ${message}`, cause));
|
|
16279
16337
|
}
|
|
16280
16338
|
}
|
|
16281
16339
|
function parseVersion(xml) {
|
|
@@ -16390,4 +16448,136 @@ function assignNum(target, key, value) {
|
|
|
16390
16448
|
if (value !== void 0) target[key] = Number(value);
|
|
16391
16449
|
}
|
|
16392
16450
|
//#endregion
|
|
16393
|
-
|
|
16451
|
+
//#region src/familiesAdapter.ts
|
|
16452
|
+
/**
|
|
16453
|
+
* brepjs-families -> BimModel adapter. Consumes a resolved element tree and
|
|
16454
|
+
* feeds each element's PRE-DESUGARED props into the parametric specs — the
|
|
16455
|
+
* spec path stays authoritative for IFC (IfcExtrudedAreaSolid + placement),
|
|
16456
|
+
* while the IR path serves the viewport and dedup. GlobalIds derive from
|
|
16457
|
+
* families key paths (stable under reordering), not insertion order.
|
|
16458
|
+
*
|
|
16459
|
+
* v1 scope: Storey containers and Wall/Slab elements. Openings, fills, and
|
|
16460
|
+
* relationship wiring (IfcRelVoidsElement) follow with the opening writer.
|
|
16461
|
+
*/
|
|
16462
|
+
var SPEC_DEFAULTS = {
|
|
16463
|
+
origin: [
|
|
16464
|
+
0,
|
|
16465
|
+
0,
|
|
16466
|
+
0
|
|
16467
|
+
],
|
|
16468
|
+
axisX: [
|
|
16469
|
+
1,
|
|
16470
|
+
0,
|
|
16471
|
+
0
|
|
16472
|
+
],
|
|
16473
|
+
axisZ: [
|
|
16474
|
+
0,
|
|
16475
|
+
0,
|
|
16476
|
+
1
|
|
16477
|
+
],
|
|
16478
|
+
materialName: "Default"
|
|
16479
|
+
};
|
|
16480
|
+
var GEOMETRY_PROPS = /* @__PURE__ */ new Set([
|
|
16481
|
+
"voids",
|
|
16482
|
+
"fuse",
|
|
16483
|
+
"transform",
|
|
16484
|
+
"psets"
|
|
16485
|
+
]);
|
|
16486
|
+
/** Fold the resolved geometry's OUTER literal translate chain into the spec
|
|
16487
|
+
* placement origin, so IfcLocalPlacement matches the IR world frame no
|
|
16488
|
+
* matter where the transform came from (family-internal or prop-level).
|
|
16489
|
+
* Parameter-driven translations cannot fold and keep the default origin. */
|
|
16490
|
+
function composedOrigin(el) {
|
|
16491
|
+
const out = [...el.props["origin"] ?? [
|
|
16492
|
+
0,
|
|
16493
|
+
0,
|
|
16494
|
+
0
|
|
16495
|
+
]];
|
|
16496
|
+
let moved = false;
|
|
16497
|
+
let node = el.geometry;
|
|
16498
|
+
while (node.kind === "Translate") {
|
|
16499
|
+
const v = node.vector;
|
|
16500
|
+
if (v.kind !== "Vec3Lit") break;
|
|
16501
|
+
out[0] += v.value[0];
|
|
16502
|
+
out[1] += v.value[1];
|
|
16503
|
+
out[2] += v.value[2];
|
|
16504
|
+
moved = true;
|
|
16505
|
+
node = node.target;
|
|
16506
|
+
}
|
|
16507
|
+
return moved || el.props["origin"] !== void 0 ? out : void 0;
|
|
16508
|
+
}
|
|
16509
|
+
function specInput(el) {
|
|
16510
|
+
const fromProps = {};
|
|
16511
|
+
for (const [k, v] of Object.entries(el.props)) if (!GEOMETRY_PROPS.has(k)) fromProps[k] = v;
|
|
16512
|
+
const origin = composedOrigin(el);
|
|
16513
|
+
return {
|
|
16514
|
+
...SPEC_DEFAULTS,
|
|
16515
|
+
...fromProps,
|
|
16516
|
+
...origin ? { origin } : {},
|
|
16517
|
+
...collectSpecProps(el)
|
|
16518
|
+
};
|
|
16519
|
+
}
|
|
16520
|
+
function collectSpecProps(el) {
|
|
16521
|
+
const psets = el.attributes["psets"];
|
|
16522
|
+
const out = {};
|
|
16523
|
+
if (psets && typeof psets === "object") {
|
|
16524
|
+
const common = psets["Pset_WallCommon"];
|
|
16525
|
+
if (common && typeof common === "object") {
|
|
16526
|
+
const c = common;
|
|
16527
|
+
if (typeof c["IsExternal"] === "boolean") out["isExternal"] = c["IsExternal"];
|
|
16528
|
+
if (typeof c["FireRating"] === "string") out["fireRating"] = c["FireRating"];
|
|
16529
|
+
}
|
|
16530
|
+
}
|
|
16531
|
+
delete out["psets"];
|
|
16532
|
+
return out;
|
|
16533
|
+
}
|
|
16534
|
+
/**
|
|
16535
|
+
* Project a resolved families tree into an eager BimModel. The caller owns
|
|
16536
|
+
* the returned model (`using`); families stays domain-neutral — this adapter
|
|
16537
|
+
* is where families types meet the IFC vocabulary.
|
|
16538
|
+
*/
|
|
16539
|
+
function familiesToBim(root, options) {
|
|
16540
|
+
const model = new BimModel();
|
|
16541
|
+
const initResult = model.init(options.project);
|
|
16542
|
+
if (!initResult.ok) return initResult;
|
|
16543
|
+
const siteId = model.addSite({ name: options.siteName ?? "Site" });
|
|
16544
|
+
const buildingId = model.addBuilding({ name: options.buildingName ?? "Building" });
|
|
16545
|
+
model.aggregate(siteId, buildingId);
|
|
16546
|
+
const idByKeyPath = /* @__PURE__ */ new Map();
|
|
16547
|
+
const walk = (el, storeyId) => {
|
|
16548
|
+
let containerId = storeyId;
|
|
16549
|
+
if (el.type === "Storey") {
|
|
16550
|
+
const id = model.addStorey({
|
|
16551
|
+
name: el.attributes["name"] ?? el.keyPath,
|
|
16552
|
+
elevation: el.props["elevation"] ?? 0
|
|
16553
|
+
}, { stableKey: el.keyPath });
|
|
16554
|
+
model.aggregate(buildingId, id);
|
|
16555
|
+
idByKeyPath.set(el.keyPath, id);
|
|
16556
|
+
containerId = id;
|
|
16557
|
+
} else if (el.type === "Wall" || el.type === "Slab") {
|
|
16558
|
+
const parsed = el.type === "Wall" ? parseWallSpec(specInput(el)) : parseSlabSpec(specInput(el));
|
|
16559
|
+
if (!parsed.ok) return parsed;
|
|
16560
|
+
const added = el.type === "Wall" ? model.addWall(parsed.value, { stableKey: el.keyPath }) : model.addSlab(parsed.value, { stableKey: el.keyPath });
|
|
16561
|
+
if (!added.ok) return added;
|
|
16562
|
+
idByKeyPath.set(el.keyPath, added.value);
|
|
16563
|
+
if (containerId === null) return err(specError("FAMILIES_NO_STOREY", `familiesToBim: '${el.keyPath}' has no Storey ancestor — IFC elements need spatial containment`));
|
|
16564
|
+
model.placeIn(added.value, containerId);
|
|
16565
|
+
} else if (el.type !== "Opening" && el.type !== "Group" && el.geometry.kind !== "Empty") return err(specError("FAMILIES_UNSUPPORTED_TYPE", `familiesToBim: no spec mapping for element type '${el.type}' at '${el.keyPath}'`));
|
|
16566
|
+
for (const child of el.children) {
|
|
16567
|
+
const r = walk(child, containerId);
|
|
16568
|
+
if (!r.ok) return r;
|
|
16569
|
+
}
|
|
16570
|
+
return ok(void 0);
|
|
16571
|
+
};
|
|
16572
|
+
const walked = walk(root, null);
|
|
16573
|
+
if (!walked.ok) {
|
|
16574
|
+
model[Symbol.dispose]();
|
|
16575
|
+
return walked;
|
|
16576
|
+
}
|
|
16577
|
+
return ok({
|
|
16578
|
+
model,
|
|
16579
|
+
idByKeyPath
|
|
16580
|
+
});
|
|
16581
|
+
}
|
|
16582
|
+
//#endregion
|
|
16583
|
+
export { BimModel, DEFAULT_IFC_SCHEMA, DEFAULT_UNITS, IFC_SCHEMAS, PSET_PROPERTY_TYPE_TABLE, PSET_TEMPLATES, SpfReader, bcfError, checkGeometryValidity, checkModelAgainstIds as checkIds, checkModelAgainstIds, checkReferentialIntegrity, checkRoundTrip, checkSchema, countBySeverity, deriveCobieModel, deriveCobieModel as exportCobie, deriveIfcGuid, deriveIfcGuidSync, disposeImportedModel, emptyReport, extendedProfileArea, extendedProfileToFace, familiesToBim, fileSchemaString, fromBrepError, fromIfc, geometryError, hasErrors, idsError, ifcError, importError, isExtendedProfile, isIfcSchema, isSlabOpening, isValidIfcGuid, isWallOpening, issue, makeLocalIdCounter, measureTypeFor, newIfcGuid, parseBcfFiles, parseBeamSpec, parseColumnSpec, parseCoveringSpec, parseCurtainWallSpec, parseDoorSpec, parseElementAssemblySpec, parseFootingSpec, parseIdsXml, parsePileSpec, parseProfile, parseRailingSpec, parseRampFlightSpec, parseRampSpec, parseRoofSpec, parseSlabOpeningInput, parseSlabSpec, parseSpaceSpec, parseStairFlightSpec, parseStairSpec, parseSurfaceStyleSpec, parseSystemSpec, parseWallSpec, parseWindowSpec, parseZoneSpec, placedSolids, schemaSupports, serializeBcfFiles, serializeCobieToCsv, serializeCobieToJson, setIfcWasmLocateFile, specError, templateFor, toIfc, toIfcLengthM, toIfcValidated, toLengthMm, writeClassificationRefs, writeElementAssemblyEntity, writeIfcType, writeMaterialLayerSet, writeMaterialProfileSet, writeMaterialSimple, writePresentationLayer, writeRelAggregatesElements, writeRelAssignsToGroup, writeRelConnectsElements, writeRelConnectsPathElements, writeRelNests, writeStyledItem, writeSurfaceStyle, writeSystemEntity, writeZoneEntity };
|