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}