1use num::{One, Zero};
9
10use crate::base::allocator::Allocator;
11use crate::base::dimension::{DimName, DimNameDiff, DimNameSub, U1};
12use crate::base::storage::{Storage, StorageMut};
13use crate::base::{
14 Const, DefaultAllocator, Matrix3, Matrix4, OMatrix, OVector, Scalar, SquareMatrix, Unit,
15 Vector, Vector2, Vector3,
16};
17use crate::geometry::{
18 Isometry, IsometryMatrix3, Orthographic3, Perspective3, Point, Point2, Point3, Rotation2,
19 Rotation3,
20};
21
22use simba::scalar::{ClosedAdd, ClosedMul, RealField};
23
24impl<T, D: DimName> OMatrix<T, D, D>
26where
27 T: Scalar + Zero + One,
28 DefaultAllocator: Allocator<T, D, D>,
29{
30 #[inline]
32 pub fn new_scaling(scaling: T) -> Self {
33 let mut res = Self::from_diagonal_element(scaling);
34 res[(D::dim() - 1, D::dim() - 1)] = T::one();
35
36 res
37 }
38
39 #[inline]
41 pub fn new_nonuniform_scaling<SB>(scaling: &Vector<T, DimNameDiff<D, U1>, SB>) -> Self
42 where
43 D: DimNameSub<U1>,
44 SB: Storage<T, DimNameDiff<D, U1>>,
45 {
46 let mut res = Self::identity();
47 for i in 0..scaling.len() {
48 res[(i, i)] = scaling[i].clone();
49 }
50
51 res
52 }
53
54 #[inline]
56 pub fn new_translation<SB>(translation: &Vector<T, DimNameDiff<D, U1>, SB>) -> Self
57 where
58 D: DimNameSub<U1>,
59 SB: Storage<T, DimNameDiff<D, U1>>,
60 {
61 let mut res = Self::identity();
62 res.generic_slice_mut(
63 (0, D::dim() - 1),
64 (DimNameDiff::<D, U1>::name(), Const::<1>),
65 )
66 .copy_from(translation);
67
68 res
69 }
70}
71
72impl<T: RealField> Matrix3<T> {
74 #[inline]
76 pub fn new_rotation(angle: T) -> Self {
77 Rotation2::new(angle).to_homogeneous()
78 }
79
80 #[inline]
84 pub fn new_nonuniform_scaling_wrt_point(scaling: &Vector2<T>, pt: &Point2<T>) -> Self {
85 let zero = T::zero();
86 let one = T::one();
87 Matrix3::new(
88 scaling.x.clone(),
89 zero.clone(),
90 pt.x.clone() - pt.x.clone() * scaling.x.clone(),
91 zero.clone(),
92 scaling.y.clone(),
93 pt.y.clone() - pt.y.clone() * scaling.y.clone(),
94 zero.clone(),
95 zero,
96 one,
97 )
98 }
99}
100
101impl<T: RealField> Matrix4<T> {
103 #[inline]
107 pub fn new_rotation(axisangle: Vector3<T>) -> Self {
108 Rotation3::new(axisangle).to_homogeneous()
109 }
110
111 #[inline]
115 pub fn new_rotation_wrt_point(axisangle: Vector3<T>, pt: Point3<T>) -> Self {
116 let rot = Rotation3::from_scaled_axis(axisangle);
117 Isometry::rotation_wrt_point(rot, pt).to_homogeneous()
118 }
119
120 #[inline]
124 pub fn new_nonuniform_scaling_wrt_point(scaling: &Vector3<T>, pt: &Point3<T>) -> Self {
125 let zero = T::zero();
126 let one = T::one();
127 Matrix4::new(
128 scaling.x.clone(),
129 zero.clone(),
130 zero.clone(),
131 pt.x.clone() - pt.x.clone() * scaling.x.clone(),
132 zero.clone(),
133 scaling.y.clone(),
134 zero.clone(),
135 pt.y.clone() - pt.y.clone() * scaling.y.clone(),
136 zero.clone(),
137 zero.clone(),
138 scaling.z.clone(),
139 pt.z.clone() - pt.z.clone() * scaling.z.clone(),
140 zero.clone(),
141 zero.clone(),
142 zero,
143 one,
144 )
145 }
146
147 #[inline]
152 pub fn from_scaled_axis(axisangle: Vector3<T>) -> Self {
153 Rotation3::from_scaled_axis(axisangle).to_homogeneous()
154 }
155
156 pub fn from_euler_angles(roll: T, pitch: T, yaw: T) -> Self {
160 Rotation3::from_euler_angles(roll, pitch, yaw).to_homogeneous()
161 }
162
163 pub fn from_axis_angle(axis: &Unit<Vector3<T>>, angle: T) -> Self {
165 Rotation3::from_axis_angle(axis, angle).to_homogeneous()
166 }
167
168 #[inline]
170 pub fn new_orthographic(left: T, right: T, bottom: T, top: T, znear: T, zfar: T) -> Self {
171 Orthographic3::new(left, right, bottom, top, znear, zfar).into_inner()
172 }
173
174 #[inline]
176 pub fn new_perspective(aspect: T, fovy: T, znear: T, zfar: T) -> Self {
177 Perspective3::new(aspect, fovy, znear, zfar).into_inner()
178 }
179
180 #[inline]
186 pub fn face_towards(eye: &Point3<T>, target: &Point3<T>, up: &Vector3<T>) -> Self {
187 IsometryMatrix3::face_towards(eye, target, up).to_homogeneous()
188 }
189
190 #[deprecated(note = "renamed to `face_towards`")]
192 pub fn new_observer_frame(eye: &Point3<T>, target: &Point3<T>, up: &Vector3<T>) -> Self {
193 Matrix4::face_towards(eye, target, up)
194 }
195
196 #[inline]
198 pub fn look_at_rh(eye: &Point3<T>, target: &Point3<T>, up: &Vector3<T>) -> Self {
199 IsometryMatrix3::look_at_rh(eye, target, up).to_homogeneous()
200 }
201
202 #[inline]
204 pub fn look_at_lh(eye: &Point3<T>, target: &Point3<T>, up: &Vector3<T>) -> Self {
205 IsometryMatrix3::look_at_lh(eye, target, up).to_homogeneous()
206 }
207}
208
209impl<T: Scalar + Zero + One + ClosedMul + ClosedAdd, D: DimName, S: Storage<T, D, D>>
211 SquareMatrix<T, D, S>
212{
213 #[inline]
215 #[must_use = "Did you mean to use append_scaling_mut()?"]
216 pub fn append_scaling(&self, scaling: T) -> OMatrix<T, D, D>
217 where
218 D: DimNameSub<U1>,
219 DefaultAllocator: Allocator<T, D, D>,
220 {
221 let mut res = self.clone_owned();
222 res.append_scaling_mut(scaling);
223 res
224 }
225
226 #[inline]
228 #[must_use = "Did you mean to use prepend_scaling_mut()?"]
229 pub fn prepend_scaling(&self, scaling: T) -> OMatrix<T, D, D>
230 where
231 D: DimNameSub<U1>,
232 DefaultAllocator: Allocator<T, D, D>,
233 {
234 let mut res = self.clone_owned();
235 res.prepend_scaling_mut(scaling);
236 res
237 }
238
239 #[inline]
241 #[must_use = "Did you mean to use append_nonuniform_scaling_mut()?"]
242 pub fn append_nonuniform_scaling<SB>(
243 &self,
244 scaling: &Vector<T, DimNameDiff<D, U1>, SB>,
245 ) -> OMatrix<T, D, D>
246 where
247 D: DimNameSub<U1>,
248 SB: Storage<T, DimNameDiff<D, U1>>,
249 DefaultAllocator: Allocator<T, D, D>,
250 {
251 let mut res = self.clone_owned();
252 res.append_nonuniform_scaling_mut(scaling);
253 res
254 }
255
256 #[inline]
258 #[must_use = "Did you mean to use prepend_nonuniform_scaling_mut()?"]
259 pub fn prepend_nonuniform_scaling<SB>(
260 &self,
261 scaling: &Vector<T, DimNameDiff<D, U1>, SB>,
262 ) -> OMatrix<T, D, D>
263 where
264 D: DimNameSub<U1>,
265 SB: Storage<T, DimNameDiff<D, U1>>,
266 DefaultAllocator: Allocator<T, D, D>,
267 {
268 let mut res = self.clone_owned();
269 res.prepend_nonuniform_scaling_mut(scaling);
270 res
271 }
272
273 #[inline]
275 #[must_use = "Did you mean to use append_translation_mut()?"]
276 pub fn append_translation<SB>(
277 &self,
278 shift: &Vector<T, DimNameDiff<D, U1>, SB>,
279 ) -> OMatrix<T, D, D>
280 where
281 D: DimNameSub<U1>,
282 SB: Storage<T, DimNameDiff<D, U1>>,
283 DefaultAllocator: Allocator<T, D, D>,
284 {
285 let mut res = self.clone_owned();
286 res.append_translation_mut(shift);
287 res
288 }
289
290 #[inline]
292 #[must_use = "Did you mean to use prepend_translation_mut()?"]
293 pub fn prepend_translation<SB>(
294 &self,
295 shift: &Vector<T, DimNameDiff<D, U1>, SB>,
296 ) -> OMatrix<T, D, D>
297 where
298 D: DimNameSub<U1>,
299 SB: Storage<T, DimNameDiff<D, U1>>,
300 DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimNameDiff<D, U1>>,
301 {
302 let mut res = self.clone_owned();
303 res.prepend_translation_mut(shift);
304 res
305 }
306
307 #[inline]
309 pub fn append_scaling_mut(&mut self, scaling: T)
310 where
311 S: StorageMut<T, D, D>,
312 D: DimNameSub<U1>,
313 {
314 let mut to_scale = self.rows_generic_mut(0, DimNameDiff::<D, U1>::name());
315 to_scale *= scaling;
316 }
317
318 #[inline]
320 pub fn prepend_scaling_mut(&mut self, scaling: T)
321 where
322 S: StorageMut<T, D, D>,
323 D: DimNameSub<U1>,
324 {
325 let mut to_scale = self.columns_generic_mut(0, DimNameDiff::<D, U1>::name());
326 to_scale *= scaling;
327 }
328
329 #[inline]
331 pub fn append_nonuniform_scaling_mut<SB>(&mut self, scaling: &Vector<T, DimNameDiff<D, U1>, SB>)
332 where
333 S: StorageMut<T, D, D>,
334 D: DimNameSub<U1>,
335 SB: Storage<T, DimNameDiff<D, U1>>,
336 {
337 for i in 0..scaling.len() {
338 let mut to_scale = self.fixed_rows_mut::<1>(i);
339 to_scale *= scaling[i].clone();
340 }
341 }
342
343 #[inline]
345 pub fn prepend_nonuniform_scaling_mut<SB>(
346 &mut self,
347 scaling: &Vector<T, DimNameDiff<D, U1>, SB>,
348 ) where
349 S: StorageMut<T, D, D>,
350 D: DimNameSub<U1>,
351 SB: Storage<T, DimNameDiff<D, U1>>,
352 {
353 for i in 0..scaling.len() {
354 let mut to_scale = self.fixed_columns_mut::<1>(i);
355 to_scale *= scaling[i].clone();
356 }
357 }
358
359 #[inline]
361 pub fn append_translation_mut<SB>(&mut self, shift: &Vector<T, DimNameDiff<D, U1>, SB>)
362 where
363 S: StorageMut<T, D, D>,
364 D: DimNameSub<U1>,
365 SB: Storage<T, DimNameDiff<D, U1>>,
366 {
367 for i in 0..D::dim() {
368 for j in 0..D::dim() - 1 {
369 let add = shift[j].clone() * self[(D::dim() - 1, i)].clone();
370 self[(j, i)] += add;
371 }
372 }
373 }
374
375 #[inline]
377 pub fn prepend_translation_mut<SB>(&mut self, shift: &Vector<T, DimNameDiff<D, U1>, SB>)
378 where
379 D: DimNameSub<U1>,
380 S: StorageMut<T, D, D>,
381 SB: Storage<T, DimNameDiff<D, U1>>,
382 DefaultAllocator: Allocator<T, DimNameDiff<D, U1>>,
383 {
384 let scale = self
385 .generic_slice(
386 (D::dim() - 1, 0),
387 (Const::<1>, DimNameDiff::<D, U1>::name()),
388 )
389 .tr_dot(shift);
390 let post_translation = self.generic_slice(
391 (0, 0),
392 (DimNameDiff::<D, U1>::name(), DimNameDiff::<D, U1>::name()),
393 ) * shift;
394
395 self[(D::dim() - 1, D::dim() - 1)] += scale;
396
397 let mut translation = self.generic_slice_mut(
398 (0, D::dim() - 1),
399 (DimNameDiff::<D, U1>::name(), Const::<1>),
400 );
401 translation += post_translation;
402 }
403}
404
405impl<T: RealField, D: DimNameSub<U1>, S: Storage<T, D, D>> SquareMatrix<T, D, S>
407where
408 DefaultAllocator: Allocator<T, D, D>
409 + Allocator<T, DimNameDiff<D, U1>>
410 + Allocator<T, DimNameDiff<D, U1>, DimNameDiff<D, U1>>,
411{
412 #[inline]
414 pub fn transform_vector(
415 &self,
416 v: &OVector<T, DimNameDiff<D, U1>>,
417 ) -> OVector<T, DimNameDiff<D, U1>> {
418 let transform = self.generic_slice(
419 (0, 0),
420 (DimNameDiff::<D, U1>::name(), DimNameDiff::<D, U1>::name()),
421 );
422 let normalizer = self.generic_slice(
423 (D::dim() - 1, 0),
424 (Const::<1>, DimNameDiff::<D, U1>::name()),
425 );
426 let n = normalizer.tr_dot(v);
427
428 if !n.is_zero() {
429 return transform * (v / n);
430 }
431
432 transform * v
433 }
434}
435
436impl<T: RealField, S: Storage<T, Const<3>, Const<3>>> SquareMatrix<T, Const<3>, S> {
437 #[inline]
439 pub fn transform_point(&self, pt: &Point<T, 2>) -> Point<T, 2> {
440 let transform = self.fixed_slice::<2, 2>(0, 0);
441 let translation = self.fixed_slice::<2, 1>(0, 2);
442 let normalizer = self.fixed_slice::<1, 2>(2, 0);
443 let n = normalizer.tr_dot(&pt.coords) + unsafe { self.get_unchecked((2, 2)).clone() };
444
445 if !n.is_zero() {
446 (transform * pt + translation) / n
447 } else {
448 transform * pt + translation
449 }
450 }
451}
452
453impl<T: RealField, S: Storage<T, Const<4>, Const<4>>> SquareMatrix<T, Const<4>, S> {
454 #[inline]
456 pub fn transform_point(&self, pt: &Point<T, 3>) -> Point<T, 3> {
457 let transform = self.fixed_slice::<3, 3>(0, 0);
458 let translation = self.fixed_slice::<3, 1>(0, 3);
459 let normalizer = self.fixed_slice::<1, 3>(3, 0);
460 let n = normalizer.tr_dot(&pt.coords) + unsafe { self.get_unchecked((3, 3)).clone() };
461
462 if !n.is_zero() {
463 (transform * pt + translation) / n
464 } else {
465 transform * pt + translation
466 }
467 }
468}