From d6da8a7ee110862bbc815272ec5e2d9833c4b8ef Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Wed, 15 Jan 2025 15:58:13 +0500 Subject: [PATCH] Support duplicating potential openings and potential/existing booleans --- src/bonsai/bonsai/bim/module/geometry/operator.py | 14 +++++++++++--- src/bonsai/bonsai/bim/module/model/opening.py | 8 ++++---- src/bonsai/bonsai/core/root.py | 2 -- src/bonsai/bonsai/tool/model.py | 8 ++++++++ src/bonsai/bonsai/tool/root.py | 5 +++-- src/bonsai/test/tool/test_root.py | 3 ++- 6 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/geometry/operator.py b/src/bonsai/bonsai/bim/module/geometry/operator.py index 02664b0193..5a492715b0 100644 --- a/src/bonsai/bonsai/bim/module/geometry/operator.py +++ b/src/bonsai/bonsai/bim/module/geometry/operator.py @@ -983,7 +983,9 @@ class OverrideDuplicateMove(bpy.types.Operator): OverrideDuplicateMove.duplicate_item(self, obj) continue - linked_non_ifc_object = linked and not element + tracked_opening_type = tool.Model.get_tracked_opening_type(obj) + is_tracked_opening = bool(tracked_opening_type) + keep_data_linked = linked and not element and not is_tracked_opening # Prior to duplicating, sync the object placement to make decomposition recreation more stable. if tool.Ifc.is_moved(obj): @@ -1000,11 +1002,17 @@ class OverrideDuplicateMove(bpy.types.Operator): if tool.Ifc.is_edited(obj, ignore_scale=True): tool.Ifc.edit(new_obj) - if obj.data and not linked_non_ifc_object: + if obj.data and not keep_data_linked: # assure root.copy_class won't replace the previous mesh globally temp_data = obj.data.copy() new_obj.data = temp_data + # Unlink from previous boolean element + # and keep object tracked for decorations. + if is_tracked_opening: + new_obj.data.BIMMeshProperties.ifc_boolean_id = 0 + tool.Root.add_tracked_opening(new_obj, tracked_opening_type) + if obj == context.active_object: self.new_active_obj = new_obj for collection in obj.users_collection: @@ -1012,7 +1020,7 @@ class OverrideDuplicateMove(bpy.types.Operator): obj.select_set(False) new_obj.select_set(True) - if linked_non_ifc_object: + if not element: continue # clear object's collection so it will be able to have it's own diff --git a/src/bonsai/bonsai/bim/module/model/opening.py b/src/bonsai/bonsai/bim/module/model/opening.py index ff98561a39..7df9dcc7fd 100644 --- a/src/bonsai/bonsai/bim/module/model/opening.py +++ b/src/bonsai/bonsai/bim/module/model/opening.py @@ -489,7 +489,7 @@ class AddPotentialOpening(Operator, AddObjectHelper): obj.matrix_world = new_matrix tool.Model.purge_scene_openings() - tool.Root.add_tracked_opening(obj) + tool.Root.add_tracked_opening(obj, "OPENING") DecorationsHandler.install(context) return {"FINISHED"} @@ -513,7 +513,7 @@ class AddPotentialHalfSpaceSolid(Operator, AddObjectHelper): obj.name = "HalfSpaceSolid" tool.Model.purge_scene_openings() - tool.Root.add_tracked_opening(obj) + tool.Root.add_tracked_opening(obj, "BOOLEAN") DecorationsHandler.install(context) return {"FINISHED"} @@ -663,7 +663,7 @@ class ShowBooleans(Operator, tool.Ifc.Operator, AddObjectHelper): objects_to_remove.add(existing_booleans[boolean_id]) boolean_obj.data.BIMMeshProperties.ifc_boolean_id = boolean_id boolean_obj.data.BIMMeshProperties.obj = obj - tool.Root.add_tracked_opening(boolean_obj) + tool.Root.add_tracked_opening(boolean_obj, "BOOLEAN") booleans_objs.append(boolean_obj) tool.Blender.remove_data_blocks(objects_to_remove, remove_unused_data=True) @@ -849,7 +849,7 @@ class ShowOpenings(Operator, tool.Ifc.Operator): self.on_new_opening_obj(opening) def on_new_opening_obj(self, opening_obj: bpy.types.Object) -> None: - tool.Root.add_tracked_opening(opening_obj) + tool.Root.add_tracked_opening(opening_obj, "OPENING") opening_obj.display_type = "WIRE" diff --git a/src/bonsai/bonsai/core/root.py b/src/bonsai/bonsai/core/root.py index 7e0b9381ba..c668c9c37d 100644 --- a/src/bonsai/bonsai/core/root.py +++ b/src/bonsai/bonsai/core/root.py @@ -51,8 +51,6 @@ def copy_class( geometry.rename_object(data, geometry.get_representation_name(ifc.get_entity(data))) root.assign_body_styles(new, obj) collector.assign(obj) - if root.is_element_a(new, "IfcOpeningElement"): - root.add_tracked_opening(obj) return new diff --git a/src/bonsai/bonsai/tool/model.py b/src/bonsai/bonsai/tool/model.py index da720b755e..4573f72e0e 100644 --- a/src/bonsai/bonsai/tool/model.py +++ b/src/bonsai/bonsai/tool/model.py @@ -2014,6 +2014,14 @@ class Model(bonsai.core.tool.Model): def get_booleaned_obj(cls, boolean_obj: bpy.types.Object) -> bpy.types.Object: return boolean_obj.data.BIMMeshProperties.obj + @classmethod + def get_tracked_opening_type(cls, obj: bpy.types.Object) -> Union[Literal["OPENING", "BOOLEAN"], None]: + """Get tracked opening type, return `None` if object is not a tracked opening.""" + for opening in bpy.context.scene.BIMModelProperties.openings: + if opening.obj == obj: + return opening.name + return None + @classmethod def bm_sort_out_geom( cls, geom_data: list[Union[bmesh.types.BMVert, bmesh.types.BMEdge, bmesh.types.BMFace]] diff --git a/src/bonsai/bonsai/tool/root.py b/src/bonsai/bonsai/tool/root.py index 28d1f00e59..fad01245dd 100644 --- a/src/bonsai/bonsai/tool/root.py +++ b/src/bonsai/bonsai/tool/root.py @@ -26,17 +26,18 @@ import bonsai.core.tool import bonsai.core.aggregate import bonsai.core.geometry import bonsai.tool as tool -from typing import Union, Optional, Any +from typing import Union, Optional, Any, Literal from bonsai.bim.module.spatial.decorator import GridDecorator from bonsai.bim.module.geometry.decorator import ItemDecorator class Root(bonsai.core.tool.Root): @classmethod - def add_tracked_opening(cls, obj: bpy.types.Object) -> None: + def add_tracked_opening(cls, obj: bpy.types.Object, opening_type: Literal["OPENING", "BOOLEAN"]) -> None: """Add tracked opening or boolean object.""" new = bpy.context.scene.BIMModelProperties.openings.add() new.obj = obj + new.name = opening_type @classmethod def assign_body_styles(cls, element: ifcopenshell.entity_instance, obj: bpy.types.Object) -> None: diff --git a/src/bonsai/test/tool/test_root.py b/src/bonsai/test/tool/test_root.py index dda03e1ed3..79b773d256 100644 --- a/src/bonsai/test/tool/test_root.py +++ b/src/bonsai/test/tool/test_root.py @@ -33,9 +33,10 @@ class TestImplementsTool(NewFile): class TestAddTrackedOpening(NewFile): def test_run(self): obj = bpy.data.objects.new("Object", None) - subject.add_tracked_opening(obj) + subject.add_tracked_opening(obj, "OPENING") props = bpy.context.scene.BIMModelProperties assert props.openings[0].obj == obj + assert props.openings[0].name == "OPENING" class TestCopyRepresentation(NewFile):