diff --git a/src/bonsai/bonsai/bim/ifc.py b/src/bonsai/bonsai/bim/ifc.py index 9576c60459..f6413ee798 100644 --- a/src/bonsai/bonsai/bim/ifc.py +++ b/src/bonsai/bonsai/bim/ifc.py @@ -407,7 +407,12 @@ class IfcStore: obj.BIMObjectProperties.ifc_definition_id = 0 @staticmethod - def execute_ifc_operator(operator: tool.Ifc.Operator, context: bpy.types.Context, is_invoke=False) -> set[str]: + def execute_ifc_operator( + operator: tool.Ifc.Operator, + context: bpy.types.Context, + event=None, + method: Literal["EXECUTE", "INVOKE", "MODAL"] = "EXECUTE", + ) -> set[str]: bonsai.last_actions.append({"type": "operator", "name": operator.bl_idname}) bpy.context.scene.BIMProperties.is_dirty = True is_top_level_operator = not bool(IfcStore.current_transaction) @@ -436,10 +441,12 @@ class IfcStore: bonsai.bim.handler.refresh_ui_data() try: - if is_invoke: - result = getattr(operator, "_invoke")(context, None) - else: + if method == "EXECUTE": result = getattr(operator, "_execute")(context) + elif method == "INVOKE": + result = getattr(operator, "_invoke")(context, event) + elif method == "MODAL": + result = getattr(operator, "_modal")(context, event) except: bonsai.last_error = traceback.format_exc() # Try to ensure undo will work since Blender undo does work in case of errors. diff --git a/src/bonsai/bonsai/bim/module/geometry/operator.py b/src/bonsai/bonsai/bim/module/geometry/operator.py index c07f427851..c5d82936fb 100644 --- a/src/bonsai/bonsai/bim/module/geometry/operator.py +++ b/src/bonsai/bonsai/bim/module/geometry/operator.py @@ -1913,7 +1913,7 @@ class OverrideModeSetEdit(bpy.types.Operator, tool.Ifc.Operator): bl_options = {"REGISTER", "UNDO"} def invoke(self, context, event): - return IfcStore.execute_ifc_operator(self, context, is_invoke=True) + return IfcStore.execute_ifc_operator(self, context, event, method="INVOKE") def _invoke(self, context, event): if not tool.Ifc.get(): @@ -2089,7 +2089,7 @@ class OverrideModeSetObject(bpy.types.Operator, tool.Ifc.Operator): should_save: bpy.props.BoolProperty(name="Should Save", default=True) def invoke(self, context, event): - return IfcStore.execute_ifc_operator(self, context, is_invoke=True) + return IfcStore.execute_ifc_operator(self, context, event, method="INVOKE") def _invoke(self, context: bpy.types.Context, event: bpy.types.Event) -> set[str]: if not tool.Ifc.get(): diff --git a/src/bonsai/bonsai/bim/module/model/product.py b/src/bonsai/bonsai/bim/module/model/product.py index 7edf9323f7..06ae1a4fa0 100644 --- a/src/bonsai/bonsai/bim/module/model/product.py +++ b/src/bonsai/bonsai/bim/module/model/product.py @@ -154,7 +154,7 @@ class AddDefaultType(bpy.types.Operator, tool.Ifc.Operator): bpy.ops.bim.add_element() -class AddOccurrence(bpy.types.Operator, PolylineOperator): +class AddOccurrence(bpy.types.Operator, PolylineOperator, tool.Ifc.Operator): bl_idname = "bim.add_occurrence" bl_label = "Add Occurrence" bl_options = {"REGISTER", "UNDO"} @@ -199,6 +199,9 @@ class AddOccurrence(bpy.types.Operator, PolylineOperator): snap_obj.select_set(False) def modal(self, context, event): + return IfcStore.execute_ifc_operator(self, context, event, method="MODAL") + + def _modal(self, context, event): # Ensure state of BIM tool props is valid props = tool.Model.get_model_props() relating_type_id = tool.Blender.get_enum_safe(props, "relating_type_id") @@ -251,6 +254,9 @@ class AddOccurrence(bpy.types.Operator, PolylineOperator): return {"RUNNING_MODAL"} def invoke(self, context, event): + return IfcStore.execute_ifc_operator(self, context, event, method="INVOKE") + + def _invoke(self, context, event): super().invoke(context, event) ProductDecorator.install(context) self.tool_state.use_default_container = True diff --git a/src/bonsai/bonsai/bim/module/model/profile.py b/src/bonsai/bonsai/bim/module/model/profile.py index bbc2671314..00e594323b 100644 --- a/src/bonsai/bonsai/bim/module/model/profile.py +++ b/src/bonsai/bonsai/bim/module/model/profile.py @@ -32,9 +32,9 @@ import bonsai.core.type import bonsai.core.geometry import bonsai.core.material import bonsai.core.root -from math import pi, degrees, inf, atan2 -from mathutils import Vector, Matrix, Quaternion -from bonsai.bim.module.geometry.helper import Helper +from bonsai.bim.ifc import IfcStore +from math import pi, degrees, atan2 +from mathutils import Vector, Matrix from bonsai.bim.module.model.wall import DumbWallRecalculator from bonsai.bim.module.model.decorator import ProfileDecorator, PolylineDecorator, ProductDecorator from bonsai.bim.module.model.polyline import PolylineOperator @@ -1109,7 +1109,7 @@ class EditExtrusionAxis(bpy.types.Operator, tool.Ifc.Operator): return {"FINISHED"} -class DrawPolylineProfile(bpy.types.Operator, PolylineOperator): +class DrawPolylineProfile(bpy.types.Operator, PolylineOperator, tool.Ifc.Operator): bl_idname = "bim.draw_polyline_profile" bl_label = "Draw Polyline Profile" bl_options = {"REGISTER", "UNDO"} @@ -1142,6 +1142,9 @@ class DrawPolylineProfile(bpy.types.Operator, PolylineOperator): DumbProfileJoiner().join_V(profile2["obj"], profile1["obj"]) def modal(self, context, event): + return IfcStore.execute_ifc_operator(self, context, event, method="MODAL") + + def _modal(self, context, event): if not self.relating_type: self.report({"WARNING"}, "You need to select a profile type.") PolylineDecorator.uninstall() @@ -1192,6 +1195,9 @@ class DrawPolylineProfile(bpy.types.Operator, PolylineOperator): return {"RUNNING_MODAL"} def invoke(self, context, event): + return IfcStore.execute_ifc_operator(self, context, event, method="INVOKE") + + def _invoke(self, context, event): super().invoke(context, event) ProductDecorator.install(context) self.tool_state.use_default_container = True diff --git a/src/bonsai/bonsai/bim/module/model/slab.py b/src/bonsai/bonsai/bim/module/model/slab.py index b362f1e736..de3078819d 100644 --- a/src/bonsai/bonsai/bim/module/model/slab.py +++ b/src/bonsai/bonsai/bim/module/model/slab.py @@ -31,9 +31,8 @@ import bonsai.core.geometry import bonsai.core.root import bonsai.tool as tool from bonsai.bim.ifc import IfcStore -from math import cos, radians +from math import cos from mathutils import Vector, Matrix -from bonsai.bim.module.geometry.helper import Helper from bonsai.bim.module.model.decorator import ProfileDecorator, PolylineDecorator, ProductDecorator from bonsai.bim.module.model.polyline import PolylineOperator from bonsai.bim.module.model.wall import DumbWallRecalculator @@ -864,7 +863,7 @@ class AddSlabFromWall(bpy.types.Operator, tool.Ifc.Operator): return {"FINISHED"} -class DrawPolylineSlab(bpy.types.Operator, PolylineOperator): +class DrawPolylineSlab(bpy.types.Operator, PolylineOperator, tool.Ifc.Operator): bl_idname = "bim.draw_polyline_slab" bl_label = "Draw Polyline Slab" bl_options = {"REGISTER", "UNDO"} @@ -905,6 +904,9 @@ class DrawPolylineSlab(bpy.types.Operator, PolylineOperator): DumbSlabPlaner().regenerate_from_occurence(element, material_set_usage) def modal(self, context, event): + return IfcStore.execute_ifc_operator(self, context, event, method="MODAL") + + def _modal(self, context, event): if not self.relating_type: self.report({"WARNING"}, "You need to select a slab type.") PolylineDecorator.uninstall() @@ -975,6 +977,9 @@ class DrawPolylineSlab(bpy.types.Operator, PolylineOperator): return {"RUNNING_MODAL"} def invoke(self, context, event): + return IfcStore.execute_ifc_operator(self, context, event, method="INVOKE") + + def _invoke(self, context, event): super().invoke(context, event) ProductDecorator.install(context) self.tool_state.use_default_container = True diff --git a/src/bonsai/bonsai/bim/module/model/wall.py b/src/bonsai/bonsai/bim/module/model/wall.py index 73df5e8d95..5a94be7528 100644 --- a/src/bonsai/bonsai/bim/module/model/wall.py +++ b/src/bonsai/bonsai/bim/module/model/wall.py @@ -350,7 +350,7 @@ class AddWallsFromSlab(bpy.types.Operator, tool.Ifc.Operator): DumbWallJoiner().join_V(wall2["obj"], wall1["obj"]) -class DrawPolylineWall(bpy.types.Operator, PolylineOperator): +class DrawPolylineWall(bpy.types.Operator, PolylineOperator, tool.Ifc.Operator): bl_idname = "bim.draw_polyline_wall" bl_label = "Draw Polyline Wall" bl_options = {"REGISTER", "UNDO"} @@ -399,6 +399,9 @@ class DrawPolylineWall(bpy.types.Operator, PolylineOperator): DumbWallJoiner().join_V(wall2["obj"], wall1["obj"]) def modal(self, context, event): + return IfcStore.execute_ifc_operator(self, context, event, method="MODAL") + + def _modal(self, context, event): if not self.relating_type: self.report({"WARNING"}, "You need to select a wall type.") PolylineDecorator.uninstall() @@ -471,6 +474,9 @@ class DrawPolylineWall(bpy.types.Operator, PolylineOperator): return {"RUNNING_MODAL"} def invoke(self, context, event): + return IfcStore.execute_ifc_operator(self, context, event, method="INVOKE") + + def _invoke(self, context, event): super().invoke(context, event) ProductDecorator.install(context) self.tool_state.use_default_container = True diff --git a/src/bonsai/bonsai/bim/module/root/operator.py b/src/bonsai/bonsai/bim/module/root/operator.py index 0ba93cc800..4801d3f999 100644 --- a/src/bonsai/bonsai/bim/module/root/operator.py +++ b/src/bonsai/bonsai/bim/module/root/operator.py @@ -355,7 +355,7 @@ class AddElement(bpy.types.Operator, tool.Ifc.Operator): ifc_class: bpy.props.StringProperty(options={"SKIP_SAVE"}) def invoke(self, context, event): - return IfcStore.execute_ifc_operator(self, context, is_invoke=True) + return IfcStore.execute_ifc_operator(self, context, event, method="INVOKE") def _invoke(self, context, event): props = context.scene.BIMRootProperties diff --git a/src/ifcopenshell-python/ifcopenshell/api/material/set_shape_aspect_constituents.py b/src/ifcopenshell-python/ifcopenshell/api/material/set_shape_aspect_constituents.py index 4df3770083..d95f877fcf 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/material/set_shape_aspect_constituents.py +++ b/src/ifcopenshell-python/ifcopenshell/api/material/set_shape_aspect_constituents.py @@ -44,7 +44,7 @@ def set_shape_aspect_constituents( A material may be associated with a style (i.e. colour). For example, a grey style for the "Aluminium" material and a transparent blue style for - the "Laminated Low-e Glass" material. + the "Laminated Low-e Glass" material. These three concepts of material constituents, shape aspects, and associated styles are correlated. For example, if the name (e.g. "Framing") @@ -75,7 +75,7 @@ def set_shape_aspect_constituents( # Create two materials aluminium = ifcopenshell.api.material.add_material(model, name="AL01", category="aluminium") glass = ifcopenshell.api.material.add_material(model, name="GLZ01", category="glass") - + # Auto assign material constituents and styles to items based on shape aspects ifcopenshell.api.material.set_shape_aspect_constituents( model, element=window, context=body, materials={ @@ -102,9 +102,7 @@ def set_shape_aspect_constituents( if should_create_new_material_set: material_set = ifcopenshell.api.material.add_material_set(file, set_type="IfcMaterialConstituentSet") for name, material in materials.items(): - ifcopenshell.api.material.add_constituent( - file, constituent_set=material_set, material=material, name=name - ) + ifcopenshell.api.material.add_constituent(file, constituent_set=material_set, material=material, name=name) ifcopenshell.api.material.assign_material(file, products=[element], material=material_set) styles = {n: ifcopenshell.util.representation.get_material_style(m, context) for n, m in materials.items()}