@ifc-lite/ifcx 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,227 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ import { ATTR, SPATIAL_TYPES } from './types.js';
5
+ import { IfcTypeEnum, IfcTypeEnumFromString } from '@ifc-lite/data';
6
+ /**
7
+ * Build spatial hierarchy from composed IFCX nodes.
8
+ *
9
+ * IFCX hierarchy comes from children relationships:
10
+ * - Project -> Site -> Building -> Storey -> Elements
11
+ *
12
+ * We identify spatial structure elements by their bsi::ifc::class codes.
13
+ */
14
+ export function buildHierarchy(composed, pathToId) {
15
+ // Find project root
16
+ const projectNode = findProjectRoot(composed);
17
+ if (!projectNode) {
18
+ return createEmptyHierarchy();
19
+ }
20
+ // Build spatial tree
21
+ const projectSpatial = buildSpatialNode(projectNode, pathToId);
22
+ // Build lookup maps
23
+ const byStorey = new Map();
24
+ const byBuilding = new Map();
25
+ const bySite = new Map();
26
+ const bySpace = new Map();
27
+ const storeyElevations = new Map();
28
+ const storeyHeights = new Map();
29
+ const elementToStorey = new Map();
30
+ // Traverse and populate maps
31
+ populateMaps(projectSpatial, null, null, null, pathToId, byStorey, byBuilding, bySite, bySpace, storeyElevations, elementToStorey);
32
+ // Note: storeyHeights remains empty - uses on-demand property extraction
33
+ return {
34
+ project: projectSpatial,
35
+ byStorey,
36
+ byBuilding,
37
+ bySite,
38
+ bySpace,
39
+ storeyElevations,
40
+ storeyHeights,
41
+ elementToStorey,
42
+ // Helper methods
43
+ getStoreyElements(storeyId) {
44
+ return byStorey.get(storeyId) || [];
45
+ },
46
+ getStoreyByElevation(z) {
47
+ let closestStorey = null;
48
+ let closestDist = Infinity;
49
+ for (const [storeyId, elevation] of storeyElevations) {
50
+ const dist = Math.abs(z - elevation);
51
+ if (dist < closestDist) {
52
+ closestDist = dist;
53
+ closestStorey = storeyId;
54
+ }
55
+ }
56
+ return closestStorey;
57
+ },
58
+ getContainingSpace(elementId) {
59
+ // Check if element is directly in a space
60
+ for (const [spaceId, elements] of bySpace) {
61
+ if (elements.includes(elementId)) {
62
+ return spaceId;
63
+ }
64
+ }
65
+ return null;
66
+ },
67
+ getPath(elementId) {
68
+ const path = [];
69
+ function findPath(node) {
70
+ if (node.expressId === elementId) {
71
+ path.push(node);
72
+ return true;
73
+ }
74
+ if (node.elements.includes(elementId)) {
75
+ path.push(node);
76
+ return true;
77
+ }
78
+ for (const child of node.children) {
79
+ if (findPath(child)) {
80
+ path.unshift(node);
81
+ return true;
82
+ }
83
+ }
84
+ return false;
85
+ }
86
+ findPath(projectSpatial);
87
+ return path;
88
+ },
89
+ };
90
+ }
91
+ /**
92
+ * Find the IfcProject node in composed nodes.
93
+ */
94
+ function findProjectRoot(composed) {
95
+ for (const node of composed.values()) {
96
+ const ifcClass = node.attributes.get(ATTR.CLASS);
97
+ if (ifcClass?.code === 'IfcProject') {
98
+ return node;
99
+ }
100
+ }
101
+ return null;
102
+ }
103
+ /**
104
+ * Build a SpatialNode from a ComposedNode.
105
+ */
106
+ function buildSpatialNode(node, pathToId) {
107
+ const ifcClass = node.attributes.get(ATTR.CLASS);
108
+ const expressId = pathToId.get(node.path) ?? 0;
109
+ const typeEnum = IfcTypeEnumFromString(ifcClass?.code ?? '');
110
+ const spatialNode = {
111
+ expressId,
112
+ type: typeEnum,
113
+ name: extractName(node) ?? node.path.slice(0, 8),
114
+ children: [],
115
+ elements: [],
116
+ };
117
+ // Extract elevation for storeys
118
+ if (ifcClass?.code === 'IfcBuildingStorey') {
119
+ const elevation = node.attributes.get('bsi::ifc::prop::Elevation');
120
+ if (typeof elevation === 'number') {
121
+ spatialNode.elevation = elevation;
122
+ }
123
+ }
124
+ // Process children
125
+ for (const [, child] of node.children) {
126
+ const childClass = child.attributes.get(ATTR.CLASS);
127
+ if (childClass && SPATIAL_TYPES.has(childClass.code)) {
128
+ // Spatial child - recurse
129
+ spatialNode.children.push(buildSpatialNode(child, pathToId));
130
+ }
131
+ else if (childClass) {
132
+ // Element - add to elements list
133
+ const childId = pathToId.get(child.path);
134
+ if (childId !== undefined) {
135
+ spatialNode.elements.push(childId);
136
+ }
137
+ }
138
+ // Geometry-only children (Body, Axis, etc.) are skipped
139
+ }
140
+ return spatialNode;
141
+ }
142
+ /**
143
+ * Populate lookup maps by traversing the spatial hierarchy.
144
+ */
145
+ function populateMaps(node, currentStorey, currentBuilding, currentSite, pathToId, byStorey, byBuilding, bySite, bySpace, storeyElevations, elementToStorey) {
146
+ // Update current context based on node type
147
+ if (node.type === IfcTypeEnum.IfcBuildingStorey) {
148
+ currentStorey = node.expressId;
149
+ if (node.elevation !== undefined) {
150
+ storeyElevations.set(node.expressId, node.elevation);
151
+ }
152
+ byStorey.set(node.expressId, []);
153
+ }
154
+ else if (node.type === IfcTypeEnum.IfcBuilding) {
155
+ currentBuilding = node.expressId;
156
+ byBuilding.set(node.expressId, []);
157
+ }
158
+ else if (node.type === IfcTypeEnum.IfcSite) {
159
+ currentSite = node.expressId;
160
+ bySite.set(node.expressId, []);
161
+ }
162
+ else if (node.type === IfcTypeEnum.IfcSpace) {
163
+ bySpace.set(node.expressId, []);
164
+ }
165
+ // Add elements to appropriate maps
166
+ for (const elementId of node.elements) {
167
+ if (currentStorey !== null) {
168
+ byStorey.get(currentStorey)?.push(elementId);
169
+ elementToStorey.set(elementId, currentStorey);
170
+ }
171
+ if (currentBuilding !== null) {
172
+ byBuilding.get(currentBuilding)?.push(elementId);
173
+ }
174
+ if (currentSite !== null) {
175
+ bySite.get(currentSite)?.push(elementId);
176
+ }
177
+ if (node.type === IfcTypeEnum.IfcSpace) {
178
+ bySpace.get(node.expressId)?.push(elementId);
179
+ }
180
+ }
181
+ // Recurse to children
182
+ for (const child of node.children) {
183
+ populateMaps(child, currentStorey, currentBuilding, currentSite, pathToId, byStorey, byBuilding, bySite, bySpace, storeyElevations, elementToStorey);
184
+ }
185
+ }
186
+ /**
187
+ * Create an empty hierarchy when no project is found.
188
+ */
189
+ function createEmptyHierarchy() {
190
+ const emptyProject = {
191
+ expressId: 0,
192
+ type: IfcTypeEnum.IfcProject,
193
+ name: 'Unknown Project',
194
+ children: [],
195
+ elements: [],
196
+ };
197
+ return {
198
+ project: emptyProject,
199
+ byStorey: new Map(),
200
+ byBuilding: new Map(),
201
+ bySite: new Map(),
202
+ bySpace: new Map(),
203
+ storeyElevations: new Map(),
204
+ storeyHeights: new Map(),
205
+ elementToStorey: new Map(),
206
+ getStoreyElements: () => [],
207
+ getStoreyByElevation: () => null,
208
+ getContainingSpace: () => null,
209
+ getPath: () => [],
210
+ };
211
+ }
212
+ /**
213
+ * Extract name from node attributes.
214
+ */
215
+ function extractName(node) {
216
+ const name = node.attributes.get('bsi::ifc::prop::Name');
217
+ if (typeof name === 'string')
218
+ return name;
219
+ const typeName = node.attributes.get('bsi::ifc::prop::TypeName');
220
+ if (typeof typeName === 'string')
221
+ return typeName;
222
+ const longName = node.attributes.get('bsi::ifc::prop::LongName');
223
+ if (typeof longName === 'string')
224
+ return longName;
225
+ return null;
226
+ }
227
+ //# sourceMappingURL=hierarchy-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hierarchy-builder.js","sourceRoot":"","sources":["../src/hierarchy-builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ import { type MeshData } from './geometry-extractor.js';
2
+ import { StringTable } from '@ifc-lite/data';
3
+ import type { SpatialHierarchy, EntityTable, PropertyTable, QuantityTable, RelationshipGraph } from '@ifc-lite/data';
4
+ export * from './types.js';
5
+ export { composeIfcx, findRoots, getDescendants, getPathToRoot } from './composition.js';
6
+ export { extractEntities } from './entity-extractor.js';
7
+ export { extractProperties, isQuantityProperty } from './property-extractor.js';
8
+ export { extractGeometry, type MeshData } from './geometry-extractor.js';
9
+ export { buildHierarchy } from './hierarchy-builder.js';
10
+ /**
11
+ * Result of parsing an IFCX file.
12
+ * Compatible with existing ifc-lite data structures.
13
+ */
14
+ export interface IfcxParseResult {
15
+ /** Columnar entity table */
16
+ entities: EntityTable;
17
+ /** Columnar property table */
18
+ properties: PropertyTable;
19
+ /** Columnar quantity table */
20
+ quantities: QuantityTable;
21
+ /** Relationship graph */
22
+ relationships: RelationshipGraph;
23
+ /** Spatial hierarchy */
24
+ spatialHierarchy: SpatialHierarchy;
25
+ /** String table for interned strings */
26
+ strings: StringTable;
27
+ /** Pre-tessellated geometry meshes */
28
+ meshes: MeshData[];
29
+ /** Mapping from IFCX path to express ID */
30
+ pathToId: Map<string, number>;
31
+ /** Mapping from express ID to IFCX path */
32
+ idToPath: Map<number, string>;
33
+ /** Schema version */
34
+ schemaVersion: 'IFC5';
35
+ /** File size in bytes */
36
+ fileSize: number;
37
+ /** Number of entities */
38
+ entityCount: number;
39
+ /** Parse time in milliseconds */
40
+ parseTime: number;
41
+ }
42
+ export interface IfcxParseOptions {
43
+ /** Progress callback */
44
+ onProgress?: (progress: {
45
+ phase: string;
46
+ percent: number;
47
+ }) => void;
48
+ }
49
+ /**
50
+ * Parse an IFCX file and return data compatible with existing ifc-lite pipeline.
51
+ */
52
+ export declare function parseIfcx(buffer: ArrayBuffer, options?: IfcxParseOptions): Promise<IfcxParseResult>;
53
+ /**
54
+ * Detect if a buffer contains IFCX (JSON) or IFC (STEP) format.
55
+ */
56
+ export declare function detectFormat(buffer: ArrayBuffer): 'ifcx' | 'ifc' | 'unknown';
57
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAEzE,OAAO,EACL,WAAW,EAIZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGrH,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACzF,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAChF,OAAO,EAAE,eAAe,EAAE,KAAK,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,4BAA4B;IAC5B,QAAQ,EAAE,WAAW,CAAC;IACtB,8BAA8B;IAC9B,UAAU,EAAE,aAAa,CAAC;IAC1B,8BAA8B;IAC9B,UAAU,EAAE,aAAa,CAAC;IAC1B,yBAAyB;IACzB,aAAa,EAAE,iBAAiB,CAAC;IACjC,wBAAwB;IACxB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,wCAAwC;IACxC,OAAO,EAAE,WAAW,CAAC;IACrB,sCAAsC;IACtC,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,2CAA2C;IAC3C,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,2CAA2C;IAC3C,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,qBAAqB;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,yBAAyB;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,yBAAyB;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,iCAAiC;IACjC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,wBAAwB;IACxB,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CACrE;AAED;;GAEG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,WAAW,EACnB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,eAAe,CAAC,CAwE1B;AAiHD;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,CAe5E"}
package/dist/index.js ADDED
@@ -0,0 +1,189 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ import { composeIfcx } from './composition.js';
5
+ import { extractEntities } from './entity-extractor.js';
6
+ import { extractProperties, isQuantityProperty } from './property-extractor.js';
7
+ import { extractGeometry } from './geometry-extractor.js';
8
+ import { buildHierarchy } from './hierarchy-builder.js';
9
+ import { StringTable, RelationshipGraphBuilder, RelationshipType, QuantityTableBuilder, } from '@ifc-lite/data';
10
+ // Re-export types
11
+ export * from './types.js';
12
+ export { composeIfcx, findRoots, getDescendants, getPathToRoot } from './composition.js';
13
+ export { extractEntities } from './entity-extractor.js';
14
+ export { extractProperties, isQuantityProperty } from './property-extractor.js';
15
+ export { extractGeometry } from './geometry-extractor.js';
16
+ export { buildHierarchy } from './hierarchy-builder.js';
17
+ /**
18
+ * Parse an IFCX file and return data compatible with existing ifc-lite pipeline.
19
+ */
20
+ export async function parseIfcx(buffer, options = {}) {
21
+ const startTime = performance.now();
22
+ // Phase 1: Parse JSON
23
+ options.onProgress?.({ phase: 'parse', percent: 0 });
24
+ const text = new TextDecoder().decode(buffer);
25
+ let file;
26
+ try {
27
+ file = JSON.parse(text);
28
+ }
29
+ catch (e) {
30
+ throw new Error(`Invalid IFCX file: JSON parse error - ${e}`);
31
+ }
32
+ // Validate header
33
+ if (!file.header?.ifcxVersion?.toLowerCase().includes('ifcx')) {
34
+ throw new Error('Invalid IFCX file: missing or invalid header.ifcxVersion');
35
+ }
36
+ options.onProgress?.({ phase: 'parse', percent: 100 });
37
+ // Phase 2: Compose ECS nodes
38
+ options.onProgress?.({ phase: 'compose', percent: 0 });
39
+ const composed = composeIfcx(file);
40
+ options.onProgress?.({ phase: 'compose', percent: 100 });
41
+ // Phase 3: Extract entities
42
+ options.onProgress?.({ phase: 'entities', percent: 0 });
43
+ const strings = new StringTable();
44
+ const { entities, pathToId, idToPath } = extractEntities(composed, strings);
45
+ options.onProgress?.({ phase: 'entities', percent: 100 });
46
+ // Phase 4: Extract properties
47
+ options.onProgress?.({ phase: 'properties', percent: 0 });
48
+ const properties = extractProperties(composed, pathToId, strings);
49
+ options.onProgress?.({ phase: 'properties', percent: 100 });
50
+ // Phase 5: Extract geometry
51
+ options.onProgress?.({ phase: 'geometry', percent: 0 });
52
+ const meshes = extractGeometry(composed, pathToId);
53
+ options.onProgress?.({ phase: 'geometry', percent: 100 });
54
+ // Phase 6: Build hierarchy
55
+ options.onProgress?.({ phase: 'hierarchy', percent: 0 });
56
+ const spatialHierarchy = buildHierarchy(composed, pathToId);
57
+ options.onProgress?.({ phase: 'hierarchy', percent: 100 });
58
+ // Phase 7: Build relationships
59
+ options.onProgress?.({ phase: 'relationships', percent: 0 });
60
+ const relationships = buildRelationships(composed, pathToId);
61
+ options.onProgress?.({ phase: 'relationships', percent: 100 });
62
+ // Phase 8: Build quantities (from properties that look like quantities)
63
+ const quantities = buildQuantities(composed, pathToId, strings);
64
+ const parseTime = performance.now() - startTime;
65
+ return {
66
+ entities,
67
+ properties,
68
+ quantities,
69
+ relationships,
70
+ spatialHierarchy,
71
+ strings,
72
+ meshes,
73
+ pathToId,
74
+ idToPath,
75
+ schemaVersion: 'IFC5',
76
+ fileSize: buffer.byteLength,
77
+ entityCount: entities.count,
78
+ parseTime,
79
+ };
80
+ }
81
+ /**
82
+ * Build relationship graph from composed nodes.
83
+ * In IFCX, relationships are implicit in the children structure.
84
+ */
85
+ function buildRelationships(composed, pathToId) {
86
+ const builder = new RelationshipGraphBuilder();
87
+ let relId = 1;
88
+ for (const node of composed.values()) {
89
+ const parentId = pathToId.get(node.path);
90
+ if (parentId === undefined)
91
+ continue;
92
+ for (const child of node.children.values()) {
93
+ const childId = pathToId.get(child.path);
94
+ if (childId !== undefined) {
95
+ // Determine relationship type based on node types
96
+ const relType = determineRelationshipType(node, child);
97
+ builder.addEdge(parentId, childId, relType, relId++);
98
+ }
99
+ }
100
+ }
101
+ return builder.build();
102
+ }
103
+ /**
104
+ * Determine relationship type based on parent and child node types.
105
+ */
106
+ function determineRelationshipType(parent, child) {
107
+ const parentClass = parent.attributes.get('bsi::ifc::class')?.code;
108
+ const childClass = child.attributes.get('bsi::ifc::class')?.code;
109
+ // Spatial containment
110
+ if (isSpatialElement(parentClass) && !isSpatialElement(childClass)) {
111
+ return RelationshipType.ContainsElements;
112
+ }
113
+ // Aggregation (spatial structure hierarchy)
114
+ if (isSpatialElement(parentClass) && isSpatialElement(childClass)) {
115
+ return RelationshipType.Aggregates;
116
+ }
117
+ // Default to containment
118
+ return RelationshipType.ContainsElements;
119
+ }
120
+ function isSpatialElement(typeCode) {
121
+ if (!typeCode)
122
+ return false;
123
+ const spatialTypes = ['IfcProject', 'IfcSite', 'IfcBuilding', 'IfcBuildingStorey', 'IfcSpace'];
124
+ return spatialTypes.includes(typeCode);
125
+ }
126
+ /**
127
+ * Build quantity table from properties that appear to be quantities.
128
+ * Uses the isQuantityProperty helper to identify quantity-like properties.
129
+ */
130
+ function buildQuantities(composed, pathToId, strings) {
131
+ const builder = new QuantityTableBuilder(strings);
132
+ // Map property names to quantity types
133
+ const getQuantityType = (propName) => {
134
+ // Volume types
135
+ if (propName === 'Volume' || propName.endsWith('Volume'))
136
+ return 2; // QuantityType.Volume
137
+ // Area types
138
+ if (propName === 'Area' || propName.endsWith('Area'))
139
+ return 1; // QuantityType.Area
140
+ // Count types
141
+ if (propName === 'Count' || propName.endsWith('Count'))
142
+ return 3; // QuantityType.Count
143
+ // Weight types
144
+ if (propName === 'Weight' || propName === 'Mass' ||
145
+ propName.endsWith('Weight') || propName.endsWith('Mass'))
146
+ return 4; // QuantityType.Weight
147
+ // Default to length for dimension-like quantities
148
+ return 0; // QuantityType.Length
149
+ };
150
+ for (const node of composed.values()) {
151
+ const expressId = pathToId.get(node.path);
152
+ if (expressId === undefined)
153
+ continue;
154
+ // Get the IFC class to use as context for qset naming
155
+ const ifcClass = node.attributes.get('bsi::ifc::class')?.code;
156
+ const qsetName = ifcClass ? `Qto_${ifcClass.replace('Ifc', '')}BaseQuantities` : 'BaseQuantities';
157
+ for (const [key, value] of node.attributes) {
158
+ // Check if this looks like a quantity
159
+ const propName = key.split('::').pop() ?? '';
160
+ if (typeof value === 'number' && isQuantityProperty(propName)) {
161
+ builder.add({
162
+ entityId: expressId,
163
+ qsetName,
164
+ quantityName: propName,
165
+ quantityType: getQuantityType(propName),
166
+ value,
167
+ });
168
+ }
169
+ }
170
+ }
171
+ return builder.build();
172
+ }
173
+ /**
174
+ * Detect if a buffer contains IFCX (JSON) or IFC (STEP) format.
175
+ */
176
+ export function detectFormat(buffer) {
177
+ const bytes = new Uint8Array(buffer, 0, Math.min(100, buffer.byteLength));
178
+ const start = new TextDecoder().decode(bytes).trim();
179
+ // IFCX is JSON starting with {
180
+ if (start.startsWith('{')) {
181
+ return 'ifcx';
182
+ }
183
+ // IFC STEP starts with ISO-10303-21
184
+ if (start.includes('ISO-10303-21') || start.startsWith('ISO')) {
185
+ return 'ifc';
186
+ }
187
+ return 'unknown';
188
+ }
189
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Property Extractor for IFCX
3
+ * Extracts properties from node attributes and builds PropertyTable
4
+ */
5
+ import type { ComposedNode } from './types.js';
6
+ import { StringTable } from '@ifc-lite/data';
7
+ import type { PropertyTable } from '@ifc-lite/data';
8
+ /**
9
+ * Extract properties from composed IFCX nodes.
10
+ *
11
+ * IFCX properties are flat attributes with namespace prefixes:
12
+ * - bsi::ifc::prop::IsExternal -> PropertySingleValue
13
+ * - bsi::ifc::prop::Volume -> QuantitySingleValue
14
+ *
15
+ * We group properties by namespace prefix for PropertySet-like grouping.
16
+ */
17
+ export declare function extractProperties(composed: Map<string, ComposedNode>, pathToId: Map<string, number>, strings: StringTable): PropertyTable;
18
+ /**
19
+ * Extract quantity-like properties (Volume, Area, Length, etc.)
20
+ * These are identified by their names matching quantity patterns.
21
+ */
22
+ export declare function isQuantityProperty(propName: string): boolean;
23
+ //# sourceMappingURL=property-extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"property-extractor.d.ts","sourceRoot":"","sources":["../src/property-extractor.ts"],"names":[],"mappings":"AAIA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,OAAO,EACL,WAAW,EAGZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAapD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,EACnC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAC7B,OAAO,EAAE,WAAW,GACnB,aAAa,CA2Bf;AA+HD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAqC5D"}