nalgebra/geometry/
orthographic.rs

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