@bldrs-ai/conway 1.413.1255 → 1.416.1260
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/compiled/examples/browser-bundled.cjs +1 -1
- package/compiled/examples/cli-bundled.cjs +194 -227
- package/compiled/examples/cli-step-bundled.cjs +1 -1
- package/compiled/examples/validator-bundled.cjs +1 -1
- package/compiled/src/ifc/ifc_demand_extraction.test.d.ts +2 -0
- package/compiled/src/ifc/ifc_demand_extraction.test.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_demand_extraction.test.js +111 -0
- package/compiled/src/ifc/ifc_geometry_extraction.d.ts +47 -0
- package/compiled/src/ifc/ifc_geometry_extraction.d.ts.map +1 -1
- package/compiled/src/ifc/ifc_geometry_extraction.js +223 -269
- package/compiled/src/ifc/ifc_stream_open.d.ts +68 -0
- package/compiled/src/ifc/ifc_stream_open.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_stream_open.js +46 -0
- package/compiled/src/ifc/ifc_stream_open.test.d.ts +2 -0
- package/compiled/src/ifc/ifc_stream_open.test.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_stream_open.test.js +63 -0
- package/compiled/src/ifc/ifc_tile_extractor.d.ts +84 -0
- package/compiled/src/ifc/ifc_tile_extractor.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_tile_extractor.js +134 -0
- package/compiled/src/ifc/ifc_tile_extractor.test.d.ts +2 -0
- package/compiled/src/ifc/ifc_tile_extractor.test.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_tile_extractor.test.js +118 -0
- package/compiled/src/index.d.ts +14 -0
- package/compiled/src/index.d.ts.map +1 -1
- package/compiled/src/index.js +16 -0
- package/compiled/src/version/version.js +1 -1
- package/compiled/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -30,7 +30,7 @@ var import_node_process = require("node:process");
|
|
|
30
30
|
var readline = __toESM(require("node:readline"), 1);
|
|
31
31
|
|
|
32
32
|
// compiled/src/version/version.js
|
|
33
|
-
var versionString = "Conway v1.
|
|
33
|
+
var versionString = "Conway v1.416.1260";
|
|
34
34
|
|
|
35
35
|
// compiled/dependencies/conway-geom/interface/conway_geometry.js
|
|
36
36
|
var wasmType = "";
|
|
@@ -14965,7 +14965,7 @@ ${t5.join("\n")}` : "";
|
|
|
14965
14965
|
var import_process = require("process");
|
|
14966
14966
|
|
|
14967
14967
|
// compiled/src/version/version.js
|
|
14968
|
-
var versionString = "Conway v1.
|
|
14968
|
+
var versionString = "Conway v1.416.1260";
|
|
14969
14969
|
|
|
14970
14970
|
// compiled/dependencies/conway-geom/interface/conway_geometry.js
|
|
14971
14971
|
function pThreadsAllowed() {
|
|
@@ -87610,6 +87610,7 @@ var IfcGeometryExtraction = class _IfcGeometryExtraction {
|
|
|
87610
87610
|
this.geometryTypeCounts = /* @__PURE__ */ new Map();
|
|
87611
87611
|
this.csgDepth = 0;
|
|
87612
87612
|
this.freeVectorPolygonalFaces_ = [];
|
|
87613
|
+
this.extractionMapsPrepared_ = false;
|
|
87613
87614
|
this.csgMemoization = !this.lowMemoryMode;
|
|
87614
87615
|
this.materials = model.materials;
|
|
87615
87616
|
this.scene = new IfcSceneBuilder(model, conwayModel, this.materials);
|
|
@@ -91414,6 +91415,195 @@ var IfcGeometryExtraction = class _IfcGeometryExtraction {
|
|
|
91414
91415
|
*/
|
|
91415
91416
|
dumpGeometry(outputFilePath, geometry) {
|
|
91416
91417
|
}
|
|
91418
|
+
/**
|
|
91419
|
+
* One-time extraction setup shared by the whole-model walk and the
|
|
91420
|
+
* per-product demand path (Phase B2): linear scaling factor and the
|
|
91421
|
+
* cross-product maps (materials, material definitions, rel-voids, styled
|
|
91422
|
+
* items). Idempotent.
|
|
91423
|
+
*/
|
|
91424
|
+
prepareExtractionMaps_() {
|
|
91425
|
+
if (this.extractionMapsPrepared_) {
|
|
91426
|
+
return;
|
|
91427
|
+
}
|
|
91428
|
+
this.extractionMapsPrepared_ = true;
|
|
91429
|
+
this.extractLinearScalingFactor();
|
|
91430
|
+
const relAssociatesMaterials = this.model.types(IfcRelAssociatesMaterial);
|
|
91431
|
+
for (const relAssociateMaterial of relAssociatesMaterials) {
|
|
91432
|
+
const relatingMaterial = relAssociateMaterial.RelatingMaterial;
|
|
91433
|
+
try {
|
|
91434
|
+
const relatedObjects = relAssociateMaterial.RelatedObjects;
|
|
91435
|
+
for (const relatedObject of relatedObjects) {
|
|
91436
|
+
const product = relatedObject;
|
|
91437
|
+
if (product instanceof IfcProduct) {
|
|
91438
|
+
if (product instanceof IfcOpeningElement || product instanceof IfcSpace || product instanceof IfcOpeningStandardCase) {
|
|
91439
|
+
continue;
|
|
91440
|
+
}
|
|
91441
|
+
this.materials.relMaterialsMap.set(product.localID, relatingMaterial.localID);
|
|
91442
|
+
} else {
|
|
91443
|
+
}
|
|
91444
|
+
}
|
|
91445
|
+
} catch (ex) {
|
|
91446
|
+
if (ex instanceof Error) {
|
|
91447
|
+
if (MATERIAL_RELATED_OBJECTS_PERMISSIVE) {
|
|
91448
|
+
logger_default.error(`Error processing relatingMaterial expressID: ${relatingMaterial.expressID}, error: ${ex.message}`);
|
|
91449
|
+
} else {
|
|
91450
|
+
throw ex;
|
|
91451
|
+
}
|
|
91452
|
+
} else {
|
|
91453
|
+
logger_default.error("Unknown exception processing IfcRelAssociateMaterials.");
|
|
91454
|
+
}
|
|
91455
|
+
}
|
|
91456
|
+
}
|
|
91457
|
+
this.populateMaterialDefinitionsMap();
|
|
91458
|
+
this.populateRelVoidsMap();
|
|
91459
|
+
this.populateStyledItemsMap();
|
|
91460
|
+
}
|
|
91461
|
+
/**
|
|
91462
|
+
* Prepare for per-product demand extraction (Phase B2) without running the
|
|
91463
|
+
* whole-model walk: populates the shared extraction maps so
|
|
91464
|
+
* {@link extractProductGeometryByLocalID} can extract any single product.
|
|
91465
|
+
* Idempotent; the whole-model walk shares the same preparation.
|
|
91466
|
+
*/
|
|
91467
|
+
prepareDemandExtraction() {
|
|
91468
|
+
this.prepareExtractionMaps_();
|
|
91469
|
+
}
|
|
91470
|
+
/**
|
|
91471
|
+
* Extract one product's geometry into the scene by local ID — the demand
|
|
91472
|
+
* path's entry (Phase B2). Requires {@link prepareDemandExtraction} (or a
|
|
91473
|
+
* prior whole-model walk) so the shared maps exist.
|
|
91474
|
+
*
|
|
91475
|
+
* Note: products that are targets of IfcRelAggregates whose relating
|
|
91476
|
+
* object carries rel-voids get those master voids only on the whole-model
|
|
91477
|
+
* walk; the demand path extracts the product's own voids. The parity gate
|
|
91478
|
+
* for this seam is the whole-model digest CI.
|
|
91479
|
+
*
|
|
91480
|
+
* @param localID The product's local ID.
|
|
91481
|
+
* @return {boolean} True if the local ID was an IfcProduct and was
|
|
91482
|
+
* extracted; false if it wasn't a product.
|
|
91483
|
+
*/
|
|
91484
|
+
extractProductGeometryByLocalID(localID) {
|
|
91485
|
+
this.prepareExtractionMaps_();
|
|
91486
|
+
const element = this.model.getElementByLocalID(localID);
|
|
91487
|
+
if (!(element instanceof IfcProduct)) {
|
|
91488
|
+
return false;
|
|
91489
|
+
}
|
|
91490
|
+
this.extractProductGeometry(element);
|
|
91491
|
+
return true;
|
|
91492
|
+
}
|
|
91493
|
+
/**
|
|
91494
|
+
* Extract one product's geometry into the scene: placement, material /
|
|
91495
|
+
* style extraction, representation items (including mapped items) and
|
|
91496
|
+
* rel-void application. The deduplicated body of the whole-model walk's
|
|
91497
|
+
* two product loops (plain products + rel-aggregates), shared with the
|
|
91498
|
+
* per-product demand path.
|
|
91499
|
+
*
|
|
91500
|
+
* @param product The product to extract.
|
|
91501
|
+
* @param precomputedRelVoids Optional caller-owned rel-voids (the
|
|
91502
|
+
* rel-aggregates "master" case): when supplied the caller retains
|
|
91503
|
+
* ownership and this method does not delete the mesh vector; when
|
|
91504
|
+
* omitted, voids are extracted per product and freed here.
|
|
91505
|
+
*/
|
|
91506
|
+
extractProductGeometry(product, precomputedRelVoids) {
|
|
91507
|
+
this.scene.clearParentStack();
|
|
91508
|
+
const isSpace = product instanceof IfcOpeningElement || product instanceof IfcSpace || product instanceof IfcOpeningStandardCase;
|
|
91509
|
+
const objectPlacement = product.ObjectPlacement;
|
|
91510
|
+
if (objectPlacement !== null) {
|
|
91511
|
+
this.extractPlacement(objectPlacement);
|
|
91512
|
+
}
|
|
91513
|
+
const representations = product.Representation;
|
|
91514
|
+
if (representations === null) {
|
|
91515
|
+
return;
|
|
91516
|
+
}
|
|
91517
|
+
const styledItemID = this.extractMaterialStyle(product);
|
|
91518
|
+
let hasRelVoid = false;
|
|
91519
|
+
const extractRelVoidsResult = precomputedRelVoids ?? this.extractRelVoids(product);
|
|
91520
|
+
let relVoidsMeshVector;
|
|
91521
|
+
let relVoidLocalIDs;
|
|
91522
|
+
if (extractRelVoidsResult !== void 0) {
|
|
91523
|
+
[relVoidsMeshVector, relVoidLocalIDs] = extractRelVoidsResult;
|
|
91524
|
+
}
|
|
91525
|
+
if (relVoidsMeshVector !== void 0) {
|
|
91526
|
+
hasRelVoid = true;
|
|
91527
|
+
}
|
|
91528
|
+
if (styledItemID !== void 0) {
|
|
91529
|
+
const styledItem = this.model.getElementByLocalID(styledItemID);
|
|
91530
|
+
let reusableStyleID;
|
|
91531
|
+
for (const representation of representations.Representations) {
|
|
91532
|
+
if (representation instanceof IfcShapeRepresentation) {
|
|
91533
|
+
if (representation.RepresentationIdentifier !== "Body" && representation.RepresentationIdentifier !== "Facetation") {
|
|
91534
|
+
continue;
|
|
91535
|
+
}
|
|
91536
|
+
}
|
|
91537
|
+
for (const item of representation.Items) {
|
|
91538
|
+
if (item instanceof IfcMappedItem) {
|
|
91539
|
+
this.extractMappedItem(item, product, hasRelVoid, isSpace);
|
|
91540
|
+
} else {
|
|
91541
|
+
try {
|
|
91542
|
+
this.extractRepresentationItem(item, product.localID, hasRelVoid, isSpace);
|
|
91543
|
+
if (hasRelVoid) {
|
|
91544
|
+
this.applyRelVoidToRepresentation(item, relVoidsMeshVector, product.localID, relVoidLocalIDs, void 0, isSpace);
|
|
91545
|
+
}
|
|
91546
|
+
} catch (error) {
|
|
91547
|
+
if (error instanceof Error) {
|
|
91548
|
+
logger_default.error(`Error extracting representation item
|
|
91549
|
+
${error.message}
|
|
91550
|
+
Express ID: #${item.expressID}`);
|
|
91551
|
+
} else {
|
|
91552
|
+
logger_default.error(`Error extracting representation item
|
|
91553
|
+
Express ID: #${item.expressID}`);
|
|
91554
|
+
}
|
|
91555
|
+
}
|
|
91556
|
+
}
|
|
91557
|
+
const styledItemLocalID_ = this.materials.styledItemMap.get(item.localID);
|
|
91558
|
+
if (styledItemLocalID_ !== void 0) {
|
|
91559
|
+
const styledItem_ = this.model.getElementByLocalID(styledItemLocalID_);
|
|
91560
|
+
this.extractStyledItem(styledItem_);
|
|
91561
|
+
} else if (reusableStyleID !== void 0) {
|
|
91562
|
+
this.materials.addGeometryMapping(item.localID, reusableStyleID);
|
|
91563
|
+
} else if (styledItem instanceof IfcStyledItem) {
|
|
91564
|
+
reusableStyleID = this.extractStyledItem(styledItem, item);
|
|
91565
|
+
}
|
|
91566
|
+
}
|
|
91567
|
+
}
|
|
91568
|
+
} else {
|
|
91569
|
+
for (const representation of representations.Representations) {
|
|
91570
|
+
if (representation instanceof IfcShapeRepresentation) {
|
|
91571
|
+
if (representation.RepresentationIdentifier !== "Body" && representation.RepresentationIdentifier !== "Facetation") {
|
|
91572
|
+
continue;
|
|
91573
|
+
}
|
|
91574
|
+
}
|
|
91575
|
+
for (const item of representation.Items) {
|
|
91576
|
+
if (item instanceof IfcMappedItem) {
|
|
91577
|
+
this.extractMappedItem(item, product, hasRelVoid, isSpace);
|
|
91578
|
+
} else {
|
|
91579
|
+
try {
|
|
91580
|
+
this.extractRepresentationItem(item, product.localID, hasRelVoid, isSpace);
|
|
91581
|
+
if (hasRelVoid) {
|
|
91582
|
+
this.applyRelVoidToRepresentation(item, relVoidsMeshVector, product.localID, relVoidLocalIDs, void 0, isSpace);
|
|
91583
|
+
}
|
|
91584
|
+
const styledItemLocalID_ = this.materials.styledItemMap.get(item.localID);
|
|
91585
|
+
if (styledItemLocalID_ !== void 0) {
|
|
91586
|
+
const styledItem_ = this.model.getElementByLocalID(styledItemLocalID_);
|
|
91587
|
+
this.extractStyledItem(styledItem_);
|
|
91588
|
+
}
|
|
91589
|
+
} catch (error) {
|
|
91590
|
+
if (error instanceof Error) {
|
|
91591
|
+
logger_default.error(`Error extracting representation item
|
|
91592
|
+
${error.message}
|
|
91593
|
+
${error.stack}
|
|
91594
|
+
Express ID: #${item.localID}`);
|
|
91595
|
+
} else {
|
|
91596
|
+
logger_default.error(`Unknown error extracting representation item Express ID: #${item.localID}`);
|
|
91597
|
+
}
|
|
91598
|
+
}
|
|
91599
|
+
}
|
|
91600
|
+
}
|
|
91601
|
+
}
|
|
91602
|
+
}
|
|
91603
|
+
if (precomputedRelVoids === void 0) {
|
|
91604
|
+
relVoidsMeshVector?.delete();
|
|
91605
|
+
}
|
|
91606
|
+
}
|
|
91417
91607
|
/**
|
|
91418
91608
|
* Extract the geometry data from the IFC
|
|
91419
91609
|
*
|
|
@@ -91488,144 +91678,19 @@ var IfcGeometryExtraction = class _IfcGeometryExtraction {
|
|
|
91488
91678
|
*/
|
|
91489
91679
|
*extractIFCGeometryDataIncremental() {
|
|
91490
91680
|
let result = ExtractResult.INCOMPLETE;
|
|
91491
|
-
this.extractLinearScalingFactor();
|
|
91492
91681
|
const previousMemoizationState = this.model.elementMemoization;
|
|
91493
|
-
const relAssociatesMaterials = this.model.types(IfcRelAssociatesMaterial);
|
|
91494
91682
|
try {
|
|
91495
91683
|
const MEMOIZATION_THRESHOLD = 256 * 1024 * 1024;
|
|
91496
91684
|
if (this.lowMemoryMode || this.model.bufferBytesize > MEMOIZATION_THRESHOLD) {
|
|
91497
91685
|
this.model.elementMemoization = false;
|
|
91498
91686
|
}
|
|
91499
|
-
|
|
91500
|
-
const relatingMaterial = relAssociateMaterial.RelatingMaterial;
|
|
91501
|
-
try {
|
|
91502
|
-
const relatedObjects = relAssociateMaterial.RelatedObjects;
|
|
91503
|
-
for (const relatedObject of relatedObjects) {
|
|
91504
|
-
const product = relatedObject;
|
|
91505
|
-
if (product instanceof IfcProduct) {
|
|
91506
|
-
if (product instanceof IfcOpeningElement || product instanceof IfcSpace || product instanceof IfcOpeningStandardCase) {
|
|
91507
|
-
continue;
|
|
91508
|
-
}
|
|
91509
|
-
this.materials.relMaterialsMap.set(product.localID, relatingMaterial.localID);
|
|
91510
|
-
} else {
|
|
91511
|
-
}
|
|
91512
|
-
}
|
|
91513
|
-
} catch (ex) {
|
|
91514
|
-
if (ex instanceof Error) {
|
|
91515
|
-
if (MATERIAL_RELATED_OBJECTS_PERMISSIVE) {
|
|
91516
|
-
logger_default.error(`Error processing relatingMaterial expressID: ${relatingMaterial.expressID}, error: ${ex.message}`);
|
|
91517
|
-
} else {
|
|
91518
|
-
throw ex;
|
|
91519
|
-
}
|
|
91520
|
-
} else {
|
|
91521
|
-
logger_default.error("Unknown exception processing IfcRelAssociateMaterials.");
|
|
91522
|
-
}
|
|
91523
|
-
}
|
|
91524
|
-
}
|
|
91525
|
-
this.populateMaterialDefinitionsMap();
|
|
91526
|
-
this.populateRelVoidsMap();
|
|
91527
|
-
this.populateStyledItemsMap();
|
|
91687
|
+
this.prepareExtractionMaps_();
|
|
91528
91688
|
const products = this.model.types(IfcProduct);
|
|
91529
91689
|
const totalItems = this.model.typeCount(IfcProduct) + this.model.typeCount(IfcRelAggregates);
|
|
91530
91690
|
let completedItems = 0;
|
|
91531
91691
|
for (const product of products) {
|
|
91532
91692
|
yield [++completedItems, totalItems];
|
|
91533
|
-
this.
|
|
91534
|
-
const isSpace = product instanceof IfcOpeningElement || product instanceof IfcSpace || product instanceof IfcOpeningStandardCase;
|
|
91535
|
-
const objectPlacement = product.ObjectPlacement;
|
|
91536
|
-
if (objectPlacement !== null) {
|
|
91537
|
-
this.extractPlacement(objectPlacement);
|
|
91538
|
-
}
|
|
91539
|
-
const representations = product.Representation;
|
|
91540
|
-
if (representations !== null) {
|
|
91541
|
-
const styledItemID = this.extractMaterialStyle(product);
|
|
91542
|
-
let hasRelVoid = false;
|
|
91543
|
-
const extractRelVoidsResult = this.extractRelVoids(product);
|
|
91544
|
-
let relVoidsMeshVector;
|
|
91545
|
-
let relVoidLocalIDs;
|
|
91546
|
-
if (extractRelVoidsResult !== void 0) {
|
|
91547
|
-
[relVoidsMeshVector, relVoidLocalIDs] = extractRelVoidsResult;
|
|
91548
|
-
}
|
|
91549
|
-
if (relVoidsMeshVector !== void 0) {
|
|
91550
|
-
hasRelVoid = true;
|
|
91551
|
-
}
|
|
91552
|
-
if (styledItemID !== void 0) {
|
|
91553
|
-
const styledItem = this.model.getElementByLocalID(styledItemID);
|
|
91554
|
-
let reusableStyleID;
|
|
91555
|
-
for (const representation of representations.Representations) {
|
|
91556
|
-
if (representation instanceof IfcShapeRepresentation) {
|
|
91557
|
-
if (representation.RepresentationIdentifier !== "Body" && representation.RepresentationIdentifier !== "Facetation") {
|
|
91558
|
-
continue;
|
|
91559
|
-
}
|
|
91560
|
-
}
|
|
91561
|
-
for (const item of representation.Items) {
|
|
91562
|
-
if (item instanceof IfcMappedItem) {
|
|
91563
|
-
this.extractMappedItem(item, product, hasRelVoid, isSpace);
|
|
91564
|
-
} else {
|
|
91565
|
-
try {
|
|
91566
|
-
this.extractRepresentationItem(item, product.localID, hasRelVoid, isSpace);
|
|
91567
|
-
if (hasRelVoid) {
|
|
91568
|
-
this.applyRelVoidToRepresentation(item, relVoidsMeshVector, product.localID, relVoidLocalIDs, void 0, isSpace);
|
|
91569
|
-
}
|
|
91570
|
-
} catch (error) {
|
|
91571
|
-
if (error instanceof Error) {
|
|
91572
|
-
logger_default.error(`Error extracting representation item
|
|
91573
|
-
${error.message}
|
|
91574
|
-
Express ID: #${item.expressID}`);
|
|
91575
|
-
} else {
|
|
91576
|
-
logger_default.error(`Error extracting representation item
|
|
91577
|
-
Express ID: #${item.expressID}`);
|
|
91578
|
-
}
|
|
91579
|
-
}
|
|
91580
|
-
}
|
|
91581
|
-
const styledItemLocalID_ = this.materials.styledItemMap.get(item.localID);
|
|
91582
|
-
if (styledItemLocalID_ !== void 0) {
|
|
91583
|
-
const styledItem_ = this.model.getElementByLocalID(styledItemLocalID_);
|
|
91584
|
-
this.extractStyledItem(styledItem_);
|
|
91585
|
-
} else if (reusableStyleID !== void 0) {
|
|
91586
|
-
this.materials.addGeometryMapping(item.localID, reusableStyleID);
|
|
91587
|
-
} else if (styledItem instanceof IfcStyledItem) {
|
|
91588
|
-
reusableStyleID = this.extractStyledItem(styledItem, item);
|
|
91589
|
-
}
|
|
91590
|
-
}
|
|
91591
|
-
}
|
|
91592
|
-
} else {
|
|
91593
|
-
for (const representation of representations.Representations) {
|
|
91594
|
-
if (representation instanceof IfcShapeRepresentation) {
|
|
91595
|
-
if (representation.RepresentationIdentifier !== "Body" && representation.RepresentationIdentifier !== "Facetation") {
|
|
91596
|
-
continue;
|
|
91597
|
-
}
|
|
91598
|
-
}
|
|
91599
|
-
for (const item of representation.Items) {
|
|
91600
|
-
if (item instanceof IfcMappedItem) {
|
|
91601
|
-
this.extractMappedItem(item, product, hasRelVoid, isSpace);
|
|
91602
|
-
} else {
|
|
91603
|
-
try {
|
|
91604
|
-
this.extractRepresentationItem(item, product.localID, hasRelVoid, isSpace);
|
|
91605
|
-
if (hasRelVoid) {
|
|
91606
|
-
this.applyRelVoidToRepresentation(item, relVoidsMeshVector, product.localID, relVoidLocalIDs, void 0, isSpace);
|
|
91607
|
-
}
|
|
91608
|
-
const styledItemLocalID_ = this.materials.styledItemMap.get(item.localID);
|
|
91609
|
-
if (styledItemLocalID_ !== void 0) {
|
|
91610
|
-
const styledItem_ = this.model.getElementByLocalID(styledItemLocalID_);
|
|
91611
|
-
this.extractStyledItem(styledItem_);
|
|
91612
|
-
}
|
|
91613
|
-
} catch (error) {
|
|
91614
|
-
if (error instanceof Error) {
|
|
91615
|
-
logger_default.error(`Error extracting representation item
|
|
91616
|
-
${error.message}
|
|
91617
|
-
${error.stack}
|
|
91618
|
-
Express ID: #${item.localID}`);
|
|
91619
|
-
} else {
|
|
91620
|
-
logger_default.error(`Unknown error extracting representation item Express ID: #${item.localID}`);
|
|
91621
|
-
}
|
|
91622
|
-
}
|
|
91623
|
-
}
|
|
91624
|
-
}
|
|
91625
|
-
}
|
|
91626
|
-
}
|
|
91627
|
-
relVoidsMeshVector?.delete();
|
|
91628
|
-
}
|
|
91693
|
+
this.extractProductGeometry(product);
|
|
91629
91694
|
}
|
|
91630
91695
|
const relAggregates = this.model.types(IfcRelAggregates);
|
|
91631
91696
|
for (const relAggregate of relAggregates) {
|
|
@@ -91636,105 +91701,7 @@ var IfcGeometryExtraction = class _IfcGeometryExtraction {
|
|
|
91636
91701
|
const relatedObjects = relAggregate.RelatedObjects;
|
|
91637
91702
|
for (const productRepresentation of relatedObjects) {
|
|
91638
91703
|
if (productRepresentation instanceof IfcProduct) {
|
|
91639
|
-
|
|
91640
|
-
const product = productRepresentation;
|
|
91641
|
-
this.scene.clearParentStack();
|
|
91642
|
-
const objectPlacement = product.ObjectPlacement;
|
|
91643
|
-
if (objectPlacement !== null) {
|
|
91644
|
-
this.extractPlacement(objectPlacement);
|
|
91645
|
-
}
|
|
91646
|
-
const representations = product.Representation;
|
|
91647
|
-
if (representations !== null) {
|
|
91648
|
-
const styledItemID = this.extractMaterialStyle(product);
|
|
91649
|
-
const extractRelVoidsResult = masterRelVoids ?? this.extractRelVoids(product);
|
|
91650
|
-
let hasRelVoid = false;
|
|
91651
|
-
let relVoidsMeshVector;
|
|
91652
|
-
let relVoidLocalIDs;
|
|
91653
|
-
if (extractRelVoidsResult !== void 0) {
|
|
91654
|
-
[relVoidsMeshVector, relVoidLocalIDs] = extractRelVoidsResult;
|
|
91655
|
-
}
|
|
91656
|
-
if (relVoidsMeshVector !== void 0) {
|
|
91657
|
-
hasRelVoid = true;
|
|
91658
|
-
}
|
|
91659
|
-
if (styledItemID !== void 0) {
|
|
91660
|
-
const styledItem = this.model.getElementByLocalID(styledItemID);
|
|
91661
|
-
let reusableStyleID;
|
|
91662
|
-
for (const representation of representations.Representations) {
|
|
91663
|
-
if (representation instanceof IfcShapeRepresentation) {
|
|
91664
|
-
if (representation.RepresentationIdentifier !== "Body" && representation.RepresentationIdentifier !== "Facetation") {
|
|
91665
|
-
continue;
|
|
91666
|
-
}
|
|
91667
|
-
}
|
|
91668
|
-
for (const item of representation.Items) {
|
|
91669
|
-
if (item instanceof IfcMappedItem) {
|
|
91670
|
-
this.extractMappedItem(item, product, hasRelVoid, isSpace);
|
|
91671
|
-
} else {
|
|
91672
|
-
try {
|
|
91673
|
-
this.extractRepresentationItem(item, product.localID, hasRelVoid, isSpace);
|
|
91674
|
-
if (hasRelVoid) {
|
|
91675
|
-
this.applyRelVoidToRepresentation(item, relVoidsMeshVector, product.localID, relVoidLocalIDs, void 0, isSpace);
|
|
91676
|
-
}
|
|
91677
|
-
} catch (error) {
|
|
91678
|
-
if (error instanceof Error) {
|
|
91679
|
-
logger_default.error(`Error extracting rel aggregate representation item
|
|
91680
|
-
${error.message}
|
|
91681
|
-
${error.stack}
|
|
91682
|
-
Express ID: #${item.expressID}`);
|
|
91683
|
-
} else {
|
|
91684
|
-
logger_default.error(`Unknown error extracting rel aggregate representation item Express ID: #${item.expressID}`);
|
|
91685
|
-
}
|
|
91686
|
-
}
|
|
91687
|
-
}
|
|
91688
|
-
const styledItemLocalID_ = this.materials.styledItemMap.get(item.localID);
|
|
91689
|
-
if (styledItemLocalID_ !== void 0) {
|
|
91690
|
-
const styledItem_ = this.model.getElementByLocalID(styledItemLocalID_);
|
|
91691
|
-
this.extractStyledItem(styledItem_);
|
|
91692
|
-
} else if (reusableStyleID !== void 0) {
|
|
91693
|
-
this.materials.addGeometryMapping(item.localID, reusableStyleID);
|
|
91694
|
-
} else if (styledItem instanceof IfcStyledItem) {
|
|
91695
|
-
reusableStyleID = this.extractStyledItem(styledItem, item);
|
|
91696
|
-
}
|
|
91697
|
-
}
|
|
91698
|
-
}
|
|
91699
|
-
} else {
|
|
91700
|
-
for (const representation of representations.Representations) {
|
|
91701
|
-
if (representation instanceof IfcShapeRepresentation) {
|
|
91702
|
-
if (representation.RepresentationIdentifier !== "Body" && representation.RepresentationIdentifier !== "Facetation") {
|
|
91703
|
-
continue;
|
|
91704
|
-
}
|
|
91705
|
-
}
|
|
91706
|
-
for (const item of representation.Items) {
|
|
91707
|
-
if (item instanceof IfcMappedItem) {
|
|
91708
|
-
this.extractMappedItem(item, product, hasRelVoid, isSpace);
|
|
91709
|
-
} else {
|
|
91710
|
-
try {
|
|
91711
|
-
this.extractRepresentationItem(item, product.localID, hasRelVoid, isSpace);
|
|
91712
|
-
if (hasRelVoid) {
|
|
91713
|
-
this.applyRelVoidToRepresentation(item, relVoidsMeshVector, product.localID, relVoidLocalIDs, void 0, isSpace);
|
|
91714
|
-
}
|
|
91715
|
-
const styledItemLocalID_ = this.materials.styledItemMap.get(item.localID);
|
|
91716
|
-
if (styledItemLocalID_ !== void 0) {
|
|
91717
|
-
const styledItem_ = this.model.getElementByLocalID(styledItemLocalID_);
|
|
91718
|
-
this.extractStyledItem(styledItem_);
|
|
91719
|
-
}
|
|
91720
|
-
} catch (error) {
|
|
91721
|
-
if (error instanceof Error) {
|
|
91722
|
-
logger_default.error(`Error extracting rel aggregate representation item
|
|
91723
|
-
${error.message}
|
|
91724
|
-
${error.stack}
|
|
91725
|
-
Express ID: #${item.expressID}`);
|
|
91726
|
-
} else {
|
|
91727
|
-
logger_default.error(`Unknown error extracting rel aggregate representation item Express ID: #${item.expressID}`);
|
|
91728
|
-
}
|
|
91729
|
-
}
|
|
91730
|
-
}
|
|
91731
|
-
}
|
|
91732
|
-
}
|
|
91733
|
-
}
|
|
91734
|
-
if (masterRelVoids === void 0) {
|
|
91735
|
-
relVoidsMeshVector?.delete();
|
|
91736
|
-
}
|
|
91737
|
-
}
|
|
91704
|
+
this.extractProductGeometry(productRepresentation, masterRelVoids);
|
|
91738
91705
|
}
|
|
91739
91706
|
}
|
|
91740
91707
|
if (masterRelVoids !== void 0) {
|
|
@@ -15943,7 +15943,7 @@ var ParsingBuffer = class {
|
|
|
15943
15943
|
};
|
|
15944
15944
|
|
|
15945
15945
|
// compiled/src/version/version.js
|
|
15946
|
-
var versionString = "Conway v1.
|
|
15946
|
+
var versionString = "Conway v1.416.1260";
|
|
15947
15947
|
|
|
15948
15948
|
// compiled/dependencies/conway-geom/interface/conway_geometry.js
|
|
15949
15949
|
function pThreadsAllowed() {
|
|
@@ -944,7 +944,7 @@ var EntityTypesIfcCount = 909;
|
|
|
944
944
|
var entity_types_ifc_gen_default = EntityTypesIfc;
|
|
945
945
|
|
|
946
946
|
// compiled/src/version/version.js
|
|
947
|
-
var versionString = "Conway v1.
|
|
947
|
+
var versionString = "Conway v1.416.1260";
|
|
948
948
|
|
|
949
949
|
// compiled/dependencies/conway-geom/interface/conway_geometry.js
|
|
950
950
|
var wasmType = "";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ifc_demand_extraction.test.d.ts","sourceRoot":"","sources":["../../../src/ifc/ifc_demand_extraction.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/* eslint-disable no-magic-numbers, @typescript-eslint/no-explicit-any */
|
|
2
|
+
// Phase B2: per-product demand extraction must produce the same meshes the
|
|
3
|
+
// whole-model walk produces — same products with geometry, same vertex and
|
|
4
|
+
// index counts per product — since both now run the same deduplicated
|
|
5
|
+
// per-product body (extractProductGeometry).
|
|
6
|
+
import fs from "fs";
|
|
7
|
+
import { beforeAll, describe, expect, test } from "@jest/globals";
|
|
8
|
+
import { IfcGeometryExtraction } from "./ifc_geometry_extraction.js";
|
|
9
|
+
import { ParseResult } from "../step/parsing/step_parser.js";
|
|
10
|
+
import IfcStepParser from "./ifc_step_parser.js";
|
|
11
|
+
import ParsingBuffer from "../parsing/parsing_buffer.js";
|
|
12
|
+
import { ConwayGeometry } from "../../dependencies/conway-geom/index.js";
|
|
13
|
+
import { ExtractResult } from "../core/shared_constants.js";
|
|
14
|
+
import { IfcProduct } from "./ifc4_gen/index.js";
|
|
15
|
+
let conwayGeometry;
|
|
16
|
+
/**
|
|
17
|
+
* Parse a fresh model from index.ifc (models are stateful; each extraction
|
|
18
|
+
* mode gets its own).
|
|
19
|
+
*
|
|
20
|
+
* @return {IfcStepModel} The parsed model.
|
|
21
|
+
*/
|
|
22
|
+
function freshModel() {
|
|
23
|
+
const bytes = fs.readFileSync("data/index.ifc");
|
|
24
|
+
const input = new ParsingBuffer(bytes);
|
|
25
|
+
expect(IfcStepParser.Instance.parseHeader(input)[1])
|
|
26
|
+
.toBe(ParseResult.COMPLETE);
|
|
27
|
+
const [, model] = IfcStepParser.Instance.parseDataToModel(input);
|
|
28
|
+
expect(model).toBeDefined();
|
|
29
|
+
return model;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Collect per-localID mesh signatures (vertex + triangle counts) from a
|
|
33
|
+
* model's extracted geometry.
|
|
34
|
+
*
|
|
35
|
+
* @param extraction The extraction whose model geometry to summarise.
|
|
36
|
+
* @return {Map<number, string>} localID → "vertexCount/triangleCount".
|
|
37
|
+
*/
|
|
38
|
+
function meshSignatures(extraction) {
|
|
39
|
+
const signatures = new Map();
|
|
40
|
+
for (const mesh of extraction.model.geometry) {
|
|
41
|
+
const geometry = mesh.geometry;
|
|
42
|
+
if (geometry === void 0 || typeof geometry.getVertexCount !== "function") {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
signatures.set(mesh.localID, `${geometry.getVertexCount()}/${geometry.getTriangleCount()}`);
|
|
46
|
+
}
|
|
47
|
+
return signatures;
|
|
48
|
+
}
|
|
49
|
+
beforeAll(async () => {
|
|
50
|
+
conwayGeometry = new ConwayGeometry();
|
|
51
|
+
expect(await conwayGeometry.initialize()).toBe(true);
|
|
52
|
+
});
|
|
53
|
+
describe("per-product demand extraction (Phase B2)", () => {
|
|
54
|
+
test("demand extraction over all products matches the whole-model walk", () => {
|
|
55
|
+
// Whole-model walk (the CI-anchored path).
|
|
56
|
+
const wholeExtraction = new IfcGeometryExtraction(conwayGeometry, freshModel());
|
|
57
|
+
expect(wholeExtraction.extractIFCGeometryData()[0])
|
|
58
|
+
.toBe(ExtractResult.COMPLETE);
|
|
59
|
+
const wholeSignatures = meshSignatures(wholeExtraction);
|
|
60
|
+
expect(wholeSignatures.size).toBeGreaterThan(0);
|
|
61
|
+
// Demand path: prepare once, then extract every product individually.
|
|
62
|
+
const demandModel = freshModel();
|
|
63
|
+
const demandExtraction = new IfcGeometryExtraction(conwayGeometry, demandModel);
|
|
64
|
+
demandExtraction.prepareDemandExtraction();
|
|
65
|
+
let extractedProducts = 0;
|
|
66
|
+
for (const product of demandModel.types(IfcProduct)) {
|
|
67
|
+
if (demandExtraction.extractProductGeometryByLocalID(product.localID)) {
|
|
68
|
+
++extractedProducts;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
expect(extractedProducts).toBeGreaterThan(0);
|
|
72
|
+
const demandSignatures = meshSignatures(demandExtraction);
|
|
73
|
+
// Same set of products with geometry, same mesh shape per product.
|
|
74
|
+
expect(demandSignatures).toEqual(wholeSignatures);
|
|
75
|
+
});
|
|
76
|
+
test("a single product extracts on demand without the whole-model walk", () => {
|
|
77
|
+
// Whole-model reference signatures (mesh localIDs key representation
|
|
78
|
+
// items, not products — so parity is checked per matching key).
|
|
79
|
+
const reference = new IfcGeometryExtraction(conwayGeometry, freshModel());
|
|
80
|
+
reference.extractIFCGeometryData();
|
|
81
|
+
const referenceSignatures = meshSignatures(reference);
|
|
82
|
+
const model = freshModel();
|
|
83
|
+
const extraction = new IfcGeometryExtraction(conwayGeometry, model);
|
|
84
|
+
// Extract single products on the fresh model until one yields a mesh —
|
|
85
|
+
// proving a lone product materialises without the whole-model walk.
|
|
86
|
+
let produced = 0;
|
|
87
|
+
for (const product of model.types(IfcProduct)) {
|
|
88
|
+
extraction.extractProductGeometryByLocalID(product.localID);
|
|
89
|
+
produced = meshSignatures(extraction).size;
|
|
90
|
+
if (produced > 0) {
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
expect(produced).toBeGreaterThan(0);
|
|
95
|
+
expect(produced).toBeLessThan(referenceSignatures.size);
|
|
96
|
+
// Every mesh the single extraction produced matches the reference's
|
|
97
|
+
// mesh for the same key exactly.
|
|
98
|
+
for (const [localID, signature] of meshSignatures(extraction)) {
|
|
99
|
+
expect(referenceSignatures.get(localID)).toBe(signature);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
test("a non-product local ID is refused", () => {
|
|
103
|
+
const model = freshModel();
|
|
104
|
+
const extraction = new IfcGeometryExtraction(conwayGeometry, model);
|
|
105
|
+
// localID 0 in index.ifc is not an IfcProduct (first record is a root
|
|
106
|
+
// non-product entity in this fixture; the assertion below guards that).
|
|
107
|
+
const first = model.getElementByLocalID(0);
|
|
108
|
+
expect(first instanceof IfcProduct).toBe(false);
|
|
109
|
+
expect(extraction.extractProductGeometryByLocalID(0)).toBe(false);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
@@ -920,6 +920,53 @@ export declare class IfcGeometryExtraction {
|
|
|
920
920
|
* @param geometry
|
|
921
921
|
*/
|
|
922
922
|
dumpGeometry(outputFilePath: string, geometry: GeometryObject): void;
|
|
923
|
+
private extractionMapsPrepared_;
|
|
924
|
+
/**
|
|
925
|
+
* One-time extraction setup shared by the whole-model walk and the
|
|
926
|
+
* per-product demand path (Phase B2): linear scaling factor and the
|
|
927
|
+
* cross-product maps (materials, material definitions, rel-voids, styled
|
|
928
|
+
* items). Idempotent.
|
|
929
|
+
*/
|
|
930
|
+
private prepareExtractionMaps_;
|
|
931
|
+
/**
|
|
932
|
+
* Prepare for per-product demand extraction (Phase B2) without running the
|
|
933
|
+
* whole-model walk: populates the shared extraction maps so
|
|
934
|
+
* {@link extractProductGeometryByLocalID} can extract any single product.
|
|
935
|
+
* Idempotent; the whole-model walk shares the same preparation.
|
|
936
|
+
*/
|
|
937
|
+
prepareDemandExtraction(): void;
|
|
938
|
+
/**
|
|
939
|
+
* Extract one product's geometry into the scene by local ID — the demand
|
|
940
|
+
* path's entry (Phase B2). Requires {@link prepareDemandExtraction} (or a
|
|
941
|
+
* prior whole-model walk) so the shared maps exist.
|
|
942
|
+
*
|
|
943
|
+
* Note: products that are targets of IfcRelAggregates whose relating
|
|
944
|
+
* object carries rel-voids get those master voids only on the whole-model
|
|
945
|
+
* walk; the demand path extracts the product's own voids. The parity gate
|
|
946
|
+
* for this seam is the whole-model digest CI.
|
|
947
|
+
*
|
|
948
|
+
* @param localID The product's local ID.
|
|
949
|
+
* @return {boolean} True if the local ID was an IfcProduct and was
|
|
950
|
+
* extracted; false if it wasn't a product.
|
|
951
|
+
*/
|
|
952
|
+
extractProductGeometryByLocalID(localID: number): boolean;
|
|
953
|
+
/**
|
|
954
|
+
* Extract one product's geometry into the scene: placement, material /
|
|
955
|
+
* style extraction, representation items (including mapped items) and
|
|
956
|
+
* rel-void application. The deduplicated body of the whole-model walk's
|
|
957
|
+
* two product loops (plain products + rel-aggregates), shared with the
|
|
958
|
+
* per-product demand path.
|
|
959
|
+
*
|
|
960
|
+
* @param product The product to extract.
|
|
961
|
+
* @param precomputedRelVoids Optional caller-owned rel-voids (the
|
|
962
|
+
* rel-aggregates "master" case): when supplied the caller retains
|
|
963
|
+
* ownership and this method does not delete the mesh vector; when
|
|
964
|
+
* omitted, voids are extracted per product and freed here.
|
|
965
|
+
*/
|
|
966
|
+
extractProductGeometry(product: IfcProduct, precomputedRelVoids?: [
|
|
967
|
+
NativeVectorGeometry,
|
|
968
|
+
number[]
|
|
969
|
+
]): void;
|
|
923
970
|
/**
|
|
924
971
|
* Extract the geometry data from the IFC
|
|
925
972
|
*
|