pub type Vec2 = [f64; 2];
#[inline]
pub fn add(a: Vec2, b: Vec2) -> Vec2 {
[a[0] + b[0], a[1] + b[1]]
}
#[inline]
pub fn sub(a: Vec2, b: Vec2) -> Vec2 {
[a[0] - b[0], a[1] - b[1]]
}
#[inline]
pub fn scale(a: Vec2, s: f64) -> Vec2 {
[a[0] * s, a[1] * s]
}
#[inline]
pub fn dot(a: Vec2, b: Vec2) -> f64 {
a[0] * b[0] + a[1] * b[1]
}
#[inline]
pub fn cross(a: Vec2, b: Vec2) -> f64 {
a[0] * b[1] - a[1] * b[0]
}
#[inline]
pub fn norm(a: Vec2) -> f64 {
(a[0] * a[0] + a[1] * a[1]).sqrt()
}
#[inline]
pub fn norm_squared(a: Vec2) -> f64 {
a[0] * a[0] + a[1] * a[1]
}
#[inline]
pub fn normalize(a: Vec2) -> Vec2 {
let n = norm(a);
if n < 1e-12 {
[0.0, 0.0]
} else {
[a[0] / n, a[1] / n]
}
}
#[inline]
pub fn distance(a: Vec2, b: Vec2) -> f64 {
norm(sub(a, b))
}
#[inline]
pub fn lerp(a: Vec2, b: Vec2, t: f64) -> Vec2 {
[a[0] + t * (b[0] - a[0]), a[1] + t * (b[1] - a[1])]
}
#[inline]
pub fn rotate(v: Vec2, angle: f64) -> Vec2 {
let (s, c) = angle.sin_cos();
[c * v[0] - s * v[1], s * v[0] + c * v[1]]
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn basic_ops() {
assert_eq!(add([1.0, 2.0], [3.0, 4.0]), [4.0, 6.0]);
assert_eq!(sub([3.0, 4.0], [1.0, 2.0]), [2.0, 2.0]);
assert_eq!(scale([1.0, 2.0], 3.0), [3.0, 6.0]);
assert_eq!(dot([1.0, 2.0], [3.0, 4.0]), 11.0);
}
#[test]
fn normalize_zero_is_zero() {
assert_eq!(normalize([0.0, 0.0]), [0.0, 0.0]);
}
#[test]
fn rotate_90_degrees() {
let r = rotate([1.0, 0.0], std::f64::consts::FRAC_PI_2);
assert!((r[0]).abs() < 1e-9);
assert!((r[1] - 1.0).abs() < 1e-9);
}
}