Skip to content

Commit 8b1ab2f

Browse files
authored
feat(core): improves IfcRelationsIndexer.processFromWebIfc (#384)
1 parent d1352d8 commit 8b1ab2f

3 files changed

Lines changed: 81 additions & 122 deletions

File tree

packages/components/src/ifc/IfcRelationsIndexer/index.ts

Lines changed: 80 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { FragmentsGroup } from "@thatopen/fragments";
33
import { Disposable, Event, Component, Components } from "../../core";
44
import { FragmentManager } from "../../fragments/FragmentManager";
55
import { IfcPropertiesUtils } from "../Utils";
6-
import { getRelationMap } from "./src/getRelationMap";
76
import {
87
RelationsMap,
98
ModelsRelationMap,
@@ -32,11 +31,7 @@ export class IfcRelationsIndexer extends Component implements Disposable {
3231

3332
private _relToAttributesMap = relToAttributesMap;
3433

35-
/**
36-
* Array of inverse attribute names.
37-
* This array is used to define the inverse attributes that the indexer will process and index.
38-
*/
39-
readonly inverseAttributes: InverseAttributes = [
34+
private _inverseAttributes: InverseAttributes = [
4035
"IsDecomposedBy",
4136
"Decomposes",
4237
"AssociatedTo",
@@ -53,6 +48,17 @@ export class IfcRelationsIndexer extends Component implements Disposable {
5348
"ContainsElements",
5449
];
5550

51+
private _ifcRels = [
52+
WEBIFC.IFCRELAGGREGATES,
53+
WEBIFC.IFCRELASSOCIATESMATERIAL,
54+
WEBIFC.IFCRELASSOCIATESCLASSIFICATION,
55+
WEBIFC.IFCRELASSIGNSTOGROUP,
56+
WEBIFC.IFCRELDEFINESBYPROPERTIES,
57+
WEBIFC.IFCRELDEFINESBYTYPE,
58+
WEBIFC.IFCRELDEFINESBYTEMPLATE,
59+
WEBIFC.IFCRELCONTAINEDINSPATIALSTRUCTURE,
60+
] as const;
61+
5662
/**
5763
* Holds the relationship mappings for each model processed by the indexer.
5864
* The structure is a map where each key is a model's UUID, and the value is another map.
@@ -78,15 +84,6 @@ export class IfcRelationsIndexer extends Component implements Disposable {
7884
delete this.relationMaps[data.groupID];
7985
};
8086

81-
private getAttributeRels(value: string) {
82-
const keys: number[] = [];
83-
for (const [rel, attribute] of this._relToAttributesMap.entries()) {
84-
const { forRelating, forRelated } = attribute;
85-
if (forRelating === value || forRelated === value) keys.push(rel);
86-
}
87-
return keys;
88-
}
89-
9087
/**
9188
* Adds a relation map to the model's relations map.
9289
*
@@ -125,46 +122,43 @@ export class IfcRelationsIndexer extends Component implements Disposable {
125122

126123
const relationsMap: RelationsMap = new Map();
127124

128-
for (const attribute of this.inverseAttributes) {
129-
const rels = this.getAttributeRels(attribute);
130-
for (const rel of rels) {
131-
await IfcPropertiesUtils.getRelationMap(
132-
model,
133-
rel,
134-
async (relatingID, relatedID) => {
135-
const inverseAttributes = this._relToAttributesMap.get(rel);
136-
if (!inverseAttributes) return;
137-
const { forRelated: related, forRelating: relating } =
138-
inverseAttributes;
139-
if (relating) {
140-
const currentMap =
141-
relationsMap.get(relatingID) ?? new Map<number, number[]>();
142-
// TODO: indexOf might be slow. Better a Map<string, number>?
143-
const index = this.inverseAttributes.indexOf(relating);
144-
currentMap.set(index, relatedID);
145-
relationsMap.set(relatingID, currentMap);
146-
}
147-
if (related) {
148-
for (const id of relatedID) {
149-
const currentMap =
150-
relationsMap.get(id) ?? new Map<number, number[]>();
151-
const index = this.inverseAttributes.indexOf(related);
152-
const relations = currentMap.get(index) ?? [];
153-
relations.push(relatingID);
154-
currentMap.set(index, relations);
155-
relationsMap.set(id, currentMap);
156-
}
157-
}
158-
},
159-
);
160-
}
125+
for (const rel of this._ifcRels) {
126+
await IfcPropertiesUtils.getRelationMap(
127+
model,
128+
rel,
129+
async (relatingID, relatedIDs) => {
130+
const inverseAttributes = this._relToAttributesMap.get(rel);
131+
if (!inverseAttributes) return;
132+
const { forRelated: related, forRelating: relating } =
133+
inverseAttributes;
134+
135+
// forRelating
136+
const currentMap =
137+
relationsMap.get(relatingID) ?? new Map<number, number[]>();
138+
const index = this._inverseAttributes.indexOf(relating);
139+
currentMap.set(index, relatedIDs);
140+
relationsMap.set(relatingID, currentMap);
141+
142+
// forRelated
143+
for (const id of relatedIDs) {
144+
const currentMap =
145+
relationsMap.get(id) ?? new Map<number, number[]>();
146+
const index = this._inverseAttributes.indexOf(related);
147+
const relations = currentMap.get(index) ?? [];
148+
relations.push(relatingID);
149+
currentMap.set(index, relations);
150+
relationsMap.set(id, currentMap);
151+
}
152+
},
153+
);
161154
}
155+
162156
this.setRelationMap(model, relationsMap);
163157
return relationsMap;
164158
}
165159

166160
/**
167-
* Processes a given model from a WebIfc API to index its IFC entities relations based on predefined inverse attributes.
161+
* Processes a given model from a WebIfc API to index its IFC entities relations.
168162
*
169163
* @param ifcApi - The WebIfc API instance from which to retrieve the model's properties.
170164
* @param modelID - The unique identifier of the model within the WebIfc API.
@@ -174,42 +168,44 @@ export class IfcRelationsIndexer extends Component implements Disposable {
174168
async processFromWebIfc(ifcApi: WEBIFC.IfcAPI, modelID: number) {
175169
const relationsMap: RelationsMap = new Map();
176170

177-
const properties: Record<string, Record<string, any>> = {};
178-
const lines = ifcApi.GetAllLines(modelID);
171+
for (const relType of this._ifcRels) {
172+
const relInverseAttributes = this._relToAttributesMap.get(relType);
173+
if (!relInverseAttributes) continue;
174+
const { forRelated: related, forRelating: relating } =
175+
relInverseAttributes;
176+
const relExpressIDs = ifcApi.GetLineIDsWithType(modelID, relType);
177+
for (let i = 0; i < relExpressIDs.size(); i++) {
178+
const relAttrs = await ifcApi.properties.getItemProperties(
179+
modelID,
180+
relExpressIDs.get(i),
181+
);
182+
const relatingKey = Object.keys(relAttrs).find((key) =>
183+
key.startsWith("Relating"),
184+
);
185+
const relatedKey = Object.keys(relAttrs).find((key) =>
186+
key.startsWith("Related"),
187+
);
188+
if (!(relatingKey && relatedKey)) continue;
189+
const relatingID = relAttrs[relatingKey].value;
190+
const relatedIDs = relAttrs[relatedKey].map((el: any) => el.value);
179191

180-
for (let i = 0; i < lines.size(); i++) {
181-
const line = lines.get(i);
182-
const attrs = await ifcApi.properties.getItemProperties(modelID, line);
183-
properties[line] = attrs;
184-
}
192+
// forRelating
193+
const currentMap =
194+
relationsMap.get(relatingID) ?? new Map<number, number[]>();
195+
const index = this._inverseAttributes.indexOf(relating);
196+
currentMap.set(index, relatedIDs);
197+
relationsMap.set(relatingID, currentMap);
185198

186-
for (const attribute of this.inverseAttributes) {
187-
const rels = this.getAttributeRels(attribute);
188-
for (const rel of rels) {
189-
getRelationMap(properties, rel, (relatingID, relatedID) => {
190-
const inverseAttributes = this._relToAttributesMap.get(rel);
191-
if (!inverseAttributes) return;
192-
const { forRelated: related, forRelating: relating } =
193-
inverseAttributes;
194-
if (relating) {
195-
const currentMap =
196-
relationsMap.get(relatingID) ?? new Map<number, number[]>();
197-
const index = this.inverseAttributes.indexOf(relating);
198-
currentMap.set(index, relatedID);
199-
relationsMap.set(relatingID, currentMap);
200-
}
201-
if (related) {
202-
for (const id of relatedID) {
203-
const currentMap =
204-
relationsMap.get(id) ?? new Map<number, number[]>();
205-
const index = this.inverseAttributes.indexOf(related);
206-
const relations = currentMap.get(index) ?? [];
207-
relations.push(relatingID);
208-
currentMap.set(index, relations);
209-
relationsMap.set(id, currentMap);
210-
}
211-
}
212-
});
199+
// forRelated
200+
for (const id of relatedIDs) {
201+
const currentMap =
202+
relationsMap.get(id) ?? new Map<number, number[]>();
203+
const index = this._inverseAttributes.indexOf(related);
204+
const relations = currentMap.get(index) ?? [];
205+
relations.push(relatingID);
206+
currentMap.set(index, relations);
207+
relationsMap.set(id, currentMap);
208+
}
213209
}
214210
}
215211

@@ -240,7 +236,7 @@ export class IfcRelationsIndexer extends Component implements Disposable {
240236
const indexMap = this.relationMaps[model.uuid];
241237
if (!indexMap) return null;
242238
const entityRelations = indexMap.get(expressID);
243-
const attributeIndex = this.inverseAttributes.indexOf(relationName);
239+
const attributeIndex = this._inverseAttributes.indexOf(relationName);
244240
if (!entityRelations || attributeIndex === -1) return null;
245241
const relations = entityRelations.get(attributeIndex);
246242
if (!relations) return null;

packages/components/src/ifc/IfcRelationsIndexer/src/getRelationMap.ts

Lines changed: 0 additions & 37 deletions
This file was deleted.

packages/components/src/ifc/IfcRelationsIndexer/src/relToAttributesMap.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { InverseAttribute } from "./types";
44
// TODO: Construct this based on the IFC EXPRESS long form schema?
55
export const relToAttributesMap = new Map<
66
number,
7-
{ forRelating?: InverseAttribute; forRelated?: InverseAttribute }
7+
{ forRelating: InverseAttribute; forRelated: InverseAttribute }
88
>([
99
[
1010
WEBIFC.IFCRELAGGREGATES,

0 commit comments

Comments
 (0)