Skip to content

Commit

Permalink
feat(core): adds a new created pset with the IfcPropertiesManager to …
Browse files Browse the repository at this point in the history
…the relations index
  • Loading branch information
HoyosJuan committed Jul 17, 2024
1 parent 32efe3c commit 000bc06
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 22 deletions.
2 changes: 1 addition & 1 deletion packages/core/src/fragments/Hider/example.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ for (const name in spatialStructures) {
const found = classifier.list.spatialStructures[name];
if (found && found.id !== null) {
for (const [_id, model] of fragments.groups) {
const foundIDs = indexer.getElementsChildren(model, found.id);
const foundIDs = indexer.getEntityChildren(model, found.id);
const fragMap = model.getFragmentMap(foundIDs);
hider.set(target.value, fragMap);
}
Expand Down
17 changes: 11 additions & 6 deletions packages/core/src/ifc/IfcPropertiesManager/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Component, Disposable, Event, Components } from "../../core";
import { IfcPropertiesUtils } from "../Utils";
import { IfcLoader } from "../../fragments/IfcLoader";
import { UUID } from "../../utils";
import { IfcRelationsIndexer } from "../IfcRelationsIndexer";

/**
* Types for boolean properties in IFC schema.
Expand Down Expand Up @@ -171,7 +172,7 @@ export class IfcPropertiesManager extends Component implements Disposable {
* Each object must have an `expressID` property, which is the express ID of the entity in the model.
* The rest of the properties will be set as the properties of the entity.
*
* @returns {Promise<void>} A promise that resolves when all the properties have been set.
* @returns A promise that resolves when all the properties have been set.
*
* @throws Will throw an error if any of the `expressID` properties are missing in the `dataToSave` array.
*/
Expand Down Expand Up @@ -238,7 +239,7 @@ export class IfcPropertiesManager extends Component implements Disposable {
* @param model - The FragmentsGroup model from which to remove the Pset.
* @param psetID - The express IDs of the Psets to be removed.
*
* @returns {Promise<void>} A promise that resolves when all the Psets have been removed.
* @returns A promise that resolves when all the Psets have been removed.
*
* @throws Will throw an error if any of the `expressID` properties are missing in the `psetID` array.
* @throws Will throw an error if the Pset to be removed is not of type `IFCPROPERTYSET`.
Expand Down Expand Up @@ -337,7 +338,7 @@ export class IfcPropertiesManager extends Component implements Disposable {
* @param psetID - The express ID of the Pset from which to remove the property.
* @param propID - The express ID of the property to be removed.
*
* @returns {Promise<void>} A promise that resolves when the property has been removed.
* @returns A promise that resolves when the property has been removed.
*
* @throws Will throw an error if the Pset or the property to be removed are not found in the model.
* @throws Will throw an error if the Pset to be removed is not of type `IFCPROPERTYSET`.
Expand All @@ -357,13 +358,13 @@ export class IfcPropertiesManager extends Component implements Disposable {
async addElementToPset(
model: FragmentsGroup,
psetID: number,
...elementID: number[]
...expressIDs: number[]
) {
const relID = await IfcPropertiesUtils.getPsetRel(model, psetID);
if (!relID) return;
const rel = await model.getProperties(relID);
if (!rel) return;
for (const expressID of elementID) {
for (const expressID of expressIDs) {
const elementHandle = new WEBIFC.Handle(expressID);
rel.RelatedObjects.push(elementHandle);
this.onElementToPset.trigger({
Expand All @@ -373,6 +374,10 @@ export class IfcPropertiesManager extends Component implements Disposable {
});
}
this.registerChange(model, psetID);
const indexer = this.components.get(IfcRelationsIndexer);
for (const expressID of expressIDs) {
indexer.addEntityRelations(model, expressID, "IsDefinedBy", psetID);
}
}

/**
Expand All @@ -382,7 +387,7 @@ export class IfcPropertiesManager extends Component implements Disposable {
* @param psetID - The express ID of the Pset to which to add the elements.
* @param elementID - The express IDs of the elements to be added.
*
* @returns {Promise<void>} A promise that resolves when all the elements have been added.
* @returns A promise that resolves when all the elements have been added.
*
* @throws Will throw an error if the Pset or the elements to be added are not found in the model.
* @throws Will throw an error if the Pset to be added to is not of type `IFCPROPERTYSET`.
Expand Down
80 changes: 65 additions & 15 deletions packages/core/src/ifc/IfcRelationsIndexer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,21 +117,30 @@ export class IfcRelationsIndexer extends Component implements Disposable {
// forRelating
const currentMap =
relationsMap.get(relatingID) ?? new Map<number, number[]>();
const index = this._inverseAttributes.indexOf(relating);
currentMap.set(index, relatedIDs);
relationsMap.set(relatingID, currentMap);
const index = this.getAttributeIndex(relating);
if (index) {
currentMap.set(index, relatedIDs);
relationsMap.set(relatingID, currentMap);
}

// forRelated
for (const id of relatedIDs) {
const currentMap = relationsMap.get(id) ?? new Map<number, number[]>();
const index = this._inverseAttributes.indexOf(related);
const index = this.getAttributeIndex(related);
if (!index) continue;
const relations = currentMap.get(index) ?? [];
relations.push(relatingID);
currentMap.set(index, relations);
relationsMap.set(id, currentMap);
}
}

private getAttributeIndex(inverseAttribute: InverseAttribute) {
const index = this._inverseAttributes.indexOf(inverseAttribute);
if (index === -1) return null;
return index;
}

/**
* Adds a relation map to the model's relations map.
*
Expand Down Expand Up @@ -244,11 +253,13 @@ export class IfcRelationsIndexer extends Component implements Disposable {
) {
const indexMap = this.relationMaps[model.uuid];
if (!indexMap) {
return null;
throw new Error(
`IfcRelationsIndexer: model ${model.uuid} has no relations indexed.`,
);
}
const entityRelations = indexMap.get(expressID);
const attributeIndex = this._inverseAttributes.indexOf(relationName);
if (!entityRelations || attributeIndex === -1) {
const attributeIndex = this.getAttributeIndex(relationName);
if (!(entityRelations && attributeIndex)) {
return null;
}
const relations = entityRelations.get(attributeIndex);
Expand Down Expand Up @@ -360,21 +371,56 @@ export class IfcRelationsIndexer extends Component implements Disposable {
this.onDisposed.reset();
}

/**
* Adds relations between an entity and other entities in a BIM model.
*
* @param model - The BIM model to which the relations will be added.
* @param expressID - The expressID of the entity within the model.
* @param relationName - The IFC schema inverse attribute of the relation to add (e.g., "IsDefinedBy", "ContainsElements").
* @param relIDs - The expressIDs of the related entities within the model.
*
* @throws An error if the relation name is not a valid relation name.
*/
addEntityRelations(
model: FragmentsGroup,
expressID: number,
relationName: InverseAttribute,
...relIDs: number[]
) {
const existingRelations = this.getEntityRelations(
model,
expressID,
relationName,
);
if (!existingRelations) {
const attributeIndex = this.getAttributeIndex(relationName);
if (!attributeIndex) {
throw new Error(
`IfcRelationsIndexer: ${relationName} is not a valid relation name.`,
);
}
const entityRelations = this.relationMaps[model.uuid].get(expressID);
entityRelations?.set(attributeIndex, relIDs);
} else {
existingRelations.push(...relIDs);
}
}

/**
* Gets the children of the given element recursively. E.g. in a model with project - site - building - storeys - rooms, passing a storey will include all its children and the children of the rooms contained in it.
*
* @param model The BIM model whose children to get.
* @param id The expressID of the item whose children to get.
* @param expressID The expressID of the item whose children to get.
* @param found An optional parameter that includes a set of expressIDs where the found element IDs will be added.
*
* @returns A `Set` with the expressIDs of the found items.
*/
getElementsChildren(
getEntityChildren(
model: FragmentsGroup,
id: number,
expressID: number,
found = new Set<number>(),
) {
found.add(id);
found.add(expressID);

const modelRelations = this.relationMaps[model.uuid];
if (modelRelations === undefined) {
Expand All @@ -384,18 +430,22 @@ export class IfcRelationsIndexer extends Component implements Disposable {
}

// Spatial structure elements contained in this item
const spatialRels = this.getEntityRelations(model, id, "IsDecomposedBy");
const spatialRels = this.getEntityRelations(
model,
expressID,
"IsDecomposedBy",
);
if (spatialRels) {
for (const id of spatialRels) {
this.getElementsChildren(model, id, found);
this.getEntityChildren(model, id, found);
}
}

// Elements contained in this item
const rels = this.getEntityRelations(model, id, "ContainsElements");
const rels = this.getEntityRelations(model, expressID, "ContainsElements");
if (rels) {
for (const id of rels) {
this.getElementsChildren(model, id, found);
this.getEntityChildren(model, id, found);
}
}

Expand Down

0 comments on commit 000bc06

Please sign in to comment.