Skip to content

Group by geometry/design: representationId issues #735

@ShaMan123

Description

@ShaMan123

I am looking into grouping instances of the same design.
@agviegas suggested using representationId, see ref below.
However I am facing numerical instability in ifc files exported from Tekla.
I ran the following to group instances using fragment's representationId:

    const model = new SingleThreadedFragmentsModel("MODEL", buffer);
    const ids = model.getItemsWithGeometry();
    const items = await model.getItems(ids);
    // TODO: some IFCPLATE entities are the same but are assembled with different bolts
    // workaround by using the tag, should find a better solution
    const tags = new Map(
      [...items].map(([id, { data }]) => [
        id,
        parseTag(data.Tag?.value) ?? parseTag(data.Name?.value),
      ])
    );
    const idsByGeometryMap = new Map<string, number[]>();
    model.getItemsGeometry(ids).forEach((geometries, index) => {
      const id = ids[index];
      const key = `${geometries.map((g) => g.representationId).join(",")}_${tags.get(id)}`;
      let entry = idsByGeometryMap.get(key);
      if (!entry) {
        entry = [];
        idsByGeometryMap.set(key, entry);
      }
      entry.push(id);
    });
    model.dispose();

Numerical instability

This has revealed that Tekla is exporting ifc data with rounding issues, causing instances to vary because of insignificant floating points.
I have tried to configure the ifc importer but that doesn't seem to make a difference.

importer.webIfcSettings.TOLERANCE_SCALAR_EQUALITY = 10;

How can this be improved/workedaround?

Splitting

Another issue I wish to surface is that when splitting an ifc it seems that the localId assigned as the representationId is not unique across splits. This needs discussion.
Shouldn't the splitter split the ifc such that all instances of the same design reside in the same split? If not I think representationId must be unique across all splits or else splitting is causing a damage in performance causing fragments to generate redundant geometries/BIMMesh instances.

Ref

2. Getting representationId while reading the IFC line by line.

Strictly speaking, representationId doesn't exist during IFC parsing. It's a localId the importer allocates at write time when it builds the .frag (see representationsLocalIds.unshift(nextId++) in packages/fragments/src/Importers/IfcImporter/src/geometry/index.ts). The .frag's meshes.representationIds vector is what surfaces it at runtime.

What does exist during parsing is the geometry's express ID, and that's what fragments uses internally as the equality key while building. In packages/fragments/src/Importers/IfcImporter/src/geometry/ifc-file-reader.ts, look at processFlatGeometry (and the parallel methods):

const geometryRef = mesh.geometries.get(geometryIndex);
// ...
const geometryData: IfcGeometryInstance = {
  id: geometryRef.geometryExpressID,
  // ...
};

That geometryExpressID is web-ifc's stable id for the underlying IFC representation. Two products that share a representation get the same geometryExpressID, which is exactly the "instances of the same design" key you want. The importer dedupes on it (_previousGeometriesIDs) and emits one entry per unique express id, then samples reference it.

If you're walking IFC raw (no web-ifc), the equivalent is the express id of IFCSHAPEREPRESENTATION for direct geometry, and IFCREPRESENTATIONMAP (referenced through IFCMAPPEDITEM.MappingSource) for true instanced geometry. Those are the IFC schema's own "shared geometry" handles.

So the recipe for your importer: when you see an IFCMAPPEDITEM, read its MappingSource (an IFCREPRESENTATIONMAP express id) and use that as your equality key. For non-mapped items, use the IFCSHAPEREPRESENTATION express id of the product's Representation. That gives you the same grouping fragments uses, available before any conversion runs.

Originally posted by @agviegas in #709

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions