diff --git a/packages/components/src/ifc/IfcRelationsIndexer/index.ts b/packages/components/src/ifc/IfcRelationsIndexer/index.ts index 7850d1039..9f8ad23bf 100644 --- a/packages/components/src/ifc/IfcRelationsIndexer/index.ts +++ b/packages/components/src/ifc/IfcRelationsIndexer/index.ts @@ -3,7 +3,6 @@ import { FragmentsGroup } from "@thatopen/fragments"; import { Disposable, Event, Component, Components } from "../../core"; import { FragmentManager } from "../../fragments/FragmentManager"; import { IfcPropertiesUtils } from "../Utils"; -import { getRelationMap } from "./src/getRelationMap"; import { RelationsMap, ModelsRelationMap, @@ -32,11 +31,7 @@ export class IfcRelationsIndexer extends Component implements Disposable { private _relToAttributesMap = relToAttributesMap; - /** - * Array of inverse attribute names. - * This array is used to define the inverse attributes that the indexer will process and index. - */ - readonly inverseAttributes: InverseAttributes = [ + private _inverseAttributes: InverseAttributes = [ "IsDecomposedBy", "Decomposes", "AssociatedTo", @@ -53,6 +48,17 @@ export class IfcRelationsIndexer extends Component implements Disposable { "ContainsElements", ]; + private _ifcRels = [ + WEBIFC.IFCRELAGGREGATES, + WEBIFC.IFCRELASSOCIATESMATERIAL, + WEBIFC.IFCRELASSOCIATESCLASSIFICATION, + WEBIFC.IFCRELASSIGNSTOGROUP, + WEBIFC.IFCRELDEFINESBYPROPERTIES, + WEBIFC.IFCRELDEFINESBYTYPE, + WEBIFC.IFCRELDEFINESBYTEMPLATE, + WEBIFC.IFCRELCONTAINEDINSPATIALSTRUCTURE, + ] as const; + /** * Holds the relationship mappings for each model processed by the indexer. * 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 { delete this.relationMaps[data.groupID]; }; - private getAttributeRels(value: string) { - const keys: number[] = []; - for (const [rel, attribute] of this._relToAttributesMap.entries()) { - const { forRelating, forRelated } = attribute; - if (forRelating === value || forRelated === value) keys.push(rel); - } - return keys; - } - /** * Adds a relation map to the model's relations map. * @@ -125,46 +122,43 @@ export class IfcRelationsIndexer extends Component implements Disposable { const relationsMap: RelationsMap = new Map(); - for (const attribute of this.inverseAttributes) { - const rels = this.getAttributeRels(attribute); - for (const rel of rels) { - await IfcPropertiesUtils.getRelationMap( - model, - rel, - async (relatingID, relatedID) => { - const inverseAttributes = this._relToAttributesMap.get(rel); - if (!inverseAttributes) return; - const { forRelated: related, forRelating: relating } = - inverseAttributes; - if (relating) { - const currentMap = - relationsMap.get(relatingID) ?? new Map(); - // TODO: indexOf might be slow. Better a Map? - const index = this.inverseAttributes.indexOf(relating); - currentMap.set(index, relatedID); - relationsMap.set(relatingID, currentMap); - } - if (related) { - for (const id of relatedID) { - const currentMap = - relationsMap.get(id) ?? new Map(); - const index = this.inverseAttributes.indexOf(related); - const relations = currentMap.get(index) ?? []; - relations.push(relatingID); - currentMap.set(index, relations); - relationsMap.set(id, currentMap); - } - } - }, - ); - } + for (const rel of this._ifcRels) { + await IfcPropertiesUtils.getRelationMap( + model, + rel, + async (relatingID, relatedIDs) => { + const inverseAttributes = this._relToAttributesMap.get(rel); + if (!inverseAttributes) return; + const { forRelated: related, forRelating: relating } = + inverseAttributes; + + // forRelating + const currentMap = + relationsMap.get(relatingID) ?? new Map(); + const index = this._inverseAttributes.indexOf(relating); + currentMap.set(index, relatedIDs); + relationsMap.set(relatingID, currentMap); + + // forRelated + for (const id of relatedIDs) { + const currentMap = + relationsMap.get(id) ?? new Map(); + const index = this._inverseAttributes.indexOf(related); + const relations = currentMap.get(index) ?? []; + relations.push(relatingID); + currentMap.set(index, relations); + relationsMap.set(id, currentMap); + } + }, + ); } + this.setRelationMap(model, relationsMap); return relationsMap; } /** - * Processes a given model from a WebIfc API to index its IFC entities relations based on predefined inverse attributes. + * Processes a given model from a WebIfc API to index its IFC entities relations. * * @param ifcApi - The WebIfc API instance from which to retrieve the model's properties. * @param modelID - The unique identifier of the model within the WebIfc API. @@ -174,42 +168,44 @@ export class IfcRelationsIndexer extends Component implements Disposable { async processFromWebIfc(ifcApi: WEBIFC.IfcAPI, modelID: number) { const relationsMap: RelationsMap = new Map(); - const properties: Record> = {}; - const lines = ifcApi.GetAllLines(modelID); + for (const relType of this._ifcRels) { + const relInverseAttributes = this._relToAttributesMap.get(relType); + if (!relInverseAttributes) continue; + const { forRelated: related, forRelating: relating } = + relInverseAttributes; + const relExpressIDs = ifcApi.GetLineIDsWithType(modelID, relType); + for (let i = 0; i < relExpressIDs.size(); i++) { + const relAttrs = await ifcApi.properties.getItemProperties( + modelID, + relExpressIDs.get(i), + ); + const relatingKey = Object.keys(relAttrs).find((key) => + key.startsWith("Relating"), + ); + const relatedKey = Object.keys(relAttrs).find((key) => + key.startsWith("Related"), + ); + if (!(relatingKey && relatedKey)) continue; + const relatingID = relAttrs[relatingKey].value; + const relatedIDs = relAttrs[relatedKey].map((el: any) => el.value); - for (let i = 0; i < lines.size(); i++) { - const line = lines.get(i); - const attrs = await ifcApi.properties.getItemProperties(modelID, line); - properties[line] = attrs; - } + // forRelating + const currentMap = + relationsMap.get(relatingID) ?? new Map(); + const index = this._inverseAttributes.indexOf(relating); + currentMap.set(index, relatedIDs); + relationsMap.set(relatingID, currentMap); - for (const attribute of this.inverseAttributes) { - const rels = this.getAttributeRels(attribute); - for (const rel of rels) { - getRelationMap(properties, rel, (relatingID, relatedID) => { - const inverseAttributes = this._relToAttributesMap.get(rel); - if (!inverseAttributes) return; - const { forRelated: related, forRelating: relating } = - inverseAttributes; - if (relating) { - const currentMap = - relationsMap.get(relatingID) ?? new Map(); - const index = this.inverseAttributes.indexOf(relating); - currentMap.set(index, relatedID); - relationsMap.set(relatingID, currentMap); - } - if (related) { - for (const id of relatedID) { - const currentMap = - relationsMap.get(id) ?? new Map(); - const index = this.inverseAttributes.indexOf(related); - const relations = currentMap.get(index) ?? []; - relations.push(relatingID); - currentMap.set(index, relations); - relationsMap.set(id, currentMap); - } - } - }); + // forRelated + for (const id of relatedIDs) { + const currentMap = + relationsMap.get(id) ?? new Map(); + const index = this._inverseAttributes.indexOf(related); + const relations = currentMap.get(index) ?? []; + relations.push(relatingID); + currentMap.set(index, relations); + relationsMap.set(id, currentMap); + } } } @@ -240,7 +236,7 @@ export class IfcRelationsIndexer extends Component implements Disposable { const indexMap = this.relationMaps[model.uuid]; if (!indexMap) return null; const entityRelations = indexMap.get(expressID); - const attributeIndex = this.inverseAttributes.indexOf(relationName); + const attributeIndex = this._inverseAttributes.indexOf(relationName); if (!entityRelations || attributeIndex === -1) return null; const relations = entityRelations.get(attributeIndex); if (!relations) return null; diff --git a/packages/components/src/ifc/IfcRelationsIndexer/src/getRelationMap.ts b/packages/components/src/ifc/IfcRelationsIndexer/src/getRelationMap.ts deleted file mode 100644 index 1d581a34c..000000000 --- a/packages/components/src/ifc/IfcRelationsIndexer/src/getRelationMap.ts +++ /dev/null @@ -1,37 +0,0 @@ -export const getRelationMap = ( - properties: Record>, - relationType: number, - onElementsFound?: (relatingID: number, relatedIDs: number[]) => void, -) => { - const defaultCallback = () => {}; - const _onElementsFound = onElementsFound ?? defaultCallback; - const result: { [relatingID: number]: number[] } = {}; - const ids = Object.keys(properties); - for (const expressID of ids) { - const prop = properties[expressID]; - - if (!prop) continue; - - const isRelation = prop.type === relationType; - const relatingKey = Object.keys(prop).find((key) => - key.startsWith("Relating"), - ); - - const relatedKey = Object.keys(prop).find((key) => - key.startsWith("Related"), - ); - - if (!(isRelation && relatingKey && relatedKey)) continue; - const relating = properties[prop[relatingKey]?.value]; - const related = prop[relatedKey]; - - if (!relating || !related) continue; - - if (!(related && Array.isArray(related))) continue; - const elements = related.map((el: any) => el.value); - - _onElementsFound(relating.expressID, elements); - result[relating.expressID] = elements; - } - return result; -}; diff --git a/packages/components/src/ifc/IfcRelationsIndexer/src/relToAttributesMap.ts b/packages/components/src/ifc/IfcRelationsIndexer/src/relToAttributesMap.ts index d456e4615..dd87a6293 100644 --- a/packages/components/src/ifc/IfcRelationsIndexer/src/relToAttributesMap.ts +++ b/packages/components/src/ifc/IfcRelationsIndexer/src/relToAttributesMap.ts @@ -4,7 +4,7 @@ import { InverseAttribute } from "./types"; // TODO: Construct this based on the IFC EXPRESS long form schema? export const relToAttributesMap = new Map< number, - { forRelating?: InverseAttribute; forRelated?: InverseAttribute } + { forRelating: InverseAttribute; forRelated: InverseAttribute } >([ [ WEBIFC.IFCRELAGGREGATES,