| name | bonsai-syntax-elements |
| description | Use when accessing IFC elements from Blender objects in Bonsai -- getting the IFC entity behind a selected object, or finding which Blender object represents an IFC element. Prevents the common mistake of using ifcopenshell.open() instead of tool.Ifc.get() to access the live Bonsai file. Covers element-to-object mapping, IfcStore retrieval, and the Bonsai data bridge between bpy.types.Object and IFC entities. Keywords: tool.Ifc.get(), IfcStore, element mapping, Blender object to IFC, IFC entity, selected element, data bridge, Bonsai elements, get IFC from selected, which element is this.
|
| license | MIT |
| compatibility | Designed for Claude Code. Requires Python 3.x. |
| metadata | {"author":"OpenAEC-Foundation","version":"1.0"} |
Bonsai IFC Element Access Syntax
Version: Bonsai v0.8.4 | Blender 4.2.0+ | Python 3.11
Module path: bonsai.* — NEVER blenderbim.*
Dependencies: bonsai-core-architecture, ifcos-syntax-api
Critical Warnings
- ALWAYS use
bonsai.* imports. NEVER use blenderbim.* — renamed in 2024 (v0.8.0+).
- ALWAYS check
IfcStore.get_file() and tool.Ifc.get() for None before any IFC operation.
- ALWAYS use
tool.Ifc.get_entity(obj) to get an IFC entity from a Blender object. NEVER read obj.BIMProperties.ifc_definition_id and call model.by_id() manually — the tool method handles edge cases.
- NEVER assume every Blender object has an IFC entity.
get_entity() returns None for non-IFC objects.
- NEVER assume every IFC entity has a Blender object.
get_object() returns None for entities without scene representation.
- ALWAYS run element access code inside Blender (
blender --python). bonsai.tool.* depends on bpy and CANNOT run in standalone Python.
- NEVER cache IFC entity references across file reloads. Entity instances become stale when the IFC file is reloaded.
- ALWAYS use
tool.Ifc.link(element, obj) to create bidirectional mappings. NEVER manually populate IfcStore.id_map or IfcStore.guid_map.
Decision Tree: How to Access IFC Elements
What do you have?
│
├── A Blender object (bpy.types.Object)?
│ │
│ ├── Need the IFC entity?
│ │ └── tool.Ifc.get_entity(obj)
│ │ ├── Returns entity_instance → access .GlobalId, .Name, .is_a(), attributes
│ │ └── Returns None → object is NOT linked to IFC
│ │
│ ├── Need just the IFC step ID?
│ │ └── obj.BIMProperties.ifc_definition_id
│ │ ├── Returns int > 0 → linked to IFC entity with that step ID
│ │ └── Returns 0 → NOT linked to IFC
│ │
│ └── Need IFC class name?
│ └── entity = tool.Ifc.get_entity(obj)
│ └── entity.is_a() # "IfcWall", "IfcSlab", etc.
│
├── An IFC entity (ifcopenshell.entity_instance)?
│ │
│ ├── Need the Blender object?
│ │ └── tool.Ifc.get_object(entity)
│ │ ├── Returns bpy.types.Object → manipulate via Blender API
│ │ └── Returns None → entity has no Blender scene representation
│ │
│ └── Need another entity related to this one?
│ ├── Type definition?
│ │ └── ifcopenshell.util.element.get_type(entity)
│ ├── Spatial container?
│ │ └── ifcopenshell.util.element.get_container(entity)
│ ├── Property sets?
│ │ └── ifcopenshell.util.element.get_psets(entity)
│ └── Material?
│ └── ifcopenshell.util.element.get_material(entity)
│
├── An IFC class name (string)?
│ │
│ └── Need all entities of that class?
│ └── model = tool.Ifc.get()
│ └── model.by_type("IfcWall") # Returns list of entity_instance
│
├── An IFC GlobalId (string)?
│ │
│ └── model = tool.Ifc.get()
│ └── model.by_guid("2O2Fr$t4X7Zf8...") # Returns entity_instance
│
├── An IFC step ID (int)?
│ │
│ ├── Need the IFC entity?
│ │ └── model = tool.Ifc.get()
│ │ └── model.by_id(step_id) # Returns entity_instance
│ │
│ └── Need the Blender object directly?
│ └── IfcStore.id_map.get(step_id) # Returns bpy.types.Object or None
│
└── Nothing — need to discover elements?
│
├── All elements in the model?
│ └── model.by_type("IfcElement") # All physical elements
│
├── All elements in a specific storey?
│ └── ifcopenshell.util.element.get_decomposition(storey)
│
└── All elements matching a query?
└── Use ifcopenshell.util.selector (CSS-like syntax)
Essential Patterns
Pattern 1: Get the Live IFC File
import bonsai.tool as tool
model = tool.Ifc.get()
if model is None:
raise RuntimeError("No IFC project loaded.")
from bonsai.bim.ifc import IfcStore
model = IfcStore.get_file()
if model is None:
raise RuntimeError("No IFC project loaded.")
tool.Ifc.get() and IfcStore.get_file() return the same ifcopenshell.file instance. Use tool.Ifc.get() in tool/core code; use IfcStore.get_file() in operator/UI code.
Pattern 2: Blender Object → IFC Entity
import bpy
import bonsai.tool as tool
obj = bpy.context.active_object
entity = tool.Ifc.get_entity(obj)
if entity is None:
print(f"{obj.name} is not linked to IFC")
else:
print(f"IFC class: {entity.is_a()}")
print(f"GlobalId: {entity.GlobalId}")
print(f"Name: {entity.Name}")
print(f"Step ID: {entity.id()}")
Pattern 3: IFC Entity → Blender Object
import bonsai.tool as tool
model = tool.Ifc.get()
wall = model.by_type("IfcWall")[0]
obj = tool.Ifc.get_object(wall)
if obj is None:
print(f"Wall {wall.Name} has no Blender representation")
else:
print(f"Blender object: {obj.name}")
obj.select_set(True)
Pattern 4: Query Elements by Type
import bonsai.tool as tool
model = tool.Ifc.get()
if model is None:
raise RuntimeError("No IFC project loaded.")
walls = model.by_type("IfcWall")
elements = model.by_type("IfcElement")
spatial = model.by_type("IfcSpatialElement")
walls_only = model.by_type("IfcWall", include_subtypes=False)
Pattern 5: Look Up by GlobalId or Step ID
import bonsai.tool as tool
from bonsai.bim.ifc import IfcStore
model = tool.Ifc.get()
entity = model.by_guid("2O2Fr$t4X7Zf8NOew3FLOH")
entity = model.by_id(42)
obj = IfcStore.id_map.get(42)
obj = IfcStore.guid_map.get("2O2Fr$t4X7Zf8NOew3FLOH")
Pattern 6: Navigate Entity Relationships
import bonsai.tool as tool
import ifcopenshell.util.element
model = tool.Ifc.get()
wall = model.by_type("IfcWall")[0]
container = ifcopenshell.util.element.get_container(wall)
if container:
print(f"Wall is in: {container.Name} ({container.is_a()})")
wall_type = ifcopenshell.util.element.get_type(wall)
if wall_type:
print(f"Wall type: {wall_type.Name}")
psets = ifcopenshell.util.element.get_psets(wall)
for pset_name, props in psets.items():
print(f" {pset_name}: {props}")
material = ifcopenshell.util.element.get_material(wall)
if material:
print(f"Material: {material.is_a()} — {material.Name}")
Pattern 7: Iterate Over All Elements with Blender Objects
import bonsai.tool as tool
from bonsai.bim.ifc import IfcStore
model = tool.Ifc.get()
for ifc_id, obj in IfcStore.id_map.items():
entity = model.by_id(ifc_id)
print(f"{obj.name} → {entity.is_a()} ({entity.Name})")
for wall in model.by_type("IfcWall"):
obj = tool.Ifc.get_object(wall)
if obj:
print(f"{wall.Name} → {obj.name}")
Pattern 8: Check if Object is IFC-Linked
import bpy
obj = bpy.context.active_object
ifc_id = obj.BIMProperties.ifc_definition_id
if ifc_id == 0:
print("Not linked to IFC")
else:
print(f"Linked to IFC entity #{ifc_id}")
import bonsai.tool as tool
entity = tool.Ifc.get_entity(obj)
is_ifc_linked = entity is not None
The Blender-IFC Data Bridge
Mapping Architecture
Blender Side IFC Side
─────────────────────── ────────────────────────
bpy.types.Object ifcopenshell.entity_instance
.name ←→ .Name
.BIMProperties
.ifc_definition_id ────→ .id() (step ID)
←──── IfcStore.id_map[id]
.matrix_world ←→ IfcLocalPlacement
.data (Mesh) ←→ IfcShapeRepresentation
tool.Ifc.get_entity(obj) ──→
tool.Ifc.get_object(ent) ←──
tool.Ifc.link(ent, obj) ←→ bidirectional registration
Key Properties on Blender Objects
| Property | Type | Access | Description |
|---|
obj.BIMProperties.ifc_definition_id | int | Read | IFC step ID. 0 = not linked. |
obj.name | str | Read/Write | Blender object name (may differ from IFC Name) |
obj.matrix_world | Matrix | Read/Write | World-space transform (sync to IFC via edit_object_placement) |
obj.data | bpy.types.Mesh | Read | Geometry data (regenerated from IFC representations) |
Mapping Lookup Tables
| Lookup | Data Structure | Direction | Key → Value |
|---|
IfcStore.id_map | dict | IFC → Blender | int (step ID) → bpy.types.Object |
IfcStore.guid_map | dict | IFC → Blender | str (GlobalId) → bpy.types.Object |
obj.BIMProperties.ifc_definition_id | Property | Blender → IFC | bpy.types.Object → int (step ID) |
IfcStore Element Access Methods
Quick Reference
| Method | Input | Returns | Use When |
|---|
IfcStore.get_file() | — | ifcopenshell.file | None | Getting the live IFC model |
IfcStore.get_element(ifc_id) | int | bpy.types.Object | None | Looking up Blender object by step ID |
IfcStore.id_map | — | dict[int, Object] | Iterating all linked objects |
IfcStore.guid_map | — | dict[str, Object] | Looking up by GlobalId |
tool.Ifc.get() | — | ifcopenshell.file | None | Same as get_file() (tool layer) |
tool.Ifc.get_entity(obj) | Object | entity_instance | None | Object → IFC entity |
tool.Ifc.get_object(element) | entity_instance | Object | None | IFC entity → Object |
tool.Ifc.link(element, obj) | Both | None | Register bidirectional mapping |
ifcopenshell.file Query Methods
These methods are called on the ifcopenshell.file instance returned by tool.Ifc.get() or IfcStore.get_file().
| Method | Signature | Returns | Description |
|---|
by_type(type) | (type: str, include_subtypes=True) -> list | List of entities | All entities of a given IFC class |
by_id(id) | (id: int) -> entity_instance | Single entity | Entity by step ID. Raises RuntimeError if not found. |
by_guid(guid) | (guid: str) -> entity_instance | Single entity | Entity by GlobalId. Raises RuntimeError if not found. |
ALWAYS Wrap Lookups in Try/Except When ID Source is External
model = tool.Ifc.get()
try:
entity = model.by_id(user_provided_id)
except RuntimeError:
print(f"No entity with step ID {user_provided_id}")
ifcopenshell.util.element: Relationship Navigation
| Function | Signature | Returns | Description |
|---|
get_container(element) | (element) -> entity | None | Spatial container | IfcBuildingStorey, IfcSpace, etc. |
get_type(element) | (element) -> entity | None | Type definition | IfcWallType, IfcSlabType, etc. |
get_types(type_element) | (type_element) -> list | Occurrences | All instances of a type |
get_psets(element) | (element, psets_only=False, qtos_only=False, should_inherit=True) -> dict | Property dict | All psets/qtos as nested dict |
get_material(element) | (element) -> entity | None | Material | IfcMaterial, IfcMaterialLayerSet, etc. |
get_decomposition(element) | (element) -> list | Children | All decomposed child elements |
get_aggregate(element) | (element) -> entity | None | Parent | Aggregating parent element |
Common Operations
Select All Elements of a Type in Viewport
import bpy
import bonsai.tool as tool
model = tool.Ifc.get()
if model is None:
raise RuntimeError("No IFC project loaded.")
bpy.ops.object.select_all(action='DESELECT')
for door in model.by_type("IfcDoor"):
obj = tool.Ifc.get_object(door)
if obj:
obj.select_set(True)
Get Property Value from Active Object
import bpy
import bonsai.tool as tool
import ifcopenshell.util.element
obj = bpy.context.active_object
entity = tool.Ifc.get_entity(obj)
if entity:
psets = ifcopenshell.util.element.get_psets(entity)
wall_common = psets.get("Pset_WallCommon", {})
fire_rating = wall_common.get("FireRating")
print(f"FireRating: {fire_rating}")
List All Elements in a Storey
import bonsai.tool as tool
import ifcopenshell.util.element
model = tool.Ifc.get()
storey = model.by_type("IfcBuildingStorey")[0]
elements = ifcopenshell.util.element.get_decomposition(storey)
for el in elements:
print(f" {el.is_a()}: {el.Name} (#{el.id()})")
Version Notes
Bonsai v0.8.0+ (2024 Rename)
| Change | Before (BlenderBIM) | After (Bonsai v0.8.0+) |
|---|
| Module path | blenderbim.* | bonsai.* |
| IfcStore import | from blenderbim.bim.ifc import IfcStore | from bonsai.bim.ifc import IfcStore |
| Tool import | import blenderbim.tool as tool | import bonsai.tool as tool |
| Core import | import blenderbim.core.spatial | import bonsai.core.spatial |
IfcOpenShell v0.8+ List Parameters
Since IfcOpenShell v0.8, most relationship API functions use list parameters (products, related_objects) instead of singular. This affects tool.Ifc.run() calls:
tool.Ifc.run("spatial.assign_container",
products=[wall], relating_structure=storey)
tool.Ifc.run("spatial.assign_container",
product=wall, relating_structure=storey)
Reference Links
Dependencies
- bonsai-core-architecture — Three-layer architecture, IfcStore overview, operator pattern
- ifcos-syntax-api —
ifcopenshell.api.run() invocation patterns, module table
Sources
- Bonsai source:
src/bonsai/bonsai/bim/ifc.py (IfcStore)
- Bonsai source:
src/bonsai/bonsai/tool/ifc.py (tool.Ifc implementation)
- Bonsai source:
src/bonsai/bonsai/core/tool.py (@interface definitions)
- IfcOpenShell API: https://docs.ifcopenshell.org
- Bonsai Documentation: https://docs.bonsaibim.org