ifc-commit/docs/space_modifications.md
2026-03-25 10:36:30 +01:00

3 KiB
Raw Blame History

Space extraction and object modifications

Extracting a space

The space command extracts an IfcSpace and all elements contained within it (furniture, walls, etc.) using the ifcopenshell location filter.

# by Name (room code)
uv run ifccommit.py space input.ifc out.ifc A102

# by LongName (human label)
uv run ifccommit.py space input.ifc out.ifc "Living Room" --by longname

Internally the query is:

IfcElement, location = "A102"

The location filter follows IfcRelContainedInSpatialStructure links — it returns the IfcSpace itself plus every element directly contained in it.

Known limitation — aggregated spaces

Some IFC files place spaces via IfcRelAggregates instead of IfcRelContainedInSpatialStructure. The location filter only follows the latter, so those spaces appear empty. This is a data modelling choice in the source file, not a bug in ifcbus.

Multi-match with --by longname

When a LongName matches several spaces (e.g. "Bathroom 1" → A104 and B104), the command writes one output file per space:

dist/out_A104.ifc
dist/out_B104.ifc

The stem of the user-provided output path is reused; the space Name is appended as a suffix.


Moving objects

IFC element positions are stored in a 4×4 transformation matrix inside IfcLocalPlacement → IfcAxis2Placement3D. The last column holds the translation in the file's length unit (metres for duplex.ifc).

[[ r00  r01  r02  X ],
 [ r10  r11  r12  Y ],
 [ r20  r21  r22  Z ],
 [  0    0    0   1 ]]

Reading and writing placement

import ifcopenshell
import ifcopenshell.util.placement
import ifcopenshell.api

model = ifcopenshell.open("input.ifc")
el    = model.by_id(17902)          # entity id (not GlobalId)

matrix = ifcopenshell.util.placement.get_local_placement(el.ObjectPlacement)

# translate +2 m on world X axis ("right")
matrix[0, 3] += 2.0

ifcopenshell.api.run(
    "geometry.edit_object_placement",
    model,
    product=el,
    matrix=matrix,
)

model.write("output.ifc")

Finding an element by name

Entity ids are file-specific and unstable. Prefer searching by name:

results = [
    e for e in model.by_type("IfcFurnishingElement")
    if "168381" in (e.Name or "")
]
el = results[0]

Or use ifcopenshell.util.selector.filter_elements for richer queries.

Axis convention

"Right" is ambiguous without a viewport. In duplex.ifc the world X axis is used as the reference. Verify with the placement matrix before committing to a direction — a 180° rotated element has its local X pointing in the opposite direction to world X.

move command

uv run ifccommit.py move input.ifc output.ifc <entity_id> --x 2 --y 0 --z 0

Offsets are in the file's length unit (metres for duplex.ifc). Example:

uv run ifccommit.py move samples/duplex.ifc dist/duplex_moved_table.ifc 17902 --x 2
# Element  : #17902 M_Table-Coffee:0915 x 1830 x 0457mm:...
# Before   : X=2.6192  Y=-15.3432  Z=0.0000
# After    : X=4.6192  Y=-15.3432  Z=0.0000