Add tool for 'group' module

This commit is contained in:
Andrej730
2025-09-15 10:13:59 +05:00
parent 629d6c85ae
commit 646f2f2e32
7 changed files with 116 additions and 65 deletions
+14 -52
View File
@@ -23,7 +23,6 @@ import ifcopenshell.util.element
import bonsai.bim.helper
import bonsai.tool as tool
import json
from natsort import natsorted
class LoadGroups(bpy.types.Operator, tool.Ifc.Operator):
@@ -31,48 +30,12 @@ class LoadGroups(bpy.types.Operator, tool.Ifc.Operator):
bl_label = "Load Groups"
bl_options = {"REGISTER", "UNDO"}
expanded_groups: list[int]
def _execute(self, context):
self.props = tool.Blender.get_group_props()
self.expanded_groups = json.loads(self.props.expanded_groups_json)
self.props.groups.clear()
groups = [
group for group in tool.Ifc.get().by_type("IfcGroup", include_subtypes=False) if not group.HasAssignments
]
sorted_groups = natsorted(groups, key=lambda group: group.Name or "Unnamed")
for group in sorted_groups:
self.load_group(group)
self.props.is_editing = True
bpy.ops.bim.disable_editing_group()
tool.Group.import_groups()
tool.Group.enable_group_editing_ui()
tool.Group.disable_editing_group()
return {"FINISHED"}
def load_group(self, group: ifcopenshell.entity_instance, tree_depth: int = 0) -> None:
new = self.props.groups.add()
new.ifc_definition_id = group.id()
new["name"] = group.Name or "Unnamed"
new.tree_depth = tree_depth
new.has_children = False
new.is_expanded = group.id() in self.expanded_groups
related_groups: list[ifcopenshell.entity_instance]
related_groups = [
related_object
for rel in group.IsGroupedBy or []
for related_object in rel.RelatedObjects
if related_object.is_a("IfcGroup")
]
sorted_related_groups = natsorted(related_groups, key=lambda group: group.Name or "Unnamed")
if sorted_related_groups:
new.has_children = True
if new.is_expanded:
for related_group in sorted_related_groups:
self.load_group(related_group, tree_depth=tree_depth + 1)
class ToggleGroup(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.toggle_group"
@@ -83,7 +46,7 @@ class ToggleGroup(bpy.types.Operator, tool.Ifc.Operator):
option: bpy.props.StringProperty(name="Expand or Collapse")
def _execute(self, context):
props = tool.Blender.get_group_props()
props = tool.Group.get_group_props()
expanded_groups: set[int]
expanded_groups = set(json.loads(props.expanded_groups_json))
if self.option == "Expand":
@@ -101,9 +64,8 @@ class DisableGroupEditingUI(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
props = tool.Blender.get_group_props()
props.is_editing = False
props.active_group_id = 0
tool.Group.disable_group_editing_ui()
tool.Group.disable_editing_group()
return {"FINISHED"}
@@ -125,7 +87,7 @@ class AddGroup(bpy.types.Operator, tool.Ifc.Operator):
ifcopenshell.api.group.assign_group(
tool.Ifc.get(), products=[result], group=tool.Ifc.get().by_id(self.group)
)
bpy.ops.bim.load_groups()
tool.Group.import_groups("IfcGroup")
return {"FINISHED"}
@@ -135,11 +97,11 @@ class EditGroup(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
props = tool.Blender.get_group_props()
props = tool.Group.get_group_props()
attributes = bonsai.bim.helper.export_attributes(props.group_attributes)
ifc_file = tool.Ifc.get()
ifcopenshell.api.group.edit_group(ifc_file, group=ifc_file.by_id(props.active_group_id), attributes=attributes)
bpy.ops.bim.load_groups()
tool.Group.import_groups("IfcGroup")
return {"FINISHED"}
@@ -152,7 +114,7 @@ class RemoveGroup(bpy.types.Operator, tool.Ifc.Operator):
def _execute(self, context):
self.file = tool.Ifc.get()
ifcopenshell.api.group.remove_group(self.file, group=self.file.by_id(self.group))
bpy.ops.bim.load_groups()
tool.Group.import_groups("IfcGroup")
return {"FINISHED"}
@@ -163,10 +125,11 @@ class EnableEditingGroup(bpy.types.Operator, tool.Ifc.Operator):
group: bpy.props.IntProperty()
def _execute(self, context):
props = tool.Blender.get_group_props()
props = tool.Group.get_group_props()
props.group_attributes.clear()
bonsai.bim.helper.import_attributes(tool.Ifc.get().by_id(self.group), props.group_attributes)
props.active_group_id = self.group
ifc_file = tool.Ifc.get()
tool.Group.set_active_group_to_edit(ifc_file.by_id(self.group))
return {"FINISHED"}
@@ -176,8 +139,7 @@ class DisableEditingGroup(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
props = tool.Blender.get_group_props()
props.active_group_id = 0
tool.Group.disable_editing_group()
return {"FINISHED"}
+2 -2
View File
@@ -44,7 +44,7 @@ class BIM_PT_groups(Panel):
def draw(self, context):
if not GroupsData.is_loaded:
GroupsData.load()
self.props = tool.Blender.get_group_props()
self.props = tool.Group.get_group_props()
assert self.layout
row = self.layout.row(align=True)
@@ -106,7 +106,7 @@ class BIM_PT_object_groups(Panel):
if not ObjectGroupsData.is_loaded:
ObjectGroupsData.load()
assert self.layout
self.props = tool.Blender.get_group_props()
self.props = tool.Group.get_group_props()
for group in ObjectGroupsData.data["groups"]:
row = self.layout.row(align=True)
+2 -2
View File
@@ -269,7 +269,7 @@ class GroupQtosData(Data):
@classmethod
def load(cls):
props = tool.Blender.get_group_props()
props = tool.Group.get_group_props()
assert (active_group := props.active_group)
ifc_definition_id = active_group.ifc_definition_id
cls.data = {"qtos": cls.psetqtos(tool.Ifc.get_entity_by_id(ifc_definition_id), qtos_only=True)}
@@ -282,7 +282,7 @@ class GroupPsetData(Data):
@classmethod
def load(cls):
props = tool.Blender.get_group_props()
props = tool.Group.get_group_props()
assert (active_group := props.active_group)
ifc_definition_id = active_group.ifc_definition_id
cls.data = {"psets": cls.psetqtos(tool.Ifc.get_entity_by_id(ifc_definition_id), psets_only=True)}
+2 -2
View File
@@ -667,7 +667,7 @@ class BIM_PT_group_qtos(Panel):
@classmethod
def poll(cls, context):
props = tool.Blender.get_group_props()
props = tool.Group.get_group_props()
return bool(props.active_group)
def draw(self, context):
@@ -699,7 +699,7 @@ class BIM_PT_group_psets(Panel):
@classmethod
def poll(cls, context):
props = tool.Blender.get_group_props()
props = tool.Group.get_group_props()
return bool(props.active_group)
def draw(self, context):
+1
View File
@@ -37,6 +37,7 @@ from bonsai.tool.drawing import Drawing
from bonsai.tool.feature import Feature
from bonsai.tool.geometry import Geometry
from bonsai.tool.georeference import Georeference
from bonsai.tool.group import Group
from bonsai.tool.ifc import Ifc
from bonsai.tool.ifcgit import IfcGit
from bonsai.tool.ifcgit import IfcGitRepo
+1 -7
View File
@@ -63,7 +63,6 @@ if TYPE_CHECKING:
from bonsai.bim.module.csv.prop import CsvProperties
from bonsai.bim.module.diff.prop import DiffProperties
from bonsai.bim.module.fm.prop import BIMFMProperties
from bonsai.bim.module.group.prop import BIMGroupProperties
from bonsai.bim.module.light.prop import BIMSolarProperties, RadianceExporterProperties
T = TypeVar("T")
@@ -260,7 +259,7 @@ class Blender(bonsai.core.tool.Blender):
wsprops = tool.Sequence.get_work_schedule_props()
return wsprops.active_work_schedule_id
elif obj_type == "Group":
props = tool.Blender.get_group_props()
props = tool.Group.get_group_props()
assert (active_group := props.active_group)
return active_group.ifc_definition_id
elif obj_type == "Zone":
@@ -1778,11 +1777,6 @@ class Blender(bonsai.core.tool.Blender):
assert (scene := bpy.context.scene)
return scene.DiffProperties # pyright: ignore[reportAttributeAccessIssue]
@classmethod
def get_group_props(cls) -> BIMGroupProperties:
assert (scene := bpy.context.scene)
return scene.BIMGroupProperties # pyright: ignore[reportAttributeAccessIssue]
@classmethod
def get_bim_props(cls, scene: Optional[bpy.types.Scene] = None) -> BIMProperties:
if scene is None:
+94
View File
@@ -0,0 +1,94 @@
# Bonsai - OpenBIM Blender Add-on
# Copyright (C) 2022 Dion Moult <dion@thinkmoult.com>
#
# This file is part of Bonsai.
#
# Bonsai is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Bonsai 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import json
import bpy
import ifcopenshell
import bonsai.bim.helper
import bonsai.core.tool
import bonsai.tool as tool
from typing import TYPE_CHECKING
from natsort import natsorted
if TYPE_CHECKING:
from bonsai.bim.module.group.prop import BIMGroupProperties
class Group(bonsai.core.tool.System):
@classmethod
def get_group_props(cls) -> BIMGroupProperties:
assert (scene := bpy.context.scene)
return scene.BIMGroupProperties # pyright: ignore[reportAttributeAccessIssue]
@classmethod
def import_groups(cls) -> None:
props = tool.Group.get_group_props()
expanded_groups: list[int] = json.loads(props.expanded_groups_json)
props.groups.clear()
groups = [
group for group in tool.Ifc.get().by_type("IfcGroup", include_subtypes=False) if not group.HasAssignments
]
sorted_groups = natsorted(groups, key=lambda group: group.Name or "Unnamed")
def load_group(group: ifcopenshell.entity_instance, tree_depth: int = 0) -> None:
new = props.groups.add()
new.ifc_definition_id = group.id()
new["name"] = group.Name or "Unnamed"
new.tree_depth = tree_depth
new.has_children = False
new.is_expanded = group.id() in expanded_groups
related_groups: list[ifcopenshell.entity_instance]
related_groups = [
related_object
for rel in group.IsGroupedBy or []
for related_object in rel.RelatedObjects
if related_object.is_a("IfcGroup")
]
sorted_related_groups = natsorted(related_groups, key=lambda group: group.Name or "Unnamed")
if sorted_related_groups:
new.has_children = True
if new.is_expanded:
for related_group in sorted_related_groups:
load_group(related_group, tree_depth=tree_depth + 1)
for group in sorted_groups:
load_group(group)
@classmethod
def enable_group_editing_ui(cls) -> None:
props = cls.get_group_props()
props.is_editing = True
@classmethod
def disable_group_editing_ui(cls) -> None:
props = cls.get_group_props()
props.is_editing = False
@classmethod
def disable_editing_group(cls) -> None:
props = cls.get_group_props()
props.active_group_id = 0
@classmethod
def set_active_group_to_edit(cls, group: ifcopenshell.entity_instance) -> None:
props = cls.get_group_props()
props.active_group_id = group.id()