1use crate::{vector, GA3};
9use serde::{Deserialize, Serialize};
10
11#[derive(Clone, Debug, Serialize, Deserialize)]
18pub struct GeometricError {
19 pub distance: f64,
21
22 pub gradient: [f64; 3],
27
28 pub correction: [f64; 8],
33
34 pub description: String,
36}
37
38impl GeometricError {
39 pub fn new(distance: f64, description: impl Into<String>) -> Self {
41 Self {
42 distance,
43 gradient: [0.0; 3],
44 correction: [0.0; 8],
45 description: description.into(),
46 }
47 }
48
49 pub fn with_gradient(mut self, gradient: [f64; 3]) -> Self {
51 self.gradient = gradient;
52 self
53 }
54
55 pub fn with_correction(mut self, correction: [f64; 8]) -> Self {
57 self.correction = correction;
58 self
59 }
60
61 pub fn from_multivector(error_mv: &GA3, description: impl Into<String>) -> Self {
66 Self {
67 distance: error_mv.magnitude(),
68 gradient: [
69 error_mv.get(1), error_mv.get(2), error_mv.get(4), ],
73 correction: [
74 error_mv.get(0), error_mv.get(1), error_mv.get(2), error_mv.get(4), error_mv.get(3), error_mv.get(5), error_mv.get(6), error_mv.get(7), ],
83 description: description.into(),
84 }
85 }
86
87 pub fn is_within_tolerance(&self, epsilon: f64) -> bool {
89 self.distance < epsilon
90 }
91
92 pub fn gradient_as_ga3(&self) -> GA3 {
94 vector(self.gradient[0], self.gradient[1], self.gradient[2])
95 }
96
97 pub fn correction_as_ga3(&self) -> GA3 {
99 GA3::from_coefficients(self.correction.to_vec())
100 }
101}
102
103impl std::fmt::Display for GeometricError {
104 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
105 write!(
106 f,
107 "GeometricError {{ distance: {:.6}, description: \"{}\" }}",
108 self.distance, self.description
109 )
110 }
111}
112
113impl std::error::Error for GeometricError {}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118
119 #[test]
120 fn test_error_creation() {
121 let error = GeometricError::new(0.5, "Test error");
122 assert_eq!(error.distance, 0.5);
123 assert_eq!(error.description, "Test error");
124 }
125
126 #[test]
127 fn test_error_from_multivector() {
128 let mv = vector(1.0, 2.0, 3.0);
129 let error = GeometricError::from_multivector(&mv, "Vector error");
130
131 assert!((error.distance - mv.magnitude()).abs() < 1e-10);
132 assert_eq!(error.gradient[0], 1.0);
133 assert_eq!(error.gradient[1], 2.0);
134 assert_eq!(error.gradient[2], 3.0);
135 }
136
137 #[test]
138 fn test_within_tolerance() {
139 let error = GeometricError::new(0.001, "Small error");
140 assert!(error.is_within_tolerance(0.01));
141 assert!(!error.is_within_tolerance(0.0001));
142 }
143}