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}