diff --git a/src/bonsai/bonsai/bim/import_ifc.py b/src/bonsai/bonsai/bim/import_ifc.py
index 8747f28891..1332258c12 100644
--- a/src/bonsai/bonsai/bim/import_ifc.py
+++ b/src/bonsai/bonsai/bim/import_ifc.py
@@ -1033,7 +1033,7 @@ class IfcImporter:
element: ifcopenshell.entity_instance,
shape: Union[ifcopenshell.geom.ShapeElementType, ifcopenshell.geom.ShapeType],
) -> bpy.types.Curve:
- if hasattr(shape, "geometry"):
+ if isinstance(shape, ifcopenshell.geom.ShapeElementType):
geometry = shape.geometry
else:
geometry = shape
@@ -1066,7 +1066,7 @@ class IfcImporter:
cartesian_point_offset: Union[npt.NDArray[np.float64], Literal[False]] = None,
) -> Union[bpy.types.Mesh, None]:
try:
- if hasattr(shape, "geometry"):
+ if isinstance(shape, ifcopenshell.geom.ShapeElementType):
# shape is ShapeElementType
geometry = shape.geometry
else:
diff --git a/src/bonsai/bonsai/bim/module/constraint/operator.py b/src/bonsai/bonsai/bim/module/constraint/operator.py
index 4ae0dde395..5b291106f8 100644
--- a/src/bonsai/bonsai/bim/module/constraint/operator.py
+++ b/src/bonsai/bonsai/bim/module/constraint/operator.py
@@ -17,12 +17,27 @@
# along with Bonsai. If not, see .
import bpy
-import json
import ifcopenshell.api
import ifcopenshell.api.constraint
-import ifcopenshell.util.attribute
import bonsai.bim.helper
import bonsai.tool as tool
+from typing import TYPE_CHECKING
+
+
+def get_active_object(context: bpy.types.Context, obj_name: str) -> bpy.types.Object:
+ if obj_name:
+ obj = bpy.data.objects[obj_name]
+ else:
+ assert (obj := context.active_object)
+ return obj
+
+
+def get_selected_objects(context: bpy.types.Context, obj_name: str) -> list[bpy.types.Object]:
+ if obj_name:
+ objs = [bpy.data.objects[obj_name]]
+ else:
+ objs = context.selected_objects
+ return objs
class LoadObjectives(bpy.types.Operator):
@@ -31,7 +46,7 @@ class LoadObjectives(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
- props = context.scene.BIMConstraintProperties
+ props = tool.Blender.get_constraint_props()
props.constraints.clear()
for constraint in tool.Ifc.get().by_type("IfcObjective"):
new = props.constraints.add()
@@ -48,7 +63,8 @@ class DisableConstraintEditingUI(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
- context.scene.BIMConstraintProperties.is_editing = ""
+ props = tool.Blender.get_constraint_props()
+ props.is_editing = ""
bpy.ops.bim.disable_editing_constraint()
return {"FINISHED"}
@@ -59,8 +75,11 @@ class EnableEditingConstraint(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
constraint: bpy.props.IntProperty()
+ if TYPE_CHECKING:
+ constraint: int
+
def execute(self, context):
- props = context.scene.BIMConstraintProperties
+ props = tool.Blender.get_constraint_props()
props.constraint_attributes.clear()
bonsai.bim.helper.import_attributes2(tool.Ifc.get().by_id(self.constraint), props.constraint_attributes)
props.active_constraint_id = self.constraint
@@ -73,7 +92,8 @@ class DisableEditingConstraint(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
- context.scene.BIMConstraintProperties.active_constraint_id = 0
+ props = tool.Blender.get_constraint_props()
+ props.active_constraint_id = 0
return {"FINISHED"}
@@ -83,7 +103,7 @@ class AddObjective(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
- result = ifcopenshell.api.run("constraint.add_objective", tool.Ifc.get())
+ result = ifcopenshell.api.constraint.add_objective(tool.Ifc.get())
bpy.ops.bim.load_objectives()
bpy.ops.bim.enable_editing_constraint(constraint=result.id())
return {"FINISHED"}
@@ -95,7 +115,7 @@ class EditObjective(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
- props = context.scene.BIMConstraintProperties
+ props = tool.Blender.get_constraint_props()
attributes = bonsai.bim.helper.export_attributes(props.constraint_attributes)
ifc_file = tool.Ifc.get()
ifcopenshell.api.constraint.edit_objective(
@@ -113,12 +133,13 @@ class RemoveConstraint(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"}
constraint: bpy.props.IntProperty()
+ if TYPE_CHECKING:
+ constraint: int
+
def _execute(self, context):
- props = context.scene.BIMConstraintProperties
+ props = tool.Blender.get_constraint_props()
self.file = tool.Ifc.get()
- ifcopenshell.api.run(
- "constraint.remove_constraint", self.file, **{"constraint": self.file.by_id(self.constraint)}
- )
+ ifcopenshell.api.constraint.remove_constraint(self.file, constraint=self.file.by_id(self.constraint))
if props.is_editing == "IfcObjective":
bpy.ops.bim.load_objectives()
return {"FINISHED"}
@@ -130,9 +151,12 @@ class EnableAssigningConstraint(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
obj: bpy.props.StringProperty()
+ if TYPE_CHECKING:
+ obj: str
+
def execute(self, context):
- obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object
- props = obj.BIMObjectConstraintProperties
+ obj = get_active_object(context, self.obj)
+ props = tool.Blender.get_object_constraint_props(obj)
if props.available_constraint_types == "IfcObjective":
bpy.ops.bim.load_objectives()
props.is_adding = props.available_constraint_types
@@ -145,9 +169,12 @@ class DisableAssigningConstraint(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
obj: bpy.props.StringProperty()
+ if TYPE_CHECKING:
+ obj: str
+
def execute(self, context):
- obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object
- props = obj.BIMObjectConstraintProperties
+ obj = get_active_object(context, self.obj)
+ props = tool.Blender.get_object_constraint_props(obj)
props.is_adding = ""
return {"FINISHED"}
@@ -159,8 +186,13 @@ class AssignConstraint(bpy.types.Operator, tool.Ifc.Operator):
obj: bpy.props.StringProperty()
constraint: bpy.props.IntProperty()
+ if TYPE_CHECKING:
+ obj: str
+ constraint: int
+
def _execute(self, context):
self.file = tool.Ifc.get()
+ objs = get_selected_objects(context, self.obj)
objs = [bpy.data.objects[self.obj]] if self.obj else context.selected_objects
products = [
self.file.by_id(obj_id)
@@ -168,13 +200,10 @@ class AssignConstraint(bpy.types.Operator, tool.Ifc.Operator):
if (obj_id := tool.Blender.get_object_bim_props(obj).ifc_definition_id)
]
if products:
- ifcopenshell.api.run(
- "constraint.assign_constraint",
+ ifcopenshell.api.constraint.assign_constraint(
self.file,
- **{
- "products": products,
- "constraint": self.file.by_id(self.constraint),
- },
+ products=products,
+ constraint=self.file.by_id(self.constraint),
)
return {"FINISHED"}
@@ -186,21 +215,22 @@ class UnassignConstraint(bpy.types.Operator, tool.Ifc.Operator):
obj: bpy.props.StringProperty()
constraint: bpy.props.IntProperty()
+ if TYPE_CHECKING:
+ obj: str
+ constraint: int
+
def _execute(self, context):
self.file = tool.Ifc.get()
- objs = [bpy.data.objects[self.obj]] if self.obj else context.selected_objects
+ objs = get_selected_objects(context, self.obj)
products = [
self.file.by_id(obj_id)
for obj in objs
if (obj_id := tool.Blender.get_object_bim_props(obj).ifc_definition_id)
]
if products:
- ifcopenshell.api.run(
- "constraint.unassign_constraint",
+ ifcopenshell.api.constraint.unassign_constraint(
self.file,
- **{
- "products": products,
- "constraint": self.file.by_id(self.constraint),
- },
+ products=products,
+ constraint=self.file.by_id(self.constraint),
)
return {"FINISHED"}
diff --git a/src/bonsai/bonsai/bim/module/constraint/prop.py b/src/bonsai/bonsai/bim/module/constraint/prop.py
index b773af506a..ec66f78211 100644
--- a/src/bonsai/bonsai/bim/module/constraint/prop.py
+++ b/src/bonsai/bonsai/bim/module/constraint/prop.py
@@ -32,6 +32,7 @@ from bpy.props import (
FloatVectorProperty,
CollectionProperty,
)
+from typing import TYPE_CHECKING, Literal
def get_available_constraint_types(self, context):
@@ -44,6 +45,10 @@ class Constraint(PropertyGroup):
name: StringProperty(name="Name")
ifc_definition_id: IntProperty(name="IFC Definition ID")
+ if TYPE_CHECKING:
+ name: str
+ ifc_definition_id: int
+
class BIMConstraintProperties(PropertyGroup):
constraint_attributes: CollectionProperty(name="Constraint Attributes", type=Attribute)
@@ -52,7 +57,18 @@ class BIMConstraintProperties(PropertyGroup):
active_constraint_index: IntProperty(name="Active Constraint Index")
is_editing: StringProperty(name="Is Editing")
+ if TYPE_CHECKING:
+ constraint_attributes: bpy.types.bpy_prop_collection_idprop[Attribute]
+ active_constraint_id: int
+ constraints: bpy.types.bpy_prop_collection_idprop[Constraint]
+ active_constraint_index: int
+ is_editing: str
+
class BIMObjectConstraintProperties(PropertyGroup):
is_adding: StringProperty(name="Is Adding")
available_constraint_types: EnumProperty(items=get_available_constraint_types, name="Available Constraint Types")
+
+ if TYPE_CHECKING:
+ is_adding: str
+ available_constraint_types: Literal["IfcObjective"]
diff --git a/src/bonsai/bonsai/bim/module/constraint/ui.py b/src/bonsai/bonsai/bim/module/constraint/ui.py
index 3693e9565a..61b335d782 100644
--- a/src/bonsai/bonsai/bim/module/constraint/ui.py
+++ b/src/bonsai/bonsai/bim/module/constraint/ui.py
@@ -16,10 +16,15 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see .
+from __future__ import annotations
import bonsai.tool as tool
from bpy.types import Panel, UIList
from bonsai.bim.helper import draw_attributes
from bonsai.bim.module.constraint.data import ConstraintsData, ObjectConstraintsData
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+ from bonsai.bim.module.constraint.prop import BIMConstraintProperties, BIMObjectConstraintProperties, Constraint
class BIM_PT_constraints(Panel):
@@ -39,7 +44,7 @@ class BIM_PT_constraints(Panel):
if not ConstraintsData.is_loaded:
ConstraintsData.load()
- self.props = context.scene.BIMConstraintProperties
+ self.props = tool.Blender.get_constraint_props()
if not self.props.is_editing or self.props.is_editing == "IfcObjective":
row = self.layout.row(align=True)
@@ -91,8 +96,8 @@ class BIM_PT_object_constraints(Panel):
obj = context.active_object
assert obj
self.oprops = tool.Blender.get_object_bim_props(obj)
- self.sprops = context.scene.BIMConstraintProperties
- self.props = obj.BIMObjectConstraintProperties
+ self.sprops = tool.Blender.get_constraint_props()
+ self.props = tool.Blender.get_object_constraint_props(obj)
self.file = tool.Ifc.get()
self.draw_add_ui()
@@ -131,15 +136,24 @@ class BIM_PT_object_constraints(Panel):
class BIM_UL_constraints(UIList):
- def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
+ def draw_item(
+ self,
+ context,
+ layout,
+ data: BIMConstraintProperties,
+ item: Constraint,
+ icon,
+ active_data,
+ active_propname,
+ ):
if item:
row = layout.row(align=True)
row.label(text=item.name)
- if context.scene.BIMConstraintProperties.active_constraint_id == item.ifc_definition_id:
- if context.scene.BIMConstraintProperties.is_editing == "IfcObjective":
+ if data.active_constraint_id == item.ifc_definition_id:
+ if data.is_editing == "IfcObjective":
row.operator("bim.edit_objective", text="", icon="CHECKMARK")
row.operator("bim.disable_editing_constraint", text="", icon="CANCEL")
- elif context.scene.BIMConstraintProperties.active_constraint_id:
+ elif data.active_constraint_id:
row.operator("bim.remove_constraint", text="", icon="X").constraint = item.ifc_definition_id
else:
op = row.operator("bim.enable_editing_constraint", text="", icon="GREASEPENCIL")
@@ -148,7 +162,16 @@ class BIM_UL_constraints(UIList):
class BIM_UL_object_constraints(UIList):
- def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
+ def draw_item(
+ self,
+ context,
+ layout,
+ data: BIMObjectConstraintProperties,
+ item: Constraint,
+ icon,
+ active_data,
+ active_propname,
+ ):
if item:
row = layout.row(align=True)
row.label(text=item.name)
diff --git a/src/bonsai/bonsai/bim/module/layer/operator.py b/src/bonsai/bonsai/bim/module/layer/operator.py
index 5480c86034..079c5477f6 100644
--- a/src/bonsai/bonsai/bim/module/layer/operator.py
+++ b/src/bonsai/bonsai/bim/module/layer/operator.py
@@ -17,13 +17,21 @@
# along with Bonsai. If not, see .
import bpy
-import json
import ifcopenshell.api
import ifcopenshell.api.layer
import ifcopenshell.util.element
-import ifcopenshell.util.attribute
import bonsai.bim.helper
import bonsai.tool as tool
+from typing import TYPE_CHECKING
+
+
+def get_active_mesh(context: bpy.types.Context, mesh_name: str) -> bpy.types.Mesh:
+ if mesh_name:
+ item_mesh = bpy.data.meshes[mesh_name]
+ else:
+ assert (obj := context.active_object)
+ assert isinstance(item_mesh := obj.data, bpy.types.Mesh)
+ return item_mesh
class LoadLayers(bpy.types.Operator):
@@ -32,10 +40,10 @@ class LoadLayers(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
- self.file = tool.Ifc.get()
- props = context.scene.BIMLayerProperties
+ ifc_file = tool.Ifc.get()
+ props = tool.Layer.get_layer_props()
props.layers.clear()
- for layer in tool.Ifc.get().by_type("IfcPresentationLayerAssignment"):
+ for layer in ifc_file.by_type("IfcPresentationLayerAssignment"):
new = props.layers.add()
new.name = layer.Name or "Unnamed"
new.ifc_definition_id = layer.id()
@@ -57,7 +65,8 @@ class DisableLayerEditingUI(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
- context.scene.BIMLayerProperties.is_editing = False
+ props = tool.Layer.get_layer_props()
+ props.is_editing = False
return {"FINISHED"}
@@ -67,8 +76,11 @@ class EnableEditingLayer(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
layer: bpy.props.IntProperty()
+ if TYPE_CHECKING:
+ layer: int
+
def execute(self, context):
- props = context.scene.BIMLayerProperties
+ props = tool.Layer.get_layer_props()
props.layer_attributes.clear()
bonsai.bim.helper.import_attributes2(tool.Ifc.get().by_id(self.layer), props.layer_attributes)
props.active_layer_id = self.layer
@@ -81,7 +93,8 @@ class DisableEditingLayer(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
- context.scene.BIMLayerProperties.active_layer_id = 0
+ props = tool.Layer.get_layer_props()
+ props.active_layer_id = 0
return {"FINISHED"}
@@ -92,7 +105,7 @@ class AddPresentationLayer(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
- props = context.scene.BIMLayerProperties
+ props = tool.Layer.get_layer_props()
ifc_file = tool.Ifc.get()
if props.layer_type == "IfcPresentationLayerWithStyle":
layer = ifcopenshell.api.layer.add_layer_with_style(ifc_file)
@@ -109,7 +122,7 @@ class EditPresentationLayer(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
- props = context.scene.BIMLayerProperties
+ props = tool.Layer.get_layer_props()
attributes = bonsai.bim.helper.export_attributes(props.layer_attributes)
ifc_file = tool.Ifc.get()
ifcopenshell.api.layer.edit_layer(ifc_file, layer=ifc_file.by_id(props.active_layer_id), attributes=attributes)
@@ -123,10 +136,12 @@ class RemovePresentationLayer(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"}
layer: bpy.props.IntProperty()
+ if TYPE_CHECKING:
+ layer: int
+
def _execute(self, context):
- props = context.scene.BIMLayerProperties
- self.file = tool.Ifc.get()
- ifcopenshell.api.run("layer.remove_layer", self.file, **{"layer": self.file.by_id(self.layer)})
+ ifc_file = tool.Ifc.get()
+ ifcopenshell.api.layer.remove_layer(ifc_file, layer=ifc_file.by_id(self.layer))
bpy.ops.bim.load_layers()
return {"FINISHED"}
@@ -139,16 +154,17 @@ class AssignPresentationLayer(bpy.types.Operator, tool.Ifc.Operator):
item: bpy.props.StringProperty()
layer: bpy.props.IntProperty()
+ if TYPE_CHECKING:
+ item: str
+ layer: int
+
def _execute(self, context):
- item = bpy.data.meshes.get(self.item) if self.item else context.active_object.data
- self.file = tool.Ifc.get()
- ifcopenshell.api.run(
- "layer.assign_layer",
- self.file,
- **{
- "items": [self.file.by_id(tool.Geometry.get_mesh_props(item).ifc_definition_id)],
- "layer": self.file.by_id(self.layer),
- },
+ item = get_active_mesh(context, self.item)
+ ifc_file = tool.Ifc.get()
+ ifcopenshell.api.layer.assign_layer(
+ ifc_file,
+ items=[ifc_file.by_id(tool.Geometry.get_mesh_props(item).ifc_definition_id)],
+ layer=ifc_file.by_id(self.layer),
)
return {"FINISHED"}
@@ -161,8 +177,12 @@ class UnassignPresentationLayer(bpy.types.Operator, tool.Ifc.Operator):
item: bpy.props.StringProperty()
layer: bpy.props.IntProperty()
+ if TYPE_CHECKING:
+ item: str
+ layer: int
+
def _execute(self, context):
- item = bpy.data.meshes.get(self.item) if self.item else context.active_object.data
+ item = get_active_mesh(context, self.item)
ifc_file = tool.Ifc.get()
representation = tool.Geometry.get_data_representation(item)
assert representation
@@ -176,6 +196,9 @@ class SelectLayerProducts(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
layer: bpy.props.IntProperty()
+ if TYPE_CHECKING:
+ layer: int
+
def execute(self, context):
elements = ifcopenshell.util.element.get_elements_by_layer(tool.Ifc.get(), tool.Ifc.get().by_id(self.layer))
for obj in context.visible_objects:
@@ -192,6 +215,9 @@ class SelectLayerInLayerUI(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
layer_id: bpy.props.IntProperty()
+ if TYPE_CHECKING:
+ layer_id: int
+
def execute(self, context):
props = tool.Layer.get_layer_props()
ifc_file = tool.Ifc.get()
diff --git a/src/bonsai/bonsai/bim/module/layer/prop.py b/src/bonsai/bonsai/bim/module/layer/prop.py
index 6f0dbd7c9c..079ba262de 100644
--- a/src/bonsai/bonsai/bim/module/layer/prop.py
+++ b/src/bonsai/bonsai/bim/module/layer/prop.py
@@ -59,6 +59,14 @@ class Layer(PropertyGroup):
update=lambda self, context: update_layer_property(self, context, property="blocked"),
)
+ if TYPE_CHECKING:
+ name: str
+ ifc_definition_id: int
+ with_style: bool
+ on: bool
+ frozen: bool
+ blocked: bool
+
class BIMLayerProperties(PropertyGroup):
layer_attributes: CollectionProperty(name="Layer Attributes", type=Attribute)
diff --git a/src/bonsai/bonsai/bim/module/layer/ui.py b/src/bonsai/bonsai/bim/module/layer/ui.py
index 609cb62815..d7fcdec215 100644
--- a/src/bonsai/bonsai/bim/module/layer/ui.py
+++ b/src/bonsai/bonsai/bim/module/layer/ui.py
@@ -16,11 +16,16 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see .
+from __future__ import annotations
import bpy
import bonsai.tool as tool
from bpy.types import Panel, UIList, Mesh
from bonsai.bim.helper import draw_attributes
from bonsai.bim.module.layer.data import LayersData
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+ from bonsai.bim.module.layer.prop import BIMLayerProperties, Layer
class BIM_PT_layers(Panel):
@@ -40,7 +45,7 @@ class BIM_PT_layers(Panel):
if not LayersData.is_loaded:
LayersData.load()
- self.props = context.scene.BIMLayerProperties
+ self.props = tool.Layer.get_layer_props()
row = self.layout.row(align=True)
row.label(text=f"{LayersData.data['total_layers']} Layers Found", icon="STICKY_UVS_LOC")
@@ -71,7 +76,16 @@ class BIM_PT_layers(Panel):
class BIM_UL_layers(UIList):
- def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
+ def draw_item(
+ self,
+ context: bpy.types.Context,
+ layout: bpy.types.UILayout,
+ data: BIMLayerProperties,
+ item: Layer,
+ icon,
+ active_data,
+ active_propname,
+ ):
if item:
row = layout.row(align=True)
row.label(text=item.name)
@@ -89,12 +103,12 @@ class BIM_UL_layers(UIList):
row.prop(item, "frozen", text="", icon="FREEZE" if item.frozen else "MESH_PLANE", emboss=False)
row.prop(item, "blocked", text="", icon="LOCKED" if item.blocked else "UNLOCKED", emboss=False)
- if context.scene.BIMLayerProperties.active_layer_id == item.ifc_definition_id:
+ if data.active_layer_id == item.ifc_definition_id:
op = row.operator("bim.select_layer_products", text="", icon="RESTRICT_SELECT_OFF")
op.layer = item.ifc_definition_id
row.operator("bim.edit_presentation_layer", text="", icon="CHECKMARK")
row.operator("bim.disable_editing_layer", text="", icon="CANCEL")
- elif context.scene.BIMLayerProperties.active_layer_id:
+ elif data.active_layer_id:
op = row.operator("bim.select_layer_products", text="", icon="RESTRICT_SELECT_OFF")
op.layer = item.ifc_definition_id
row.operator("bim.remove_presentation_layer", text="", icon="X").layer = item.ifc_definition_id
diff --git a/src/bonsai/bonsai/tool/blender.py b/src/bonsai/bonsai/tool/blender.py
index 7ad78d2339..c02a9ce1d8 100644
--- a/src/bonsai/bonsai/tool/blender.py
+++ b/src/bonsai/bonsai/tool/blender.py
@@ -50,6 +50,7 @@ if TYPE_CHECKING:
from bonsai.bim.prop import BIMProperties, BIMObjectProperties
from bonsai.bim.module.attribute.prop import BIMAttributeProperties
from bonsai.bim.module.csv.prop import CsvProperties
+ from bonsai.bim.module.constraint.prop import BIMConstraintProperties, BIMObjectConstraintProperties
from bonsai.bim.module.diff.prop import DiffProperties
T = TypeVar("T")
@@ -1644,13 +1645,24 @@ class Blender(bonsai.core.tool.Blender):
dct = {cls.bl_idname: cls.ifc_element_type for cls in (BimTool.__subclasses__())}
return types.MappingProxyType(dct)
+ @classmethod
+ def get_object_constraint_props(cls, obj: bpy.types.Object) -> BIMObjectConstraintProperties:
+ return obj.BIMObjectConstraintProperties
+
+ @classmethod
+ def get_constraint_props(cls) -> BIMConstraintProperties:
+ assert (scene := bpy.context.scene)
+ return scene.BIMConstraintProperties
+
@classmethod
def get_csv_props(cls) -> CsvProperties:
- return bpy.context.scene.CsvProperties
+ assert (scene := bpy.context.scene)
+ return scene.CsvProperties
@classmethod
def get_diff_props(cls) -> DiffProperties:
- return bpy.context.scene.DiffProperties
+ assert (scene := bpy.context.scene)
+ return scene.DiffProperties
@classmethod
def get_bim_props(cls, scene: Optional[bpy.types.Scene] = None) -> BIMProperties:
diff --git a/src/bonsai/bonsai/tool/loader.py b/src/bonsai/bonsai/tool/loader.py
index 6f58bbc665..05dbe0b594 100644
--- a/src/bonsai/bonsai/tool/loader.py
+++ b/src/bonsai/bonsai/tool/loader.py
@@ -101,7 +101,7 @@ class Loader(bonsai.core.tool.Loader):
shape: Union[ifcopenshell.geom.ShapeElementType, ifcopenshell.geom.ShapeType],
mesh: tool.Geometry.TYPES_WITH_MESH_PROPERTIES,
) -> None:
- geometry = shape.geometry if hasattr(shape, "geometry") else shape
+ geometry = shape.geometry if isinstance(shape, ifcopenshell.geom.ShapeElementType) else shape
tool.Geometry.get_mesh_props(mesh).ifc_definition_id = int(geometry.id.split("-")[0])
@classmethod
diff --git a/src/bonsai/bonsai/tool/sequence.py b/src/bonsai/bonsai/tool/sequence.py
index f89afe3fec..eb8dd03277 100644
--- a/src/bonsai/bonsai/tool/sequence.py
+++ b/src/bonsai/bonsai/tool/sequence.py
@@ -39,6 +39,7 @@ from dateutil import parser
from datetime import datetime
from datetime import time as datetime_time
from typing import Optional, Any, Union, Literal, TYPE_CHECKING, Iterable
+from mathutils import Color
if TYPE_CHECKING:
import bonsai.bim.prop
@@ -1449,7 +1450,7 @@ class Sequence(bonsai.core.tool.Sequence):
obj.keyframe_insert(data_path="color", frame=product_frame["COMPLETED"])
@classmethod
- def animate_operation(cls, obj, start_frame, product_frame, color):
+ def animate_operation(cls, obj: bpy.types.Object, start_frame: int, product_frame, color: Color) -> None:
if cls.earliest_frame is None or product_frame["STARTED"] < cls.earliest_frame:
obj.color = (1.0, 1.0, 1.0, 1)
obj.keyframe_insert(data_path="color", frame=start_frame)
diff --git a/src/ifcopenshell-python/ifcopenshell/__init__.py b/src/ifcopenshell-python/ifcopenshell/__init__.py
index 0942269ceb..97083d0938 100644
--- a/src/ifcopenshell-python/ifcopenshell/__init__.py
+++ b/src/ifcopenshell-python/ifcopenshell/__init__.py
@@ -260,7 +260,7 @@ def schema_by_name(
return ifcopenshell_wrapper.schema_by_name(schema)
-def guess_format(path: Path) -> Union[str, None]:
+def guess_format(path: Path) -> Literal[".ifc", ".ifcZIP", ".ifcXML", ".ifcJSON", ".ifcSQLite", None]:
"""Guesses the IFC format using file extension
IFCs may be serialised as different formats. The most common is a ``.ifc``
@@ -273,8 +273,6 @@ def guess_format(path: Path) -> Union[str, None]:
Users generally won't call this function. The :func:`open` function uses
this internally to guess the file format.
-
- :return: Either .ifc, .ifcZIP, .ifcXML, .ifcJSON, .ifcSQLite, or None.
"""
suffix = path.suffix.lower()
if suffix == ".ifc":
diff --git a/src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.pyi b/src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.pyi
index 9f8db92bc6..5e631804ae 100644
--- a/src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.pyi
+++ b/src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.pyi
@@ -127,7 +127,7 @@ class BRep(Representation):
class BRepElement(Element):
def calculate_projected_surface_area(self, along_x, along_y, along_z): ...
@property
- def geometry(self): ...
+ def geometry(self) -> BRep: ...
def geometry_pointer(self): ...
@property
def surface_area(self): ...
@@ -361,7 +361,7 @@ class Serialization(Representation):
class SerializedElement(Element):
@property
- def geometry(self): ...
+ def geometry(self) -> Serialization: ...
class SerializerSettings:
def get_(self, name): ...
@@ -744,7 +744,7 @@ class ellipse(curve):
def matrix(self): ...
class entity(declaration):
- def all_attributes(self): ...
+ def all_attributes(self) -> tuple[attribute, ...]: ...
def all_inverse_attributes(self): ...
def argument_types(self): ...
def as_entity(self): ...
@@ -1127,10 +1127,10 @@ class revolve(sweep):
class schema_definition:
def declaration_by_name(self, *args: str) -> declaration: ...
def declarations(self) -> tuple[declaration, ...]: ...
- def entities(self): ...
+ def entities(self) -> tuple[entity, ...]: ...
def enumeration_types(self): ...
def instantiate(self, decl, data): ...
- def name(self): ...
+ def name(self) -> str: ...
def select_types(self): ...
def type_declarations(self): ...
@@ -1446,7 +1446,7 @@ def polygons_to_svg(*args): ...
def read(data): ...
def register_schema(arg1): ...
def schema_by_name(arg1: str) -> schema_definition: ...
-def schema_names(): ...
+def schema_names() -> tuple[str, ...]: ...
def serialise(schema_name, shape_str, advanced): ...
def set_feature(x, v): ...
def set_log_format_json(): ...
@@ -1455,6 +1455,6 @@ def svg_to_line_segments(data, class_name): ...
def svg_to_polygons(data, class_name): ...
def taxonomy_item_repr(i): ...
def tesselate(schema_name, shape_str, d): ...
-def turn_off_detailed_logging(): ...
-def turn_on_detailed_logging(): ...
-def version(): ...
+def turn_off_detailed_logging() -> None: ...
+def turn_on_detailed_logging() -> None: ...
+def version() -> str: ...
diff --git a/src/ifcopenshell-python/ifcopenshell/sql.py b/src/ifcopenshell-python/ifcopenshell/sql.py
index a77b5a85af..fc7f7f8fa9 100644
--- a/src/ifcopenshell-python/ifcopenshell/sql.py
+++ b/src/ifcopenshell-python/ifcopenshell/sql.py
@@ -96,9 +96,9 @@ class sqlite(file):
self.preprocess_schema()
def preprocess_schema(self) -> None:
- self.ifc_class_subtypes = {}
+ self.ifc_class_subtypes: dict[str, Any] = {}
self.ifc_class_attributes: dict[str, dict[str, ifcopenshell_wrapper.attribute]] = {}
- self.ifc_class_inverse_attributes = {}
+ self.ifc_class_inverse_attributes: dict[str, Any] = {}
self.ifc_class_references = {}
self.ifc_class_inverses = {}
diff --git a/src/ifcopenshell-python/ifcopenshell/util/constraint.py b/src/ifcopenshell-python/ifcopenshell/util/constraint.py
index f4e18d61b3..2c370aa997 100644
--- a/src/ifcopenshell-python/ifcopenshell/util/constraint.py
+++ b/src/ifcopenshell-python/ifcopenshell/util/constraint.py
@@ -27,9 +27,7 @@ def get_constraints(product: ifcopenshell.entity_instance) -> list[ifcopenshell.
Retrieves the constraints assigned to the `product`.
:param product: The IFC element.
- :type product: ifcopenshell.entity_instance
:return: List of assigned constraints.
- :rtype: list[ifcopenshell.entity_instance]
"""
constraints = []
for rel in product.HasAssociations or []:
@@ -43,9 +41,7 @@ def get_constrained_elements(constraint: ifcopenshell.entity_instance) -> set[if
Retrieves the elements constrained by a `constraint`.
:param product: The IFC element.
- :type product: ifcopenshell.entity_instance
:return: Set of elements constrained by a `constrant`.
- :rtype: set[ifcopenshell.entity_instance]
"""
elements = set()
for rel in constraint.file.get_inverse(constraint):
@@ -59,9 +55,7 @@ def get_metrics(constraint: ifcopenshell.entity_instance) -> list[ifcopenshell.e
Retrieves the list of nested constraints for a IfcObjective `constraint`.
:param product: IfcObjective constraint.
- :type product: ifcopenshell.entity_instance
:return: List of nested constraints.
- :rtype: list[ifcopenshell.entity_instance]
"""
metrics = []