diff --git a/src/bonsai/bonsai/bim/module/geometry/operator.py b/src/bonsai/bonsai/bim/module/geometry/operator.py index 000257265e..6242f1d35c 100644 --- a/src/bonsai/bonsai/bim/module/geometry/operator.py +++ b/src/bonsai/bonsai/bim/module/geometry/operator.py @@ -38,7 +38,7 @@ import bonsai.core.root import bonsai.core.drawing import bonsai.tool as tool import bonsai.bim.handler -from mathutils import Vector, Matrix +from mathutils import Vector, Matrix, Quaternion from time import time from bonsai.bim.ifc import IfcStore from ifcopenshell.util.shape_builder import ShapeBuilder @@ -1399,9 +1399,9 @@ class RefreshLinkedAggregate(bpy.types.Operator, tool.Ifc.Operator): self.pset_name = "BBIM_Linked_Aggregate" refresh_start_time = time() old_to_new = {} - original_names = {} + original_names: dict[int, dict[int, str]] = {} - def delete_objects(element): + def delete_objects(element: ifcopenshell.entity_instance) -> None: parts = ifcopenshell.util.element.get_parts(element) if parts: for part in parts: @@ -1412,7 +1412,7 @@ class RefreshLinkedAggregate(bpy.types.Operator, tool.Ifc.Operator): tool.Geometry.delete_ifc_object(tool.Ifc.get_object(element)) - def get_original_names(element): + def get_original_names(element: ifcopenshell.entity_instance) -> dict[int, dict[int, str]]: group = [ r.RelatingGroup for r in getattr(element, "HasAssignments", []) or [] @@ -1429,6 +1429,7 @@ class RefreshLinkedAggregate(bpy.types.Operator, tool.Ifc.Operator): if parts: for part in parts: if part.is_a("IfcElementAssembly"): + # TODO: missing assignment. original_names | get_original_names(part) else: try: @@ -1441,7 +1442,7 @@ class RefreshLinkedAggregate(bpy.types.Operator, tool.Ifc.Operator): return original_names - def set_original_name(obj, original_names): + def set_original_name(obj: bpy.types.Object, original_names: dict[int, dict[int, str]]) -> None: element = tool.Ifc.get_entity(obj) aggregate = ifcopenshell.util.element.get_aggregate(element) if ifcopenshell.util.element.get_parts( @@ -1468,7 +1469,7 @@ class RefreshLinkedAggregate(bpy.types.Operator, tool.Ifc.Operator): except: return - def get_element_assembly(element): + def get_element_assembly(element: ifcopenshell.entity_instance) -> Union[ifcopenshell.entity_instance, None]: if element.is_a("IfcElementAssembly"): return element elif element.Decomposes: @@ -1478,7 +1479,9 @@ class RefreshLinkedAggregate(bpy.types.Operator, tool.Ifc.Operator): else: return None - def handle_selection(selected_objs): + def handle_selection( + selected_objs: list[bpy.types.Object], + ) -> tuple[list[int], list[ifcopenshell.entity_instance]]: selected_elements = [tool.Ifc.get_entity(selected_obj) for selected_obj in selected_objs] if None in selected_elements: self.report({"INFO"}, "Object has no Ifc Metadata.") @@ -1509,7 +1512,9 @@ class RefreshLinkedAggregate(bpy.types.Operator, tool.Ifc.Operator): return list(set(linked_aggregate_groups)), selected_parents - def get_original_matrix(element, base_instance): + def get_original_matrix( + element: ifcopenshell.entity_instance, base_instance: ifcopenshell.entity_instance + ) -> tuple[Matrix, tuple[Vector, Quaternion, Vector]]: selected_obj = tool.Ifc.get_object(base_instance) selected_matrix = selected_obj.matrix_world object_duplicate = tool.Ifc.get_object(element) @@ -1517,7 +1522,9 @@ class RefreshLinkedAggregate(bpy.types.Operator, tool.Ifc.Operator): return selected_matrix, duplicate_matrix - def set_new_matrix(selected_matrix, duplicate_matrix, old_to_new): + def set_new_matrix( + selected_matrix: Matrix, duplicate_matrix: tuple[Vector, Quaternion, Vector], old_to_new: dict + ) -> None: for old, new in old_to_new.items(): new_obj = tool.Ifc.get_object(new[0]) new_base_matrix = Matrix.LocRotScale(*duplicate_matrix) diff --git a/src/bonsai/bonsai/bim/module/model/polyline.py b/src/bonsai/bonsai/bim/module/model/polyline.py index 0d09f87035..4484a39eb7 100644 --- a/src/bonsai/bonsai/bim/module/model/polyline.py +++ b/src/bonsai/bonsai/bim/module/model/polyline.py @@ -16,6 +16,7 @@ # You should have received a copy of the GNU General Public License # along with Bonsai. If not, see . +from __future__ import annotations import bpy import copy import math @@ -46,6 +47,9 @@ class PolylineOperator: # TODO Fill doc strings """ """ + number_input: list[str] + input_type: tool.Polyline.InputType + @classmethod def poll(cls, context: bpy.types.Context) -> bool: return context.space_data.type == "VIEW_3D" @@ -81,7 +85,6 @@ class PolylineOperator: self.number_is_negative = False self.input_options = ["D", "A", "X", "Y"] self.input_type = None - self.input_type = None self.input_value_xy = [None, None] self.input_ui = tool.Polyline.create_input_ui() self.is_typing = False diff --git a/src/bonsai/bonsai/bim/module/model/wall.py b/src/bonsai/bonsai/bim/module/model/wall.py index 25b3ee1e30..88db7f3a26 100644 --- a/src/bonsai/bonsai/bim/module/model/wall.py +++ b/src/bonsai/bonsai/bim/module/model/wall.py @@ -41,7 +41,7 @@ from mathutils import Vector, Matrix from bonsai.bim.module.model.opening import FilledOpeningGenerator from bonsai.bim.module.model.decorator import PolylineDecorator, ProductDecorator from bonsai.bim.module.model.polyline import PolylineOperator -from typing import Optional, assert_never, TYPE_CHECKING, get_args, Literal +from typing import Optional, assert_never, TYPE_CHECKING, get_args, Literal, Union, Any from lark import Lark, Transformer @@ -330,7 +330,7 @@ class DrawPolylineWall(bpy.types.Operator, PolylineOperator): if relating_type_id: self.relating_type = tool.Ifc.get().by_id(int(relating_type_id)) - def create_walls_from_polyline(self, context): + def create_walls_from_polyline(self, context: bpy.types.Context) -> Union[set[str], None]: if not self.relating_type: return {"FINISHED"} @@ -587,7 +587,7 @@ class DumbWallGenerator: and bpy.context.scene.grease_pencil.layers[0].active_frame.strokes ) - def derive_from_polyline(self): + def derive_from_polyline(self) -> tuple[list[Union[dict[str, Any], None]], bool]: polyline_data = bpy.context.scene.BIMPolylineProperties.insertion_polyline polyline_points = polyline_data[0].polyline_points if polyline_data else [] is_polyline_closed = False @@ -658,7 +658,7 @@ class DumbWallGenerator: bpy.context.scene.grease_pencil.layers.remove(layer) return objs - def create_wall_from_2_points(self, coords, should_round=False): + def create_wall_from_2_points(self, coords, should_round=False) -> Union[dict[str, Any], None]: direction = coords[1] - coords[0] length = direction.length if round(length, 4) < 0.1: @@ -696,7 +696,7 @@ class DumbWallGenerator: def is_near(self, point1, point2): return (point1 - point2).length < 0.1 - def derive_from_cursor(self): + def derive_from_cursor(self) -> bpy.types.Object: RAYCAST_PRECISION = 0.01 self.location = bpy.context.scene.cursor.location if self.container: @@ -746,7 +746,7 @@ class DumbWallGenerator: break return self.create_wall() - def create_wall(self): + def create_wall(self) -> bpy.types.Object: props = bpy.context.scene.BIMModelProperties ifc_class = self.get_relating_type_class(self.relating_type) mesh = bpy.data.meshes.new("Dummy") diff --git a/src/bonsai/bonsai/tool/polyline.py b/src/bonsai/bonsai/tool/polyline.py index 60ac79606e..612b1a6422 100644 --- a/src/bonsai/bonsai/tool/polyline.py +++ b/src/bonsai/bonsai/tool/polyline.py @@ -26,7 +26,7 @@ from dataclasses import dataclass from lark import Lark, Transformer from math import degrees, radians, sin, cos, tan from mathutils import Vector, Matrix -from typing import Optional, Union +from typing import Optional, Union, Literal class Polyline(bonsai.core.tool.Polyline): @@ -75,6 +75,8 @@ class Polyline(bonsai.core.tool.Polyline): else: return Polyline.format_input_ui_units(value) + InputType = Literal["D", "A", "X", "Y", None] + @dataclass class ToolState: use_default_container: bool = None @@ -83,8 +85,8 @@ class Polyline(bonsai.core.tool.Polyline): lock_axis: bool = False # angle_axis_start: Vector # angle_axis_end: Vector - axis_method: str = None - plane_method: str = None + axis_method: Literal["X", "Y", "Z", None] = None + plane_method: Literal["XY", "XZ", "YZ", None] = None plane_origin: Vector = Vector((0.0, 0.0, 0.0)) instructions: str = """TAB: Cycle Input M: Modify Snap Point @@ -94,8 +96,8 @@ class Polyline(bonsai.core.tool.Polyline): L: Lock axis """ snap_info: str = None - mode: str = None - input_type: str = None + mode: Literal["Mouse", "Select", "Edit", None] = None + input_type: "Polyline.InputType" = None @classmethod def create_input_ui(cls, init_z: bool = False, init_area: bool = False) -> PolylineUI: @@ -307,7 +309,13 @@ class Polyline(bonsai.core.tool.Polyline): return @classmethod - def validate_input(cls, input_number, input_type) -> tuple[bool, str]: + def validate_input(cls, input_number: str, input_type: InputType) -> tuple[bool, str]: + """ + + :return: Tuple with a boolean indicating if the input is valid + and the final string output. + Distance units converted to meters, angles input/output is in degrees. + """ grammar_imperial = """ start: (FORMULA dim expr) | dim @@ -395,7 +403,7 @@ class Polyline(bonsai.core.tool.Polyline): elif op == "/": return lambda x: x / value - def FORMULA(cls, args): + def FORMULA(self, args): return args[0] def start(self, args): diff --git a/src/bonsai/bonsai/tool/snap.py b/src/bonsai/bonsai/tool/snap.py index 3c8e228bae..1a06d15fd4 100644 --- a/src/bonsai/bonsai/tool/snap.py +++ b/src/bonsai/bonsai/tool/snap.py @@ -250,7 +250,7 @@ class Snap(bonsai.core.tool.Snap): return sorted_intersections @classmethod - def detect_snapping_points(cls, context, event, objs_2d_bbox, tool_state): + def detect_snapping_points(cls, context: bpy.types.Context, event: bpy.types.Event, objs_2d_bbox, tool_state): rv3d = context.region_data space = context.space_data mouse_pos = event.mouse_region_x, event.mouse_region_y