brepjs-bim 0.16.0 → 0.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7804,9 +7804,42 @@ function writeHeader(w, meta) {
7804
7804
  ownerHistoryId,
7805
7805
  geomContextId,
7806
7806
  geomSubContextId,
7807
- unitAssignmentId
7807
+ unitAssignmentId,
7808
+ lengthUnitId
7808
7809
  };
7809
7810
  }
7811
+ /**
7812
+ * Writes IfcProjectedCRS + IfcMapConversion georeferencing the model context
7813
+ * (GRF003). Coordinates are metres; rotation defaults to identity.
7814
+ */
7815
+ function writeMapConversion(w, crs, geomContextId, lengthUnitId) {
7816
+ const crsId = w.nextId();
7817
+ w.writeLine({
7818
+ expressID: crsId,
7819
+ type: web_ifc.IFCPROJECTEDCRS,
7820
+ Name: w.mkType(web_ifc.IFCLABEL, crs.name),
7821
+ Description: crs.description !== void 0 ? w.mkType(web_ifc.IFCTEXT, crs.description) : null,
7822
+ GeodeticDatum: crs.geodeticDatum !== void 0 ? w.mkType(web_ifc.IFCIDENTIFIER, crs.geodeticDatum) : null,
7823
+ VerticalDatum: crs.verticalDatum !== void 0 ? w.mkType(web_ifc.IFCIDENTIFIER, crs.verticalDatum) : null,
7824
+ MapProjection: crs.mapProjection !== void 0 ? w.mkType(web_ifc.IFCIDENTIFIER, crs.mapProjection) : null,
7825
+ MapZone: crs.mapZone !== void 0 ? w.mkType(web_ifc.IFCIDENTIFIER, crs.mapZone) : null,
7826
+ MapUnit: w.ref(lengthUnitId)
7827
+ });
7828
+ const conversionId = w.nextId();
7829
+ w.writeLine({
7830
+ expressID: conversionId,
7831
+ type: web_ifc.IFCMAPCONVERSION,
7832
+ SourceCRS: w.ref(geomContextId),
7833
+ TargetCRS: w.ref(crsId),
7834
+ Eastings: w.mkType(web_ifc.IFCLENGTHMEASURE, crs.eastings ?? 0),
7835
+ Northings: w.mkType(web_ifc.IFCLENGTHMEASURE, crs.northings ?? 0),
7836
+ OrthogonalHeight: w.mkType(web_ifc.IFCLENGTHMEASURE, crs.orthogonalHeight ?? 0),
7837
+ XAxisAbscissa: crs.xAxisAbscissa !== void 0 ? w.mkType(web_ifc.IFCREAL, crs.xAxisAbscissa) : null,
7838
+ XAxisOrdinate: crs.xAxisOrdinate !== void 0 ? w.mkType(web_ifc.IFCREAL, crs.xAxisOrdinate) : null,
7839
+ Scale: crs.scale !== void 0 ? w.mkType(web_ifc.IFCREAL, crs.scale) : null
7840
+ });
7841
+ return crsId;
7842
+ }
7810
7843
  function writeAxis2Placement3D(w, origin = [
7811
7844
  0,
7812
7845
  0,
@@ -9572,12 +9605,56 @@ function writeStairFlightEntity(w, guid, name, flight, ownerHistoryId, localPlac
9572
9605
  ObjectPlacement: w.ref(localPlacementId),
9573
9606
  Representation: w.ref(productDefinitionShapeId),
9574
9607
  Tag: null,
9575
- NumberOfRisers: w.mkType(web_ifc.IFCINTEGER, flight.numberOfRisers),
9576
- NumberOfTreads: w.mkType(web_ifc.IFCINTEGER, flight.numberOfRisers - 1),
9577
- RiserHeight: w.mkType(web_ifc.IFCPOSITIVELENGTHMEASURE, toIfcLengthM(flight.riserHeight)),
9578
- TreadLength: w.mkType(web_ifc.IFCPOSITIVELENGTHMEASURE, toIfcLengthM(flight.treadLength)),
9608
+ NumberOfRisers: null,
9609
+ NumberOfTreads: null,
9610
+ RiserHeight: null,
9611
+ TreadLength: null,
9579
9612
  PredefinedType: null
9580
9613
  });
9614
+ writeStairFlightCommonPset(w, ownerHistoryId, id, flight);
9615
+ return id;
9616
+ }
9617
+ /** Pset_StairFlightCommon: the standard home for the flight geometry data the
9618
+ * deprecated IfcStairFlight attributes used to carry. Note the standard's
9619
+ * singular `NumberOfRiser`. */
9620
+ function writeStairFlightCommonPset(w, ownerHistoryId, flightExpressId, flight) {
9621
+ const props = [
9622
+ writeSingleValue(w, "NumberOfRiser", w.mkType(web_ifc.IFCCOUNTMEASURE, flight.numberOfRisers)),
9623
+ writeSingleValue(w, "NumberOfTreads", w.mkType(web_ifc.IFCCOUNTMEASURE, flight.numberOfRisers - 1)),
9624
+ writeSingleValue(w, "RiserHeight", w.mkType(web_ifc.IFCPOSITIVELENGTHMEASURE, toIfcLengthM(flight.riserHeight))),
9625
+ writeSingleValue(w, "TreadLength", w.mkType(web_ifc.IFCPOSITIVELENGTHMEASURE, toIfcLengthM(flight.treadLength)))
9626
+ ];
9627
+ const psetId = w.nextId();
9628
+ w.writeLine({
9629
+ expressID: psetId,
9630
+ type: web_ifc.IFCPROPERTYSET,
9631
+ GlobalId: w.mkType(web_ifc.IFCGLOBALLYUNIQUEID, w.guidFor(psetId)),
9632
+ OwnerHistory: w.ref(ownerHistoryId),
9633
+ Name: w.mkType(web_ifc.IFCLABEL, "Pset_StairFlightCommon"),
9634
+ Description: null,
9635
+ HasProperties: props.map((id) => w.ref(id))
9636
+ });
9637
+ w.writeLine({
9638
+ expressID: w.nextId(),
9639
+ type: web_ifc.IFCRELDEFINESBYPROPERTIES,
9640
+ GlobalId: w.mkType(web_ifc.IFCGLOBALLYUNIQUEID, w.guidFor(psetId + 1e5)),
9641
+ OwnerHistory: w.ref(ownerHistoryId),
9642
+ Name: null,
9643
+ Description: null,
9644
+ RelatedObjects: [w.ref(flightExpressId)],
9645
+ RelatingPropertyDefinition: w.ref(psetId)
9646
+ });
9647
+ }
9648
+ function writeSingleValue(w, name, value) {
9649
+ const id = w.nextId();
9650
+ w.writeLine({
9651
+ expressID: id,
9652
+ type: web_ifc.IFCPROPERTYSINGLEVALUE,
9653
+ Name: w.mkType(web_ifc.IFCIDENTIFIER, name),
9654
+ Description: null,
9655
+ NominalValue: value,
9656
+ Unit: null
9657
+ });
9581
9658
  return id;
9582
9659
  }
