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

119 lines
3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 <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
```