diff --git a/src/blenderbim/blenderbim/bim/module/aggregate/data.py b/src/blenderbim/blenderbim/bim/module/aggregate/data.py index ee717cccec..b4e466355c 100644 --- a/src/blenderbim/blenderbim/bim/module/aggregate/data.py +++ b/src/blenderbim/blenderbim/bim/module/aggregate/data.py @@ -34,7 +34,6 @@ class AggregateData: cls.data = { "has_relating_object": cls.has_relating_object(), "relating_object_label": cls.get_relating_object_label(), - "relating_object_id": cls.get_relating_object_id(), "has_related_objects": cls.has_related_objects(), "related_objects_amount": cls.get_related_objects_amount(), "ifc_class": cls.ifc_class(), @@ -55,12 +54,6 @@ class AggregateData: if aggregate: return f"{aggregate.is_a()}/{aggregate.Name or ''}" - @classmethod - def get_relating_object_id(cls) -> int: - aggregate = cls.get_relating_object() - if aggregate: - return aggregate.id() - @classmethod def get_related_objects(cls): return ifcopenshell.util.element.get_parts(tool.Ifc.get_entity(bpy.context.active_object)) diff --git a/src/blenderbim/blenderbim/bim/module/aggregate/operator.py b/src/blenderbim/blenderbim/bim/module/aggregate/operator.py index b89b5d2baf..dd3d767377 100644 --- a/src/blenderbim/blenderbim/bim/module/aggregate/operator.py +++ b/src/blenderbim/blenderbim/bim/module/aggregate/operator.py @@ -58,16 +58,22 @@ class BIM_OT_unassign_object(bpy.types.Operator, Operator): bl_idname = "bim.unassign_object" bl_label = "Unassign Object" bl_options = {"REGISTER", "UNDO"} - relating_object: bpy.props.IntProperty() - related_object: bpy.props.IntProperty() def _execute(self, context): - core.unassign_object( - tool.Ifc, - tool.Collector, - relating_obj=tool.Ifc.get_object(tool.Ifc.get().by_id(self.relating_object)), - related_obj=tool.Ifc.get_object(tool.Ifc.get().by_id(self.related_object)), - ) + for obj in bpy.context.selected_objects: + element = tool.Ifc.get_entity(obj) + if not element: + continue + aggregate = ifcopenshell.util.element.get_aggregate(element) + if not aggregate: + continue + core.unassign_object( + tool.Ifc, + tool.Aggregate, + tool.Collector, + relating_obj=tool.Ifc.get_object(aggregate), + related_obj=tool.Ifc.get_object(element), + ) class BIM_OT_enable_editing_aggregate(bpy.types.Operator, Operator): diff --git a/src/blenderbim/blenderbim/bim/module/aggregate/ui.py b/src/blenderbim/blenderbim/bim/module/aggregate/ui.py index 9f9ff240e5..d593599604 100644 --- a/src/blenderbim/blenderbim/bim/module/aggregate/ui.py +++ b/src/blenderbim/blenderbim/bim/module/aggregate/ui.py @@ -67,8 +67,6 @@ class BIM_PT_aggregate(Panel): row.operator("bim.enable_editing_aggregate", icon="GREASEPENCIL", text="") row.operator("bim.add_aggregate", icon="ADD", text="") op = row.operator("bim.unassign_object", icon="X", text="") - op.relating_object = AggregateData.data["relating_object_id"] - op.related_object = context.active_object.BIMObjectProperties.ifc_definition_id else: row.label(text="No Aggregate", icon="TRIA_UP") row.operator("bim.enable_editing_aggregate", icon="GREASEPENCIL", text="") diff --git a/src/blenderbim/blenderbim/bim/module/model/opening.py b/src/blenderbim/blenderbim/bim/module/model/opening.py index af68690bf4..134dc75720 100644 --- a/src/blenderbim/blenderbim/bim/module/model/opening.py +++ b/src/blenderbim/blenderbim/bim/module/model/opening.py @@ -53,7 +53,7 @@ class AddFilledOpening(bpy.types.Operator, tool.Ifc.Operator): class FilledOpeningGenerator: - def generate(self, filling_obj, voided_obj): + def generate(self, filling_obj, voided_obj, target=None): props = bpy.context.scene.BIMModelProperties unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) @@ -62,8 +62,14 @@ class FilledOpeningGenerator: if not voided_obj or not filling_obj: return + if filling.FillsVoids: + ifcopenshell.api.run( + "void.remove_opening", tool.Ifc.get(), opening=filling.FillsVoids[0].RelatingOpeningElement + ) + + if target is None: + target = bpy.context.scene.cursor.location element = tool.Ifc.get_entity(voided_obj) - target = bpy.context.scene.cursor.location raycast = voided_obj.closest_point_on_mesh(voided_obj.matrix_world.inverted() @ target, distance=0.01) if not raycast[0]: target = filling_obj.matrix_world.col[3].to_3d().copy() diff --git a/src/blenderbim/blenderbim/core/aggregate.py b/src/blenderbim/blenderbim/core/aggregate.py index 02366e54e2..b9e6f8ff7e 100644 --- a/src/blenderbim/blenderbim/core/aggregate.py +++ b/src/blenderbim/blenderbim/core/aggregate.py @@ -37,11 +37,14 @@ def assign_object(ifc, aggregator, collector, relating_obj=None, related_obj=Non return rel -def unassign_object(ifc, collector, relating_obj=None, related_obj=None): - rel = ifc.run("aggregate.unassign_object", product=ifc.get_entity(related_obj)) +def unassign_object(ifc, aggregate, collector, relating_obj=None, related_obj=None): + related_element = ifc.get_entity(related_obj) + container = aggregate.get_container(related_element) + ifc.run("aggregate.unassign_object", product=related_element) + if container: + ifc.run("spatial.assign_container", product=related_element, relating_structure=container) collector.assign(relating_obj) collector.assign(related_obj) - return rel def add_part_to_object(ifc, aggregator, collector, blender, obj, part_class, part_name=None): diff --git a/src/blenderbim/blenderbim/core/tool.py b/src/blenderbim/blenderbim/core/tool.py index 9b386a59f4..39c3d6e123 100644 --- a/src/blenderbim/blenderbim/core/tool.py +++ b/src/blenderbim/blenderbim/core/tool.py @@ -67,6 +67,7 @@ class Aggregate: def can_aggregate(cls, relating_object, related_object): pass def disable_editing(cls, obj): pass def enable_editing(cls, obj): pass + def get_container(cls, element): pass @interface diff --git a/src/blenderbim/blenderbim/tool/aggregate.py b/src/blenderbim/blenderbim/tool/aggregate.py index b1d45f4d69..2da8d0b484 100644 --- a/src/blenderbim/blenderbim/tool/aggregate.py +++ b/src/blenderbim/blenderbim/tool/aggregate.py @@ -18,17 +18,10 @@ import blenderbim.core.tool import blenderbim.tool as tool +import ifcopenshell.util.element class Aggregate(blenderbim.core.tool.Aggregate): - @classmethod - def enable_editing(cls, obj): - obj.BIMObjectAggregateProperties.is_editing = True - - @classmethod - def disable_editing(cls, obj): - obj.BIMObjectAggregateProperties.is_editing = False - @classmethod def can_aggregate(cls, relating_obj, related_obj): relating_object = tool.Ifc.get_entity(relating_obj) @@ -50,3 +43,15 @@ class Aggregate(blenderbim.core.tool.Aggregate): if relating_object.is_a("IfcProject") and related_object.is_a("IfcSpatialElement"): return True return False + + @classmethod + def disable_editing(cls, obj): + obj.BIMObjectAggregateProperties.is_editing = False + + @classmethod + def enable_editing(cls, obj): + obj.BIMObjectAggregateProperties.is_editing = True + + @classmethod + def get_container(cls, element): + return ifcopenshell.util.element.get_container(element) diff --git a/src/blenderbim/test/bim/feature/aggregate.feature b/src/blenderbim/test/bim/feature/aggregate.feature index acb7197252..0403f91384 100644 --- a/src/blenderbim/test/bim/feature/aggregate.feature +++ b/src/blenderbim/test/bim/feature/aggregate.feature @@ -34,7 +34,7 @@ Scenario: Unassign object And the variable "related_object" is "tool.Ifc.get().by_type('IfcBuildingStorey')[0].id()" And I press "bim.assign_object(relating_object={relating_object}, related_object={related_object})" And the object "IfcBuildingStorey/My Storey" is selected - When I press "bim.unassign_object(relating_object={relating_object}, related_object={related_object})" + When I press "bim.unassign_object" Then the object "IfcSite/My Site" is in the collection "IfcSite/My Site" And the object "IfcBuildingStorey/My Storey" is in the collection "IfcBuildingStorey/My Storey" And the collection "IfcBuildingStorey/My Storey" is in the collection "IfcProject/My Project" diff --git a/src/blenderbim/test/core/test_aggregate.py b/src/blenderbim/test/core/test_aggregate.py index cbec08656e..ca8cadcbdc 100644 --- a/src/blenderbim/test/core/test_aggregate.py +++ b/src/blenderbim/test/core/test_aggregate.py @@ -50,9 +50,11 @@ class TestAssignObject: class TestUnassignObject: - def test_run(self, ifc, collector): - ifc.get_entity("related_obj").should_be_called().will_return("related_object") - ifc.run("aggregate.unassign_object", product="related_object").should_be_called().will_return("rel") + def test_run(self, ifc, aggregate, collector): + ifc.get_entity("related_obj").should_be_called().will_return("element") + aggregate.get_container("element").should_be_called().will_return("container") + ifc.run("spatial.assign_container", product="element", relating_structure="container").should_be_called() + ifc.run("aggregate.unassign_object", product="element").should_be_called().will_return("rel") collector.assign("relating_obj").should_be_called() collector.assign("related_obj").should_be_called() - assert subject.unassign_object(ifc, collector, relating_obj="relating_obj", related_obj="related_obj") == "rel" + subject.unassign_object(ifc, aggregate, collector, relating_obj="relating_obj", related_obj="related_obj") diff --git a/src/blenderbim/test/tool/test_aggregate.py b/src/blenderbim/test/tool/test_aggregate.py index 5af016a34f..cb01270711 100644 --- a/src/blenderbim/test/tool/test_aggregate.py +++ b/src/blenderbim/test/tool/test_aggregate.py @@ -29,19 +29,8 @@ class TestImplementsTool(NewFile): assert isinstance(subject(), blenderbim.core.tool.Aggregate) -class TestEnableEditing(NewFile): - def test_run(self): - obj = bpy.data.objects.new("Object", None) - subject.enable_editing(obj) - assert obj.BIMObjectAggregateProperties.is_editing is True -class TestDisableEditing(NewFile): - def test_run(self): - obj = bpy.data.objects.new("Object", None) - subject.enable_editing(obj) - subject.disable_editing(obj) - assert obj.BIMObjectAggregateProperties.is_editing is False class TestCanAggregate(NewFile): @@ -117,3 +106,27 @@ class TestCanAggregate(NewFile): subelement_obj = bpy.data.objects.new("Object", None) tool.Ifc.link(subelement, subelement_obj) assert subject.can_aggregate(element_obj, subelement_obj) is False + +class TestDisableEditing(NewFile): + def test_run(self): + obj = bpy.data.objects.new("Object", None) + subject.enable_editing(obj) + subject.disable_editing(obj) + assert obj.BIMObjectAggregateProperties.is_editing is False + + +class TestEnableEditing(NewFile): + def test_run(self): + obj = bpy.data.objects.new("Object", None) + subject.enable_editing(obj) + assert obj.BIMObjectAggregateProperties.is_editing is True + + +class TestGetContainer(NewFile): + def test_run(self): + ifc = ifcopenshell.file() + tool.Ifc.set(ifc) + element = ifc.createIfcWall() + container = ifc.createIfcBuildingStorey() + ifcopenshell.api.run("spatial.assign_container", ifc, product=element, relating_structure=container) + assert subject.get_container(element) == container