9583
9660
  function writeStairEntity(w, guid, name, _predefinedType, ownerHistoryId, localPlacementId) {
@@ -11088,12 +11165,11 @@ function writeRoofBaseQuantities(w, ownerHistoryId, roofExpressId, spec) {
11088
11165
  const widthM = toIfcLengthM(spec.width);
11089
11166
  const thicknessM = toIfcLengthM(spec.thickness);
11090
11167
  const grossAreaM2 = lengthM * widthM;
11091
- const grossVolumeM3 = grossAreaM2 * thicknessM;
11168
+ grossAreaM2 * thicknessM;
11092
11169
  writeRelDefinesByProperties(w, ownerHistoryId, roofExpressId, writeElementQuantity(w, ownerHistoryId, "Qto_RoofBaseQuantities", [
11093
11170
  writeQtyArea(w, "GrossArea", grossAreaM2),
11094
11171
  writeQtyArea(w, "NetArea", grossAreaM2),
11095
- writeQtyVolume(w, "GrossVolume", grossVolumeM3),
11096
- writeQtyVolume(w, "NetVolume", grossVolumeM3)
11172
+ writeQtyArea(w, "ProjectedArea", grossAreaM2)
11097
11173
  ]));
11098
11174
  }
11099
11175
  function writeCurtainWallCommonPset(w, ownerHistoryId, curtainWallExpressId, spec) {
@@ -11120,7 +11196,7 @@ function writeFootingBaseQuantities(w, ownerHistoryId, footingExpressId, spec) {
11120
11196
  writeRelDefinesByProperties(w, ownerHistoryId, footingExpressId, writeElementQuantity(w, ownerHistoryId, "Qto_FootingBaseQuantities", [
11121
11197
  writeQtyLength(w, "Length", lengthM),
11122
11198
  writeQtyLength(w, "Width", widthM),
11123
- writeQtyLength(w, "Depth", depthM),
11199
+ writeQtyLength(w, "Height", depthM),
11124
11200
  writeQtyVolume(w, "GrossVolume", grossVolumeM3),
11125
11201
  writeQtyVolume(w, "NetVolume", grossVolumeM3)
11126
11202
  ]));
@@ -12068,6 +12144,918 @@ async function checkRoundTrip(bytes) {
12068
12144
  };
12069
12145
  }
12070
12146
  //#endregion
12147
+ //#region src/import/spfReader.ts
12148
+ var SUPPORTED_SCHEMAS = [
12149
+ "IFC2X3",
12150
+ "IFC4",
12151
+ "IFC4X3"
12152
+ ];
12153
+ /**
12154
+ * Foundation layer of the IFC reader: owns the web-ifc WASM model handle and
12155
+ * exposes typed line access, GUID↔expressId lookup, world-transform composition,
12156
+ * geometry-engine access and STEP string decoding.
12157
+ *
12158
+ * Lifecycle: created via the static async {@link SpfReader.create}; the caller
12159
+ * MUST call {@link SpfReader.close} (it always issues `CloseModel`, preventing
12160
+ * WASM handle leaks). The handle is `using`-friendly via `Symbol.dispose`.
12161
+ */
12162
+ function deleteVector(vec) {
12163
+ vec.delete?.();
12164
+ }
12165
+ var SpfReader = class SpfReader {
12166
+ schema;
12167
+ modelId;
12168
+ #api;
12169
+ #closed = false;
12170
+ #linesByType = /* @__PURE__ */ new Map();
12171
+ constructor(api, modelId, schema) {
12172
+ this.#api = api;
12173
+ this.modelId = modelId;
12174
+ this.schema = schema;
12175
+ }
12176
+ static async create(bytes, settings = {}) {
12177
+ let api;
12178
+ try {
12179
+ api = new web_ifc.IfcAPI();
12180
+ await initIfcApi(api);
12181
+ } catch (e) {
12182
+ return (0, brepjs.err)(importError("OPEN_MODEL_FAILED", "Failed to initialize web-ifc", e));
12183
+ }
12184
+ let modelId;
12185
+ try {
12186
+ modelId = api.OpenModel(bytes, { COORDINATE_TO_ORIGIN: settings.coordinateToOrigin ?? false });
12187
+ } catch (e) {
12188
+ return (0, brepjs.err)(importError("OPEN_MODEL_FAILED", "web-ifc OpenModel threw", e));
12189
+ }
12190
+ if (modelId < 0 || !api.IsModelOpen(modelId)) {
12191
+ if (modelId >= 0) api.CloseModel(modelId);
12192
+ return (0, brepjs.err)(importError("OPEN_MODEL_FAILED", "web-ifc OpenModel returned an invalid model id"));
12193
+ }
12194
+ const schemaRaw = api.GetModelSchema(modelId);
12195
+ if (!SUPPORTED_SCHEMAS.includes(schemaRaw)) {
12196
+ api.CloseModel(modelId);
12197
+ return (0, brepjs.err)(importError("SCHEMA_UNSUPPORTED", `Unsupported IFC schema "${schemaRaw}"`));
12198
+ }
12199
+ return (0, brepjs.ok)(new SpfReader(api, modelId, schemaRaw));
12200
+ }
12201
+ /** Always issues CloseModel; safe to call more than once. */
12202
+ close() {
12203
+ if (this.#closed) return;
12204
+ this.#closed = true;
12205
+ this.#api.CloseModel(this.modelId);
12206
+ }
12207
+ [Symbol.dispose]() {
12208
+ this.close();
12209
+ }
12210
+ /**
12211
+ * Raw line object for an express id. With `flatten=false` (default) references
12212
+ * appear as `{ type, value }` wrappers and nested entities are not resolved;
12213
+ * pass `flatten=true` to recursively inline referenced lines.
12214
+ */
12215
+ getLine(expressId, flatten = false) {
12216
+ return this.#api.GetLine(this.modelId, expressId, flatten) ?? null;
12217
+ }
12218
+ /** Express ids of every line whose type equals `type` (no inherited types). */
12219
+ getLinesOfType(type) {
12220
+ const cached = this.#linesByType.get(type);
12221
+ if (cached !== void 0) return cached;
12222
+ const vec = this.#api.GetLineIDsWithType(this.modelId, type);
12223
+ const out = [];
12224
+ for (let i = 0; i < vec.size(); i++) out.push(vec.get(i));
12225
+ deleteVector(vec);
12226
+ this.#linesByType.set(type, out);
12227
+ return out;
12228
+ }
12229
+ /** Express ids of every line in the model. */
12230
+ getAllLines() {
12231
+ const vec = this.#api.GetAllLines(this.modelId);
12232
+ const out = [];
12233
+ for (let i = 0; i < vec.size(); i++) out.push(vec.get(i));
12234
+ deleteVector(vec);
12235
+ return out;
12236
+ }
12237
+ /** IFC type code for an express id. */
12238
+ /** Uppercased IFC entity name of the instance (e.g. `IFCWALL`). */
12239
+ typeNameOf(expressId) {
12240
+ return this.#api.GetNameFromTypeCode(this.getLineType(expressId)).toUpperCase();
12241
+ }
12242
+ getLineType(expressId) {
12243
+ const t = this.#api.GetLineType(this.modelId, expressId);
12244
+ return typeof t === "number" ? t : Number(t?.value ?? t);
12245
+ }
12246
+ /** Builds web-ifc's internal GUID→expressId index; call before guid lookups. */
12247
+ buildGuidMap() {
12248
+ this.#api.CreateIfcGuidToExpressIdMapping(this.modelId);
12249
+ }
12250
+ /** expressId for a GlobalId, or undefined. Requires {@link buildGuidMap} first. */
12251
+ expressIdFromGuid(guid) {
12252
+ const id = this.#api.GetExpressIdFromGuid(this.modelId, guid);
12253
+ return typeof id === "number" ? id : void 0;
12254
+ }
12255
+ /** GlobalId for an express id, or undefined. Requires {@link buildGuidMap} first. */
12256
+ guidFromExpressId(expressId) {
12257
+ const guid = this.#api.GetGuidFromExpressId(this.modelId, expressId);
12258
+ return typeof guid === "string" ? guid : void 0;
12259
+ }
12260
+ /**
12261
+ * Composed world transform (column-major 16-float matrix) for a placement
12262
+ * express id, resolving the full IfcLocalPlacement chain.
12263
+ */
12264
+ getWorldTransform(placementExpressId) {
12265
+ return this.#api.GetWorldTransformMatrix(this.modelId, placementExpressId);
12266
+ }
12267
+ /** Streams placed meshes for the given product express ids. */
12268
+ streamMeshes(expressIds, cb) {
12269
+ this.#api.StreamMeshes(this.modelId, expressIds, cb);
12270
+ }
12271
+ /** Geometry buffers for a geometry express id; caller MUST call `.delete()`. */
12272
+ getGeometry(geometryExpressId) {
12273
+ return this.#api.GetGeometry(this.modelId, geometryExpressId);
12274
+ }
12275
+ /** Reads a Float32Array view of vertex data from a WASM pointer. */
12276
+ getVertexArray(ptr, size) {
12277
+ return this.#api.GetVertexArray(ptr, size);
12278
+ }
12279
+ /** Reads a Uint32Array view of index data from a WASM pointer. */
12280
+ getIndexArray(ptr, size) {
12281
+ return this.#api.GetIndexArray(ptr, size);
12282
+ }
12283
+ /** Decodes IFC STEP string escapes (`\X2\`, `\S\`, `\X\`) in a raw value. */
12284
+ decodeText(s) {
12285
+ const decoded = this.#api.DecodeText(s);
12286
+ return typeof decoded === "string" ? decoded : s;
12287
+ }
12288
+ };
12289
+ //#endregion
12290
+ //#region src/validation/qtoDefinitions.generated.ts
12291
+ var QTO_DEFINITIONS = {
12292
+ "Qto_ActuatorBaseQuantities": {
12293
+ "entities": ["IFCACTUATOR"],
12294
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12295
+ },
12296
+ "Qto_AirTerminalBaseQuantities": {
12297
+ "entities": ["IFCAIRTERMINAL"],
12298
+ "quantities": {
12299
+ "GrossWeight": "IFCQUANTITYWEIGHT",
12300
+ "Perimeter": "IFCQUANTITYLENGTH",
12301
+ "TotalSurfaceArea": "IFCQUANTITYAREA"
12302
+ }
12303
+ },
12304
+ "Qto_AirTerminalBoxTypeBaseQuantities": {
12305
+ "entities": ["IFCAIRTERMINALBOX"],
12306
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12307
+ },
12308
+ "Qto_AirToAirHeatRecoveryBaseQuantities": {
12309
+ "entities": ["IFCAIRTOAIRHEATRECOVERY"],
12310
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12311
+ },
12312
+ "Qto_AlarmBaseQuantities": {
12313
+ "entities": ["IFCALARM"],
12314
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12315
+ },
12316
+ "Qto_AudioVisualApplianceBaseQuantities": {
12317
+ "entities": ["IFCAUDIOVISUALAPPLIANCE"],
12318
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12319
+ },
12320
+ "Qto_BeamBaseQuantities": {
12321
+ "entities": ["IFCBEAM"],
12322
+ "quantities": {
12323
+ "CrossSectionArea": "IFCQUANTITYAREA",
12324
+ "GrossSurfaceArea": "IFCQUANTITYAREA",
12325
+ "GrossVolume": "IFCQUANTITYVOLUME",
12326
+ "GrossWeight": "IFCQUANTITYWEIGHT",
12327
+ "Length": "IFCQUANTITYLENGTH",
12328
+ "NetSurfaceArea": "IFCQUANTITYAREA",
12329
+ "NetVolume": "IFCQUANTITYVOLUME",
12330
+ "NetWeight": "IFCQUANTITYWEIGHT",
12331
+ "OuterSurfaceArea": "IFCQUANTITYAREA"
12332
+ }
12333
+ },
12334
+ "Qto_BoilerBaseQuantities": {
12335
+ "entities": ["IFCBOILER"],
12336
+ "quantities": {
12337
+ "GrossWeight": "IFCQUANTITYWEIGHT",
12338
+ "NetWeight": "IFCQUANTITYWEIGHT",
12339
+ "TotalSurfaceArea": "IFCQUANTITYAREA"
12340
+ }
12341
+ },
12342
+ "Qto_BuildingBaseQuantities": {
12343
+ "entities": ["IFCBUILDING"],
12344
+ "quantities": {
12345
+ "EavesHeight": "IFCQUANTITYLENGTH",
12346
+ "FootprintArea": "IFCQUANTITYAREA",
12347
+ "GrossFloorArea": "IFCQUANTITYAREA",
12348
+ "GrossVolume": "IFCQUANTITYVOLUME",
12349
+ "Height": "IFCQUANTITYLENGTH",
12350
+ "NetFloorArea": "IFCQUANTITYAREA",
12351
+ "NetVolume": "IFCQUANTITYVOLUME"
12352
+ }
12353
+ },
12354
+ "Qto_BuildingElementProxyQuantities": {
12355
+ "entities": ["IFCBUILDINGELEMENTPROXY"],
12356
+ "quantities": {
12357
+ "NetSurfaceArea": "IFCQUANTITYCOUNT",
12358
+ "NetVolume": "IFCQUANTITYCOUNT"
12359
+ }
12360
+ },
12361
+ "Qto_BuildingStoreyBaseQuantities": {
12362
+ "entities": ["IFCBUILDINGSTOREY"],
12363
+ "quantities": {
12364
+ "GrossFloorArea": "IFCQUANTITYAREA",
12365
+ "GrossHeight": "IFCQUANTITYLENGTH",
12366
+ "GrossPerimeter": "IFCQUANTITYLENGTH",
12367
+ "GrossVolume": "IFCQUANTITYVOLUME",
12368
+ "NetFloorArea": "IFCQUANTITYAREA",
12369
+ "NetHeigtht": "IFCQUANTITYLENGTH",
12370
+ "NetVolume": "IFCQUANTITYVOLUME"
12371
+ }
12372
+ },
12373
+ "Qto_BurnerBaseQuantities": {
12374
+ "entities": ["IFCBURNER"],
12375
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12376
+ },
12377
+ "Qto_CableCarrierFittingBaseQuantities": {
12378
+ "entities": ["IFCCABLECARRIERFITTING"],
12379
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12380
+ },
12381
+ "Qto_CableCarrierSegmentBaseQuantities": {
12382
+ "entities": ["IFCCABLECARRIERSEGMENT"],
12383
+ "quantities": {
12384
+ "CrossSectionArea": "IFCQUANTITYAREA",
12385
+ "GrossWeight": "IFCQUANTITYWEIGHT",
12386
+ "Length": "IFCQUANTITYLENGTH",
12387
+ "OuterSurfaceArea": "IFCQUANTITYAREA"
12388
+ }
12389
+ },
12390
+ "Qto_CableFittingBaseQuantities": {
12391
+ "entities": ["IFCCABLEFITTING"],
12392
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12393
+ },
12394
+ "Qto_CableSegmentBaseQuantities": {
12395
+ "entities": ["IFCCABLESEGMENT"],
12396
+ "quantities": {
12397
+ "CrossSectionArea": "IFCQUANTITYAREA",
12398
+ "GrossWeight": "IFCQUANTITYWEIGHT",
12399
+ "Length": "IFCQUANTITYLENGTH",
12400
+ "OuterSurfaceArea": "IFCQUANTITYAREA"
12401
+ }
12402
+ },
12403
+ "Qto_ChillerBaseQuantities": {
12404
+ "entities": ["IFCCHILLER"],
12405
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12406
+ },
12407
+ "Qto_ChimneyBaseQuantities": {
12408
+ "entities": ["IFCCHIMNEY"],
12409
+ "quantities": { "Length": "IFCQUANTITYLENGTH" }
12410
+ },
12411
+ "Qto_CoilBaseQuantities": {
12412
+ "entities": ["IFCCOIL"],
12413
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12414
+ },
12415
+ "Qto_ColumnBaseQuantities": {
12416
+ "entities": ["IFCCOLUMN"],
12417
+ "quantities": {
12418
+ "CrossSectionArea": "IFCQUANTITYAREA",
12419
+ "GrossSurfaceArea": "IFCQUANTITYAREA",
12420
+ "GrossVolume": "IFCQUANTITYVOLUME",
12421
+ "GrossWeight": "IFCQUANTITYWEIGHT",
12422
+ "Length": "IFCQUANTITYLENGTH",
12423
+ "NetSurfaceArea": "IFCQUANTITYAREA",
12424
+ "NetVolume": "IFCQUANTITYVOLUME",
12425
+ "NetWeight": "IFCQUANTITYWEIGHT",
12426
+ "OuterSurfaceArea": "IFCQUANTITYAREA"
12427
+ }
12428
+ },
12429
+ "Qto_CommunicationsApplianceBaseQuantities": {
12430
+ "entities": ["IFCCOMMUNICATIONSAPPLIANCE"],
12431
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12432
+ },
12433
+ "Qto_CompressorBaseQuantities": {
12434
+ "entities": ["IFCCOMPRESSOR"],
12435
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12436
+ },
12437
+ "Qto_CondenserBaseQuantities": {
12438
+ "entities": ["IFCCONDENSER"],
12439
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12440
+ },
12441
+ "Qto_ConstructionEquipmentResourceBaseQuantities": {
12442
+ "entities": ["IFCCONSTRUCTIONEQUIPMENTRESOURCE"],
12443
+ "quantities": {
12444
+ "OperatingTime": "IFCQUANTITYTIME",
12445
+ "UsageTime": "IFCQUANTITYTIME"
12446
+ }
12447
+ },
12448
+ "Qto_ConstructionMaterialResourceBaseQuantities": {
12449
+ "entities": ["IFCCONSTRUCTIONMATERIALRESOURCE"],
12450
+ "quantities": {
12451
+ "GrossVolume": "IFCQUANTITYVOLUME",
12452
+ "GrossWeight": "IFCQUANTITYWEIGHT",
12453
+ "NetVolume": "IFCQUANTITYVOLUME",
12454
+ "NetWeight": "IFCQUANTITYWEIGHT"
12455
+ }
12456
+ },
12457
+ "Qto_ControllerBaseQuantities": {
12458
+ "entities": ["IFCCONTROLLER"],
12459
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12460
+ },
12461
+ "Qto_CooledBeamBaseQuantities": {
12462
+ "entities": ["IFCCOOLEDBEAM"],
12463
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12464
+ },
12465
+ "Qto_CoolingTowerBaseQuantities": {
12466
+ "entities": ["IFCCOOLINGTOWER"],
12467
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12468
+ },
12469
+ "Qto_CoveringBaseQuantities": {
12470
+ "entities": ["IFCCOVERING"],
12471
+ "quantities": {
12472
+ "GrossArea": "IFCQUANTITYAREA",
12473
+ "NetArea": "IFCQUANTITYAREA",
12474
+ "Width": "IFCQUANTITYLENGTH"
12475
+ }
12476
+ },
12477
+ "Qto_CurtainWallQuantities": {
12478
+ "entities": ["IFCCURTAINWALL"],
12479
+ "quantities": {
12480
+ "GrossSideArea": "IFCQUANTITYAREA",
12481
+ "Height": "IFCQUANTITYLENGTH",
12482
+ "Length": "IFCQUANTITYLENGTH",
12483
+ "NetSideArea": "IFCQUANTITYAREA",
12484
+ "Width": "IFCQUANTITYLENGTH"
12485
+ }
12486
+ },
12487
+ "Qto_DamperBaseQuantities": {
12488
+ "entities": ["IFCDAMPER"],
12489
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12490
+ },
12491
+ "Qto_DistributionChamberElementBaseQuantities": {
12492
+ "entities": ["IFCDISTRIBUTIONCHAMBERELEMENT"],
12493
+ "quantities": {
12494
+ "GrossSurfaceArea": "IFCQUANTITYAREA",
12495
+ "GrossVolume": "IFCQUANTITYVOLUME",
12496
+ "NetSurfaceArea": "IFCQUANTITYAREA",
12497
+ "NetVolume": "IFCQUANTITYVOLUME"
12498
+ }
12499
+ },
12500
+ "Qto_DoorBaseQuantities": {
12501
+ "entities": ["IFCDOOR"],
12502
+ "quantities": {
12503
+ "Area": "IFCQUANTITYAREA",
12504
+ "Height": "IFCQUANTITYLENGTH",
12505
+ "Perimeter": "IFCQUANTITYLENGTH",
12506
+ "Width": "IFCQUANTITYLENGTH"
12507
+ }
12508
+ },
12509
+ "Qto_DuctFittingBaseQuantities": {
12510
+ "entities": ["IFCDUCTFITTING"],
12511
+ "quantities": {
12512
+ "GrossCrossSectionArea": "IFCQUANTITYAREA",
12513
+ "GrossWeight": "IFCQUANTITYWEIGHT",
12514
+ "Length": "IFCQUANTITYLENGTH",
12515
+ "NetCrossSectionArea": "IFCQUANTITYAREA",
12516
+ "OuterSurfaceArea": "IFCQUANTITYAREA"
12517
+ }
12518
+ },
12519
+ "Qto_DuctSegmentBaseQuantities": {
12520
+ "entities": ["IFCDUCTSEGMENT"],
12521
+ "quantities": {
12522
+ "GrossCrossSectionArea": "IFCQUANTITYAREA",
12523
+ "GrossWeight": "IFCQUANTITYWEIGHT",
12524
+ "Length": "IFCQUANTITYLENGTH",
12525
+ "NetCrossSectionArea": "IFCQUANTITYAREA",
12526
+ "OuterSurfaceArea": "IFCQUANTITYAREA"
12527
+ }
12528
+ },
12529
+ "Qto_DuctSilencerBaseQuantities": {
12530
+ "entities": ["IFCDUCTSILENCER"],
12531
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12532
+ },
12533
+ "Qto_ElectricApplianceBaseQuantities": {
12534
+ "entities": ["IFCELECTRICAPPLIANCE"],
12535
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12536
+ },
12537
+ "Qto_ElectricDistributionBoardBaseQuantities": {
12538
+ "entities": ["IFCELECTRICDISTRIBUTIONBOARD"],
12539
+ "quantities": {
12540
+ "GrossWeight": "IFCQUANTITYWEIGHT",
12541
+ "NumberOfCircuits": "IFCQUANTITYCOUNT"
12542
+ }
12543
+ },
12544
+ "Qto_ElectricFlowStorageDeviceBaseQuantities": {
12545
+ "entities": ["IFCELECTRICFLOWSTORAGEDEVICE"],
12546
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12547
+ },
12548
+ "Qto_ElectricGeneratorBaseQuantities": {
12549
+ "entities": ["IFCELECTRICGENERATOR"],
12550
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12551
+ },
12552
+ "Qto_ElectricMotorBaseQuantities": {
12553
+ "entities": ["IFCELECTRICMOTOR"],
12554
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12555
+ },
12556
+ "Qto_ElectricTimeControlBaseQuantities": {
12557
+ "entities": ["IFCELECTRICTIMECONTROL"],
12558
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12559
+ },
12560
+ "Qto_EvaporativeCoolerBaseQuantities": {
12561
+ "entities": ["IFCEVAPORATIVECOOLER"],
12562
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12563
+ },
12564
+ "Qto_EvaporatorBaseQuantities": {
12565
+ "entities": ["IFCEVAPORATOR"],
12566
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12567
+ },
12568
+ "Qto_FanBaseQuantities": {
12569
+ "entities": ["IFCFAN"],
12570
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12571
+ },
12572
+ "Qto_FilterBaseQuantities": {
12573
+ "entities": ["IFCFILTER"],
12574
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12575
+ },
12576
+ "Qto_FireSuppressionTerminalBaseQuantities": {
12577
+ "entities": ["IFCFIRESUPPRESSIONTERMINAL"],
12578
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12579
+ },
12580
+ "Qto_FlowInstrumentBaseQuantities": {
12581
+ "entities": ["IFCFLOWINSTRUMENT"],
12582
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12583
+ },
12584
+ "Qto_FlowMeterBaseQuantities": {
12585
+ "entities": ["IFCFLOWMETER"],
12586
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12587
+ },
12588
+ "Qto_FootingBaseQuantities": {
12589
+ "entities": ["IFCFOOTING"],
12590
+ "quantities": {
12591
+ "CrossSectionArea": "IFCQUANTITYAREA",
12592
+ "GrossSurfaceArea": "IFCQUANTITYAREA",
12593
+ "GrossVolume": "IFCQUANTITYVOLUME",
12594
+ "GrossWeight": "IFCQUANTITYWEIGHT",
12595
+ "Height": "IFCQUANTITYLENGTH",
12596
+ "Length": "IFCQUANTITYLENGTH",
12597
+ "NetVolume": "IFCQUANTITYVOLUME",
12598
+ "NetWeight": "IFCQUANTITYWEIGHT",
12599
+ "OuterSurfaceArea": "IFCQUANTITYAREA",
12600
+ "Width": "IFCQUANTITYLENGTH"
12601
+ }
12602
+ },
12603
+ "Qto_HeatExchangerBaseQuantities": {
12604
+ "entities": ["IFCHEATEXCHANGER"],
12605
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12606
+ },
12607
+ "Qto_HumidifierBaseQuantities": {
12608
+ "entities": ["IFCHUMIDIFIER"],
12609
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12610
+ },
12611
+ "Qto_InterceptorBaseQuantities": {
12612
+ "entities": ["IFCINTERCEPTOR"],
12613
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12614
+ },
12615
+ "Qto_JunctionBoxBaseQuantities": {
12616
+ "entities": ["IFCJUNCTIONBOX"],
12617
+ "quantities": {
12618
+ "GrossWeight": "IFCQUANTITYWEIGHT",
12619
+ "NumberOfGangs": "IFCQUANTITYCOUNT"
12620
+ }
12621
+ },
12622
+ "Qto_LaborResourceBaseQuantities": {
12623
+ "entities": ["IFCLABORRESOURCE"],
12624
+ "quantities": {
12625
+ "OvertimeWork": "IFCQUANTITYTIME",
12626
+ "StandardWork": "IFCQUANTITYTIME"
12627
+ }
12628
+ },
12629
+ "Qto_LampBaseQuantities": {
12630
+ "entities": ["IFCLAMP"],
12631
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12632
+ },
12633
+ "Qto_LightFixtureBaseQuantities": {
12634
+ "entities": ["IFCLIGHTFIXTURE"],
12635
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12636
+ },
12637
+ "Qto_MemberBaseQuantities": {
12638
+ "entities": ["IFCMEMBER"],
12639
+ "quantities": {
12640
+ "CrossSectionArea": "IFCQUANTITYAREA",
12641
+ "GrossSurfaceArea": "IFCQUANTITYAREA",
12642
+ "GrossVolume": "IFCQUANTITYVOLUME",
12643
+ "GrossWeight": "IFCQUANTITYWEIGHT",
12644
+ "Length": "IFCQUANTITYLENGTH",
12645
+ "NetSurfaceArea": "IFCQUANTITYAREA",
12646
+ "NetVolume": "IFCQUANTITYVOLUME",
12647
+ "NetWeight": "IFCQUANTITYWEIGHT",
12648
+ "OuterSurfaceArea": "IFCQUANTITYAREA"
12649
+ }
12650
+ },
12651
+ "Qto_MotorConnectionBaseQuantities": {
12652
+ "entities": ["IFCMOTORCONNECTION"],
12653
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12654
+ },
12655
+ "Qto_OpeningElementBaseQuantities": {
12656
+ "entities": ["IFCOPENINGELEMENT"],
12657
+ "quantities": {
12658
+ "Area": "IFCQUANTITYAREA",
12659
+ "Depth": "IFCQUANTITYLENGTH",
12660
+ "Height": "IFCQUANTITYLENGTH",
12661
+ "Volume": "IFCQUANTITYVOLUME",
12662
+ "Width": "IFCQUANTITYLENGTH"
12663
+ }
12664
+ },
12665
+ "Qto_OutletBaseQuantities": {
12666
+ "entities": ["IFCOUTLET"],
12667
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12668
+ },
12669
+ "Qto_PileBaseQuantities": {
12670
+ "entities": ["IFCPILE"],
12671
+ "quantities": {
12672
+ "CrossSectionArea": "IFCQUANTITYAREA",
12673
+ "GrossSurfaceArea": "IFCQUANTITYAREA",
12674
+ "GrossVolume": "IFCQUANTITYVOLUME",
12675
+ "GrossWeight": "IFCQUANTITYWEIGHT",
12676
+ "Length": "IFCQUANTITYLENGTH",
12677
+ "NetVolume": "IFCQUANTITYVOLUME",
12678
+ "NetWeight": "IFCQUANTITYWEIGHT",
12679
+ "OuterSurfaceArea": "IFCQUANTITYAREA"
12680
+ }
12681
+ },
12682
+ "Qto_PipeFittingBaseQuantities": {
12683
+ "entities": ["IFCPIPEFITTING"],
12684
+ "quantities": {
12685
+ "GrossCrossSectionArea": "IFCQUANTITYAREA",
12686
+ "GrossWeight": "IFCQUANTITYWEIGHT",
12687
+ "Length": "IFCQUANTITYLENGTH",
12688
+ "NetCrossSectionArea": "IFCQUANTITYAREA",
12689
+ "NetWeight": "IFCQUANTITYWEIGHT",
12690
+ "OuterSurfaceArea": "IFCQUANTITYAREA"
12691
+ }
12692
+ },
12693
+ "Qto_PipeSegmentBaseQuantities": {
12694
+ "entities": ["IFCPIPESEGMENT"],
12695
+ "quantities": {
12696
+ "GrossCrossSectionArea": "IFCQUANTITYAREA",
12697
+ "GrossWeight": "IFCQUANTITYWEIGHT",
12698
+ "Length": "IFCQUANTITYLENGTH",
12699
+ "NetCrossSectionArea": "IFCQUANTITYAREA",
12700
+ "NetWeight": "IFCQUANTITYWEIGHT",
12701
+ "OuterSurfaceArea": "IFCQUANTITYAREA"
12702
+ }
12703
+ },
12704
+ "Qto_PlateBaseQuantities": {
12705
+ "entities": ["IFCPLATE"],
12706
+ "quantities": {
12707
+ "GrossArea": "IFCQUANTITYAREA",
12708
+ "GrossVolume": "IFCQUANTITYVOLUME",
12709
+ "GrossWeight": "IFCQUANTITYWEIGHT",
12710
+ "NetArea": "IFCQUANTITYAREA",
12711
+ "NetVolume": "IFCQUANTITYVOLUME",
12712
+ "NetWeight": "IFCQUANTITYWEIGHT",
12713
+ "Perimeter": "IFCQUANTITYLENGTH",
12714
+ "Width": "IFCQUANTITYLENGTH"
12715
+ }
12716
+ },
12717
+ "Qto_ProjectionElementBaseQuantities": {
12718
+ "entities": ["IFCPROJECTIONELEMENT"],
12719
+ "quantities": {
12720
+ "Area": "IFCQUANTITYAREA",
12721
+ "Volume": "IFCQUANTITYVOLUME"
12722
+ }
12723
+ },
12724
+ "Qto_ProtectiveDeviceBaseQuantities": {
12725
+ "entities": ["IFCPROTECTIVEDEVICE"],
12726
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12727
+ },
12728
+ "Qto_ProtectiveDeviceTrippingUnitBaseQuantities": {
12729
+ "entities": ["IFCPROTECTIVEDEVICETRIPPINGUNIT"],
12730
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12731
+ },
12732
+ "Qto_PumpBaseQuantities": {
12733
+ "entities": ["IFCPUMP"],
12734
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12735
+ },
12736
+ "Qto_RailingBaseQuantities": {
12737
+ "entities": ["IFCRAILING"],
12738
+ "quantities": { "Length": "IFCQUANTITYLENGTH" }
12739
+ },
12740
+ "Qto_RampFlightBaseQuantities": {
12741
+ "entities": ["IFCRAMPFLIGHT"],
12742
+ "quantities": {
12743
+ "GrossArea": "IFCQUANTITYAREA",
12744
+ "GrossVolume": "IFCQUANTITYVOLUME",
12745
+ "Length": "IFCQUANTITYLENGTH",
12746
+ "NetArea": "IFCQUANTITYAREA",
12747
+ "NetVolume": "IFCQUANTITYVOLUME",
12748
+ "Width": "IFCQUANTITYLENGTH"
12749
+ }
12750
+ },
12751
+ "Qto_ReinforcingElementBaseQuantities": {
12752
+ "entities": ["IFCREINFORCINGELEMENT"],
12753
+ "quantities": {
12754
+ "Count": "IFCQUANTITYCOUNT",
12755
+ "Length": "IFCQUANTITYLENGTH",
12756
+ "Weight": "IFCQUANTITYWEIGHT"
12757
+ }
12758
+ },
12759
+ "Qto_RoofBaseQuantities": {
12760
+ "entities": ["IFCROOF"],
12761
+ "quantities": {
12762
+ "GrossArea": "IFCQUANTITYAREA",
12763
+ "NetArea": "IFCQUANTITYAREA",
12764
+ "ProjectedArea": "IFCQUANTITYAREA"
12765
+ }
12766
+ },
12767
+ "Qto_SanitaryTerminalBaseQuantities": {
12768
+ "entities": ["IFCSANITARYTERMINAL"],
12769
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12770
+ },
12771
+ "Qto_SensorBaseQuantities": {
12772
+ "entities": ["IFCSENSOR"],
12773
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12774
+ },
12775
+ "Qto_SiteBaseQuantities": {
12776
+ "entities": ["IFCSITE"],
12777
+ "quantities": {
12778
+ "GrossArea": "IFCQUANTITYAREA",
12779
+ "GrossPerimeter": "IFCQUANTITYLENGTH"
12780
+ }
12781
+ },
12782
+ "Qto_SlabBaseQuantities": {
12783
+ "entities": ["IFCSLAB"],
12784
+ "quantities": {
12785
+ "Depth": "IFCQUANTITYLENGTH",
12786
+ "GrossArea": "IFCQUANTITYAREA",
12787
+ "GrossVolume": "IFCQUANTITYVOLUME",
12788
+ "GrossWeight": "IFCQUANTITYWEIGHT",
12789
+ "Length": "IFCQUANTITYLENGTH",
12790
+ "NetArea": "IFCQUANTITYAREA",
12791
+ "NetVolume": "IFCQUANTITYVOLUME",
12792
+ "NetWeight": "IFCQUANTITYWEIGHT",
12793
+ "Perimeter": "IFCQUANTITYLENGTH",
12794
+ "Width": "IFCQUANTITYLENGTH"
12795
+ }
12796
+ },
12797
+ "Qto_SolarDeviceBaseQuantities": {
12798
+ "entities": ["IFCSOLARDEVICE"],
12799
+ "quantities": {
12800
+ "GrossArea": "IFCQUANTITYAREA",
12801
+ "GrossWeight": "IFCQUANTITYWEIGHT"
12802
+ }
12803
+ },
12804
+ "Qto_SpaceBaseQuantities": {
12805
+ "entities": ["IFCSPACE"],
12806
+ "quantities": {
12807
+ "FinishCeilingHeight": "IFCQUANTITYLENGTH",
12808
+ "FinishFloorHeight": "IFCQUANTITYLENGTH",
12809
+ "GrossCeilingArea": "IFCQUANTITYAREA",
12810
+ "GrossFloorArea": "IFCQUANTITYAREA",
12811
+ "GrossPerimeter": "IFCQUANTITYLENGTH",
12812
+ "GrossVolume": "IFCQUANTITYVOLUME",
12813
+ "GrossWallArea": "IFCQUANTITYAREA",
12814
+ "Height": "IFCQUANTITYLENGTH",
12815
+ "NetCeilingArea": "IFCQUANTITYAREA",
12816
+ "NetFloorArea": "IFCQUANTITYAREA",
12817
+ "NetPerimeter": "IFCQUANTITYLENGTH",
12818
+ "NetVolume": "IFCQUANTITYVOLUME",
12819
+ "NetWallArea": "IFCQUANTITYAREA"
12820
+ }
12821
+ },
12822
+ "Qto_SpaceHeaterBaseQuantities": {
12823
+ "entities": ["IFCSPACEHEATER"],
12824
+ "quantities": {
12825
+ "GrossWeight": "IFCQUANTITYWEIGHT",
12826
+ "Length": "IFCQUANTITYLENGTH",
12827
+ "NetWeight": "IFCQUANTITYWEIGHT"
12828
+ }
12829
+ },
12830
+ "Qto_StackTerminalBaseQuantities": {
12831
+ "entities": ["IFCSTACKTERMINAL"],
12832
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12833
+ },
12834
+ "Qto_StairFlightBaseQuantities": {
12835
+ "entities": ["IFCSTAIRFLIGHT"],
12836
+ "quantities": {
12837
+ "GrossVolume": "IFCQUANTITYVOLUME",
12838
+ "Length": "IFCQUANTITYLENGTH",
12839
+ "NetVolume": "IFCQUANTITYVOLUME"
12840
+ }
12841
+ },
12842
+ "Qto_SwitchingDeviceBaseQuantities": {
12843
+ "entities": ["IFCSWITCHINGDEVICE"],
12844
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12845
+ },
12846
+ "Qto_TankBaseQuantities": {
12847
+ "entities": ["IFCTANK"],
12848
+ "quantities": {
12849
+ "GrossWeight": "IFCQUANTITYWEIGHT",
12850
+ "NetWeight": "IFCQUANTITYWEIGHT",
12851
+ "TotalSurfaceArea": "IFCQUANTITYAREA"
12852
+ }
12853
+ },
12854
+ "Qto_TransformerBaseQuantities": {
12855
+ "entities": ["IFCTRANSFORMER"],
12856
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12857
+ },
12858
+ "Qto_TubeBundleBaseQuantities": {
12859
+ "entities": ["IFCTUBEBUNDLE"],
12860
+ "quantities": {
12861
+ "GrossWeight": "IFCQUANTITYWEIGHT",
12862
+ "NetWeight": "IFCQUANTITYWEIGHT"
12863
+ }
12864
+ },
12865
+ "Qto_UnitaryControlElementBaseQuantities": {
12866
+ "entities": ["IFCUNITARYCONTROLELEMENT"],
12867
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12868
+ },
12869
+ "Qto_UnitaryEquipmentBaseQuantities": {
12870
+ "entities": ["IFCUNITARYEQUIPMENT"],
12871
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12872
+ },
12873
+ "Qto_ValveBaseQuantities": {
12874
+ "entities": ["IFCVALVE"],
12875
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12876
+ },
12877
+ "Qto_VibrationIsolatorBaseQuantities": {
12878
+ "entities": ["IFCVIBRATIONISOLATOR"],
12879
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12880
+ },
12881
+ "Qto_WallBaseQuantities": {
12882
+ "entities": ["IFCWALL"],
12883
+ "quantities": {
12884
+ "GrossFootprintArea": "IFCQUANTITYAREA",
12885
+ "GrossSideArea": "IFCQUANTITYAREA",
12886
+ "GrossVolume": "IFCQUANTITYVOLUME",
12887
+ "GrossWeight": "IFCQUANTITYWEIGHT",
12888
+ "Height": "IFCQUANTITYLENGTH",
12889
+ "Length": "IFCQUANTITYLENGTH",
12890
+ "NetFootprintArea": "IFCQUANTITYAREA",
12891
+ "NetSideArea": "IFCQUANTITYAREA",
12892
+ "NetVolume": "IFCQUANTITYVOLUME",
12893
+ "NetWeight": "IFCQUANTITYWEIGHT",
12894
+ "Width": "IFCQUANTITYLENGTH"
12895
+ }
12896
+ },
12897
+ "Qto_WasteTerminalBaseQuantities": {
12898
+ "entities": ["IFCWASTETERMINAL"],
12899
+ "quantities": { "GrossWeight": "IFCQUANTITYWEIGHT" }
12900
+ },
12901
+ "Qto_WindowBaseQuantities": {
12902
+ "entities": ["IFCWINDOW"],
12903
+ "quantities": {
12904
+ "Area": "IFCQUANTITYAREA",
12905
+ "Height": "IFCQUANTITYLENGTH",
12906
+ "Perimeter": "IFCQUANTITYLENGTH",
12907
+ "Width": "IFCQUANTITYLENGTH"
12908
+ }
12909
+ }
12910
+ };
12911
+ //#endregion
12912
+ //#region src/validation/gherkinChecks.ts
12913
+ /**
12914
+ * Local implementations of the buildingSMART Validation Service's gherkin
12915
+ * normative rules that apply to the entity vocabulary this writer emits:
12916
+ *
12917
+ * - IFC102 — absence of deprecated entities and attributes (IFC4 lists from
12918
+ * the official rule definition).
12919
+ * - QTY001 — every `Qto_*` element quantity uses the standard set name,
12920
+ * quantity names, quantity entity types, applicable element, and
12921
+ * `MethodOfMeasurement='BaseQuantities'` (table generated from the official
12922
+ * qto_definitions.csv).
12923
+ * - GRF003 — a model containing facilities (IfcBuilding) declares a
12924
+ * coordinate reference system (warning severity, like the service).
12925
+ *
12926
+ * These run inside `toIfcValidated`, so the local gate covers the gherkin
12927
+ * layer before anything is uploaded.
12928
+ */
12929
+ async function checkGherkinRules(bytes) {
12930
+ const readerResult = await SpfReader.create(bytes);
12931
+ if (!readerResult.ok) return [issue("error", "PARSE_FAILED", `Could not open the model: ${readerResult.error.message}`)];
12932
+ const reader = readerResult.value;
12933
+ try {
12934
+ return [
12935
+ ...checkDeprecated(reader),
12936
+ ...checkQuantitySets(reader),
12937
+ ...checkGeoreferencing(reader)
12938
+ ];
12939
+ } finally {
12940
+ reader.close();
12941
+ }
12942
+ }
12943
+ /** IFC4 deprecated entities (IFC102, official rule table). */
12944
+ var DEPRECATED_IFC4_ENTITIES = [
12945
+ "IFC2DCOMPOSITECURVE",
12946
+ "IFCBEAMSTANDARDCASE",
12947
+ "IFCCONNECTIONPORTGEOMETRY",
12948
+ "IFCCOLUMNSTANDARDCASE",
12949
+ "IFCDOORSTANDARDCASE",
12950
+ "IFCDOORSTYLE",
12951
+ "IFCELECTRICALELEMENT",
12952
+ "IFCEQUIPMENTELEMENT",
12953
+ "IFCFACEBASEDSURFACEMODEL",
12954
+ "IFCMATERIALCLASSIFICATIONRELATIONSHIP",
12955
+ "IFCMATERIALLIST",
12956
+ "IFCMEMBERSTANDARDCASE",
12957
+ "IFCOPENINGSTANDARDCASE",
12958
+ "IFCPLATESTANDARDCASE",
12959
+ "IFCPRESENTATIONSTYLEASSIGNMENT",
12960
+ "IFCPROXY",
12961
+ "IFCRELCOVERSBLDGELEMENTS",
12962
+ "IFCRELCOVERSSPACES",
12963
+ "IFCSLABELEMENTEDCASE",
12964
+ "IFCSLABSTANDARDCASE",
12965
+ "IFCTEXTLITERAL",
12966
+ "IFCWALLELEMENTEDCASE",
12967
+ "IFCWALLSTANDARDCASE",
12968
+ "IFCWINDOWSTANDARDCASE",
12969
+ "IFCWINDOWSTYLE"
12970
+ ];
12971
+ /** IFC4 deprecated attributes (IFC102): entity -> attributes that must be empty. */
12972
+ var DEPRECATED_IFC4_ATTRIBUTES = {
12973
+ IFCDOORLININGPROPERTIES: ["ShapeAspectStyle"],
12974
+ IFCDOORPANELPROPERTIES: ["ShapeAspectStyle"],
12975
+ IFCFILLAREASTYLEHATCHING: ["PointOfReferenceHatchLine"],
12976
+ IFCREINFORCINGELEMENT: ["SteelGrade"],
12977
+ IFCRELASSIGNSTOACTOR: ["RelatedObjectsType"],
12978
+ IFCRELASSIGNSTOCONTROL: ["RelatedObjectsType"],
12979
+ IFCRELASSIGNSTOGROUP: ["RelatedObjectsType"],
12980
+ IFCRELASSIGNSTOGROUPBYFACTOR: ["RelatedObjectsType"],
12981
+ IFCRELASSIGNSTOPROCESS: ["RelatedObjectsType"],
12982
+ IFCRELASSIGNSTOPRODUCT: ["RelatedObjectsType"],
12983
+ IFCRELASSIGNSTORESOURCE: ["RelatedObjectsType"],
12984
+ IFCSTAIRFLIGHT: [
12985
+ "NumberOfRisers",
12986
+ "NumberOfTreads",
12987
+ "RiserHeight",
12988
+ "TreadLength"
12989
+ ],
12990
+ IFCWINDOWPANELPROPERTIES: ["ShapeAspectStyle"],
12991
+ IFCWINDOWLININGPROPERTIES: ["ShapeAspectStyle"]
12992
+ };
12993
+ function checkDeprecated(reader) {
12994
+ const issues = [];
12995
+ if (reader.schema !== "IFC4") return issues;
12996
+ for (const id of reader.getAllLines()) {
12997
+ const typeName = reader.typeNameOf(id);
12998
+ if (DEPRECATED_IFC4_ENTITIES.includes(typeName)) {
12999
+ issues.push(issue("error", "DEPRECATED_ENTITY", `#${id} ${typeName} is deprecated in IFC4 (IFC102)`, id));
13000
+ continue;
13001
+ }
13002
+ const attrs = DEPRECATED_IFC4_ATTRIBUTES[typeName];
13003
+ if (attrs === void 0) continue;
13004
+ const line = reader.getLine(id);
13005
+ if (line === null) continue;
13006
+ for (const attr of attrs) if (line[attr] !== null && line[attr] !== void 0) issues.push(issue("error", "DEPRECATED_ATTRIBUTE", `#${id} ${typeName}.${attr} is deprecated in IFC4 and must be empty (IFC102)`, id));
13007
+ }
13008
+ return issues;
13009
+ }
13010
+ function textOf(v) {
13011
+ const value = v?.value;
13012
+ return typeof value === "string" ? value : void 0;
13013
+ }
13014
+ function checkQuantitySets(reader) {
13015
+ const issues = [];
13016
+ const related = /* @__PURE__ */ new Map();
13017
+ for (const relId of reader.getLinesOfType(web_ifc.IFCRELDEFINESBYPROPERTIES)) {
13018
+ const rel = reader.getLine(relId);
13019
+ if (rel === null) continue;
13020
+ const target = rel["RelatingPropertyDefinition"]?.value;
13021
+ if (typeof target !== "number") continue;
13022
+ const objects = rel["RelatedObjects"];
13023
+ if (!Array.isArray(objects)) continue;
13024
+ const names = objects.map((o) => o.value).filter((v) => typeof v === "number").map((id) => reader.typeNameOf(id));
13025
+ related.set(target, [...related.get(target) ?? [], ...names]);
13026
+ }
13027
+ for (const id of reader.getLinesOfType(web_ifc.IFCELEMENTQUANTITY)) {
13028
+ const line = reader.getLine(id);
13029
+ if (line === null) continue;
13030
+ const name = textOf(line["Name"]);
13031
+ if (name === void 0 || !name.startsWith("Qto_")) continue;
13032
+ const definition = QTO_DEFINITIONS[name];
13033
+ if (definition === void 0) {
13034
+ issues.push(issue("error", "QTO_UNKNOWN_SET", `#${id} '${name}' is not a standard quantity set (QTY001)`, id));
13035
+ continue;
13036
+ }
13037
+ if (textOf(line["MethodOfMeasurement"]) !== "BaseQuantities") issues.push(issue("error", "QTO_METHOD", `#${id} '${name}' must declare MethodOfMeasurement='BaseQuantities' (QTY001)`, id));
13038
+ for (const entity of related.get(id) ?? []) if (!definition.entities.includes(entity)) issues.push(issue("error", "QTO_WRONG_ENTITY", `#${id} '${name}' is not applicable to ${entity} (QTY001)`, id));
13039
+ const quantities = line["Quantities"];
13040
+ if (!Array.isArray(quantities)) continue;
13041
+ for (const q of quantities) {
13042
+ const qid = q.value;
13043
+ if (typeof qid !== "number") continue;
13044
+ const qName = textOf(reader.getLine(qid)?.["Name"]);
13045
+ if (qName === void 0) continue;
13046
+ const expectedType = definition.quantities[qName];
13047
+ if (expectedType === void 0) issues.push(issue("error", "QTO_UNKNOWN_QUANTITY", `#${qid} '${qName}' is not defined in ${name} (QTY001)`, qid));
13048
+ else if (reader.typeNameOf(qid) !== expectedType) issues.push(issue("error", "QTO_WRONG_TYPE", `#${qid} '${qName}' must be a ${expectedType} (QTY001)`, qid));
13049
+ }
13050
+ }
13051
+ return issues;
13052
+ }
13053
+ function checkGeoreferencing(reader) {
13054
+ if (!(reader.getLinesOfType(web_ifc.IFCBUILDING).length > 0)) return [];
13055
+ if (reader.getLinesOfType(web_ifc.IFCPROJECTEDCRS).length > 0 || reader.getLinesOfType(web_ifc.IFCGEOGRAPHICCRS).length > 0) return [];
13056
+ return [issue("warning", "NO_GEOREFERENCING", "Model contains a facility but no IfcProjectedCRS/IfcGeographicCRS (GRF003) — set ProjectSpec.crs")];
13057
+ }
13058
+ //#endregion
12071
13059
  //#region src/serialize/toIfc.ts
12072
13060
  async function toIfc(model, meta) {
12073
13061
  const project = model.getProject();
@@ -12101,7 +13089,8 @@ async function toIfc(model, meta) {
12101
13089
  const assemblies = model.getElementAssemblies();
12102
13090
  const zones = model.getZones();
12103
13091
  const systems = model.getSystems();
12104
- const { ownerHistoryId, geomContextId, geomSubContextId, unitAssignmentId } = writeHeader(w, meta);
13092
+ const { ownerHistoryId, geomContextId, geomSubContextId, unitAssignmentId, lengthUnitId } = writeHeader(w, meta);
13093
+ if (project.spec.crs !== void 0) writeMapConversion(w, project.spec.crs, geomContextId, lengthUnitId);
12105
13094
  const densityByElement = buildDensityMap(relationships);
12106
13095
  const idMap = /* @__PURE__ */ new Map();
12107
13096
  const placementMap = /* @__PURE__ */ new Map();
@@ -12602,11 +13591,13 @@ async function toIfcValidated(model, meta) {
12602
13591
  const geometry = collectGeometryIssues(model);
12603
13592
  const schema = await checkSchema(bytes);
12604
13593
  const roundTrip = await checkRoundTrip(bytes);
13594
+ const gherkin = await checkGherkinRules(bytes);
12605
13595
  const report = { issues: [
12606
13596
  ...integrity.issues,
12607
13597
  ...geometry.issues,
12608
13598
  ...schema.issues,
12609
- ...roundTrip.issues
13599
+ ...roundTrip.issues,
13600
+ ...gherkin
12610
13601
  ] };
12611
13602
  return (0, brepjs.ok)({
12612
13603
  bytes,
@@ -12691,149 +13682,6 @@ function findContainerOf(elementId, relationships) {
12691
13682
  return null;
12692
13683
  }
12693
13684
  //#endregion
12694
- //#region src/import/spfReader.ts
12695
- var SUPPORTED_SCHEMAS = [
12696
- "IFC2X3",
12697
- "IFC4",
12698
- "IFC4X3"
12699
- ];
12700
- /**
12701
- * Foundation layer of the IFC reader: owns the web-ifc WASM model handle and
12702
- * exposes typed line access, GUID↔expressId lookup, world-transform composition,
12703
- * geometry-engine access and STEP string decoding.
12704
- *
12705
- * Lifecycle: created via the static async {@link SpfReader.create}; the caller
12706
- * MUST call {@link SpfReader.close} (it always issues `CloseModel`, preventing
12707
- * WASM handle leaks). The handle is `using`-friendly via `Symbol.dispose`.
12708
- */
12709
- function deleteVector(vec) {
12710
- vec.delete?.();
12711
- }
12712
- var SpfReader = class SpfReader {
12713
- schema;
12714
- modelId;
12715
- #api;
12716
- #closed = false;
12717
- #linesByType = /* @__PURE__ */ new Map();
12718
- constructor(api, modelId, schema) {
12719
- this.#api = api;
12720
- this.modelId = modelId;
12721
- this.schema = schema;
12722
- }
12723
- static async create(bytes, settings = {}) {
12724
- let api;
12725
- try {
12726
- api = new web_ifc.IfcAPI();
12727
- await initIfcApi(api);
12728
- } catch (e) {
12729
- return (0, brepjs.err)(importError("OPEN_MODEL_FAILED", "Failed to initialize web-ifc", e));
12730
- }
12731
- let modelId;
12732
- try {
12733
- modelId = api.OpenModel(bytes, { COORDINATE_TO_ORIGIN: settings.coordinateToOrigin ?? false });
12734
- } catch (e) {
12735
- return (0, brepjs.err)(importError("OPEN_MODEL_FAILED", "web-ifc OpenModel threw", e));
12736
- }
12737
- if (modelId < 0 || !api.IsModelOpen(modelId)) {
12738
- if (modelId >= 0) api.CloseModel(modelId);
12739
- return (0, brepjs.err)(importError("OPEN_MODEL_FAILED", "web-ifc OpenModel returned an invalid model id"));
12740
- }
12741
- const schemaRaw = api.GetModelSchema(modelId);
12742
- if (!SUPPORTED_SCHEMAS.includes(schemaRaw)) {
12743
- api.CloseModel(modelId);
12744
- return (0, brepjs.err)(importError("SCHEMA_UNSUPPORTED", `Unsupported IFC schema "${schemaRaw}"`));
12745
- }
12746
- return (0, brepjs.ok)(new SpfReader(api, modelId, schemaRaw));
12747
- }
12748
- /** Always issues CloseModel; safe to call more than once. */
12749
- close() {
12750
- if (this.#closed) return;
12751
- this.#closed = true;
12752
- this.#api.CloseModel(this.modelId);
12753
- }
12754
- [Symbol.dispose]() {
12755
- this.close();
12756
- }
12757
- /**
12758
- * Raw line object for an express id. With `flatten=false` (default) references
12759
- * appear as `{ type, value }` wrappers and nested entities are not resolved;
12760
- * pass `flatten=true` to recursively inline referenced lines.
12761
- */
12762
- getLine(expressId, flatten = false) {
12763
- return this.#api.GetLine(this.modelId, expressId, flatten) ?? null;
12764
- }
12765
- /** Express ids of every line whose type equals `type` (no inherited types). */
12766
- getLinesOfType(type) {
12767
- const cached = this.#linesByType.get(type);
12768
- if (cached !== void 0) return cached;
12769
- const vec = this.#api.GetLineIDsWithType(this.modelId, type);
12770
- const out = [];
12771
- for (let i = 0; i < vec.size(); i++) out.push(vec.get(i));
12772
- deleteVector(vec);
12773
- this.#linesByType.set(type, out);
12774
- return out;
12775
- }
12776
- /** Express ids of every line in the model. */
12777
- getAllLines() {
12778
- const vec = this.#api.GetAllLines(this.modelId);
12779
- const out = [];
12780
- for (let i = 0; i < vec.size(); i++) out.push(vec.get(i));
12781
- deleteVector(vec);
12782
- return out;
12783
- }
12784
- /** IFC type code for an express id. */
12785
- /** Uppercased IFC entity name of the instance (e.g. `IFCWALL`). */
12786
- typeNameOf(expressId) {
12787
- return this.#api.GetNameFromTypeCode(this.getLineType(expressId)).toUpperCase();
12788
- }
12789
- getLineType(expressId) {
12790
- const t = this.#api.GetLineType(this.modelId, expressId);
12791
- return typeof t === "number" ? t : Number(t?.value ?? t);
12792
- }
12793
- /** Builds web-ifc's internal GUID→expressId index; call before guid lookups. */
12794
- buildGuidMap() {
12795
- this.#api.CreateIfcGuidToExpressIdMapping(this.modelId);
12796
- }
12797
- /** expressId for a GlobalId, or undefined. Requires {@link buildGuidMap} first. */
12798
- expressIdFromGuid(guid) {
12799
- const id = this.#api.GetExpressIdFromGuid(this.modelId, guid);
12800
- return typeof id === "number" ? id : void 0;
12801
- }
12802
- /** GlobalId for an express id, or undefined. Requires {@link buildGuidMap} first. */
12803
- guidFromExpressId(expressId) {
12804
- const guid = this.#api.GetGuidFromExpressId(this.modelId, expressId);
12805
- return typeof guid === "string" ? guid : void 0;
12806
- }
12807
- /**
12808
- * Composed world transform (column-major 16-float matrix) for a placement
12809
- * express id, resolving the full IfcLocalPlacement chain.
12810
- */
12811
- getWorldTransform(placementExpressId) {
12812
- return this.#api.GetWorldTransformMatrix(this.modelId, placementExpressId);
12813
- }
12814
- /** Streams placed meshes for the given product express ids. */
12815
- streamMeshes(expressIds, cb) {
12816
- this.#api.StreamMeshes(this.modelId, expressIds, cb);
12817
- }
12818
- /** Geometry buffers for a geometry express id; caller MUST call `.delete()`. */
12819
- getGeometry(geometryExpressId) {
12820
- return this.#api.GetGeometry(this.modelId, geometryExpressId);
12821
- }
12822
- /** Reads a Float32Array view of vertex data from a WASM pointer. */
12823
- getVertexArray(ptr, size) {
12824
- return this.#api.GetVertexArray(ptr, size);
12825
- }
12826
- /** Reads a Uint32Array view of index data from a WASM pointer. */
12827
- getIndexArray(ptr, size) {
12828
- return this.#api.GetIndexArray(ptr, size);
12829
- }
12830
- /** Decodes IFC STEP string escapes (`\X2\`, `\S\`, `\X\`) in a raw value. */
12831
- decodeText(s) {
12832
- const decoded = this.#api.DecodeText(s);
12833
- return typeof decoded === "string" ? decoded : s;
12834
- }
12835
- };
12836
- //#endregion
12837
13685
  //#region src/import/spatialTree.ts
12838
13686
  var CATEGORY_BY_TYPE = /* @__PURE__ */ new Map([
12839
13687
  [web_ifc.IFCPROJECT, "PROJECT"],
@@ -27026,6 +27874,7 @@ exports.PSET_TEMPLATES = PSET_TEMPLATES;
27026
27874
  exports.SpfReader = SpfReader;
27027
27875
  exports.bcfError = bcfError;
27028
27876
  exports.checkGeometryValidity = checkGeometryValidity;
27877
+ exports.checkGherkinRules = checkGherkinRules;
27029
27878
  exports.checkIds = checkIdsData;
27030
27879
  exports.checkIdsData = checkIdsData;
27031
27880
  exports.checkReferentialIntegrity = checkReferentialIntegrity;