From 29a4f786891570c0674706ee21f1096a6add0800 Mon Sep 17 00:00:00 2001 From: Vukas Pajic Date: Thu, 21 Jul 2022 16:10:10 +0200 Subject: [PATCH] Integrate ifcgroups with selector --- .../blenderbim/bim/module/group/__init__.py | 1 + .../blenderbim/bim/module/group/operator.py | 30 +++++++++++++++++ .../blenderbim/bim/module/group/prop.py | 3 +- .../blenderbim/bim/module/group/ui.py | 16 +++++++-- .../blenderbim/bim/module/search/operator.py | 2 +- .../bim/module/structural/operator.py | 2 +- src/blenderbim/blenderbim/core/drawing.py | 6 ++-- src/blenderbim/test/core/test_drawing.py | 4 +-- .../ifcopenshell/api/group/add_group.py | 4 ++- .../ifcopenshell/api/group/edit_group.py | 3 +- .../api/group/update_group_products.py | 33 +++++++++++++++++++ 11 files changed, 91 insertions(+), 13 deletions(-) create mode 100644 src/ifcopenshell-python/ifcopenshell/api/group/update_group_products.py diff --git a/src/blenderbim/blenderbim/bim/module/group/__init__.py b/src/blenderbim/blenderbim/bim/module/group/__init__.py index ddfc4ff48c..1b765a0a94 100644 --- a/src/blenderbim/blenderbim/bim/module/group/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/group/__init__.py @@ -31,6 +31,7 @@ classes = ( operator.EnableEditingGroup, operator.DisableEditingGroup, operator.SelectGroupProducts, + operator.UpdateGroup, prop.Group, prop.BIMGroupProperties, ui.BIM_PT_groups, diff --git a/src/blenderbim/blenderbim/bim/module/group/operator.py b/src/blenderbim/blenderbim/bim/module/group/operator.py index 3249195c55..c48ea81bcd 100644 --- a/src/blenderbim/blenderbim/bim/module/group/operator.py +++ b/src/blenderbim/blenderbim/bim/module/group/operator.py @@ -22,6 +22,7 @@ import ifcopenshell.api import blenderbim.bim.helper from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.group.data import Data +from ifcopenshell.util.selector import Selector class LoadGroups(bpy.types.Operator): @@ -36,6 +37,7 @@ class LoadGroups(bpy.types.Operator): new = props.groups.add() new.ifc_definition_id = ifc_definition_id new.name = group["Name"] + new.selection_query = group["Description"].split("*selector*")[1] if group["Description"] else "" props.is_editing = True bpy.ops.bim.disable_editing_group() return {"FINISHED"} @@ -219,3 +221,31 @@ class SelectGroupProducts(bpy.types.Operator): if self.group in product_groups: obj.select_set(True) return {"FINISHED"} + +class UpdateGroup(bpy.types.Operator): + bl_idname = "bim.update_group" + bl_label = "Update Group" + bl_options = {"REGISTER", "UNDO"} + query: bpy.props.StringProperty() + group_id: bpy.props.IntProperty() + + def execute(self, context): + return IfcStore.execute_ifc_operator(self, context) + + def _execute(self, context): + self.file = IfcStore.get_file() + group = self.file.by_id(self.group_id) + query = self.query + + new_products = Selector.parse(self.file, query) + ifcopenshell.api.run( + "group.update_group_products", + self.file, + **{ + "products": new_products, + "group": group, + } + ) + Data.load(IfcStore.get_file()) + bpy.ops.bim.load_groups() + return {"FINISHED"} \ No newline at end of file diff --git a/src/blenderbim/blenderbim/bim/module/group/prop.py b/src/blenderbim/blenderbim/bim/module/group/prop.py index 03011af513..e97f024584 100644 --- a/src/blenderbim/blenderbim/bim/module/group/prop.py +++ b/src/blenderbim/blenderbim/bim/module/group/prop.py @@ -34,7 +34,8 @@ from bpy.props import ( class Group(PropertyGroup): name: StringProperty(name="Name") ifc_definition_id: IntProperty(name="IFC Definition ID") - + selection_query: StringProperty(name="Selection Query") + class BIMGroupProperties(PropertyGroup): group_attributes: CollectionProperty(name="Group Attributes", type=Attribute) diff --git a/src/blenderbim/blenderbim/bim/module/group/ui.py b/src/blenderbim/blenderbim/bim/module/group/ui.py index ce24d514cc..2c7525132d 100644 --- a/src/blenderbim/blenderbim/bim/module/group/ui.py +++ b/src/blenderbim/blenderbim/bim/module/group/ui.py @@ -40,7 +40,7 @@ class BIM_PT_groups(Panel): self.props = context.scene.BIMGroupProperties row = self.layout.row(align=True) - row.label(text="{} Groups Found".format(len(Data.groups)), icon="OUTLINER") + row.label(text=f"{len(Data.groups)} Groups Found", icon="OUTLINER") if self.props.is_editing: row.operator("bim.add_group", text="", icon="ADD") row.operator("bim.disable_group_editing_ui", text="", icon="CANCEL") @@ -118,7 +118,7 @@ class BIM_UL_groups(UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname): if item: row = layout.row(align=True) - row.label(text=item.name) + row.label(text=f"*{item.name}") if item.selection_query != "" else row.label(text=item.name) group_id = item.ifc_definition_id if context.scene.BIMGroupProperties.active_group_id == group_id: op = row.operator("bim.select_group_products", text="", icon="RESTRICT_SELECT_OFF") @@ -130,6 +130,10 @@ class BIM_UL_groups(UIList): op.group = group_id op = row.operator("bim.remove_group", text="", icon="X") op.group = group_id + if item.selection_query != "": + op = row.operator("bim.update_group", text="", icon="FILE_REFRESH") + op.group_id = item.ifc_definition_id + op.query = item.selection_query else: op = row.operator("bim.select_group_products", text="", icon="RESTRICT_SELECT_OFF") op.group = group_id @@ -137,12 +141,18 @@ class BIM_UL_groups(UIList): op.group = group_id op = row.operator("bim.remove_group", text="", icon="X") op.group = group_id + if item.selection_query != "": + op = row.operator("bim.update_group", text="", icon="FILE_REFRESH") + op.group_id = item.ifc_definition_id + op.query = item.selection_query class BIM_UL_object_groups(UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname): if item: row = layout.row(align=True) - row.label(text=item.name) + row.label(text=f"*{item.name}") if item.selection_query != "" else row.label(text=item.name) + op = row.operator("bim.remove_group", text="", icon="X") + op.group = item.ifc_definition_id op = row.operator("bim.assign_group", text="", icon="ADD") op.group = item.ifc_definition_id diff --git a/src/blenderbim/blenderbim/bim/module/search/operator.py b/src/blenderbim/blenderbim/bim/module/search/operator.py index 8deaecd224..27504f0772 100644 --- a/src/blenderbim/blenderbim/bim/module/search/operator.py +++ b/src/blenderbim/blenderbim/bim/module/search/operator.py @@ -666,7 +666,7 @@ class AddToIfcGroup(Operator): ifc_selector = context.scene.IfcSelectorProperties selector_query_syntax = ifc_selector.selector_query_syntax - group = ifcopenshell.api.run("group.add_group", self.file, **{"Name": self.group_name}) + group = ifcopenshell.api.run("group.add_group", self.file, **{"Name": self.group_name, "Description": f'*selector*{selector_query_syntax}*selector*'}) objects = Selector.parse(self.file, selector_query_syntax) ifcopenshell.api.run("group.assign_group", self.file, **{"product": objects, "group": group}) diff --git a/src/blenderbim/blenderbim/bim/module/structural/operator.py b/src/blenderbim/blenderbim/bim/module/structural/operator.py index a2be6d51a4..bbe1a4a016 100644 --- a/src/blenderbim/blenderbim/bim/module/structural/operator.py +++ b/src/blenderbim/blenderbim/bim/module/structural/operator.py @@ -754,7 +754,7 @@ class AddStructuralActivity(bpy.types.Operator): structural_member=element, ) ifcopenshell.api.run( - "group.assign_group", self.file, product=activity, group=self.file.by_id(self.load_group) + "group.assign_group", self.file, product=[activity], group=self.file.by_id(self.load_group) ) Data.load(IfcStore.get_file()) bpy.ops.bim.enable_editing_structural_load_group_activities(load_group=self.load_group) diff --git a/src/blenderbim/blenderbim/core/drawing.py b/src/blenderbim/blenderbim/core/drawing.py index bb836e2908..ab58f5407a 100644 --- a/src/blenderbim/blenderbim/core/drawing.py +++ b/src/blenderbim/blenderbim/core/drawing.py @@ -148,7 +148,7 @@ def add_drawing(ifc, collector, drawing, target_view=None, location_hint=None): ) group = ifc.run("group.add_group") ifc.run("group.edit_group", group=group, attributes={"Name": drawing_name, "ObjectType": "DRAWING"}) - ifc.run("group.assign_group", group=group, product=element) + ifc.run("group.assign_group", group=group, product=[element]) collector.assign(camera) pset = ifc.run("pset.add_pset", product=element, name="EPset_Drawing") ifc.run( @@ -203,7 +203,7 @@ def add_annotation(ifc, collector, drawing_tool, drawing=None, object_type=None) context=context, ifc_representation_class=drawing_tool.get_ifc_representation_class(object_type), ) - ifc.run("group.assign_group", group=drawing_tool.get_drawing_group(drawing), product=element) + ifc.run("group.assign_group", group=drawing_tool.get_drawing_group(drawing), product=[element]) collector.assign(obj) drawing_tool.enable_editing(obj) @@ -251,7 +251,7 @@ def sync_references(ifc, collector, drawing_tool, drawing=None): annotation = drawing_tool.generate_reference_annotation(drawing, reference_element, context) if annotation: ifc.run("drawing.assign_product", relating_product=reference_element, related_object=annotation) - ifc.run("group.assign_group", group=group, product=annotation) + ifc.run("group.assign_group", group=group, product=[annotation]) collector.assign(ifc.get_object(annotation)) if reference_obj and ifc.is_moved(reference_obj): diff --git a/src/blenderbim/test/core/test_drawing.py b/src/blenderbim/test/core/test_drawing.py index 3746379740..d6cd58d45e 100644 --- a/src/blenderbim/test/core/test_drawing.py +++ b/src/blenderbim/test/core/test_drawing.py @@ -223,7 +223,7 @@ class TestAddDrawing: ifc.run( "group.edit_group", group="group", attributes={"Name": "name", "ObjectType": "DRAWING"} ).should_be_called() - ifc.run("group.assign_group", group="group", product="element").should_be_called() + ifc.run("group.assign_group", group="group", product=["element"]).should_be_called() collector.assign("obj").should_be_called() ifc.run("pset.add_pset", product="element", name="EPset_Drawing").should_be_called().will_return("pset") ifc.run( @@ -293,7 +293,7 @@ class TestAddAnnotation: ifc_representation_class="ifc_representation_class", ).should_be_called().will_return("element") drawing.get_drawing_group("drawing").should_be_called().will_return("group") - ifc.run("group.assign_group", group="group", product="element").should_be_called() + ifc.run("group.assign_group", group="group", product=["element"]).should_be_called() collector.assign("obj").should_be_called() drawing.enable_editing("obj").should_be_called() subject.add_annotation(ifc, collector, drawing, drawing="drawing", object_type="object_type") diff --git a/src/ifcopenshell-python/ifcopenshell/api/group/add_group.py b/src/ifcopenshell-python/ifcopenshell/api/group/add_group.py index 27a7e4972e..4014fbae97 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/group/add_group.py +++ b/src/ifcopenshell-python/ifcopenshell/api/group/add_group.py @@ -24,7 +24,8 @@ class Usecase: def __init__(self, file, **settings): self.file = file self.settings = { - "Name": "Unnamed" + "Name": "Unnamed", + "Description": "", } for key, value in settings.items(): self.settings[key] = value @@ -36,5 +37,6 @@ class Usecase: "GlobalId": ifcopenshell.guid.new(), "OwnerHistory": ifcopenshell.api.run("owner.create_owner_history", self.file), "Name": self.settings["Name"], + "Description": self.settings["Description"], } ) diff --git a/src/ifcopenshell-python/ifcopenshell/api/group/edit_group.py b/src/ifcopenshell-python/ifcopenshell/api/group/edit_group.py index a47d571ca6..2851b85029 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/group/edit_group.py +++ b/src/ifcopenshell-python/ifcopenshell/api/group/edit_group.py @@ -20,7 +20,8 @@ class Usecase: def __init__(self, file, **settings): self.file = file - self.settings = {"group": None, "attributes": {}} + self.settings = { + "group": None, "attributes": {}} for key, value in settings.items(): self.settings[key] = value diff --git a/src/ifcopenshell-python/ifcopenshell/api/group/update_group_products.py b/src/ifcopenshell-python/ifcopenshell/api/group/update_group_products.py new file mode 100644 index 0000000000..f7caac2885 --- /dev/null +++ b/src/ifcopenshell-python/ifcopenshell/api/group/update_group_products.py @@ -0,0 +1,33 @@ +# IfcOpenShell - IFC toolkit and geometry engine +# Copyright (C) 2021 Dion Moult +# +# This file is part of IfcOpenShell. +# +# IfcOpenShell is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# IfcOpenShell is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with IfcOpenShell. If not, see . + + +class Usecase: + def __init__(self, file, **settings): + self.file = file + self.settings = { + "group": None, + "products": None, + } + for key, value in settings.items(): + self.settings[key] = value + + def execute(self): + rel = self.settings["group"].IsGroupedBy[0] + rel.RelatedObjects = self.settings["products"] +