From 4a5f1b01a133741625bfd28f7d1e6cbe1e923066 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Mon, 17 Nov 2025 11:08:47 +0500 Subject: [PATCH] black . --- .../bonsai/bim/module/drawing/decoration.py | 4 +- .../bonsai/bim/module/geometry/operator.py | 93 ++++++++++--------- src/bonsai/bonsai/tool/drawing.py | 4 +- 3 files changed, 53 insertions(+), 48 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/drawing/decoration.py b/src/bonsai/bonsai/bim/module/drawing/decoration.py index f91b0085eb..1735b32575 100644 --- a/src/bonsai/bonsai/bim/module/drawing/decoration.py +++ b/src/bonsai/bonsai/bim/module/drawing/decoration.py @@ -175,10 +175,10 @@ class BaseDecorator: # https://blender.stackexchange.com/questions/16493/is-there-a-way-to-fit-the-viewport-to-the-current-field-of-view camera = bpy.context.scene.camera render = bpy.context.scene.render - + # Always use the camera's ortho_scale as the width in model space camera_width_model = camera.data.ortho_scale - + scale = tool.Drawing.get_scale_ratio(tool.Drawing.get_diagram_scale(camera)["Scale"]) camera_width_mm = scale * camera_width_model return camera_width_mm diff --git a/src/bonsai/bonsai/bim/module/geometry/operator.py b/src/bonsai/bonsai/bim/module/geometry/operator.py index 66f5d50d48..248a226244 100644 --- a/src/bonsai/bonsai/bim/module/geometry/operator.py +++ b/src/bonsai/bonsai/bim/module/geometry/operator.py @@ -2544,7 +2544,6 @@ class OverrideModeSetObject(bpy.types.Operator, tool.Ifc.Operator): props.is_changing_mode = False - class DirectProfileEdit(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.direct_profile_edit" bl_label = "IFC Direct Profile Edit" @@ -2556,22 +2555,22 @@ class DirectProfileEdit(bpy.types.Operator, tool.Ifc.Operator): # Only allow in OBJECT or EDIT modes if context.mode not in ("OBJECT", "EDIT_MESH", "EDIT_CURVE"): return False - + # Must have an active object if not context.active_object: return False - + # In edit mode, we're good to go (we'll exit) if context.mode in ("EDIT_MESH", "EDIT_CURVE"): return True - + # In object mode, check if it's an editable object type obj = context.active_object - + # Only mesh and curve objects are editable if obj.type not in ("MESH", "CURVE"): return False - + return True def _execute(self, context): @@ -2580,15 +2579,18 @@ class DirectProfileEdit(bpy.types.Operator, tool.Ifc.Operator): active_obj = context.active_object if active_obj and context.mode == "OBJECT": if len(context.selected_objects) > 1: - self.report({"WARNING"}, "Currently Direct Profile Edit only works on one object at a time. Operating on active object only.") - bpy.ops.object.select_all(action='DESELECT') + self.report( + {"WARNING"}, + "Currently Direct Profile Edit only works on one object at a time. Operating on active object only.", + ) + bpy.ops.object.select_all(action="DESELECT") active_obj.select_set(True) context.view_layer.objects.active = active_obj - + # If we're already in edit mode, exit to object mode and SAVE changes if context.mode in ("EDIT_MESH", "EDIT_CURVE"): return self.handle_exit_edit_mode(context) - + # We're in object mode, try to enter profile/axis edit return self.handle_enter_edit_mode(context) @@ -2597,16 +2599,16 @@ class DirectProfileEdit(bpy.types.Operator, tool.Ifc.Operator): obj = context.active_object if not obj: return {"CANCELLED"} - + # Check if we're editing a representation item if tool.Geometry.is_representation_item(obj): return self.exit_item_edit_mode(context, obj) - + # Check if we're editing an element-level profile or axis element = tool.Ifc.get_entity(obj) if element and tool.Geometry.has_mesh_properties(obj.data): return self.exit_element_edit_mode(context, obj, element) - + # For other edit modes, use standard operator return bpy.ops.bim.override_mode_set_object() @@ -2616,36 +2618,39 @@ class DirectProfileEdit(bpy.types.Operator, tool.Ifc.Operator): item = tool.Geometry.get_active_representation(obj) if not item or not item.is_a("IfcSweptAreaSolid"): return bpy.ops.bim.override_mode_set_object() - + # Use the standard save workflow for items from bonsai.bim.module.model.decorator import ProfileDecorator + ProfileDecorator.uninstall() tool.Blender.toggle_edit_mode(context) - + profile = tool.Model.export_profile(obj) if not profile: + def msg(self, context): self.layout.label(text="INVALID PROFILE") + context.window_manager.popup_menu(msg, title="Error", icon="ERROR") tool.Blender.toggle_edit_mode(context) ProfileDecorator.install(context) return {"CANCELLED"} - + old_profile = item.SweptArea profile.ProfileName = old_profile.ProfileName - + ifc_file = tool.Ifc.get() for inverse in ifc_file.get_inverse(old_profile): ifcopenshell.util.element.replace_attribute(inverse, old_profile, profile) - + tool.Profile.replace_profile_in_profiles_ui(old_profile.id(), profile.id()) ifcopenshell.util.element.remove_deep2(ifc_file, old_profile) - + props = tool.Geometry.get_geometry_props() if props.representation_obj: tool.Geometry.reload_representation(props.representation_obj) tool.Geometry.disable_item_mode() - + return {"FINISHED"} except Exception as e: self.report({"ERROR"}, f"Failed to save item changes: {str(e)}") @@ -2655,11 +2660,11 @@ class DirectProfileEdit(bpy.types.Operator, tool.Ifc.Operator): """Exit from element-level profile or axis editing.""" try: mesh_props = tool.Geometry.get_mesh_props(obj.data) - + # Check if we're editing axis if mesh_props.subshape_type == "AXIS": return bpy.ops.bim.edit_extrusion_axis() - + # Otherwise, we're editing a profile body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW") if body: @@ -2670,7 +2675,7 @@ class DirectProfileEdit(bpy.types.Operator, tool.Ifc.Operator): except Exception as e: self.report({"ERROR"}, f"Failed to save profile/axis changes: {str(e)}") return {"CANCELLED"} - + # Fallback to standard operator return bpy.ops.bim.override_mode_set_object() @@ -2679,37 +2684,37 @@ class DirectProfileEdit(bpy.types.Operator, tool.Ifc.Operator): obj = context.active_object if not obj: return {"CANCELLED"} - + # Check if object has mesh or curve data - if not hasattr(obj, 'data') or not obj.data: + if not hasattr(obj, "data") or not obj.data: self.report({"INFO"}, "Object has no editable data") return {"CANCELLED"} - + element = tool.Ifc.get_entity(obj) if not element: self.report({"INFO"}, "Active object is not an IFC element") return {"CANCELLED"} - + # Check if this is a LAYER2 element (wall, railing, etc.) try: material_usage = tool.Model.get_usage_type(element) except: material_usage = None - + if material_usage == "LAYER2": self.report({"ERROR"}, "LAYER2 elements (walls, railings, etc.) cannot use profile editing.") return {"CANCELLED"} - + # Try to get representation try: representation = tool.Geometry.get_active_representation(obj) except: representation = None - + if not representation: self.report({"INFO"}, "Object has no active representation") return {"CANCELLED"} - + # Check for PROFILE usage (beams, columns, members) - should edit axis if material_usage == "PROFILE": try: @@ -2717,7 +2722,7 @@ class DirectProfileEdit(bpy.types.Operator, tool.Ifc.Operator): except Exception as e: self.report({"ERROR"}, f"Failed to enable axis editing: {str(e)}") return {"CANCELLED"} - + # Check if this is an element with an extrusion profile (LAYER3, etc) try: body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW") @@ -2729,7 +2734,7 @@ class DirectProfileEdit(bpy.types.Operator, tool.Ifc.Operator): except Exception as e: self.report({"ERROR"}, f"Failed to enable profile editing: {str(e)}") return {"CANCELLED"} - + # Otherwise, try to enter item mode and edit SweptAreaSolid return self.enter_item_edit_mode(context, obj) @@ -2740,7 +2745,7 @@ class DirectProfileEdit(bpy.types.Operator, tool.Ifc.Operator): if not props.representation_obj: bpy.ops.bim.import_representation_items() props = tool.Geometry.get_geometry_props() - + # Find the SweptAreaSolid item swept_solid_obj = None for item_obj_data in props.item_objs: @@ -2754,17 +2759,17 @@ class DirectProfileEdit(bpy.types.Operator, tool.Ifc.Operator): break except: continue - + if not swept_solid_obj: self.report({"INFO"}, "No editable SweptAreaSolid item found") tool.Geometry.disable_item_mode() return {"CANCELLED"} - + # Select and activate the swept solid object - bpy.ops.object.select_all(action='DESELECT') + bpy.ops.object.select_all(action="DESELECT") swept_solid_obj.select_set(True) context.view_layer.objects.active = swept_solid_obj - + # Import the profile to prepare for editing item = tool.Geometry.get_active_representation(swept_solid_obj) if item and item.is_a("IfcSweptAreaSolid"): @@ -2774,16 +2779,17 @@ class DirectProfileEdit(bpy.types.Operator, tool.Ifc.Operator): self.report({"ERROR"}, "Couldn't import profile for editing") tool.Geometry.disable_item_mode() return {"CANCELLED"} - + tool.Ifc.link(item, swept_solid_obj.data) tool.Blender.toggle_edit_mode(context) - + from bonsai.bim.module.model.decorator import ProfileDecorator + ProfileDecorator.install(context) - + if not bpy.app.background: tool.Blender.set_viewport_tool("bim.cad_tool") - + return {"FINISHED"} except Exception as e: self.report({"ERROR"}, f"Failed to enter item edit mode: {str(e)}") @@ -2792,9 +2798,8 @@ class DirectProfileEdit(bpy.types.Operator, tool.Ifc.Operator): except: pass return {"CANCELLED"} - - return {"CANCELLED"} + return {"CANCELLED"} class FlipObject(bpy.types.Operator): diff --git a/src/bonsai/bonsai/tool/drawing.py b/src/bonsai/bonsai/tool/drawing.py index bb0b9a374c..00fd6c9505 100644 --- a/src/bonsai/bonsai/tool/drawing.py +++ b/src/bonsai/bonsai/tool/drawing.py @@ -2009,11 +2009,11 @@ class Drawing(bonsai.core.tool.Drawing): if matrix_world is None: # Use normalized camera matrix (without scale) for RCP compatibility matrix_world = cls.get_camera_matrix(camera) - + # Check if this is an RCP (reflected ceiling plan) by checking for negative scale camera_scale = camera.matrix_world.to_scale() is_rcp = camera_scale.x < 0 or camera_scale.y < 0 or camera_scale.z < 0 - + # For RCP, the offset needs to be positive instead of negative # because the Z axis is flipped 180° in get_camera_matrix offset_direction = 1 if is_rcp else -1