mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-27 02:31:09 +00:00
Prevent cyclic references when assigning nesting or aggregation
Walk up the full hierarchy via get_parent() in can_nest() and can_aggregate() to reject assignments that would create a cycle. Also reject self-assignment. Fix #7248 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api.aggregate
|
||||
import ifcopenshell.api.context
|
||||
import ifcopenshell.api.geometry
|
||||
import ifcopenshell.api.root
|
||||
@@ -99,6 +100,42 @@ class TestCanAggregate(NewFile):
|
||||
subelement_obj = bpy.data.objects.new("Object", None)
|
||||
assert subject.can_aggregate(element_obj, subelement_obj) is False
|
||||
|
||||
def test_element_cannot_aggregate_to_itself(self):
|
||||
ifc = ifcopenshell.file()
|
||||
tool.Ifc.set(ifc)
|
||||
element = ifc.createIfcElementAssembly()
|
||||
element_obj = bpy.data.objects.new("Object", None)
|
||||
tool.Ifc.link(element, element_obj)
|
||||
assert subject.can_aggregate(element_obj, element_obj) is False
|
||||
|
||||
def test_cyclic_aggregation_is_prevented(self):
|
||||
ifc = ifcopenshell.file()
|
||||
tool.Ifc.set(ifc)
|
||||
assembly_a = ifc.createIfcElementAssembly()
|
||||
assembly_a_obj = bpy.data.objects.new("AssemblyA", None)
|
||||
tool.Ifc.link(assembly_a, assembly_a_obj)
|
||||
beam = ifc.createIfcBeam()
|
||||
beam_obj = bpy.data.objects.new("Beam", None)
|
||||
tool.Ifc.link(beam, beam_obj)
|
||||
ifcopenshell.api.aggregate.assign_object(ifc, products=[beam], relating_object=assembly_a)
|
||||
assert subject.can_aggregate(beam_obj, assembly_a_obj) is False
|
||||
|
||||
def test_deep_cyclic_aggregation_is_prevented(self):
|
||||
ifc = ifcopenshell.file()
|
||||
tool.Ifc.set(ifc)
|
||||
assembly_a = ifc.createIfcElementAssembly()
|
||||
assembly_a_obj = bpy.data.objects.new("AssemblyA", None)
|
||||
tool.Ifc.link(assembly_a, assembly_a_obj)
|
||||
assembly_b = ifc.createIfcElementAssembly()
|
||||
assembly_b_obj = bpy.data.objects.new("AssemblyB", None)
|
||||
tool.Ifc.link(assembly_b, assembly_b_obj)
|
||||
beam = ifc.createIfcBeam()
|
||||
beam_obj = bpy.data.objects.new("Beam", None)
|
||||
tool.Ifc.link(beam, beam_obj)
|
||||
ifcopenshell.api.aggregate.assign_object(ifc, products=[assembly_b], relating_object=assembly_a)
|
||||
ifcopenshell.api.aggregate.assign_object(ifc, products=[beam], relating_object=assembly_b)
|
||||
assert subject.can_aggregate(beam_obj, assembly_a_obj) is False
|
||||
|
||||
|
||||
class TestHasPhysicalBodyRepresentation(NewFile):
|
||||
def test_run(self):
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.api.nest
|
||||
import ifcopenshell.api.spatial
|
||||
|
||||
import bonsai.core.tool
|
||||
@@ -51,6 +52,42 @@ class TestCanNest(NewFile):
|
||||
subelement_obj = bpy.data.objects.new("Object", None)
|
||||
assert subject.can_nest(element_obj, subelement_obj) is False
|
||||
|
||||
def test_element_cannot_nest_to_itself(self):
|
||||
ifc = ifcopenshell.file()
|
||||
tool.Ifc.set(ifc)
|
||||
element = ifc.createIfcWall()
|
||||
element_obj = bpy.data.objects.new("Object", None)
|
||||
tool.Ifc.link(element, element_obj)
|
||||
assert subject.can_nest(element_obj, element_obj) is False
|
||||
|
||||
def test_cyclic_nesting_is_prevented(self):
|
||||
ifc = ifcopenshell.file()
|
||||
tool.Ifc.set(ifc)
|
||||
wall_a = ifc.createIfcWall()
|
||||
wall_a_obj = bpy.data.objects.new("WallA", None)
|
||||
tool.Ifc.link(wall_a, wall_a_obj)
|
||||
wall_b = ifc.createIfcWall()
|
||||
wall_b_obj = bpy.data.objects.new("WallB", None)
|
||||
tool.Ifc.link(wall_b, wall_b_obj)
|
||||
ifcopenshell.api.nest.assign_object(ifc, related_objects=[wall_b], relating_object=wall_a)
|
||||
assert subject.can_nest(wall_b_obj, wall_a_obj) is False
|
||||
|
||||
def test_deep_cyclic_nesting_is_prevented(self):
|
||||
ifc = ifcopenshell.file()
|
||||
tool.Ifc.set(ifc)
|
||||
wall_a = ifc.createIfcWall()
|
||||
wall_a_obj = bpy.data.objects.new("WallA", None)
|
||||
tool.Ifc.link(wall_a, wall_a_obj)
|
||||
wall_b = ifc.createIfcWall()
|
||||
wall_b_obj = bpy.data.objects.new("WallB", None)
|
||||
tool.Ifc.link(wall_b, wall_b_obj)
|
||||
wall_c = ifc.createIfcWall()
|
||||
wall_c_obj = bpy.data.objects.new("WallC", None)
|
||||
tool.Ifc.link(wall_c, wall_c_obj)
|
||||
ifcopenshell.api.nest.assign_object(ifc, related_objects=[wall_b], relating_object=wall_a)
|
||||
ifcopenshell.api.nest.assign_object(ifc, related_objects=[wall_c], relating_object=wall_b)
|
||||
assert subject.can_nest(wall_c_obj, wall_a_obj) is False
|
||||
|
||||
|
||||
class TestDisableEditing(NewFile):
|
||||
def test_run(self):
|
||||
|
||||
Reference in New Issue
Block a user