From c076cbc5db67bc29ef609f779f680b20f718770d Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sat, 29 Jul 2023 20:46:07 +1000 Subject: [PATCH] Fix #3502. New select similar feature. --- .../blenderbim/bim/module/search/__init__.py | 2 ++ .../blenderbim/bim/module/search/data.py | 27 +++++++++++++++++++ .../blenderbim/bim/module/search/operator.py | 18 +++++++++++++ .../blenderbim/bim/module/search/prop.py | 9 ++++++- .../blenderbim/bim/module/search/ui.py | 26 +++++++++++++++++- src/blenderbim/blenderbim/tool/drawing.py | 12 +++++---- 6 files changed, 87 insertions(+), 7 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/search/__init__.py b/src/blenderbim/blenderbim/bim/module/search/__init__.py index 01c01e0c33..7913cea72b 100644 --- a/src/blenderbim/blenderbim/bim/module/search/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/search/__init__.py @@ -46,6 +46,7 @@ classes = ( operator.SelectGlobalId, operator.SelectIfcClass, operator.SelectPset, + operator.SelectSimilar, operator.ShowAllElements, operator.ToggleFilterSelection, prop.BIMColour, @@ -61,6 +62,7 @@ classes = ( prop.IfcSelectorProperties, ui.BIM_PT_search, ui.BIM_PT_colour_by_property, + ui.BIM_PT_select_similar, ui.BIM_UL_colourscheme, ui.BIM_UL_ifc_class_filter, ui.BIM_UL_ifc_building_storey_filter, diff --git a/src/blenderbim/blenderbim/bim/module/search/data.py b/src/blenderbim/blenderbim/bim/module/search/data.py index 41345d8a16..62e2f46e78 100644 --- a/src/blenderbim/blenderbim/bim/module/search/data.py +++ b/src/blenderbim/blenderbim/bim/module/search/data.py @@ -18,12 +18,14 @@ import bpy import json +import ifcopenshell.util.element import blenderbim.tool as tool def refresh(): SearchData.is_loaded = False ColourByPropertyData.is_loaded = False + SelectSimilarData.is_loaded = False class SearchData: @@ -76,3 +78,28 @@ class ColourByPropertyData: except: pass return [(str(g.id()), g.Name or "Unnamed", "") for g in sorted(results, key=lambda x: x.Name or "Unnamed")] + + +class SelectSimilarData: + data = {} + is_loaded = False + + @classmethod + def load(cls): + cls.is_loaded = True + cls.data = {} + cls.data["element_key"] = cls.element_key() + + @classmethod + def element_key(cls): + obj = bpy.context.active_object + if not obj: + return [] + element = tool.Ifc.get_entity(obj) + if not element: + return [] + keys = [a.name() for a in element.wrapped_data.declaration().as_entity().all_attributes()] + psets = ifcopenshell.util.element.get_psets(element, psets_only=True) + for pset, properties in psets.items(): + keys.extend([f"{pset}.{name}" for name in properties.keys() if name != "id"]) + return [(k, k, "") for k in keys] diff --git a/src/blenderbim/blenderbim/bim/module/search/operator.py b/src/blenderbim/blenderbim/bim/module/search/operator.py index 5719cabfa5..4f5fc42f1b 100644 --- a/src/blenderbim/blenderbim/bim/module/search/operator.py +++ b/src/blenderbim/blenderbim/bim/module/search/operator.py @@ -993,3 +993,21 @@ class AddToIfcGroup(Operator): bpy.ops.bim.edit_group() bpy.ops.bim.disable_group_editing_ui() return {"FINISHED"} + + +class SelectSimilar(Operator, tool.Ifc.Operator): + bl_idname = "bim.select_similar" + bl_label = "Select Similar" + bl_options = {"REGISTER", "UNDO"} + + def _execute(self, context): + props = context.scene.BIMSearchProperties + obj = context.active_object + element = tool.Ifc.get_entity(obj) + value = ifcopenshell.util.selector.get_element_value(element, props.element_key) + for obj in context.visible_objects: + element = tool.Ifc.get_entity(obj) + if not element: + continue + if ifcopenshell.util.selector.get_element_value(element, props.element_key) == value: + obj.select_set(True) diff --git a/src/blenderbim/blenderbim/bim/module/search/prop.py b/src/blenderbim/blenderbim/bim/module/search/prop.py index 047132cc51..f8ce39d1b8 100644 --- a/src/blenderbim/blenderbim/bim/module/search/prop.py +++ b/src/blenderbim/blenderbim/bim/module/search/prop.py @@ -22,7 +22,7 @@ from ifcopenshell.util.selector import Selector import blenderbim.tool as tool from blenderbim.bim.prop import ObjProperty, StrProperty from blenderbim.bim.ifc import IfcStore -from blenderbim.bim.module.search.data import SearchData, ColourByPropertyData +from blenderbim.bim.module.search.data import SearchData, ColourByPropertyData, SelectSimilarData from bpy.types import PropertyGroup from blenderbim.tool.ifc import Ifc from . import ui, prop, operator @@ -38,6 +38,12 @@ from bpy.props import ( ) +def get_element_key(self, context): + if not SelectSimilarData.is_loaded: + SelectSimilarData.load() + return SelectSimilarData.data["element_key"] + + def get_saved_searches(self, context): if not SearchData.is_loaded: SearchData.load() @@ -110,6 +116,7 @@ class BIMColour(PropertyGroup): class BIMSearchProperties(PropertyGroup): + element_key: EnumProperty(items=get_element_key, name="Element Key") filter_query: StringProperty(name="Filter Query") filter_groups: CollectionProperty(type=BIMFilterGroup, name="Filter Groups") facet: EnumProperty( diff --git a/src/blenderbim/blenderbim/bim/module/search/ui.py b/src/blenderbim/blenderbim/bim/module/search/ui.py index 231e8114fd..9a18195620 100644 --- a/src/blenderbim/blenderbim/bim/module/search/ui.py +++ b/src/blenderbim/blenderbim/bim/module/search/ui.py @@ -18,7 +18,7 @@ import bpy from bpy.types import Panel -from blenderbim.bim.module.search.data import SearchData, ColourByPropertyData +from blenderbim.bim.module.search.data import SearchData, ColourByPropertyData, SelectSimilarData class BIM_PT_search(Panel): @@ -171,6 +171,30 @@ class BIM_PT_colour_by_property(Panel): self.layout.template_list("BIM_UL_colourscheme", "", props, "colourscheme", props, "active_colourscheme_index") +class BIM_PT_select_similar(Panel): + bl_label = "Select Similar" + bl_idname = "BIM_PT_select_similar" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "scene" + bl_options = {"DEFAULT_CLOSED"} + bl_parent_id = "BIM_PT_tab_grouping_and_filtering" + + def draw(self, context): + if not SelectSimilarData.is_loaded: + SelectSimilarData.load() + + props = context.scene.BIMSearchProperties + + if SelectSimilarData.data["element_key"]: + row = self.layout.row(align=True) + row.prop(props, "element_key", text="") + row.operator("bim.select_similar", text="", icon="RESTRICT_SELECT_OFF") + else: + row = self.layout.row() + row.label(text=f"No Active Element") + + class BIM_UL_colourscheme(bpy.types.UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname): props = context.scene.BIMWorkScheduleProperties diff --git a/src/blenderbim/blenderbim/tool/drawing.py b/src/blenderbim/blenderbim/tool/drawing.py index 4059dab70f..b9606797a1 100644 --- a/src/blenderbim/blenderbim/tool/drawing.py +++ b/src/blenderbim/blenderbim/tool/drawing.py @@ -888,8 +888,8 @@ class Drawing(blenderbim.core.tool.Drawing): try: shutil.move(src, dest) except: - # Perhaps the file is locked in Windows? - shutil.copy(src, dest) + # Perhaps the file is locked in Windows? + shutil.copy(src, dest) @classmethod def generate_drawing_name(cls, target_view, location_hint): @@ -1387,11 +1387,13 @@ class Drawing(blenderbim.core.tool.Drawing): root = tree.getroot() rel_location = os.path.relpath(new_location, os.path.dirname(uri)) - for g in root.findall('.//{http://www.w3.org/2000/svg}g[@data-type="drawing"][@data-id="' + str(reference.id()) + '"]'): + for g in root.findall( + './/{http://www.w3.org/2000/svg}g[@data-type="drawing"][@data-id="' + str(reference.id()) + '"]' + ): for foreground in g.findall('.//{http://www.w3.org/2000/svg}image[@data-type="foreground"]'): - foreground.attrib['{http://www.w3.org/1999/xlink}href'] = rel_location + foreground.attrib["{http://www.w3.org/1999/xlink}href"] = rel_location for background in g.findall('.//{http://www.w3.org/2000/svg}image[@data-type="background"]'): - background.attrib['{http://www.w3.org/1999/xlink}href'] = rel_location[0:-4] + "-underlay.png" + background.attrib["{http://www.w3.org/1999/xlink}href"] = rel_location[0:-4] + "-underlay.png" tree.write(uri, pretty_print=True, xml_declaration=True, encoding="utf-8") @classmethod