diff --git a/src/bonsai/bonsai/bim/module/drawing/decoration.py b/src/bonsai/bonsai/bim/module/drawing/decoration.py index 470bccf8ad..6251cf1c87 100644 --- a/src/bonsai/bonsai/bim/module/drawing/decoration.py +++ b/src/bonsai/bonsai/bim/module/drawing/decoration.py @@ -1643,7 +1643,7 @@ class CutDecorator: # Check if any viewport is in local view - skip decorations if so for area in context.screen.areas: - if area.type == 'VIEW_3D': + if area.type == "VIEW_3D": space = area.spaces.active if isinstance(space, bpy.types.SpaceView3D) and space.local_view: return # Don't draw decorations in local view @@ -1995,7 +1995,7 @@ class DecorationsHandler: def __call__(self, context): # Check if any viewport is in local view - skip decorations if so for area in context.screen.areas: - if area.type == 'VIEW_3D': + if area.type == "VIEW_3D": space = area.spaces.active if isinstance(space, bpy.types.SpaceView3D) and space.local_view: return # Don't draw decorations in local view diff --git a/src/bonsai/bonsai/bim/module/geometry/operator.py b/src/bonsai/bonsai/bim/module/geometry/operator.py index 34faa89428..17d57c8d56 100644 --- a/src/bonsai/bonsai/bim/module/geometry/operator.py +++ b/src/bonsai/bonsai/bim/module/geometry/operator.py @@ -1204,6 +1204,7 @@ class DuplicateMoveLinkedAggregateMacro(bpy.types.Macro): bl_label = "IFC Duplicate and Move Linked Aggregate" bl_options = {"REGISTER", "UNDO"} + class DuplicateMoveLinkedAggregate(bpy.types.Operator): bl_idname = "bim.object_duplicate_move_linked_aggregate" bl_label = "IFC Duplicate and Move Linked Aggregate" @@ -1289,7 +1290,11 @@ class DuplicateMoveLinkedAggregate(bpy.types.Operator): new_obj.name = pset["Name"] + "_" + str(pset["Aggregate_Index"]) def get_max_index(parts): - psets = [ifcopenshell.util.element.get_pset(p, "BBIM_Linked_Aggregate") for p in parts if ifcopenshell.util.element.get_pset(p, "BBIM_Linked_Aggregate")] + psets = [ + ifcopenshell.util.element.get_pset(p, "BBIM_Linked_Aggregate") + for p in parts + if ifcopenshell.util.element.get_pset(p, "BBIM_Linked_Aggregate") + ] if psets: index = max([i["Index"] for i in psets if i]) return index @@ -1315,9 +1320,13 @@ class DuplicateMoveLinkedAggregate(bpy.types.Operator): group_elements = [] if new[0].is_a("IfcElementAssembly"): group_elements = next( - (r.RelatedObjects for r in getattr(new[0], "HasAssignments", []) or [] - if r.is_a("IfcRelAssignsToGroup") and "BBIM_Linked_Aggregate" in r.RelatingGroup.Name), - [] + ( + r.RelatedObjects + for r in getattr(new[0], "HasAssignments", []) or [] + if r.is_a("IfcRelAssignsToGroup") + and "BBIM_Linked_Aggregate" in r.RelatingGroup.Name + ), + [], ) properties = { "Index": pset["Index"], @@ -1355,41 +1364,41 @@ class DuplicateMoveLinkedAggregate(bpy.types.Operator): elif selected_element.Decomposes: if selected_element.Decomposes[0].RelatingObject.is_a("IfcElementAssembly"): selected_aggregates.append(selected_element.Decomposes[0].RelatingObject) - + # Remove duplicates selected_aggregates = list(set(selected_aggregates)) - + if not selected_aggregates: self.report({"INFO"}, "No Linked Aggregates selected.") return {"FINISHED"} # Deselect all first bpy.ops.object.select_all(action="DESELECT") - + # Process each selected aggregate for aggregate in selected_aggregates: aggregate_obj = tool.Ifc.get_object(aggregate) - + # Select and prepare the aggregate for duplication select_objects_and_add_data(aggregate) - + # Duplicate the aggregate 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) - + # Copy linked aggregate data copy_linked_aggregate_data(old_to_new) - + # Apply custom naming custom_incremental_naming_for_element_assembly(old_to_new) - + # Apply 3D cursor location if requested if location_from_3d_cursor: get_location_from_3d_cursor(old_to_new, aggregate) - + # Deselect for next iteration bpy.ops.object.select_all(action="DESELECT") @@ -1410,6 +1419,7 @@ class DuplicateMoveLinkedAggregate(bpy.types.Operator): return all_old_to_new + class DuplicateLinkedAggregateTo3dCursor(bpy.types.Operator): bl_idname = "bim.duplicate_linked_aggregate_to_3d_cursor" bl_label = "IFC Duplicate Linked Aggregate to 3d Cursor" diff --git a/src/bonsai/bonsai/bim/module/qto/operator.py b/src/bonsai/bonsai/bim/module/qto/operator.py index c8d32b5829..47b0f5059a 100644 --- a/src/bonsai/bonsai/bim/module/qto/operator.py +++ b/src/bonsai/bonsai/bim/module/qto/operator.py @@ -149,7 +149,7 @@ class CalculateSingleQuantity(bpy.types.Operator, tool.Ifc.Operator): } ifc_file = tool.Ifc.get() - with(Profiler("Quantify function time:")): + with Profiler("Quantify function time:"): results = ifc5d.qto.quantify(ifc_file, elements, rules) ifc5d.qto.edit_qtos(ifc_file, results) @@ -192,7 +192,7 @@ class PerformQuantityTakeOff(bpy.types.Operator, tool.Ifc.Operator): ) -> set[ifcopenshell.entity_instance]: rules = ifc5d.qto.rules[rule] ifc_file = tool.Ifc.get() - with(Profiler("Quantify function time:")): + with Profiler("Quantify function time:"): results = ifc5d.qto.quantify(ifc_file, elements, rules) ifc5d.qto.edit_qtos(ifc_file, results) not_quantified_elements = elements - set(results.keys()) diff --git a/src/bonsai/bonsai/core/drawing.py b/src/bonsai/bonsai/core/drawing.py index 4a378a7e73..88c12295fa 100644 --- a/src/bonsai/bonsai/core/drawing.py +++ b/src/bonsai/bonsai/core/drawing.py @@ -60,20 +60,20 @@ def edit_assigned_product( ) -> None: element = ifc.get_entity(obj) assert element - + # Get ALL existing products, not just one existing_products = [] - if hasattr(element, 'HasAssignments'): + if hasattr(element, "HasAssignments"): for rel in element.HasAssignments: - if rel.is_a('IfcRelAssignsToProduct'): + if rel.is_a("IfcRelAssignsToProduct"): existing_products.append(rel.RelatingProduct) - + # Only proceed if the assignment is different if not (len(existing_products) == 1 and existing_products[0] == product): # Unassign from ALL existing products for existing_product in existing_products: ifc.run("drawing.unassign_product", relating_product=existing_product, related_object=element) - + # Assign to the new product if product: ifc.run("drawing.assign_product", relating_product=product, related_object=element) diff --git a/src/ifcopenshell-python/ifcopenshell/util/profiler.py b/src/ifcopenshell-python/ifcopenshell/util/profiler.py index aabfe37977..2228a54a6a 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/profiler.py +++ b/src/ifcopenshell-python/ifcopenshell/util/profiler.py @@ -19,6 +19,7 @@ from timeit import default_timer as timer + class Profiler: """ A python context manager timing utility, useful for measure functions performances