From a4eeae28728d71b40c36a8132cc7fb82a5b70827 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Perdig=C3=A3o?= <57102715+brunoperdigao@users.noreply.github.com> Date: Fri, 23 Feb 2024 17:56:28 -0300 Subject: [PATCH] UI for linked aggregate (#4271) * initial ui * changed the group name * groups counter in ui * added operators for selection and breaking link in the ui * small removal * changed IFC operators to _execute --- .../bim/module/aggregate/__init__.py | 3 + .../blenderbim/bim/module/aggregate/data.py | 24 +++++++ .../bim/module/aggregate/operator.py | 66 +++++++++++++++++++ .../blenderbim/bim/module/aggregate/ui.py | 47 +++++++++++++ 4 files changed, 140 insertions(+) diff --git a/src/blenderbim/blenderbim/bim/module/aggregate/__init__.py b/src/blenderbim/blenderbim/bim/module/aggregate/__init__.py index ccaafc92fc..bdb4992248 100644 --- a/src/blenderbim/blenderbim/bim/module/aggregate/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/aggregate/__init__.py @@ -28,8 +28,11 @@ classes = ( operator.BIM_OT_select_aggregate, operator.BIM_OT_select_parts, operator.BIM_OT_aggregate_unassign_object, + operator.BIM_OT_break_link_to_other_aggregates, + operator.BIM_OT_select_linked_aggregates, prop.BIMObjectAggregateProperties, ui.BIM_PT_aggregate, + ui.BIM_PT_linked_aggregate, ) diff --git a/src/blenderbim/blenderbim/bim/module/aggregate/data.py b/src/blenderbim/blenderbim/bim/module/aggregate/data.py index 66c82d9cec..eb4f8a2504 100644 --- a/src/blenderbim/blenderbim/bim/module/aggregate/data.py +++ b/src/blenderbim/blenderbim/bim/module/aggregate/data.py @@ -37,6 +37,7 @@ class AggregateData: "has_related_objects": cls.has_related_objects(), "total_parts": cls.total_parts(), "ifc_class": cls.ifc_class(), + "total_linked_aggregate": cls.total_linked_aggregate(), } cls.is_loaded = True @@ -72,3 +73,26 @@ class AggregateData: element = tool.Ifc.get_entity(bpy.context.active_object) if element: return element.is_a() + + @classmethod + def total_linked_aggregate(cls): + element = tool.Ifc.get_entity(bpy.context.active_object) + aggregate = ifcopenshell.util.element.get_aggregate(element) + if not aggregate: + return [] + if not element: + return [] + + product_linked_agg_group = [ + r + for r in getattr(aggregate, "HasAssignments", []) or [] + if r.is_a("IfcRelAssignsToGroup") + if "BBIM_Linked_Aggregate" in r.RelatingGroup.Name + ] + + if not product_linked_agg_group: + return [] + + total = len(product_linked_agg_group[0].RelatedObjects) + return total + diff --git a/src/blenderbim/blenderbim/bim/module/aggregate/operator.py b/src/blenderbim/blenderbim/bim/module/aggregate/operator.py index 4d7f0491ef..bf336ad69b 100644 --- a/src/blenderbim/blenderbim/bim/module/aggregate/operator.py +++ b/src/blenderbim/blenderbim/bim/module/aggregate/operator.py @@ -89,6 +89,12 @@ class BIM_OT_aggregate_unassign_object(bpy.types.Operator, Operator): relating_obj=tool.Ifc.get_object(aggregate), related_obj=tool.Ifc.get_object(element), ) + + # Removes Pset related to Linked Aggregates + pset = ifcopenshell.util.element.get_pset(element, 'BBIM_Linked_Aggregate') + if pset: + pset = tool.Ifc.get().by_id(pset["id"]) + ifcopenshell.api.run("pset.remove_pset", tool.Ifc.get(), pset=pset) class BIM_OT_enable_editing_aggregate(bpy.types.Operator, Operator): @@ -230,3 +236,63 @@ class BIM_OT_add_part_to_object(bpy.types.Operator, Operator): part_class=self.part_class, part_name=self.part_name, ) + +class BIM_OT_break_link_to_other_aggregates(bpy.types.Operator, Operator): + bl_idname = "bim.break_link_to_other_aggregates" + bl_label = "Break link to other aggregates" + bl_options = {"REGISTER", "UNDO"} + + def _execute(self, context): + element = tool.Ifc.get_entity(bpy.context.active_object) + aggregate = ifcopenshell.util.element.get_aggregate(element) + if not aggregate: + return [] + if not element: + return [] + + parts = ifcopenshell.util.element.get_parts(aggregate) + + for part in parts: + pset = ifcopenshell.util.element.get_pset(part, 'BBIM_Linked_Aggregate') + pset = tool.Ifc.get().by_id(pset["id"]) + ifcopenshell.api.run("pset.remove_pset", tool.Ifc.get(), pset=pset) + + linked_aggregate_group = [ + r.RelatingGroup + for r in getattr(aggregate, "HasAssignments", []) or [] + if r.is_a("IfcRelAssignsToGroup") + if "BBIM_Linked_Aggregate" in r.RelatingGroup.Name + ] + tool.Ifc.run("group.unassign_group", group=linked_aggregate_group[0], product=aggregate) + + return {"FINISHED"} + +class BIM_OT_select_linked_aggregates(bpy.types.Operator, Operator): + bl_idname = "bim.select_linked_aggregates" + bl_label = "Select linked aggregates" + bl_options = {"REGISTER", "UNDO"} + + def _execute(self, context): + element = tool.Ifc.get_entity(bpy.context.active_object) + aggregate = ifcopenshell.util.element.get_aggregate(element) + if not aggregate: + return [] + if not element: + return [] + + linked_aggregate_group = [ + r.RelatingGroup + for r in getattr(aggregate, "HasAssignments", []) or [] + if r.is_a("IfcRelAssignsToGroup") + if "BBIM_Linked_Aggregate" in r.RelatingGroup.Name + ] + + for obj in context.selected_objects: + obj.select_set(False) + + for rel in linked_aggregate_group[0].IsGroupedBy or []: + for element in rel.RelatedObjects: + obj = tool.Ifc.get_object(element) + obj.select_set(True) + + return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/aggregate/ui.py b/src/blenderbim/blenderbim/bim/module/aggregate/ui.py index 74c2db3670..dcef2a9435 100644 --- a/src/blenderbim/blenderbim/bim/module/aggregate/ui.py +++ b/src/blenderbim/blenderbim/bim/module/aggregate/ui.py @@ -18,6 +18,7 @@ from bpy.types import Panel from blenderbim.bim.module.aggregate.data import AggregateData +from blenderbim.bim.module.group.data import GroupsData, ObjectGroupsData from blenderbim.bim.ifc import IfcStore @@ -96,3 +97,49 @@ class BIM_PT_aggregate(Panel): op = layout.operator("bim.add_part_to_object", text="Add " + part_class.lstrip("Ifc")) op.part_class = part_class op.obj = context.active_object.name + + +class BIM_PT_linked_aggregate(Panel): + bl_label = "Linked Aggregates" + bl_idname = "BIM_PT_linked_aggregate" + bl_options = {"DEFAULT_CLOSED"} + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "object" + bl_order = 2 + bl_parent_id = "BIM_PT_aggregate" + + @classmethod + def poll(cls, context): + if not context.active_object: + return False + props = context.active_object.BIMObjectProperties + if not props.ifc_definition_id: + return False + if not IfcStore.get_element(props.ifc_definition_id): + return False + if not IfcStore.get_file().by_id(props.ifc_definition_id).is_a("IfcObjectDefinition"): + return False + return True + + def draw(self, context): + layout = self.layout + if not AggregateData.is_loaded: + AggregateData.load() + + props = context.active_object.BIMObjectAggregateProperties + row = layout.row(align=True) + row.label(text="Advanced Users Only", icon="ERROR") + row = layout.row(align=True) + + if type(AggregateData.data['total_linked_aggregate']) is int: + if AggregateData.data['total_linked_aggregate'] > 0: + row.label(text=f"{AggregateData.data['total_linked_aggregate']} Linked Aggregates") + row.operator("bim.select_linked_aggregates", text="", icon="RESTRICT_SELECT_OFF") + row.operator("bim.refresh_linked_aggregate", text="", icon="FILE_REFRESH") + op = row.operator("bim.break_link_to_other_aggregates", text="", icon="X") + else: + row.label(text="No Linked Aggregates") + + +