1use crate::geometric::GA3;
12use amari_core::{Bivector, Vector};
13
14#[derive(Clone, Debug)]
23pub struct Rotor {
24 inner: GA3,
26}
27
28impl Rotor {
29 pub fn from_multivector(mv: GA3) -> Self {
31 Self { inner: mv }
32 }
33
34 pub fn identity() -> Self {
36 Self {
37 inner: GA3::scalar(1.0),
38 }
39 }
40
41 pub fn xy(angle: f64) -> Self {
45 Self::from_bivector_angle(angle, 1.0, 0.0, 0.0)
46 }
47
48 pub fn xz(angle: f64) -> Self {
52 Self::from_bivector_angle(angle, 0.0, 1.0, 0.0)
53 }
54
55 pub fn yz(angle: f64) -> Self {
59 Self::from_bivector_angle(angle, 0.0, 0.0, 1.0)
60 }
61
62 pub fn from_bivector_angle(angle: f64, xy: f64, xz: f64, yz: f64) -> Self {
67 let half_angle = angle / 2.0;
68
69 let biv = Bivector::<3, 0, 0>::from_components(-xy, -xz, -yz);
72 let biv_mv = GA3::from_bivector(&biv);
73 let mag = biv_mv.magnitude();
74
75 if mag < 1e-10 {
76 return Self::identity();
78 }
79
80 let biv_unit = &biv_mv * (1.0 / mag);
81
82 let cos_part = GA3::scalar(half_angle.cos());
84 let sin_part = &biv_unit * half_angle.sin();
85
86 Self {
87 inner: &cos_part + &sin_part,
88 }
89 }
90
91 pub fn from_axis_angle(axis_x: f64, axis_y: f64, axis_z: f64, angle: f64) -> Self {
95 Self::from_bivector_angle(angle, axis_z, -axis_y, axis_x)
100 }
101
102 pub fn as_multivector(&self) -> &GA3 {
104 &self.inner
105 }
106
107 pub fn transform(&self, v: &GA3) -> GA3 {
111 let rev = self.inner.reverse();
112 self.inner.geometric_product(v).geometric_product(&rev)
113 }
114
115 pub fn then(&self, other: &Rotor) -> Rotor {
119 Rotor {
120 inner: other.inner.geometric_product(&self.inner),
121 }
122 }
123
124 pub fn inverse(&self) -> Rotor {
126 Rotor {
128 inner: self.inner.reverse(),
129 }
130 }
131
132 pub fn normalize(&self) -> Rotor {
134 match self.inner.normalize() {
135 Some(normalized) => Rotor { inner: normalized },
136 None => Self::identity(),
137 }
138 }
139
140 pub fn angle(&self) -> f64 {
142 let scalar = self.inner.get(0);
145 2.0 * scalar.clamp(-1.0, 1.0).acos()
146 }
147
148 pub fn slerp(&self, t: f64) -> Rotor {
152 let angle = self.angle();
153 let new_angle = angle * t;
154
155 let biv_xy = -self.inner.get(3); let biv_xz = -self.inner.get(5); let biv_yz = -self.inner.get(6); let biv_mag = (biv_xy * biv_xy + biv_xz * biv_xz + biv_yz * biv_yz).sqrt();
161
162 if biv_mag < 1e-10 {
163 Self::identity()
165 } else {
166 Self::from_bivector_angle(
167 new_angle,
168 biv_xy / biv_mag,
169 biv_xz / biv_mag,
170 biv_yz / biv_mag,
171 )
172 }
173 }
174
175 pub fn slerp_to(&self, other: &Rotor, t: f64) -> Rotor {
177 let relative = other.then(&self.inverse());
180 let interpolated = relative.slerp(t);
181 interpolated.then(self)
182 }
183}
184
185#[derive(Clone, Debug)]
191pub struct Versor {
192 inner: GA3,
194 is_even: bool,
196}
197
198impl Versor {
199 pub fn from_multivector(mv: GA3, is_even: bool) -> Self {
201 Self { inner: mv, is_even }
202 }
203
204 pub fn identity() -> Self {
206 Self {
207 inner: GA3::scalar(1.0),
208 is_even: true,
209 }
210 }
211
212 pub fn reflection(normal_x: f64, normal_y: f64, normal_z: f64) -> Self {
216 let vec = Vector::<3, 0, 0>::from_components(normal_x, normal_y, normal_z);
218 let mv = GA3::from_vector(&vec);
219 let normalized = mv
220 .normalize()
221 .unwrap_or_else(|| GA3::from_vector(&Vector::from_components(1.0, 0.0, 0.0)));
222
223 Self {
224 inner: normalized,
225 is_even: false,
226 }
227 }
228
229 pub fn from_rotor(rotor: Rotor) -> Self {
231 Self {
232 inner: rotor.inner,
233 is_even: true,
234 }
235 }
236
237 pub fn as_multivector(&self) -> &GA3 {
239 &self.inner
240 }
241
242 pub fn transform(&self, v: &GA3) -> GA3 {
247 let rev = self.inner.reverse();
248 if self.is_even {
249 self.inner.geometric_product(v).geometric_product(&rev)
250 } else {
251 let result = self.inner.geometric_product(v).geometric_product(&rev);
254 &result * -1.0
255 }
256 }
257
258 pub fn then(&self, other: &Versor) -> Versor {
260 Versor {
261 inner: other.inner.geometric_product(&self.inner),
262 is_even: self.is_even == other.is_even, }
264 }
265
266 pub fn is_rotor(&self) -> bool {
268 self.is_even
269 }
270
271 pub fn to_rotor(&self) -> Option<Rotor> {
273 if self.is_even {
274 Some(Rotor {
275 inner: self.inner.clone(),
276 })
277 } else {
278 None
279 }
280 }
281}
282
283#[derive(Clone, Debug)]
289pub struct Translation {
290 x: f64,
292 y: f64,
293 z: f64,
294}
295
296impl Translation {
297 pub fn new(x: f64, y: f64, z: f64) -> Self {
299 Self { x, y, z }
300 }
301
302 pub fn x(amount: f64) -> Self {
304 Self::new(amount, 0.0, 0.0)
305 }
306
307 pub fn y(amount: f64) -> Self {
309 Self::new(0.0, amount, 0.0)
310 }
311
312 pub fn z(amount: f64) -> Self {
314 Self::new(0.0, 0.0, amount)
315 }
316
317 pub fn transform(&self, v: &GA3) -> GA3 {
322 let trans_vec = Vector::<3, 0, 0>::from_components(self.x, self.y, self.z);
323 let trans_mv = GA3::from_vector(&trans_vec);
324 v + &trans_mv
325 }
326
327 pub fn then(&self, other: &Translation) -> Translation {
329 Translation {
330 x: self.x + other.x,
331 y: self.y + other.y,
332 z: self.z + other.z,
333 }
334 }
335
336 pub fn inverse(&self) -> Translation {
338 Translation {
339 x: -self.x,
340 y: -self.y,
341 z: -self.z,
342 }
343 }
344
345 pub fn lerp(&self, t: f64) -> Translation {
347 Translation {
348 x: self.x * t,
349 y: self.y * t,
350 z: self.z * t,
351 }
352 }
353
354 pub fn lerp_to(&self, other: &Translation, t: f64) -> Translation {
356 Translation {
357 x: self.x + (other.x - self.x) * t,
358 y: self.y + (other.y - self.y) * t,
359 z: self.z + (other.z - self.z) * t,
360 }
361 }
362}
363
364#[derive(Clone, Debug)]
366pub struct Transform {
367 rotor: Rotor,
369 translation: Translation,
371}
372
373impl Transform {
374 pub fn new(rotor: Rotor, translation: Translation) -> Self {
376 Self { rotor, translation }
377 }
378
379 pub fn identity() -> Self {
381 Self {
382 rotor: Rotor::identity(),
383 translation: Translation::new(0.0, 0.0, 0.0),
384 }
385 }
386
387 pub fn rotation(rotor: Rotor) -> Self {
389 Self {
390 rotor,
391 translation: Translation::new(0.0, 0.0, 0.0),
392 }
393 }
394
395 pub fn translation(translation: Translation) -> Self {
397 Self {
398 rotor: Rotor::identity(),
399 translation,
400 }
401 }
402
403 pub fn transform(&self, v: &GA3) -> GA3 {
405 let rotated = self.rotor.transform(v);
406 self.translation.transform(&rotated)
407 }
408
409 pub fn then(&self, other: &Transform) -> Transform {
411 let combined_rotor = self.rotor.then(&other.rotor);
417
418 let self_trans_vec = Vector::<3, 0, 0>::from_components(
420 self.translation.x,
421 self.translation.y,
422 self.translation.z,
423 );
424 let self_trans_mv = GA3::from_vector(&self_trans_vec);
425 let rotated_trans = other.rotor.transform(&self_trans_mv);
426
427 let combined_translation = Translation::new(
428 rotated_trans.get(1) + other.translation.x,
429 rotated_trans.get(2) + other.translation.y,
430 rotated_trans.get(4) + other.translation.z,
431 );
432
433 Transform {
434 rotor: combined_rotor,
435 translation: combined_translation,
436 }
437 }
438
439 pub fn inverse(&self) -> Transform {
441 let inv_rotor = self.rotor.inverse();
442 let inv_trans_base = self.translation.inverse();
443
444 let trans_vec = Vector::<3, 0, 0>::from_components(
446 inv_trans_base.x,
447 inv_trans_base.y,
448 inv_trans_base.z,
449 );
450 let trans_mv = GA3::from_vector(&trans_vec);
451 let rotated = inv_rotor.transform(&trans_mv);
452
453 Transform {
454 rotor: inv_rotor,
455 translation: Translation::new(rotated.get(1), rotated.get(2), rotated.get(4)),
456 }
457 }
458
459 pub fn interpolate(&self, t: f64) -> Transform {
461 Transform {
462 rotor: self.rotor.slerp(t),
463 translation: self.translation.lerp(t),
464 }
465 }
466
467 pub fn interpolate_to(&self, other: &Transform, t: f64) -> Transform {
469 Transform {
470 rotor: self.rotor.slerp_to(&other.rotor, t),
471 translation: self.translation.lerp_to(&other.translation, t),
472 }
473 }
474}
475
476#[cfg(test)]
477mod tests {
478 use super::*;
479 use std::f64::consts::PI;
480
481 #[test]
482 fn test_rotor_identity() {
483 let r = Rotor::identity();
484 let v = Vector::<3, 0, 0>::from_components(1.0, 2.0, 3.0);
485 let mv = GA3::from_vector(&v);
486
487 let rotated = r.transform(&mv);
488
489 assert!((rotated.get(1) - 1.0).abs() < 1e-10);
491 assert!((rotated.get(2) - 2.0).abs() < 1e-10);
492 assert!((rotated.get(4) - 3.0).abs() < 1e-10);
493 }
494
495 #[test]
496 fn test_rotor_xy_90() {
497 let r = Rotor::xy(PI / 2.0);
499
500 let v = GA3::from_vector(&Vector::from_components(1.0, 0.0, 0.0));
502 let rotated = r.transform(&v);
503
504 assert!((rotated.get(1) - 0.0).abs() < 1e-10); assert!((rotated.get(2) - 1.0).abs() < 1e-10); assert!((rotated.get(4) - 0.0).abs() < 1e-10); }
508
509 #[test]
510 fn test_rotor_preserves_magnitude() {
511 let r = Rotor::from_bivector_angle(1.23, 1.0, 2.0, 3.0);
512 let v = GA3::from_vector(&Vector::from_components(3.0, 4.0, 5.0));
513
514 let original_mag = v.magnitude();
515 let rotated = r.transform(&v);
516 let rotated_mag = rotated.magnitude();
517
518 assert!(
519 (original_mag - rotated_mag).abs() < 1e-10,
520 "Magnitude changed: {} -> {}",
521 original_mag,
522 rotated_mag
523 );
524 }
525
526 #[test]
527 fn test_rotor_composition() {
528 let r1 = Rotor::xy(PI / 2.0);
530 let r2 = Rotor::xy(PI / 2.0);
531 let r_combined = r1.then(&r2);
532
533 let v = GA3::from_vector(&Vector::from_components(1.0, 0.0, 0.0));
534 let rotated = r_combined.transform(&v);
535
536 assert!((rotated.get(1) + 1.0).abs() < 1e-10);
538 assert!((rotated.get(2) - 0.0).abs() < 1e-10);
539 }
540
541 #[test]
542 fn test_rotor_inverse() {
543 let r = Rotor::from_bivector_angle(0.7, 1.0, 1.0, 1.0);
544 let v = GA3::from_vector(&Vector::from_components(1.0, 2.0, 3.0));
545
546 let rotated = r.transform(&v);
547 let back = r.inverse().transform(&rotated);
548
549 assert!((back.get(1) - 1.0).abs() < 1e-10);
550 assert!((back.get(2) - 2.0).abs() < 1e-10);
551 assert!((back.get(4) - 3.0).abs() < 1e-10);
552 }
553
554 #[test]
555 fn test_rotor_slerp() {
556 let r = Rotor::xy(PI);
557
558 let half = r.slerp(0.5);
560
561 let v = GA3::from_vector(&Vector::from_components(1.0, 0.0, 0.0));
562 let rotated = half.transform(&v);
563
564 assert!((rotated.get(1) - 0.0).abs() < 1e-10);
566 assert!((rotated.get(2) - 1.0).abs() < 1e-10);
567 }
568
569 #[test]
570 fn test_translation() {
571 let t = Translation::new(1.0, 2.0, 3.0);
572 let v = GA3::from_vector(&Vector::from_components(0.0, 0.0, 0.0));
573
574 let translated = t.transform(&v);
575
576 assert!((translated.get(1) - 1.0).abs() < 1e-10);
577 assert!((translated.get(2) - 2.0).abs() < 1e-10);
578 assert!((translated.get(4) - 3.0).abs() < 1e-10);
579 }
580
581 #[test]
582 fn test_transform_composition() {
583 let rot = Rotor::xy(PI / 2.0);
584 let trans = Translation::new(1.0, 0.0, 0.0);
585 let transform = Transform::new(rot, trans);
586
587 let v = GA3::from_vector(&Vector::from_components(1.0, 0.0, 0.0));
588 let result = transform.transform(&v);
589
590 assert!((result.get(1) - 1.0).abs() < 1e-10);
593 assert!((result.get(2) - 1.0).abs() < 1e-10);
594 }
595}