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::{ClosedAddAssign, ClosedMulAssign, RealField};
23
24impl<T, D: DimName> OMatrix<T, D, D>
26where
27 T: Scalar + Zero + One,
28 DefaultAllocator: Allocator<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_view_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<
211 T: Scalar + Zero + One + ClosedMulAssign + ClosedAddAssign,
212 D: DimName,
213 S: Storage<T, D, D>,
214 > SquareMatrix<T, D, S>
215{
216 #[inline]
218 #[must_use = "Did you mean to use append_scaling_mut()?"]
219 pub fn append_scaling(&self, scaling: T) -> OMatrix<T, D, D>
220 where
221 D: DimNameSub<U1>,
222 DefaultAllocator: Allocator<D, D>,
223 {
224 let mut res = self.clone_owned();
225 res.append_scaling_mut(scaling);
226 res
227 }
228
229 #[inline]
231 #[must_use = "Did you mean to use prepend_scaling_mut()?"]
232 pub fn prepend_scaling(&self, scaling: T) -> OMatrix<T, D, D>
233 where
234 D: DimNameSub<U1>,
235 DefaultAllocator: Allocator<D, D>,
236 {
237 let mut res = self.clone_owned();
238 res.prepend_scaling_mut(scaling);
239 res
240 }
241
242 #[inline]
244 #[must_use = "Did you mean to use append_nonuniform_scaling_mut()?"]
245 pub fn append_nonuniform_scaling<SB>(
246 &self,
247 scaling: &Vector<T, DimNameDiff<D, U1>, SB>,
248 ) -> OMatrix<T, D, D>
249 where
250 D: DimNameSub<U1>,
251 SB: Storage<T, DimNameDiff<D, U1>>,
252 DefaultAllocator: Allocator<D, D>,
253 {
254 let mut res = self.clone_owned();
255 res.append_nonuniform_scaling_mut(scaling);
256 res
257 }
258
259 #[inline]
261 #[must_use = "Did you mean to use prepend_nonuniform_scaling_mut()?"]
262 pub fn prepend_nonuniform_scaling<SB>(
263 &self,
264 scaling: &Vector<T, DimNameDiff<D, U1>, SB>,
265 ) -> OMatrix<T, D, D>
266 where
267 D: DimNameSub<U1>,
268 SB: Storage<T, DimNameDiff<D, U1>>,
269 DefaultAllocator: Allocator<D, D>,
270 {
271 let mut res = self.clone_owned();
272 res.prepend_nonuniform_scaling_mut(scaling);
273 res
274 }
275
276 #[inline]
278 #[must_use = "Did you mean to use append_translation_mut()?"]
279 pub fn append_translation<SB>(
280 &self,
281 shift: &Vector<T, DimNameDiff<D, U1>, SB>,
282 ) -> OMatrix<T, D, D>
283 where
284 D: DimNameSub<U1>,
285 SB: Storage<T, DimNameDiff<D, U1>>,
286 DefaultAllocator: Allocator<D, D>,
287 {
288 let mut res = self.clone_owned();
289 res.append_translation_mut(shift);
290 res
291 }
292
293 #[inline]
295 #[must_use = "Did you mean to use prepend_translation_mut()?"]
296 pub fn prepend_translation<SB>(
297 &self,
298 shift: &Vector<T, DimNameDiff<D, U1>, SB>,
299 ) -> OMatrix<T, D, D>
300 where
301 D: DimNameSub<U1>,
302 SB: Storage<T, DimNameDiff<D, U1>>,
303 DefaultAllocator: Allocator<D, D> + Allocator<DimNameDiff<D, U1>>,
304 {
305 let mut res = self.clone_owned();
306 res.prepend_translation_mut(shift);
307 res
308 }
309
310 #[inline]
312 pub fn append_scaling_mut(&mut self, scaling: T)
313 where
314 S: StorageMut<T, D, D>,
315 D: DimNameSub<U1>,
316 {
317 let mut to_scale = self.rows_generic_mut(0, DimNameDiff::<D, U1>::name());
318 to_scale *= scaling;
319 }
320
321 #[inline]
323 pub fn prepend_scaling_mut(&mut self, scaling: T)
324 where
325 S: StorageMut<T, D, D>,
326 D: DimNameSub<U1>,
327 {
328 let mut to_scale = self.columns_generic_mut(0, DimNameDiff::<D, U1>::name());
329 to_scale *= scaling;
330 }
331
332 #[inline]
334 pub fn append_nonuniform_scaling_mut<SB>(&mut self, scaling: &Vector<T, DimNameDiff<D, U1>, SB>)
335 where
336 S: StorageMut<T, D, D>,
337 D: DimNameSub<U1>,
338 SB: Storage<T, DimNameDiff<D, U1>>,
339 {
340 for i in 0..scaling.len() {
341 let mut to_scale = self.fixed_rows_mut::<1>(i);
342 to_scale *= scaling[i].clone();
343 }
344 }
345
346 #[inline]
348 pub fn prepend_nonuniform_scaling_mut<SB>(
349 &mut self,
350 scaling: &Vector<T, DimNameDiff<D, U1>, SB>,
351 ) where
352 S: StorageMut<T, D, D>,
353 D: DimNameSub<U1>,
354 SB: Storage<T, DimNameDiff<D, U1>>,
355 {
356 for i in 0..scaling.len() {
357 let mut to_scale = self.fixed_columns_mut::<1>(i);
358 to_scale *= scaling[i].clone();
359 }
360 }
361
362 #[inline]
364 pub fn append_translation_mut<SB>(&mut self, shift: &Vector<T, DimNameDiff<D, U1>, SB>)
365 where
366 S: StorageMut<T, D, D>,
367 D: DimNameSub<U1>,
368 SB: Storage<T, DimNameDiff<D, U1>>,
369 {
370 for i in 0..D::dim() {
371 for j in 0..D::dim() - 1 {
372 let add = shift[j].clone() * self[(D::dim() - 1, i)].clone();
373 self[(j, i)] += add;
374 }
375 }
376 }
377
378 #[inline]
380 pub fn prepend_translation_mut<SB>(&mut self, shift: &Vector<T, DimNameDiff<D, U1>, SB>)
381 where
382 D: DimNameSub<U1>,
383 S: StorageMut<T, D, D>,
384 SB: Storage<T, DimNameDiff<D, U1>>,
385 DefaultAllocator: Allocator<DimNameDiff<D, U1>>,
386 {
387 let scale = self
388 .generic_view(
389 (D::dim() - 1, 0),
390 (Const::<1>, DimNameDiff::<D, U1>::name()),
391 )
392 .tr_dot(shift);
393 let post_translation = self.generic_view(
394 (0, 0),
395 (DimNameDiff::<D, U1>::name(), DimNameDiff::<D, U1>::name()),
396 ) * shift;
397
398 self[(D::dim() - 1, D::dim() - 1)] += scale;
399
400 let mut translation = self.generic_view_mut(
401 (0, D::dim() - 1),
402 (DimNameDiff::<D, U1>::name(), Const::<1>),
403 );
404 translation += post_translation;
405 }
406}
407
408impl<T: RealField, D: DimNameSub<U1>, S: Storage<T, D, D>> SquareMatrix<T, D, S>
410where
411 DefaultAllocator: Allocator<D, D>
412 + Allocator<DimNameDiff<D, U1>>
413 + Allocator<DimNameDiff<D, U1>, DimNameDiff<D, U1>>,
414{
415 #[inline]
417 pub fn transform_vector(
418 &self,
419 v: &OVector<T, DimNameDiff<D, U1>>,
420 ) -> OVector<T, DimNameDiff<D, U1>> {
421 let transform = self.generic_view(
422 (0, 0),
423 (DimNameDiff::<D, U1>::name(), DimNameDiff::<D, U1>::name()),
424 );
425 let normalizer = self.generic_view(
426 (D::dim() - 1, 0),
427 (Const::<1>, DimNameDiff::<D, U1>::name()),
428 );
429 let n = normalizer.tr_dot(v);
430
431 if !n.is_zero() {
432 return transform * (v / n);
433 }
434
435 transform * v
436 }
437}
438
439impl<T: RealField, S: Storage<T, Const<3>, Const<3>>> SquareMatrix<T, Const<3>, S> {
440 #[inline]
442 pub fn transform_point(&self, pt: &Point<T, 2>) -> Point<T, 2> {
443 let transform = self.fixed_view::<2, 2>(0, 0);
444 let translation = self.fixed_view::<2, 1>(0, 2);
445 let normalizer = self.fixed_view::<1, 2>(2, 0);
446 let n = normalizer.tr_dot(&pt.coords) + unsafe { self.get_unchecked((2, 2)).clone() };
447
448 if !n.is_zero() {
449 (transform * pt + translation) / n
450 } else {
451 transform * pt + translation
452 }
453 }
454}
455
456impl<T: RealField, S: Storage<T, Const<4>, Const<4>>> SquareMatrix<T, Const<4>, S> {
457 #[inline]
459 pub fn transform_point(&self, pt: &Point<T, 3>) -> Point<T, 3> {
460 let transform = self.fixed_view::<3, 3>(0, 0);
461 let translation = self.fixed_view::<3, 1>(0, 3);
462 let normalizer = self.fixed_view::<1, 3>(3, 0);
463 let n = normalizer.tr_dot(&pt.coords) + unsafe { self.get_unchecked((3, 3)).clone() };
464
465 if !n.is_zero() {
466 (transform * pt + translation) / n
467 } else {
468 transform * pt + translation
469 }
470 }
471}