From 8060c790ed2018e02b1b99eb1f1d5348cb2d56f0 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Thu, 15 Jan 2026 22:00:51 +1100 Subject: [PATCH] Black --- src/bonsai/bonsai/bim/module/geometry/operator.py | 8 ++++---- src/bonsai/bonsai/bim/module/model/wall.py | 12 +++++++----- src/bonsai/bonsai/bim/module/spatial/operator.py | 14 +++++++------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/geometry/operator.py b/src/bonsai/bonsai/bim/module/geometry/operator.py index 4927c9cfab..a35a4de7bc 100644 --- a/src/bonsai/bonsai/bim/module/geometry/operator.py +++ b/src/bonsai/bonsai/bim/module/geometry/operator.py @@ -1723,11 +1723,11 @@ class RefreshLinkedAggregate(bpy.types.Operator, tool.Ifc.Operator): container=container, element_obj=obj, ) - + # Get the container's collection for moving parts in the outliner container_obj = tool.Ifc.get_object(container) container_collection = container_obj.BIMObjectProperties.collection if container_obj else None - + # Move all parts to the container's collection in the outliner if container_collection: for part in ifcopenshell.util.element.get_parts(element): @@ -1736,11 +1736,11 @@ class RefreshLinkedAggregate(bpy.types.Operator, tool.Ifc.Operator): # Remove from all previous collections for col in part_obj.users_collection[:]: col.objects.unlink(part_obj) - + # Link to container collection if part_obj.name not in container_collection.objects: container_collection.objects.link(part_obj) - + # Recursively handle nested parts for nested_part in ifcopenshell.util.element.get_parts(part): nested_part_obj = tool.Ifc.get_object(nested_part) diff --git a/src/bonsai/bonsai/bim/module/model/wall.py b/src/bonsai/bonsai/bim/module/model/wall.py index 0d0b88339e..d652041125 100644 --- a/src/bonsai/bonsai/bim/module/model/wall.py +++ b/src/bonsai/bonsai/bim/module/model/wall.py @@ -575,20 +575,22 @@ class ChangeExtrusionXAngle(bpy.types.Operator, tool.Ifc.Operator): rotation_axis.normalize() dot_product = expected_new_world_direction.dot(current_world_direction) angle = acos(min(max(dot_product, -1), 1)) - + # Rotate around object's own origin # Decompose the matrix to get translation, rotation, scale translation, rotation, scale = obj.matrix_world.decompose() - + # Create rotation matrix and convert to quaternion rotation_matrix = Matrix.Rotation(angle, 4, rotation_axis) rotation_quat = rotation_matrix.to_quaternion() - + # Apply rotation to existing rotation (quaternion multiplication) new_rotation = rotation_quat @ rotation - + # Reconstruct matrix_world with same translation, new rotation, same scale - obj.matrix_world = Matrix.Translation(translation) @ new_rotation.to_matrix().to_4x4() @ Matrix.Scale(1, 4) + obj.matrix_world = ( + Matrix.Translation(translation) @ new_rotation.to_matrix().to_4x4() @ Matrix.Scale(1, 4) + ) bpy.context.view_layer.update() bonsai.core.geometry.switch_representation( diff --git a/src/bonsai/bonsai/bim/module/spatial/operator.py b/src/bonsai/bonsai/bim/module/spatial/operator.py index 67189666e6..075c3a9a38 100644 --- a/src/bonsai/bonsai/bim/module/spatial/operator.py +++ b/src/bonsai/bonsai/bim/module/spatial/operator.py @@ -183,7 +183,7 @@ class AssignContainer(bpy.types.Operator, tool.Ifc.Operator): root = aggregate current = aggregate return root - + def get_all_parts_recursive(element): """Recursively get all parts of an aggregate""" parts = [] @@ -196,17 +196,17 @@ class AssignContainer(bpy.types.Operator, tool.Ifc.Operator): objs: list[bpy.types.Object] = [] processed_elements = set() # Track elements we've already handled (by IFC ID) promoted_parts = 0 # Count how many parts were promoted to their root aggregate - + for obj in tool.Blender.get_selected_objects(): if not (element := tool.Ifc.get_entity(obj)): continue - + # Check if element is part of an aggregate (at any level) if root_aggregate := get_root_aggregate(element): # Skip if we've already processed this root aggregate if root_aggregate.id() in processed_elements: continue - + # Get the root aggregate object and add it instead if root_aggregate_obj := tool.Ifc.get_object(root_aggregate): objs.append(root_aggregate_obj) @@ -225,13 +225,13 @@ class AssignContainer(bpy.types.Operator, tool.Ifc.Operator): for element_obj in objs: element = tool.Ifc.get_entity(element_obj) - + # Only assign container to the ROOT aggregate (this updates IFC relationships) if self.remove_from_other_containers: for col in element_obj.users_collection[:]: col.objects.unlink(element_obj) core.assign_container(tool.Ifc, tool.Collector, tool.Spatial, container=container, element_obj=element_obj) - + # For parts, only move them in Blender collections (don't change IFC relationships) if container_collection: all_parts = get_all_parts_recursive(element) @@ -240,7 +240,7 @@ class AssignContainer(bpy.types.Operator, tool.Ifc.Operator): # Always remove from ALL previous collections when moving to new container for col in part_obj.users_collection[:]: col.objects.unlink(part_obj) - + # Link to new container collection (Blender-only, no IFC change) if part_obj.name not in container_collection.objects: container_collection.objects.link(part_obj)