1#![warn(missing_docs)]
7
8pub mod solvers;
9
10pub use solvers::{least_squares_solve, sanitize_float, svd_3x3, SvdResult3x3};
11
12pub const EPSILON: f64 = 1e-9;
14
15#[derive(Debug, Clone, Copy, PartialEq)]
17pub struct Vector3 {
18 pub x: f64,
20 pub y: f64,
22 pub z: f64,
24}
25
26impl Vector3 {
27 pub const ZERO: Self = Self { x: 0.0, y: 0.0, z: 0.0 };
29
30 pub fn new(x: f64, y: f64, z: f64) -> Self {
32 Self { x, y, z }
33 }
34
35 pub fn dot(&self, other: &Self) -> f64 {
37 self.x * other.x + self.y * other.y + self.z * other.z
38 }
39
40 pub fn cross(&self, other: &Self) -> Self {
42 Self {
43 x: self.y * other.z - self.z * other.y,
44 y: self.z * other.x - self.x * other.z,
45 z: self.x * other.y - self.y * other.x,
46 }
47 }
48
49 pub fn norm(&self) -> f64 {
51 self.dot(self).sqrt()
52 }
53
54 pub fn normalize(&self) -> Option<Self> {
56 let mag = self.norm();
57 if mag < EPSILON {
58 None
59 } else {
60 Some(Self { x: self.x / mag, y: self.y / mag, z: self.z / mag })
61 }
62 }
63}
64
65#[derive(Debug, Clone, Copy, PartialEq)]
67pub struct Matrix3x3 {
68 pub data: [f64; 9],
70}
71
72impl Matrix3x3 {
73 pub const IDENTITY: Self = Self { data: [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0] };
75
76 pub fn identity() -> Self {
78 Self::IDENTITY
79 }
80
81 pub fn from_row_major(data: [f64; 9]) -> Self {
83 Self { data }
84 }
85
86 pub fn get(&self, row: usize, col: usize) -> f64 {
88 self.data[row * 3 + col]
89 }
90
91 pub fn set(&mut self, row: usize, col: usize, val: f64) {
93 self.data[row * 3 + col] = val;
94 }
95
96 pub fn determinant(&self) -> f64 {
98 let m = &self.data;
99 m[0] * (m[4] * m[8] - m[5] * m[7]) - m[1] * (m[3] * m[8] - m[5] * m[6])
100 + m[2] * (m[3] * m[7] - m[4] * m[6])
101 }
102
103 pub fn mul_vec(&self, v: Vector3) -> Vector3 {
105 let m = &self.data;
106 Vector3 {
107 x: m[0] * v.x + m[1] * v.y + m[2] * v.z,
108 y: m[3] * v.x + m[4] * v.y + m[5] * v.z,
109 z: m[6] * v.x + m[7] * v.y + m[8] * v.z,
110 }
111 }
112
113 pub fn mul_mat(&self, other: &Self) -> Self {
115 let mut out = [0.0; 9];
116 for r in 0..3 {
117 for c in 0..3 {
118 let mut sum = 0.0;
119 for k in 0..3 {
120 sum += self.get(r, k) * other.get(k, c);
121 }
122 out[r * 3 + c] = sum;
123 }
124 }
125 Self::from_row_major(out)
126 }
127
128 pub fn invert(&self) -> Option<Self> {
130 let det = self.determinant();
131 if det.abs() < EPSILON {
132 return None;
133 }
134 let inv_det = 1.0 / det;
135 let m = &self.data;
136
137 let out = [
138 (m[4] * m[8] - m[5] * m[7]) * inv_det,
139 (m[2] * m[7] - m[1] * m[8]) * inv_det,
140 (m[1] * m[5] - m[2] * m[4]) * inv_det,
141 (m[5] * m[6] - m[3] * m[8]) * inv_det,
142 (m[0] * m[8] - m[2] * m[6]) * inv_det,
143 (m[2] * m[3] - m[0] * m[5]) * inv_det,
144 (m[3] * m[7] - m[4] * m[6]) * inv_det,
145 (m[1] * m[6] - m[0] * m[7]) * inv_det,
146 (m[0] * m[4] - m[1] * m[3]) * inv_det,
147 ];
148 Some(Self::from_row_major(out))
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155
156 #[test]
157 fn test_vector_dot_and_cross() {
158 let v1 = Vector3::new(1.0, 0.0, 0.0);
159 let v2 = Vector3::new(0.0, 1.0, 0.0);
160 assert_eq!(v1.dot(&v2), 0.0);
161
162 let v3 = v1.cross(&v2);
163 assert_eq!(v3, Vector3::new(0.0, 0.0, 1.0));
164 }
165
166 #[test]
167 fn test_vector_normalize() {
168 let v = Vector3::new(3.0, 0.0, 0.0);
169 let norm = v.normalize().unwrap();
170 assert!((norm.x - 1.0).abs() < EPSILON);
171 assert_eq!(norm.y, 0.0);
172 assert_eq!(norm.z, 0.0);
173 }
174
175 #[test]
176 fn test_matrix_determinant_identity() {
177 let mat = Matrix3x3::IDENTITY;
178 assert!((mat.determinant() - 1.0).abs() < EPSILON);
179
180 let v = Vector3::new(2.0, 3.0, 4.0);
181 assert_eq!(mat.mul_vec(v), v);
182 }
183}