Make the 'Angle Between' node report the signed angle and fix its zero-vector output (#4362)

This commit is contained in:
Keavon Chambers
2026-07-22 22:39:36 -07:00
committed by Dennis Kobert
parent dfec7c9e4b
commit 77f7e654e8

View File

@@ -1293,11 +1293,23 @@ fn cross_product(
/// Calculates the angle swept between two vec2s.
///
/// The value is always positive and ranges from 0° (both vec2s point the same direction) to 180° (both vec2s point opposite directions).
/// The angle ranges from -180° to 180° (or -π to π radians) and its sign gives the sweep direction from the "Direction From" input to the "Direction To" input: positive for clockwise, negative for counterclockwise, as drawn in the viewport and matching the direction convention of the Transform node's rotation.
#[node_macro::node(category("Math: Vec2"))]
fn angle_between(_: impl Ctx, vector_a: DVec2, vector_b: DVec2, radians: bool) -> f64 {
let dot_product = vector_a.normalize_or_zero().dot(vector_b.normalize_or_zero());
let angle = dot_product.acos();
fn angle_between(
_: impl Ctx,
/// The direction the angle is measured from.
direction_from: DVec2,
/// The direction the angle is measured to.
#[default(1., 0.)]
direction_to: DVec2,
/// Whether the resulting angle should be given in radians instead of degrees.
radians: bool,
) -> f64 {
if direction_from == DVec2::ZERO || direction_to == DVec2::ZERO {
return 0.;
}
let angle = direction_from.angle_to(direction_to);
if radians { angle } else { angle.to_degrees() }
}
@@ -1430,6 +1442,21 @@ mod test {
assert!(lerp_between(5., -0., 1.).is_sign_negative());
}
#[test]
pub fn angle_between_signed() {
let right = DVec2::new(1., 0.);
let down = DVec2::new(0., 1.);
let angle = |a, b, radians| angle_between(&(), a, b, radians);
assert_eq!(angle(right, down, false), 90.);
assert_eq!(angle(down, right, false), -90.);
}
#[test]
pub fn angle_between_zero_vector() {
let (zero, right) = (DVec2::ZERO, DVec2::new(1., 0.));
assert_eq!(angle_between(&(), zero, right, false), 0.);
}
#[test]
pub fn clamp_vec2_within_swapped_bounds() {
let vec2 = |x, y| DVec2::new(x, y);