@bldrs-ai/conway 1.346.1102 → 1.347.1107
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 +1 -1
- package/compiled/examples/cli-step-bundled.cjs +1 -1
- package/compiled/examples/validator-bundled.cjs +1 -1
- package/compiled/src/AP214E3_2010/ap214_product_structure_extraction.d.ts +144 -0
- package/compiled/src/AP214E3_2010/ap214_product_structure_extraction.d.ts.map +1 -0
- package/compiled/src/AP214E3_2010/ap214_product_structure_extraction.js +236 -0
- package/compiled/src/AP214E3_2010/ap214_product_structure_extraction.test.d.ts +2 -0
- package/compiled/src/AP214E3_2010/ap214_product_structure_extraction.test.d.ts.map +1 -0
- package/compiled/src/AP214E3_2010/ap214_product_structure_extraction.test.js +107 -0
- package/compiled/src/AP214E3_2010/ap214_property_extraction.d.ts +90 -0
- package/compiled/src/AP214E3_2010/ap214_property_extraction.d.ts.map +1 -0
- package/compiled/src/AP214E3_2010/ap214_property_extraction.js +143 -0
- package/compiled/src/AP214E3_2010/ap214_property_extraction.test.d.ts +2 -0
- package/compiled/src/AP214E3_2010/ap214_property_extraction.test.d.ts.map +1 -0
- package/compiled/src/AP214E3_2010/ap214_property_extraction.test.js +56 -0
- package/compiled/src/compat/web-ifc/ap214_properties.d.ts +140 -13
- package/compiled/src/compat/web-ifc/ap214_properties.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/ap214_properties.js +267 -26
- package/compiled/src/compat/web-ifc/ap214_properties.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/ap214_properties.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/ap214_properties.test.js +85 -0
- package/compiled/src/version/version.js +1 -1
- package/compiled/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -69608,7 +69608,7 @@ var IfcStepParser = class extends StepParser {
|
|
|
69608
69608
|
IfcStepParser.Instance = new IfcStepParser();
|
|
69609
69609
|
|
|
69610
69610
|
// compiled/src/version/version.js
|
|
69611
|
-
var versionString = "Conway Web-Ifc Shim v1.
|
|
69611
|
+
var versionString = "Conway Web-Ifc Shim v1.347.1107";
|
|
69612
69612
|
|
|
69613
69613
|
// compiled/src/statistics/statistics.js
|
|
69614
69614
|
var Statistics = class {
|
|
@@ -85869,7 +85869,7 @@ var IfcSceneBuilder = class {
|
|
|
85869
85869
|
};
|
|
85870
85870
|
|
|
85871
85871
|
// compiled/src/version/version.js
|
|
85872
|
-
var versionString = "Conway Web-Ifc Shim v1.
|
|
85872
|
+
var versionString = "Conway Web-Ifc Shim v1.347.1107";
|
|
85873
85873
|
|
|
85874
85874
|
// compiled/src/statistics/statistics.js
|
|
85875
85875
|
var Statistics = class {
|
|
@@ -79320,7 +79320,7 @@ var ExtractResult;
|
|
|
79320
79320
|
})(ExtractResult || (ExtractResult = {}));
|
|
79321
79321
|
|
|
79322
79322
|
// compiled/src/version/version.js
|
|
79323
|
-
var versionString = "Conway Web-Ifc Shim v1.
|
|
79323
|
+
var versionString = "Conway Web-Ifc Shim v1.347.1107";
|
|
79324
79324
|
|
|
79325
79325
|
// compiled/src/statistics/statistics.js
|
|
79326
79326
|
var Statistics = class {
|
|
@@ -69606,7 +69606,7 @@ var IfcStepParser = class extends StepParser {
|
|
|
69606
69606
|
IfcStepParser.Instance = new IfcStepParser();
|
|
69607
69607
|
|
|
69608
69608
|
// compiled/src/version/version.js
|
|
69609
|
-
var versionString = "Conway Web-Ifc Shim v1.
|
|
69609
|
+
var versionString = "Conway Web-Ifc Shim v1.347.1107";
|
|
69610
69610
|
|
|
69611
69611
|
// compiled/src/statistics/statistics.js
|
|
69612
69612
|
var Statistics = class {
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import AP214StepModel from "./ap214_step_model.js";
|
|
2
|
+
import { AP214ProductShapeMap } from "./ap214_product_shape_map.js";
|
|
3
|
+
/**
|
|
4
|
+
* A node in the extracted STEP product / assembly structure.
|
|
5
|
+
*
|
|
6
|
+
* The structure is *occurrence*-keyed, not product-keyed: STEP instancing lets
|
|
7
|
+
* one `product_definition` (a part *type*) appear many times in an assembly via
|
|
8
|
+
* distinct `next_assembly_usage_occurrence` (NAUO) edges. A scalar express id of
|
|
9
|
+
* the product cannot tell two visual instances apart, so each occurrence node
|
|
10
|
+
* carries both its NAUO express id (`expressID`) and the ordered
|
|
11
|
+
* `occurrencePath` (root→node, NAUO ids) that is the stable
|
|
12
|
+
* selection / permalink token. See
|
|
13
|
+
* `design/new/step-metadata-nist.md` §"Occurrence identity".
|
|
14
|
+
*
|
|
15
|
+
* This is the forcing function for Share's goal of generalizing its scalar
|
|
16
|
+
* `expressID` selection key into a format-agnostic *occurrence path* — flag it
|
|
17
|
+
* wherever this tree is consumed Share-side.
|
|
18
|
+
*/
|
|
19
|
+
export interface ProductStructureNode {
|
|
20
|
+
/**
|
|
21
|
+
* Node selection key. For an occurrence node this is the NAUO express id; for
|
|
22
|
+
* a root (single-part files have no NAUO) it falls back to the
|
|
23
|
+
* `product_definition` express id.
|
|
24
|
+
*/
|
|
25
|
+
expressID: number;
|
|
26
|
+
/** Readable node kind: `'product'` for roots, `'product_occurrence'` for NAUO nodes. */
|
|
27
|
+
type: string;
|
|
28
|
+
/** Display label: `product.name`, falling back to the NAUO name / reference designator. */
|
|
29
|
+
name: string;
|
|
30
|
+
/** Express id of the underlying `product_definition` (the part *type*). */
|
|
31
|
+
productDefinitionExpressID: number;
|
|
32
|
+
/** NAUO express id for occurrence nodes; `undefined` for roots. */
|
|
33
|
+
occurrenceExpressID?: number;
|
|
34
|
+
/**
|
|
35
|
+
* Ordered occurrence path (NAUO express ids) from the top-level occurrence to
|
|
36
|
+
* this node. Empty for roots. Disambiguates instances of the same part — e.g.
|
|
37
|
+
* `[3810, 1921, 1910]` vs `[6217, 1921, 1910]` for the two bolts in `as1`.
|
|
38
|
+
*/
|
|
39
|
+
occurrencePath: number[];
|
|
40
|
+
/**
|
|
41
|
+
* Shape representation express ids linked to this part (via
|
|
42
|
+
* `product_definition_shape` → `shape_definition_representation`). The seam to
|
|
43
|
+
* scene geometry for NavTree-click ⇄ viewport-pick round-tripping.
|
|
44
|
+
*/
|
|
45
|
+
shapeRepresentationIds: number[];
|
|
46
|
+
/** Child occurrence nodes. */
|
|
47
|
+
children: ProductStructureNode[];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Extracts the STEP product / assembly structure from a populated
|
|
51
|
+
* {@link AP214StepModel} into a nested, named, occurrence-keyed tree.
|
|
52
|
+
*
|
|
53
|
+
* Mirrors the IFC precedent (`src/ifc/ifc_property_extraction.ts`) but for
|
|
54
|
+
* AP214/AP242: walks `product` / `product_definition` /
|
|
55
|
+
* `next_assembly_usage_occurrence` into a tree, resolves labels from
|
|
56
|
+
* `product.name`, and links each part to its shape representations so a NavTree
|
|
57
|
+
* node can highlight the right geometry instance.
|
|
58
|
+
*/
|
|
59
|
+
export declare class AP214ProductStructureExtraction {
|
|
60
|
+
private readonly model;
|
|
61
|
+
private readonly productShapeMap?;
|
|
62
|
+
private readonly nauosByParent_;
|
|
63
|
+
private readonly childProductDefIds_;
|
|
64
|
+
private readonly productDefById_;
|
|
65
|
+
private readonly shapeRepsByProductDef_;
|
|
66
|
+
/**
|
|
67
|
+
* @param model The populated AP214/AP242 step model to walk.
|
|
68
|
+
* @param productShapeMap Optional product↔shape map populated during geometry
|
|
69
|
+
* extraction. When provided its links are merged with the ones derived here so
|
|
70
|
+
* the tree's `shapeRepresentationIds` agree with the scene; the map is empty
|
|
71
|
+
* unless geometry extraction has run, so the entity-graph walk below is the
|
|
72
|
+
* primary source.
|
|
73
|
+
*/
|
|
74
|
+
constructor(model: AP214StepModel, productShapeMap?: AP214ProductShapeMap | undefined);
|
|
75
|
+
/**
|
|
76
|
+
* Build the product-structure tree.
|
|
77
|
+
*
|
|
78
|
+
* @return {ProductStructureNode[]} The roots of the assembly forest. A
|
|
79
|
+
* single-part file yields one root; a multi-level assembly (e.g. `as1`) yields
|
|
80
|
+
* one root whose descendants are the NAUO occurrences.
|
|
81
|
+
*/
|
|
82
|
+
extractProductStructure(): ProductStructureNode[];
|
|
83
|
+
/**
|
|
84
|
+
* Index every `product_definition` by express id for O(1) lookup during the
|
|
85
|
+
* recursive walk.
|
|
86
|
+
*/
|
|
87
|
+
private indexProductDefinitions;
|
|
88
|
+
/**
|
|
89
|
+
* Index every NAUO by its parent (`relating_product_definition`) express id
|
|
90
|
+
* and record which product definitions appear as a child
|
|
91
|
+
* (`related_product_definition`) so roots can be identified.
|
|
92
|
+
*/
|
|
93
|
+
private indexAssemblyUsages;
|
|
94
|
+
/**
|
|
95
|
+
* Link product definitions to their shape representations by walking
|
|
96
|
+
* `shape_definition_representation` → `product_definition_shape` →
|
|
97
|
+
* `product_definition`, and merge any links already present in the
|
|
98
|
+
* geometry-extraction product↔shape map.
|
|
99
|
+
*/
|
|
100
|
+
private indexShapeRepresentations;
|
|
101
|
+
/**
|
|
102
|
+
* Record a shape-representation id for a product definition, de-duplicating.
|
|
103
|
+
*
|
|
104
|
+
* @param productDefId The product definition express id.
|
|
105
|
+
* @param shapeId The shape representation express id to associate.
|
|
106
|
+
*/
|
|
107
|
+
private addShapeRepresentation;
|
|
108
|
+
/**
|
|
109
|
+
* Recursively build a tree node for one product-definition occurrence.
|
|
110
|
+
*
|
|
111
|
+
* @param productDef The product definition this node represents.
|
|
112
|
+
* @param occurrence The NAUO edge that introduced this occurrence, or
|
|
113
|
+
* `undefined` for a root.
|
|
114
|
+
* @param parentPath The occurrence path of the parent node (NAUO ids).
|
|
115
|
+
* @param onPath Product-definition ids currently on the recursion stack;
|
|
116
|
+
* guards against a malformed cyclic assembly causing infinite recursion (a
|
|
117
|
+
* legitimately re-used part in sibling branches is unaffected).
|
|
118
|
+
* @return {ProductStructureNode} The built node, with children.
|
|
119
|
+
*/
|
|
120
|
+
private buildNode;
|
|
121
|
+
/**
|
|
122
|
+
* Resolve a node label, preferring the product name, then the occurrence's
|
|
123
|
+
* own name / reference designator.
|
|
124
|
+
*
|
|
125
|
+
* @param productDef The product definition for the node.
|
|
126
|
+
* @param occurrence The NAUO edge, when this is an occurrence node.
|
|
127
|
+
* @return {string} The best available human-readable label.
|
|
128
|
+
*/
|
|
129
|
+
private resolveLabel;
|
|
130
|
+
/**
|
|
131
|
+
* Resolve the owning `product_definition` express id from a
|
|
132
|
+
* `property_definition`-style `definition` select. Handles the direct
|
|
133
|
+
* `product_definition` case and the `product_definition_shape` indirection
|
|
134
|
+
* (its own `definition` points at the product definition).
|
|
135
|
+
*
|
|
136
|
+
* @param definition The resolved `definition` reference, or `undefined`.
|
|
137
|
+
* @return {number | undefined} The product definition express id, or
|
|
138
|
+
* `undefined` if it does not resolve to one.
|
|
139
|
+
*/
|
|
140
|
+
static resolveProductDefinitionId(definition: {
|
|
141
|
+
expressID?: number;
|
|
142
|
+
} | undefined): number | undefined;
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=ap214_product_structure_extraction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ap214_product_structure_extraction.d.ts","sourceRoot":"","sources":["../../../src/AP214E3_2010/ap214_product_structure_extraction.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,MAAM,oBAAoB,CAAA;AAC/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAA;AAOhE;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,oBAAoB;IAEnC;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAA;IAEjB,wFAAwF;IACxF,IAAI,EAAE,MAAM,CAAA;IAEZ,2FAA2F;IAC3F,IAAI,EAAE,MAAM,CAAA;IAEZ,2EAA2E;IAC3E,0BAA0B,EAAE,MAAM,CAAA;IAElC,mEAAmE;IACnE,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAE5B;;;;OAIG;IACH,cAAc,EAAE,MAAM,EAAE,CAAA;IAExB;;;;OAIG;IACH,sBAAsB,EAAE,MAAM,EAAE,CAAA;IAEhC,8BAA8B;IAC9B,QAAQ,EAAE,oBAAoB,EAAE,CAAA;CACjC;AAMD;;;;;;;;;GASG;AACH,qBAAa,+BAA+B;IAgBtC,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC;IAfrC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAsD;IACrF,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAoB;IACxD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAwC;IACxE,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAA8B;IAErE;;;;;;;OAOG;gBAEkB,KAAK,EAAE,cAAc,EACrB,eAAe,CAAC,kCAAsB;IAG3D;;;;;;OAMG;IACI,uBAAuB,IAAI,oBAAoB,EAAE;IA6BxD;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAa/B;;;;OAIG;IACH,OAAO,CAAC,mBAAmB;IA0B3B;;;;;OAKG;IACH,OAAO,CAAC,yBAAyB;IAiCjC;;;;;OAKG;IACH,OAAO,CAAC,sBAAsB;IAc9B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,SAAS;IAsDjB;;;;;;;OAOG;IACH,OAAO,CAAC,YAAY;IA0BpB;;;;;;;;;OASG;IACH,MAAM,CAAC,0BAA0B,CAC7B,UAAU,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,GAAI,MAAM,GAAG,SAAS;CAgBzE"}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { next_assembly_usage_occurrence } from "./AP214E3_2010_gen/next_assembly_usage_occurrence.gen.js";
|
|
2
|
+
import { product_definition } from "./AP214E3_2010_gen/product_definition.gen.js";
|
|
3
|
+
import { product_definition_shape } from "./AP214E3_2010_gen/product_definition_shape.gen.js";
|
|
4
|
+
import { shape_definition_representation } from "./AP214E3_2010_gen/shape_definition_representation.gen.js";
|
|
5
|
+
/** Readable node-kind strings for {@link ProductStructureNode.type}. */
|
|
6
|
+
const ROOT_NODE_TYPE = "product";
|
|
7
|
+
const OCCURRENCE_NODE_TYPE = "product_occurrence";
|
|
8
|
+
/**
|
|
9
|
+
* Extracts the STEP product / assembly structure from a populated
|
|
10
|
+
* {@link AP214StepModel} into a nested, named, occurrence-keyed tree.
|
|
11
|
+
*
|
|
12
|
+
* Mirrors the IFC precedent (`src/ifc/ifc_property_extraction.ts`) but for
|
|
13
|
+
* AP214/AP242: walks `product` / `product_definition` /
|
|
14
|
+
* `next_assembly_usage_occurrence` into a tree, resolves labels from
|
|
15
|
+
* `product.name`, and links each part to its shape representations so a NavTree
|
|
16
|
+
* node can highlight the right geometry instance.
|
|
17
|
+
*/
|
|
18
|
+
export class AP214ProductStructureExtraction {
|
|
19
|
+
/**
|
|
20
|
+
* @param model The populated AP214/AP242 step model to walk.
|
|
21
|
+
* @param productShapeMap Optional product↔shape map populated during geometry
|
|
22
|
+
* extraction. When provided its links are merged with the ones derived here so
|
|
23
|
+
* the tree's `shapeRepresentationIds` agree with the scene; the map is empty
|
|
24
|
+
* unless geometry extraction has run, so the entity-graph walk below is the
|
|
25
|
+
* primary source.
|
|
26
|
+
*/
|
|
27
|
+
constructor(model, productShapeMap) {
|
|
28
|
+
this.model = model;
|
|
29
|
+
this.productShapeMap = productShapeMap;
|
|
30
|
+
this.nauosByParent_ = new Map();
|
|
31
|
+
this.childProductDefIds_ = new Set();
|
|
32
|
+
this.productDefById_ = new Map();
|
|
33
|
+
this.shapeRepsByProductDef_ = new Map();
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Build the product-structure tree.
|
|
37
|
+
*
|
|
38
|
+
* @return {ProductStructureNode[]} The roots of the assembly forest. A
|
|
39
|
+
* single-part file yields one root; a multi-level assembly (e.g. `as1`) yields
|
|
40
|
+
* one root whose descendants are the NAUO occurrences.
|
|
41
|
+
*/
|
|
42
|
+
extractProductStructure() {
|
|
43
|
+
this.indexProductDefinitions();
|
|
44
|
+
this.indexAssemblyUsages();
|
|
45
|
+
this.indexShapeRepresentations();
|
|
46
|
+
const roots = [];
|
|
47
|
+
for (const [productDefId, productDef] of this.productDefById_) {
|
|
48
|
+
if (this.childProductDefIds_.has(productDefId)) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
// A genuine root is a part: it has geometry and/or sub-assembly children.
|
|
52
|
+
// This excludes stray product_definitions referenced only by metadata.
|
|
53
|
+
const hasChildren = this.nauosByParent_.has(productDefId);
|
|
54
|
+
const hasShape = this.shapeRepsByProductDef_.has(productDefId);
|
|
55
|
+
if (!hasChildren && !hasShape) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
roots.push(this.buildNode(productDef, undefined, [], new Set()));
|
|
59
|
+
}
|
|
60
|
+
return roots;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Index every `product_definition` by express id for O(1) lookup during the
|
|
64
|
+
* recursive walk.
|
|
65
|
+
*/
|
|
66
|
+
indexProductDefinitions() {
|
|
67
|
+
for (const element of this.model.types(product_definition)) {
|
|
68
|
+
const productDef = element;
|
|
69
|
+
const expressID = productDef.expressID;
|
|
70
|
+
if (expressID !== void 0) {
|
|
71
|
+
this.productDefById_.set(expressID, productDef);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Index every NAUO by its parent (`relating_product_definition`) express id
|
|
77
|
+
* and record which product definitions appear as a child
|
|
78
|
+
* (`related_product_definition`) so roots can be identified.
|
|
79
|
+
*/
|
|
80
|
+
indexAssemblyUsages() {
|
|
81
|
+
for (const element of this.model.types(next_assembly_usage_occurrence)) {
|
|
82
|
+
const nauo = element;
|
|
83
|
+
const parentId = nauo.relating_product_definition?.expressID;
|
|
84
|
+
const childId = nauo.related_product_definition?.expressID;
|
|
85
|
+
if (parentId === void 0 || childId === void 0) {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
this.childProductDefIds_.add(childId);
|
|
89
|
+
let siblings = this.nauosByParent_.get(parentId);
|
|
90
|
+
if (siblings === void 0) {
|
|
91
|
+
siblings = [];
|
|
92
|
+
this.nauosByParent_.set(parentId, siblings);
|
|
93
|
+
}
|
|
94
|
+
siblings.push(nauo);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Link product definitions to their shape representations by walking
|
|
99
|
+
* `shape_definition_representation` → `product_definition_shape` →
|
|
100
|
+
* `product_definition`, and merge any links already present in the
|
|
101
|
+
* geometry-extraction product↔shape map.
|
|
102
|
+
*/
|
|
103
|
+
indexShapeRepresentations() {
|
|
104
|
+
for (const element of this.model.types(shape_definition_representation)) {
|
|
105
|
+
const sdr = element;
|
|
106
|
+
const productDefId = AP214ProductStructureExtraction.resolveProductDefinitionId(sdr.definition);
|
|
107
|
+
if (productDefId === void 0) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
// The shape id is the *used_representation* (the geometry), not the SDR's
|
|
111
|
+
// own id — falling back to `sdr.expressID` would store a non-geometry id
|
|
112
|
+
// that a pick-reconciliation consumer could not resolve to a scene mesh.
|
|
113
|
+
const shapeId = sdr.used_representation?.expressID;
|
|
114
|
+
if (shapeId !== void 0) {
|
|
115
|
+
this.addShapeRepresentation(productDefId, shapeId);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (this.productShapeMap === void 0) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
for (const [productDefId, shapes] of this.productShapeMap.productDefsToShapes()) {
|
|
122
|
+
for (const shapeId of shapes) {
|
|
123
|
+
this.addShapeRepresentation(productDefId, shapeId);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Record a shape-representation id for a product definition, de-duplicating.
|
|
129
|
+
*
|
|
130
|
+
* @param productDefId The product definition express id.
|
|
131
|
+
* @param shapeId The shape representation express id to associate.
|
|
132
|
+
*/
|
|
133
|
+
addShapeRepresentation(productDefId, shapeId) {
|
|
134
|
+
let shapes = this.shapeRepsByProductDef_.get(productDefId);
|
|
135
|
+
if (shapes === void 0) {
|
|
136
|
+
shapes = [];
|
|
137
|
+
this.shapeRepsByProductDef_.set(productDefId, shapes);
|
|
138
|
+
}
|
|
139
|
+
if (!shapes.includes(shapeId)) {
|
|
140
|
+
shapes.push(shapeId);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Recursively build a tree node for one product-definition occurrence.
|
|
145
|
+
*
|
|
146
|
+
* @param productDef The product definition this node represents.
|
|
147
|
+
* @param occurrence The NAUO edge that introduced this occurrence, or
|
|
148
|
+
* `undefined` for a root.
|
|
149
|
+
* @param parentPath The occurrence path of the parent node (NAUO ids).
|
|
150
|
+
* @param onPath Product-definition ids currently on the recursion stack;
|
|
151
|
+
* guards against a malformed cyclic assembly causing infinite recursion (a
|
|
152
|
+
* legitimately re-used part in sibling branches is unaffected).
|
|
153
|
+
* @return {ProductStructureNode} The built node, with children.
|
|
154
|
+
*/
|
|
155
|
+
buildNode(productDef, occurrence, parentPath, onPath) {
|
|
156
|
+
const productDefId = productDef.expressID;
|
|
157
|
+
const label = this.resolveLabel(productDef, occurrence);
|
|
158
|
+
const occurrenceExpressID = occurrence?.expressID;
|
|
159
|
+
const occurrencePath = occurrenceExpressID !== void 0 ?
|
|
160
|
+
[...parentPath, occurrenceExpressID] : [...parentPath];
|
|
161
|
+
const node = {
|
|
162
|
+
expressID: occurrenceExpressID ?? productDefId,
|
|
163
|
+
type: occurrence !== void 0 ? OCCURRENCE_NODE_TYPE : ROOT_NODE_TYPE,
|
|
164
|
+
name: label,
|
|
165
|
+
productDefinitionExpressID: productDefId,
|
|
166
|
+
occurrenceExpressID,
|
|
167
|
+
occurrencePath,
|
|
168
|
+
shapeRepresentationIds: this.shapeRepsByProductDef_.get(productDefId) ?? [],
|
|
169
|
+
children: [],
|
|
170
|
+
};
|
|
171
|
+
const childUsages = this.nauosByParent_.get(productDefId);
|
|
172
|
+
if (childUsages === void 0 || onPath.has(productDefId)) {
|
|
173
|
+
return node;
|
|
174
|
+
}
|
|
175
|
+
onPath.add(productDefId);
|
|
176
|
+
for (const childUsage of childUsages) {
|
|
177
|
+
const childDefId = childUsage.related_product_definition?.expressID;
|
|
178
|
+
if (childDefId === void 0) {
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
const childDef = this.productDefById_.get(childDefId);
|
|
182
|
+
if (childDef === void 0) {
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
node.children.push(this.buildNode(childDef, childUsage, occurrencePath, onPath));
|
|
186
|
+
}
|
|
187
|
+
onPath.delete(productDefId);
|
|
188
|
+
return node;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Resolve a node label, preferring the product name, then the occurrence's
|
|
192
|
+
* own name / reference designator.
|
|
193
|
+
*
|
|
194
|
+
* @param productDef The product definition for the node.
|
|
195
|
+
* @param occurrence The NAUO edge, when this is an occurrence node.
|
|
196
|
+
* @return {string} The best available human-readable label.
|
|
197
|
+
*/
|
|
198
|
+
resolveLabel(productDef, occurrence) {
|
|
199
|
+
const productName = productDef.formation?.of_product?.name;
|
|
200
|
+
if (productName !== void 0 && productName.length > 0) {
|
|
201
|
+
return productName;
|
|
202
|
+
}
|
|
203
|
+
if (occurrence !== void 0) {
|
|
204
|
+
if (occurrence.name.length > 0) {
|
|
205
|
+
return occurrence.name;
|
|
206
|
+
}
|
|
207
|
+
const referenceDesignator = occurrence.reference_designator;
|
|
208
|
+
if (referenceDesignator !== null && referenceDesignator.length > 0) {
|
|
209
|
+
return referenceDesignator;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return productDef.name ?? "";
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Resolve the owning `product_definition` express id from a
|
|
216
|
+
* `property_definition`-style `definition` select. Handles the direct
|
|
217
|
+
* `product_definition` case and the `product_definition_shape` indirection
|
|
218
|
+
* (its own `definition` points at the product definition).
|
|
219
|
+
*
|
|
220
|
+
* @param definition The resolved `definition` reference, or `undefined`.
|
|
221
|
+
* @return {number | undefined} The product definition express id, or
|
|
222
|
+
* `undefined` if it does not resolve to one.
|
|
223
|
+
*/
|
|
224
|
+
static resolveProductDefinitionId(definition) {
|
|
225
|
+
if (definition === void 0) {
|
|
226
|
+
return void 0;
|
|
227
|
+
}
|
|
228
|
+
if (definition instanceof product_definition) {
|
|
229
|
+
return definition.expressID;
|
|
230
|
+
}
|
|
231
|
+
if (definition instanceof product_definition_shape) {
|
|
232
|
+
return AP214ProductStructureExtraction.resolveProductDefinitionId(definition.definition);
|
|
233
|
+
}
|
|
234
|
+
return void 0;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ap214_product_structure_extraction.test.d.ts","sourceRoot":"","sources":["../../../src/AP214E3_2010/ap214_product_structure_extraction.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import { describe, expect, test } from "@jest/globals";
|
|
3
|
+
import AP214StepParser from "./ap214_step_parser.js";
|
|
4
|
+
import ParsingBuffer from "../parsing/parsing_buffer.js";
|
|
5
|
+
import { ParseResult } from "../step/parsing/step_parser.js";
|
|
6
|
+
import { AP214ProductStructureExtraction, } from "./ap214_product_structure_extraction.js";
|
|
7
|
+
const parser = AP214StepParser.Instance;
|
|
8
|
+
/**
|
|
9
|
+
* Parse the hermetic as1 assembly fixture and extract its product structure.
|
|
10
|
+
*
|
|
11
|
+
* @return {ProductStructureNode[]} The extracted assembly forest.
|
|
12
|
+
*/
|
|
13
|
+
function extractAs1Structure() {
|
|
14
|
+
const buffer = fs.readFileSync("data/as1-assembly.step");
|
|
15
|
+
const bufferInput = new ParsingBuffer(buffer);
|
|
16
|
+
const headerResult = parser.parseHeader(bufferInput)[1];
|
|
17
|
+
expect(headerResult).toBe(ParseResult.COMPLETE);
|
|
18
|
+
const [result, model] = parser.parseDataToModel(bufferInput);
|
|
19
|
+
expect(model).not.toBe(void 0);
|
|
20
|
+
expect(result === ParseResult.COMPLETE || result === ParseResult.INCOMPLETE).toBe(true);
|
|
21
|
+
return new AP214ProductStructureExtraction(model).extractProductStructure();
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Find a direct child of a node by display name.
|
|
25
|
+
*
|
|
26
|
+
* @param node The parent node.
|
|
27
|
+
* @param name The child name to find.
|
|
28
|
+
* @return {ProductStructureNode} The first matching child.
|
|
29
|
+
*/
|
|
30
|
+
function child(node, name) {
|
|
31
|
+
const found = node.children.find((candidate) => candidate.name === name);
|
|
32
|
+
expect(found).not.toBe(void 0);
|
|
33
|
+
return found;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Names of the direct children of a node.
|
|
37
|
+
*
|
|
38
|
+
* @param node The parent node.
|
|
39
|
+
* @return {string[]} The child names, in order.
|
|
40
|
+
*/
|
|
41
|
+
function childNames(node) {
|
|
42
|
+
return node.children.map((candidate) => candidate.name);
|
|
43
|
+
}
|
|
44
|
+
const NUT_BOLT_ASSEMBLY_INSTANCE_COUNT = 3;
|
|
45
|
+
const AS1_ROOT_CHILD_COUNT = 4;
|
|
46
|
+
describe("AP214ProductStructureExtraction", () => {
|
|
47
|
+
test("extracts a single named root for the as1 assembly", () => {
|
|
48
|
+
const roots = extractAs1Structure();
|
|
49
|
+
expect(roots.length).toBe(1);
|
|
50
|
+
expect(roots[0].name).toBe("as1");
|
|
51
|
+
expect(roots[0].occurrencePath).toEqual([]);
|
|
52
|
+
});
|
|
53
|
+
test("builds the nested nut/rod/bracket/plate hierarchy with names", () => {
|
|
54
|
+
const root = extractAs1Structure()[0];
|
|
55
|
+
expect(childNames(root).sort()).toEqual(["l-bracket-assembly", "l-bracket-assembly", "plate", "rod-assembly"]);
|
|
56
|
+
const rodAssembly = child(root, "rod-assembly");
|
|
57
|
+
expect(childNames(rodAssembly).sort()).toEqual(["nut", "nut", "rod"]);
|
|
58
|
+
const lBracketAssembly = child(root, "l-bracket-assembly");
|
|
59
|
+
expect(childNames(lBracketAssembly).sort()).toEqual(["l-bracket", "nut-bolt-assembly", "nut-bolt-assembly", "nut-bolt-assembly"]);
|
|
60
|
+
const nutBoltAssembly = child(lBracketAssembly, "nut-bolt-assembly");
|
|
61
|
+
expect(childNames(nutBoltAssembly).sort()).toEqual(["bolt", "nut"]);
|
|
62
|
+
});
|
|
63
|
+
test("gives repeated sub-assembly occurrences distinct nodes and paths", () => {
|
|
64
|
+
const root = extractAs1Structure()[0];
|
|
65
|
+
const lBracketAssemblies = root.children.filter((node) => node.name === "l-bracket-assembly");
|
|
66
|
+
// Two occurrences of the SAME product_definition: same part type id...
|
|
67
|
+
expect(lBracketAssemblies.length).toBe(2);
|
|
68
|
+
expect(lBracketAssemblies[0].productDefinitionExpressID)
|
|
69
|
+
.toBe(lBracketAssemblies[1].productDefinitionExpressID);
|
|
70
|
+
// ...but distinct occurrence (NAUO) keys and distinct paths.
|
|
71
|
+
expect(lBracketAssemblies[0].expressID)
|
|
72
|
+
.not.toBe(lBracketAssemblies[1].expressID);
|
|
73
|
+
expect(lBracketAssemblies[0].occurrencePath)
|
|
74
|
+
.not.toEqual(lBracketAssemblies[1].occurrencePath);
|
|
75
|
+
});
|
|
76
|
+
test("disambiguates a reused leaf part by full occurrence path", () => {
|
|
77
|
+
const root = extractAs1Structure()[0];
|
|
78
|
+
const lBracketAssemblies = root.children.filter((node) => node.name === "l-bracket-assembly");
|
|
79
|
+
const boltPaths = lBracketAssemblies.map((assembly) => {
|
|
80
|
+
const nutBoltAssembly = child(assembly, "nut-bolt-assembly");
|
|
81
|
+
return child(nutBoltAssembly, "bolt").occurrencePath;
|
|
82
|
+
});
|
|
83
|
+
// Same leaf NAUO id at the tail, but the path roots differ — exactly the
|
|
84
|
+
// instancing case a scalar expressID cannot represent.
|
|
85
|
+
expect(boltPaths[0]).not.toEqual(boltPaths[1]);
|
|
86
|
+
expect(boltPaths[0][boltPaths[0].length - 1])
|
|
87
|
+
.toBe(boltPaths[1][boltPaths[1].length - 1]);
|
|
88
|
+
expect(boltPaths[0][0]).not.toBe(boltPaths[1][0]);
|
|
89
|
+
});
|
|
90
|
+
test("each nut-bolt-assembly occurrence has its own bolt and nut", () => {
|
|
91
|
+
const root = extractAs1Structure()[0];
|
|
92
|
+
const lBracketAssembly = child(root, "l-bracket-assembly");
|
|
93
|
+
const nutBoltAssemblies = lBracketAssembly.children.filter((node) => node.name === "nut-bolt-assembly");
|
|
94
|
+
expect(nutBoltAssemblies.length).toBe(NUT_BOLT_ASSEMBLY_INSTANCE_COUNT);
|
|
95
|
+
for (const nutBoltAssembly of nutBoltAssemblies) {
|
|
96
|
+
expect(childNames(nutBoltAssembly).sort()).toEqual(["bolt", "nut"]);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
test("links the root part to its shape representation", () => {
|
|
100
|
+
const root = extractAs1Structure()[0];
|
|
101
|
+
expect(root.shapeRepresentationIds.length).toBeGreaterThan(0);
|
|
102
|
+
});
|
|
103
|
+
test("root has the expected number of top-level occurrences", () => {
|
|
104
|
+
const root = extractAs1Structure()[0];
|
|
105
|
+
expect(root.children.length).toBe(AS1_ROOT_CHILD_COUNT);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import AP214StepModel from "./ap214_step_model.js";
|
|
2
|
+
/**
|
|
3
|
+
* One extracted key/value property row for a part.
|
|
4
|
+
*/
|
|
5
|
+
export interface ExtractedProperty {
|
|
6
|
+
/** Property key, e.g. `'Modeled By'`, `'volume measure'`. */
|
|
7
|
+
name: string;
|
|
8
|
+
/** Stringified value, e.g. `'Engineer'`, `'14644822.6361138'`. */
|
|
9
|
+
value: string;
|
|
10
|
+
/** Numeric value for measure properties (volume/area/…); `undefined` for text. */
|
|
11
|
+
numericValue?: number;
|
|
12
|
+
/**
|
|
13
|
+
* Grouping label from the owning `property_definition.name` — e.g.
|
|
14
|
+
* `'geometric validation property'` for NIST volume/area validation rows.
|
|
15
|
+
* Empty for plain attribute properties.
|
|
16
|
+
*/
|
|
17
|
+
group: string;
|
|
18
|
+
/**
|
|
19
|
+
* Express id of the source representation item (the
|
|
20
|
+
* `descriptive_representation_item` / `measure_representation_item`). The
|
|
21
|
+
* compat surface uses it as the property's own express id so the web-ifc
|
|
22
|
+
* `IfcPropertySet.HasProperties` reference handles can be resolved back to
|
|
23
|
+
* this row via `getItemProperties`. `undefined` if the item carried no id.
|
|
24
|
+
*/
|
|
25
|
+
expressID?: number;
|
|
26
|
+
}
|
|
27
|
+
/** Properties grouped by the express id of the owning `product_definition`. */
|
|
28
|
+
export type ExtractedPropertyMap = Map<number, ExtractedProperty[]>;
|
|
29
|
+
/** Minimal shape of a representation item needed for property conversion. */
|
|
30
|
+
interface RepresentationItemLike {
|
|
31
|
+
name: string;
|
|
32
|
+
expressID?: number;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Extracts STEP part properties from a populated {@link AP214StepModel}.
|
|
36
|
+
*
|
|
37
|
+
* Walks the property chain
|
|
38
|
+
* `general_property` → (`general_property_association`) → `property_definition`
|
|
39
|
+
* → `property_definition_representation` → `representation` →
|
|
40
|
+
* `descriptive_representation_item` / `measure_representation_item` into
|
|
41
|
+
* per-part key/value rows. Includes the NIST validation properties
|
|
42
|
+
* (`geometric/attribute validation property`, e.g. volume via
|
|
43
|
+
* `measure_representation_item`).
|
|
44
|
+
*
|
|
45
|
+
* Mirrors the IFC precedent (`src/ifc/ifc_property_extraction.ts`); feeds the
|
|
46
|
+
* web-ifc compat surface `ap214_properties.ts` that Share consumes.
|
|
47
|
+
*/
|
|
48
|
+
export declare class AP214PropertyExtraction {
|
|
49
|
+
private readonly model;
|
|
50
|
+
private readonly generalPropertyNameByDef_;
|
|
51
|
+
/**
|
|
52
|
+
* @param model The populated AP214/AP242 step model to walk.
|
|
53
|
+
*/
|
|
54
|
+
constructor(model: AP214StepModel);
|
|
55
|
+
/**
|
|
56
|
+
* Build the per-part property map.
|
|
57
|
+
*
|
|
58
|
+
* @return {ExtractedPropertyMap} Properties keyed by owning
|
|
59
|
+
* `product_definition` express id. Properties whose owner is a feature
|
|
60
|
+
* (`shape_aspect`, dimensions) rather than a part are skipped at this
|
|
61
|
+
* (Simplified) tier — they belong to the Full PMI tier.
|
|
62
|
+
*/
|
|
63
|
+
extractProperties(): ExtractedPropertyMap;
|
|
64
|
+
/**
|
|
65
|
+
* Index general-property names by the express id of the `property_definition`
|
|
66
|
+
* they are associated with, so a property can carry the canonical
|
|
67
|
+
* `general_property` label when one exists.
|
|
68
|
+
*/
|
|
69
|
+
private indexGeneralPropertyNames;
|
|
70
|
+
/**
|
|
71
|
+
* Resolve the part owner and value rows for one
|
|
72
|
+
* `property_definition_representation` and append them to the result map.
|
|
73
|
+
*
|
|
74
|
+
* @param pdr The property-definition representation to walk.
|
|
75
|
+
* @param result The accumulating per-part property map.
|
|
76
|
+
*/
|
|
77
|
+
private collectFromRepresentation;
|
|
78
|
+
/**
|
|
79
|
+
* Convert a representation item into a property row, or `undefined` for item
|
|
80
|
+
* kinds that carry no key/value (e.g. a centroid `cartesian_point`).
|
|
81
|
+
*
|
|
82
|
+
* @param item The representation item to convert.
|
|
83
|
+
* @param fallbackKey Key to use when the item itself is unnamed.
|
|
84
|
+
* @param group Grouping label from the owning property definition.
|
|
85
|
+
* @return {ExtractedProperty | undefined} The property row, or `undefined`.
|
|
86
|
+
*/
|
|
87
|
+
static toProperty(item: RepresentationItemLike, fallbackKey: string, group: string): ExtractedProperty | undefined;
|
|
88
|
+
}
|
|
89
|
+
export {};
|
|
90
|
+
//# sourceMappingURL=ap214_property_extraction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ap214_property_extraction.d.ts","sourceRoot":"","sources":["../../../src/AP214E3_2010/ap214_property_extraction.ts"],"names":[],"mappings":"AACA,OAAO,cAAc,MAAM,oBAAoB,CAAA;AAU/C;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAEhC,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAA;IAEZ,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAA;IAEb,kFAAkF;IAClF,YAAY,CAAC,EAAE,MAAM,CAAA;IAErB;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAA;IAEb;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,+EAA+E;AAC/E,MAAM,MAAM,oBAAoB,GAAG,GAAG,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAA;AAEnE,6EAA6E;AAC7E,UAAU,sBAAsB;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,uBAAuB;IAOrB,OAAO,CAAC,QAAQ,CAAC,KAAK;IALnC,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAA4B;IAEtE;;OAEG;gBAC2B,KAAK,EAAE,cAAc;IAGnD;;;;;;;OAOG;IACI,iBAAiB,IAAI,oBAAoB;IAsBhD;;;;OAIG;IACH,OAAO,CAAC,yBAAyB;IAsBjC;;;;;;OAMG;IACH,OAAO,CAAC,yBAAyB;IAgDjC;;;;;;;;OAQG;IACH,MAAM,CAAC,UAAU,CACb,IAAI,EAAE,sBAAsB,EAC5B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,GAAI,iBAAiB,GAAG,SAAS;CAiCnD"}
|