From 8b644d84151a3563f600e6cf140bb2fc5de5683b Mon Sep 17 00:00:00 2001 From: Gorgious Date: Sun, 23 Jul 2023 15:13:04 +0200 Subject: [PATCH] You can now directly apply an ifc array modifier Previously one would have to click on "remove" then "keep objects" --- .../blenderbim/bim/module/model/__init__.py | 1 + .../blenderbim/bim/module/model/array.py | 33 ++++++++++++------- .../blenderbim/bim/module/model/ui.py | 3 ++ src/blenderbim/blenderbim/tool/blender.py | 33 +++++++++++++------ src/blenderbim/blenderbim/tool/model.py | 2 ++ 5 files changed, 50 insertions(+), 22 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/model/__init__.py b/src/blenderbim/blenderbim/bim/module/model/__init__.py index fd5d7c6378..228e3cae03 100644 --- a/src/blenderbim/blenderbim/bim/module/model/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/model/__init__.py @@ -45,6 +45,7 @@ classes = ( array.DisableEditingArray, array.EditArray, array.EnableEditingArray, + array.ApplyArray, array.RemoveArray, array.SelectArrayParent, array.SelectAllArrayObjects, diff --git a/src/blenderbim/blenderbim/bim/module/model/array.py b/src/blenderbim/blenderbim/bim/module/model/array.py index 2a0557eef1..5b1606154b 100644 --- a/src/blenderbim/blenderbim/bim/module/model/array.py +++ b/src/blenderbim/blenderbim/bim/module/model/array.py @@ -135,11 +135,26 @@ class EditArray(bpy.types.Operator, tool.Ifc.Operator): data = json.dumps(data) ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties={"Data": data}) - tool.Blender.Modifier.Array.lock_children_transform(element, True) + tool.Blender.Modifier.Array.set_children_lock_state(element, self.item, True) tool.Blender.Modifier.Array.constrain_children_to_parent(element) return {"FINISHED"} +class ApplyArray(bpy.types.Operator, tool.Ifc.Operator): + bl_idname = "bim.apply_array" + bl_label = "Apply Array" + bl_options = {"REGISTER", "UNDO"} + bl_description = "Apply the array and keep children as separate entities. Only available for the last array" + + def _execute(self, context): + obj = context.active_object + element = tool.Ifc.get_entity(obj) + pset = ifcopenshell.util.element.get_pset(element, "BBIM_Array") + data = json.loads(pset["Data"]) + bpy.ops.bim.remove_array(item=len(data) - 1, keep_objs=True) + return {"FINISHED"} + + class RemoveArray(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.remove_array" bl_label = "Remove Array" @@ -169,11 +184,11 @@ class RemoveArray(bpy.types.Operator, tool.Ifc.Operator): except: return {"FINISHED"} - tool.Model.regenerate_array(parent, data, self.keep_objs) - if self.keep_objs: - tool.Blender.Modifier.Array.unconstrain_children_from_parent(element) - tool.Blender.Modifier.Array.lock_children_transform(element, False) + tool.Blender.Modifier.Array.bake_children_transform(element, self.item) + tool.Blender.Modifier.Array.set_children_lock_state(element, self.item, False) + + tool.Model.regenerate_array(parent, data, self.keep_objs) pset = tool.Ifc.get().by_id(pset["id"]) if len(data) == 1: @@ -182,16 +197,10 @@ class RemoveArray(bpy.types.Operator, tool.Ifc.Operator): del data[self.item] data = json.dumps(data) ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties={"Data": data}) + tool.Blender.Modifier.Array.constrain_children_to_parent(element) return {"FINISHED"} - def draw(self, context): - row = self.layout.row() - row.prop(self, "keep_objs") - - def invoke(self, context, event): - return context.window_manager.invoke_props_dialog(self) - class SelectArrayParent(bpy.types.Operator): bl_idname = "bim.select_array_parent" diff --git a/src/blenderbim/blenderbim/bim/module/model/ui.py b/src/blenderbim/blenderbim/bim/module/model/ui.py index 21a298d36d..ef2edc1219 100644 --- a/src/blenderbim/blenderbim/bim/module/model/ui.py +++ b/src/blenderbim/blenderbim/bim/module/model/ui.py @@ -224,6 +224,9 @@ class BIM_PT_array(bpy.types.Panel): name = f"{array['count']} Items ({array.get('method', 'OFFSET').capitalize()})" row.label(text=name, icon="MOD_ARRAY") row.operator("bim.enable_editing_array", icon="GREASEPENCIL", text="").item = i + apply_button = row.row(align=True) + apply_button.operator("bim.apply_array", text="", icon="CHECKMARK") + apply_button.enabled = i == len(ArrayData.data["parameters"]["data_dict"]) - 1 row.operator("bim.remove_array", icon="X", text="").item = i row = box.row(align=True) icon = "EMPTY_ARROWS" if array.get("use_local_space", False) else "EMPTY_AXIS" diff --git a/src/blenderbim/blenderbim/tool/blender.py b/src/blenderbim/blenderbim/tool/blender.py index 217b654368..3df17209ce 100644 --- a/src/blenderbim/blenderbim/tool/blender.py +++ b/src/blenderbim/blenderbim/tool/blender.py @@ -523,31 +523,44 @@ class Blender: class Array: @classmethod - def constrain_children_to_parent(cls, parent_element): - parent_obj = tool.Ifc.get_object(parent_element) - children = cls.get_all_children_objects(parent_element) + def bake_children_transform(cls, parent_element, item): + modifier_data = list(cls.get_modifiers_data(parent_element))[item] + children = cls.get_children_objects(modifier_data) for child in children: - constraint = next( - (c for c in child.constraints if c.type == "CHILD_OF"), None - ) or child.constraints.new("CHILD_OF") - constraint.target = parent_obj + constraint = next((c for c in child.constraints if c.type == "CHILD_OF"), None) + if constraint: + with bpy.context.temp_override(object=child): + bpy.ops.constraint.apply(constraint=constraint.name, owner="OBJECT") @classmethod - def unconstrain_children_from_parent(cls, parent_element): + def constrain_children_to_parent(cls, parent_element): + parent_obj = tool.Ifc.get_object(parent_element) children = cls.get_all_children_objects(parent_element) for child in children: constraint = next((c for c in child.constraints if c.type == "CHILD_OF"), None) if constraint: child.constraints.remove(constraint) + constraint = child.constraints.new("CHILD_OF") + constraint.target = parent_obj @classmethod - def lock_children_transform(cls, parent_element, lock_state=True): - for child_obj in cls.get_all_children_objects(parent_element): + def set_children_lock_state(cls, parent_element, item, lock_state=True): + modifier_data = list(cls.get_modifiers_data(parent_element))[item] + children = cls.get_children_objects(modifier_data) + for child_obj in children: for prop in ("lock_location", "lock_rotation", "lock_scale"): attr = getattr(child_obj, prop) for axis_idx in range(3): attr[axis_idx] = lock_state + @classmethod + def remove_constraints(cls, parent_element): + children = cls.get_all_children_objects(parent_element) + for child in children: + constraint = next((c for c in child.constraints if c.type == "CHILD_OF"), None) + if constraint: + child.constraints.remove(constraint) + @classmethod def get_all_objects(cls, parent_element): parent_obj = tool.Ifc.get_object(parent_element) diff --git a/src/blenderbim/blenderbim/tool/model.py b/src/blenderbim/blenderbim/tool/model.py index 4b288b9e23..65774fec9e 100644 --- a/src/blenderbim/blenderbim/tool/model.py +++ b/src/blenderbim/blenderbim/tool/model.py @@ -529,6 +529,8 @@ class Model(blenderbim.core.tool.Model): @classmethod def regenerate_array(cls, parent, data, keep_objs=False): + tool.Blender.Modifier.Array.remove_constraints(tool.Ifc.get_entity(parent)) + unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) obj_stack = [parent]