IFClite TypeScript API
    Preparing search index...

    Function collectStyleEntities

    • Collect style and presentation-layer entities (IFCSTYLEDITEM, IFCSTYLEDREPRESENTATION, IFCPRESENTATIONLAYERASSIGNMENT, IFCPRESENTATIONLAYERWITHSTYLE) that reference geometry already in the closure, then transitively follow their own references.

      In IFC STEP, IFCSTYLEDITEM references a geometry RepresentationItem, but nothing references the StyledItem back — and IFCPRESENTATIONLAYERASSIGNMENT is the same shape: it names the representation/items assigned to a layer (AssignedItems) but nothing points back at the assignment itself. So the forward closure walk misses both entirely. This function does one reverse pass using the byType index: for each candidate, check if any referenced ID is in the closure. If yes, add it and walk its own reference chain in.

      excludeIds (hiddenProductIds) only ever holds PRODUCT ids, never the geometry those products exclusively own. IfcPresentationLayerAssignment. AssignedItems routinely names REPRESENTATION-level ids directly (one CAD layer naming every wall's IfcShapeRepresentation), so a shared layer assignment can legitimately be rescued by a VISIBLE wall's representation while also naming a HIDDEN wall's — an id nowhere in excludeIds. A plain excludeIds.has(id) check (the shape collectGeoreferencingEntities uses) would miss that id entirely and resurrect the hidden wall's geometry.

      The fix relies on an invariant this function's own contract already guarantees: it runs strictly AFTER collectReferencedEntityIds, which has already walked the FULL forward closure from every visible root. So any geometry/representation-classified entity (isGeometryEntity) that is NOT already in closure by the time this pass starts has no other path to visibility — it is either exclusively owned by an excluded product, or genuinely unreferenced by any visible root — and must not be resurrected just because it happens to sit in the same AssignedItems/Item list as something that IS visible. Presentation RESOURCE types (colours, surface styles — see STYLE_RESOURCE_EXEMPT_TYPES) are the one exception: they are shared data, never product-exclusive, so the pre-existing "pull in the style chain" behaviour for them is preserved unconditionally.

      excludeIds is still threaded through and checked directly (matching collectGeoreferencingEntities's shape) as a second, cheap guard — e.g. if a future entity ever names an excluded id that is not geometry-classified.

      Uses byType for O(candidates) instead of O(allEntities), and byte-level scanning for #ID extraction.

      Must be called AFTER collectReferencedEntityIds so the closure is complete.

      Parameters

      • closure: Set<number>

        The existing closure set (mutated in place)

      • source: Uint8Array<ArrayBufferLike> | IfcSourceBytes

        The original STEP file source buffer

      • entityIndex: {
            byId: {
                refGroupsOf?: (
                    id: number,
                    sourceGroups?: readonly (number | readonly number[] | undefined)[],
                ) => readonly (number | readonly number[])[] | undefined;
                get(
                    expressId: number,
                ): { byteLength: number; byteOffset: number; type: string } | undefined;
                has(expressId: number): boolean;
                refsOf?(expressId: number): readonly number[] | undefined;
            };
            byType: Map<string, number[]>;
        }

        Full entity index with type info and byType lookup

      • OptionalexcludeIds: ReadonlySet<number>

        Entity IDs to never add, even if they reference the closure (e.g. pass.hiddenProductIds / a subset export's excludedIds)

      Returns void