diff --git a/src/bonsai/bonsai/bim/module/geometry/operator.py b/src/bonsai/bonsai/bim/module/geometry/operator.py index 9bc0566532..6d62d6cccf 100644 --- a/src/bonsai/bonsai/bim/module/geometry/operator.py +++ b/src/bonsai/bonsai/bim/module/geometry/operator.py @@ -1531,8 +1531,13 @@ class DuplicateMoveLinkedAggregate(bpy.types.Operator): old_to_new = OverrideDuplicateMove.execute_ifc_duplicate_operator(self, context, linked=True) all_old_to_new.update(old_to_new) # Collect all duplicates - # Recreate aggregate structure - tool.Root.recreate_aggregate(old_to_new) + # Note: execute_ifc_duplicate_operator() above already recreates the aggregate + # structure for us (including reassigning to an unduplicated parent aggregate, see + # its "Restore parent aggregate relationships" step). Calling + # tool.Root.recreate_aggregate() again here is not just redundant: since the parent + # aggregate is never part of `old_to_new` when it wasn't itself duplicated, + # recreate_aggregate()'s "parent not found" branch actively *unassigns* the just + # restored parent link, stranding a duplicated nested aggregate outside its parent (#6663). # Copy linked aggregate data copy_linked_aggregate_data(old_to_new) diff --git a/src/bonsai/test/bim/feature/geometry.feature b/src/bonsai/test/bim/feature/geometry.feature index 1236f416c8..fa2a1dbafd 100644 --- a/src/bonsai/test/bim/feature/geometry.feature +++ b/src/bonsai/test/bim/feature/geometry.feature @@ -610,6 +610,21 @@ Scenario: Duplicate linked aggregate And the object "Assembly_01" exists Then the object "IfcElementAssembly/Assembly" and "Assembly_01" belong to the same Linked Aggregate Group +Scenario: Duplicate linked aggregate - a nested aggregate stays inside its parent aggregate + Given I load the IFC test file "/test/files/linked-aggregates.ifc" + And the object "IfcWall/Wall_01" is selected + And additionally the object "IfcWall/Wall_02" is selected + When I press "bim.add_aggregate(aggregate_name='Nested')" + Then the object "IfcElementAssembly/Nested" is aggregated by object "IfcElementAssembly/Assembly" + When the object "IfcWall/Wall_01" is selected + And I duplicate linked aggregate the selected objects + Then the object "IfcWall/Wall_01.001" exists + And the object "IfcWall/Wall_02.001" exists + # msgbus updates don't happen in background mode, so obj is not renamed to "IfcElementAssembly/Nested_01" + And the object "Nested_01" exists + And the object "IfcWall/Wall_01.001" is aggregated by object "Nested_01" + And the object "Nested_01" is aggregated by object "IfcElementAssembly/Assembly" + Scenario: Refresh linked aggregate Given I load the IFC test file "/test/files/linked-aggregates.ifc" And the object "IfcWall/Wall_01" is selected