simply_2dpga/extras/
transformations.rs

1use num_traits::Float;
2
3use crate::{defs::{vector::Vector, bivector::{Bivector}, trivector::Trivector, multivector::Multivector}, traits::{GeometricProduct, Dagger}};
4
5use super::{angle::Angle, point2d::Point2d};
6
7// BASIC REFLECTIONS //
8
9impl<N: Float> Multivector<N> {
10    /// Reflect a multivector across a vector (line).   
11    /// Note that the result will NOT be normalized! 
12    pub fn reflect(&self, other: &Vector<N>) -> Multivector<N> {
13        let a = other.geo(self);
14        self.geo(&a)
15    }   
16}
17impl<N: Float> Vector<N> {
18    /// Reflect a vector (line) across another vector (line).   
19    /// Note that the result will NOT be normalized! 
20    pub fn reflect(&self, other: &Vector<N>) -> Vector<N> {
21        other.geo(&self.geo(other))
22            .vector
23    }   
24}
25impl<N: Float> Bivector<N> {
26    /// Reflect a bivector (point) across another vector (line).   
27    /// Note that the result will NOT be normalized! 
28    pub fn reflect(&self, other: &Vector<N>) -> Bivector<N> {
29        other.geo(&self.geo(other))
30            .bivector
31    }   
32}
33
34// TRANSFORMERS //
35
36/// A thing that can apply a sandwich product to do a rigid transformation for you!
37pub trait RigidTransformation<V> {
38    /// Apply a sandwich product. The target will be sandwiched between
39    /// the rigid transform's multivector and its reverse.
40    fn apply(&self, target: &V) -> V;
41}
42
43
44/// A general rigid transformation handler.
45pub struct Transformer<N: Float> {
46    multivector: Multivector<N>
47}
48impl<N: Float> Transformer<N> {
49    pub fn get_multivector(&self) -> &Multivector<N> {
50        &self.multivector
51    }
52}
53impl<N: Float> RigidTransformation<Multivector<N>> for Transformer<N> {
54    fn apply(&self, target: &Multivector<N>) -> Multivector<N> {
55        self.multivector.reverse()
56            .geo(&target.geo(&self.multivector))
57    }
58}
59impl<N: Float> RigidTransformation<Vector<N>> for Transformer<N> {
60    fn apply(&self, target: &Vector<N>) -> Vector<N> {
61        self.multivector.reverse()
62            .geo(&target.geo(&self.multivector))
63            .vector
64    }
65}
66impl<N: Float> RigidTransformation<Bivector<N>> for Transformer<N> {
67    fn apply(&self, target: &Bivector<N>) -> Bivector<N> {
68        self.multivector.reverse()
69            .geo(&target.geo(&self.multivector))
70            .bivector
71    }
72}
73
74
75pub struct Rotor<N: Float> {
76    angle: Angle<N>,
77    transformer: Transformer<N>,
78}
79impl<N: Float> Rotor<N> {
80    /// Create a rotor with an axis (point we want to rotate around) and an angle.
81    pub fn new(axis: Point2d<N>, angle: Angle<N>) -> Rotor<N> {
82        let alpha = angle.get_radians();
83        let half = N::from(0.5).unwrap();
84        let cos = (alpha * half).cos();
85        let sin = (alpha * half).sin();
86        let mv = Multivector {
87            scalar: cos,
88            vector: crate::defs::vector::Vector::zero(),
89            bivector: (axis.to_bivector() * sin),
90            trivector: Trivector::zero(),
91        };
92        Rotor { angle, transformer: Transformer { multivector: mv }}
93    }
94
95    /// Gets this transfermor's angle by value.  Should be immutable.
96    pub fn get_angle(&self) -> Angle<N> {
97        self.angle
98    }
99    /// Get the underlying transformer.
100    pub fn get_transformer(&self) -> &Transformer<N> {
101        &self.transformer
102    }
103}
104impl<N: Float> RigidTransformation<Multivector<N>> for Rotor<N> {
105    fn apply(&self, target: &Multivector<N>) -> Multivector<N> {
106        self.transformer.apply(target)
107    }
108}
109impl<N: Float> RigidTransformation<Vector<N>> for Rotor<N> {
110    fn apply(&self, target: &Vector<N>) -> Vector<N> {
111        self.transformer.apply(target)
112    }
113}
114impl<N: Float> RigidTransformation<Bivector<N>> for Rotor<N> {
115    fn apply(&self, target: &Bivector<N>) -> Bivector<N> {
116        self.transformer.apply(target)
117    }
118}
119
120/// Motors are a translator in PGA.  They can be combined with rotors to represent any rigid transformation.
121pub struct Motor<N: Float> {
122    x: N,
123    y: N,
124    displacement: N,
125    transformer: Transformer<N>,
126}
127/// A motor- which handles translations.
128impl<N: Float> Motor<N> {
129    /// Create a new motor! 'x' and 'y' are a direction (point at infinity), and 'd' is displacement.
130    pub fn new(x: N, y: N, d: N) -> Motor<N> {
131        let direction = Bivector {
132            e20: x,
133            e01: y,
134            e12: N::zero()
135        };
136        let half = N::from(0.5).unwrap();
137
138        let multivector = Multivector {
139                scalar: N::from(1.0).unwrap(),
140                vector: Vector::zero(),
141                bivector: direction * (d * half),
142                trivector: Trivector::zero()
143            };
144
145        Motor {
146            x, y,
147            displacement: d,
148            transformer: Transformer { multivector }
149        }
150    }
151
152    /// The point at infinity this motor translates towards.
153    pub fn get_direction(&self) -> Bivector<N> {
154        Bivector {
155            e20: self.x,
156            e01: self.y,
157            e12: N::zero()
158        }
159    }
160
161    /// The displacement of this translation.
162    pub fn get_displacement(&self) -> N {
163        self.displacement
164    }
165
166    /// Get the underlying transformer.
167    pub fn get_transformer(&self) -> &Transformer<N> {
168        &self.transformer
169    }
170}
171impl<N: Float> RigidTransformation<Multivector<N>> for Motor<N> {
172    fn apply(&self, target: &Multivector<N>) -> Multivector<N> {
173        self.transformer.apply(target)
174    }
175} 
176impl<N: Float> RigidTransformation<Bivector<N>> for Motor<N> {
177    fn apply(&self, target: &Bivector<N>) -> Bivector<N> {
178        self.transformer.apply(target)
179    }
180} 
181impl<N: Float> RigidTransformation<Vector<N>> for Motor<N> {
182    fn apply(&self, target: &Vector<N>) -> Vector<N> {
183        self.transformer.apply(target)
184    }
185} 
186
187
188/// Combines multiple rigid transforms into one transform.
189pub struct MultiTransform<N: Float> {
190    multivector: Multivector<N>
191}
192impl<N: Float> MultiTransform<N> {
193    pub fn new(transformations: Vec<&Transformer<N>>) -> MultiTransform<N> {
194        let mut mv = transformations
195            .first()
196            .unwrap()
197            .multivector
198            .clone();
199
200        for tr in transformations.iter().skip(1) {
201            mv = mv.geo(&tr.multivector);
202        }
203
204        MultiTransform { 
205            multivector: mv
206        }
207    }
208}
209impl<N: Float> RigidTransformation<Multivector<N>> for MultiTransform<N> {
210    fn apply(&self, target: &Multivector<N>) -> Multivector<N> {
211        self.multivector.reverse()
212            .geo(&target.geo(&self.multivector))
213    }
214}
215impl<N: Float> RigidTransformation<Vector<N>> for MultiTransform<N> {
216    fn apply(&self, target: &Vector<N>) -> Vector<N> {
217        self.multivector.reverse()
218            .geo(&target.geo(&self.multivector))
219            .vector
220    }
221}
222impl<N: Float> RigidTransformation<Bivector<N>> for MultiTransform<N> {
223    fn apply(&self, target: &Bivector<N>) -> Bivector<N> {
224        self.multivector.reverse()
225            .geo(&target.geo(&self.multivector))
226            .bivector
227    }
228}