mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-18 22:33:33 +00:00
Add tool for 'group' module
This commit is contained in:
@@ -23,7 +23,6 @@ import ifcopenshell.util.element
|
|||||||
import bonsai.bim.helper
|
import bonsai.bim.helper
|
||||||
import bonsai.tool as tool
|
import bonsai.tool as tool
|
||||||
import json
|
import json
|
||||||
from natsort import natsorted
|
|
||||||
|
|
||||||
|
|
||||||
class LoadGroups(bpy.types.Operator, tool.Ifc.Operator):
|
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_label = "Load Groups"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
expanded_groups: list[int]
|
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
self.props = tool.Blender.get_group_props()
|
tool.Group.import_groups()
|
||||||
self.expanded_groups = json.loads(self.props.expanded_groups_json)
|
tool.Group.enable_group_editing_ui()
|
||||||
self.props.groups.clear()
|
tool.Group.disable_editing_group()
|
||||||
|
|
||||||
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()
|
|
||||||
return {"FINISHED"}
|
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):
|
class ToggleGroup(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.toggle_group"
|
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")
|
option: bpy.props.StringProperty(name="Expand or Collapse")
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
props = tool.Blender.get_group_props()
|
props = tool.Group.get_group_props()
|
||||||
expanded_groups: set[int]
|
expanded_groups: set[int]
|
||||||
expanded_groups = set(json.loads(props.expanded_groups_json))
|
expanded_groups = set(json.loads(props.expanded_groups_json))
|
||||||
if self.option == "Expand":
|
if self.option == "Expand":
|
||||||
@@ -101,9 +64,8 @@ class DisableGroupEditingUI(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
props = tool.Blender.get_group_props()
|
tool.Group.disable_group_editing_ui()
|
||||||
props.is_editing = False
|
tool.Group.disable_editing_group()
|
||||||
props.active_group_id = 0
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -125,7 +87,7 @@ class AddGroup(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
ifcopenshell.api.group.assign_group(
|
ifcopenshell.api.group.assign_group(
|
||||||
tool.Ifc.get(), products=[result], group=tool.Ifc.get().by_id(self.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"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -135,11 +97,11 @@ class EditGroup(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def _execute(self, context):
|
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)
|
attributes = bonsai.bim.helper.export_attributes(props.group_attributes)
|
||||||
ifc_file = tool.Ifc.get()
|
ifc_file = tool.Ifc.get()
|
||||||
ifcopenshell.api.group.edit_group(ifc_file, group=ifc_file.by_id(props.active_group_id), attributes=attributes)
|
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"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -152,7 +114,7 @@ class RemoveGroup(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
self.file = tool.Ifc.get()
|
self.file = tool.Ifc.get()
|
||||||
ifcopenshell.api.group.remove_group(self.file, group=self.file.by_id(self.group))
|
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"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -163,10 +125,11 @@ class EnableEditingGroup(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
group: bpy.props.IntProperty()
|
group: bpy.props.IntProperty()
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
props = tool.Blender.get_group_props()
|
props = tool.Group.get_group_props()
|
||||||
props.group_attributes.clear()
|
props.group_attributes.clear()
|
||||||
bonsai.bim.helper.import_attributes(tool.Ifc.get().by_id(self.group), props.group_attributes)
|
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"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -176,8 +139,7 @@ class DisableEditingGroup(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
props = tool.Blender.get_group_props()
|
tool.Group.disable_editing_group()
|
||||||
props.active_group_id = 0
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class BIM_PT_groups(Panel):
|
|||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
if not GroupsData.is_loaded:
|
if not GroupsData.is_loaded:
|
||||||
GroupsData.load()
|
GroupsData.load()
|
||||||
self.props = tool.Blender.get_group_props()
|
self.props = tool.Group.get_group_props()
|
||||||
assert self.layout
|
assert self.layout
|
||||||
|
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
@@ -106,7 +106,7 @@ class BIM_PT_object_groups(Panel):
|
|||||||
if not ObjectGroupsData.is_loaded:
|
if not ObjectGroupsData.is_loaded:
|
||||||
ObjectGroupsData.load()
|
ObjectGroupsData.load()
|
||||||
assert self.layout
|
assert self.layout
|
||||||
self.props = tool.Blender.get_group_props()
|
self.props = tool.Group.get_group_props()
|
||||||
|
|
||||||
for group in ObjectGroupsData.data["groups"]:
|
for group in ObjectGroupsData.data["groups"]:
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
|
|||||||
@@ -269,7 +269,7 @@ class GroupQtosData(Data):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load(cls):
|
def load(cls):
|
||||||
props = tool.Blender.get_group_props()
|
props = tool.Group.get_group_props()
|
||||||
assert (active_group := props.active_group)
|
assert (active_group := props.active_group)
|
||||||
ifc_definition_id = active_group.ifc_definition_id
|
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)}
|
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
|
@classmethod
|
||||||
def load(cls):
|
def load(cls):
|
||||||
props = tool.Blender.get_group_props()
|
props = tool.Group.get_group_props()
|
||||||
assert (active_group := props.active_group)
|
assert (active_group := props.active_group)
|
||||||
ifc_definition_id = active_group.ifc_definition_id
|
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)}
|
cls.data = {"psets": cls.psetqtos(tool.Ifc.get_entity_by_id(ifc_definition_id), psets_only=True)}
|
||||||
|
|||||||
@@ -667,7 +667,7 @@ class BIM_PT_group_qtos(Panel):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
props = tool.Blender.get_group_props()
|
props = tool.Group.get_group_props()
|
||||||
return bool(props.active_group)
|
return bool(props.active_group)
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
@@ -699,7 +699,7 @@ class BIM_PT_group_psets(Panel):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
props = tool.Blender.get_group_props()
|
props = tool.Group.get_group_props()
|
||||||
return bool(props.active_group)
|
return bool(props.active_group)
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ from bonsai.tool.drawing import Drawing
|
|||||||
from bonsai.tool.feature import Feature
|
from bonsai.tool.feature import Feature
|
||||||
from bonsai.tool.geometry import Geometry
|
from bonsai.tool.geometry import Geometry
|
||||||
from bonsai.tool.georeference import Georeference
|
from bonsai.tool.georeference import Georeference
|
||||||
|
from bonsai.tool.group import Group
|
||||||
from bonsai.tool.ifc import Ifc
|
from bonsai.tool.ifc import Ifc
|
||||||
from bonsai.tool.ifcgit import IfcGit
|
from bonsai.tool.ifcgit import IfcGit
|
||||||
from bonsai.tool.ifcgit import IfcGitRepo
|
from bonsai.tool.ifcgit import IfcGitRepo
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ if TYPE_CHECKING:
|
|||||||
from bonsai.bim.module.csv.prop import CsvProperties
|
from bonsai.bim.module.csv.prop import CsvProperties
|
||||||
from bonsai.bim.module.diff.prop import DiffProperties
|
from bonsai.bim.module.diff.prop import DiffProperties
|
||||||
from bonsai.bim.module.fm.prop import BIMFMProperties
|
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
|
from bonsai.bim.module.light.prop import BIMSolarProperties, RadianceExporterProperties
|
||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
@@ -260,7 +259,7 @@ class Blender(bonsai.core.tool.Blender):
|
|||||||
wsprops = tool.Sequence.get_work_schedule_props()
|
wsprops = tool.Sequence.get_work_schedule_props()
|
||||||
return wsprops.active_work_schedule_id
|
return wsprops.active_work_schedule_id
|
||||||
elif obj_type == "Group":
|
elif obj_type == "Group":
|
||||||
props = tool.Blender.get_group_props()
|
props = tool.Group.get_group_props()
|
||||||
assert (active_group := props.active_group)
|
assert (active_group := props.active_group)
|
||||||
return active_group.ifc_definition_id
|
return active_group.ifc_definition_id
|
||||||
elif obj_type == "Zone":
|
elif obj_type == "Zone":
|
||||||
@@ -1778,11 +1777,6 @@ class Blender(bonsai.core.tool.Blender):
|
|||||||
assert (scene := bpy.context.scene)
|
assert (scene := bpy.context.scene)
|
||||||
return scene.DiffProperties # pyright: ignore[reportAttributeAccessIssue]
|
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
|
@classmethod
|
||||||
def get_bim_props(cls, scene: Optional[bpy.types.Scene] = None) -> BIMProperties:
|
def get_bim_props(cls, scene: Optional[bpy.types.Scene] = None) -> BIMProperties:
|
||||||
if scene is None:
|
if scene is None:
|
||||||
|
|||||||
@@ -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()
|
||||||
Reference in New Issue
Block a user