@ifc-lite/parser 2.1.8 → 2.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/classification-extractor.d.ts +1 -1
- package/dist/classification-extractor.d.ts.map +1 -1
- package/dist/classification-resolver.d.ts +18 -0
- package/dist/classification-resolver.d.ts.map +1 -0
- package/dist/classification-resolver.js +126 -0
- package/dist/classification-resolver.js.map +1 -0
- package/dist/columnar-parser-attributes.d.ts +39 -0
- package/dist/columnar-parser-attributes.d.ts.map +1 -0
- package/dist/columnar-parser-attributes.js +225 -0
- package/dist/columnar-parser-attributes.js.map +1 -0
- package/dist/columnar-parser-indexes.d.ts +42 -0
- package/dist/columnar-parser-indexes.d.ts.map +1 -0
- package/dist/columnar-parser-indexes.js +102 -0
- package/dist/columnar-parser-indexes.js.map +1 -0
- package/dist/columnar-parser-relationships.d.ts +17 -0
- package/dist/columnar-parser-relationships.d.ts.map +1 -0
- package/dist/columnar-parser-relationships.js +95 -0
- package/dist/columnar-parser-relationships.js.map +1 -0
- package/dist/columnar-parser.d.ts +2 -21
- package/dist/columnar-parser.d.ts.map +1 -1
- package/dist/columnar-parser.js +3 -409
- package/dist/columnar-parser.js.map +1 -1
- package/dist/georef-extractor.d.ts +7 -1
- package/dist/georef-extractor.d.ts.map +1 -1
- package/dist/georef-extractor.js +29 -5
- package/dist/georef-extractor.js.map +1 -1
- package/dist/material-extractor.d.ts +1 -1
- package/dist/material-extractor.d.ts.map +1 -1
- package/dist/material-resolver.d.ts +37 -0
- package/dist/material-resolver.d.ts.map +1 -0
- package/dist/material-resolver.js +230 -0
- package/dist/material-resolver.js.map +1 -0
- package/dist/on-demand-extractors.d.ts +4 -51
- package/dist/on-demand-extractors.d.ts.map +1 -1
- package/dist/on-demand-extractors.js +17 -341
- package/dist/on-demand-extractors.js.map +1 -1
- package/dist/style-extractor.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,95 @@
|
|
|
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
|
+
/**
|
|
5
|
+
* Relationship extraction for columnar parsing.
|
|
6
|
+
*
|
|
7
|
+
* Byte-level relationship scanners that extract numeric entity IDs
|
|
8
|
+
* from STEP relationship entities without TextDecoder overhead.
|
|
9
|
+
*/
|
|
10
|
+
import { skipCommas, readRefId, readRefList } from './columnar-parser-attributes.js';
|
|
11
|
+
/**
|
|
12
|
+
* Extract relatingObject and relatedObjects from a relationship entity using byte-level scanning.
|
|
13
|
+
* No TextDecoder needed - only extracts numeric entity IDs.
|
|
14
|
+
*/
|
|
15
|
+
export function extractRelFast(buffer, byteOffset, byteLength, typeUpper) {
|
|
16
|
+
const end = byteOffset + byteLength;
|
|
17
|
+
let pos = byteOffset;
|
|
18
|
+
while (pos < end && buffer[pos] !== 0x28)
|
|
19
|
+
pos++;
|
|
20
|
+
if (pos >= end)
|
|
21
|
+
return null;
|
|
22
|
+
pos++;
|
|
23
|
+
// Skip to attr[4] (all IfcRelationship subtypes have 4 shared IfcRoot+IfcRelationship attrs)
|
|
24
|
+
pos = skipCommas(buffer, pos, end, 4);
|
|
25
|
+
if (typeUpper === 'IFCRELCONTAINEDINSPATIALSTRUCTURE'
|
|
26
|
+
|| typeUpper === 'IFCRELREFERENCEDINSPATIALSTRUCTURE'
|
|
27
|
+
|| typeUpper === 'IFCRELDEFINESBYPROPERTIES'
|
|
28
|
+
|| typeUpper === 'IFCRELDEFINESBYTYPE') {
|
|
29
|
+
// attr[4]=RelatedObjects, attr[5]=RelatingObject
|
|
30
|
+
const [related, rp] = readRefList(buffer, pos, end);
|
|
31
|
+
pos = rp;
|
|
32
|
+
while (pos < end && buffer[pos] !== 0x2C)
|
|
33
|
+
pos++;
|
|
34
|
+
pos++;
|
|
35
|
+
const [relating, _] = readRefId(buffer, pos, end);
|
|
36
|
+
if (relating < 0 || related.length === 0)
|
|
37
|
+
return null;
|
|
38
|
+
return { relatingObject: relating, relatedObjects: related };
|
|
39
|
+
}
|
|
40
|
+
else if (typeUpper === 'IFCRELASSIGNSTOGROUP' || typeUpper === 'IFCRELASSIGNSTOPRODUCT') {
|
|
41
|
+
const [related, rp] = readRefList(buffer, pos, end);
|
|
42
|
+
pos = skipCommas(buffer, rp, end, 2);
|
|
43
|
+
const [relating, _] = readRefId(buffer, pos, end);
|
|
44
|
+
if (relating < 0 || related.length === 0)
|
|
45
|
+
return null;
|
|
46
|
+
return { relatingObject: relating, relatedObjects: related };
|
|
47
|
+
}
|
|
48
|
+
else if (typeUpper === 'IFCRELCONNECTSELEMENTS' || typeUpper === 'IFCRELCONNECTSPATHELEMENTS') {
|
|
49
|
+
pos = skipCommas(buffer, pos, end, 1);
|
|
50
|
+
const [relating, rp2] = readRefId(buffer, pos, end);
|
|
51
|
+
pos = skipCommas(buffer, rp2, end, 1);
|
|
52
|
+
const [related, _] = readRefId(buffer, pos, end);
|
|
53
|
+
if (relating < 0 || related < 0)
|
|
54
|
+
return null;
|
|
55
|
+
return { relatingObject: relating, relatedObjects: [related] };
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
// Default: attr[4]=RelatingObject, attr[5]=RelatedObject(s)
|
|
59
|
+
const [relating, rp] = readRefId(buffer, pos, end);
|
|
60
|
+
if (relating < 0)
|
|
61
|
+
return null;
|
|
62
|
+
pos = rp;
|
|
63
|
+
while (pos < end && buffer[pos] !== 0x2C)
|
|
64
|
+
pos++;
|
|
65
|
+
pos++;
|
|
66
|
+
const [related, _] = readRefList(buffer, pos, end);
|
|
67
|
+
if (related.length === 0)
|
|
68
|
+
return null;
|
|
69
|
+
return { relatingObject: relating, relatedObjects: related };
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Extract property rel data: attr[4]=relatedObjects, attr[5]=relatingDef.
|
|
74
|
+
* Numbers only, no TextDecoder.
|
|
75
|
+
*/
|
|
76
|
+
export function extractPropertyRelFast(buffer, byteOffset, byteLength) {
|
|
77
|
+
const end = byteOffset + byteLength;
|
|
78
|
+
let pos = byteOffset;
|
|
79
|
+
while (pos < end && buffer[pos] !== 0x28)
|
|
80
|
+
pos++;
|
|
81
|
+
if (pos >= end)
|
|
82
|
+
return null;
|
|
83
|
+
pos++;
|
|
84
|
+
pos = skipCommas(buffer, pos, end, 4);
|
|
85
|
+
const [relatedObjects, rp] = readRefList(buffer, pos, end);
|
|
86
|
+
pos = rp;
|
|
87
|
+
while (pos < end && buffer[pos] !== 0x2C)
|
|
88
|
+
pos++;
|
|
89
|
+
pos++;
|
|
90
|
+
const [relatingDef, _] = readRefId(buffer, pos, end);
|
|
91
|
+
if (relatingDef < 0 || relatedObjects.length === 0)
|
|
92
|
+
return null;
|
|
93
|
+
return { relatedObjects, relatingDef };
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=columnar-parser-relationships.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"columnar-parser-relationships.js","sourceRoot":"","sources":["../src/columnar-parser-relationships.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,27 +7,8 @@
|
|
|
7
7
|
import type { EntityRef } from './types.js';
|
|
8
8
|
import { StringTable, EntityTableBuilder, PropertyTableBuilder, RelationshipGraphBuilder } from '@ifc-lite/data';
|
|
9
9
|
import type { SpatialHierarchy, QuantityTable, PropertyValue } from '@ifc-lite/data';
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
min: [number, number, number];
|
|
13
|
-
max: [number, number, number];
|
|
14
|
-
}): number[];
|
|
15
|
-
raycast(origin: [number, number, number], direction: [number, number, number]): number[];
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Entity-by-ID lookup interface. Supports both Map<number, EntityRef> (legacy)
|
|
19
|
-
* and CompactEntityIndex (memory-optimized typed arrays with LRU cache).
|
|
20
|
-
*/
|
|
21
|
-
export type EntityByIdIndex = {
|
|
22
|
-
get(expressId: number): EntityRef | undefined;
|
|
23
|
-
has(expressId: number): boolean;
|
|
24
|
-
readonly size: number;
|
|
25
|
-
keys(): IterableIterator<number>;
|
|
26
|
-
values(): IterableIterator<EntityRef>;
|
|
27
|
-
entries(): IterableIterator<[number, EntityRef]>;
|
|
28
|
-
forEach(callback: (value: EntityRef, key: number) => void): void;
|
|
29
|
-
[Symbol.iterator](): IterableIterator<[number, EntityRef]>;
|
|
30
|
-
};
|
|
10
|
+
import type { SpatialIndex, EntityByIdIndex } from './columnar-parser-indexes.js';
|
|
11
|
+
export type { SpatialIndex, EntityByIdIndex } from './columnar-parser-indexes.js';
|
|
31
12
|
export interface IfcDataStore {
|
|
32
13
|
fileSize: number;
|
|
33
14
|
schemaVersion: 'IFC2X3' | 'IFC4' | 'IFC4X3' | 'IFC5';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"columnar-parser.d.ts","sourceRoot":"","sources":["../src/columnar-parser.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"columnar-parser.d.ts","sourceRoot":"","sources":["../src/columnar-parser.ts"],"names":[],"mappings":"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"}
|
package/dist/columnar-parser.js
CHANGED
|
@@ -4,419 +4,13 @@
|
|
|
4
4
|
import { SpatialHierarchyBuilder } from './spatial-hierarchy-builder.js';
|
|
5
5
|
import { EntityExtractor } from './entity-extractor.js';
|
|
6
6
|
import { extractLengthUnitScale } from './unit-extractor.js';
|
|
7
|
-
import { decodeIfcString } from '@ifc-lite/encoding';
|
|
8
7
|
import { getAttributeNames, getInheritanceChain } from './ifc-schema.js';
|
|
9
8
|
import { parsePropertyValue } from './on-demand-extractors.js';
|
|
10
9
|
import { buildCompactEntityIndexAsync } from './compact-entity-index.js';
|
|
11
10
|
import { StringTable, EntityTableBuilder, PropertyTableBuilder, QuantityTableBuilder, RelationshipGraphBuilder, RelationshipType, QuantityType, } from '@ifc-lite/data';
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
'IFCCOLUMN', 'IFCBEAM', 'IFCROOF', 'IFCSTAIR', 'IFCSTAIRFLIGHT',
|
|
16
|
-
'IFCRAILING', 'IFCRAMP', 'IFCRAMPFLIGHT', 'IFCPLATE', 'IFCMEMBER',
|
|
17
|
-
'IFCCURTAINWALL', 'IFCFOOTING', 'IFCPILE', 'IFCBUILDINGELEMENTPROXY',
|
|
18
|
-
'IFCFURNISHINGELEMENT', 'IFCFLOWSEGMENT', 'IFCFLOWTERMINAL',
|
|
19
|
-
'IFCFLOWCONTROLLER', 'IFCFLOWFITTING', 'IFCSPACE', 'IFCOPENINGELEMENT',
|
|
20
|
-
'IFCSITE', 'IFCBUILDING', 'IFCBUILDINGSTOREY',
|
|
21
|
-
]);
|
|
22
|
-
// IMPORTANT: This set MUST include ALL RelationshipType enum values to prevent semantic loss
|
|
23
|
-
// Missing types will be skipped during parsing, causing incomplete relationship graphs
|
|
24
|
-
const RELATIONSHIP_TYPES = new Set([
|
|
25
|
-
'IFCRELCONTAINEDINSPATIALSTRUCTURE', 'IFCRELAGGREGATES',
|
|
26
|
-
'IFCRELDEFINESBYPROPERTIES', 'IFCRELDEFINESBYTYPE',
|
|
27
|
-
'IFCRELASSOCIATESMATERIAL', 'IFCRELASSOCIATESCLASSIFICATION',
|
|
28
|
-
'IFCRELASSOCIATESDOCUMENT',
|
|
29
|
-
'IFCRELVOIDSELEMENT', 'IFCRELFILLSELEMENT',
|
|
30
|
-
'IFCRELCONNECTSPATHELEMENTS', 'IFCRELCONNECTSELEMENTS',
|
|
31
|
-
'IFCRELSPACEBOUNDARY',
|
|
32
|
-
'IFCRELASSIGNSTOGROUP', 'IFCRELASSIGNSTOPRODUCT',
|
|
33
|
-
'IFCRELREFERENCEDINSPATIALSTRUCTURE',
|
|
34
|
-
]);
|
|
35
|
-
// Map IFC relationship type strings to RelationshipType enum
|
|
36
|
-
// MUST cover ALL RelationshipType enum values (14 types total)
|
|
37
|
-
const REL_TYPE_MAP = {
|
|
38
|
-
'IFCRELCONTAINEDINSPATIALSTRUCTURE': RelationshipType.ContainsElements,
|
|
39
|
-
'IFCRELAGGREGATES': RelationshipType.Aggregates,
|
|
40
|
-
'IFCRELDEFINESBYPROPERTIES': RelationshipType.DefinesByProperties,
|
|
41
|
-
'IFCRELDEFINESBYTYPE': RelationshipType.DefinesByType,
|
|
42
|
-
'IFCRELASSOCIATESMATERIAL': RelationshipType.AssociatesMaterial,
|
|
43
|
-
'IFCRELASSOCIATESCLASSIFICATION': RelationshipType.AssociatesClassification,
|
|
44
|
-
'IFCRELASSOCIATESDOCUMENT': RelationshipType.AssociatesDocument,
|
|
45
|
-
'IFCRELVOIDSELEMENT': RelationshipType.VoidsElement,
|
|
46
|
-
'IFCRELFILLSELEMENT': RelationshipType.FillsElement,
|
|
47
|
-
'IFCRELCONNECTSPATHELEMENTS': RelationshipType.ConnectsPathElements,
|
|
48
|
-
'IFCRELCONNECTSELEMENTS': RelationshipType.ConnectsElements,
|
|
49
|
-
'IFCRELSPACEBOUNDARY': RelationshipType.SpaceBoundary,
|
|
50
|
-
'IFCRELASSIGNSTOGROUP': RelationshipType.AssignsToGroup,
|
|
51
|
-
'IFCRELASSIGNSTOPRODUCT': RelationshipType.AssignsToProduct,
|
|
52
|
-
'IFCRELREFERENCEDINSPATIALSTRUCTURE': RelationshipType.ReferencedInSpatialStructure,
|
|
53
|
-
};
|
|
54
|
-
const QUANTITY_TYPE_MAP = {
|
|
55
|
-
'IFCQUANTITYLENGTH': QuantityType.Length,
|
|
56
|
-
'IFCQUANTITYAREA': QuantityType.Area,
|
|
57
|
-
'IFCQUANTITYVOLUME': QuantityType.Volume,
|
|
58
|
-
'IFCQUANTITYCOUNT': QuantityType.Count,
|
|
59
|
-
'IFCQUANTITYWEIGHT': QuantityType.Weight,
|
|
60
|
-
'IFCQUANTITYTIME': QuantityType.Time,
|
|
61
|
-
};
|
|
62
|
-
// Types needed for spatial hierarchy (small subset)
|
|
63
|
-
const SPATIAL_TYPES = new Set([
|
|
64
|
-
'IFCPROJECT', 'IFCSITE', 'IFCBUILDING', 'IFCBUILDINGSTOREY', 'IFCSPACE',
|
|
65
|
-
'IFCFACILITY', 'IFCFACILITYPART',
|
|
66
|
-
'IFCBRIDGE', 'IFCBRIDGEPART',
|
|
67
|
-
'IFCROAD', 'IFCROADPART',
|
|
68
|
-
'IFCRAILWAY', 'IFCRAILWAYPART',
|
|
69
|
-
'IFCMARINEFACILITY',
|
|
70
|
-
]);
|
|
71
|
-
// Relationship types needed for hierarchy and structural relationships
|
|
72
|
-
const HIERARCHY_REL_TYPES = new Set([
|
|
73
|
-
'IFCRELAGGREGATES', 'IFCRELCONTAINEDINSPATIALSTRUCTURE',
|
|
74
|
-
'IFCRELDEFINESBYTYPE',
|
|
75
|
-
// Structural relationships (voids, fills, connections, groups)
|
|
76
|
-
'IFCRELVOIDSELEMENT', 'IFCRELFILLSELEMENT',
|
|
77
|
-
'IFCRELCONNECTSPATHELEMENTS', 'IFCRELCONNECTSELEMENTS',
|
|
78
|
-
'IFCRELSPACEBOUNDARY',
|
|
79
|
-
'IFCRELASSIGNSTOGROUP', 'IFCRELASSIGNSTOPRODUCT',
|
|
80
|
-
'IFCRELREFERENCEDINSPATIALSTRUCTURE',
|
|
81
|
-
]);
|
|
82
|
-
// Relationship types for on-demand property loading
|
|
83
|
-
const PROPERTY_REL_TYPES = new Set([
|
|
84
|
-
'IFCRELDEFINESBYPROPERTIES',
|
|
85
|
-
]);
|
|
86
|
-
// Relationship types for on-demand classification/material loading
|
|
87
|
-
const ASSOCIATION_REL_TYPES = new Set([
|
|
88
|
-
'IFCRELASSOCIATESCLASSIFICATION', 'IFCRELASSOCIATESMATERIAL',
|
|
89
|
-
'IFCRELASSOCIATESDOCUMENT',
|
|
90
|
-
]);
|
|
91
|
-
// Attributes to skip in extractAllEntityAttributes (shown elsewhere or non-displayable)
|
|
92
|
-
const SKIP_DISPLAY_ATTRS = new Set(['GlobalId', 'OwnerHistory', 'ObjectPlacement', 'Representation', 'HasPropertySets', 'RepresentationMaps']);
|
|
93
|
-
// Property-related entity types for on-demand extraction
|
|
94
|
-
const PROPERTY_ENTITY_TYPES = new Set([
|
|
95
|
-
'IFCPROPERTYSET', 'IFCELEMENTQUANTITY',
|
|
96
|
-
'IFCPROPERTYSINGLEVALUE', 'IFCPROPERTYENUMERATEDVALUE',
|
|
97
|
-
'IFCPROPERTYBOUNDEDVALUE', 'IFCPROPERTYTABLEVALUE',
|
|
98
|
-
'IFCPROPERTYLISTVALUE', 'IFCPROPERTYREFERENCEVALUE',
|
|
99
|
-
'IFCQUANTITYLENGTH', 'IFCQUANTITYAREA', 'IFCQUANTITYVOLUME',
|
|
100
|
-
'IFCQUANTITYCOUNT', 'IFCQUANTITYWEIGHT', 'IFCQUANTITYTIME',
|
|
101
|
-
]);
|
|
102
|
-
const PROPERTY_CONTAINER_TYPES = new Set([
|
|
103
|
-
'IFCPROPERTYSET',
|
|
104
|
-
'IFCELEMENTQUANTITY',
|
|
105
|
-
]);
|
|
106
|
-
function isIfcTypeLikeEntity(typeUpper) {
|
|
107
|
-
return typeUpper.endsWith('TYPE') || typeUpper.endsWith('STYLE');
|
|
108
|
-
}
|
|
109
|
-
// ==========================================
|
|
110
|
-
// Byte-level helpers for fast extraction
|
|
111
|
-
// These avoid per-entity TextDecoder calls by working on raw bytes.
|
|
112
|
-
// ==========================================
|
|
113
|
-
/**
|
|
114
|
-
* Find the byte range of a quoted string at a specific attribute position in STEP entity bytes.
|
|
115
|
-
* Returns [start, end) byte offsets (excluding quotes), or null if not found.
|
|
116
|
-
*
|
|
117
|
-
* @param buffer - The IFC file buffer
|
|
118
|
-
* @param entityStart - byte offset of the entity
|
|
119
|
-
* @param entityLen - byte length of the entity
|
|
120
|
-
* @param attrIndex - 0-based attribute index (0=GlobalId, 2=Name)
|
|
121
|
-
*/
|
|
122
|
-
function findQuotedAttrRange(buffer, entityStart, entityLen, attrIndex) {
|
|
123
|
-
const end = entityStart + entityLen;
|
|
124
|
-
let pos = entityStart;
|
|
125
|
-
// Skip to opening paren '(' after TYPE name
|
|
126
|
-
while (pos < end && buffer[pos] !== 0x28 /* ( */)
|
|
127
|
-
pos++;
|
|
128
|
-
if (pos >= end)
|
|
129
|
-
return null;
|
|
130
|
-
pos++; // skip '('
|
|
131
|
-
// Skip commas to reach the target attribute
|
|
132
|
-
if (attrIndex > 0) {
|
|
133
|
-
let toSkip = attrIndex;
|
|
134
|
-
let depth = 0;
|
|
135
|
-
let inStr = false;
|
|
136
|
-
while (pos < end && toSkip > 0) {
|
|
137
|
-
const ch = buffer[pos];
|
|
138
|
-
if (ch === 0x27 /* ' */) {
|
|
139
|
-
if (inStr && pos + 1 < end && buffer[pos + 1] === 0x27) {
|
|
140
|
-
pos += 2;
|
|
141
|
-
continue;
|
|
142
|
-
}
|
|
143
|
-
inStr = !inStr;
|
|
144
|
-
}
|
|
145
|
-
else if (!inStr) {
|
|
146
|
-
if (ch === 0x28)
|
|
147
|
-
depth++;
|
|
148
|
-
else if (ch === 0x29)
|
|
149
|
-
depth--;
|
|
150
|
-
else if (ch === 0x2C && depth === 0)
|
|
151
|
-
toSkip--;
|
|
152
|
-
}
|
|
153
|
-
pos++;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
// Skip whitespace
|
|
157
|
-
while (pos < end && (buffer[pos] === 0x20 || buffer[pos] === 0x09))
|
|
158
|
-
pos++;
|
|
159
|
-
// Check for quoted string
|
|
160
|
-
if (pos >= end || buffer[pos] !== 0x27 /* ' */)
|
|
161
|
-
return null;
|
|
162
|
-
pos++; // skip opening quote
|
|
163
|
-
const start = pos;
|
|
164
|
-
// Find closing quote (handle escaped quotes '')
|
|
165
|
-
while (pos < end) {
|
|
166
|
-
if (buffer[pos] === 0x27) {
|
|
167
|
-
if (pos + 1 < end && buffer[pos + 1] === 0x27) {
|
|
168
|
-
pos += 2;
|
|
169
|
-
continue;
|
|
170
|
-
}
|
|
171
|
-
break;
|
|
172
|
-
}
|
|
173
|
-
pos++;
|
|
174
|
-
}
|
|
175
|
-
return [start, pos];
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Batch extract GlobalId (attr[0]) and Name (attr[2]) for many entities using
|
|
179
|
-
* only 2 TextDecoder.decode() calls total (one for all GlobalIds, one for all Names).
|
|
180
|
-
*
|
|
181
|
-
* This is ~100x faster than calling extractEntity() per entity for large batches
|
|
182
|
-
* because it eliminates per-entity TextDecoder overhead which is significant in Firefox.
|
|
183
|
-
*
|
|
184
|
-
* Returns a Map from expressId → { globalId, name }.
|
|
185
|
-
*/
|
|
186
|
-
async function batchExtractGlobalIdAndName(buffer, refs, yieldIfNeeded) {
|
|
187
|
-
const result = new Map();
|
|
188
|
-
if (refs.length === 0)
|
|
189
|
-
return result;
|
|
190
|
-
const CHUNK_SIZE = 2048;
|
|
191
|
-
// Phase 1: Scan byte ranges for GlobalId and Name positions (no string allocation)
|
|
192
|
-
const gidRanges = []; // [start, end) for each entity
|
|
193
|
-
const nameRanges = [];
|
|
194
|
-
const validIndices = []; // indices into refs for entities with valid ranges
|
|
195
|
-
for (let i = 0; i < refs.length; i++) {
|
|
196
|
-
if (yieldIfNeeded && (i & (CHUNK_SIZE - 1)) === 0) {
|
|
197
|
-
await yieldIfNeeded();
|
|
198
|
-
}
|
|
199
|
-
const ref = refs[i];
|
|
200
|
-
const gidRange = findQuotedAttrRange(buffer, ref.byteOffset, ref.byteLength, 0);
|
|
201
|
-
const nameRange = findQuotedAttrRange(buffer, ref.byteOffset, ref.byteLength, 2);
|
|
202
|
-
gidRanges.push(gidRange ?? [0, 0]);
|
|
203
|
-
nameRanges.push(nameRange ?? [0, 0]);
|
|
204
|
-
validIndices.push(i);
|
|
205
|
-
}
|
|
206
|
-
// Phase 2: Concatenate all GlobalId bytes into one buffer, decode once
|
|
207
|
-
// Use null byte (0x00) as separator (never appears in IFC string content)
|
|
208
|
-
let totalGidBytes = 0;
|
|
209
|
-
let totalNameBytes = 0;
|
|
210
|
-
for (let i = 0; i < validIndices.length; i++) {
|
|
211
|
-
if (yieldIfNeeded && (i & (CHUNK_SIZE - 1)) === 0) {
|
|
212
|
-
await yieldIfNeeded();
|
|
213
|
-
}
|
|
214
|
-
const [gs, ge] = gidRanges[i];
|
|
215
|
-
const [ns, ne] = nameRanges[i];
|
|
216
|
-
totalGidBytes += (ge - gs) + 1; // +1 for separator
|
|
217
|
-
totalNameBytes += (ne - ns) + 1;
|
|
218
|
-
}
|
|
219
|
-
const gidBuf = new Uint8Array(totalGidBytes);
|
|
220
|
-
const nameBuf = new Uint8Array(totalNameBytes);
|
|
221
|
-
let gidOffset = 0;
|
|
222
|
-
let nameOffset = 0;
|
|
223
|
-
for (let i = 0; i < validIndices.length; i++) {
|
|
224
|
-
if (yieldIfNeeded && (i & (CHUNK_SIZE - 1)) === 0) {
|
|
225
|
-
await yieldIfNeeded();
|
|
226
|
-
}
|
|
227
|
-
const [gs, ge] = gidRanges[i];
|
|
228
|
-
const [ns, ne] = nameRanges[i];
|
|
229
|
-
if (ge > gs) {
|
|
230
|
-
gidBuf.set(buffer.subarray(gs, ge), gidOffset);
|
|
231
|
-
gidOffset += ge - gs;
|
|
232
|
-
}
|
|
233
|
-
gidBuf[gidOffset++] = 0; // null separator
|
|
234
|
-
if (ne > ns) {
|
|
235
|
-
nameBuf.set(buffer.subarray(ns, ne), nameOffset);
|
|
236
|
-
nameOffset += ne - ns;
|
|
237
|
-
}
|
|
238
|
-
nameBuf[nameOffset++] = 0;
|
|
239
|
-
}
|
|
240
|
-
// Phase 3: Two TextDecoder calls for ALL entities
|
|
241
|
-
const decoder = new TextDecoder();
|
|
242
|
-
const allGids = decoder.decode(gidBuf.subarray(0, gidOffset));
|
|
243
|
-
const allNames = decoder.decode(nameBuf.subarray(0, nameOffset));
|
|
244
|
-
const gids = allGids.split('\0');
|
|
245
|
-
const names = allNames.split('\0');
|
|
246
|
-
// Phase 4: Build result map
|
|
247
|
-
for (let i = 0; i < validIndices.length; i++) {
|
|
248
|
-
if (yieldIfNeeded && (i & (CHUNK_SIZE - 1)) === 0) {
|
|
249
|
-
await yieldIfNeeded();
|
|
250
|
-
}
|
|
251
|
-
const ref = refs[validIndices[i]];
|
|
252
|
-
const rawName = names[i] || '';
|
|
253
|
-
result.set(ref.expressId, {
|
|
254
|
-
globalId: gids[i] || '',
|
|
255
|
-
name: rawName ? decodeIfcString(rawName) : '',
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
return result;
|
|
259
|
-
}
|
|
260
|
-
// ==========================================
|
|
261
|
-
// Byte-level relationship scanners (numbers only, no TextDecoder)
|
|
262
|
-
// ==========================================
|
|
263
|
-
/**
|
|
264
|
-
* Skip N commas at depth 0 in STEP bytes.
|
|
265
|
-
*/
|
|
266
|
-
function skipCommas(buffer, start, end, count) {
|
|
267
|
-
let pos = start;
|
|
268
|
-
let remaining = count;
|
|
269
|
-
let depth = 0;
|
|
270
|
-
let inString = false;
|
|
271
|
-
while (pos < end && remaining > 0) {
|
|
272
|
-
const ch = buffer[pos];
|
|
273
|
-
if (ch === 0x27) {
|
|
274
|
-
if (inString && pos + 1 < end && buffer[pos + 1] === 0x27) {
|
|
275
|
-
pos += 2;
|
|
276
|
-
continue;
|
|
277
|
-
}
|
|
278
|
-
inString = !inString;
|
|
279
|
-
}
|
|
280
|
-
else if (!inString) {
|
|
281
|
-
if (ch === 0x28)
|
|
282
|
-
depth++;
|
|
283
|
-
else if (ch === 0x29)
|
|
284
|
-
depth--;
|
|
285
|
-
else if (ch === 0x2C && depth === 0)
|
|
286
|
-
remaining--;
|
|
287
|
-
}
|
|
288
|
-
pos++;
|
|
289
|
-
}
|
|
290
|
-
return pos;
|
|
291
|
-
}
|
|
292
|
-
/** Read a #ID entity reference as a number. Returns -1 if not an entity ref. */
|
|
293
|
-
function readRefId(buffer, pos, end) {
|
|
294
|
-
while (pos < end && (buffer[pos] === 0x20 || buffer[pos] === 0x09))
|
|
295
|
-
pos++;
|
|
296
|
-
if (pos < end && buffer[pos] === 0x23) {
|
|
297
|
-
pos++;
|
|
298
|
-
let num = 0;
|
|
299
|
-
while (pos < end && buffer[pos] >= 0x30 && buffer[pos] <= 0x39) {
|
|
300
|
-
num = num * 10 + (buffer[pos] - 0x30);
|
|
301
|
-
pos++;
|
|
302
|
-
}
|
|
303
|
-
return [num, pos];
|
|
304
|
-
}
|
|
305
|
-
return [-1, pos];
|
|
306
|
-
}
|
|
307
|
-
/** Read a list of entity refs (#id1,#id2,...) or a single #id. Returns [ids, newPos]. */
|
|
308
|
-
function readRefList(buffer, pos, end) {
|
|
309
|
-
while (pos < end && (buffer[pos] === 0x20 || buffer[pos] === 0x09))
|
|
310
|
-
pos++;
|
|
311
|
-
const ids = [];
|
|
312
|
-
if (pos < end && buffer[pos] === 0x28) {
|
|
313
|
-
pos++;
|
|
314
|
-
while (pos < end && buffer[pos] !== 0x29) {
|
|
315
|
-
while (pos < end && (buffer[pos] === 0x20 || buffer[pos] === 0x09 || buffer[pos] === 0x2C))
|
|
316
|
-
pos++;
|
|
317
|
-
if (pos < end && buffer[pos] === 0x23) {
|
|
318
|
-
const [id, np] = readRefId(buffer, pos, end);
|
|
319
|
-
if (id >= 0)
|
|
320
|
-
ids.push(id);
|
|
321
|
-
pos = np;
|
|
322
|
-
}
|
|
323
|
-
else if (pos < end && buffer[pos] !== 0x29) {
|
|
324
|
-
pos++;
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
else if (pos < end && buffer[pos] === 0x23) {
|
|
329
|
-
const [id, np] = readRefId(buffer, pos, end);
|
|
330
|
-
if (id >= 0)
|
|
331
|
-
ids.push(id);
|
|
332
|
-
pos = np;
|
|
333
|
-
}
|
|
334
|
-
return [ids, pos];
|
|
335
|
-
}
|
|
336
|
-
/**
|
|
337
|
-
* Extract relatingObject and relatedObjects from a relationship entity using byte-level scanning.
|
|
338
|
-
* No TextDecoder needed - only extracts numeric entity IDs.
|
|
339
|
-
*/
|
|
340
|
-
function extractRelFast(buffer, byteOffset, byteLength, typeUpper) {
|
|
341
|
-
const end = byteOffset + byteLength;
|
|
342
|
-
let pos = byteOffset;
|
|
343
|
-
while (pos < end && buffer[pos] !== 0x28)
|
|
344
|
-
pos++;
|
|
345
|
-
if (pos >= end)
|
|
346
|
-
return null;
|
|
347
|
-
pos++;
|
|
348
|
-
// Skip to attr[4] (all IfcRelationship subtypes have 4 shared IfcRoot+IfcRelationship attrs)
|
|
349
|
-
pos = skipCommas(buffer, pos, end, 4);
|
|
350
|
-
if (typeUpper === 'IFCRELCONTAINEDINSPATIALSTRUCTURE'
|
|
351
|
-
|| typeUpper === 'IFCRELREFERENCEDINSPATIALSTRUCTURE'
|
|
352
|
-
|| typeUpper === 'IFCRELDEFINESBYPROPERTIES'
|
|
353
|
-
|| typeUpper === 'IFCRELDEFINESBYTYPE') {
|
|
354
|
-
// attr[4]=RelatedObjects, attr[5]=RelatingObject
|
|
355
|
-
const [related, rp] = readRefList(buffer, pos, end);
|
|
356
|
-
pos = rp;
|
|
357
|
-
while (pos < end && buffer[pos] !== 0x2C)
|
|
358
|
-
pos++;
|
|
359
|
-
pos++;
|
|
360
|
-
const [relating, _] = readRefId(buffer, pos, end);
|
|
361
|
-
if (relating < 0 || related.length === 0)
|
|
362
|
-
return null;
|
|
363
|
-
return { relatingObject: relating, relatedObjects: related };
|
|
364
|
-
}
|
|
365
|
-
else if (typeUpper === 'IFCRELASSIGNSTOGROUP' || typeUpper === 'IFCRELASSIGNSTOPRODUCT') {
|
|
366
|
-
const [related, rp] = readRefList(buffer, pos, end);
|
|
367
|
-
pos = skipCommas(buffer, rp, end, 2);
|
|
368
|
-
const [relating, _] = readRefId(buffer, pos, end);
|
|
369
|
-
if (relating < 0 || related.length === 0)
|
|
370
|
-
return null;
|
|
371
|
-
return { relatingObject: relating, relatedObjects: related };
|
|
372
|
-
}
|
|
373
|
-
else if (typeUpper === 'IFCRELCONNECTSELEMENTS' || typeUpper === 'IFCRELCONNECTSPATHELEMENTS') {
|
|
374
|
-
pos = skipCommas(buffer, pos, end, 1);
|
|
375
|
-
const [relating, rp2] = readRefId(buffer, pos, end);
|
|
376
|
-
pos = skipCommas(buffer, rp2, end, 1);
|
|
377
|
-
const [related, _] = readRefId(buffer, pos, end);
|
|
378
|
-
if (relating < 0 || related < 0)
|
|
379
|
-
return null;
|
|
380
|
-
return { relatingObject: relating, relatedObjects: [related] };
|
|
381
|
-
}
|
|
382
|
-
else {
|
|
383
|
-
// Default: attr[4]=RelatingObject, attr[5]=RelatedObject(s)
|
|
384
|
-
const [relating, rp] = readRefId(buffer, pos, end);
|
|
385
|
-
if (relating < 0)
|
|
386
|
-
return null;
|
|
387
|
-
pos = rp;
|
|
388
|
-
while (pos < end && buffer[pos] !== 0x2C)
|
|
389
|
-
pos++;
|
|
390
|
-
pos++;
|
|
391
|
-
const [related, _] = readRefList(buffer, pos, end);
|
|
392
|
-
if (related.length === 0)
|
|
393
|
-
return null;
|
|
394
|
-
return { relatingObject: relating, relatedObjects: related };
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
/**
|
|
398
|
-
* Extract property rel data: attr[4]=relatedObjects, attr[5]=relatingDef.
|
|
399
|
-
* Numbers only, no TextDecoder.
|
|
400
|
-
*/
|
|
401
|
-
function extractPropertyRelFast(buffer, byteOffset, byteLength) {
|
|
402
|
-
const end = byteOffset + byteLength;
|
|
403
|
-
let pos = byteOffset;
|
|
404
|
-
while (pos < end && buffer[pos] !== 0x28)
|
|
405
|
-
pos++;
|
|
406
|
-
if (pos >= end)
|
|
407
|
-
return null;
|
|
408
|
-
pos++;
|
|
409
|
-
pos = skipCommas(buffer, pos, end, 4);
|
|
410
|
-
const [relatedObjects, rp] = readRefList(buffer, pos, end);
|
|
411
|
-
pos = rp;
|
|
412
|
-
while (pos < end && buffer[pos] !== 0x2C)
|
|
413
|
-
pos++;
|
|
414
|
-
pos++;
|
|
415
|
-
const [relatingDef, _] = readRefId(buffer, pos, end);
|
|
416
|
-
if (relatingDef < 0 || relatedObjects.length === 0)
|
|
417
|
-
return null;
|
|
418
|
-
return { relatedObjects, relatingDef };
|
|
419
|
-
}
|
|
11
|
+
import { batchExtractGlobalIdAndName } from './columnar-parser-attributes.js';
|
|
12
|
+
import { GEOMETRY_TYPES, REL_TYPE_MAP, QUANTITY_TYPE_MAP, SPATIAL_TYPES, HIERARCHY_REL_TYPES, PROPERTY_REL_TYPES, ASSOCIATION_REL_TYPES, SKIP_DISPLAY_ATTRS, PROPERTY_ENTITY_TYPES, PROPERTY_CONTAINER_TYPES, isIfcTypeLikeEntity, } from './columnar-parser-indexes.js';
|
|
13
|
+
import { extractRelFast, extractPropertyRelFast } from './columnar-parser-relationships.js';
|
|
420
14
|
function detectSchemaVersion(buffer) {
|
|
421
15
|
const headerEnd = Math.min(buffer.length, 2000);
|
|
422
16
|
const headerText = new TextDecoder().decode(buffer.subarray(0, headerEnd)).toUpperCase();
|