mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-16 21:42:19 +00:00
typing
This commit is contained in:
@@ -1076,9 +1076,10 @@ class IfcImporter:
|
||||
print(traceback.format_exc())
|
||||
|
||||
def set_default_context(self):
|
||||
rprops = tool.Root.get_root_props()
|
||||
for subcontext in self.file.by_type("IfcGeometricRepresentationSubContext"):
|
||||
if subcontext.ContextIdentifier == "Body":
|
||||
bpy.context.scene.BIMRootProperties.contexts = str(subcontext.id())
|
||||
rprops.contexts = str(subcontext.id())
|
||||
break
|
||||
|
||||
def link_element(self, element: ifcopenshell.entity_instance, obj: IFC_CONNECTED_TYPE) -> None:
|
||||
|
||||
@@ -97,7 +97,7 @@ class AuthoringData:
|
||||
|
||||
@classmethod
|
||||
def default_container(cls) -> str | None:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = tool.Spatial.get_spatial_props()
|
||||
if props.default_container:
|
||||
try:
|
||||
return tool.Ifc.get().by_id(props.default_container).Name
|
||||
|
||||
@@ -58,7 +58,8 @@ class AddEmptyType(bpy.types.Operator, AddObjectHelper):
|
||||
def execute(self, context):
|
||||
obj = bpy.data.objects.new("TYPEX", None)
|
||||
context.scene.collection.objects.link(obj)
|
||||
context.scene.BIMRootProperties.ifc_product = "IfcElementType"
|
||||
rprops = tool.Root.get_root_props()
|
||||
rprops.ifc_product = "IfcElementType"
|
||||
tool.Blender.select_and_activate_single_object(context, obj)
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -71,7 +72,7 @@ class AddDefaultType(bpy.types.Operator, tool.Ifc.Operator):
|
||||
ifc_element_type: bpy.props.StringProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMRootProperties
|
||||
props = tool.Root.get_root_props()
|
||||
props.ifc_product = "IfcElementType"
|
||||
props.ifc_class = self.ifc_element_type
|
||||
if self.ifc_element_type == "IfcWallType":
|
||||
@@ -363,7 +364,7 @@ class AddConstrTypeInstance(bpy.types.Operator, tool.Ifc.Operator):
|
||||
)
|
||||
bonsai.core.type.assign_type(tool.Ifc, tool.Type, element=element, type=relating_type)
|
||||
|
||||
rprops = context.scene.BIMRootProperties
|
||||
rprops = tool.Root.get_root_props()
|
||||
ifc_context = None
|
||||
if get_enum_items(rprops, "contexts", context):
|
||||
ifc_context = int(rprops.contexts or "0") or None
|
||||
|
||||
@@ -60,7 +60,8 @@ class IfcClassData:
|
||||
|
||||
@classmethod
|
||||
def ifc_classes(cls):
|
||||
ifc_product = bpy.context.scene.BIMRootProperties.ifc_product
|
||||
rprops = tool.Root.get_root_props()
|
||||
ifc_product = rprops.ifc_product
|
||||
declaration = tool.Ifc.schema().declaration_by_name(ifc_product)
|
||||
declarations = ifcopenshell.util.schema.get_subtypes(declaration)
|
||||
names = [d.name() for d in declarations]
|
||||
@@ -80,7 +81,8 @@ class IfcClassData:
|
||||
@classmethod
|
||||
def ifc_predefined_types(cls):
|
||||
types_enum = []
|
||||
ifc_class = bpy.context.scene.BIMRootProperties.ifc_class
|
||||
rprops = tool.Root.get_root_props()
|
||||
ifc_class = rprops.ifc_class
|
||||
declaration = tool.Ifc.schema().declaration_by_name(ifc_class)
|
||||
version = tool.Ifc.get_schema()
|
||||
for attribute in declaration.attributes():
|
||||
@@ -114,7 +116,8 @@ class IfcClassData:
|
||||
|
||||
@classmethod
|
||||
def representation_template(cls):
|
||||
ifc_class = bpy.context.scene.BIMRootProperties.ifc_class
|
||||
rprops = tool.Root.get_root_props()
|
||||
ifc_class = rprops.ifc_class
|
||||
templates = [
|
||||
("EMPTY", "No Geometry", "Start with an empty object"),
|
||||
None,
|
||||
|
||||
@@ -42,6 +42,7 @@ class EnableReassignClass(bpy.types.Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
rprops = tool.Root.get_root_props()
|
||||
obj = context.active_object
|
||||
self.file = tool.Ifc.get()
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
@@ -53,7 +54,7 @@ class EnableReassignClass(bpy.types.Operator):
|
||||
declaration = schema.declaration_by_name(ifc_class)
|
||||
for ifc_product in ifc_products:
|
||||
if ifcopenshell.util.schema.is_a(declaration, ifc_product):
|
||||
context.scene.BIMRootProperties.ifc_product = ifc_product
|
||||
rprops.ifc_product = ifc_product
|
||||
break
|
||||
else:
|
||||
self.report({"ERROR"}, f"Couldn't find matching IFC product for the selected object: '{element}'.")
|
||||
@@ -61,13 +62,13 @@ class EnableReassignClass(bpy.types.Operator):
|
||||
return {"CANCELLED"}
|
||||
|
||||
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
context.scene.BIMRootProperties.ifc_class = element.is_a()
|
||||
context.scene.BIMRootProperties.relating_class_object = None
|
||||
rprops.ifc_class = element.is_a()
|
||||
rprops.relating_class_object = None
|
||||
if hasattr(element, "PredefinedType"):
|
||||
if element.PredefinedType:
|
||||
context.scene.BIMRootProperties.ifc_predefined_type = element.PredefinedType
|
||||
rprops.ifc_predefined_type = element.PredefinedType
|
||||
userdefined_type = ifcopenshell.util.element.get_predefined_type(element)
|
||||
context.scene.BIMRootProperties.ifc_userdefined_type = userdefined_type or ""
|
||||
rprops.ifc_userdefined_type = userdefined_type or ""
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -94,9 +95,9 @@ class ReassignClass(bpy.types.Operator, tool.Ifc.Operator):
|
||||
else:
|
||||
objects = set(context.selected_objects + [context.active_object])
|
||||
self.file = tool.Ifc.get()
|
||||
root_props = context.scene.BIMRootProperties
|
||||
ifc_product: str = root_props.ifc_product
|
||||
ifc_class: str = root_props.ifc_class
|
||||
root_props = tool.Root.get_root_props()
|
||||
ifc_product = root_props.ifc_product
|
||||
ifc_class = root_props.ifc_class
|
||||
type_ifc_class = next(iter(ifcopenshell.util.type.get_applicable_types(ifc_class, self.file.schema)), None)
|
||||
|
||||
predefined_type = root_props.ifc_predefined_type
|
||||
@@ -176,7 +177,7 @@ class AssignClass(bpy.types.Operator, tool.Ifc.Operator):
|
||||
ifc_representation_class: bpy.props.StringProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMRootProperties
|
||||
props = tool.Root.get_root_props()
|
||||
objects: list[bpy.types.Object] = []
|
||||
if self.obj:
|
||||
objects = [bpy.data.objects[self.obj]]
|
||||
@@ -358,7 +359,7 @@ class AddElement(bpy.types.Operator, tool.Ifc.Operator):
|
||||
return IfcStore.execute_ifc_operator(self, context, event, method="INVOKE")
|
||||
|
||||
def _invoke(self, context, event):
|
||||
props = context.scene.BIMRootProperties
|
||||
props = tool.Root.get_root_props()
|
||||
# For convenience, preselect OBJs if applicable
|
||||
if props.ifc_product == "IfcFeatureElement":
|
||||
if (obj := tool.Blender.get_active_object(is_selected=True)) and obj.type == "MESH":
|
||||
@@ -376,7 +377,7 @@ class AddElement(bpy.types.Operator, tool.Ifc.Operator):
|
||||
return context.window_manager.invoke_props_dialog(self)
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMRootProperties
|
||||
props = tool.Root.get_root_props()
|
||||
predefined_type = (
|
||||
props.ifc_userdefined_type if props.ifc_predefined_type == "USERDEFINED" else props.ifc_predefined_type
|
||||
)
|
||||
@@ -500,7 +501,7 @@ class AddElement(bpy.types.Operator, tool.Ifc.Operator):
|
||||
else:
|
||||
material = ifcopenshell.api.run("material.add_material", tool.Ifc.get(), name="Unknown")
|
||||
if representation_template == "PROFILESET":
|
||||
profile_id = tool.Blender.get_enum_safe(context.scene.BIMRootProperties, "profile")
|
||||
profile_id = tool.Blender.get_enum_safe(props, "profile")
|
||||
if profile_id in ("-", None):
|
||||
profile = next((p for p in ifc_file.by_type("IfcProfileDef") if p.ProfileName), None)
|
||||
if profile is None:
|
||||
@@ -589,7 +590,7 @@ class AddElement(bpy.types.Operator, tool.Ifc.Operator):
|
||||
tool.Blender.set_active_object(obj)
|
||||
|
||||
def draw(self, context):
|
||||
props = context.scene.BIMRootProperties
|
||||
props = tool.Root.get_root_props()
|
||||
self.layout.use_property_split = True
|
||||
self.layout.use_property_decorate = False
|
||||
row = self.layout.row()
|
||||
@@ -600,7 +601,7 @@ class AddElement(bpy.types.Operator, tool.Ifc.Operator):
|
||||
if not self.ifc_product:
|
||||
prop_with_search(self.layout, props, "ifc_product", text="Definition", should_click_ok=True)
|
||||
prop_with_search(self.layout, props, "ifc_class", should_click_ok=True)
|
||||
ifc_predefined_types = root_prop.get_ifc_predefined_types(context.scene.BIMRootProperties, context)
|
||||
ifc_predefined_types = root_prop.get_ifc_predefined_types(props, context)
|
||||
if ifc_predefined_types:
|
||||
prop_with_search(self.layout, props, "ifc_predefined_type", should_click_ok=True)
|
||||
if props.ifc_predefined_type == "USERDEFINED":
|
||||
|
||||
@@ -34,28 +34,27 @@ from bpy.props import (
|
||||
FloatVectorProperty,
|
||||
CollectionProperty,
|
||||
)
|
||||
from typing import TYPE_CHECKING, Union
|
||||
|
||||
|
||||
def get_ifc_predefined_types(self, context):
|
||||
def get_ifc_predefined_types(self: "BIMRootProperties", context: bpy.types.Context) -> list[tuple[str, str]]:
|
||||
if not IfcClassData.is_loaded:
|
||||
IfcClassData.load()
|
||||
return IfcClassData.data["ifc_predefined_types"]
|
||||
|
||||
|
||||
def get_representation_template(self, context):
|
||||
def get_representation_template(self: "BIMRootProperties", context: bpy.types.Context) -> list[tuple[str, str]]:
|
||||
if not IfcClassData.is_loaded:
|
||||
IfcClassData.load()
|
||||
return IfcClassData.data["representation_template"]
|
||||
|
||||
|
||||
def refresh_classes(self, context):
|
||||
old_class = context.scene.BIMRootProperties.ifc_class
|
||||
old_predefined_type = (
|
||||
context.scene.BIMRootProperties.ifc_predefined_type if get_ifc_predefined_types(self, context) else ""
|
||||
)
|
||||
def refresh_classes(self: "BIMRootProperties", context: bpy.types.Context) -> None:
|
||||
old_class = self.ifc_class
|
||||
old_predefined_type = self.ifc_predefined_type if get_ifc_predefined_types(self, context) else ""
|
||||
|
||||
enum = get_ifc_classes(self, context)
|
||||
context.scene.BIMRootProperties.ifc_class = enum[0][0]
|
||||
self.ifc_class = enum[0][0]
|
||||
IfcClassData.load()
|
||||
|
||||
if self.ifc_product == "IfcFeatureElement":
|
||||
@@ -81,48 +80,44 @@ def refresh_classes(self, context):
|
||||
self.ifc_predefined_type = old_predefined_type
|
||||
|
||||
|
||||
def refresh_predefined_types(self, context):
|
||||
def refresh_predefined_types(self: "BIMRootProperties", context: bpy.types.Context) -> None:
|
||||
IfcClassData.load()
|
||||
enum = get_ifc_predefined_types(self, context)
|
||||
if enum:
|
||||
context.scene.BIMRootProperties.ifc_predefined_type = enum[0][0]
|
||||
self.ifc_predefined_type = enum[0][0]
|
||||
|
||||
|
||||
def update_class_enum(self, context):
|
||||
self.ifc_class = self.ifc_class_filter_enum
|
||||
|
||||
|
||||
def get_ifc_products(self, context):
|
||||
def get_ifc_products(self: "BIMRootProperties", context: bpy.types.Context) -> list[tuple[str, str]]:
|
||||
if not IfcClassData.is_loaded:
|
||||
IfcClassData.load()
|
||||
return IfcClassData.data["ifc_products"]
|
||||
|
||||
|
||||
def get_ifc_classes(self, context):
|
||||
def get_ifc_classes(self: "BIMRootProperties", context: bpy.types.Context) -> list[tuple[str, str]]:
|
||||
if not IfcClassData.is_loaded:
|
||||
IfcClassData.load()
|
||||
return IfcClassData.data["ifc_classes"]
|
||||
|
||||
|
||||
def get_ifc_classes_suggestions():
|
||||
def get_ifc_classes_suggestions(self: "BIMRootProperties", context: bpy.types.Context) -> list[tuple[str, str]]:
|
||||
if not IfcClassData.is_loaded:
|
||||
IfcClassData.load()
|
||||
return IfcClassData.data["ifc_classes_suggestions"]
|
||||
|
||||
|
||||
def get_contexts(self, context):
|
||||
def get_contexts(self: "BIMRootProperties", context: bpy.types.Context) -> list[tuple[str, str]]:
|
||||
if not IfcClassData.is_loaded:
|
||||
IfcClassData.load()
|
||||
return IfcClassData.data["contexts"]
|
||||
|
||||
|
||||
def get_profile(self, context):
|
||||
def get_profile(self: "BIMRootProperties", context: bpy.types.Context) -> list[tuple[str, str]]:
|
||||
if not IfcClassData.is_loaded:
|
||||
IfcClassData.load()
|
||||
return IfcClassData.data["profile"]
|
||||
|
||||
|
||||
def update_relating_class_from_object(self, context):
|
||||
def update_relating_class_from_object(self: "BIMRootProperties", context: bpy.types.Context) -> None:
|
||||
if self.relating_class_object is None:
|
||||
return
|
||||
element = tool.Ifc.get_entity(self.relating_class_object)
|
||||
@@ -139,7 +134,7 @@ def update_relating_class_from_object(self, context):
|
||||
bpy.ops.bim.reassign_class()
|
||||
|
||||
|
||||
def is_object_class_applicable(self, obj):
|
||||
def is_object_class_applicable(self: "BIMRootProperties", obj: bpy.types.Object) -> bool:
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element:
|
||||
return False
|
||||
@@ -149,11 +144,11 @@ def is_object_class_applicable(self, obj):
|
||||
return element.is_a("IfcTypeObject") == active_element.is_a("IfcTypeObject")
|
||||
|
||||
|
||||
def poll_representation_obj(self, obj):
|
||||
def poll_representation_obj(self: "BIMRootProperties", obj: bpy.types.Object) -> bool:
|
||||
return obj.type == "MESH" and obj.data.polygons
|
||||
|
||||
|
||||
def poll_featured_obj(self, obj):
|
||||
def poll_featured_obj(self: "BIMRootProperties", obj: bpy.types.Object) -> bool:
|
||||
return tool.Ifc.get_entity(obj)
|
||||
|
||||
|
||||
@@ -192,3 +187,16 @@ class BIMRootProperties(PropertyGroup):
|
||||
getter_enum_suggestions = {
|
||||
"ifc_class": get_ifc_classes_suggestions,
|
||||
}
|
||||
|
||||
if TYPE_CHECKING:
|
||||
contexts: str
|
||||
description: str
|
||||
ifc_product: str
|
||||
ifc_class: str
|
||||
ifc_predefined_type: str
|
||||
ifc_userdefined_type: str
|
||||
featured_obj: Union[bpy.types.Object, None]
|
||||
representation_template: str
|
||||
representation_obj: Union[bpy.types.Object, None]
|
||||
profile: str
|
||||
relating_class_object: Union[bpy.types.Object, None]
|
||||
|
||||
@@ -44,6 +44,7 @@ class BIM_PT_class(Panel):
|
||||
if not IfcClassData.is_loaded:
|
||||
IfcClassData.load()
|
||||
props = context.active_object.BIMObjectProperties
|
||||
rprops = tool.Root.get_root_props()
|
||||
if props.ifc_definition_id:
|
||||
if not IfcClassData.data["has_entity"]:
|
||||
row = self.layout.row(align=True)
|
||||
@@ -58,10 +59,10 @@ class BIM_PT_class(Panel):
|
||||
row.operator("bim.disable_reassign_class", icon="CANCEL", text="")
|
||||
self.draw_class_dropdowns(
|
||||
context,
|
||||
root_prop.get_ifc_predefined_types(context.scene.BIMRootProperties, context),
|
||||
root_prop.get_ifc_predefined_types(rprops, context),
|
||||
is_reassigning_class=True,
|
||||
)
|
||||
self.layout.prop(context.scene.BIMRootProperties, "relating_class_object", icon="COPYDOWN")
|
||||
self.layout.prop(rprops, "relating_class_object", icon="COPYDOWN")
|
||||
else:
|
||||
row = self.layout.row(align=True)
|
||||
row.label(
|
||||
@@ -78,16 +79,16 @@ class BIM_PT_class(Panel):
|
||||
if AuthoringData.data["is_representation_item_active"]:
|
||||
return
|
||||
|
||||
ifc_predefined_types = root_prop.get_ifc_predefined_types(context.scene.BIMRootProperties, context)
|
||||
ifc_predefined_types = root_prop.get_ifc_predefined_types(rprops, context)
|
||||
self.draw_class_dropdowns(context, ifc_predefined_types)
|
||||
row = self.layout.row(align=True)
|
||||
op = row.operator("bim.assign_class")
|
||||
op.ifc_class = context.scene.BIMRootProperties.ifc_class
|
||||
op.predefined_type = context.scene.BIMRootProperties.ifc_predefined_type if ifc_predefined_types else ""
|
||||
op.userdefined_type = context.scene.BIMRootProperties.ifc_userdefined_type
|
||||
op.ifc_class = rprops.ifc_class
|
||||
op.predefined_type = rprops.ifc_predefined_type if ifc_predefined_types else ""
|
||||
op.userdefined_type = rprops.ifc_userdefined_type
|
||||
|
||||
def draw_class_dropdowns(self, context, ifc_predefined_types, is_reassigning_class=False):
|
||||
props = context.scene.BIMRootProperties
|
||||
props = tool.Root.get_root_props()
|
||||
layout = self.layout
|
||||
prop_with_search(layout, props, "ifc_product")
|
||||
prop_with_search(layout, props, "ifc_class")
|
||||
|
||||
@@ -58,7 +58,7 @@ class SpatialData:
|
||||
|
||||
@classmethod
|
||||
def default_container(cls) -> str | None:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = tool.Spatial.get_spatial_props()
|
||||
if props.default_container:
|
||||
try:
|
||||
return tool.Ifc.get().by_id(props.default_container).Name
|
||||
@@ -102,7 +102,7 @@ class SpatialDecompositionData:
|
||||
|
||||
@classmethod
|
||||
def default_container(cls) -> str | None:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = tool.Spatial.get_spatial_props()
|
||||
if props.default_container:
|
||||
try:
|
||||
return tool.Ifc.get().by_id(props.default_container).Name
|
||||
@@ -112,7 +112,7 @@ class SpatialDecompositionData:
|
||||
@classmethod
|
||||
def subelement_class(cls) -> list[tuple[str, str, str]]:
|
||||
results = []
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = tool.Spatial.get_spatial_props()
|
||||
if not (container := props.active_container):
|
||||
return results
|
||||
container_class = tool.Ifc.get().by_id(container.ifc_definition_id).is_a()
|
||||
|
||||
@@ -66,7 +66,8 @@ class GridDecorator:
|
||||
blf.size(font_id, 12)
|
||||
blf.enable(font_id, blf.SHADOW)
|
||||
|
||||
for axis in context.scene.BIMGridProperties.grid_axes:
|
||||
grid_props = tool.Spatial.get_grid_props()
|
||||
for axis in grid_props.grid_axes:
|
||||
if not (obj := axis.obj) or obj.hide_get() == True:
|
||||
continue
|
||||
if obj.select_get() and context.mode != "OBJECT":
|
||||
@@ -120,7 +121,8 @@ class GridDecorator:
|
||||
selected_edges = []
|
||||
unselected_verts = []
|
||||
unselected_edges = []
|
||||
for axis in context.scene.BIMGridProperties.grid_axes:
|
||||
grid_props = tool.Spatial.get_grid_props()
|
||||
for axis in grid_props.grid_axes:
|
||||
if (obj := axis.obj) and obj.hide_get() == False:
|
||||
if obj.select_get():
|
||||
if context.mode != "OBJECT":
|
||||
|
||||
@@ -96,7 +96,7 @@ class AssignContainer(bpy.types.Operator, tool.Ifc.Operator):
|
||||
container = tool.Ifc.get().by_id(self.container)
|
||||
elif (
|
||||
(obj := tool.Blender.get_active_object())
|
||||
and (props := obj.BIMObjectSpatialProperties)
|
||||
and (props := tool.Spatial.get_object_spatial_props(obj))
|
||||
and (container_obj := props.container_obj)
|
||||
and (container := tool.Ifc.get_entity(container_obj))
|
||||
):
|
||||
|
||||
@@ -36,15 +36,18 @@ import bonsai.core.geometry
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.unit
|
||||
from typing import TYPE_CHECKING, Union, Literal
|
||||
|
||||
|
||||
def get_subelement_class(self, context):
|
||||
def get_subelement_class(
|
||||
self: "BIMSpatialDecompositionProperties", context: bpy.types.Context
|
||||
) -> list[tuple[str, str, str]]:
|
||||
if not SpatialDecompositionData.is_loaded:
|
||||
SpatialDecompositionData.load()
|
||||
return SpatialDecompositionData.data["subelement_class"]
|
||||
|
||||
|
||||
def update_elevation(self, context):
|
||||
def update_elevation(self: "BIMContainer", context: bpy.types.Context) -> None:
|
||||
try:
|
||||
elevation = float(self.elevation)
|
||||
if self.elevation != str(elevation):
|
||||
@@ -91,7 +94,7 @@ def update_element_mode(self: "BIMSpatialDecompositionProperties", context: bpy.
|
||||
tool.Spatial.load_contained_elements()
|
||||
|
||||
|
||||
def update_grid_is_locked(self, context):
|
||||
def update_grid_is_locked(self: "BIMGridProperties", context: bpy.types.Context) -> None:
|
||||
if not tool.Ifc.get():
|
||||
return
|
||||
if tool.Ifc.get().schema in ("IFC2X3", "IFC4"):
|
||||
@@ -108,7 +111,7 @@ def update_grid_is_locked(self, context):
|
||||
bonsai.bim.handler.refresh_ui_data()
|
||||
|
||||
|
||||
def update_spatial_is_locked(self, context):
|
||||
def update_spatial_is_locked(self: "BIMSpatialDecompositionProperties", context: bpy.types.Context) -> None:
|
||||
if not tool.Ifc.get():
|
||||
return
|
||||
if tool.Ifc.get().schema == "IFC2X3":
|
||||
@@ -150,6 +153,10 @@ class BIMObjectSpatialProperties(PropertyGroup):
|
||||
is_editing: BoolProperty(name="Is Editing")
|
||||
container_obj: PointerProperty(type=bpy.types.Object, name="Container", poll=poll_container_obj)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
is_editing: bool
|
||||
container_obj: Union[bpy.types.Object, None]
|
||||
|
||||
|
||||
class BIMContainer(PropertyGroup):
|
||||
name: StringProperty(name="Name", update=update_name)
|
||||
@@ -162,6 +169,16 @@ class BIMContainer(PropertyGroup):
|
||||
is_expanded: BoolProperty(name="Is Expanded")
|
||||
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
||||
|
||||
if TYPE_CHECKING:
|
||||
ifc_class: str
|
||||
description: str
|
||||
long_name: str
|
||||
elevation: str
|
||||
level_index: int
|
||||
has_children: bool
|
||||
is_expanded: bool
|
||||
ifc_definition_id: int
|
||||
|
||||
|
||||
class Element(PropertyGroup):
|
||||
name: StringProperty(name="Name")
|
||||
@@ -185,6 +202,16 @@ class Element(PropertyGroup):
|
||||
),
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
ifc_class: str
|
||||
identification: str
|
||||
ifc_definition_id: int
|
||||
level: int
|
||||
has_children: bool
|
||||
total: int
|
||||
is_expanded: bool
|
||||
type: Literal["CLASS", "TYPE", "CLASSIFICATION", "OCCURRENCE"]
|
||||
|
||||
|
||||
class BIMSpatialDecompositionProperties(PropertyGroup):
|
||||
is_locked: BoolProperty(
|
||||
@@ -223,6 +250,23 @@ class BIMSpatialDecompositionProperties(PropertyGroup):
|
||||
name="Should Include Children", default=True, update=update_should_include_children
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
is_locked: bool
|
||||
is_visible: bool
|
||||
container_filter: str
|
||||
containers: bpy.types.bpy_prop_collection_idprop[BIMContainer]
|
||||
contracted_containers: str
|
||||
active_container_index: int
|
||||
element_filter: str
|
||||
elements: bpy.types.bpy_prop_collection_idprop[Element]
|
||||
expanded_elements: str
|
||||
active_element_index: int
|
||||
total_elements: int
|
||||
element_mode: Literal["TYPE", "DECOMPOSITION", "CLASSIFICATION"]
|
||||
subelement_class: str
|
||||
default_container: int
|
||||
should_include_children: bool
|
||||
|
||||
@property
|
||||
def active_container(self):
|
||||
if self.containers and self.active_container_index < len(self.containers):
|
||||
@@ -248,3 +292,8 @@ class BIMGridProperties(PropertyGroup):
|
||||
update=update_grid_is_visible,
|
||||
)
|
||||
grid_axes: CollectionProperty(name="Grid Axes", type=ObjProperty)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
is_locked: bool
|
||||
is_visible: bool
|
||||
grid_axes: bpy.types.bpy_prop_collection_idprop[ObjProperty]
|
||||
|
||||
@@ -16,10 +16,15 @@
|
||||
# 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 bpy
|
||||
from bpy.types import Panel, UIList
|
||||
from bonsai.bim.module.spatial.data import SpatialData, SpatialDecompositionData
|
||||
import bonsai.tool as tool
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bonsai.bim.module.spatial.prop import BIMSpatialDecompositionProperties, BIMContainer, Element
|
||||
|
||||
|
||||
class BIM_PT_spatial(Panel):
|
||||
@@ -40,7 +45,9 @@ class BIM_PT_spatial(Panel):
|
||||
if not SpatialData.is_loaded:
|
||||
SpatialData.load()
|
||||
|
||||
osprops = context.active_object.BIMObjectSpatialProperties
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
osprops = tool.Spatial.get_object_spatial_props(obj)
|
||||
|
||||
if osprops.is_editing:
|
||||
if SpatialData.data["default_container"]:
|
||||
@@ -103,7 +110,7 @@ class BIM_PT_spatial_decomposition(Panel):
|
||||
return tool.Ifc.get()
|
||||
|
||||
def draw_header(self, context):
|
||||
props = context.scene.BIMSpatialDecompositionProperties
|
||||
props = tool.Spatial.get_spatial_props()
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="") # empty text occupies the left of the row
|
||||
icon = "HIDE_OFF" if props.is_visible else "HIDE_ON"
|
||||
@@ -114,7 +121,7 @@ class BIM_PT_spatial_decomposition(Panel):
|
||||
def draw(self, context):
|
||||
if not SpatialDecompositionData.is_loaded:
|
||||
SpatialDecompositionData.load()
|
||||
self.props = context.scene.BIMSpatialDecompositionProperties
|
||||
self.props = tool.Spatial.get_spatial_props()
|
||||
|
||||
if SpatialDecompositionData.data["default_container"]:
|
||||
row = self.layout.row(align=True)
|
||||
@@ -233,7 +240,7 @@ class BIM_PT_grids(Panel):
|
||||
self.layout.row().operator("mesh.add_grid", icon="ADD", text="Add Grids")
|
||||
|
||||
def draw_header(self, context):
|
||||
props = context.scene.BIMGridProperties
|
||||
props = tool.Spatial.get_grid_props()
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="") # empty text occupies the left of the row
|
||||
icon = "HIDE_OFF" if props.is_visible else "HIDE_ON"
|
||||
@@ -243,25 +250,36 @@ class BIM_PT_grids(Panel):
|
||||
|
||||
|
||||
class BIM_UL_containers_manager(UIList):
|
||||
icon_by_class = {
|
||||
"IfcProject": "FILE",
|
||||
"IfcSite": "WORLD",
|
||||
"IfcBuilding": "HOME",
|
||||
"IfcBuildingStorey": "LINENUMBERS_OFF",
|
||||
"IfcSpace": "ANTIALIASED",
|
||||
"IfcFacilityPart": "MOD_FLUID",
|
||||
"IfcBridgePart": "MOD_FLUID",
|
||||
"IfcFacilityPartCommon": "MOD_FLUID",
|
||||
"IfcMarinePart": "MOD_FLUID",
|
||||
"IfcRailwayPart": "MOD_FLUID",
|
||||
"IfcRoadPart": "MOD_FLUID",
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
self.use_filter_show = True
|
||||
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||
def draw_item(
|
||||
self,
|
||||
context,
|
||||
layout: bpy.types.UILayout,
|
||||
data: BIMSpatialDecompositionProperties,
|
||||
item: BIMContainer,
|
||||
icon,
|
||||
active_data,
|
||||
active_propname,
|
||||
):
|
||||
if item:
|
||||
row = layout.row(align=True)
|
||||
icon = {
|
||||
"IfcProject": "FILE",
|
||||
"IfcSite": "WORLD",
|
||||
"IfcBuilding": "HOME",
|
||||
"IfcBuildingStorey": "LINENUMBERS_OFF",
|
||||
"IfcSpace": "ANTIALIASED",
|
||||
"IfcFacilityPart": "MOD_FLUID",
|
||||
"IfcBridgePart": "MOD_FLUID",
|
||||
"IfcFacilityPartCommon": "MOD_FLUID",
|
||||
"IfcMarinePart": "MOD_FLUID",
|
||||
"IfcRailwayPart": "MOD_FLUID",
|
||||
"IfcRoadPart": "MOD_FLUID",
|
||||
}.get(item.ifc_class, "META_PLANE")
|
||||
icon = self.icon_by_class.get(item.ifc_class, "META_PLANE")
|
||||
split = row.split(factor=0.85)
|
||||
if item.long_name:
|
||||
split2 = split.split(factor=0.7)
|
||||
@@ -275,7 +293,7 @@ class BIM_UL_containers_manager(UIList):
|
||||
row.prop(item, "name", emboss=False, text="", icon=icon)
|
||||
split.prop(item, "elevation", emboss=False, text="")
|
||||
|
||||
def draw_hierarchy(self, row, item):
|
||||
def draw_hierarchy(self, row: bpy.types.UILayout, item: BIMContainer) -> None:
|
||||
if item.level_index:
|
||||
for i in range(0, item.level_index - 1):
|
||||
row.label(text="", icon="BLANK1")
|
||||
@@ -293,11 +311,12 @@ class BIM_UL_containers_manager(UIList):
|
||||
|
||||
def draw_filter(self, context, layout):
|
||||
row = layout.row()
|
||||
row.prop(context.scene.BIMSpatialDecompositionProperties, "container_filter", text="", icon="VIEWZOOM")
|
||||
props = tool.Spatial.get_spatial_props()
|
||||
row.prop(props, "container_filter", text="", icon="VIEWZOOM")
|
||||
|
||||
def filter_items(self, context, data, propname):
|
||||
def filter_items(self, context: bpy.types.Context, data: BIMSpatialDecompositionProperties, propname: str):
|
||||
items = getattr(data, propname)
|
||||
filter_name = context.scene.BIMSpatialDecompositionProperties.container_filter.lower()
|
||||
filter_name = data.container_filter.lower()
|
||||
filter_flags = [self.bitflag_filter_item] * len(items)
|
||||
|
||||
for idx, item in enumerate(items):
|
||||
@@ -313,7 +332,7 @@ class BIM_UL_containers_manager(UIList):
|
||||
return filter_flags, []
|
||||
|
||||
items = getattr(data, propname)
|
||||
filter_name = context.scene.BIMSpatialDecompositionProperties.container_filter
|
||||
filter_name = data.container_filter
|
||||
filtered = bpy.types.UI_UL_list.filter_items_by_name(filter_name, self.bitflag_filter_item, items, "name")
|
||||
return filtered, []
|
||||
|
||||
@@ -326,7 +345,18 @@ class BIM_UL_elements(UIList):
|
||||
icon_id = "DISCLOSURE_TRI_DOWN" if is_expanded else "DISCLOSURE_TRI_RIGHT"
|
||||
row.operator("bim.toggle_container_element", text="", emboss=False, icon=icon_id).element_index = index
|
||||
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index, fit_flag):
|
||||
def draw_item(
|
||||
self,
|
||||
context,
|
||||
layout: bpy.types.UILayout,
|
||||
data: BIMSpatialDecompositionProperties,
|
||||
item: Element,
|
||||
icon,
|
||||
active_data,
|
||||
active_propname,
|
||||
index,
|
||||
fit_flag,
|
||||
):
|
||||
if item:
|
||||
row = layout.row(align=True)
|
||||
for _ in range(item.level):
|
||||
@@ -341,11 +371,12 @@ class BIM_UL_elements(UIList):
|
||||
|
||||
def draw_filter(self, context, layout):
|
||||
row = layout.row()
|
||||
row.prop(context.scene.BIMSpatialDecompositionProperties, "element_filter", text="", icon="VIEWZOOM")
|
||||
props = tool.Spatial.get_spatial_props()
|
||||
row.prop(props, "element_filter", text="", icon="VIEWZOOM")
|
||||
|
||||
def filter_items(self, context, data, propname):
|
||||
def filter_items(self, context: bpy.types.Context, data: BIMSpatialDecompositionProperties, propname: str):
|
||||
items = getattr(data, propname)
|
||||
filter_name = context.scene.BIMSpatialDecompositionProperties.element_filter
|
||||
filter_name = data.element_filter
|
||||
filtered = bpy.types.UI_UL_list.filter_items_by_name(filter_name, self.bitflag_filter_item, items, "name")
|
||||
return filtered, []
|
||||
|
||||
|
||||
@@ -147,11 +147,11 @@ class Geometry(bonsai.core.tool.Geometry):
|
||||
def is_locked(cls, element: ifcopenshell.entity_instance) -> bool:
|
||||
if element.is_a("IfcProject"):
|
||||
return True
|
||||
elif tool.Root.is_spatial_element(element) and bpy.context.scene.BIMSpatialDecompositionProperties.is_locked:
|
||||
elif tool.Root.is_spatial_element(element) and tool.Spatial.get_spatial_props().is_locked:
|
||||
return True
|
||||
elif (
|
||||
element.is_a("IfcPositioningElement") or element.is_a("IfcGrid") or element.is_a("IfcGridAxis")
|
||||
) and bpy.context.scene.BIMGridProperties.is_locked:
|
||||
) and tool.Spatial.get_grid_props().is_locked:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
@@ -137,13 +137,15 @@ class Project(bonsai.core.tool.Project):
|
||||
@classmethod
|
||||
def set_context(cls, context):
|
||||
bonsai.bim.handler.refresh_ui_data()
|
||||
bpy.context.scene.BIMRootProperties.contexts = str(context.id())
|
||||
rprops = tool.Root.get_root_props()
|
||||
rprops.contexts = str(context.id())
|
||||
|
||||
@classmethod
|
||||
def set_default_context(cls):
|
||||
context = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW")
|
||||
if context:
|
||||
bpy.context.scene.BIMRootProperties.contexts = str(context.id())
|
||||
rprops = tool.Root.get_root_props()
|
||||
rprops.contexts = str(context.id())
|
||||
|
||||
@classmethod
|
||||
def set_default_modeling_dimensions(cls):
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
# 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 bpy
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
@@ -27,12 +28,19 @@ import bonsai.core.tool
|
||||
import bonsai.core.aggregate
|
||||
import bonsai.core.geometry
|
||||
import bonsai.tool as tool
|
||||
from typing import Union, Optional, Any, Literal
|
||||
from typing import Union, Optional, Any, Literal, TYPE_CHECKING
|
||||
from bonsai.bim.module.spatial.decorator import GridDecorator
|
||||
from bonsai.bim.module.geometry.decorator import ItemDecorator
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bonsai.bim.module.root.prop import BIMRootProperties
|
||||
|
||||
|
||||
class Root(bonsai.core.tool.Root):
|
||||
@classmethod
|
||||
def get_root_props(cls) -> BIMRootProperties:
|
||||
return bpy.context.scene.BIMRootProperties
|
||||
|
||||
@classmethod
|
||||
def add_tracked_opening(cls, obj: bpy.types.Object, opening_type: Literal["OPENING", "BOOLEAN"]) -> None:
|
||||
"""Add tracked opening or boolean object."""
|
||||
@@ -112,7 +120,7 @@ class Root(bonsai.core.tool.Root):
|
||||
|
||||
@classmethod
|
||||
def get_default_container(cls) -> Optional[ifcopenshell.entity_instance]:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = tool.Spatial.get_spatial_props()
|
||||
if container := props.default_container:
|
||||
try:
|
||||
return tool.Ifc.get().by_id(container)
|
||||
@@ -233,7 +241,7 @@ class Root(bonsai.core.tool.Root):
|
||||
|
||||
@classmethod
|
||||
def reload_grid_decorator(cls) -> None:
|
||||
axes = bpy.context.scene.BIMGridProperties.grid_axes
|
||||
axes = tool.Spatial.get_grid_props().grid_axes
|
||||
axes.clear()
|
||||
for axis in tool.Ifc.get().by_type("IfcGridAxis"):
|
||||
if obj := tool.Ifc.get_object(axis):
|
||||
|
||||
@@ -41,12 +41,31 @@ import json
|
||||
from math import pi
|
||||
from mathutils import Vector, Matrix
|
||||
from shapely import Polygon
|
||||
from typing import Generator, Optional, Union, Literal, List, Any, Iterable
|
||||
from typing import Generator, Optional, Union, Literal, List, Any, Iterable, TYPE_CHECKING
|
||||
from collections import defaultdict
|
||||
from natsort import natsorted
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bonsai.bim.module.spatial.prop import (
|
||||
BIMGridProperties,
|
||||
BIMSpatialDecompositionProperties,
|
||||
BIMObjectSpatialProperties,
|
||||
)
|
||||
|
||||
|
||||
class Spatial(bonsai.core.tool.Spatial):
|
||||
@classmethod
|
||||
def get_spatial_props(cls) -> BIMSpatialDecompositionProperties:
|
||||
return bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
|
||||
@classmethod
|
||||
def get_object_spatial_props(cls, obj: bpy.types.Object) -> BIMObjectSpatialProperties:
|
||||
return obj.BIMObjectSpatialProperties
|
||||
|
||||
@classmethod
|
||||
def get_grid_props(cls) -> BIMGridProperties:
|
||||
return bpy.context.scene.BIMGridProperties
|
||||
|
||||
@classmethod
|
||||
def can_contain(cls, container: ifcopenshell.entity_instance, element_obj: Union[bpy.types.Object, None]) -> bool:
|
||||
if not (element := tool.Ifc.get_entity(element_obj)):
|
||||
@@ -81,7 +100,8 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def disable_editing(cls, obj: bpy.types.Object) -> None:
|
||||
obj.BIMObjectSpatialProperties.is_editing = False
|
||||
props = cls.get_object_spatial_props(obj)
|
||||
props.is_editing = False
|
||||
|
||||
@classmethod
|
||||
def duplicate_object_and_data(cls, obj: bpy.types.Object) -> bpy.types.Object:
|
||||
@@ -92,8 +112,9 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def enable_editing(cls, obj: bpy.types.Object) -> None:
|
||||
obj.BIMObjectSpatialProperties.is_editing = True
|
||||
obj.BIMObjectSpatialProperties.relating_container_object = None
|
||||
props = cls.get_object_spatial_props(obj)
|
||||
props.is_editing = True
|
||||
props.relating_container_object = None
|
||||
|
||||
@classmethod
|
||||
def get_container(cls, element: ifcopenshell.entity_instance) -> Union[ifcopenshell.entity_instance, None]:
|
||||
@@ -207,7 +228,7 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def get_container_elements_grouped_by_classification(cls, container: ifcopenshell.entity_instance) -> dict:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
results = {}
|
||||
if props.should_include_children:
|
||||
elements = ifcopenshell.util.element.get_decomposition(container, is_recursive=True)
|
||||
@@ -254,7 +275,7 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def get_container_elements_grouped_by_type(cls, container: ifcopenshell.entity_instance) -> dict:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
results: defaultdict[str, dict[int, Any]] = defaultdict(dict)
|
||||
if props.should_include_children:
|
||||
elements = ifcopenshell.util.element.get_decomposition(container, is_recursive=True)
|
||||
@@ -280,7 +301,7 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def load_contained_elements(cls) -> None:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
props.elements.clear()
|
||||
if not (container := props.active_container):
|
||||
return
|
||||
@@ -295,7 +316,7 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def load_contained_elements_by_type(cls, container: ifcopenshell.entity_instance) -> None:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
results = cls.get_container_elements_grouped_by_type(container)
|
||||
|
||||
expanded_elements = json.loads(props.expanded_elements)
|
||||
@@ -350,7 +371,7 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def load_contained_elements_by_decomposition(cls, container: ifcopenshell.entity_instance) -> None:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
expanded_elements = json.loads(props.expanded_elements)
|
||||
expanded_ifc_ids = expanded_elements.get("IFC_ID", [])
|
||||
|
||||
@@ -381,7 +402,7 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def load_contained_elements_by_classification(cls, container: ifcopenshell.entity_instance) -> None:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
expanded_elements = json.loads(props.expanded_elements)
|
||||
expanded_classifications = expanded_elements.get("CLASSIFICATION", [])
|
||||
expanded_classifications_r = expanded_elements.get("CLASSIFICATION_R", [])
|
||||
@@ -445,7 +466,7 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def import_spatial_decomposition(cls) -> None:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
previous_container_index = props.active_container_index
|
||||
props.containers.clear()
|
||||
cls.contracted_containers = json.loads(props.contracted_containers)
|
||||
@@ -456,7 +477,7 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
def import_spatial_element(cls, element: ifcopenshell.entity_instance, level_index: int) -> None:
|
||||
if not element.is_a("IfcProject") and not tool.Root.is_spatial_element(element):
|
||||
return
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
new = props.containers.add()
|
||||
new.ifc_class = element.is_a()
|
||||
new["name"] = element.Name or "Unnamed"
|
||||
@@ -485,28 +506,28 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def get_active_container(cls) -> Union[ifcopenshell.entity_instance, None]:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
if props.active_container_index < len(props.containers):
|
||||
container = tool.Ifc.get().by_id(props.containers[props.active_container_index].ifc_definition_id)
|
||||
return container
|
||||
|
||||
@classmethod
|
||||
def contract_container(cls, container: ifcopenshell.entity_instance) -> None:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
contracted_containers = json.loads(props.contracted_containers)
|
||||
contracted_containers.append(container.id())
|
||||
props.contracted_containers = json.dumps(contracted_containers)
|
||||
|
||||
@classmethod
|
||||
def expand_container(cls, container: ifcopenshell.entity_instance) -> None:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
contracted_containers = json.loads(props.contracted_containers)
|
||||
contracted_containers.remove(container.id())
|
||||
props.contracted_containers = json.dumps(contracted_containers)
|
||||
|
||||
@classmethod
|
||||
def toggle_container_element(cls, element_index: int, is_recursive: bool) -> None:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
if props.element_mode == "TYPE":
|
||||
cls.toggle_container_element_by_type(element_index, is_recursive)
|
||||
elif props.element_mode == "DECOMPOSITION":
|
||||
@@ -516,7 +537,7 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def toggle_container_element_by_type(cls, element_index: int, is_recursive: bool) -> None:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
expanded_elements: dict[str, list[Union[str, int]]] = json.loads(props.expanded_elements)
|
||||
|
||||
element = props.elements[element_index]
|
||||
@@ -565,7 +586,7 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def toggle_container_element_by_decomposition(cls, element_index: int, is_recursive: bool) -> None:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
element = props.elements[element_index]
|
||||
expanded_elements: dict[str, list[Union[str, int]]] = json.loads(props.expanded_elements)
|
||||
expanded_elements_list: list[Union[str, int]] = expanded_elements.setdefault("IFC_ID", [])
|
||||
@@ -598,7 +619,7 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def toggle_container_element_by_classification(cls, element_index: int, is_recursive: bool) -> None:
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
expanded_elements: dict[str, list[str]] = json.loads(props.expanded_elements)
|
||||
expanded_elements_list: list[str] = expanded_elements.setdefault("CLASSIFICATION", [])
|
||||
|
||||
@@ -679,7 +700,7 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
|
||||
@classmethod
|
||||
def get_boundary_lines_from_context_visible_objects(cls) -> list[shapely.LineString]:
|
||||
props = props = tool.Model.get_model_props()
|
||||
props = tool.Model.get_model_props()
|
||||
calculation_rl = props.rl3
|
||||
container = tool.Root.get_default_container()
|
||||
container_obj = tool.Ifc.get_object(container)
|
||||
@@ -1154,8 +1175,8 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
def set_default_container(cls, container: ifcopenshell.entity_instance) -> None:
|
||||
from bonsai.bim.module.spatial.data import SpatialDecompositionData
|
||||
|
||||
assert bpy.context
|
||||
bpy.context.scene.BIMSpatialDecompositionProperties.default_container = container.id()
|
||||
props = cls.get_spatial_props()
|
||||
props.default_container = container.id()
|
||||
SpatialDecompositionData.data["default_container"] = SpatialDecompositionData.default_container()
|
||||
|
||||
project = tool.Ifc.get_object(tool.Ifc.get().by_type("IfcProject")[0])
|
||||
@@ -1212,16 +1233,16 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
def set_target_container_as_default(cls) -> None:
|
||||
if (
|
||||
(container := tool.Root.get_default_container())
|
||||
and (obj := tool.Ifc.get_object(container))
|
||||
and bpy.context.active_object
|
||||
and (container_obj := tool.Ifc.get_object(container))
|
||||
and (obj := bpy.context.active_object)
|
||||
):
|
||||
props = bpy.context.active_object.BIMObjectSpatialProperties
|
||||
props.container_obj = obj
|
||||
props = cls.get_object_spatial_props(obj)
|
||||
props.container_obj = container_obj
|
||||
|
||||
@classmethod
|
||||
def get_filtered_elements(cls, should_filter: bool = True) -> Iterable[ifcopenshell.entity_instance]:
|
||||
ifc_file = tool.Ifc.get()
|
||||
props = bpy.context.scene.BIMSpatialDecompositionProperties
|
||||
props = cls.get_spatial_props()
|
||||
container = ifc_file.by_id(props.active_container.ifc_definition_id)
|
||||
element_filter = props.element_filter
|
||||
active_element = props.active_element
|
||||
|
||||
@@ -383,7 +383,8 @@ class TestUsingArrays(NewFile):
|
||||
|
||||
bpy.ops.mesh.primitive_cube_add()
|
||||
obj = bpy.context.active_object
|
||||
bpy.context.scene.BIMRootProperties.ifc_product = "IfcElement"
|
||||
rprops = tool.Root.get_root_props()
|
||||
rprops.ifc_product = "IfcElement"
|
||||
bpy.ops.bim.assign_class(ifc_class="IfcActuator", predefined_type="ELECTRICACTUATOR", userdefined_type="")
|
||||
|
||||
bpy.ops.bim.add_array()
|
||||
@@ -520,7 +521,7 @@ class TestApplyIfcMaterialChanges(NewFile):
|
||||
bpy.ops.bim.add_constr_type_instance(relating_type_id=relating_type_id)
|
||||
with_opening = bpy.context.active_object
|
||||
with_opening.name = "With Opening"
|
||||
props = bpy.context.scene.BIMRootProperties
|
||||
props = tool.Root.get_root_props()
|
||||
props.representation_obj = with_opening
|
||||
bpy.ops.bim.add_element(ifc_product="IfcFeatureElement", ifc_class="IfcOpeningElement")
|
||||
|
||||
|
||||
@@ -97,7 +97,8 @@ class TestSetContext(NewFile):
|
||||
tool.Ifc.set(ifc)
|
||||
context = ifc.createIfcGeometricRepresentationContext()
|
||||
subject.set_context(context)
|
||||
assert bpy.context.scene.BIMRootProperties.contexts == str(context.id())
|
||||
rprops = tool.Root.get_root_props()
|
||||
assert rprops.contexts == str(context.id())
|
||||
|
||||
|
||||
class TestSetDefaultContext(NewFile):
|
||||
@@ -115,7 +116,8 @@ class TestSetDefaultContext(NewFile):
|
||||
target_view="MODEL_VIEW",
|
||||
)
|
||||
subject.set_default_context()
|
||||
assert bpy.context.scene.BIMRootProperties.contexts == str(body.id())
|
||||
rprops = tool.Root.get_root_props()
|
||||
assert rprops.contexts == str(body.id())
|
||||
|
||||
|
||||
class TestSetDefaultModelingDimensions(NewFile):
|
||||
|
||||
@@ -191,8 +191,10 @@ class TestReassignClass(NewFile):
|
||||
slabs = [tool.Ifc.get_object(e) for e in ifc_file.by_type("IfcSlab")]
|
||||
assert len(slabs) == 3
|
||||
tool.Blender.set_objects_selection(context, slabs[0], (slabs[1],))
|
||||
context.scene.BIMRootProperties.ifc_product = "IfcElement"
|
||||
context.scene.BIMRootProperties.ifc_class = "IfcWall"
|
||||
|
||||
props = tool.Root.get_root_props()
|
||||
props.ifc_product = "IfcElement"
|
||||
props.ifc_class = "IfcWall"
|
||||
bpy.ops.bim.reassign_class()
|
||||
|
||||
assert len(ifc_file.by_type("IfcWall")) == 3
|
||||
|
||||
@@ -129,7 +129,8 @@ class TestDisableEditing(NewFile):
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
subject.enable_editing(obj)
|
||||
subject.disable_editing(obj)
|
||||
assert obj.BIMObjectSpatialProperties.is_editing is False
|
||||
props = tool.Spatial.get_object_spatial_props(obj)
|
||||
assert props.is_editing is False
|
||||
|
||||
|
||||
class TestDuplicateObjectAndData(NewFile):
|
||||
@@ -148,7 +149,8 @@ class TestEnableEditing(NewFile):
|
||||
def test_run(self):
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
subject.enable_editing(obj)
|
||||
assert obj.BIMObjectSpatialProperties.is_editing is True
|
||||
props = tool.Spatial.get_object_spatial_props(obj)
|
||||
assert props.is_editing is True
|
||||
|
||||
|
||||
class TestGetContainer(NewFile):
|
||||
|
||||
Reference in New Issue
Block a user