Merge pull request #5930 from Gorgious56/improve_modifiers

Modifiers QOL
This commit is contained in:
Gorgious56
2025-01-06 12:10:26 +01:00
committed by GitHub
7 changed files with 136 additions and 29 deletions
@@ -78,9 +78,6 @@ class ViewportData:
modes.append(edit_mode) modes.append(edit_mode)
elif element.is_a("IfcGridAxis"): elif element.is_a("IfcGridAxis"):
modes.append(edit_mode) modes.append(edit_mode)
elif tool.Blender.Modifier.is_editing_parameters(obj):
# This should go BEFORE the modifiers
pass
elif tool.Blender.Modifier.is_roof(element): elif tool.Blender.Modifier.is_roof(element):
modes.append(edit_mode) modes.append(edit_mode)
elif tool.Blender.Modifier.is_railing(element): elif tool.Blender.Modifier.is_railing(element):
@@ -1858,8 +1858,9 @@ class OverrideEscape(bpy.types.Operator):
bpy.ops.bim.hide_all_openings() bpy.ops.bim.hide_all_openings()
elif context.scene.BIMAggregateProperties.in_aggregate_mode: elif context.scene.BIMAggregateProperties.in_aggregate_mode:
bpy.ops.bim.disable_aggregate_mode() bpy.ops.bim.disable_aggregate_mode()
elif context.active_object and context.active_object.BIMRailingProperties.is_editing_path: elif active_object:=context.active_object:
bpy.ops.bim.cancel_editing_railing_path() if tool.Blender.Modifier.try_canceling_editing_modifier_parameters_or_path(active_object):
pass
return {"FINISHED"} return {"FINISHED"}
@@ -1921,13 +1922,8 @@ class OverrideModeSetEdit(bpy.types.Operator, tool.Ifc.Operator):
bpy.ops.bim.enable_editing_boundary_geometry() bpy.ops.bim.enable_editing_boundary_geometry()
elif element.is_a("IfcGridAxis"): elif element.is_a("IfcGridAxis"):
self.enable_edit_mode(context) self.enable_edit_mode(context)
elif tool.Blender.Modifier.is_editing_parameters(obj): elif tool.Blender.Modifier.try_applying_edit_mode(obj, element):
# This should go BEFORE the modifiers pass
self.report({"INFO"}, "Can't edit while modifier parameters are being modified")
elif tool.Blender.Modifier.is_roof(element):
bpy.ops.bim.enable_editing_roof_path()
elif tool.Blender.Modifier.is_railing(element):
bpy.ops.bim.enable_editing_railing_path()
else: else:
bpy.ops.bim.import_representation_items() bpy.ops.bim.import_representation_items()
elif tool.Geometry.is_representation_item(obj): elif tool.Geometry.is_representation_item(obj):
@@ -186,6 +186,7 @@ classes = (
roof.BIM_OT_add_roof, roof.BIM_OT_add_roof,
roof.AddRoof, roof.AddRoof,
roof.CancelEditingRoof, roof.CancelEditingRoof,
roof.CopyRoofParameters,
roof.FinishEditingRoof, roof.FinishEditingRoof,
roof.EnableEditingRoof, roof.EnableEditingRoof,
roof.CancelEditingRoofPath, roof.CancelEditingRoofPath,
@@ -569,6 +569,7 @@ class RoofData:
if not cls.data["pset_data"]: if not cls.data["pset_data"]:
return return
cls.data["general_params"] = cls.general_params() cls.data["general_params"] = cls.general_params()
cls.data["path_data"] = cls.path_data()
@classmethod @classmethod
def pset_data(cls): def pset_data(cls):
@@ -589,6 +590,10 @@ class RoofData:
general_params[prop_readable_name] = prop_value general_params[prop_readable_name] = prop_value
return general_params return general_params
@classmethod
def path_data(cls):
return cls.data["pset_data"]["data_dict"]["path_data"]
class ItemData: class ItemData:
data = {} data = {}
+36 -1
View File
@@ -438,7 +438,7 @@ def update_roof_modifier_bmesh(obj: bpy.types.Object) -> None:
# NOTE: using Data since bmesh update will hapen very often # NOTE: using Data since bmesh update will hapen very often
if not RoofData.is_loaded: if not RoofData.is_loaded:
RoofData.load() RoofData.load()
path_data = RoofData.data["pset_data"]["data_dict"]["path_data"] path_data = RoofData.data["path_data"]
angle_layer_data = path_data.get("gable_roof_angles", None) angle_layer_data = path_data.get("gable_roof_angles", None)
separate_verts_data = path_data.get("gable_roof_separate_verts", None) separate_verts_data = path_data.get("gable_roof_separate_verts", None)
@@ -739,6 +739,41 @@ class CancelEditingRoofPath(bpy.types.Operator, tool.Ifc.Operator):
return cancel_editing_roof_path(context) return cancel_editing_roof_path(context)
class CopyRoofParameters(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.copy_roof_parameters"
bl_label = "Copy Roof Parameters from Active to Selected"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return context.active_object and len(context.selected_objects) > 1
def _execute(self, context):
source_obj = context.active_object
source_props = source_obj.BIMRoofProperties
data = source_props.get_general_kwargs(convert_to_project_units=True)
for target_obj in context.selected_objects:
if target_obj == source_obj:
continue
context.view_layer.objects.active = target_obj
RoofData.load()
if not "path_data" in RoofData.data:
continue
data["path_data"] = RoofData.data["path_data"]
target_element = tool.Ifc.get_entity(target_obj)
target_props = target_obj.BIMRoofProperties
target_props.set_props_kwargs_from_ifc_data(data)
update_bbim_roof_pset(target_element, data)
refresh()
update_roof_modifier_bmesh(target_obj)
update_roof_modifier_ifc_data(context)
context.view_layer.objects.active = source_obj
return {"FINISHED"}
class FinishEditingRoofPath(bpy.types.Operator, tool.Ifc.Operator): class FinishEditingRoofPath(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.finish_editing_roof_path" bl_idname = "bim.finish_editing_roof_path"
bl_label = "Finish Editing Roof Path" bl_label = "Finish Editing Roof Path"
+1 -2
View File
@@ -649,13 +649,12 @@ class BIM_PT_roof(bpy.types.Panel):
self.layout.prop(props, prop) self.layout.prop(props, prop)
update_roof_modifier_bmesh(obj) update_roof_modifier_bmesh(obj)
elif props.is_editing_path: elif props.is_editing_path:
row.operator("bim.finish_editing_roof_path", icon="CHECKMARK", text="") row.operator("bim.finish_editing_roof_path", icon="CHECKMARK", text="")
row.operator("bim.cancel_editing_roof_path", icon="CANCEL", text="") row.operator("bim.cancel_editing_roof_path", icon="CANCEL", text="")
else: else:
row.operator("bim.enable_editing_roof", icon="GREASEPENCIL", text="") row.operator("bim.enable_editing_roof", icon="GREASEPENCIL", text="")
row.operator("bim.copy_roof_parameters", icon="COPYDOWN", text="")
row.operator("bim.enable_editing_roof_path", icon="ANIM", text="") row.operator("bim.enable_editing_roof_path", icon="ANIM", text="")
row.operator("bim.remove_roof", icon="X", text="") row.operator("bim.remove_roof", icon="X", text="")
+88 -14
View File
@@ -21,6 +21,7 @@ import bpy
import bmesh import bmesh
import json import json
import os import os
from ifcopenshell import entity_instance
import ifcopenshell.api import ifcopenshell.api
import ifcopenshell.util.element import ifcopenshell.util.element
import bonsai.core.tool import bonsai.core.tool
@@ -922,58 +923,131 @@ class Blender(bonsai.core.tool.Blender):
class Modifier: class Modifier:
@classmethod @classmethod
def is_eligible_for_railing_modifier(cls, obj): def try_applying_edit_mode(cls, obj: bpy.types.Object, element: entity_instance) -> bool:
"""Tries to validate the current BIM modifier parameters for the active object
Goes into path editing mode if the modifier supports it
Returns True if an action was taken, False otherwise
"""
if cls.is_roof(element):
if cls.is_editing_roof_parameters(obj):
bpy.ops.bim.finish_editing_roof()
bpy.ops.bim.enable_editing_roof_path()
elif cls.is_railing(element):
if cls.is_editing_railing_parameters(obj):
bpy.ops.bim.finish_editing_railing()
bpy.ops.bim.enable_editing_railing_path()
elif cls.is_editing_stair_parameters(obj):
bpy.ops.bim.finish_editing_stair()
elif cls.is_editing_door_parameters(obj):
bpy.ops.bim.finish_editing_door()
elif cls.is_editing_window_parameters(obj):
bpy.ops.bim.finish_editing_window()
else:
return False
return True
@classmethod
def try_canceling_editing_modifier_parameters_or_path(cls, obj: bpy.types.Object) -> bool:
"""Tries to cancel the current BIM modifier parameters or path edition for the active object
Returns True if an action was taken, False otherwise
"""
if cls.is_editing_railing_path(obj):
bpy.ops.bim.cancel_editing_railing_path()
elif cls.is_editing_roof_path(obj):
bpy.ops.bim.cancel_editing_roof_path()
elif cls.is_editing_railing_parameters(obj):
bpy.ops.bim.cancel_editing_railing()
elif cls.is_editing_door_parameters(obj):
bpy.ops.bim.cancel_editing_door()
elif cls.is_editing_window_parameters(obj):
bpy.ops.bim.cancel_editing_window()
elif cls.is_editing_roof_parameters(obj):
bpy.ops.bim.cancel_editing_roof()
elif cls.is_editing_stair_parameters(obj):
bpy.ops.bim.cancel_editing_stair()
else:
return False
return True
@classmethod
def is_eligible_for_railing_modifier(cls, obj: bpy.types.Object)-> bool:
return tool.Blender.is_object_an_ifc_class(obj, ("IfcRailing", "IfcRailingType")) return tool.Blender.is_object_an_ifc_class(obj, ("IfcRailing", "IfcRailingType"))
@classmethod @classmethod
def is_eligible_for_stair_modifier(cls, obj): def is_eligible_for_stair_modifier(cls, obj: bpy.types.Object)-> bool:
return tool.Blender.is_object_an_ifc_class( return tool.Blender.is_object_an_ifc_class(
obj, ("IfcStairFlight", "IfcStairFlightType", "IfcMember", "IfcMemberType", "IfcStair", "IfcStairType") obj, ("IfcStairFlight", "IfcStairFlightType", "IfcMember", "IfcMemberType", "IfcStair", "IfcStairType")
) )
@classmethod @classmethod
def is_eligible_for_window_modifier(cls, obj): def is_eligible_for_window_modifier(cls, obj: bpy.types.Object)-> bool:
return tool.Blender.is_object_an_ifc_class(obj, ("IfcWindow", "IfcWindowType", "IfcWindowStyle")) return tool.Blender.is_object_an_ifc_class(obj, ("IfcWindow", "IfcWindowType", "IfcWindowStyle"))
@classmethod @classmethod
def is_eligible_for_door_modifier(cls, obj): def is_eligible_for_door_modifier(cls, obj: bpy.types.Object)-> bool:
return tool.Blender.is_object_an_ifc_class(obj, ("IfcDoor", "IfcDoorType", "IfcDoorStyle")) return tool.Blender.is_object_an_ifc_class(obj, ("IfcDoor", "IfcDoorType", "IfcDoorStyle"))
@classmethod @classmethod
def is_eligible_for_roof_modifier(cls, obj): def is_eligible_for_roof_modifier(cls, obj: bpy.types.Object)-> bool:
return tool.Blender.is_object_an_ifc_class(obj, ("IfcRoof", "IfcRoofType")) return tool.Blender.is_object_an_ifc_class(obj, ("IfcRoof", "IfcRoofType"))
@classmethod @classmethod
def is_railing(cls, element): def is_railing(cls, element: entity_instance)-> bool:
return tool.Pset.get_element_pset(element, "BBIM_Railing") return tool.Pset.get_element_pset(element, "BBIM_Railing")
@classmethod @classmethod
def is_roof(cls, element): def is_roof(cls, element: entity_instance)-> bool:
return tool.Pset.get_element_pset(element, "BBIM_Roof") return tool.Pset.get_element_pset(element, "BBIM_Roof")
@classmethod @classmethod
def is_window(cls, element): def is_window(cls, element: entity_instance)-> bool:
return tool.Pset.get_element_pset(element, "BBIM_Window") return tool.Pset.get_element_pset(element, "BBIM_Window")
@classmethod @classmethod
def is_door(cls, element): def is_door(cls, element: entity_instance)-> bool:
return tool.Pset.get_element_pset(element, "BBIM_Door") return tool.Pset.get_element_pset(element, "BBIM_Door")
@classmethod @classmethod
def is_stair(cls, element): def is_stair(cls, element: entity_instance)-> bool:
return tool.Pset.get_element_pset(element, "BBIM_Stair") return tool.Pset.get_element_pset(element, "BBIM_Stair")
@classmethod @classmethod
def is_editing_parameters(cls, obj): def is_editing_railing_path(cls, obj: bpy.types.Object):
return obj.BIMRailingProperties.is_editing or obj.BIMRoofProperties.is_editing return obj.BIMRailingProperties.is_editing_path
@classmethod @classmethod
def is_modifier_with_non_editable_path(cls, element): def is_editing_roof_path(cls, obj: bpy.types.Object)-> bool:
return obj.BIMRoofProperties.is_editing_path
@classmethod
def is_editing_railing_parameters(cls, obj: bpy.types.Object)-> bool:
return obj.BIMRailingProperties.is_editing
@classmethod
def is_editing_roof_parameters(cls, obj: bpy.types.Object)-> bool:
return obj.BIMRoofProperties.is_editing
@classmethod
def is_editing_window_parameters(cls, obj: bpy.types.Object)-> bool:
return obj.BIMWindowProperties.is_editing
@classmethod
def is_editing_door_parameters(cls, obj: bpy.types.Object)-> bool:
return obj.BIMDoorProperties.is_editing
@classmethod
def is_editing_stair_parameters(cls, obj: bpy.types.Object)-> bool:
return obj.BIMStairProperties.is_editing
@classmethod
def is_modifier_with_non_editable_path(cls, element: entity_instance)-> bool:
return cls.is_stair(element) or cls.is_door(element) or cls.is_window(element) return cls.is_stair(element) or cls.is_door(element) or cls.is_window(element)
class Array: class Array:
@classmethod @classmethod
def bake_children_transform(cls, parent_element, item): def bake_children_transform(cls, parent_element: entity_instance, item):
modifier_data = list(cls.get_modifiers_data(parent_element))[item] modifier_data = list(cls.get_modifiers_data(parent_element))[item]
children = cls.get_children_objects(modifier_data) children = cls.get_children_objects(modifier_data)
for child in children: for child in children: