brepjs-bim 0.3.1 → 0.5.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 +384 -107
- package/dist/brepjs-bim.js +383 -107
- package/dist/familiesAdapter.d.ts +22 -0
- package/dist/index.d.ts +2 -1
- package/dist/model/bimModel.d.ts +17 -7
- package/package.json +5 -2
package/dist/brepjs-bim.cjs
CHANGED
|
@@ -16,7 +16,7 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
16
|
}
|
|
17
17
|
return to;
|
|
18
18
|
};
|
|
19
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
|
|
20
20
|
value: mod,
|
|
21
21
|
enumerable: true
|
|
22
22
|
}) : target, mod));
|
|
@@ -27,7 +27,7 @@ web_ifc = __toESM(web_ifc, 1);
|
|
|
27
27
|
//#region src/identity/ifcGuid.ts
|
|
28
28
|
var IFC_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_$";
|
|
29
29
|
function newIfcGuid() {
|
|
30
|
-
const bytes = crypto.getRandomValues(new Uint8Array(16));
|
|
30
|
+
const bytes = crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(16));
|
|
31
31
|
bytes[6] = (bytes[6] ?? 0) & 15 | 64;
|
|
32
32
|
bytes[8] = (bytes[8] ?? 0) & 63 | 128;
|
|
33
33
|
return encodeIfcGuid(bytes);
|
|
@@ -69,7 +69,7 @@ function fnv1a(text) {
|
|
|
69
69
|
}
|
|
70
70
|
function digest16(stableKey) {
|
|
71
71
|
const seed = `${NAMESPACE}::${stableKey}`;
|
|
72
|
-
const bytes = new Uint8Array(16);
|
|
72
|
+
const bytes = /* @__PURE__ */ new Uint8Array(16);
|
|
73
73
|
for (let block = 0; block < 4; block++) {
|
|
74
74
|
const h = fnv1a(`b${block}:${seed}`);
|
|
75
75
|
bytes[block * 4 + 0] = h >>> 24 & 255;
|
|
@@ -206,7 +206,7 @@ function fromBrepError(inner, code, message) {
|
|
|
206
206
|
};
|
|
207
207
|
}
|
|
208
208
|
//#endregion
|
|
209
|
-
//#region \0@oxc-project+runtime@0.
|
|
209
|
+
//#region \0@oxc-project+runtime@0.143.0/helpers/esm/usingCtx.js
|
|
210
210
|
function _usingCtx() {
|
|
211
211
|
var r = "function" == typeof SuppressedError ? SuppressedError : function(r, e) {
|
|
212
212
|
var n = Error();
|
|
@@ -293,7 +293,8 @@ function wallToSolid(spec) {
|
|
|
293
293
|
]
|
|
294
294
|
]);
|
|
295
295
|
if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "WALL_PROFILE_FAILED", "Failed to create wall profile"));
|
|
296
|
-
const
|
|
296
|
+
const profile = _usingCtx$19.u(profileResult.value);
|
|
297
|
+
const solidResult = (0, brepjs.extrude)(profile, [
|
|
297
298
|
length,
|
|
298
299
|
0,
|
|
299
300
|
0
|
|
@@ -343,7 +344,8 @@ function slabToSolid(spec) {
|
|
|
343
344
|
]
|
|
344
345
|
]);
|
|
345
346
|
if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "SLAB_PROFILE_FAILED", "Failed to create slab profile"));
|
|
346
|
-
const
|
|
347
|
+
const profile = _usingCtx$18.u(profileResult.value);
|
|
348
|
+
const solidResult = (0, brepjs.extrude)(profile, [
|
|
347
349
|
0,
|
|
348
350
|
0,
|
|
349
351
|
thickness
|
|
@@ -437,7 +439,6 @@ function cached(getter) {
|
|
|
437
439
|
Object.defineProperty(this, "value", { value });
|
|
438
440
|
return value;
|
|
439
441
|
}
|
|
440
|
-
throw new Error("cached value already set");
|
|
441
442
|
} };
|
|
442
443
|
}
|
|
443
444
|
function nullish(input) {
|
|
@@ -483,7 +484,10 @@ function assignProp(target, prop, value) {
|
|
|
483
484
|
}
|
|
484
485
|
function mergeDefs(...defs) {
|
|
485
486
|
const mergedDescriptors = {};
|
|
486
|
-
for (const def of defs)
|
|
487
|
+
for (const def of defs) {
|
|
488
|
+
const descriptors = Object.getOwnPropertyDescriptors(def);
|
|
489
|
+
Object.assign(mergedDescriptors, descriptors);
|
|
490
|
+
}
|
|
487
491
|
return Object.defineProperties({}, mergedDescriptors);
|
|
488
492
|
}
|
|
489
493
|
function esc(str) {
|
|
@@ -805,7 +809,7 @@ var _parse = (_Err) => (schema, value, _ctx, _params) => {
|
|
|
805
809
|
}, ctx);
|
|
806
810
|
if (result instanceof Promise) throw new $ZodAsyncError();
|
|
807
811
|
if (result.issues.length) {
|
|
808
|
-
const e = new (_params?.Err ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config())));
|
|
812
|
+
const e = new ((_params?.Err) ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config())));
|
|
809
813
|
captureStackTrace(e, _params?.callee);
|
|
810
814
|
throw e;
|
|
811
815
|
}
|
|
@@ -822,7 +826,7 @@ var _parseAsync = (_Err) => async (schema, value, _ctx, params) => {
|
|
|
822
826
|
}, ctx);
|
|
823
827
|
if (result instanceof Promise) result = await result;
|
|
824
828
|
if (result.issues.length) {
|
|
825
|
-
const e = new (params?.Err ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config())));
|
|
829
|
+
const e = new ((params?.Err) ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config())));
|
|
826
830
|
captureStackTrace(e, params?.callee);
|
|
827
831
|
throw e;
|
|
828
832
|
}
|
|
@@ -989,8 +993,10 @@ var $ZodCheckLessThan = /*@__PURE__*/ $constructor("$ZodCheckLessThan", (inst, d
|
|
|
989
993
|
inst._zod.onattach.push((inst) => {
|
|
990
994
|
const bag = inst._zod.bag;
|
|
991
995
|
const curr = (def.inclusive ? bag.maximum : bag.exclusiveMaximum) ?? Number.POSITIVE_INFINITY;
|
|
992
|
-
if (def.value < curr)
|
|
993
|
-
|
|
996
|
+
if (def.value < curr) {
|
|
997
|
+
if (def.inclusive) bag.maximum = def.value;
|
|
998
|
+
else bag.exclusiveMaximum = def.value;
|
|
999
|
+
}
|
|
994
1000
|
});
|
|
995
1001
|
inst._zod.check = (payload) => {
|
|
996
1002
|
if (def.inclusive ? payload.value <= def.value : payload.value < def.value) return;
|
|
@@ -1011,8 +1017,10 @@ var $ZodCheckGreaterThan = /*@__PURE__*/ $constructor("$ZodCheckGreaterThan", (i
|
|
|
1011
1017
|
inst._zod.onattach.push((inst) => {
|
|
1012
1018
|
const bag = inst._zod.bag;
|
|
1013
1019
|
const curr = (def.inclusive ? bag.minimum : bag.exclusiveMinimum) ?? Number.NEGATIVE_INFINITY;
|
|
1014
|
-
if (def.value > curr)
|
|
1015
|
-
|
|
1020
|
+
if (def.value > curr) {
|
|
1021
|
+
if (def.inclusive) bag.minimum = def.value;
|
|
1022
|
+
else bag.exclusiveMinimum = def.value;
|
|
1023
|
+
}
|
|
1016
1024
|
});
|
|
1017
1025
|
inst._zod.check = (payload) => {
|
|
1018
1026
|
if (def.inclusive ? payload.value >= def.value : payload.value > def.value) return;
|
|
@@ -2545,7 +2553,7 @@ var $ZodOptional = /*@__PURE__*/ $constructor("$ZodOptional", (inst, def) => {
|
|
|
2545
2553
|
inst._zod.optin = "optional";
|
|
2546
2554
|
inst._zod.optout = "optional";
|
|
2547
2555
|
defineLazy(inst._zod, "values", () => {
|
|
2548
|
-
return def.innerType._zod.values ? new Set([...def.innerType._zod.values, void 0]) : void 0;
|
|
2556
|
+
return def.innerType._zod.values ? /* @__PURE__ */ new Set([...def.innerType._zod.values, void 0]) : void 0;
|
|
2549
2557
|
});
|
|
2550
2558
|
defineLazy(inst._zod, "pattern", () => {
|
|
2551
2559
|
const pattern = def.innerType._zod.pattern;
|
|
@@ -2579,7 +2587,7 @@ var $ZodNullable = /*@__PURE__*/ $constructor("$ZodNullable", (inst, def) => {
|
|
|
2579
2587
|
return pattern ? new RegExp(`^(${cleanRegex(pattern.source)}|null)$`) : void 0;
|
|
2580
2588
|
});
|
|
2581
2589
|
defineLazy(inst._zod, "values", () => {
|
|
2582
|
-
return def.innerType._zod.values ? new Set([...def.innerType._zod.values, null]) : void 0;
|
|
2590
|
+
return def.innerType._zod.values ? /* @__PURE__ */ new Set([...def.innerType._zod.values, null]) : void 0;
|
|
2583
2591
|
});
|
|
2584
2592
|
inst._zod.parse = (payload, ctx) => {
|
|
2585
2593
|
if (payload.value === null) return payload;
|
|
@@ -3513,8 +3521,10 @@ function finalize$1(ctx, schema) {
|
|
|
3513
3521
|
defs[seen.defId] = seen.def;
|
|
3514
3522
|
}
|
|
3515
3523
|
}
|
|
3516
|
-
if (ctx.external) {} else if (Object.keys(defs).length > 0)
|
|
3517
|
-
|
|
3524
|
+
if (ctx.external) {} else if (Object.keys(defs).length > 0) {
|
|
3525
|
+
if (ctx.target === "draft-2020-12") result.$defs = defs;
|
|
3526
|
+
else result.definitions = defs;
|
|
3527
|
+
}
|
|
3518
3528
|
try {
|
|
3519
3529
|
const finalized = JSON.parse(JSON.stringify(result));
|
|
3520
3530
|
Object.defineProperty(finalized, "~standard", {
|
|
@@ -3627,16 +3637,18 @@ var numberProcessor = (schema, ctx, _json, _params) => {
|
|
|
3627
3637
|
const exMin = typeof exclusiveMinimum === "number" && exclusiveMinimum >= (minimum ?? Number.NEGATIVE_INFINITY);
|
|
3628
3638
|
const exMax = typeof exclusiveMaximum === "number" && exclusiveMaximum <= (maximum ?? Number.POSITIVE_INFINITY);
|
|
3629
3639
|
const legacy = ctx.target === "draft-04" || ctx.target === "openapi-3.0";
|
|
3630
|
-
if (exMin)
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
if (
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
+
if (exMin) {
|
|
3641
|
+
if (legacy) {
|
|
3642
|
+
json.minimum = exclusiveMinimum;
|
|
3643
|
+
json.exclusiveMinimum = true;
|
|
3644
|
+
} else json.exclusiveMinimum = exclusiveMinimum;
|
|
3645
|
+
} else if (typeof minimum === "number") json.minimum = minimum;
|
|
3646
|
+
if (exMax) {
|
|
3647
|
+
if (legacy) {
|
|
3648
|
+
json.maximum = exclusiveMaximum;
|
|
3649
|
+
json.exclusiveMaximum = true;
|
|
3650
|
+
} else json.exclusiveMaximum = exclusiveMaximum;
|
|
3651
|
+
} else if (typeof maximum === "number") json.maximum = maximum;
|
|
3640
3652
|
if (typeof multipleOf === "number") json.multipleOf = multipleOf;
|
|
3641
3653
|
};
|
|
3642
3654
|
var booleanProcessor = (_schema, _ctx, json, _params) => {
|
|
@@ -3657,9 +3669,10 @@ var literalProcessor = (schema, ctx, json, _params) => {
|
|
|
3657
3669
|
const vals = [];
|
|
3658
3670
|
for (const val of def.values) if (val === void 0) {
|
|
3659
3671
|
if (ctx.unrepresentable === "throw") throw new Error("Literal `undefined` cannot be represented in JSON Schema");
|
|
3660
|
-
} else if (typeof val === "bigint")
|
|
3661
|
-
|
|
3662
|
-
|
|
3672
|
+
} else if (typeof val === "bigint") {
|
|
3673
|
+
if (ctx.unrepresentable === "throw") throw new Error("BigInt literals cannot be represented in JSON Schema");
|
|
3674
|
+
else vals.push(Number(val));
|
|
3675
|
+
} else vals.push(val);
|
|
3663
3676
|
if (vals.length === 0) {} else if (vals.length === 1) {
|
|
3664
3677
|
const val = vals[0];
|
|
3665
3678
|
json.type = val === null ? "null" : typeof val;
|
|
@@ -5074,7 +5087,7 @@ function extendedProfileToFace(profile) {
|
|
|
5074
5087
|
}
|
|
5075
5088
|
//#endregion
|
|
5076
5089
|
//#region src/specs/profile.ts
|
|
5077
|
-
var EXTENDED_PROFILE_KIND_SET = new Set([
|
|
5090
|
+
var EXTENDED_PROFILE_KIND_SET = /* @__PURE__ */ new Set([
|
|
5078
5091
|
"L_SHAPE",
|
|
5079
5092
|
"T_SHAPE",
|
|
5080
5093
|
"U_SHAPE",
|
|
@@ -5298,7 +5311,7 @@ function profileToPolygon(profile, circleSegments = 32) {
|
|
|
5298
5311
|
case "RECTANGULAR": {
|
|
5299
5312
|
const halfW = profile.width / 2;
|
|
5300
5313
|
const halfH = profile.height / 2;
|
|
5301
|
-
|
|
5314
|
+
const pts = [
|
|
5302
5315
|
[
|
|
5303
5316
|
-halfW,
|
|
5304
5317
|
-halfH,
|
|
@@ -5319,7 +5332,8 @@ function profileToPolygon(profile, circleSegments = 32) {
|
|
|
5319
5332
|
halfH,
|
|
5320
5333
|
0
|
|
5321
5334
|
]
|
|
5322
|
-
]
|
|
5335
|
+
];
|
|
5336
|
+
return (0, brepjs.ok)(pts);
|
|
5323
5337
|
}
|
|
5324
5338
|
case "CIRCULAR": {
|
|
5325
5339
|
if (circleSegments < 3) return (0, brepjs.err)(specError("PROFILE_CIRCLE_SEGMENTS", `profileToPolygon: circleSegments must be >= 3, got ${circleSegments}`));
|
|
@@ -5354,7 +5368,7 @@ function profileToPolygon(profile, circleSegments = 32) {
|
|
|
5354
5368
|
[-halfW, -flangeInnerY]
|
|
5355
5369
|
];
|
|
5356
5370
|
const r = profile.filletRadius ?? 0;
|
|
5357
|
-
const rootCorners = new Set([
|
|
5371
|
+
const rootCorners = /* @__PURE__ */ new Set([
|
|
5358
5372
|
3,
|
|
5359
5373
|
4,
|
|
5360
5374
|
9,
|
|
@@ -5396,13 +5410,15 @@ function beamToSolid(spec) {
|
|
|
5396
5410
|
var _usingCtx3 = _usingCtx();
|
|
5397
5411
|
const faceResult = extendedProfileToFace(spec.profile);
|
|
5398
5412
|
if (!faceResult.ok) return (0, brepjs.err)(faceResult.error);
|
|
5399
|
-
const
|
|
5413
|
+
const face = _usingCtx3.u(faceResult.value);
|
|
5414
|
+
const prismResult = (0, brepjs.extrude)(face, [
|
|
5400
5415
|
0,
|
|
5401
5416
|
0,
|
|
5402
5417
|
spec.length
|
|
5403
5418
|
]);
|
|
5404
5419
|
if (!prismResult.ok) return (0, brepjs.err)(fromBrepError(prismResult.error, "BEAM_EXTRUDE_FAILED", "Failed to extrude beam profile"));
|
|
5405
|
-
const
|
|
5420
|
+
const prism = _usingCtx3.u(prismResult.value);
|
|
5421
|
+
const solid = (0, brepjs.rotate)(prism, 90, { axis: [
|
|
5406
5422
|
0,
|
|
5407
5423
|
1,
|
|
5408
5424
|
0
|
|
@@ -5419,13 +5435,15 @@ function beamToSolid(spec) {
|
|
|
5419
5435
|
}
|
|
5420
5436
|
const profilePtsResult = profileToPolygon(spec.profile);
|
|
5421
5437
|
if (!profilePtsResult.ok) return (0, brepjs.err)(profilePtsResult.error);
|
|
5422
|
-
const
|
|
5438
|
+
const profilePts = profilePtsResult.value.map(([px, py]) => [
|
|
5423
5439
|
0,
|
|
5424
5440
|
px,
|
|
5425
5441
|
py
|
|
5426
|
-
])
|
|
5442
|
+
]);
|
|
5443
|
+
const profileResult = (0, brepjs.polygon)(profilePts);
|
|
5427
5444
|
if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "BEAM_PROFILE_FAILED", "Failed to create beam profile"));
|
|
5428
|
-
const
|
|
5445
|
+
const profile = _usingCtx$16.u(profileResult.value);
|
|
5446
|
+
const solidResult = (0, brepjs.extrude)(profile, [
|
|
5429
5447
|
spec.length,
|
|
5430
5448
|
0,
|
|
5431
5449
|
0
|
|
@@ -5453,7 +5471,8 @@ function columnToSolid(spec) {
|
|
|
5453
5471
|
var _usingCtx3 = _usingCtx();
|
|
5454
5472
|
const faceResult = extendedProfileToFace(spec.profile);
|
|
5455
5473
|
if (!faceResult.ok) return (0, brepjs.err)(faceResult.error);
|
|
5456
|
-
const
|
|
5474
|
+
const face = _usingCtx3.u(faceResult.value);
|
|
5475
|
+
const extResult = (0, brepjs.extrude)(face, [
|
|
5457
5476
|
0,
|
|
5458
5477
|
0,
|
|
5459
5478
|
spec.height
|
|
@@ -5475,7 +5494,8 @@ function columnToSolid(spec) {
|
|
|
5475
5494
|
const profilePts = profilePtsResult.value;
|
|
5476
5495
|
const profileResult = (0, brepjs.polygon)(profilePts);
|
|
5477
5496
|
if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "COLUMN_PROFILE_FAILED", "Failed to create column profile"));
|
|
5478
|
-
const
|
|
5497
|
+
const profile = _usingCtx$15.u(profileResult.value);
|
|
5498
|
+
const solidResult = (0, brepjs.extrude)(profile, [
|
|
5479
5499
|
0,
|
|
5480
5500
|
0,
|
|
5481
5501
|
spec.height
|
|
@@ -5495,7 +5515,7 @@ function columnToSolid(spec) {
|
|
|
5495
5515
|
}
|
|
5496
5516
|
//#endregion
|
|
5497
5517
|
//#region src/elementFns/openingFns.ts
|
|
5498
|
-
var EPSILON_MM
|
|
5518
|
+
var EPSILON_MM = 1;
|
|
5499
5519
|
function openingToSolid(spec, wallThickness) {
|
|
5500
5520
|
try {
|
|
5501
5521
|
var _usingCtx$14 = _usingCtx();
|
|
@@ -5504,7 +5524,7 @@ function openingToSolid(spec, wallThickness) {
|
|
|
5504
5524
|
if (wallThickness <= 0) return (0, brepjs.err)(specError("OPENING_ZERO_WALL_THICKNESS", "Wall thickness must be positive"));
|
|
5505
5525
|
const x0 = spec.offsetAlongWall;
|
|
5506
5526
|
const yLow = -1;
|
|
5507
|
-
const yHigh = wallThickness + EPSILON_MM
|
|
5527
|
+
const yHigh = wallThickness + EPSILON_MM;
|
|
5508
5528
|
const zLow = spec.offsetFromFloor;
|
|
5509
5529
|
const zHigh = spec.offsetFromFloor + spec.height;
|
|
5510
5530
|
const profileResult = (0, brepjs.polygon)([
|
|
@@ -5530,7 +5550,8 @@ function openingToSolid(spec, wallThickness) {
|
|
|
5530
5550
|
]
|
|
5531
5551
|
]);
|
|
5532
5552
|
if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "OPENING_PROFILE_FAILED", "Failed to create opening profile"));
|
|
5533
|
-
const
|
|
5553
|
+
const profile = _usingCtx$14.u(profileResult.value);
|
|
5554
|
+
const solidResult = (0, brepjs.extrude)(profile, [
|
|
5534
5555
|
spec.width,
|
|
5535
5556
|
0,
|
|
5536
5557
|
0
|
|
@@ -5550,7 +5571,6 @@ function openingToSolid(spec, wallThickness) {
|
|
|
5550
5571
|
}
|
|
5551
5572
|
//#endregion
|
|
5552
5573
|
//#region src/elementFns/slabOpeningFns.ts
|
|
5553
|
-
var EPSILON_MM = 1;
|
|
5554
5574
|
function slabOpeningToSolid(spec, slabThickness) {
|
|
5555
5575
|
try {
|
|
5556
5576
|
var _usingCtx$13 = _usingCtx();
|
|
@@ -5585,10 +5605,11 @@ function slabOpeningToSolid(spec, slabThickness) {
|
|
|
5585
5605
|
]
|
|
5586
5606
|
]);
|
|
5587
5607
|
if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "SLAB_OPENING_PROFILE_FAILED", "Failed to create slab opening profile"));
|
|
5588
|
-
const
|
|
5608
|
+
const profile = _usingCtx$13.u(profileResult.value);
|
|
5609
|
+
const solidResult = (0, brepjs.extrude)(profile, [
|
|
5589
5610
|
0,
|
|
5590
5611
|
0,
|
|
5591
|
-
slabThickness + 2
|
|
5612
|
+
slabThickness + 2
|
|
5592
5613
|
]);
|
|
5593
5614
|
if (!solidResult.ok) return (0, brepjs.err)(fromBrepError(solidResult.error, "SLAB_OPENING_EXTRUDE_FAILED", "Failed to extrude slab opening profile"));
|
|
5594
5615
|
const solid = solidResult.value;
|
|
@@ -5635,7 +5656,8 @@ function spaceToSolid(spec) {
|
|
|
5635
5656
|
]
|
|
5636
5657
|
]);
|
|
5637
5658
|
if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "SPACE_PROFILE_FAILED", "Failed to create space footprint"));
|
|
5638
|
-
const
|
|
5659
|
+
const profile = _usingCtx$12.u(profileResult.value);
|
|
5660
|
+
const solidResult = (0, brepjs.extrude)(profile, [
|
|
5639
5661
|
0,
|
|
5640
5662
|
0,
|
|
5641
5663
|
height
|
|
@@ -5690,7 +5712,8 @@ function flatRoof(spec) {
|
|
|
5690
5712
|
]
|
|
5691
5713
|
]);
|
|
5692
5714
|
if (!face.ok) return (0, brepjs.err)(fromBrepError(face.error, "ROOF_PROFILE_FAILED", "Failed to create roof profile"));
|
|
5693
|
-
const
|
|
5715
|
+
const profile = _usingCtx$11.u(face.value);
|
|
5716
|
+
const solid = (0, brepjs.extrude)(profile, [
|
|
5694
5717
|
0,
|
|
5695
5718
|
0,
|
|
5696
5719
|
thickness
|
|
@@ -5731,7 +5754,8 @@ function shedRoof(spec, pitch) {
|
|
|
5731
5754
|
]
|
|
5732
5755
|
]);
|
|
5733
5756
|
if (!face.ok) return (0, brepjs.err)(fromBrepError(face.error, "ROOF_PROFILE_FAILED", "Failed to create shed profile"));
|
|
5734
|
-
const
|
|
5757
|
+
const profile = _usingCtx3.u(face.value);
|
|
5758
|
+
const solid = (0, brepjs.extrude)(profile, [
|
|
5735
5759
|
length,
|
|
5736
5760
|
0,
|
|
5737
5761
|
0
|
|
@@ -5777,7 +5801,8 @@ function gableRoof(spec, pitch) {
|
|
|
5777
5801
|
]
|
|
5778
5802
|
]);
|
|
5779
5803
|
if (!face.ok) return (0, brepjs.err)(fromBrepError(face.error, "ROOF_PROFILE_FAILED", "Failed to create gable profile"));
|
|
5780
|
-
const
|
|
5804
|
+
const profile = _usingCtx4.u(face.value);
|
|
5805
|
+
const solid = (0, brepjs.extrude)(profile, [
|
|
5781
5806
|
length,
|
|
5782
5807
|
0,
|
|
5783
5808
|
0
|
|
@@ -5918,7 +5943,8 @@ function boxSolid(sizeX, sizeY, sizeZ) {
|
|
|
5918
5943
|
]
|
|
5919
5944
|
]);
|
|
5920
5945
|
if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "CURTAIN_WALL_PROFILE_FAILED", "Failed to create component profile"));
|
|
5921
|
-
const
|
|
5946
|
+
const profile = _usingCtx$10.u(profileResult.value);
|
|
5947
|
+
const solidResult = (0, brepjs.extrude)(profile, [
|
|
5922
5948
|
0,
|
|
5923
5949
|
0,
|
|
5924
5950
|
sizeZ
|
|
@@ -6060,7 +6086,8 @@ function footingToSolid(spec) {
|
|
|
6060
6086
|
]
|
|
6061
6087
|
]);
|
|
6062
6088
|
if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "FOOTING_PROFILE_FAILED", "Failed to create footing profile"));
|
|
6063
|
-
const
|
|
6089
|
+
const profile = _usingCtx$9.u(profileResult.value);
|
|
6090
|
+
const solidResult = (0, brepjs.extrude)(profile, [
|
|
6064
6091
|
0,
|
|
6065
6092
|
0,
|
|
6066
6093
|
thickness
|
|
@@ -6086,7 +6113,8 @@ function pileToSolid(spec) {
|
|
|
6086
6113
|
var _usingCtx4 = _usingCtx();
|
|
6087
6114
|
const faceResult = extendedProfileToFace(spec.profile);
|
|
6088
6115
|
if (!faceResult.ok) return (0, brepjs.err)(faceResult.error);
|
|
6089
|
-
const
|
|
6116
|
+
const face = _usingCtx4.u(faceResult.value);
|
|
6117
|
+
const extResult = (0, brepjs.extrude)(face, [
|
|
6090
6118
|
0,
|
|
6091
6119
|
0,
|
|
6092
6120
|
spec.length
|
|
@@ -6108,7 +6136,8 @@ function pileToSolid(spec) {
|
|
|
6108
6136
|
const profilePts = profilePtsResult.value;
|
|
6109
6137
|
const profileResult = (0, brepjs.polygon)(profilePts);
|
|
6110
6138
|
if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "PILE_PROFILE_FAILED", "Failed to create pile profile"));
|
|
6111
|
-
const
|
|
6139
|
+
const profile = _usingCtx3.u(profileResult.value);
|
|
6140
|
+
const solidResult = (0, brepjs.extrude)(profile, [
|
|
6112
6141
|
0,
|
|
6113
6142
|
0,
|
|
6114
6143
|
spec.length
|
|
@@ -6155,7 +6184,8 @@ function panelRailing(spec) {
|
|
|
6155
6184
|
]
|
|
6156
6185
|
]);
|
|
6157
6186
|
if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "RAILING_PROFILE_FAILED", "Failed to create railing profile"));
|
|
6158
|
-
const
|
|
6187
|
+
const profile = _usingCtx$8.u(profileResult.value);
|
|
6188
|
+
const solidResult = (0, brepjs.extrude)(profile, [
|
|
6159
6189
|
length,
|
|
6160
6190
|
0,
|
|
6161
6191
|
0
|
|
@@ -6261,7 +6291,8 @@ function coveringToSolid(spec) {
|
|
|
6261
6291
|
]
|
|
6262
6292
|
]);
|
|
6263
6293
|
if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "COVERING_PROFILE_FAILED", "Failed to create covering profile"));
|
|
6264
|
-
const
|
|
6294
|
+
const profile = _usingCtx$7.u(profileResult.value);
|
|
6295
|
+
const solidResult = (0, brepjs.extrude)(profile, [
|
|
6265
6296
|
0,
|
|
6266
6297
|
0,
|
|
6267
6298
|
thickness
|
|
@@ -6288,6 +6319,7 @@ var BimModel = class {
|
|
|
6288
6319
|
#counter = makeLocalIdCounter();
|
|
6289
6320
|
#projectId = null;
|
|
6290
6321
|
#modelScope = "";
|
|
6322
|
+
#usedStableKeys = /* @__PURE__ */ new Set();
|
|
6291
6323
|
init(spec) {
|
|
6292
6324
|
if (this.#projectId !== null) return (0, brepjs.err)(specError("DUPLICATE_PROJECT", "BimModel.init() called twice — only one project per model"));
|
|
6293
6325
|
this.#modelScope = spec.projectId ?? `${spec.name}::${spec.description ?? ""}`;
|
|
@@ -6305,24 +6337,43 @@ var BimModel = class {
|
|
|
6305
6337
|
addSite(spec) {
|
|
6306
6338
|
return this.#makeElement("SITE", spec, null);
|
|
6307
6339
|
}
|
|
6308
|
-
addBuilding(spec) {
|
|
6309
|
-
return this.#makeElement("BUILDING", spec, null);
|
|
6310
|
-
}
|
|
6311
|
-
addStorey(spec) {
|
|
6312
|
-
return this.#makeElement("STOREY", spec, null);
|
|
6313
|
-
}
|
|
6314
|
-
|
|
6340
|
+
addBuilding(spec, options) {
|
|
6341
|
+
return this.#makeElement("BUILDING", spec, null, options?.stableKey);
|
|
6342
|
+
}
|
|
6343
|
+
addStorey(spec, options) {
|
|
6344
|
+
return this.#makeElement("STOREY", spec, null, options?.stableKey);
|
|
6345
|
+
}
|
|
6346
|
+
/** Reject a duplicate stableKey BEFORE any geometry is built, so the
|
|
6347
|
+
* Result-returning adders never allocate a solid they cannot store. */
|
|
6348
|
+
#checkStableKey(options) {
|
|
6349
|
+
const key = options?.stableKey;
|
|
6350
|
+
if (key !== void 0 && this.#usedStableKeys.has(key)) return (0, brepjs.err)(specError("DUPLICATE_STABLE_KEY", `BimModel: duplicate stableKey '${key}'`));
|
|
6351
|
+
return (0, brepjs.ok)(void 0);
|
|
6352
|
+
}
|
|
6353
|
+
#checkOpeningKeys(options) {
|
|
6354
|
+
const filler = this.#checkStableKey(options);
|
|
6355
|
+
if (!filler.ok) return filler;
|
|
6356
|
+
const opening = this.#checkStableKey({ stableKey: options?.openingStableKey });
|
|
6357
|
+
if (!opening.ok) return opening;
|
|
6358
|
+
if (options?.stableKey !== void 0 && options.stableKey === options.openingStableKey) return (0, brepjs.err)(specError("DUPLICATE_STABLE_KEY", `BimModel: stableKey and openingStableKey are both '${options.stableKey}'`));
|
|
6359
|
+
return (0, brepjs.ok)(void 0);
|
|
6360
|
+
}
|
|
6361
|
+
addWall(spec, options) {
|
|
6362
|
+
const keyCheck = this.#checkStableKey(options);
|
|
6363
|
+
if (!keyCheck.ok) return keyCheck;
|
|
6315
6364
|
const geomResult = wallToSolid(spec);
|
|
6316
6365
|
if (!geomResult.ok) return (0, brepjs.err)(geomResult.error);
|
|
6317
|
-
const id = this.#makeElement("WALL", spec, geomResult.value);
|
|
6366
|
+
const id = this.#makeElement("WALL", spec, geomResult.value, options?.stableKey);
|
|
6318
6367
|
this.#associateMaterial(id, spec);
|
|
6319
6368
|
this.#associateClassification(id, spec);
|
|
6320
6369
|
return (0, brepjs.ok)(id);
|
|
6321
6370
|
}
|
|
6322
|
-
addSlab(spec) {
|
|
6371
|
+
addSlab(spec, options) {
|
|
6372
|
+
const keyCheck = this.#checkStableKey(options);
|
|
6373
|
+
if (!keyCheck.ok) return keyCheck;
|
|
6323
6374
|
const geomResult = slabToSolid(spec);
|
|
6324
6375
|
if (!geomResult.ok) return (0, brepjs.err)(geomResult.error);
|
|
6325
|
-
const id = this.#makeElement("SLAB", spec, geomResult.value);
|
|
6376
|
+
const id = this.#makeElement("SLAB", spec, geomResult.value, options?.stableKey);
|
|
6326
6377
|
this.#associateMaterial(id, spec);
|
|
6327
6378
|
this.#associateClassification(id, spec);
|
|
6328
6379
|
return (0, brepjs.ok)(id);
|
|
@@ -6598,7 +6649,9 @@ var BimModel = class {
|
|
|
6598
6649
|
});
|
|
6599
6650
|
return (0, brepjs.ok)(id);
|
|
6600
6651
|
}
|
|
6601
|
-
addDoor(spec) {
|
|
6652
|
+
addDoor(spec, options) {
|
|
6653
|
+
const keyCheck = this.#checkOpeningKeys(options);
|
|
6654
|
+
if (!keyCheck.ok) return keyCheck;
|
|
6602
6655
|
const wall = this.#elements.get(spec.wallLocalId);
|
|
6603
6656
|
if (wall === void 0 || wall.category !== "WALL") return (0, brepjs.err)(specError("DOOR_WALL_NOT_FOUND", `No wall found for localId ${spec.wallLocalId}`));
|
|
6604
6657
|
if (spec.offsetAlongWall + spec.width > wall.spec.length) return (0, brepjs.err)(specError("DOOR_EXCEEDS_WALL_BOUNDS", "Door (offsetAlongWall + width) exceeds wall length"));
|
|
@@ -6613,13 +6666,13 @@ var BimModel = class {
|
|
|
6613
6666
|
const cutResult = this.#cutWallGeometry(wall, openingSpec);
|
|
6614
6667
|
if (!cutResult.ok) return (0, brepjs.err)(cutResult.error);
|
|
6615
6668
|
this.#replaceWallGeometry(wall, cutResult.value);
|
|
6616
|
-
const openingId = this.#makeElement("OPENING", openingSpec, null);
|
|
6669
|
+
const openingId = this.#makeElement("OPENING", openingSpec, null, options?.openingStableKey);
|
|
6617
6670
|
this.#makeRel({
|
|
6618
6671
|
kind: "VOIDS_WALL",
|
|
6619
6672
|
wallLocalId: spec.wallLocalId,
|
|
6620
6673
|
openingLocalId: openingId
|
|
6621
6674
|
});
|
|
6622
|
-
const doorId = this.#makeElement("DOOR", spec, null);
|
|
6675
|
+
const doorId = this.#makeElement("DOOR", spec, null, options?.stableKey);
|
|
6623
6676
|
this.#makeRel({
|
|
6624
6677
|
kind: "FILLS_OPENING",
|
|
6625
6678
|
openingLocalId: openingId,
|
|
@@ -6632,7 +6685,9 @@ var BimModel = class {
|
|
|
6632
6685
|
});
|
|
6633
6686
|
return (0, brepjs.ok)(doorId);
|
|
6634
6687
|
}
|
|
6635
|
-
addWindow(spec) {
|
|
6688
|
+
addWindow(spec, options) {
|
|
6689
|
+
const keyCheck = this.#checkOpeningKeys(options);
|
|
6690
|
+
if (!keyCheck.ok) return keyCheck;
|
|
6636
6691
|
const wall = this.#elements.get(spec.wallLocalId);
|
|
6637
6692
|
if (wall === void 0 || wall.category !== "WALL") return (0, brepjs.err)(specError("WINDOW_WALL_NOT_FOUND", `No wall found for localId ${spec.wallLocalId}`));
|
|
6638
6693
|
if (spec.offsetAlongWall + spec.width > wall.spec.length) return (0, brepjs.err)(specError("WINDOW_EXCEEDS_WALL_BOUNDS", "Window (offsetAlongWall + width) exceeds wall length"));
|
|
@@ -6647,13 +6702,13 @@ var BimModel = class {
|
|
|
6647
6702
|
const cutResult = this.#cutWallGeometry(wall, openingSpec);
|
|
6648
6703
|
if (!cutResult.ok) return (0, brepjs.err)(cutResult.error);
|
|
6649
6704
|
this.#replaceWallGeometry(wall, cutResult.value);
|
|
6650
|
-
const openingId = this.#makeElement("OPENING", openingSpec, null);
|
|
6705
|
+
const openingId = this.#makeElement("OPENING", openingSpec, null, options?.openingStableKey);
|
|
6651
6706
|
this.#makeRel({
|
|
6652
6707
|
kind: "VOIDS_WALL",
|
|
6653
6708
|
wallLocalId: spec.wallLocalId,
|
|
6654
6709
|
openingLocalId: openingId
|
|
6655
6710
|
});
|
|
6656
|
-
const windowId = this.#makeElement("WINDOW", spec, null);
|
|
6711
|
+
const windowId = this.#makeElement("WINDOW", spec, null, options?.stableKey);
|
|
6657
6712
|
this.#makeRel({
|
|
6658
6713
|
kind: "FILLS_OPENING",
|
|
6659
6714
|
openingLocalId: openingId,
|
|
@@ -6666,7 +6721,9 @@ var BimModel = class {
|
|
|
6666
6721
|
});
|
|
6667
6722
|
return (0, brepjs.ok)(windowId);
|
|
6668
6723
|
}
|
|
6669
|
-
addSlabOpening(input) {
|
|
6724
|
+
addSlabOpening(input, options) {
|
|
6725
|
+
const keyCheck = this.#checkStableKey(options);
|
|
6726
|
+
if (!keyCheck.ok) return keyCheck;
|
|
6670
6727
|
const slab = this.#elements.get(input.slabLocalId);
|
|
6671
6728
|
if (slab === void 0 || slab.category !== "SLAB") return (0, brepjs.err)(specError("SLAB_OPENING_SLAB_NOT_FOUND", `No slab found for localId ${input.slabLocalId}`));
|
|
6672
6729
|
if (input.offsetX + input.sizeX > slab.spec.length) return (0, brepjs.err)(specError("SLAB_OPENING_EXCEEDS_SLAB_BOUNDS", "Opening (offsetX + sizeX) exceeds slab length"));
|
|
@@ -6696,7 +6753,7 @@ var BimModel = class {
|
|
|
6696
6753
|
const cutResult = this.#cutSlabGeometry(slab, openingSpec);
|
|
6697
6754
|
if (!cutResult.ok) return (0, brepjs.err)(cutResult.error);
|
|
6698
6755
|
this.#replaceSlabGeometry(slab, cutResult.value);
|
|
6699
|
-
const openingId = this.#makeElement("OPENING", openingSpec, null);
|
|
6756
|
+
const openingId = this.#makeElement("OPENING", openingSpec, null, options?.stableKey);
|
|
6700
6757
|
this.#makeRel({
|
|
6701
6758
|
kind: "VOIDS_SLAB",
|
|
6702
6759
|
slabLocalId: input.slabLocalId,
|
|
@@ -6941,10 +6998,14 @@ var BimModel = class {
|
|
|
6941
6998
|
getAllRelationships() {
|
|
6942
6999
|
return [...this.#relationships.values()];
|
|
6943
7000
|
}
|
|
6944
|
-
#makeElement(category, spec, geometry) {
|
|
7001
|
+
#makeElement(category, spec, geometry, stableKey) {
|
|
6945
7002
|
const localId = this.#counter.next();
|
|
7003
|
+
if (stableKey !== void 0) {
|
|
7004
|
+
if (this.#usedStableKeys.has(stableKey)) throw new Error(`BimModel: duplicate stableKey '${stableKey}'`);
|
|
7005
|
+
this.#usedStableKeys.add(stableKey);
|
|
7006
|
+
}
|
|
6946
7007
|
const el = {
|
|
6947
|
-
guid: deriveIfcGuidSync(makeElementKey(this.#modelScope, category, localId)),
|
|
7008
|
+
guid: deriveIfcGuidSync(stableKey !== void 0 ? `elem:${this.#modelScope}:${stableKey}` : makeElementKey(this.#modelScope, category, localId)),
|
|
6948
7009
|
localId,
|
|
6949
7010
|
category,
|
|
6950
7011
|
spec,
|
|
@@ -7191,9 +7252,11 @@ function stairFlightToSolid(spec) {
|
|
|
7191
7252
|
if (spec.riserHeight <= 0) return (0, brepjs.err)(specError("STAIR_FLIGHT_ZERO_RISER", "Stair flight riserHeight must be positive"));
|
|
7192
7253
|
if (spec.treadLength <= 0) return (0, brepjs.err)(specError("STAIR_FLIGHT_ZERO_TREAD", "Stair flight treadLength must be positive"));
|
|
7193
7254
|
if (!Number.isInteger(spec.numberOfRisers) || spec.numberOfRisers < 1) return (0, brepjs.err)(specError("STAIR_FLIGHT_BAD_RISERS", "Stair flight numberOfRisers must be a positive integer"));
|
|
7194
|
-
const
|
|
7255
|
+
const silhouette = buildSilhouette$1(spec.numberOfRisers, spec.riserHeight, spec.treadLength);
|
|
7256
|
+
const profileResult = (0, brepjs.polygon)(silhouette);
|
|
7195
7257
|
if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "STAIR_FLIGHT_PROFILE_FAILED", "Failed to create stair flight silhouette profile"));
|
|
7196
|
-
const
|
|
7258
|
+
const profile = _usingCtx$5.u(profileResult.value);
|
|
7259
|
+
const solidResult = (0, brepjs.extrude)(profile, [
|
|
7197
7260
|
0,
|
|
7198
7261
|
spec.width,
|
|
7199
7262
|
0
|
|
@@ -7349,7 +7412,7 @@ function isIfcSchema(value) {
|
|
|
7349
7412
|
* linear-infrastructure entities). Entities absent from every per-schema set are
|
|
7350
7413
|
* treated as schema-agnostic and supported everywhere (open-world default).
|
|
7351
7414
|
*/
|
|
7352
|
-
var IFC4X3_ONLY_ENTITIES = new Set([
|
|
7415
|
+
var IFC4X3_ONLY_ENTITIES = /* @__PURE__ */ new Set([
|
|
7353
7416
|
"IfcAlignment",
|
|
7354
7417
|
"IfcAlignmentHorizontal",
|
|
7355
7418
|
"IfcAlignmentVertical",
|
|
@@ -7429,7 +7492,8 @@ var IfcWriter = class IfcWriter {
|
|
|
7429
7492
|
try {
|
|
7430
7493
|
const api = new web_ifc.IfcAPI();
|
|
7431
7494
|
await initIfcApi(api);
|
|
7432
|
-
|
|
7495
|
+
const modelId = api.CreateModel({ schema: fileSchemaString(ifcSchema) });
|
|
7496
|
+
return (0, brepjs.ok)(new IfcWriter(api, modelId, mvdViewDefinition, header));
|
|
7433
7497
|
} catch (e) {
|
|
7434
7498
|
return (0, brepjs.err)(ifcError("IFC_INIT_FAILED", "Failed to initialize web-ifc", e));
|
|
7435
7499
|
}
|
|
@@ -7483,8 +7547,10 @@ var IfcWriter = class IfcWriter {
|
|
|
7483
7547
|
let head = new TextDecoder().decode(bytes.subarray(0, HEADER_SCAN));
|
|
7484
7548
|
if (FILE_NAME_RE.test(head)) head = head.replace(FILE_NAME_RE, (_m, prefix, systems) => `${prefix}(${stepString(this.#author)}),(${stepString(this.#organization)}),${systems},${stepString("")})`);
|
|
7485
7549
|
else console.warn("IfcWriter: FILE_NAME null-field pattern not found; author/organization/authorization left unpatched");
|
|
7486
|
-
if (this.#mvdViewDefinition.length > 0)
|
|
7487
|
-
|
|
7550
|
+
if (this.#mvdViewDefinition.length > 0) {
|
|
7551
|
+
if (VIEW_DEFINITION_RE.test(head)) head = head.replace(VIEW_DEFINITION_RE, `ViewDefinition [${this.#mvdViewDefinition}]`);
|
|
7552
|
+
else console.warn(`IfcWriter: FILE_DESCRIPTION ViewDefinition not found; MVD "${this.#mvdViewDefinition}" not declared`);
|
|
7553
|
+
}
|
|
7488
7554
|
const patchedHeadBytes = new TextEncoder().encode(head);
|
|
7489
7555
|
const tail = bytes.subarray(HEADER_SCAN);
|
|
7490
7556
|
const out = new Uint8Array(patchedHeadBytes.byteLength + tail.byteLength);
|
|
@@ -9403,9 +9469,11 @@ function rampFlightToSolid(spec) {
|
|
|
9403
9469
|
if (spec.slope <= 0) return (0, brepjs.err)(specError("RAMP_FLIGHT_ZERO_SLOPE", "Ramp flight slope must be positive"));
|
|
9404
9470
|
if (spec.thickness <= 0) return (0, brepjs.err)(specError("RAMP_FLIGHT_ZERO_THICKNESS", "Ramp flight thickness must be positive"));
|
|
9405
9471
|
const rise = spec.length * spec.slope;
|
|
9406
|
-
const
|
|
9472
|
+
const silhouette = buildSilhouette(spec.length, rise, spec.thickness);
|
|
9473
|
+
const profileResult = (0, brepjs.polygon)(silhouette);
|
|
9407
9474
|
if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "RAMP_FLIGHT_PROFILE_FAILED", "Failed to create ramp flight silhouette profile"));
|
|
9408
|
-
const
|
|
9475
|
+
const profile = _usingCtx$3.u(profileResult.value);
|
|
9476
|
+
const solidResult = (0, brepjs.extrude)(profile, [
|
|
9409
9477
|
0,
|
|
9410
9478
|
spec.width,
|
|
9411
9479
|
0
|
|
@@ -11731,7 +11799,7 @@ function isSlabOpening(spec) {
|
|
|
11731
11799
|
* instead, and OPENINGs are tied to their host through VOIDS rels — neither
|
|
11732
11800
|
* participates in containment, so excluding them here avoids false orphans.
|
|
11733
11801
|
*/
|
|
11734
|
-
var CONTAINABLE_CATEGORIES = new Set([
|
|
11802
|
+
var CONTAINABLE_CATEGORIES = /* @__PURE__ */ new Set([
|
|
11735
11803
|
"WALL",
|
|
11736
11804
|
"SLAB",
|
|
11737
11805
|
"BEAM",
|
|
@@ -12528,14 +12596,15 @@ async function toIfcValidated(model, meta) {
|
|
|
12528
12596
|
const geometry = collectGeometryIssues(model);
|
|
12529
12597
|
const schema = await checkSchema(bytes);
|
|
12530
12598
|
const roundTrip = await checkRoundTrip(bytes);
|
|
12599
|
+
const report = { issues: [
|
|
12600
|
+
...integrity.issues,
|
|
12601
|
+
...geometry.issues,
|
|
12602
|
+
...schema.issues,
|
|
12603
|
+
...roundTrip.issues
|
|
12604
|
+
] };
|
|
12531
12605
|
return (0, brepjs.ok)({
|
|
12532
12606
|
bytes,
|
|
12533
|
-
report
|
|
12534
|
-
...integrity.issues,
|
|
12535
|
-
...geometry.issues,
|
|
12536
|
-
...schema.issues,
|
|
12537
|
-
...roundTrip.issues
|
|
12538
|
-
] }
|
|
12607
|
+
report
|
|
12539
12608
|
});
|
|
12540
12609
|
}
|
|
12541
12610
|
/**
|
|
@@ -12756,7 +12825,7 @@ var SpfReader = class SpfReader {
|
|
|
12756
12825
|
};
|
|
12757
12826
|
//#endregion
|
|
12758
12827
|
//#region src/import/spatialTree.ts
|
|
12759
|
-
var CATEGORY_BY_TYPE = new Map([
|
|
12828
|
+
var CATEGORY_BY_TYPE = /* @__PURE__ */ new Map([
|
|
12760
12829
|
[web_ifc.IFCPROJECT, "PROJECT"],
|
|
12761
12830
|
[web_ifc.IFCSITE, "SITE"],
|
|
12762
12831
|
[web_ifc.IFCBUILDING, "BUILDING"],
|
|
@@ -12938,7 +13007,8 @@ function reconstructExtrusion(reader, extrusionId, scale, worldTransform, diagno
|
|
|
12938
13007
|
const solidResult = (() => {
|
|
12939
13008
|
try {
|
|
12940
13009
|
var _usingCtx$1 = _usingCtx();
|
|
12941
|
-
|
|
13010
|
+
const face = _usingCtx$1.u(faceResult.value);
|
|
13011
|
+
return (0, brepjs.extrude)(face, extrudeVec);
|
|
12942
13012
|
} catch (_) {
|
|
12943
13013
|
_usingCtx$1.e = _;
|
|
12944
13014
|
} finally {
|
|
@@ -12991,10 +13061,12 @@ function reconstructRevolution(reader, revolutionId, scale, worldTransform, diag
|
|
|
12991
13061
|
const revolved = (() => {
|
|
12992
13062
|
try {
|
|
12993
13063
|
var _usingCtx3 = _usingCtx();
|
|
12994
|
-
|
|
13064
|
+
const face = _usingCtx3.u(faceResult.value);
|
|
13065
|
+
const angleDeg = angleRaw * readPlaneAngleScale(reader) * (180 / Math.PI);
|
|
13066
|
+
return (0, brepjs.revolve)(face, {
|
|
12995
13067
|
at: center,
|
|
12996
13068
|
axis: direction,
|
|
12997
|
-
angle:
|
|
13069
|
+
angle: angleDeg
|
|
12998
13070
|
});
|
|
12999
13071
|
} catch (_) {
|
|
13000
13072
|
_usingCtx3.e = _;
|
|
@@ -13109,7 +13181,7 @@ function packBinaryStl(vertices, indices, scaleToMm) {
|
|
|
13109
13181
|
}
|
|
13110
13182
|
return new Uint8Array(buffer);
|
|
13111
13183
|
}
|
|
13112
|
-
var PARAMETRIC_PROFILE_BUILDERS = new Map([
|
|
13184
|
+
var PARAMETRIC_PROFILE_BUILDERS = /* @__PURE__ */ new Map([
|
|
13113
13185
|
[web_ifc.IFCRECTANGLEPROFILEDEF, (f) => ({
|
|
13114
13186
|
kind: "RECTANGULAR",
|
|
13115
13187
|
width: f("XDim"),
|
|
@@ -13877,14 +13949,15 @@ async function fromIfc(bytes, options = {}) {
|
|
|
13877
13949
|
}
|
|
13878
13950
|
const report = appendIssues(emptyReport(), diagnostics);
|
|
13879
13951
|
const applicationName = readApplicationName(reader);
|
|
13880
|
-
|
|
13952
|
+
const model = {
|
|
13881
13953
|
schema: reader.schema,
|
|
13882
13954
|
spatialTree: spatialRoot === null ? null : mapSpatialNode(spatialRoot),
|
|
13883
13955
|
elements,
|
|
13884
13956
|
byExpressId,
|
|
13885
13957
|
diagnostics: report,
|
|
13886
13958
|
...applicationName !== void 0 ? { applicationName } : {}
|
|
13887
|
-
}
|
|
13959
|
+
};
|
|
13960
|
+
return (0, brepjs.ok)(model);
|
|
13888
13961
|
} catch (e) {
|
|
13889
13962
|
return (0, brepjs.err)(importError("IMPORT_FAILED", "Unexpected failure during IFC import", e));
|
|
13890
13963
|
} finally {
|
|
@@ -14911,7 +14984,7 @@ function parseSlabOpeningInput(input) {
|
|
|
14911
14984
|
* containers (PROJECT/SITE/BUILDING/STOREY), abstract groupings, and the SPACE
|
|
14912
14985
|
* category (which maps to the Space sheet, not Component) are excluded.
|
|
14913
14986
|
*/
|
|
14914
|
-
var COMPONENT_CATEGORIES = new Set([
|
|
14987
|
+
var COMPONENT_CATEGORIES = /* @__PURE__ */ new Set([
|
|
14915
14988
|
"WALL",
|
|
14916
14989
|
"SLAB",
|
|
14917
14990
|
"BEAM",
|
|
@@ -15536,9 +15609,10 @@ function parseIdsXml(xml) {
|
|
|
15536
15609
|
const title = info ? firstChild(info, "title")?.text ?? "" : "";
|
|
15537
15610
|
const specsContainer = firstChild(root, "specifications");
|
|
15538
15611
|
if (specsContainer === void 0) return (0, brepjs.err)(idsError("IDS_INVALID_SCHEMA", "IDS document has no <specifications> element"));
|
|
15612
|
+
const specifications = childrenNamed(specsContainer, "specification").map(parseSpecification);
|
|
15539
15613
|
return (0, brepjs.ok)({
|
|
15540
15614
|
title,
|
|
15541
|
-
specifications
|
|
15615
|
+
specifications
|
|
15542
15616
|
});
|
|
15543
15617
|
}
|
|
15544
15618
|
function parseSpecification(el) {
|
|
@@ -15895,10 +15969,7 @@ function restrictionsOf(facet) {
|
|
|
15895
15969
|
push(facet.system);
|
|
15896
15970
|
push(facet.value);
|
|
15897
15971
|
break;
|
|
15898
|
-
case "Material":
|
|
15899
|
-
push(facet.value);
|
|
15900
|
-
break;
|
|
15901
|
-
case "PartOf": break;
|
|
15972
|
+
case "Material": push(facet.value);
|
|
15902
15973
|
}
|
|
15903
15974
|
return out;
|
|
15904
15975
|
}
|
|
@@ -16298,7 +16369,8 @@ function parseBcfFiles(files) {
|
|
|
16298
16369
|
topics
|
|
16299
16370
|
});
|
|
16300
16371
|
} catch (cause) {
|
|
16301
|
-
|
|
16372
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
16373
|
+
return (0, brepjs.err)(bcfError("BCF_PARSE_FAILED", `Failed to parse BCF container: ${message}`, cause));
|
|
16302
16374
|
}
|
|
16303
16375
|
}
|
|
16304
16376
|
function parseVersion(xml) {
|
|
@@ -16413,6 +16485,210 @@ function assignNum(target, key, value) {
|
|
|
16413
16485
|
if (value !== void 0) target[key] = Number(value);
|
|
16414
16486
|
}
|
|
16415
16487
|
//#endregion
|
|
16488
|
+
//#region src/familiesAdapter.ts
|
|
16489
|
+
/**
|
|
16490
|
+
* brepjs-families -> BimModel adapter. Consumes a resolved element tree and
|
|
16491
|
+
* feeds each element's PRE-DESUGARED props into the parametric specs — the
|
|
16492
|
+
* spec path stays authoritative for IFC (IfcExtrudedAreaSolid + placement),
|
|
16493
|
+
* while the IR path serves the viewport and dedup. GlobalIds derive from
|
|
16494
|
+
* families key paths (stable under reordering), not insertion order.
|
|
16495
|
+
*
|
|
16496
|
+
* Scope: Storey containers, Wall/Slab elements, and wall openings — a
|
|
16497
|
+
* fill-role void (Door/Window family) maps onto addDoor/addWindow, which cut
|
|
16498
|
+
* the wall and wire IfcRelVoidsElement + IfcRelFillsElement; the opening and
|
|
16499
|
+
* filler GlobalIds derive from the synthesized key paths. Anonymous (non-fill)
|
|
16500
|
+
* voids stay IR-only and never reach the spec path.
|
|
16501
|
+
*/
|
|
16502
|
+
var SPEC_DEFAULTS = {
|
|
16503
|
+
origin: [
|
|
16504
|
+
0,
|
|
16505
|
+
0,
|
|
16506
|
+
0
|
|
16507
|
+
],
|
|
16508
|
+
axisX: [
|
|
16509
|
+
1,
|
|
16510
|
+
0,
|
|
16511
|
+
0
|
|
16512
|
+
],
|
|
16513
|
+
axisZ: [
|
|
16514
|
+
0,
|
|
16515
|
+
0,
|
|
16516
|
+
1
|
|
16517
|
+
],
|
|
16518
|
+
materialName: "Default"
|
|
16519
|
+
};
|
|
16520
|
+
var GEOMETRY_PROPS = /* @__PURE__ */ new Set([
|
|
16521
|
+
"voids",
|
|
16522
|
+
"fuse",
|
|
16523
|
+
"transform",
|
|
16524
|
+
"psets"
|
|
16525
|
+
]);
|
|
16526
|
+
/** Total of the resolved geometry's OUTER literal translate chain. The
|
|
16527
|
+
* transform vocabulary is translate-only, so frame differences are exact
|
|
16528
|
+
* subtractions. Parameter-driven translations stop the peel. */
|
|
16529
|
+
function peelTranslates(node) {
|
|
16530
|
+
const total = [
|
|
16531
|
+
0,
|
|
16532
|
+
0,
|
|
16533
|
+
0
|
|
16534
|
+
];
|
|
16535
|
+
let moved = false;
|
|
16536
|
+
let cur = node;
|
|
16537
|
+
while (cur.kind === "Translate") {
|
|
16538
|
+
const v = cur.vector;
|
|
16539
|
+
if (v.kind !== "Vec3Lit") break;
|
|
16540
|
+
total[0] += v.value[0];
|
|
16541
|
+
total[1] += v.value[1];
|
|
16542
|
+
total[2] += v.value[2];
|
|
16543
|
+
moved = true;
|
|
16544
|
+
cur = cur.target;
|
|
16545
|
+
}
|
|
16546
|
+
return {
|
|
16547
|
+
total,
|
|
16548
|
+
moved
|
|
16549
|
+
};
|
|
16550
|
+
}
|
|
16551
|
+
/** Fold the resolved geometry's outer translate chain into the spec placement
|
|
16552
|
+
* origin, so IfcLocalPlacement matches the IR world frame no matter where the
|
|
16553
|
+
* transform came from (family-internal or prop-level). */
|
|
16554
|
+
function composedOrigin(el) {
|
|
16555
|
+
const base = el.props["origin"] ?? [
|
|
16556
|
+
0,
|
|
16557
|
+
0,
|
|
16558
|
+
0
|
|
16559
|
+
];
|
|
16560
|
+
const { total, moved } = peelTranslates(el.geometry);
|
|
16561
|
+
if (!moved && el.props["origin"] === void 0) return void 0;
|
|
16562
|
+
return [
|
|
16563
|
+
base[0] + total[0],
|
|
16564
|
+
base[1] + total[1],
|
|
16565
|
+
base[2] + total[2]
|
|
16566
|
+
];
|
|
16567
|
+
}
|
|
16568
|
+
function stripGeometryProps(props) {
|
|
16569
|
+
const out = {};
|
|
16570
|
+
for (const [k, v] of Object.entries(props)) if (!GEOMETRY_PROPS.has(k)) out[k] = v;
|
|
16571
|
+
return out;
|
|
16572
|
+
}
|
|
16573
|
+
function specInput(el) {
|
|
16574
|
+
const origin = composedOrigin(el);
|
|
16575
|
+
return {
|
|
16576
|
+
...SPEC_DEFAULTS,
|
|
16577
|
+
...stripGeometryProps(el.props),
|
|
16578
|
+
...origin ? { origin } : {},
|
|
16579
|
+
...collectSpecProps(el)
|
|
16580
|
+
};
|
|
16581
|
+
}
|
|
16582
|
+
function collectSpecProps(el) {
|
|
16583
|
+
const psets = el.attributes["psets"];
|
|
16584
|
+
const out = {};
|
|
16585
|
+
if (psets && typeof psets === "object") {
|
|
16586
|
+
const common = psets["Pset_WallCommon"];
|
|
16587
|
+
if (common && typeof common === "object") {
|
|
16588
|
+
const c = common;
|
|
16589
|
+
if (typeof c["IsExternal"] === "boolean") out["isExternal"] = c["IsExternal"];
|
|
16590
|
+
if (typeof c["FireRating"] === "string") out["fireRating"] = c["FireRating"];
|
|
16591
|
+
}
|
|
16592
|
+
}
|
|
16593
|
+
delete out["psets"];
|
|
16594
|
+
return out;
|
|
16595
|
+
}
|
|
16596
|
+
function addFill(model, fill, input, identity) {
|
|
16597
|
+
if (fill.type === "Door") {
|
|
16598
|
+
const parsed = parseDoorSpec(input);
|
|
16599
|
+
if (!parsed.ok) return parsed;
|
|
16600
|
+
return model.addDoor(parsed.value, identity);
|
|
16601
|
+
}
|
|
16602
|
+
if (fill.type === "Window") {
|
|
16603
|
+
const parsed = parseWindowSpec(input);
|
|
16604
|
+
if (!parsed.ok) return parsed;
|
|
16605
|
+
return model.addWindow(parsed.value, identity);
|
|
16606
|
+
}
|
|
16607
|
+
return (0, brepjs.err)(specError("FAMILIES_UNSUPPORTED_FILL", `familiesToBim: no fill mapping for element type '${fill.type}' at '${fill.keyPath}'`));
|
|
16608
|
+
}
|
|
16609
|
+
/** Map a wall's synthesized Opening children onto addDoor/addWindow. The
|
|
16610
|
+
* wall-relative offsets come from the void geometry's frame minus the host's:
|
|
16611
|
+
* exact because both carry the same outer host transform. */
|
|
16612
|
+
function addOpenings(model, host, wallId, containerId, idByKeyPath) {
|
|
16613
|
+
const hostT = peelTranslates(host.geometry).total;
|
|
16614
|
+
for (const opening of host.children) {
|
|
16615
|
+
if (opening.type !== "Opening") continue;
|
|
16616
|
+
const fill = opening.children[0];
|
|
16617
|
+
if (fill === void 0) return (0, brepjs.err)(specError("FAMILIES_OPENING_NO_FILL", `familiesToBim: opening '${opening.keyPath}' has no fill element`));
|
|
16618
|
+
const fillT = peelTranslates(opening.geometry).total;
|
|
16619
|
+
const added = addFill(model, fill, {
|
|
16620
|
+
materialName: SPEC_DEFAULTS.materialName,
|
|
16621
|
+
...stripGeometryProps(fill.props),
|
|
16622
|
+
wallLocalId: wallId,
|
|
16623
|
+
offsetAlongWall: fillT[0] - hostT[0],
|
|
16624
|
+
offsetFromFloor: fillT[2] - hostT[2]
|
|
16625
|
+
}, {
|
|
16626
|
+
stableKey: fill.keyPath,
|
|
16627
|
+
openingStableKey: opening.keyPath
|
|
16628
|
+
});
|
|
16629
|
+
if (!added.ok) return added;
|
|
16630
|
+
model.placeIn(added.value, containerId);
|
|
16631
|
+
idByKeyPath.set(fill.keyPath, added.value);
|
|
16632
|
+
const fillsRel = model.getAllRelationships().find((r) => r.kind === "FILLS_OPENING" && r.fillerLocalId === added.value);
|
|
16633
|
+
if (fillsRel !== void 0) idByKeyPath.set(opening.keyPath, fillsRel.openingLocalId);
|
|
16634
|
+
}
|
|
16635
|
+
return (0, brepjs.ok)(void 0);
|
|
16636
|
+
}
|
|
16637
|
+
/**
|
|
16638
|
+
* Project a resolved families tree into an eager BimModel. The caller owns
|
|
16639
|
+
* the returned model (`using`); families stays domain-neutral — this adapter
|
|
16640
|
+
* is where families types meet the IFC vocabulary.
|
|
16641
|
+
*/
|
|
16642
|
+
function familiesToBim(root, options) {
|
|
16643
|
+
const model = new BimModel();
|
|
16644
|
+
const initResult = model.init(options.project);
|
|
16645
|
+
if (!initResult.ok) return initResult;
|
|
16646
|
+
const siteId = model.addSite({ name: options.siteName ?? "Site" });
|
|
16647
|
+
const buildingId = model.addBuilding({ name: options.buildingName ?? "Building" });
|
|
16648
|
+
model.aggregate(siteId, buildingId);
|
|
16649
|
+
const idByKeyPath = /* @__PURE__ */ new Map();
|
|
16650
|
+
const walk = (el, storeyId) => {
|
|
16651
|
+
let containerId = storeyId;
|
|
16652
|
+
if (el.type === "Storey") {
|
|
16653
|
+
const id = model.addStorey({
|
|
16654
|
+
name: el.attributes["name"] ?? el.keyPath,
|
|
16655
|
+
elevation: el.props["elevation"] ?? 0
|
|
16656
|
+
}, { stableKey: el.keyPath });
|
|
16657
|
+
model.aggregate(buildingId, id);
|
|
16658
|
+
idByKeyPath.set(el.keyPath, id);
|
|
16659
|
+
containerId = id;
|
|
16660
|
+
} else if (el.type === "Wall" || el.type === "Slab") {
|
|
16661
|
+
const parsed = el.type === "Wall" ? parseWallSpec(specInput(el)) : parseSlabSpec(specInput(el));
|
|
16662
|
+
if (!parsed.ok) return parsed;
|
|
16663
|
+
const added = el.type === "Wall" ? model.addWall(parsed.value, { stableKey: el.keyPath }) : model.addSlab(parsed.value, { stableKey: el.keyPath });
|
|
16664
|
+
if (!added.ok) return added;
|
|
16665
|
+
idByKeyPath.set(el.keyPath, added.value);
|
|
16666
|
+
if (containerId === null) return (0, brepjs.err)(specError("FAMILIES_NO_STOREY", `familiesToBim: '${el.keyPath}' has no Storey ancestor — IFC elements need spatial containment`));
|
|
16667
|
+
model.placeIn(added.value, containerId);
|
|
16668
|
+
if (el.type === "Wall") {
|
|
16669
|
+
const opened = addOpenings(model, el, added.value, containerId, idByKeyPath);
|
|
16670
|
+
if (!opened.ok) return opened;
|
|
16671
|
+
}
|
|
16672
|
+
} else if (el.type === "Opening") return (0, brepjs.err)(specError("FAMILIES_OPENING_OUTSIDE_WALL", `familiesToBim: opening '${el.keyPath}' is not hosted by a Wall — only wall openings are mapped`));
|
|
16673
|
+
else if (el.type !== "Group" && el.geometry.kind !== "Empty") return (0, brepjs.err)(specError("FAMILIES_UNSUPPORTED_TYPE", `familiesToBim: no spec mapping for element type '${el.type}' at '${el.keyPath}'`));
|
|
16674
|
+
for (const child of el.children) {
|
|
16675
|
+
if (el.type === "Wall" && child.type === "Opening") continue;
|
|
16676
|
+
const r = walk(child, containerId);
|
|
16677
|
+
if (!r.ok) return r;
|
|
16678
|
+
}
|
|
16679
|
+
return (0, brepjs.ok)(void 0);
|
|
16680
|
+
};
|
|
16681
|
+
const walked = walk(root, null);
|
|
16682
|
+
if (!walked.ok) {
|
|
16683
|
+
model[Symbol.dispose]();
|
|
16684
|
+
return walked;
|
|
16685
|
+
}
|
|
16686
|
+
return (0, brepjs.ok)({
|
|
16687
|
+
model,
|
|
16688
|
+
idByKeyPath
|
|
16689
|
+
});
|
|
16690
|
+
}
|
|
16691
|
+
//#endregion
|
|
16416
16692
|
exports.BimModel = BimModel;
|
|
16417
16693
|
exports.DEFAULT_IFC_SCHEMA = DEFAULT_IFC_SCHEMA;
|
|
16418
16694
|
exports.DEFAULT_UNITS = DEFAULT_UNITS;
|
|
@@ -16436,6 +16712,7 @@ exports.emptyReport = emptyReport;
|
|
|
16436
16712
|
exports.exportCobie = deriveCobieModel;
|
|
16437
16713
|
exports.extendedProfileArea = extendedProfileArea;
|
|
16438
16714
|
exports.extendedProfileToFace = extendedProfileToFace;
|
|
16715
|
+
exports.familiesToBim = familiesToBim;
|
|
16439
16716
|
exports.fileSchemaString = fileSchemaString;
|
|
16440
16717
|
exports.fromBrepError = fromBrepError;
|
|
16441
16718
|
exports.fromIfc = fromIfc;
|