| name | ifcos-impl-geometry |
| description | Use when extracting 3D geometry from IFC files, creating geometric representations, or processing IFC geometry for visualization. Prevents the performance mistake of calling create_shape() per element instead of using the geometry iterator. Covers geometry settings, create_shape(), geometry iterator, extrusion/CSG/BRep creation, and coordinate transforms. Keywords: geometry, create_shape, geometry iterator, mesh extraction, extrusion, CSG, BRep, IfcShapeRepresentation, coordinates, 3D, visualization, get vertices from IFC, extract mesh, convert IFC to 3D.
|
| license | MIT |
| compatibility | Designed for Claude Code. Requires IfcOpenShell Python library. |
| metadata | {"author":"OpenAEC-Foundation","version":"1.0"} |
IfcOpenShell Geometry Processing & Creation
Quick Reference
Decision Tree: Reading vs Creating Geometry
Need geometry from IFC elements?
├── Extract existing geometry? (read/process)
│ ├── Single element → ifcopenshell.geom.create_shape(settings, element)
│ ├── Multiple elements (100+) → ifcopenshell.geom.iterator(settings, model, cpu_count)
│ └── Specific entity attributes → Manual traversal (element.Representation)
│
└── Create new geometry? (write/author)
├── Simple wall block → geometry.add_wall_representation()
├── Extruded profile (beam/column) → geometry.add_profile_representation()
├── Arbitrary mesh (furniture/equipment) → geometry.add_mesh_representation()
├── Boolean operation (opening/cut) → geometry.add_boolean()
├── Custom parametric shape → ShapeBuilder + builder.get_representation()
└── Slab/door/window/railing → geometry.add_{type}_representation()
Decision Tree: Tessellation vs BRep
What do you need the geometry for?
├── Visualization / rendering / game engine / export to mesh format
│ └── Tessellation (default) — triangulated mesh output
│ settings.set(settings.USE_BREP_DATA, False) # default
│
├── CAD operations / boolean operations / precise measurements
│ └── BRep — exact OpenCASCADE TopoDS_Shape
│ settings.set(settings.USE_BREP_DATA, True)
│ Requires: pythonOCC (PythonOCC-Core) for advanced operations
│
└── Geometry export to glTF/OBJ
└── Use serializer (ifcopenshell.geom.serializers)
Decision Tree: Local vs World Coordinates
What coordinate space?
├── Need absolute position in the model
│ └── USE_WORLD_COORDS = True
│ Vertices include full placement chain (element → storey → building → site)
│
├── Need position relative to element origin
│ └── USE_WORLD_COORDS = False (default)
│ Apply shape.transformation.matrix manually if needed
│
└── Need to compare positions across elements
└── USE_WORLD_COORDS = True (ALWAYS for cross-element comparison)
Critical Warnings
- ALWAYS wrap
create_shape() in try/except RuntimeError. Not all IfcProduct subtypes have geometry (IfcProject, IfcBuildingStorey, some IfcSite).
- ALWAYS use the iterator for processing 100+ elements. It is 5-10x faster than calling
create_shape() in a loop due to internal caching and multithreading.
- ALWAYS set up a representation context before creating geometry. Call
context.add_context() for the root 3D context, then a subcontext for Body/MODEL_VIEW.
- ALWAYS call
geometry.edit_object_placement() on elements that have geometry. Elements without a placement are positioned at the global origin.
- ALWAYS apply unit scale when reading raw coordinate values from IFC entities. Use
ifcopenshell.util.unit.calculate_unit_scale(model) to get the conversion factor to meters.
- NEVER assume geometry coordinates are in meters. Check the project units first.
- NEVER access
shape.geometry.verts without checking that create_shape() did not raise an exception.
- NEVER create geometry representations without first having a context (IfcGeometricRepresentationSubContext with identifier="Body").
- NEVER use
model.create_entity("IfcExtrudedAreaSolid", ...) for production code when geometry.add_profile_representation() or geometry.add_wall_representation() is available. The API functions handle context assignment, representation types, and validation automatically.
Essential Patterns
Pattern 1: Configure Geometry Settings
import ifcopenshell.geom
settings = ifcopenshell.geom.settings()
settings.set(settings.USE_WORLD_COORDS, True)
settings.set(settings.WELD_VERTICES, True)
settings.set(settings.USE_BREP_DATA, False)
settings_brep = ifcopenshell.geom.settings()
settings_brep.set(settings_brep.USE_BREP_DATA, True)
settings_brep.set(settings_brep.USE_WORLD_COORDS, True)
settings_fast = ifcopenshell.geom.settings()
settings_fast.set(settings_fast.DISABLE_OPENING_SUBTRACTIONS, True)
settings_fast.set(settings_fast.USE_WORLD_COORDS, True)
Pattern 2: Extract Single Element Geometry
import ifcopenshell
import ifcopenshell.geom
import numpy as np
model = ifcopenshell.open("model.ifc")
settings = ifcopenshell.geom.settings()
settings.set(settings.USE_WORLD_COORDS, True)
wall = model.by_type("IfcWall")[0]
try:
shape = ifcopenshell.geom.create_shape(settings, wall)
except RuntimeError:
print("No geometry or processing failed")
shape = None
if shape:
verts = np.array(shape.geometry.verts).reshape(-1, 3)
faces = np.array(shape.geometry.faces).reshape(-1, 3)
edges = np.array(shape.geometry.edges).reshape(-1, 2)
print(f"Vertices: {len(verts)}, Triangles: {len(faces)}")
Pattern 3: Batch Process with Iterator
import ifcopenshell
import ifcopenshell.geom
import multiprocessing
import numpy as np
model = ifcopenshell.open("model.ifc")
settings = ifcopenshell.geom.settings()
settings.set(settings.USE_WORLD_COORDS, True)
iterator = ifcopenshell.geom.iterator(
settings, model, multiprocessing.cpu_count())
if iterator.initialize():
while True:
shape = iterator.get()
element = model.by_id(shape.id)
verts = np.array(shape.geometry.verts).reshape(-1, 3)
faces = np.array(shape.geometry.faces).reshape(-1, 3)
if not iterator.next():
break
Pattern 4: Filtered Iterator
iterator = ifcopenshell.geom.iterator(
settings, model, multiprocessing.cpu_count(),
include=model.by_type("IfcWall"))
iterator = ifcopenshell.geom.iterator(
settings, model, multiprocessing.cpu_count(),
exclude=model.by_type("IfcSpace"))
if iterator.initialize():
while True:
shape = iterator.get()
if not iterator.next():
break
Pattern 5: Create Representation Context (Required Before Any Geometry Creation)
import ifcopenshell
import ifcopenshell.api
model = ifcopenshell.api.run("project.create_file", version="IFC4")
project = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcProject", name="My Project")
ifcopenshell.api.run("unit.assign_unit", model)
model3d = ifcopenshell.api.run("context.add_context", model,
context_type="Model")
body = ifcopenshell.api.run("context.add_context", model,
context_type="Model", context_identifier="Body",
target_view="MODEL_VIEW", parent=model3d)
Pattern 6: Create Wall Geometry
wall = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcWall", name="W-01")
wall_rep = ifcopenshell.api.run("geometry.add_wall_representation", model,
context=body, length=5.0, height=3.0, thickness=0.2)
ifcopenshell.api.run("geometry.assign_representation", model,
product=wall, representation=wall_rep)
ifcopenshell.api.run("geometry.edit_object_placement", model,
product=wall)
Pattern 7: Create Profile Extrusion (Beam/Column)
column = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcColumn", name="C-01")
profile = model.create_entity("IfcRectangleProfileDef",
ProfileType="AREA", XDim=0.3, YDim=0.3)
col_rep = ifcopenshell.api.run("geometry.add_profile_representation", model,
context=body, profile=profile, depth=3.0)
ifcopenshell.api.run("geometry.assign_representation", model,
product=column, representation=col_rep)
ifcopenshell.api.run("geometry.edit_object_placement", model,
product=column)
Pattern 8: Create Mesh Geometry (Arbitrary Shape)
element = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcFurniture", name="Table")
vertices = [[0,0,0],[1,0,0],[1,1,0],[0,1,0],
[0,0,0.8],[1,0,0.8],[1,1,0.8],[0,1,0.8]]
faces = [[0,1,2,3],[4,7,6,5],[0,4,5,1],[1,5,6,2],[2,6,7,3],[3,7,4,0]]
mesh_rep = ifcopenshell.api.run("geometry.add_mesh_representation", model,
context=body, vertices=vertices, faces=faces)
ifcopenshell.api.run("geometry.assign_representation", model,
product=element, representation=mesh_rep)
ifcopenshell.api.run("geometry.edit_object_placement", model,
product=element)
Pattern 9: Object Placement with Transformation Matrix
import numpy as np
import ifcopenshell.util.placement
wall = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcWall", name="Rotated Wall")
matrix = np.eye(4)
matrix = ifcopenshell.util.placement.rotation(90, "Z") @ matrix
matrix[:, 3][0:3] = (2.0, 3.0, 0.0)
ifcopenshell.api.run("geometry.edit_object_placement", model,
product=wall, matrix=matrix, is_si=True)
Pattern 10: Boolean Operations (CSG)
wall = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcWall", name="Wall with Opening")
wall_rep = ifcopenshell.api.run("geometry.add_wall_representation", model,
context=body, length=5.0, height=3.0, thickness=0.2)
ifcopenshell.api.run("geometry.assign_representation", model,
product=wall, representation=wall_rep)
opening = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcOpeningElement", name="Door Opening")
opening_rep = ifcopenshell.api.run("geometry.add_wall_representation", model,
context=body, length=0.9, height=2.1, thickness=0.2)
ifcopenshell.api.run("geometry.assign_representation", model,
product=opening, representation=opening_rep)
ifcopenshell.api.run("void.add_opening", model,
opening=opening, element=wall)
Common Operations
For detailed code examples of these operations, see Working Code Examples:
- Transformation matrix — Extract and convert 4x3 column-major matrix from processed shapes
- Material/style access — Read diffuse color, transparency from shape.geometry.materials
- ShapeBuilder — Create custom geometry with rectangle/circle/polyline profiles + extrusion
- glTF serialization — Export IFC geometry to glTF/GLB using iterator + serializer
- Shape helpers — Use
ifcopenshell.util.shape for grouped vertex/edge/face arrays
For complete settings and data structure tables, see API Method Signatures.
Version Notes
- Geometry processing via
ifcopenshell.geom is schema-agnostic. The same create_shape() and iterator calls work for IFC2X3, IFC4, and IFC4X3 files.
- Geometry creation via
ifcopenshell.api.geometry.* is also schema-agnostic — the API handles schema differences internally.
- The
ShapeBuilder utility (ifcopenshell.util.shape_builder) works across all schema versions.
- IFC4X3 adds alignment-based geometry (IfcLinearPlacement, IfcAlignment) not covered by the standard geometry API functions.
- BRep serialization to IFC depends on schema capabilities: IFC4+ supports more complex curved surfaces than IFC2X3.
Reference Links