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((0, D::DIM - 1), (DimNameDiff::<D, U1>::name(), Const::<1>))
63 .copy_from(translation);
64
65 res
66 }
67}
68
69impl<T: RealField> Matrix3<T> {
71 #[inline]
73 pub fn new_rotation(angle: T) -> Self {
74 Rotation2::new(angle).to_homogeneous()
75 }
76
77 #[inline]
81 pub fn new_nonuniform_scaling_wrt_point(scaling: &Vector2<T>, pt: &Point2<T>) -> Self {
82 let zero = T::zero();
83 let one = T::one();
84 Matrix3::new(
85 scaling.x.clone(),
86 zero.clone(),
87 pt.x.clone() - pt.x.clone() * scaling.x.clone(),
88 zero.clone(),
89 scaling.y.clone(),
90 pt.y.clone() - pt.y.clone() * scaling.y.clone(),
91 zero.clone(),
92 zero,
93 one,
94 )
95 }
96}
97
98impl<T: RealField> Matrix4<T> {
100 #[inline]
104 pub fn new_rotation(axisangle: Vector3<T>) -> Self {
105 Rotation3::new(axisangle).to_homogeneous()
106 }
107
108 #[inline]
112 pub fn new_rotation_wrt_point(axisangle: Vector3<T>, pt: Point3<T>) -> Self {
113 let rot = Rotation3::from_scaled_axis(axisangle);
114 Isometry::rotation_wrt_point(rot, pt).to_homogeneous()
115 }
116
117 #[inline]
121 pub fn new_nonuniform_scaling_wrt_point(scaling: &Vector3<T>, pt: &Point3<T>) -> Self {
122 let zero = T::zero();
123 let one = T::one();
124 Matrix4::new(
125 scaling.x.clone(),
126 zero.clone(),
127 zero.clone(),
128 pt.x.clone() - pt.x.clone() * scaling.x.clone(),
129 zero.clone(),
130 scaling.y.clone(),
131 zero.clone(),
132 pt.y.clone() - pt.y.clone() * scaling.y.clone(),
133 zero.clone(),
134 zero.clone(),
135 scaling.z.clone(),
136 pt.z.clone() - pt.z.clone() * scaling.z.clone(),
137 zero.clone(),
138 zero.clone(),
139 zero,
140 one,
141 )
142 }
143
144 #[inline]
149 pub fn from_scaled_axis(axisangle: Vector3<T>) -> Self {
150 Rotation3::from_scaled_axis(axisangle).to_homogeneous()
151 }
152
153 pub fn from_euler_angles(roll: T, pitch: T, yaw: T) -> Self {
157 Rotation3::from_euler_angles(roll, pitch, yaw).to_homogeneous()
158 }
159
160 pub fn from_axis_angle(axis: &Unit<Vector3<T>>, angle: T) -> Self {
162 Rotation3::from_axis_angle(axis, angle).to_homogeneous()
163 }
164
165 #[inline]
167 pub fn new_orthographic(left: T, right: T, bottom: T, top: T, znear: T, zfar: T) -> Self {
168 Orthographic3::new(left, right, bottom, top, znear, zfar).into_inner()
169 }
170
171 #[inline]
173 pub fn new_perspective(aspect: T, fovy: T, znear: T, zfar: T) -> Self {
174 Perspective3::new(aspect, fovy, znear, zfar).into_inner()
175 }
176
177 #[inline]
183 pub fn face_towards(eye: &Point3<T>, target: &Point3<T>, up: &Vector3<T>) -> Self {
184 IsometryMatrix3::face_towards(eye, target, up).to_homogeneous()
185 }
186
187 #[deprecated(note = "renamed to `face_towards`")]
189 pub fn new_observer_frame(eye: &Point3<T>, target: &Point3<T>, up: &Vector3<T>) -> Self {
190 Matrix4::face_towards(eye, target, up)
191 }
192
193 #[inline]
195 pub fn look_at_rh(eye: &Point3<T>, target: &Point3<T>, up: &Vector3<T>) -> Self {
196 IsometryMatrix3::look_at_rh(eye, target, up).to_homogeneous()
197 }
198
199 #[inline]
201 pub fn look_at_lh(eye: &Point3<T>, target: &Point3<T>, up: &Vector3<T>) -> Self {
202 IsometryMatrix3::look_at_lh(eye, target, up).to_homogeneous()
203 }
204}
205
206impl<T: Scalar + Zero + One + ClosedMulAssign + ClosedAddAssign, D: DimName, S: Storage<T, D, D>>
208 SquareMatrix<T, D, S>
209{
210 #[inline]
212 #[must_use = "Did you mean to use append_scaling_mut()?"]
213 pub fn append_scaling(&self, scaling: T) -> OMatrix<T, D, D>
214 where
215 D: DimNameSub<U1>,
216 DefaultAllocator: Allocator<D, D>,
217 {
218 let mut res = self.clone_owned();
219 res.append_scaling_mut(scaling);
220 res
221 }
222
223 #[inline]
225 #[must_use = "Did you mean to use prepend_scaling_mut()?"]
226 pub fn prepend_scaling(&self, scaling: T) -> OMatrix<T, D, D>
227 where
228 D: DimNameSub<U1>,
229 DefaultAllocator: Allocator<D, D>,
230 {
231 let mut res = self.clone_owned();
232 res.prepend_scaling_mut(scaling);
233 res
234 }
235
236 #[inline]
238 #[must_use = "Did you mean to use append_nonuniform_scaling_mut()?"]
239 pub fn append_nonuniform_scaling<SB>(
240 &self,
241 scaling: &Vector<T, DimNameDiff<D, U1>, SB>,
242 ) -> OMatrix<T, D, D>
243 where
244 D: DimNameSub<U1>,
245 SB: Storage<T, DimNameDiff<D, U1>>,
246 DefaultAllocator: Allocator<D, D>,
247 {
248 let mut res = self.clone_owned();
249 res.append_nonuniform_scaling_mut(scaling);
250 res
251 }
252
253 #[inline]
255 #[must_use = "Did you mean to use prepend_nonuniform_scaling_mut()?"]
256 pub fn prepend_nonuniform_scaling<SB>(
257 &self,
258 scaling: &Vector<T, DimNameDiff<D, U1>, SB>,
259 ) -> OMatrix<T, D, D>
260 where
261 D: DimNameSub<U1>,
262 SB: Storage<T, DimNameDiff<D, U1>>,
263 DefaultAllocator: Allocator<D, D>,
264 {
265 let mut res = self.clone_owned();
266 res.prepend_nonuniform_scaling_mut(scaling);
267 res
268 }
269
270 #[inline]
272 #[must_use = "Did you mean to use append_translation_mut()?"]
273 pub fn append_translation<SB>(
274 &self,
275 shift: &Vector<T, DimNameDiff<D, U1>, SB>,
276 ) -> OMatrix<T, D, D>
277 where
278 D: DimNameSub<U1>,
279 SB: Storage<T, DimNameDiff<D, U1>>,
280 DefaultAllocator: Allocator<D, D>,
281 {
282 let mut res = self.clone_owned();
283 res.append_translation_mut(shift);
284 res
285 }
286
287 #[inline]
289 #[must_use = "Did you mean to use prepend_translation_mut()?"]
290 pub fn prepend_translation<SB>(
291 &self,
292 shift: &Vector<T, DimNameDiff<D, U1>, SB>,
293 ) -> OMatrix<T, D, D>
294 where
295 D: DimNameSub<U1>,
296 SB: Storage<T, DimNameDiff<D, U1>>,
297 DefaultAllocator: Allocator<D, D> + Allocator<DimNameDiff<D, U1>>,
298 {
299 let mut res = self.clone_owned();
300 res.prepend_translation_mut(shift);
301 res
302 }
303
304 #[inline]
306 pub fn append_scaling_mut(&mut self, scaling: T)
307 where
308 S: StorageMut<T, D, D>,
309 D: DimNameSub<U1>,
310 {
311 let mut to_scale = self.rows_generic_mut(0, DimNameDiff::<D, U1>::name());
312 to_scale *= scaling;
313 }
314
315 #[inline]
317 pub fn prepend_scaling_mut(&mut self, scaling: T)
318 where
319 S: StorageMut<T, D, D>,
320 D: DimNameSub<U1>,
321 {
322 let mut to_scale = self.columns_generic_mut(0, DimNameDiff::<D, U1>::name());
323 to_scale *= scaling;
324 }
325
326 #[inline]
328 pub fn append_nonuniform_scaling_mut<SB>(&mut self, scaling: &Vector<T, DimNameDiff<D, U1>, SB>)
329 where
330 S: StorageMut<T, D, D>,
331 D: DimNameSub<U1>,
332 SB: Storage<T, DimNameDiff<D, U1>>,
333 {
334 for i in 0..scaling.len() {
335 let mut to_scale = self.fixed_rows_mut::<1>(i);
336 to_scale *= scaling[i].clone();
337 }
338 }
339
340 #[inline]
342 pub fn prepend_nonuniform_scaling_mut<SB>(
343 &mut self,
344 scaling: &Vector<T, DimNameDiff<D, U1>, SB>,
345 ) where
346 S: StorageMut<T, D, D>,
347 D: DimNameSub<U1>,
348 SB: Storage<T, DimNameDiff<D, U1>>,
349 {
350 for i in 0..scaling.len() {
351 let mut to_scale = self.fixed_columns_mut::<1>(i);
352 to_scale *= scaling[i].clone();
353 }
354 }
355
356 #[inline]
358 pub fn append_translation_mut<SB>(&mut self, shift: &Vector<T, DimNameDiff<D, U1>, SB>)
359 where
360 S: StorageMut<T, D, D>,
361 D: DimNameSub<U1>,
362 SB: Storage<T, DimNameDiff<D, U1>>,
363 {
364 for i in 0..D::DIM {
365 for j in 0..D::DIM - 1 {
366 let add = shift[j].clone() * self[(D::DIM - 1, i)].clone();
367 self[(j, i)] += add;
368 }
369 }
370 }
371
372 #[inline]
374 pub fn prepend_translation_mut<SB>(&mut self, shift: &Vector<T, DimNameDiff<D, U1>, SB>)
375 where
376 D: DimNameSub<U1>,
377 S: StorageMut<T, D, D>,
378 SB: Storage<T, DimNameDiff<D, U1>>,
379 DefaultAllocator: Allocator<DimNameDiff<D, U1>>,
380 {
381 let scale = self
382 .generic_view((D::DIM - 1, 0), (Const::<1>, DimNameDiff::<D, U1>::name()))
383 .tr_dot(shift);
384 let post_translation = self.generic_view(
385 (0, 0),
386 (DimNameDiff::<D, U1>::name(), DimNameDiff::<D, U1>::name()),
387 ) * shift;
388
389 self[(D::DIM - 1, D::DIM - 1)] += scale;
390
391 let mut translation =
392 self.generic_view_mut((0, D::DIM - 1), (DimNameDiff::<D, U1>::name(), Const::<1>));
393 translation += post_translation;
394 }
395}
396
397impl<T: RealField, D: DimNameSub<U1>, S: Storage<T, D, D>> SquareMatrix<T, D, S>
399where
400 DefaultAllocator: Allocator<D, D>
401 + Allocator<DimNameDiff<D, U1>>
402 + Allocator<DimNameDiff<D, U1>, DimNameDiff<D, U1>>,
403{
404 #[inline]
406 pub fn transform_vector(
407 &self,
408 v: &OVector<T, DimNameDiff<D, U1>>,
409 ) -> OVector<T, DimNameDiff<D, U1>> {
410 let transform = self.generic_view(
411 (0, 0),
412 (DimNameDiff::<D, U1>::name(), DimNameDiff::<D, U1>::name()),
413 );
414 let normalizer =
415 self.generic_view((D::DIM - 1, 0), (Const::<1>, DimNameDiff::<D, U1>::name()));
416 let n = normalizer.tr_dot(v);
417
418 if !n.is_zero() {
419 return transform * (v / n);
420 }
421
422 transform * v
423 }
424}
425
426impl<T: RealField, S: Storage<T, Const<3>, Const<3>>> SquareMatrix<T, Const<3>, S> {
427 #[inline]
429 pub fn transform_point(&self, pt: &Point<T, 2>) -> Point<T, 2> {
430 let transform = self.fixed_view::<2, 2>(0, 0);
431 let translation = self.fixed_view::<2, 1>(0, 2);
432 let normalizer = self.fixed_view::<1, 2>(2, 0);
433 let n = normalizer.tr_dot(&pt.coords) + unsafe { self.get_unchecked((2, 2)).clone() };
434
435 if !n.is_zero() {
436 (transform * pt + translation) / n
437 } else {
438 transform * pt + translation
439 }
440 }
441}
442
443impl<T: RealField, S: Storage<T, Const<4>, Const<4>>> SquareMatrix<T, Const<4>, S> {
444 #[inline]
446 pub fn transform_point(&self, pt: &Point<T, 3>) -> Point<T, 3> {
447 let transform = self.fixed_view::<3, 3>(0, 0);
448 let translation = self.fixed_view::<3, 1>(0, 3);
449 let normalizer = self.fixed_view::<1, 3>(3, 0);
450 let n = normalizer.tr_dot(&pt.coords) + unsafe { self.get_unchecked((3, 3)).clone() };
451
452 if !n.is_zero() {
453 (transform * pt + translation) / n
454 } else {
455 transform * pt + translation
456 }
457 }
458}