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