mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-19 06:39:13 +00:00
Duplicate the array if all it's elements are selected #3763
Demo - https://imgur.com/a/0wYZOPl
This commit is contained in:
@@ -553,7 +553,8 @@ class OverrideDelete(bpy.types.Operator):
|
|||||||
with context.temp_override(active_object=array_parent_obj):
|
with context.temp_override(active_object=array_parent_obj):
|
||||||
bpy.ops.bim.remove_array(item=i)
|
bpy.ops.bim.remove_array(item=i)
|
||||||
else:
|
else:
|
||||||
break
|
break # allows to remove only n last layers of an array
|
||||||
|
|
||||||
|
|
||||||
class OverrideOutlinerDelete(bpy.types.Operator):
|
class OverrideOutlinerDelete(bpy.types.Operator):
|
||||||
bl_idname = "bim.override_outliner_delete"
|
bl_idname = "bim.override_outliner_delete"
|
||||||
@@ -702,11 +703,20 @@ class OverrideDuplicateMove(bpy.types.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
|
objects_to_duplicate = set(context.selected_objects)
|
||||||
|
|
||||||
|
# handle arrays
|
||||||
|
arrays_to_duplicate, array_children = self.process_arrays(context)
|
||||||
|
objects_to_duplicate -= array_children
|
||||||
|
for child in array_children:
|
||||||
|
child.select_set(False)
|
||||||
|
|
||||||
self.new_active_obj = None
|
self.new_active_obj = None
|
||||||
# Track decompositions so they can be recreated after the operation
|
# Track decompositions so they can be recreated after the operation
|
||||||
relationships = tool.Root.get_decomposition_relationships(context.selected_objects)
|
relationships = tool.Root.get_decomposition_relationships(objects_to_duplicate)
|
||||||
old_to_new = {}
|
old_to_new = {}
|
||||||
for obj in context.selected_objects:
|
|
||||||
|
for obj in objects_to_duplicate:
|
||||||
element = tool.Ifc.get_entity(obj)
|
element = tool.Ifc.get_entity(obj)
|
||||||
if element and element.is_a("IfcAnnotation") and element.ObjectType == "DRAWING":
|
if element and element.is_a("IfcAnnotation") and element.ObjectType == "DRAWING":
|
||||||
continue # For now, don't copy drawings until we stabilise a bit more. It's tricky.
|
continue # For now, don't copy drawings until we stabilise a bit more. It's tricky.
|
||||||
@@ -737,14 +747,56 @@ class OverrideDuplicateMove(bpy.types.Operator):
|
|||||||
tool.Blender.remove_data_block(temp_data)
|
tool.Blender.remove_data_block(temp_data)
|
||||||
|
|
||||||
if new:
|
if new:
|
||||||
tool.Model.remove_array_from_element(new)
|
# TODO: handle array data for other cases of duplication
|
||||||
old_to_new[tool.Ifc.get_entity(obj)] = [new]
|
array_data = arrays_to_duplicate.get(obj, None)
|
||||||
|
tool.Model.handle_array_on_copied_element(new, array_data)
|
||||||
|
if array_data:
|
||||||
|
for child in tool.Blender.Modifier.Array.get_all_children_objects(new):
|
||||||
|
child.select_set(True)
|
||||||
|
|
||||||
|
# TODO: add new array children to recreate their decomposition too
|
||||||
|
old_to_new[element] = [new]
|
||||||
if new.is_a("IfcRelSpaceBoundary"):
|
if new.is_a("IfcRelSpaceBoundary"):
|
||||||
tool.Boundary.decorate_boundary(new_obj)
|
tool.Boundary.decorate_boundary(new_obj)
|
||||||
|
|
||||||
# Recreate decompositions
|
# Recreate decompositions
|
||||||
tool.Root.recreate_decompositions(relationships, old_to_new)
|
tool.Root.recreate_decompositions(relationships, old_to_new)
|
||||||
blenderbim.bim.handler.refresh_ui_data()
|
blenderbim.bim.handler.refresh_ui_data()
|
||||||
|
|
||||||
|
def process_arrays(self, context):
|
||||||
|
selected_objects = set(context.selected_objects)
|
||||||
|
array_parents = set()
|
||||||
|
arrays_to_create = dict()
|
||||||
|
array_children = set() # will be ignored during the duplication
|
||||||
|
|
||||||
|
for obj in context.selected_objects:
|
||||||
|
element = tool.Ifc.get_entity(obj)
|
||||||
|
if not element:
|
||||||
|
continue
|
||||||
|
pset = ifcopenshell.util.element.get_pset(element, "BBIM_Array")
|
||||||
|
if not pset:
|
||||||
|
continue
|
||||||
|
array_parents.add(tool.Ifc.get().by_guid(pset["Parent"]))
|
||||||
|
|
||||||
|
for array_parent in array_parents:
|
||||||
|
array_parent_obj = tool.Ifc.get_object(array_parent)
|
||||||
|
if array_parent_obj not in selected_objects:
|
||||||
|
continue
|
||||||
|
|
||||||
|
array_data = []
|
||||||
|
for modifier_data in tool.Blender.Modifier.Array.get_modifiers_data(array_parent):
|
||||||
|
children = set(tool.Blender.Modifier.Array.get_children_objects(modifier_data))
|
||||||
|
if children.issubset(selected_objects):
|
||||||
|
modifier_data["children"] = []
|
||||||
|
array_data.append(modifier_data)
|
||||||
|
array_children.update(children)
|
||||||
|
else:
|
||||||
|
break # allows to duplicate only n first layers of an array
|
||||||
|
|
||||||
|
if array_data:
|
||||||
|
arrays_to_create[array_parent_obj] = array_data
|
||||||
|
|
||||||
|
return arrays_to_create, array_children
|
||||||
|
|
||||||
class OverrideDuplicateMoveLinkedMacro(bpy.types.Macro):
|
class OverrideDuplicateMoveLinkedMacro(bpy.types.Macro):
|
||||||
bl_idname = "bim.override_object_duplicate_move_linked_macro"
|
bl_idname = "bim.override_object_duplicate_move_linked_macro"
|
||||||
@@ -804,7 +856,7 @@ class OverrideDuplicateMoveLinked(bpy.types.Operator):
|
|||||||
# Copy the actual class
|
# Copy the actual class
|
||||||
new = blenderbim.core.root.copy_class(tool.Ifc, tool.Collector, tool.Geometry, tool.Root, obj=new_obj)
|
new = blenderbim.core.root.copy_class(tool.Ifc, tool.Collector, tool.Geometry, tool.Root, obj=new_obj)
|
||||||
if new:
|
if new:
|
||||||
tool.Model.remove_array_from_element(new)
|
tool.Model.handle_array_on_copied_element(new)
|
||||||
old_to_new[tool.Ifc.get_entity(obj)] = new
|
old_to_new[tool.Ifc.get_entity(obj)] = new
|
||||||
# Recreate decompositions
|
# Recreate decompositions
|
||||||
tool.Root.recreate_decompositions(relationships, old_to_new)
|
tool.Root.recreate_decompositions(relationships, old_to_new)
|
||||||
@@ -1048,7 +1100,7 @@ class OverrideDuplicateMoveAggregate(bpy.types.Operator):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if new_entity:
|
if new_entity:
|
||||||
tool.Model.remove_array_from_element(new_entity)
|
tool.Model.handle_array_on_copied_element(new_entity)
|
||||||
blenderbim.core.aggregate.unassign_object(
|
blenderbim.core.aggregate.unassign_object(
|
||||||
tool.Ifc,
|
tool.Ifc,
|
||||||
tool.Aggregate,
|
tool.Aggregate,
|
||||||
@@ -1176,7 +1228,7 @@ class RefreshAggregate(bpy.types.Operator):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if new_entity:
|
if new_entity:
|
||||||
tool.Model.remove_array_from_element(new_entity)
|
tool.Model.handle_array_on_copied_element(new_entity)
|
||||||
blenderbim.core.aggregate.unassign_object(
|
blenderbim.core.aggregate.unassign_object(
|
||||||
tool.Ifc,
|
tool.Ifc,
|
||||||
tool.Aggregate,
|
tool.Aggregate,
|
||||||
|
|||||||
@@ -540,29 +540,56 @@ class Model(blenderbim.core.tool.Model):
|
|||||||
return axes
|
return axes
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def remove_array_from_element(cls, element):
|
def handle_array_on_copied_element(cls, element, array_data=None):
|
||||||
array_pset = ifcopenshell.util.element.get_pset(element, "BBIM_Array")
|
"""if no `array_data` is provided then an array will be removed from the element"""
|
||||||
if not array_pset:
|
|
||||||
return
|
|
||||||
|
|
||||||
array_pset_data = array_pset["Data"]
|
if array_data is None:
|
||||||
array_pset = tool.Ifc.get().by_id(array_pset["id"])
|
array_pset = ifcopenshell.util.element.get_pset(element, "BBIM_Array")
|
||||||
ifcopenshell.api.run("pset.remove_pset", tool.Ifc.get(), product=element, pset=array_pset)
|
if not array_pset:
|
||||||
|
return
|
||||||
|
|
||||||
# remove constraints
|
array_pset_data = array_pset["Data"]
|
||||||
obj = tool.Ifc.get_object(element)
|
array_pset = tool.Ifc.get().by_id(array_pset["id"])
|
||||||
if not array_pset_data and (
|
ifcopenshell.api.run("pset.remove_pset", tool.Ifc.get(), product=element, pset=array_pset)
|
||||||
constraint := next((c for c in obj.constraints if c.type == "CHILD_OF"), None)
|
|
||||||
): # skip array parents
|
# remove constraints
|
||||||
obj.constraints.remove(constraint)
|
obj = tool.Ifc.get_object(element)
|
||||||
tool.Blender.lock_transform(obj, False)
|
if not array_pset_data: # skip array parents
|
||||||
|
constraint = next((c for c in obj.constraints if c.type == "CHILD_OF"), None)
|
||||||
|
if constraint:
|
||||||
|
matrix = obj.matrix_world.copy()
|
||||||
|
obj.constraints.remove(constraint)
|
||||||
|
# keep the matrix before the constraint
|
||||||
|
# otherwise object will jump to some previous position
|
||||||
|
obj.matrix_world = matrix
|
||||||
|
tool.Blender.lock_transform(obj, False)
|
||||||
|
|
||||||
|
else:
|
||||||
|
obj = tool.Ifc.get_object(element)
|
||||||
|
array_pset = tool.Pset.get_element_pset(element, "BBIM_Array")
|
||||||
|
default_data = '[{"children": []}]'
|
||||||
|
ifcopenshell.api.run(
|
||||||
|
"pset.edit_pset",
|
||||||
|
tool.Ifc.get(),
|
||||||
|
pset=array_pset,
|
||||||
|
properties={"Parent": element.GlobalId, "Data": default_data},
|
||||||
|
)
|
||||||
|
|
||||||
|
tool.Model.regenerate_array(obj, array_data)
|
||||||
|
|
||||||
|
json_data = json.dumps(array_data)
|
||||||
|
ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=array_pset, properties={"Data": json_data})
|
||||||
|
|
||||||
|
for i in range(len(array_data)):
|
||||||
|
tool.Blender.Modifier.Array.set_children_lock_state(element, i, True)
|
||||||
|
tool.Blender.Modifier.Array.constrain_children_to_parent(element)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def regenerate_array(cls, parent, data, keep_objs=False):
|
def regenerate_array(cls, parent_obj, data, keep_objs=False):
|
||||||
tool.Blender.Modifier.Array.remove_constraints(tool.Ifc.get_entity(parent))
|
tool.Blender.Modifier.Array.remove_constraints(tool.Ifc.get_entity(parent_obj))
|
||||||
|
|
||||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||||
obj_stack = [parent]
|
obj_stack = [parent_obj]
|
||||||
|
|
||||||
for array in data:
|
for array in data:
|
||||||
if array["sync_children"]:
|
if array["sync_children"]:
|
||||||
|
|||||||
Reference in New Issue
Block a user