diff --git a/src/blenderbim/blenderbim/bim/module/model/__init__.py b/src/blenderbim/blenderbim/bim/module/model/__init__.py index ee5224b157..eed2604fe1 100644 --- a/src/blenderbim/blenderbim/bim/module/model/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/model/__init__.py @@ -78,6 +78,7 @@ classes = ( opening.AddPotentialHalfSpaceSolid, opening.AddPotentialOpening, opening.EditOpenings, + opening.CloneOpening, opening.FlipFill, opening.HideBooleans, opening.HideOpenings, diff --git a/src/blenderbim/blenderbim/bim/module/model/opening.py b/src/blenderbim/blenderbim/bim/module/model/opening.py index 4c1d7bcbe3..ebbc764c79 100644 --- a/src/blenderbim/blenderbim/bim/module/model/opening.py +++ b/src/blenderbim/blenderbim/bim/module/model/opening.py @@ -735,12 +735,19 @@ class EditOpenings(Operator, tool.Ifc.Operator): def _execute(self, context): props = bpy.context.scene.BIMModelProperties building_objs = set() + model = tool.Ifc.get() + all_openings = model.by_type("IfcOpeningElement") + similar_openings = [] + for obj in context.selected_objects: element = tool.Ifc.get_entity(obj) if not element: continue openings = [r.RelatedOpeningElement for r in element.HasOpenings] for opening in openings: + for all_opening in all_openings: + if all_opening.ObjectPlacement == opening.ObjectPlacement: + similar_openings.append(all_opening) opening_obj = tool.Ifc.get_object(opening) if opening_obj: if tool.Ifc.is_edited(opening_obj): @@ -749,6 +756,8 @@ class EditOpenings(Operator, tool.Ifc.Operator): blenderbim.core.geometry.edit_object_placement( tool.Ifc, tool.Geometry, tool.Surveyor, obj=opening_obj ) + for similar_opening in similar_openings: + similar_opening.ObjectPlacement = opening.ObjectPlacement building_objs.add(obj) building_objs.update(self.get_all_building_objects_of_similar_openings(opening)) tool.Ifc.unlink(element=opening, obj=opening_obj) @@ -773,6 +782,34 @@ class EditOpenings(Operator, tool.Ifc.Operator): results.add(obj) return results +class CloneOpening(Operator, tool.Ifc.Operator): + bl_idname = "bim.clone_opening" + bl_label = "Clone Opening" + bl_options = {"REGISTER", "UNDO"} + bl_description = "Create and assign to the selected element the selected opening and assign to it the same representation and object placement" + + def _execute(self, context): + objects = bpy.context.selected_objects + + for obj in objects: + entity = tool.Ifc.get_entity(obj) + if entity.is_a() == "IfcWall": + wall = entity + continue + if entity.is_a() == "IfcOpeningElement": + opening = entity + continue + + opening_placement = opening.ObjectPlacement + opening_representations = opening.Representation.Representations + + new_opening = ifcopenshell.api.run("root.create_entity", tool.Ifc.get(), ifc_class="IfcOpeningElement") + for representation in opening_representations: + ifcopenshell.api.run("geometry.assign_representation", tool.Ifc.get(), product = new_opening, representation = representation) + + ifcopenshell.api.run("void.add_opening", tool.Ifc.get(), opening = new_opening, element = wall) + new_opening.ObjectPlacement = opening_placement + return {"FINISHED"} # TODO: merge with ProfileDecorator? class DecorationsHandler: diff --git a/src/blenderbim/blenderbim/bim/module/model/workspace.py b/src/blenderbim/blenderbim/bim/module/model/workspace.py index c379419579..8d2b66ce4d 100644 --- a/src/blenderbim/blenderbim/bim/module/model/workspace.py +++ b/src/blenderbim/blenderbim/bim/module/model/workspace.py @@ -51,6 +51,7 @@ class BimTool(WorkSpaceTool): ("bim.hotkey", {"type": "K", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_K")]}), ("bim.hotkey", {"type": "M", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_M")]}), ("bim.hotkey", {"type": "O", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_O")]}), + ("bim.hotkey", {"type": "L", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_L")]}), ("bim.hotkey", {"type": "Q", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_Q")]}), ("bim.hotkey", {"type": "R", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_R")]}), ("bim.hotkey", {"type": "T", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_T")]}), @@ -393,6 +394,15 @@ class BimToolUI: else: row.operator("bim.show_openings", icon="HIDE_OFF", text="") + if AuthoringData.data["active_class"] in ( + "IfcOpeningElement", + ): + if len(context.selected_objects) == 2: + row = cls.layout.row(align=True) + row.label(text="", icon="EVENT_SHIFT") + row.label(text="", icon="EVENT_L") + row.operator("bim.clone_opening", text="Clone Opening") + cls.layout.row(align=True).label(text="Align") add_layout_hotkey_operator(cls.layout, "Align Exterior", "S_X", "") add_layout_hotkey_operator(cls.layout, "Align Centerline", "S_C", "") @@ -726,6 +736,13 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator): self.props.y = self.y self.props.z = self.z + def hotkey_S_L(self): + if AuthoringData.data["active_class"] in ( + "IfcOpeningElement", + ): + if len(bpy.context.selected_objects) == 2: + bpy.ops.bim.clone_opening() + def hotkey_A_D(self): if not bpy.context.selected_objects: return