# 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. ```bash # 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 ```python 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: ```python 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 ```bash uv run ifccommit.py move input.ifc output.ifc --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 ```