rs_measures/inner/
linear_map_3d.rs

1#[macro_export]
2macro_rules! inner_define_linear_map_3d {
3    {} => {
4        pub struct LinearMap3d<Number: ArithmeticOps> {
5            c: [[Number; 3]; 3],
6        }
7
8        impl<Number: ArithmeticOps> LinearMap3d<Number> {
9            pub const fn new(coefficients: [[Number; 3]; 3]) -> Self {
10                Self { c: coefficients }
11            }
12
13            // No translations
14
15            // Rotations
16
17            // Rotation by an angle measure around a unit vector.
18            // Precondition: unit_vector.squared_norm().value == 1
19            pub fn rotation<AngleUnit: AngleMeasurementUnit<Property = Angle>, AxisUnit: MeasurementUnit>(
20                angle: Measure<AngleUnit, Number>,
21                unit_vector: Measure3d<AxisUnit, Number>,
22            ) -> Self
23            where
24                AxisUnit::Property: VectorProperty,
25            {
26                Self::rotation_by_radians_around_unit_vector(
27                    angle.convert::<Radian>().value,
28                    unit_vector.x,
29                    unit_vector.y,
30                    unit_vector.z,
31                )
32            }
33
34            // Projections
35
36            // Projection onto a line identified by a unit vector.
37            // Precondition: unit_vector.squared_norm().value == 1
38            pub fn projection_onto_line<Unit: MeasurementUnit>(
39                unit_vector: Measure3d<Unit, Number>,
40            ) -> Self {
41                Self {
42                    c: [
43                        [
44                            unit_vector.x * unit_vector.x,
45                            unit_vector.y * unit_vector.x,
46                            unit_vector.z * unit_vector.x,
47                        ],
48                        [
49                            unit_vector.x * unit_vector.y,
50                            unit_vector.y * unit_vector.y,
51                            unit_vector.z * unit_vector.y,
52                        ],
53                        [
54                            unit_vector.x * unit_vector.z,
55                            unit_vector.y * unit_vector.z,
56                            unit_vector.z * unit_vector.z,
57                        ],
58                    ],
59                }
60            }
61
62            // Projection onto a plane whose normal is identified by a unit vector.
63            // Precondition: unit_vector.squared_norm().value == 1
64            pub fn projection_onto_plane<Unit: MeasurementUnit>(
65                unit_vector: Measure3d<Unit, Number>,
66            ) -> Self {
67                Self {
68                    c: [
69                        [
70                            Number::ONE - unit_vector.x * unit_vector.x,
71                            -unit_vector.y * unit_vector.x,
72                            -unit_vector.z * unit_vector.x,
73                        ],
74                        [
75                            -unit_vector.x * unit_vector.y,
76                            Number::ONE - unit_vector.y * unit_vector.y,
77                            -unit_vector.z * unit_vector.y,
78                        ],
79                        [
80                            -unit_vector.x * unit_vector.z,
81                            -unit_vector.y * unit_vector.z,
82                            Number::ONE - unit_vector.z * unit_vector.z,
83                        ],
84                    ],
85                }
86            }
87
88            // Reflections
89
90            // Reflection over a line identified by a unit vector.
91            // Precondition: unit_vector.squared_norm().value == 1
92            pub fn reflection_over_line<Unit: MeasurementUnit>(
93                unit_vector: Measure3d<Unit, Number>,
94            ) -> Self {
95                let two = Number::ONE + Number::ONE;
96                Self {
97                    c: [
98                        [
99                            two * unit_vector.x * unit_vector.x - Number::ONE,
100                            two * unit_vector.y * unit_vector.x,
101                            two * unit_vector.z * unit_vector.x,
102                        ],
103                        [
104                            two * unit_vector.x * unit_vector.y,
105                            two * unit_vector.y * unit_vector.y - Number::ONE,
106                            two * unit_vector.z * unit_vector.y,
107                        ],
108                        [
109                            two * unit_vector.x * unit_vector.z,
110                            two * unit_vector.y * unit_vector.z,
111                            two * unit_vector.z * unit_vector.z - Number::ONE,
112                        ],
113                    ],
114                }
115            }
116
117            // Reflection over a plane whose normal is identified by a unit vector.
118            // Precondition: unit_vector.squared_norm().value == 1
119            pub fn reflection_over_plane<Unit: MeasurementUnit>(
120                unit_vector: Measure3d<Unit, Number>,
121            ) -> Self {
122                let minus_two = -(Number::ONE + Number::ONE);
123                Self {
124                    c: [
125                        [
126                            minus_two * unit_vector.x * unit_vector.x + Number::ONE,
127                            minus_two * unit_vector.y * unit_vector.x,
128                            minus_two * unit_vector.z * unit_vector.x,
129                        ],
130                        [
131                            minus_two * unit_vector.x * unit_vector.y,
132                            minus_two * unit_vector.y * unit_vector.y + Number::ONE,
133                            minus_two * unit_vector.z * unit_vector.y,
134                        ],
135                        [
136                            minus_two * unit_vector.x * unit_vector.z,
137                            minus_two * unit_vector.y * unit_vector.z,
138                            minus_two * unit_vector.z * unit_vector.z + Number::ONE,
139                        ],
140                    ],
141                }
142            }
143
144            // Scaling by three factors.
145
146            pub fn scaling(kx: Number, ky: Number, kz: Number) -> Self {
147                Self {
148                    c: [
149                        [kx, Number::ZERO, Number::ZERO],
150                        [Number::ZERO, ky, Number::ZERO],
151                        [Number::ZERO, Number::ZERO, kz],
152                    ],
153                }
154            }
155
156            // Inversion
157
158            pub fn inverted(&self) -> Self {
159                let inv_determinant = Number::ONE
160                    / (self.c[0][0] * (self.c[1][1] * self.c[2][2] - self.c[1][2] * self.c[2][1])
161                        - self.c[0][1] * (self.c[1][0] * self.c[2][2] - self.c[1][2] * self.c[2][0])
162                        + self.c[0][2] * (self.c[1][0] * self.c[2][1] - self.c[1][1] * self.c[2][0]));
163                Self {
164                    c: [
165                        [
166                            (self.c[1][1] * self.c[2][2] - self.c[1][2] * self.c[2][1]) * inv_determinant,
167                            -(self.c[0][1] * self.c[2][2] - self.c[0][2] * self.c[2][1]) * inv_determinant,
168                            (self.c[0][1] * self.c[1][2] - self.c[0][2] * self.c[1][1]) * inv_determinant,
169                        ],
170                        [
171                            -(self.c[1][0] * self.c[2][2] - self.c[1][2] * self.c[2][0]) * inv_determinant,
172                            (self.c[0][0] * self.c[2][2] - self.c[0][2] * self.c[2][0]) * inv_determinant,
173                            -(self.c[0][0] * self.c[1][2] - self.c[0][2] * self.c[1][0]) * inv_determinant,
174                        ],
175                        [
176                            (self.c[1][0] * self.c[2][1] - self.c[1][1] * self.c[2][0]) * inv_determinant,
177                            -(self.c[0][0] * self.c[2][1] - self.c[0][1] * self.c[2][0]) * inv_determinant,
178                            (self.c[0][0] * self.c[1][1] - self.c[0][1] * self.c[1][0]) * inv_determinant,
179                        ],
180                    ],
181                }
182            }
183
184            // Composition of spacial linear transformations.
185            // Applying the resulting transformation is equivalent to apply first
186            // `other` and then `self`.
187            pub fn combined_with(&self, other: &LinearMap3d<Number>) -> Self {
188                Self {
189                    c: [
190                        [
191                            other.c[0][0] * self.c[0][0]
192                                + other.c[0][1] * self.c[1][0]
193                                + other.c[0][2] * self.c[2][0],
194                            other.c[0][0] * self.c[0][1]
195                                + other.c[0][1] * self.c[1][1]
196                                + other.c[0][2] * self.c[2][1],
197                            other.c[0][0] * self.c[0][2]
198                                + other.c[0][1] * self.c[1][2]
199                                + other.c[0][2] * self.c[2][2],
200                        ],
201                        [
202                            other.c[1][0] * self.c[0][0]
203                                + other.c[1][1] * self.c[1][0]
204                                + other.c[1][2] * self.c[2][0],
205                            other.c[1][0] * self.c[0][1]
206                                + other.c[1][1] * self.c[1][1]
207                                + other.c[1][2] * self.c[2][1],
208                            other.c[1][0] * self.c[0][2]
209                                + other.c[1][1] * self.c[1][2]
210                                + other.c[1][2] * self.c[2][2],
211                        ],
212                        [
213                            other.c[2][0] * self.c[0][0]
214                                + other.c[2][1] * self.c[1][0]
215                                + other.c[2][2] * self.c[2][0],
216                            other.c[2][0] * self.c[0][1]
217                                + other.c[2][1] * self.c[1][1]
218                                + other.c[2][2] * self.c[2][1],
219                            other.c[2][0] * self.c[0][2]
220                                + other.c[2][1] * self.c[1][2]
221                                + other.c[2][2] * self.c[2][2],
222                        ],
223                    ],
224                }
225            }
226
227            pub fn apply_to<Unit: MeasurementUnit>(
228                &self,
229                m: Measure3d<Unit, Number>,
230            ) -> Measure3d<Unit, Number>
231            where
232                Unit::Property: VectorProperty,
233            {
234                Measure3d::<Unit, Number>::new(
235                    self.c[0][0] * m.x + self.c[0][1] * m.y + self.c[0][2] * m.z,
236                    self.c[1][0] * m.x + self.c[1][1] * m.y + self.c[1][2] * m.z,
237                    self.c[2][0] * m.x + self.c[2][1] * m.y + self.c[2][2] * m.z,
238                )
239            }
240
241            fn rotation_by_radians_around_unit_vector(
242                a: Number,
243                ux: Number,
244                uy: Number,
245                uz: Number,
246            ) -> Self {
247                let (sin_a, cos_a) = a.sin_cos();
248                let one_minus_cos_a = Number::ONE - cos_a;
249                Self {
250                    c: [
251                        [
252                            cos_a + ux * ux * one_minus_cos_a,
253                            ux * uy * one_minus_cos_a - uz * sin_a,
254                            ux * uz * one_minus_cos_a + uy * sin_a,
255                        ],
256                        [
257                            uy * ux * one_minus_cos_a + uz * sin_a,
258                            cos_a + uy * uy * one_minus_cos_a,
259                            uy * uz * one_minus_cos_a - ux * sin_a,
260                        ],
261                        [
262                            uz * ux * one_minus_cos_a - uy * sin_a,
263                            uz * uy * one_minus_cos_a + ux * sin_a,
264                            cos_a + uz * uz * one_minus_cos_a,
265                        ],
266                    ],
267                }
268            }
269        }
270
271        impl<Number> Default for LinearMap3d<Number>
272        where
273            Number: ArithmeticOps,
274        {
275            // It returns the identity transformation.
276            fn default() -> Self {
277                Self::new([
278                    [Number::ONE, Number::ZERO, Number::ZERO],
279                    [Number::ZERO, Number::ONE, Number::ZERO],
280                    [Number::ZERO, Number::ZERO, Number::ONE],
281                ])
282            }
283        }
284
285        // format!("{}", LinearMap3d)
286        impl<Number: ArithmeticOps> fmt::Display for LinearMap3d<Number> {
287            fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
288                write!(
289                    formatter,
290                    "{}",
291                    rs_measures::matrix_utils::format_matrix::<3, 3, Number>(&self.c, "")
292                )
293            }
294        }
295
296        // format!("{:?}", LinearMap3d)
297        impl<Number: ArithmeticOps> fmt::Debug for LinearMap3d<Number> {
298            fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
299                write!(
300                    formatter,
301                    "{}",
302                    rs_measures::matrix_utils::format_matrix::<3, 3, Number>(&self.c, "")
303                )
304            }
305        }
306    };
307}