This commit is contained in:
Andrej730
2025-05-06 12:44:48 +05:00
parent b0f2785e99
commit 06a2cecb51
7 changed files with 73 additions and 40 deletions
+2 -1
View File
@@ -67,7 +67,8 @@ class TypeData:
if not relating_type_classes: if not relating_type_classes:
return [] return []
results = [] results = []
relating_type_class = bpy.context.active_object.BIMTypeProperties.relating_type_class assert (obj := bpy.context.active_object)
relating_type_class = tool.Type.get_object_type_props(obj).relating_type_class
if not relating_type_class and relating_type_classes: if not relating_type_class and relating_type_classes:
relating_type_class = relating_type_classes[0][0] relating_type_class = relating_type_classes[0][0]
elements = tool.Ifc.get().by_type(relating_type_class) elements = tool.Ifc.get().by_type(relating_type_class)
+15 -7
View File
@@ -46,9 +46,13 @@ class AssignType(bpy.types.Operator, tool.Ifc.Operator):
related_object: str related_object: str
def _execute(self, context): def _execute(self, context):
relating_type = tool.Ifc.get().by_id( if self.relating_type:
self.relating_type or int(context.active_object.BIMTypeProperties.relating_type) relating_type = self.relating_type
) else:
assert (obj := context.active_object)
props = tool.Type.get_object_type_props(obj)
relating_type = int(props.relating_type)
relating_type = tool.Ifc.get().by_id(relating_type)
if self.related_object: if self.related_object:
related_objects = [bpy.data.objects[self.related_object]] related_objects = [bpy.data.objects[self.related_object]]
else: else:
@@ -130,8 +134,10 @@ class EnableEditingType(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def execute(self, context): def execute(self, context):
context.active_object.BIMTypeProperties.is_editing_type = True assert (obj := context.active_object)
context.active_object.BIMTypeProperties.relating_type_object = None props = tool.Type.get_object_type_props(obj)
props.is_editing_type = True
props.relating_type_object = None
return {"FINISHED"} return {"FINISHED"}
@@ -142,8 +148,10 @@ class DisableEditingType(bpy.types.Operator):
obj: bpy.props.StringProperty() obj: bpy.props.StringProperty()
def execute(self, context): def execute(self, context):
obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object obj = bpy.data.objects[self.obj] if self.obj else context.active_object
obj.BIMTypeProperties.is_editing_type = False assert obj
props = tool.Type.get_object_type_props(obj)
props.is_editing_type = False
return {"FINISHED"} return {"FINISHED"}
+13 -6
View File
@@ -21,6 +21,7 @@ import ifcopenshell.util.element
import ifcopenshell.util.type import ifcopenshell.util.type
from bonsai.bim.module.type.data import TypeData from bonsai.bim.module.type.data import TypeData
import bonsai.tool as tool import bonsai.tool as tool
from typing import TYPE_CHECKING, Union
from bpy.types import PropertyGroup from bpy.types import PropertyGroup
from bpy.props import ( from bpy.props import (
PointerProperty, PointerProperty,
@@ -34,23 +35,23 @@ from bpy.props import (
) )
def get_relating_type_class(self, context): def get_relating_type_class(self: "BIMTypeProperties", context: bpy.types.Context) -> list[tuple[str, str, str]]:
if not TypeData.is_loaded: if not TypeData.is_loaded:
TypeData.load() TypeData.load()
return TypeData.data["relating_type_classes"] return TypeData.data["relating_type_classes"]
def get_relating_type(self, context): def get_relating_type(self: "BIMTypeProperties", context: bpy.types.Context) -> list[tuple[str, str, str]]:
if not TypeData.is_loaded: if not TypeData.is_loaded:
TypeData.load() TypeData.load()
return TypeData.data["relating_types"] return TypeData.data["relating_types"]
def update_relating_type_class(self, context): def update_relating_type_class(self: "BIMTypeProperties", context: bpy.types.Context) -> None:
TypeData.is_loaded = False TypeData.is_loaded = False
def update_relating_type_from_object(self, context): def update_relating_type_from_object(self: "BIMTypeProperties", context: bpy.types.Context) -> None:
if self.relating_type_object is None: if self.relating_type_object is None:
return return
element = tool.Ifc.get_entity(self.relating_type_object) element = tool.Ifc.get_entity(self.relating_type_object)
@@ -63,12 +64,12 @@ def update_relating_type_from_object(self, context):
bpy.ops.bim.assign_type() bpy.ops.bim.assign_type()
def is_object_class_applicable(self, obj): def is_object_class_applicable(self: "BIMTypeProperties", obj: bpy.types.Object) -> bool:
if not TypeData.is_loaded: if not TypeData.is_loaded:
TypeData.load() TypeData.load()
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
if not element: if not element:
return return False
element_type = ifcopenshell.util.element.get_type(element) element_type = ifcopenshell.util.element.get_type(element)
if element_type is None: if element_type is None:
return False return False
@@ -89,3 +90,9 @@ class BIMTypeProperties(PropertyGroup):
update=update_relating_type_from_object, update=update_relating_type_from_object,
poll=is_object_class_applicable, poll=is_object_class_applicable,
) )
if TYPE_CHECKING:
is_editing_type: bool
relating_type_class: str
relating_type: str
relating_type_object: Union[bpy.types.Object, None]
+7 -4
View File
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>. # along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
import bonsai.tool as tool import bonsai.tool as tool
import bonsai.bim.module.type.prop as type_prop import bonsai.bim.module.type.prop as type_prop
from bpy.types import Panel from bpy.types import Panel
@@ -55,8 +56,9 @@ class BIM_PT_type(Panel):
else: else:
self.draw_type_ui(context) self.draw_type_ui(context)
def draw_type_ui(self, context): def draw_type_ui(self, context: bpy.types.Context) -> None:
oprops = tool.Blender.get_object_bim_props(context.active_object) assert (obj := context.active_object)
oprops = tool.Blender.get_object_bim_props(obj)
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.label(text=f"{TypeData.data['total_instances']} Typed Objects") row.label(text=f"{TypeData.data['total_instances']} Typed Objects")
select_type_objects_row = row.row(align=True) select_type_objects_row = row.row(align=True)
@@ -66,9 +68,10 @@ class BIM_PT_type(Panel):
op.element = oprops.ifc_definition_id op.element = oprops.ifc_definition_id
row.operator("bim.auto_rename_occurrences", icon="ITALIC", text="") row.operator("bim.auto_rename_occurrences", icon="ITALIC", text="")
def draw_product_ui(self, context): def draw_product_ui(self, context: bpy.types.Context) -> None:
layout = self.layout layout = self.layout
props = context.active_object.BIMTypeProperties assert (obj := context.active_object)
props = tool.Type.get_object_type_props(obj)
if props.is_editing_type: if props.is_editing_type:
row = layout.row(align=True) row = layout.row(align=True)
+22 -17
View File
@@ -26,9 +26,9 @@ if TYPE_CHECKING:
def edit_object_placement( def edit_object_placement(
ifc: tool.Ifc, ifc: type[tool.Ifc],
geometry: tool.Geometry, geometry: type[tool.Geometry],
surveyor: tool.Surveyor, surveyor: type[tool.Surveyor],
obj: Optional[bpy.types.Object] = None, obj: Optional[bpy.types.Object] = None,
apply_scale: bool = True, apply_scale: bool = True,
) -> None: ) -> None:
@@ -50,10 +50,10 @@ def edit_object_placement(
def add_representation( def add_representation(
ifc: tool.Ifc, ifc: type[tool.Ifc],
geometry: tool.Geometry, geometry: type[tool.Geometry],
style: tool.Style, style: type[tool.Style],
surveyor: tool.Surveyor, surveyor: type[tool.Surveyor],
obj: bpy.types.Object, obj: bpy.types.Object,
context: ifcopenshell.entity_instance, context: ifcopenshell.entity_instance,
ifc_representation_class: Optional[str] = None, ifc_representation_class: Optional[str] = None,
@@ -110,8 +110,8 @@ def add_representation(
def switch_representation( def switch_representation(
ifc: tool.Ifc, ifc: type[tool.Ifc],
geometry: tool.Geometry, geometry: type[tool.Geometry],
obj: bpy.types.Object, obj: bpy.types.Object,
representation: ifcopenshell.entity_instance, representation: ifcopenshell.entity_instance,
should_reload: bool = True, should_reload: bool = True,
@@ -139,13 +139,16 @@ def switch_representation(
def get_representation_ifc_parameters( def get_representation_ifc_parameters(
geometry: tool.Geometry, obj: bpy.types.Object, should_sync_changes_first: bool = False geometry: type[tool.Geometry], obj: bpy.types.Object, should_sync_changes_first: bool = False
) -> None: ) -> None:
geometry.import_representation_parameters(geometry.get_object_data(obj)) geometry.import_representation_parameters(geometry.get_object_data(obj))
def remove_representation( def remove_representation(
ifc: tool.Ifc, geometry: tool.Geometry, obj: bpy.types.Object, representation: ifcopenshell.entity_instance ifc: type[tool.Ifc],
geometry: type[tool.Geometry],
obj: bpy.types.Object,
representation: ifcopenshell.entity_instance,
) -> None: ) -> None:
"""Remove IFC representation from an object. """Remove IFC representation from an object.
@@ -183,7 +186,7 @@ def remove_representation(
geometry.delete_data(data) geometry.delete_data(data)
def purge_unused_representations(ifc: tool.Ifc, geometry: tool.Geometry) -> int: def purge_unused_representations(ifc: type[tool.Ifc], geometry: type[tool.Geometry]) -> int:
"""Purge representations without inverses. """Purge representations without inverses.
:return: A number of purged representations. :return: A number of purged representations.
@@ -196,15 +199,17 @@ def purge_unused_representations(ifc: tool.Ifc, geometry: tool.Geometry) -> int:
return purged_representations return purged_representations
def select_connection(geometry: tool.Geometry, connection: ifcopenshell.entity_instance) -> None: def select_connection(geometry: type[tool.Geometry], connection: ifcopenshell.entity_instance) -> None:
geometry.select_connection(connection) geometry.select_connection(connection)
def remove_connection(geometry: tool.Geometry, connection: ifcopenshell.entity_instance) -> None: def remove_connection(geometry: type[tool.Geometry], connection: ifcopenshell.entity_instance) -> None:
geometry.remove_connection(connection) geometry.remove_connection(connection)
def get_similar_openings(ifc: tool.Ifc, opening: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]: def get_similar_openings(
ifc: type[tool.Ifc], opening: ifcopenshell.entity_instance
) -> list[ifcopenshell.entity_instance]:
model = ifc.get() model = ifc.get()
all_openings = model.by_type("IfcOpeningElement") all_openings = model.by_type("IfcOpeningElement")
similar_openings = [o for o in all_openings if o.ObjectPlacement == opening.ObjectPlacement and o != opening] similar_openings = [o for o in all_openings if o.ObjectPlacement == opening.ObjectPlacement and o != opening]
@@ -212,7 +217,7 @@ def get_similar_openings(ifc: tool.Ifc, opening: ifcopenshell.entity_instance) -
def get_similar_openings_building_objs( def get_similar_openings_building_objs(
ifc: tool.Ifc, similar_openings: list[ifcopenshell.entity_instance] ifc: type[tool.Ifc], similar_openings: list[ifcopenshell.entity_instance]
) -> list[bpy.types.Object]: ) -> list[bpy.types.Object]:
building_objs = [] building_objs = []
for similar_opening in similar_openings: for similar_opening in similar_openings:
@@ -221,7 +226,7 @@ def get_similar_openings_building_objs(
def edit_similar_opening_placement( def edit_similar_opening_placement(
geometry: tool.Geometry, geometry: type[tool.Geometry],
opening: Optional[ifcopenshell.entity_instance] = None, opening: Optional[ifcopenshell.entity_instance] = None,
similar_openings: Sequence[ifcopenshell.entity_instance] = (), similar_openings: Sequence[ifcopenshell.entity_instance] = (),
) -> None: ) -> None:
+11 -3
View File
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>. # along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import bpy import bpy
import ifcopenshell import ifcopenshell
import ifcopenshell.util.element import ifcopenshell.util.element
@@ -23,18 +24,25 @@ import ifcopenshell.util.representation
import bonsai.core.tool import bonsai.core.tool
import bonsai.core.geometry import bonsai.core.geometry
import bonsai.tool as tool import bonsai.tool as tool
import bonsai.bim.helper from typing import Union, TYPE_CHECKING
from typing import Union
if TYPE_CHECKING:
from bonsai.bim.module.type.prop import BIMTypeProperties
class Type(bonsai.core.tool.Type): class Type(bonsai.core.tool.Type):
@classmethod
def get_object_type_props(cls, obj: bpy.types.Object) -> BIMTypeProperties:
return obj.BIMTypeProperties
@classmethod @classmethod
def change_object_data(cls, obj: bpy.types.Object, data: bpy.types.ID, is_global: bool = False) -> None: def change_object_data(cls, obj: bpy.types.Object, data: bpy.types.ID, is_global: bool = False) -> None:
tool.Geometry.change_object_data(obj, data, is_global) tool.Geometry.change_object_data(obj, data, is_global)
@classmethod @classmethod
def disable_editing(cls, obj: bpy.types.Object) -> None: def disable_editing(cls, obj: bpy.types.Object) -> None:
obj.BIMTypeProperties.is_editing_type = False props = cls.get_object_type_props(obj)
props.is_editing_type = False
@classmethod @classmethod
def get_body_context(cls) -> ifcopenshell.entity_instance: def get_body_context(cls) -> ifcopenshell.entity_instance:
+3 -2
View File
@@ -52,9 +52,10 @@ class TestChangeObjectData(NewFile):
class TestDisableEditing(NewFile): class TestDisableEditing(NewFile):
def test_run(self): def test_run(self):
obj = bpy.data.objects.new("Object", None) obj = bpy.data.objects.new("Object", None)
obj.BIMTypeProperties.is_editing_type = True props = tool.Type.get_object_type_props(obj)
props.is_editing_type = True
subject.disable_editing(obj) subject.disable_editing(obj)
assert obj.BIMTypeProperties.is_editing_type is False assert props.is_editing_type is False
class TestGetBodyContext(NewFile): class TestGetBodyContext(NewFile):