Skip to content

Commit 75b8d4f

Browse files
Moultclaude
andcommitted
Remove spatial containment and aggregation when nesting
The nest assign_object API now removes existing spatial containment and aggregate relationships before creating the nest, matching the behavior documented in its docstring and consistent with aggregate.assign_object. Fix #7248 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent b8136d4 commit 75b8d4f

2 files changed

Lines changed: 26 additions & 1 deletion

File tree

src/ifcopenshell-python/ifcopenshell/api/nest/assign_object.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
from typing import Union
2020

2121
import ifcopenshell
22+
import ifcopenshell.api.aggregate
2223
import ifcopenshell.api.owner
24+
import ifcopenshell.api.spatial
2325
import ifcopenshell.guid
2426
import ifcopenshell.util.element
2527

@@ -137,7 +139,10 @@ def assign_object(
137139
if not objects_to_change:
138140
return is_nested_by
139141

140-
# NOTE: An object can both be nested and assigned to a container or an aggregate.
142+
# Can be either only nested, aggregated, or contained at the same time.
143+
possibly_contained = [o for o in objects_without_nests if hasattr(o, "ContainedInStructure")]
144+
ifcopenshell.api.spatial.unassign_container(file, products=possibly_contained)
145+
ifcopenshell.api.aggregate.unassign_object(file, products=objects_without_nests)
141146

142147
# unassign elements from previous nests
143148
for nests in previous_nests_rels:

src/ifcopenshell-python/test/api/nest/test_assign_object.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@
1818

1919
import pytest
2020

21+
import ifcopenshell.api.aggregate
2122
import ifcopenshell.api.nest
2223
import ifcopenshell.api.root
24+
import ifcopenshell.api.spatial
2325
import ifcopenshell.util.element
2426
import test.bootstrap
2527

@@ -82,6 +84,24 @@ def test_maintain_assignment_order_in_related_objects(self):
8284
ifcopenshell.api.nest.assign_object(self.file, related_objects=subelements[2:3], relating_object=element2)
8385
assert rel.RelatedObjects == tuple(subelements[:2] + subelements[3:])
8486

87+
def test_nesting_removes_spatial_containment(self):
88+
element = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWall")
89+
subelement = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWall")
90+
storey = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcBuildingStorey")
91+
ifcopenshell.api.spatial.assign_container(self.file, products=[subelement], relating_structure=storey)
92+
assert ifcopenshell.util.element.get_container(subelement) == storey
93+
ifcopenshell.api.nest.assign_object(self.file, related_objects=[subelement], relating_object=element)
94+
assert ifcopenshell.util.element.get_container(subelement) is None
95+
96+
def test_nesting_removes_aggregate(self):
97+
element = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWall")
98+
subelement = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWall")
99+
assembly = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcElementAssembly")
100+
ifcopenshell.api.aggregate.assign_object(self.file, products=[subelement], relating_object=assembly)
101+
assert ifcopenshell.util.element.get_aggregate(subelement) == assembly
102+
ifcopenshell.api.nest.assign_object(self.file, related_objects=[subelement], relating_object=element)
103+
assert ifcopenshell.util.element.get_aggregate(subelement) is None
104+
85105

86106
class TestAssignObjectIFC2X3(test.bootstrap.IFC2X3, TestAssignObject):
87107
pass

0 commit comments

Comments
 (0)