#![warn(missing_docs)]
pub mod solvers;
pub use solvers::{least_squares_solve, sanitize_float, svd_3x3, SvdResult3x3};
pub const EPSILON: f64 = 1e-9;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Vector3 {
pub x: f64,
pub y: f64,
pub z: f64,
}
impl Vector3 {
pub const ZERO: Self = Self { x: 0.0, y: 0.0, z: 0.0 };
pub fn new(x: f64, y: f64, z: f64) -> Self {
Self { x, y, z }
}
pub fn dot(&self, other: &Self) -> f64 {
self.x * other.x + self.y * other.y + self.z * other.z
}
pub fn cross(&self, other: &Self) -> Self {
Self {
x: self.y * other.z - self.z * other.y,
y: self.z * other.x - self.x * other.z,
z: self.x * other.y - self.y * other.x,
}
}
pub fn norm(&self) -> f64 {
self.dot(self).sqrt()
}
pub fn normalize(&self) -> Option<Self> {
let mag = self.norm();
if mag < EPSILON {
None
} else {
Some(Self { x: self.x / mag, y: self.y / mag, z: self.z / mag })
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Matrix3x3 {
pub data: [f64; 9],
}
impl Matrix3x3 {
pub const IDENTITY: Self = Self { data: [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0] };
pub fn identity() -> Self {
Self::IDENTITY
}
pub fn from_row_major(data: [f64; 9]) -> Self {
Self { data }
}
pub fn get(&self, row: usize, col: usize) -> f64 {
self.data[row * 3 + col]
}
pub fn set(&mut self, row: usize, col: usize, val: f64) {
self.data[row * 3 + col] = val;
}
pub fn determinant(&self) -> f64 {
let m = &self.data;
m[0] * (m[4] * m[8] - m[5] * m[7]) - m[1] * (m[3] * m[8] - m[5] * m[6])
+ m[2] * (m[3] * m[7] - m[4] * m[6])
}
pub fn mul_vec(&self, v: Vector3) -> Vector3 {
let m = &self.data;
Vector3 {
x: m[0] * v.x + m[1] * v.y + m[2] * v.z,
y: m[3] * v.x + m[4] * v.y + m[5] * v.z,
z: m[6] * v.x + m[7] * v.y + m[8] * v.z,
}
}
pub fn mul_mat(&self, other: &Self) -> Self {
let mut out = [0.0; 9];
for r in 0..3 {
for c in 0..3 {
let mut sum = 0.0;
for k in 0..3 {
sum += self.get(r, k) * other.get(k, c);
}
out[r * 3 + c] = sum;
}
}
Self::from_row_major(out)
}
pub fn invert(&self) -> Option<Self> {
let det = self.determinant();
if det.abs() < EPSILON {
return None;
}
let inv_det = 1.0 / det;
let m = &self.data;
let out = [
(m[4] * m[8] - m[5] * m[7]) * inv_det,
(m[2] * m[7] - m[1] * m[8]) * inv_det,
(m[1] * m[5] - m[2] * m[4]) * inv_det,
(m[5] * m[6] - m[3] * m[8]) * inv_det,
(m[0] * m[8] - m[2] * m[6]) * inv_det,
(m[2] * m[3] - m[0] * m[5]) * inv_det,
(m[3] * m[7] - m[4] * m[6]) * inv_det,
(m[1] * m[6] - m[0] * m[7]) * inv_det,
(m[0] * m[4] - m[1] * m[3]) * inv_det,
];
Some(Self::from_row_major(out))
}
pub fn scale(&self, s: f64) -> Self {
let mut out = [0.0; 9];
for (i, val) in out.iter_mut().enumerate() {
*val = self.data[i] * s;
}
Self::from_row_major(out)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_vector_dot_and_cross() {
let v1 = Vector3::new(1.0, 0.0, 0.0);
let v2 = Vector3::new(0.0, 1.0, 0.0);
assert_eq!(v1.dot(&v2), 0.0);
let v3 = v1.cross(&v2);
assert_eq!(v3, Vector3::new(0.0, 0.0, 1.0));
}
#[test]
fn test_vector_normalize() {
let v = Vector3::new(3.0, 0.0, 0.0);
let norm = v.normalize().unwrap();
assert!((norm.x - 1.0).abs() < EPSILON);
assert_eq!(norm.y, 0.0);
assert_eq!(norm.z, 0.0);
}
#[test]
fn test_matrix_determinant_identity() {
let mat = Matrix3x3::IDENTITY;
assert!((mat.determinant() - 1.0).abs() < EPSILON);
let v = Vector3::new(2.0, 3.0, 4.0);
assert_eq!(mat.mul_vec(v), v);
}
}