nalgebra/geometry/orthographic.rs
1#[cfg(feature = "arbitrary")]
2use quickcheck::{Arbitrary, Gen};
3#[cfg(feature = "rand-no-std")]
4use rand::{
5 distributions::{Distribution, Standard},
6 Rng,
7};
8#[cfg(feature = "serde-serialize-no-std")]
9use serde::{Deserialize, Deserializer, Serialize, Serializer};
10use std::fmt;
11
12use simba::scalar::RealField;
13
14use crate::base::dimension::U3;
15use crate::base::storage::Storage;
16use crate::base::{Matrix4, Vector, Vector3};
17
18use crate::geometry::{Point3, Projective3};
19
20#[cfg(feature = "rkyv-serialize")]
21use rkyv::bytecheck;
22
23/// A 3D orthographic projection stored as a homogeneous 4x4 matrix.
24#[repr(C)]
25#[cfg_attr(
26 feature = "rkyv-serialize-no-std",
27 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize),
28 archive(
29 as = "Orthographic3<T::Archived>",
30 bound(archive = "
31 T: rkyv::Archive,
32 Matrix4<T>: rkyv::Archive<Archived = Matrix4<T::Archived>>
33 ")
34 )
35)]
36#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))]
37#[derive(Copy, Clone)]
38pub struct Orthographic3<T> {
39 matrix: Matrix4<T>,
40}
41
42impl<T: RealField> fmt::Debug for Orthographic3<T> {
43 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
44 self.matrix.fmt(f)
45 }
46}
47
48impl<T: RealField> PartialEq for Orthographic3<T> {
49 #[inline]
50 fn eq(&self, right: &Self) -> bool {
51 self.matrix == right.matrix
52 }
53}
54
55#[cfg(feature = "bytemuck")]
56unsafe impl<T> bytemuck::Zeroable for Orthographic3<T>
57where
58 T: RealField + bytemuck::Zeroable,
59 Matrix4<T>: bytemuck::Zeroable,
60{
61}
62
63#[cfg(feature = "bytemuck")]
64unsafe impl<T> bytemuck::Pod for Orthographic3<T>
65where
66 T: RealField + bytemuck::Pod,
67 Matrix4<T>: bytemuck::Pod,
68{
69}
70
71#[cfg(feature = "serde-serialize-no-std")]
72impl<T: RealField + Serialize> Serialize for Orthographic3<T> {
73 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
74 where
75 S: Serializer,
76 {
77 self.matrix.serialize(serializer)
78 }
79}
80
81#[cfg(feature = "serde-serialize-no-std")]
82impl<'a, T: RealField + Deserialize<'a>> Deserialize<'a> for Orthographic3<T> {
83 fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
84 where
85 Des: Deserializer<'a>,
86 {
87 let matrix = Matrix4::<T>::deserialize(deserializer)?;
88
89 Ok(Self::from_matrix_unchecked(matrix))
90 }
91}
92
93impl<T> Orthographic3<T> {
94 /// Wraps the given matrix to interpret it as a 3D orthographic matrix.
95 ///
96 /// It is not checked whether or not the given matrix actually represents an orthographic
97 /// projection.
98 ///
99 /// # Example
100 /// ```
101 /// # use nalgebra::{Orthographic3, Point3, Matrix4};
102 /// let mat = Matrix4::new(
103 /// 2.0 / 9.0, 0.0, 0.0, -11.0 / 9.0,
104 /// 0.0, 2.0 / 18.0, 0.0, -22.0 / 18.0,
105 /// 0.0, 0.0, -2.0 / 999.9, -1000.1 / 999.9,
106 /// 0.0, 0.0, 0.0, 1.0
107 /// );
108 /// let proj = Orthographic3::from_matrix_unchecked(mat);
109 /// assert_eq!(proj, Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0));
110 /// ```
111 #[inline]
112 pub const fn from_matrix_unchecked(matrix: Matrix4<T>) -> Self {
113 Self { matrix }
114 }
115}
116
117impl<T: RealField> Orthographic3<T> {
118 /// Creates a new orthographic projection matrix.
119 ///
120 /// This follows the OpenGL convention, so this will flip the `z` axis.
121 ///
122 /// # Example
123 /// ```
124 /// # #[macro_use] extern crate approx;
125 /// # use nalgebra::{Orthographic3, Point3};
126 /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
127 /// // Check this projection actually transforms the view cuboid into the double-unit cube.
128 /// // See https://www.nalgebra.org/docs/user_guide/projections#orthographic-projection for more details.
129 /// let p1 = Point3::new(1.0, 2.0, -0.1);
130 /// let p2 = Point3::new(1.0, 2.0, -1000.0);
131 /// let p3 = Point3::new(1.0, 20.0, -0.1);
132 /// let p4 = Point3::new(1.0, 20.0, -1000.0);
133 /// let p5 = Point3::new(10.0, 2.0, -0.1);
134 /// let p6 = Point3::new(10.0, 2.0, -1000.0);
135 /// let p7 = Point3::new(10.0, 20.0, -0.1);
136 /// let p8 = Point3::new(10.0, 20.0, -1000.0);
137 ///
138 /// assert_relative_eq!(proj.project_point(&p1), Point3::new(-1.0, -1.0, -1.0));
139 /// assert_relative_eq!(proj.project_point(&p2), Point3::new(-1.0, -1.0, 1.0));
140 /// assert_relative_eq!(proj.project_point(&p3), Point3::new(-1.0, 1.0, -1.0));
141 /// assert_relative_eq!(proj.project_point(&p4), Point3::new(-1.0, 1.0, 1.0));
142 /// assert_relative_eq!(proj.project_point(&p5), Point3::new( 1.0, -1.0, -1.0));
143 /// assert_relative_eq!(proj.project_point(&p6), Point3::new( 1.0, -1.0, 1.0));
144 /// assert_relative_eq!(proj.project_point(&p7), Point3::new( 1.0, 1.0, -1.0));
145 /// assert_relative_eq!(proj.project_point(&p8), Point3::new( 1.0, 1.0, 1.0));
146 ///
147 /// // This also works with flipped axis. In other words, we allow that
148 /// // `left > right`, `bottom > top`, and/or `znear > zfar`.
149 /// let proj = Orthographic3::new(10.0, 1.0, 20.0, 2.0, 1000.0, 0.1);
150 ///
151 /// assert_relative_eq!(proj.project_point(&p1), Point3::new( 1.0, 1.0, 1.0));
152 /// assert_relative_eq!(proj.project_point(&p2), Point3::new( 1.0, 1.0, -1.0));
153 /// assert_relative_eq!(proj.project_point(&p3), Point3::new( 1.0, -1.0, 1.0));
154 /// assert_relative_eq!(proj.project_point(&p4), Point3::new( 1.0, -1.0, -1.0));
155 /// assert_relative_eq!(proj.project_point(&p5), Point3::new(-1.0, 1.0, 1.0));
156 /// assert_relative_eq!(proj.project_point(&p6), Point3::new(-1.0, 1.0, -1.0));
157 /// assert_relative_eq!(proj.project_point(&p7), Point3::new(-1.0, -1.0, 1.0));
158 /// assert_relative_eq!(proj.project_point(&p8), Point3::new(-1.0, -1.0, -1.0));
159 /// ```
160 #[inline]
161 pub fn new(left: T, right: T, bottom: T, top: T, znear: T, zfar: T) -> Self {
162 let matrix = Matrix4::<T>::identity();
163 let mut res = Self::from_matrix_unchecked(matrix);
164
165 res.set_left_and_right(left, right);
166 res.set_bottom_and_top(bottom, top);
167 res.set_znear_and_zfar(znear, zfar);
168
169 res
170 }
171
172 /// Creates a new orthographic projection matrix from an aspect ratio and the vertical field of view.
173 #[inline]
174 pub fn from_fov(aspect: T, vfov: T, znear: T, zfar: T) -> Self {
175 assert!(
176 znear != zfar,
177 "The far plane must not be equal to the near plane."
178 );
179 assert!(
180 !relative_eq!(aspect, T::zero()),
181 "The aspect ratio must not be zero."
182 );
183
184 let half: T = crate::convert(0.5);
185 let width = zfar.clone() * (vfov * half.clone()).tan();
186 let height = width.clone() / aspect;
187
188 Self::new(
189 -width.clone() * half.clone(),
190 width * half.clone(),
191 -height.clone() * half.clone(),
192 height * half,
193 znear,
194 zfar,
195 )
196 }
197
198 /// Retrieves the inverse of the underlying homogeneous matrix.
199 ///
200 /// # Example
201 /// ```
202 /// # #[macro_use] extern crate approx;
203 /// # use nalgebra::{Orthographic3, Point3, Matrix4};
204 /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
205 /// let inv = proj.inverse();
206 ///
207 /// assert_relative_eq!(inv * proj.as_matrix(), Matrix4::identity());
208 /// assert_relative_eq!(proj.as_matrix() * inv, Matrix4::identity());
209 ///
210 /// let proj = Orthographic3::new(10.0, 1.0, 20.0, 2.0, 1000.0, 0.1);
211 /// let inv = proj.inverse();
212 /// assert_relative_eq!(inv * proj.as_matrix(), Matrix4::identity());
213 /// assert_relative_eq!(proj.as_matrix() * inv, Matrix4::identity());
214 /// ```
215 #[inline]
216 #[must_use]
217 pub fn inverse(&self) -> Matrix4<T> {
218 let mut res = self.clone().to_homogeneous();
219
220 let inv_m11 = T::one() / self.matrix[(0, 0)].clone();
221 let inv_m22 = T::one() / self.matrix[(1, 1)].clone();
222 let inv_m33 = T::one() / self.matrix[(2, 2)].clone();
223
224 res[(0, 0)] = inv_m11.clone();
225 res[(1, 1)] = inv_m22.clone();
226 res[(2, 2)] = inv_m33.clone();
227
228 res[(0, 3)] = -self.matrix[(0, 3)].clone() * inv_m11;
229 res[(1, 3)] = -self.matrix[(1, 3)].clone() * inv_m22;
230 res[(2, 3)] = -self.matrix[(2, 3)].clone() * inv_m33;
231
232 res
233 }
234
235 /// Computes the corresponding homogeneous matrix.
236 ///
237 /// # Example
238 /// ```
239 /// # use nalgebra::{Orthographic3, Point3, Matrix4};
240 /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
241 /// let expected = Matrix4::new(
242 /// 2.0 / 9.0, 0.0, 0.0, -11.0 / 9.0,
243 /// 0.0, 2.0 / 18.0, 0.0, -22.0 / 18.0,
244 /// 0.0, 0.0, -2.0 / 999.9, -1000.1 / 999.9,
245 /// 0.0, 0.0, 0.0, 1.0
246 /// );
247 /// assert_eq!(proj.to_homogeneous(), expected);
248 /// ```
249 #[inline]
250 #[must_use]
251 pub fn to_homogeneous(self) -> Matrix4<T> {
252 self.matrix
253 }
254
255 /// A reference to the underlying homogeneous transformation matrix.
256 ///
257 /// # Example
258 /// ```
259 /// # use nalgebra::{Orthographic3, Point3, Matrix4};
260 /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
261 /// let expected = Matrix4::new(
262 /// 2.0 / 9.0, 0.0, 0.0, -11.0 / 9.0,
263 /// 0.0, 2.0 / 18.0, 0.0, -22.0 / 18.0,
264 /// 0.0, 0.0, -2.0 / 999.9, -1000.1 / 999.9,
265 /// 0.0, 0.0, 0.0, 1.0
266 /// );
267 /// assert_eq!(*proj.as_matrix(), expected);
268 /// ```
269 #[inline]
270 #[must_use]
271 pub fn as_matrix(&self) -> &Matrix4<T> {
272 &self.matrix
273 }
274
275 /// A reference to this transformation seen as a `Projective3`.
276 ///
277 /// # Example
278 /// ```
279 /// # use nalgebra::Orthographic3;
280 /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
281 /// assert_eq!(proj.as_projective().to_homogeneous(), proj.to_homogeneous());
282 /// ```
283 #[inline]
284 #[must_use]
285 pub fn as_projective(&self) -> &Projective3<T> {
286 unsafe { &*(self as *const Orthographic3<T> as *const Projective3<T>) }
287 }
288
289 /// This transformation seen as a `Projective3`.
290 ///
291 /// # Example
292 /// ```
293 /// # use nalgebra::Orthographic3;
294 /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
295 /// assert_eq!(proj.to_projective().to_homogeneous(), proj.to_homogeneous());
296 /// ```
297 #[inline]
298 #[must_use]
299 pub fn to_projective(self) -> Projective3<T> {
300 Projective3::from_matrix_unchecked(self.matrix)
301 }
302
303 /// Retrieves the underlying homogeneous matrix.
304 ///
305 /// # Example
306 /// ```
307 /// # #[macro_use] extern crate approx;
308 /// # use nalgebra::{Orthographic3, Point3, Matrix4};
309 /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
310 /// let expected = Matrix4::new(
311 /// 2.0 / 9.0, 0.0, 0.0, -11.0 / 9.0,
312 /// 0.0, 2.0 / 18.0, 0.0, -22.0 / 18.0,
313 /// 0.0, 0.0, -2.0 / 999.9, -1000.1 / 999.9,
314 /// 0.0, 0.0, 0.0, 1.0
315 /// );
316 /// assert_eq!(proj.into_inner(), expected);
317 /// ```
318 #[inline]
319 pub fn into_inner(self) -> Matrix4<T> {
320 self.matrix
321 }
322
323 /// Retrieves the underlying homogeneous matrix.
324 /// Deprecated: Use [`Orthographic3::into_inner`] instead.
325 #[deprecated(note = "use `.into_inner()` instead")]
326 #[inline]
327 pub fn unwrap(self) -> Matrix4<T> {
328 self.matrix
329 }
330
331 /// The left offset of the view cuboid.
332 ///
333 /// # Example
334 /// ```
335 /// # #[macro_use] extern crate approx;
336 /// # use nalgebra::Orthographic3;
337 /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
338 /// assert_relative_eq!(proj.left(), 1.0, epsilon = 1.0e-6);
339 ///
340 /// let proj = Orthographic3::new(10.0, 1.0, 20.0, 2.0, 1000.0, 0.1);
341 /// assert_relative_eq!(proj.left(), 10.0, epsilon = 1.0e-6);
342 /// ```
343 #[inline]
344 #[must_use]
345 pub fn left(&self) -> T {
346 (-T::one() - self.matrix[(0, 3)].clone()) / self.matrix[(0, 0)].clone()
347 }
348
349 /// The right offset of the view cuboid.
350 ///
351 /// # Example
352 /// ```
353 /// # #[macro_use] extern crate approx;
354 /// # use nalgebra::Orthographic3;
355 /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
356 /// assert_relative_eq!(proj.right(), 10.0, epsilon = 1.0e-6);
357 ///
358 /// let proj = Orthographic3::new(10.0, 1.0, 20.0, 2.0, 1000.0, 0.1);
359 /// assert_relative_eq!(proj.right(), 1.0, epsilon = 1.0e-6);
360 /// ```
361 #[inline]
362 #[must_use]
363 pub fn right(&self) -> T {
364 (T::one() - self.matrix[(0, 3)].clone()) / self.matrix[(0, 0)].clone()
365 }
366
367 /// The bottom offset of the view cuboid.
368 ///
369 /// # Example
370 /// ```
371 /// # #[macro_use] extern crate approx;
372 /// # use nalgebra::Orthographic3;
373 /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
374 /// assert_relative_eq!(proj.bottom(), 2.0, epsilon = 1.0e-6);
375 ///
376 /// let proj = Orthographic3::new(10.0, 1.0, 20.0, 2.0, 1000.0, 0.1);
377 /// assert_relative_eq!(proj.bottom(), 20.0, epsilon = 1.0e-6);
378 /// ```
379 #[inline]
380 #[must_use]
381 pub fn bottom(&self) -> T {
382 (-T::one() - self.matrix[(1, 3)].clone()) / self.matrix[(1, 1)].clone()
383 }
384
385 /// The top offset of the view cuboid.
386 ///
387 /// # Example
388 /// ```
389 /// # #[macro_use] extern crate approx;
390 /// # use nalgebra::Orthographic3;
391 /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
392 /// assert_relative_eq!(proj.top(), 20.0, epsilon = 1.0e-6);
393 ///
394 /// let proj = Orthographic3::new(10.0, 1.0, 20.0, 2.0, 1000.0, 0.1);
395 /// assert_relative_eq!(proj.top(), 2.0, epsilon = 1.0e-6);
396 /// ```
397 #[inline]
398 #[must_use]
399 pub fn top(&self) -> T {
400 (T::one() - self.matrix[(1, 3)].clone()) / self.matrix[(1, 1)].clone()
401 }
402
403 /// The near plane offset of the view cuboid.
404 ///
405 /// # Example
406 /// ```
407 /// # #[macro_use] extern crate approx;
408 /// # use nalgebra::Orthographic3;
409 /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
410 /// assert_relative_eq!(proj.znear(), 0.1, epsilon = 1.0e-6);
411 ///
412 /// let proj = Orthographic3::new(10.0, 1.0, 20.0, 2.0, 1000.0, 0.1);
413 /// assert_relative_eq!(proj.znear(), 1000.0, epsilon = 1.0e-6);
414 /// ```
415 #[inline]
416 #[must_use]
417 pub fn znear(&self) -> T {
418 (T::one() + self.matrix[(2, 3)].clone()) / self.matrix[(2, 2)].clone()
419 }
420
421 /// The far plane offset of the view cuboid.
422 ///
423 /// # Example
424 /// ```
425 /// # #[macro_use] extern crate approx;
426 /// # use nalgebra::Orthographic3;
427 /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
428 /// assert_relative_eq!(proj.zfar(), 1000.0, epsilon = 1.0e-6);
429 ///
430 /// let proj = Orthographic3::new(10.0, 1.0, 20.0, 2.0, 1000.0, 0.1);
431 /// assert_relative_eq!(proj.zfar(), 0.1, epsilon = 1.0e-6);
432 /// ```
433 #[inline]
434 #[must_use]
435 pub fn zfar(&self) -> T {
436 (-T::one() + self.matrix[(2, 3)].clone()) / self.matrix[(2, 2)].clone()
437 }
438
439 // TODO: when we get specialization, specialize the Mul impl instead.
440 /// Projects a point. Faster than matrix multiplication.
441 ///
442 /// # Example
443 /// ```
444 /// # #[macro_use] extern crate approx;
445 /// # use nalgebra::{Orthographic3, Point3};
446 /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
447 ///
448 /// let p1 = Point3::new(1.0, 2.0, -0.1);
449 /// let p2 = Point3::new(1.0, 2.0, -1000.0);
450 /// let p3 = Point3::new(1.0, 20.0, -0.1);
451 /// let p4 = Point3::new(1.0, 20.0, -1000.0);
452 /// let p5 = Point3::new(10.0, 2.0, -0.1);
453 /// let p6 = Point3::new(10.0, 2.0, -1000.0);
454 /// let p7 = Point3::new(10.0, 20.0, -0.1);
455 /// let p8 = Point3::new(10.0, 20.0, -1000.0);
456 ///
457 /// assert_relative_eq!(proj.project_point(&p1), Point3::new(-1.0, -1.0, -1.0));
458 /// assert_relative_eq!(proj.project_point(&p2), Point3::new(-1.0, -1.0, 1.0));
459 /// assert_relative_eq!(proj.project_point(&p3), Point3::new(-1.0, 1.0, -1.0));
460 /// assert_relative_eq!(proj.project_point(&p4), Point3::new(-1.0, 1.0, 1.0));
461 /// assert_relative_eq!(proj.project_point(&p5), Point3::new( 1.0, -1.0, -1.0));
462 /// assert_relative_eq!(proj.project_point(&p6), Point3::new( 1.0, -1.0, 1.0));
463 /// assert_relative_eq!(proj.project_point(&p7), Point3::new( 1.0, 1.0, -1.0));
464 /// assert_relative_eq!(proj.project_point(&p8), Point3::new( 1.0, 1.0, 1.0));
465 /// ```
466 #[inline]
467 #[must_use]
468 pub fn project_point(&self, p: &Point3<T>) -> Point3<T> {
469 Point3::new(
470 self.matrix[(0, 0)].clone() * p[0].clone() + self.matrix[(0, 3)].clone(),
471 self.matrix[(1, 1)].clone() * p[1].clone() + self.matrix[(1, 3)].clone(),
472 self.matrix[(2, 2)].clone() * p[2].clone() + self.matrix[(2, 3)].clone(),
473 )
474 }
475
476 /// Un-projects a point. Faster than multiplication by the underlying matrix inverse.
477 ///
478 /// # Example
479 /// ```
480 /// # #[macro_use] extern crate approx;
481 /// # use nalgebra::{Orthographic3, Point3};
482 /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
483 ///
484 /// let p1 = Point3::new(-1.0, -1.0, -1.0);
485 /// let p2 = Point3::new(-1.0, -1.0, 1.0);
486 /// let p3 = Point3::new(-1.0, 1.0, -1.0);
487 /// let p4 = Point3::new(-1.0, 1.0, 1.0);
488 /// let p5 = Point3::new( 1.0, -1.0, -1.0);
489 /// let p6 = Point3::new( 1.0, -1.0, 1.0);
490 /// let p7 = Point3::new( 1.0, 1.0, -1.0);
491 /// let p8 = Point3::new( 1.0, 1.0, 1.0);
492 ///
493 /// assert_relative_eq!(proj.unproject_point(&p1), Point3::new(1.0, 2.0, -0.1), epsilon = 1.0e-6);
494 /// assert_relative_eq!(proj.unproject_point(&p2), Point3::new(1.0, 2.0, -1000.0), epsilon = 1.0e-6);
495 /// assert_relative_eq!(proj.unproject_point(&p3), Point3::new(1.0, 20.0, -0.1), epsilon = 1.0e-6);
496 /// assert_relative_eq!(proj.unproject_point(&p4), Point3::new(1.0, 20.0, -1000.0), epsilon = 1.0e-6);
497 /// assert_relative_eq!(proj.unproject_point(&p5), Point3::new(10.0, 2.0, -0.1), epsilon = 1.0e-6);
498 /// assert_relative_eq!(proj.unproject_point(&p6), Point3::new(10.0, 2.0, -1000.0), epsilon = 1.0e-6);
499 /// assert_relative_eq!(proj.unproject_point(&p7), Point3::new(10.0, 20.0, -0.1), epsilon = 1.0e-6);
500 /// assert_relative_eq!(proj.unproject_point(&p8), Point3::new(10.0, 20.0, -1000.0), epsilon = 1.0e-6);
501 /// ```
502 #[inline]
503 #[must_use]
504 pub fn unproject_point(&self, p: &Point3<T>) -> Point3<T> {
505 Point3::new(
506 (p[0].clone() - self.matrix[(0, 3)].clone()) / self.matrix[(0, 0)].clone(),
507 (p[1].clone() - self.matrix[(1, 3)].clone()) / self.matrix[(1, 1)].clone(),
508 (p[2].clone() - self.matrix[(2, 3)].clone()) / self.matrix[(2, 2)].clone(),
509 )
510 }
511
512 // TODO: when we get specialization, specialize the Mul impl instead.
513 /// Projects a vector. Faster than matrix multiplication.
514 ///
515 /// Vectors are not affected by the translation part of the projection.
516 ///
517 /// # Example
518 /// ```
519 /// # #[macro_use] extern crate approx;
520 /// # use nalgebra::{Orthographic3, Vector3};
521 /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
522 ///
523 /// let v1 = Vector3::x();
524 /// let v2 = Vector3::y();
525 /// let v3 = Vector3::z();
526 ///
527 /// assert_relative_eq!(proj.project_vector(&v1), Vector3::x() * 2.0 / 9.0);
528 /// assert_relative_eq!(proj.project_vector(&v2), Vector3::y() * 2.0 / 18.0);
529 /// assert_relative_eq!(proj.project_vector(&v3), Vector3::z() * -2.0 / 999.9);
530 /// ```
531 #[inline]
532 #[must_use]
533 pub fn project_vector<SB>(&self, p: &Vector<T, U3, SB>) -> Vector3<T>
534 where
535 SB: Storage<T, U3>,
536 {
537 Vector3::new(
538 self.matrix[(0, 0)].clone() * p[0].clone(),
539 self.matrix[(1, 1)].clone() * p[1].clone(),
540 self.matrix[(2, 2)].clone() * p[2].clone(),
541 )
542 }
543
544 /// Sets the left offset of the view cuboid.
545 ///
546 /// # Example
547 /// ```
548 /// # #[macro_use] extern crate approx;
549 /// # use nalgebra::Orthographic3;
550 /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
551 /// proj.set_left(2.0);
552 /// assert_relative_eq!(proj.left(), 2.0, epsilon = 1.0e-6);
553 ///
554 /// // It is OK to set a left offset greater than the current right offset.
555 /// proj.set_left(20.0);
556 /// assert_relative_eq!(proj.left(), 20.0, epsilon = 1.0e-6);
557 /// ```
558 #[inline]
559 pub fn set_left(&mut self, left: T) {
560 let right = self.right();
561 self.set_left_and_right(left, right);
562 }
563
564 /// Sets the right offset of the view cuboid.
565 ///
566 /// # Example
567 /// ```
568 /// # #[macro_use] extern crate approx;
569 /// # use nalgebra::Orthographic3;
570 /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
571 /// proj.set_right(15.0);
572 /// assert_relative_eq!(proj.right(), 15.0, epsilon = 1.0e-6);
573 ///
574 /// // It is OK to set a right offset smaller than the current left offset.
575 /// proj.set_right(-3.0);
576 /// assert_relative_eq!(proj.right(), -3.0, epsilon = 1.0e-6);
577 /// ```
578 #[inline]
579 pub fn set_right(&mut self, right: T) {
580 let left = self.left();
581 self.set_left_and_right(left, right);
582 }
583
584 /// Sets the bottom offset of the view cuboid.
585 ///
586 /// # Example
587 /// ```
588 /// # #[macro_use] extern crate approx;
589 /// # use nalgebra::Orthographic3;
590 /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
591 /// proj.set_bottom(8.0);
592 /// assert_relative_eq!(proj.bottom(), 8.0, epsilon = 1.0e-6);
593 ///
594 /// // It is OK to set a bottom offset greater than the current top offset.
595 /// proj.set_bottom(50.0);
596 /// assert_relative_eq!(proj.bottom(), 50.0, epsilon = 1.0e-6);
597 /// ```
598 #[inline]
599 pub fn set_bottom(&mut self, bottom: T) {
600 let top = self.top();
601 self.set_bottom_and_top(bottom, top);
602 }
603
604 /// Sets the top offset of the view cuboid.
605 ///
606 /// # Example
607 /// ```
608 /// # #[macro_use] extern crate approx;
609 /// # use nalgebra::Orthographic3;
610 /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
611 /// proj.set_top(15.0);
612 /// assert_relative_eq!(proj.top(), 15.0, epsilon = 1.0e-6);
613 ///
614 /// // It is OK to set a top offset smaller than the current bottom offset.
615 /// proj.set_top(-3.0);
616 /// assert_relative_eq!(proj.top(), -3.0, epsilon = 1.0e-6);
617 /// ```
618 #[inline]
619 pub fn set_top(&mut self, top: T) {
620 let bottom = self.bottom();
621 self.set_bottom_and_top(bottom, top);
622 }
623
624 /// Sets the near plane offset of the view cuboid.
625 ///
626 /// # Example
627 /// ```
628 /// # #[macro_use] extern crate approx;
629 /// # use nalgebra::Orthographic3;
630 /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
631 /// proj.set_znear(8.0);
632 /// assert_relative_eq!(proj.znear(), 8.0, epsilon = 1.0e-6);
633 ///
634 /// // It is OK to set a znear greater than the current zfar.
635 /// proj.set_znear(5000.0);
636 /// assert_relative_eq!(proj.znear(), 5000.0, epsilon = 1.0e-6);
637 /// ```
638 #[inline]
639 pub fn set_znear(&mut self, znear: T) {
640 let zfar = self.zfar();
641 self.set_znear_and_zfar(znear, zfar);
642 }
643
644 /// Sets the far plane offset of the view cuboid.
645 ///
646 /// # Example
647 /// ```
648 /// # #[macro_use] extern crate approx;
649 /// # use nalgebra::Orthographic3;
650 /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
651 /// proj.set_zfar(15.0);
652 /// assert_relative_eq!(proj.zfar(), 15.0, epsilon = 1.0e-6);
653 ///
654 /// // It is OK to set a zfar smaller than the current znear.
655 /// proj.set_zfar(-3.0);
656 /// assert_relative_eq!(proj.zfar(), -3.0, epsilon = 1.0e-6);
657 /// ```
658 #[inline]
659 pub fn set_zfar(&mut self, zfar: T) {
660 let znear = self.znear();
661 self.set_znear_and_zfar(znear, zfar);
662 }
663
664 /// Sets the view cuboid offsets along the `x` axis.
665 ///
666 /// # Example
667 /// ```
668 /// # #[macro_use] extern crate approx;
669 /// # use nalgebra::Orthographic3;
670 /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
671 /// proj.set_left_and_right(7.0, 70.0);
672 /// assert_relative_eq!(proj.left(), 7.0, epsilon = 1.0e-6);
673 /// assert_relative_eq!(proj.right(), 70.0, epsilon = 1.0e-6);
674 ///
675 /// // It is also OK to have `left > right`.
676 /// proj.set_left_and_right(70.0, 7.0);
677 /// assert_relative_eq!(proj.left(), 70.0, epsilon = 1.0e-6);
678 /// assert_relative_eq!(proj.right(), 7.0, epsilon = 1.0e-6);
679 /// ```
680 #[inline]
681 pub fn set_left_and_right(&mut self, left: T, right: T) {
682 assert!(
683 left != right,
684 "The left corner must not be equal to the right corner."
685 );
686 self.matrix[(0, 0)] = crate::convert::<_, T>(2.0) / (right.clone() - left.clone());
687 self.matrix[(0, 3)] = -(right.clone() + left.clone()) / (right - left);
688 }
689
690 /// Sets the view cuboid offsets along the `y` axis.
691 ///
692 /// # Example
693 /// ```
694 /// # #[macro_use] extern crate approx;
695 /// # use nalgebra::Orthographic3;
696 /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
697 /// proj.set_bottom_and_top(7.0, 70.0);
698 /// assert_relative_eq!(proj.bottom(), 7.0, epsilon = 1.0e-6);
699 /// assert_relative_eq!(proj.top(), 70.0, epsilon = 1.0e-6);
700 ///
701 /// // It is also OK to have `bottom > top`.
702 /// proj.set_bottom_and_top(70.0, 7.0);
703 /// assert_relative_eq!(proj.bottom(), 70.0, epsilon = 1.0e-6);
704 /// assert_relative_eq!(proj.top(), 7.0, epsilon = 1.0e-6);
705 /// ```
706 #[inline]
707 pub fn set_bottom_and_top(&mut self, bottom: T, top: T) {
708 assert_ne!(
709 bottom, top,
710 "The top corner must not be equal to the bottom corner."
711 );
712 self.matrix[(1, 1)] = crate::convert::<_, T>(2.0) / (top.clone() - bottom.clone());
713 self.matrix[(1, 3)] = -(top.clone() + bottom.clone()) / (top - bottom);
714 }
715
716 /// Sets the near and far plane offsets of the view cuboid.
717 ///
718 /// # Example
719 /// ```
720 /// # #[macro_use] extern crate approx;
721 /// # use nalgebra::Orthographic3;
722 /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
723 /// proj.set_znear_and_zfar(50.0, 5000.0);
724 /// assert_relative_eq!(proj.znear(), 50.0, epsilon = 1.0e-6);
725 /// assert_relative_eq!(proj.zfar(), 5000.0, epsilon = 1.0e-6);
726 ///
727 /// // It is also OK to have `znear > zfar`.
728 /// proj.set_znear_and_zfar(5000.0, 0.5);
729 /// assert_relative_eq!(proj.znear(), 5000.0, epsilon = 1.0e-6);
730 /// assert_relative_eq!(proj.zfar(), 0.5, epsilon = 1.0e-6);
731 /// ```
732 #[inline]
733 pub fn set_znear_and_zfar(&mut self, znear: T, zfar: T) {
734 assert!(
735 zfar != znear,
736 "The near-plane and far-plane must not be superimposed."
737 );
738 self.matrix[(2, 2)] = -crate::convert::<_, T>(2.0) / (zfar.clone() - znear.clone());
739 self.matrix[(2, 3)] = -(zfar.clone() + znear.clone()) / (zfar - znear);
740 }
741}
742
743#[cfg(feature = "rand-no-std")]
744impl<T: RealField> Distribution<Orthographic3<T>> for Standard
745where
746 Standard: Distribution<T>,
747{
748 /// Generate an arbitrary random variate for testing purposes.
749 fn sample<R: Rng + ?Sized>(&self, r: &mut R) -> Orthographic3<T> {
750 use crate::base::helper;
751 let left = r.gen();
752 let right = helper::reject_rand(r, |x: &T| *x > left);
753 let bottom = r.gen();
754 let top = helper::reject_rand(r, |x: &T| *x > bottom);
755 let znear = r.gen();
756 let zfar = helper::reject_rand(r, |x: &T| *x > znear);
757
758 Orthographic3::new(left, right, bottom, top, znear, zfar)
759 }
760}
761
762#[cfg(feature = "arbitrary")]
763impl<T: RealField + Arbitrary> Arbitrary for Orthographic3<T>
764where
765 Matrix4<T>: Send,
766{
767 fn arbitrary(g: &mut Gen) -> Self {
768 use crate::base::helper;
769 let left = Arbitrary::arbitrary(g);
770 let right = helper::reject(g, |x: &T| *x > left);
771 let bottom = Arbitrary::arbitrary(g);
772 let top = helper::reject(g, |x: &T| *x > bottom);
773 let znear = Arbitrary::arbitrary(g);
774 let zfar = helper::reject(g, |x: &T| *x > znear);
775
776 Self::new(left, right, bottom, top, znear, zfar)
777 }
778}
779
780impl<T: RealField> From<Orthographic3<T>> for Matrix4<T> {
781 #[inline]
782 fn from(orth: Orthographic3<T>) -> Self {
783 orth.into_inner()
784 }
785}