diff --git a/src/bonsai/bonsai/bim/module/model/decorator.py b/src/bonsai/bonsai/bim/module/model/decorator.py index 56e8ab07d1..69fa8a7aee 100644 --- a/src/bonsai/bonsai/bim/module/model/decorator.py +++ b/src/bonsai/bonsai/bim/module/model/decorator.py @@ -413,7 +413,7 @@ class PolylineDecorator: distance = (snap_vector - last_point).length if distance > 0: - angle = tool.Cad.angle_3_vectors(second_to_last_point, last_point, snap_vector, degrees=True) + angle = tool.Cad.angle_3_vectors(second_to_last_point, last_point, snap_vector, new_angle=None, degrees=True) if cls.input_panel: cls.input_panel["X"] = str(round(snap_vector.x, 3)) cls.input_panel["Y"] = str(round(snap_vector.y, 3)) @@ -496,20 +496,7 @@ class PolylineDecorator: if distance < 0 or distance > 0: angle = radians(float(cls.input_panel["A"])) - # TODO This is basically the reverse process of tool.Cad.angle_3_vectors - # Combine them into a single function - v1 = second_to_last_point - last_point - v2 = snap_vector - last_point - - v1.normalize() - v2.normalize() - - # Calculate the axis of rotation - axis = v1.cross(v2).normalized() - rot_mat = Matrix.Rotation(angle, 3, axis) - parameter = round(axis.z, 2) < 0 or (round(axis.y, 2) == 0 and round(axis.x < 0)) or (round(axis.x, 2) == 0 and round(axis.y < 0)) - - rot_vector = (v1 @ rot_mat) if parameter else (rot_mat @ v1) + rot_vector = tool.Cad.angle_3_vectors(second_to_last_point, last_point, snap_vector, angle, degrees=True) coords = rot_vector * distance + last_point diff --git a/src/bonsai/bonsai/tool/cad.py b/src/bonsai/bonsai/tool/cad.py index 419edc49d6..bd735cda98 100644 --- a/src/bonsai/bonsai/tool/cad.py +++ b/src/bonsai/bonsai/tool/cad.py @@ -85,32 +85,39 @@ class Cad: return math.degrees(a) if degrees else a @classmethod - def angle_3_vectors(cls, v1, v2, v3, degrees=False): + def angle_3_vectors(cls, v1, v2, v3, new_angle=None, degrees=False): """ > takes 3 vectors. The order matters, v2 is the center point. < returns the signed angle as degrees or radians + < if a new angle is provided, return the rotation vector """ d1 = v1 - v2 d2 = v3 - v2 - axis = d1.cross(d2) - print(axis) - print(round(axis.z, 2)) - axis.normalize() + d1.normalize() + d2.normalize() + + axis = d1.cross(d2).normalized() # Calculate the unsigned angle between the "d1" and "d2" vectors a = d1.angle(d2) # Determine the sign of the angle based on the provided axis + # If new_angle, determine the direction of the rotation parameter = round(axis.z, 2) < 0 or (round(axis.y, 2) == 0 and round(axis.x < 0)) or (round(axis.x, 2) == 0 and round(axis.y < 0)) - sign = -1 if parameter else 1 - - if degrees: - a = math.degrees(a) - return a * sign + if new_angle: + rot_mat = Matrix.Rotation(new_angle, 3, axis) + rot_vector = (d1 @ rot_mat) if parameter else (rot_mat @ d1) + return rot_vector else: - return a + sign = -1 if parameter else 1 + + if degrees: + a = math.degrees(a) + return a * sign + else: + return a @classmethod def is_x(cls, value: float, x: float, tolerance: float | None = None) -> bool: