ga3 0.3.7

Common types for 3D geometric algebra
Documentation
use ga3::{Bivector, Rotor, Vector};
use inner_space::{DotProduct, InnerSpace};
use scalars::Exp;

fn wedge(a: Vector<f32>, b: Vector<f32>) -> Bivector<f32> {
    let product: Rotor<f32> = a * b;
    Bivector::new(product.xy, product.xz, product.yz)
}

#[test]
fn vector_bivector_dot_matches_rotation_derivative() {
    let plane = Bivector::new(0.7, -1.2, 0.5);
    let vector = Vector::new(0.3, -0.7, 1.1);

    let predicted = vector.dot(&plane);

    let angle = 1e-3;
    let rotated = (plane * (angle * 0.5)).exp().rotate(vector);
    let actual = (rotated - vector) / angle;

    assert!(
        (predicted - actual).magnitude() < 1e-2,
        "dot ({}, {}, {}) vs rotation derivative ({}, {}, {})",
        predicted.x,
        predicted.y,
        predicted.z,
        actual.x,
        actual.y,
        actual.z
    );
}

#[test]
fn rotor_product_composes_left_to_right() {
    let first = Bivector::new(0.4, 0.1, 0.3).exp();
    let second = Bivector::new(-0.2, 0.5, 0.1).exp();
    let vector = Vector::new(0.3, -0.7, 1.1);

    let composed = (first * second).rotate(vector);
    let sequential = second.rotate(first.rotate(vector));

    assert!((composed - sequential).magnitude() < 1e-5);
}

#[test]
fn rotate_bivector_matches_rotated_wedge() {
    let rotor = Bivector::new(0.4, 0.1, 0.3).exp();
    let a = Vector::new(0.3, -0.7, 1.1);
    let b = Vector::new(-0.5, 0.2, 0.9);

    let direct = rotor.rotate_bivector(wedge(a, b));
    let expected = wedge(rotor.rotate(a), rotor.rotate(b));

    let difference = direct - expected;
    assert!(difference.scalar(&difference) < 1e-10);
}