Collapse an IFC building into a single UnstructuredGrid

Collapse an IFC building into a single UnstructuredGrid#

IFC files arrive as deeply-nested pyvista.MultiBlock trees (building / storey / element). For some downstream analyses you want one mesh, with each cell tagged by its source element. Combine the tree and carry an element id onto cell data so downstream code can filter by element without walking the tree.

This uses a real BIM model: the buildingSMART “Single-family house” sample (CC-BY 4.0, buildingSMART International), an IFC4 project with a full site / building / storey hierarchy, walls, slabs, and property sets.

import numpy as np
import pandas as pd
import pyvista as pv

import pyvista_cad
from pyvista_cad.examples import downloads

Read the real IFC building.

MultiBlock (0x7f6fa5f80100)
  N Blocks:   5
  X Bounds:   -2.964e+01, 8.900e+00
  Y Bounds:   -1.499e+01, 9.300e+00
  Z Bounds:   -1.300e+00, 5.700e+00


Drop stray geo-reference / survey markers placed far from the house (a robust MAD test on block position, not a brittle name/type rule) so they do not skew the combined grid’s bounds.

mb = mb.cad.drop_spatial_outliers()

Tag each leaf block’s cells with a numeric id and its IFC type, then combine into a single UnstructuredGrid.

rows = []
for i, (path, block) in enumerate(mb.cad.walk()):
    if not isinstance(block, pv.DataSet) or block.n_cells == 0:
        continue
    block['element_id'] = np.full(block.n_cells, i, dtype=np.int32)
    rows.append(
        {
            'element_id': i,
            'path': str(path),
            'ifc_type': block.field_data.get('cad.ifc_type', [b''])[0],
        }
    )

combined = mb.combine(merge_points=False)
pd.DataFrame(rows)
element_id path ifc_type
0 5 environment - site/house - site/Single-family ... IfcFurniture
1 6 environment - site/house - site/Single-family ... IfcSlab
2 7 environment - site/house - site/Single-family ... IfcWall
3 8 environment - site/house - site/Single-family ... IfcWall
4 9 environment - site/house - site/Single-family ... IfcWall
5 10 environment - site/house - site/Single-family ... IfcWall
6 11 environment - site/house - site/Single-family ... IfcSpatialZone
7 12 environment - site/house - site/Single-family ... IfcBuildingElementProxy
8 13 living room IfcSpace
9 14 entry hall IfcSpace
10 15 house - roof - slab left IfcSlab
11 16 house - roof - slab right IfcSlab


The combined grid carries element_id on its cells.

UnstructuredGrid (0x7f6fa5f80ac0)
  N Cells:    331
  N Points:   193
  X Bounds:   2.700e+00, 8.900e+00
  Y Bounds:   2.700e+00, 9.300e+00
  Z Bounds:   -5.987e-01, 5.700e+00
  N Arrays:   9


Render the building colored by element id.

pl = pv.Plotter()
pl.add_mesh(combined, scalars='element_id', cmap='tab20', show_edges=True, edge_color='black')
pl.show()
ifc to unstructured grid

Total running time of the script: (0 minutes 0.568 seconds)