pub fn propagate_voids_to_parts<T>(
void_index: &mut FxHashMap<u32, Vec<u32>>,
content: &T,
decoder: &mut EntityDecoder<'_>,
) -> FxHashMap<u32, u32>Expand description
Propagate void (opening) relationships from aggregate parents to their children
and return a child-part → parent-element map covering every emitted aggregate
IfcWall → IfcBuildingElementPart pair.
In IFC, multilayer walls use IfcRelAggregates to decompose a parent IfcWall
into child IfcBuildingElementPart entities (one per material layer). The
IfcRelVoidsElement relationships reference the parent wall, but the individual
layer parts also need void subtraction to cut windows/doors through each layer.
This function scans for IfcRelAggregates and, in the same pass:
- Copies the host’s void relationships to EVERY aggregated descendant,
any depth and any type, whether or not it has a
Representation(propagate_voids_via_aggregates; an entry for a geometry-less part is never looked up). Each layer slice still gets its window/door cutouts. - Returns a [
FxHashMap] mapping everyIfcBuildingElementPartthat has its ownRepresentationto its NEAREST aggregating ancestor that also has one. Callers use this to skip per-part geometry emission when the “merge multilayer wall as a single solid” toggle is on (issue #540): the ancestor’s merged solid is drawn instead, which is only possible when that ancestor has geometry of its own.
The map walk descends to the same depth as the void propagation, but only
through representation-less intermediates (an IfcElementAssembly that
merely groups), so IfcWall -> IfcElementAssembly -> IfcBuildingElementPart
lands the part on the wall. A child with its own Representation ends the
descent: it is the parent of its own subtree in this same loop
(tests/void_index_nested_aggregates.rs). Parents without their own
geometry never appear as a map value, so the caller can never “skip” the
only geometry available for the assembly.