#![cfg(feature = "vec3")]
use gemath::vec3::*;
use gemath::{Degrees, Radians};
#[cfg(test)]
mod tests {
use super::*;
const EPSILON: f32 = if cfg!(feature = "libm") { 1e-6 } else { 1e-7 };
#[test]
fn test_vec3_new() {
let v: Vec3f32 = Vec3::new(1.0, 2.0, 3.0);
assert!((v.x - 1.0).abs() < EPSILON);
assert!((v.y - 2.0).abs() < EPSILON);
assert!((v.z - 3.0).abs() < EPSILON);
}
#[test]
fn test_vec3_zero() {
let v: Vec3f32 = Vec3::ZERO;
assert!((v.x - 0.0).abs() < EPSILON);
assert!((v.y - 0.0).abs() < EPSILON);
assert!((v.z - 0.0).abs() < EPSILON);
}
#[test]
fn test_vec3_default() {
let v: Vec3 = Default::default();
assert!((v.x - 0.0).abs() < EPSILON);
assert!((v.y - 0.0).abs() < EPSILON);
assert!((v.z - 0.0).abs() < EPSILON);
}
#[test]
fn test_vec3_checked_div_scalar() {
let v: Vec3f32 = Vec3::new(2.0, 4.0, 6.0);
assert_eq!(v.checked_div_scalar(2.0), Some(Vec3::new(1.0, 2.0, 3.0)));
assert_eq!(v.checked_div_scalar(0.0), None);
assert_eq!(v.checked_div_scalar(-0.0), None);
assert_eq!(v.checked_div_scalar(f32::NAN), None);
assert_eq!(v.checked_div_scalar(f32::INFINITY), None);
}
#[test]
fn test_vec3_eq() {
let v1: Vec3f32 = Vec3::new(1.0, 2.0, 3.0);
let v2: Vec3f32 = Vec3::new(1.0, 2.0, 3.0);
let v3: Vec3f32 = Vec3::new(3.0, 2.0, 1.0);
assert_eq!(v1, v2);
assert_ne!(v1, v3);
}
#[test]
fn test_vec3_add() {
let v1: Vec3f32 = Vec3::new(1.0, 2.0, 3.0);
let v2: Vec3f32 = Vec3::new(4.0, 5.0, 6.0);
let result = v1 + v2;
assert!((result.x - 5.0).abs() < EPSILON);
assert!((result.y - 7.0).abs() < EPSILON);
assert!((result.z - 9.0).abs() < EPSILON);
let mut v3 = v1;
v3 += v2;
assert!((v3.x - 5.0).abs() < EPSILON);
assert!((v3.y - 7.0).abs() < EPSILON);
assert!((v3.z - 9.0).abs() < EPSILON);
}
#[test]
fn test_vec3_sub() {
let v1: Vec3f32 = Vec3::new(4.0, 5.0, 6.0);
let v2: Vec3f32 = Vec3::new(1.0, 2.0, 3.0);
let result = v1 - v2;
assert!((result.x - 3.0).abs() < EPSILON);
assert!((result.y - 3.0).abs() < EPSILON);
assert!((result.z - 3.0).abs() < EPSILON);
let mut v3 = v1;
v3 -= v2;
assert!((v3.x - 3.0).abs() < EPSILON);
assert!((v3.y - 3.0).abs() < EPSILON);
assert!((v3.z - 3.0).abs() < EPSILON);
}
#[test]
fn test_vec3_mul_scalar() {
let v1: Vec3f32 = Vec3::new(1.0, 2.0, 3.0);
let scalar = 3.0;
let result1 = v1 * scalar;
assert!((result1.x - 3.0).abs() < EPSILON);
assert!((result1.y - 6.0).abs() < EPSILON);
assert!((result1.z - 9.0).abs() < EPSILON);
let result2 = scalar * v1;
assert!((result2.x - 3.0).abs() < EPSILON);
assert!((result2.y - 6.0).abs() < EPSILON);
assert!((result2.z - 9.0).abs() < EPSILON);
let mut v2 = v1;
v2 *= scalar;
assert!((v2.x - 3.0).abs() < EPSILON);
assert!((v2.y - 6.0).abs() < EPSILON);
assert!((v2.z - 9.0).abs() < EPSILON);
}
#[test]
fn test_vec3_div_scalar() {
let v1: Vec3f32 = Vec3::new(3.0, 6.0, 9.0);
let scalar = 3.0;
let result = v1 / scalar;
assert!((result.x - 1.0).abs() < EPSILON);
assert!((result.y - 2.0).abs() < EPSILON);
assert!((result.z - 3.0).abs() < EPSILON);
let mut v2 = v1;
v2 /= scalar;
assert!((v2.x - 1.0).abs() < EPSILON);
assert!((v2.y - 2.0).abs() < EPSILON);
assert!((v2.z - 3.0).abs() < EPSILON);
}
#[test]
fn test_vec3_mul_hadamard() {
let v1: Vec3f32 = Vec3::new(1.0, 2.0, 3.0);
let v2: Vec3f32 = Vec3::new(4.0, 5.0, 6.0);
let result = v1 * v2;
assert!((result.x - 4.0).abs() < EPSILON);
assert!((result.y - 10.0).abs() < EPSILON);
assert!((result.z - 18.0).abs() < EPSILON);
let mut v3 = v1;
v3 *= v2;
assert!((v3.x - 4.0).abs() < EPSILON);
assert!((v3.y - 10.0).abs() < EPSILON);
assert!((v3.z - 18.0).abs() < EPSILON);
}
#[test]
fn test_vec3_div_hadamard() {
let v1: Vec3f32 = Vec3::new(4.0, 10.0, 18.0);
let v2: Vec3f32 = Vec3::new(4.0, 5.0, 6.0);
let result = v1 / v2;
assert!((result.x - 1.0).abs() < EPSILON);
assert!((result.y - 2.0).abs() < EPSILON);
assert!((result.z - 3.0).abs() < EPSILON);
let mut v3 = v1;
v3 /= v2;
assert!((v3.x - 1.0).abs() < EPSILON);
assert!((v3.y - 2.0).abs() < EPSILON);
assert!((v3.z - 3.0).abs() < EPSILON);
}
#[test]
fn test_vec3_neg() {
let v1: Vec3f32 = Vec3::new(1.0, -2.0, 3.0);
let result = -v1;
assert_eq!(result, Vec3::new(-1.0, 2.0, -3.0));
}
#[test]
fn test_vec3_dot() {
let v1: Vec3f32 = Vec3::new(1.0, 2.0, 3.0);
let v2: Vec3f32 = Vec3::new(4.0, 5.0, 6.0);
let result = v1.dot(v2);
assert!((result - 32.0).abs() < EPSILON);
let v3: Vec3f32 = Vec3::new(-1.0, 0.5, -2.0);
let v4: Vec3f32 = Vec3::new(2.0, -4.0, 0.1);
let result2 = v3.dot(v4);
assert!((result2 - (-4.2)).abs() < EPSILON);
assert!((Vec3::ZERO.dot(v1) - 0.0).abs() < EPSILON);
assert!((v1.dot(Vec3::ZERO) - 0.0).abs() < EPSILON);
}
#[test]
fn test_vec3_div_assign_f32() {
let mut v: Vec3f32 = Vec3::new(2.0, 4.0, 6.0);
v /= 2.0;
assert_eq!(v, Vec3::new(1.0, 2.0, 3.0));
}
#[test]
fn test_vec3_cross() {
let v1: Vec3f32 = Vec3::new(1.0, 0.0, 0.0); let v2: Vec3f32 = Vec3::new(0.0, 1.0, 0.0); let expected_z = Vec3::new(0.0, 0.0, 1.0); assert_eq!(v1.cross(v2), expected_z);
let v3: Vec3f32 = Vec3::new(1.0, 2.0, 3.0);
let v4: Vec3f32 = Vec3::new(4.0, 5.0, 6.0);
let expected_cross = Vec3::new(-3.0, 6.0, -3.0);
assert_eq!(v3.cross(v4), expected_cross);
assert_eq!(v1.cross(v1), Vec3::ZERO);
assert_eq!(v3.cross(v3), Vec3::ZERO);
}
#[test]
fn test_vec3_length_squared() {
let v1: Vec3f32 = Vec3::new(1.0, 2.0, 2.0);
assert!((v1.length_squared() - 9.0).abs() < EPSILON);
assert!((Vec3f32::ZERO.length_squared() - 0.0).abs() < EPSILON);
}
#[test]
fn test_vec3_length() {
let v1: Vec3f32 = Vec3::new(1.0, 2.0, 2.0);
assert!((v1.length() - 3.0).abs() < EPSILON);
assert!((Vec3f32::ZERO.length() - 0.0).abs() < EPSILON);
let v2: Vec3f32 = Vec3::new(0.0, 0.0, 1.0);
assert!((v2.length() - 1.0).abs() < EPSILON);
}
#[test]
fn test_vec3_normalize() {
let v1: Vec3f32 = Vec3::new(1.0, 2.0, 2.0); let norm_v1 = v1.normalize();
assert!((norm_v1.length() - 1.0).abs() < EPSILON);
assert!((norm_v1.x - 1.0 / 3.0).abs() < EPSILON);
assert!((norm_v1.y - 2.0 / 3.0).abs() < EPSILON);
assert!((norm_v1.z - 2.0 / 3.0).abs() < EPSILON);
let v_zero: Vec3f32 = Vec3::ZERO;
assert_eq!(v_zero.normalize(), Vec3::ZERO);
}
#[test]
fn test_vec3_try_normalize() {
let v1: Vec3f32 = Vec3::new(1.0, 2.0, 2.0);
let norm_v1_opt = v1.try_normalize();
assert!(norm_v1_opt.is_some());
let norm_v1 = norm_v1_opt.unwrap();
assert!((norm_v1.length() - 1.0).abs() < EPSILON);
assert!((norm_v1.x - 1.0 / 3.0).abs() < EPSILON);
assert!((norm_v1.y - 2.0 / 3.0).abs() < EPSILON);
assert!((norm_v1.z - 2.0 / 3.0).abs() < EPSILON);
let v_zero: Vec3f32 = Vec3::ZERO;
assert!(v_zero.try_normalize().is_none());
}
#[test]
fn test_vec3_reflect() {
let v1: Vec3f32 = Vec3::new(1.0, 1.0, 1.0);
let n1: Vec3f32 = Vec3::new(0.0, 0.0, -1.0);
let r1 = v1.reflect(n1);
assert_eq!(r1, Vec3::new(1.0, 1.0, -1.0));
let v2: Vec3f32 = Vec3::new(1.0, 1.0, 1.0);
let n2: Vec3f32 = Vec3::new(0.0, -1.0, 0.0);
let r2 = v2.reflect(n2);
assert_eq!(r2, Vec3::new(1.0, -1.0, 1.0));
let v3: Vec3f32 = Vec3::new(1.0, 1.0, 1.0);
let n3: Vec3f32 = Vec3::new(0.0, 0.0, -1.0);
let r3 = v3.reflect(n3);
assert!((r3.x - 1.0).abs() < EPSILON);
assert!((r3.y - 1.0).abs() < EPSILON);
assert!((r3.z - (-1.0)).abs() < EPSILON);
let v4: Vec3f32 = Vec3::new(0.0, 1.0, 0.0);
let n4: Vec3f32 = Vec3::new(0.0, 1.0, 0.0);
let r4 = v4.reflect(n4);
let expected_r4: Vec3f32 = Vec3::new(0.0, -1.0, 0.0);
assert!((r4.x - expected_r4.x).abs() < EPSILON, "r4.x mismatch");
assert!((r4.y - expected_r4.y).abs() < EPSILON, "r4.y mismatch");
assert!((r4.z - expected_r4.z).abs() < EPSILON, "r4.z mismatch");
let v5: Vec3f32 = Vec3::new(0.0, -1.0, 0.0);
let n5: Vec3f32 = Vec3::new(0.0, 1.0, 0.0);
let r5 = v5.reflect(n5);
let expected_r5: Vec3f32 = Vec3::new(0.0, 1.0, 0.0);
assert!((r5.x - expected_r5.x).abs() < EPSILON, "r5.x mismatch");
assert!((r5.y - expected_r5.y).abs() < EPSILON, "r5.y mismatch");
assert!((r5.z - expected_r5.z).abs() < EPSILON, "r5.z mismatch");
}
#[test]
fn test_vec3_refract() {
let v1: Vec3f32 = Vec3::new(1.0, 0.0, 0.0);
let n1: Vec3f32 = Vec3::new(0.0, 1.0, 0.0);
let eta = 1.5;
let r1 = v1.refract(n1, eta);
assert_eq!(r1, Vec3::new(0.0, 0.0, 0.0));
let v2: Vec3f32 = Vec3::new(1.0, 0.0, 0.0);
let n2: Vec3f32 = Vec3::new(0.0, 1.0, 0.0);
let eta = 0.5;
let r2 = v2.refract(n2, eta);
assert_eq!(r2, Vec3::new(0.5, 0.0, 0.0));
let v3: Vec3f32 = Vec3::new(1.0, 0.0, 0.0);
let n3: Vec3f32 = Vec3::new(0.0, 1.0, 0.0);
let eta = 1.0;
let r3 = v3.refract(n3, eta);
assert_eq!(r3, Vec3::new(1.0, 0.0, 0.0));
}
#[test]
fn test_vec3_try_refract() {
let v1: Vec3f32 = Vec3::new(1.0, 0.0, 0.0);
let n1: Vec3f32 = Vec3::new(0.0, 1.0, 0.0);
let eta = 1.5;
let r1_opt = v1.try_refract(n1, eta);
assert!(r1_opt.is_none());
let v2: Vec3f32 = Vec3::new(1.0, 0.0, 0.0);
let n2: Vec3f32 = Vec3::new(0.0, 1.0, 0.0);
let eta = 0.5;
let r2_opt = v2.try_refract(n2, eta);
assert!(r2_opt.is_some());
if let Some(r2) = r2_opt {
assert_eq!(r2, Vec3::new(0.5, 0.0, 0.0));
}
let v3: Vec3f32 = Vec3::new(1.0, 0.0, 0.0);
let n3: Vec3f32 = Vec3::new(0.0, 1.0, 0.0);
let eta = 1.0;
let r3_opt = v3.try_refract(n3, eta);
assert!(r3_opt.is_some());
let r3 = r3_opt.unwrap();
assert_eq!(r3, Vec3::new(1.0, 0.0, 0.0));
}
#[test]
fn test_vec3_lerp() {
let a: Vec3f32 = Vec3::new(1.0, 2.0, 3.0);
let b: Vec3f32 = Vec3::new(5.0, 6.0, 7.0);
let r1 = a.lerp(b, 0.0); assert_eq!(r1, a);
let r2 = a.lerp(b, 1.0); assert_eq!(r2, b);
let r3 = a.lerp(b, 0.5); assert_eq!(r3, Vec3::new(3.0, 4.0, 5.0));
let r4 = a.lerp(b, 0.25);
assert_eq!(r4, Vec3::new(2.0, 3.0, 4.0));
}
#[test]
fn test_vec3_angle_between() {
let v1: Vec3f32 = Vec3::new(1.0, 0.0, 0.0);
let v2: Vec3f32 = Vec3::new(0.0, 1.0, 0.0);
assert!((v1.angle_between(v2) - std::f32::consts::FRAC_PI_2).abs() < EPSILON);
let v3: Vec3f32 = Vec3::new(1.0, 0.0, 0.0);
let v4 = Vec3::new(1.0, 0.0, 0.0);
assert!((v3.angle_between(v4)).abs() < EPSILON);
}
#[test]
fn test_vec3_project_onto() {
let v: Vec3f32 = Vec3::new(2.0, 2.0, 0.0);
let onto: Vec3f32 = Vec3::new(1.0, 0.0, 0.0);
let proj = v.project_onto(onto);
assert!((proj.x - 2.0).abs() < EPSILON);
assert!((proj.y - 0.0).abs() < EPSILON);
assert!((proj.z - 0.0).abs() < EPSILON);
}
#[test]
fn test_vec3_normalize_or_zero() {
let v: Vec3f32 = Vec3::new(1.0, 2.0, 2.0);
let n = v.normalize_or_zero();
assert!((n.length() - 1.0).abs() < EPSILON);
let zero: Vec3f32 = Vec3::ZERO;
assert_eq!(zero.normalize_or_zero(), Vec3::ZERO);
}
#[test]
fn test_vec3_distance() {
let v1: Vec3f32 = Vec3::new(0.0, 0.0, 0.0);
let v2: Vec3f32 = Vec3::new(1.0, 2.0, 2.0);
assert!((v1.distance(v2) - 3.0).abs() < EPSILON);
}
#[test]
fn test_vec3_clamp() {
let v: Vec3f32 = Vec3::new(5.0, -2.0, 10.0);
let min: Vec3f32 = Vec3::new(0.0, 0.0, 0.0);
let max: Vec3f32 = Vec3::new(4.0, 4.0, 4.0);
let clamped = v.clamp(min, max);
assert_eq!(clamped, Vec3::new(4.0, 0.0, 4.0));
}
#[test]
fn test_vec3_min_max() {
let v1: Vec3f32 = Vec3::new(1.0, 5.0, 3.0);
let v2: Vec3f32 = Vec3::new(3.0, 2.0, 4.0);
assert_eq!(v1.min(v2), Vec3::new(1.0, 2.0, 3.0));
assert_eq!(v1.max(v2), Vec3::new(3.0, 5.0, 4.0));
}
#[test]
fn test_vec3_is_nan_is_finite() {
let v: Vec3f32 = Vec3::new(f32::NAN, 1.0, 2.0);
assert!(v.is_nan());
let v2: Vec3f32 = Vec3::new(1.0, 2.0, 3.0);
assert!(v2.is_finite());
let v3: Vec3f32 = Vec3::new(f32::INFINITY, 1.0, 2.0);
assert!(!v3.is_finite());
}
#[test]
fn test_angle_types_conversion() {
let deg = Degrees(180.0);
let rad = deg.to_radians();
assert!((rad.0 - std::f32::consts::PI).abs() < EPSILON);
let deg2 = rad.to_degrees();
assert!((deg2.0 - 180.0).abs() < EPSILON);
let rad2: Radians = Degrees(90.0).into();
assert!((rad2.0 - std::f32::consts::FRAC_PI_2).abs() < EPSILON);
let deg3: Degrees = Radians(std::f32::consts::PI).into();
assert!((deg3.0 - 180.0).abs() < EPSILON);
}
#[test]
fn test_vec3_rotate() {
let v = Vec3f32::new(1.0, 0.0, 0.0);
let rotated_z = v.rotate_axis(Vec3f32::new(0.0, 0.0, 1.0), Radians(std::f32::consts::FRAC_PI_2));
assert!((rotated_z.x).abs() < EPSILON);
assert!((rotated_z.y - 1.0).abs() < EPSILON);
assert!((rotated_z.z).abs() < EPSILON);
let rotated_y = v.rotate_axis(Vec3f32::new(0.0, 1.0, 0.0), Radians(std::f32::consts::FRAC_PI_2));
assert!((rotated_y.x).abs() < EPSILON);
assert!((rotated_y.y).abs() < EPSILON);
assert!((rotated_y.z + 1.0).abs() < EPSILON);
let rotated_x = v.rotate_axis(Vec3f32::new(1.0, 0.0, 0.0), Radians(std::f32::consts::FRAC_PI_2));
assert!((rotated_x.x - 1.0).abs() < EPSILON);
assert!((rotated_x.y).abs() < EPSILON);
assert!((rotated_x.z).abs() < EPSILON);
let rotated2 = v.rotate_axis(Vec3f32::new(0.0, 0.0, 1.0), Degrees(180.0).to_radians());
assert!((rotated2.x + 1.0).abs() < EPSILON);
assert!(rotated2.y.abs() < EPSILON);
assert!(rotated2.z.abs() < EPSILON);
let rotated3 = v.rotate_deg(Degrees(90.0));
assert!((rotated3.x).abs() < EPSILON);
assert!((rotated3.y - 1.0).abs() < EPSILON);
assert!((rotated3.z).abs() < EPSILON);
let rotated4 = v.rotate(Radians(std::f32::consts::FRAC_PI_2));
assert!((rotated4.x).abs() < EPSILON);
assert!((rotated4.y - 1.0).abs() < EPSILON);
assert!((rotated4.z).abs() < EPSILON);
let axis = Vec3f32::new(1.0, 1.0, 0.0).normalize();
let v2 = Vec3f32::new(1.0, 0.0, 0.0);
let rotated_arbitrary = v2.rotate_axis(axis, Degrees(90.0).to_radians());
assert!((rotated_arbitrary.length() - 1.0).abs() < EPSILON);
assert!((rotated_arbitrary.x - v2.x).abs() > EPSILON || (rotated_arbitrary.y - v2.y).abs() > EPSILON);
}
}
const _CONST_V0: Vec3 = Vec3::new(1.0, 2.0, 3.0);
const _CONST_V1: Vec3 = Vec3::new(4.0, 5.0, 6.0);
const _CONST_DOT: f32 = Vec3f32::new(1.0, 2.0, 3.0).dot(Vec3::new(4.0, 5.0, 6.0));
const _CONST_CROSS: Vec3 = Vec3::new(1.0, 2.0, 3.0).cross(Vec3::new(4.0, 5.0, 6.0));
const _CONST_YXZ: Vec3 = Vec3::new(1.0, 2.0, 3.0).yxz();
const _CONST_LEN_SQ: f32 = Vec3f32::new(1.0, 2.0, 2.0).length_squared();
const _CONST_MIN: Vec3 = Vec3::new(1.0, 5.0, 3.0).min(Vec3::new(3.0, 2.0, 4.0));
const _CONST_MAX: Vec3 = Vec3::new(1.0, 5.0, 3.0).max(Vec3::new(3.0, 2.0, 4.0));
const _: () = {
assert!(_CONST_V0.x == 1.0 && _CONST_V0.y == 2.0 && _CONST_V0.z == 3.0);
assert!(_CONST_V1.x == 4.0 && _CONST_V1.y == 5.0 && _CONST_V1.z == 6.0);
assert!(_CONST_DOT == 32.0);
assert!(_CONST_CROSS.x == -3.0 && _CONST_CROSS.y == 6.0 && _CONST_CROSS.z == -3.0);
assert!(_CONST_YXZ.x == 2.0 && _CONST_YXZ.y == 1.0 && _CONST_YXZ.z == 3.0);
assert!(_CONST_LEN_SQ == 9.0);
assert!(_CONST_MIN.x == 1.0 && _CONST_MIN.y == 2.0 && _CONST_MIN.z == 3.0);
assert!(_CONST_MAX.x == 3.0 && _CONST_MAX.y == 5.0 && _CONST_MAX.z == 4.0);
};
const _CONST_METERS: Vec3Meters = Vec3Meters::new(1.0, 2.0, 3.0);
const _CONST_PIXELS: Vec3Pixels = Vec3Pixels::new(10.0, 20.0, 30.0);
const fn _make_vec3_meters() -> Vec3Meters {
Vec3Meters::new(3.0, 4.0, 5.0)
}
const fn _make_vec3_pixels() -> Vec3Pixels {
Vec3Pixels::new(30.0, 40.0, 50.0)
}
const _CONST_METERS2: Vec3Meters = _make_vec3_meters();
const _CONST_PIXELS2: Vec3Pixels = _make_vec3_pixels();
#[test]
fn test_vec3_meters_to_pixels() {
let meters: Vec3<Meters, ()> = Vec3::new(2.0, 3.0, 4.0);
let pixels = meters.to_pixels(100.0);
assert_eq!(pixels, Vec3::<Pixels, ()>::new(200.0, 300.0, 400.0));
}
const _CONST_WORLD: Vec3<(), World> = Vec3::new(1.0, 2.0, 3.0);
const _CONST_LOCAL: Vec3<(), Local> = Vec3::new(3.0, 4.0, 5.0);
const _CONST_SCREEN: Vec3<(), Screen> = Vec3::new(5.0, 6.0, 7.0);
#[test]
fn test_vec3_spaces_addition() {
let world = Vec3World::new(1.0, 2.0, 3.0);
let local = Vec3Local::new(3.0, 4.0, 5.0);
let screen = Vec3Screen::new(5.0, 6.0, 7.0);
assert_eq!(world + _CONST_WORLD, Vec3World::new(2.0, 4.0, 6.0));
assert_eq!(local + _CONST_LOCAL, Vec3Local::new(6.0, 8.0, 10.0));
assert_eq!(screen + _CONST_SCREEN, Vec3Screen::new(10.0, 12.0, 14.0));
}