use geonum::*;
use std::f64::consts::PI;
const EPSILON: f64 = 1e-10;
#[test]
fn it_adds_aligned_vectors() {
let a = Geonum::new(2.0, 0.0, 1.0);
let b = Geonum::new(3.0, 0.0, 1.0);
let sum = a + b;
assert!(sum.near_mag(5.0));
assert_eq!(sum.angle, Angle::new(0.0, 1.0));
}
#[test]
fn it_handles_opposite_vectors() {
let a = Geonum::new(5.0, 0.0, 1.0);
let b = Geonum::new(3.0, 1.0, 1.0);
let sum = a + b;
assert!(sum.near_mag(2.0));
assert_eq!(sum.angle, a.angle);
}
#[test]
fn it_adds_orthogonal_vectors() {
let a = Geonum::new(3.0, 0.0, 1.0);
let b = Geonum::new(4.0, 1.0, 2.0);
let sum = a + b;
assert!(sum.near_mag(5.0));
let expected_phase = (4.0_f64).atan2(3.0);
assert!(sum.angle.near_rad(expected_phase));
}
#[test]
fn it_adds_high_blades_and_preserves_history() {
let a = Geonum::new_with_blade(2.0, 1000, 0.0, 1.0); let b = Geonum::new_with_blade(3.0, 1001, 1.0, 2.0);
let sum = a + b;
let x1 = a.mag * a.angle.grade_angle().cos();
let y1 = a.mag * a.angle.grade_angle().sin();
let x2 = b.mag * b.angle.grade_angle().cos();
let y2 = b.mag * b.angle.grade_angle().sin();
let expected_phase = (y1 + y2).atan2(x1 + x2);
assert!(sum.angle.near_rad(expected_phase));
}
#[test]
fn it_matches_projection_based_sum() {
let a = Geonum::new(2.0, 1.0, 6.0); let b = Geonum::new(3.0, 1.0, 4.0);
let delta = (b.angle.grade_angle() - a.angle.grade_angle()).rem_euclid(2.0 * PI);
let adj = Geonum::cos(Angle::new(delta, PI)).scale(b.mag);
let opp = Geonum::sin(Angle::new(delta, PI)).scale(b.mag);
let a_along = Geonum::cos(Angle::new(0.0, 1.0)).scale(a.mag);
let sum_in_a = a_along + adj + opp;
let result = Geonum::new_with_angle(sum_in_a.mag, sum_in_a.angle + a.angle);
let direct = a + b;
assert!(result.near_mag(direct.mag));
assert_eq!(result.angle.base_angle(), direct.angle.base_angle());
let adj_len = (Geonum::cos(a.angle).scale(a.mag) + Geonum::cos(b.angle).scale(b.mag)).mag;
let opp_len = (Geonum::sin(a.angle).scale(a.mag) + Geonum::sin(b.angle).scale(b.mag)).mag;
let hyp_sq = adj_len.powi(2) + opp_len.powi(2);
assert!((hyp_sq - direct.mag.powi(2)).abs() < EPSILON);
}
#[test]
fn it_preserves_blade_history_on_cancellation() {
let a = Geonum::new_with_blade(5.0, 7, 0.0, 1.0);
let b = Geonum::new_with_blade(5.0, 3, 1.0, 1.0);
let sum = a + b;
assert!(sum.near_mag(0.0));
let expected = Angle::new(0.0, 1.0) + Angle::new(7.0, 2.0) + Angle::new(3.0, 2.0) + Angle::new(1.0, 1.0); assert_eq!(sum.angle, expected);
}
#[test]
fn it_accumulates_blades_in_general_case() {
let a = Geonum::new_with_blade(2.0, 5, 0.0, 1.0); let b = Geonum::new_with_blade(3.0, 8, 0.0, 1.0);
let sum = a + b;
let x1 = a.mag * a.angle.grade_angle().cos();
let y1 = a.mag * a.angle.grade_angle().sin();
let x2 = b.mag * b.angle.grade_angle().cos();
let y2 = b.mag * b.angle.grade_angle().sin();
let expected_mag = ((x1 + x2).powi(2) + (y1 + y2).powi(2)).sqrt();
assert!(sum.near_mag(expected_mag));
let cartesian_result = Geonum::new_from_cartesian(x1 + x2, y1 + y2);
let expected = cartesian_result.angle
+ Angle::new(5.0, 2.0) + Angle::new(8.0, 2.0) + Angle::new(3.0, 2.0); assert_eq!(sum.angle, expected);
}
#[test]
fn it_handles_near_opposite_angles() {
let a = Geonum::new(5.0, 0.0, 1.0);
let b = Geonum::new(3.0, 0.999999, 1.0);
let sum = a + b;
assert!((sum.mag - 2.0).abs() < 1e-5); assert_eq!(sum.angle.grade(), 0); }
#[test]
fn it_handles_zero_length_addition() {
let zero = Geonum::new(0.0, 0.0, 1.0);
let a = Geonum::new(5.0, 1.0, 3.0);
let zero_plus_a = zero + a;
assert!(zero_plus_a.near_mag(a.mag));
assert_eq!(zero_plus_a.angle.base_angle(), a.angle.base_angle());
let a_plus_zero = a + zero;
assert!(a_plus_zero.near_mag(a.mag));
assert_eq!(a_plus_zero.angle.base_angle(), a.angle.base_angle());
}
#[test]
fn it_maintains_commutative_blade_accumulation() {
let a = Geonum::new_with_blade(2.0, 3, 1.0, 6.0);
let b = Geonum::new_with_blade(3.0, 5, 1.0, 4.0);
let ab = a + b;
let ba = b + a;
assert!(ab.near_mag(ba.mag));
assert_eq!(ab.angle.base_angle(), ba.angle.base_angle());
assert_eq!(ab.angle, ba.angle);
let x1 = a.mag * a.angle.grade_angle().cos();
let y1 = a.mag * a.angle.grade_angle().sin();
let x2 = b.mag * b.angle.grade_angle().cos();
let y2 = b.mag * b.angle.grade_angle().sin();
let cartesian_result = Geonum::new_from_cartesian(x1 + x2, y1 + y2);
let expected = cartesian_result.angle
+ Angle::new(3.0, 2.0) + Angle::new(5.0, 2.0); assert_eq!(ab.angle, expected);
}