trackball/
fixed.rs

1use nalgebra::{Point2, RealField};
2use simba::scalar::SubsetOf;
3
4/// Fixed quantity wrt field of view.
5///
6///   * Implements [`Default`] and can be created with `Fixed::default()` returning
7///     `Fixed::Ver(N::frac_pi_4())`.
8///   * Implements `From<N>` and can be created with `N::into()` returning `Fixed::Ver()`.
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11pub enum Fixed<N: Copy + RealField> {
12	/// Fixed horizontal field of view aka Vert- scaling.
13	Hor(N),
14	/// Fixed vertical field of view aka Hor+ scaling.
15	Ver(N),
16	/// Fixed unit per pixel on focus plane at distance from eye of one aka Pixel-based scaling.
17	Upp(N),
18}
19
20impl<N: Copy + RealField> Default for Fixed<N> {
21	fn default() -> Self {
22		N::frac_pi_4().into()
23	}
24}
25
26impl<N: Copy + RealField> From<N> for Fixed<N> {
27	fn from(fov: N) -> Self {
28		Self::Ver(fov)
29	}
30}
31
32impl<N: Copy + RealField> Fixed<N> {
33	/// Converts to fixed horizontal field of view wrt maximum position in screen space.
34	#[must_use]
35	pub fn to_hor(self, max: &Point2<N>) -> Self {
36		let two = N::one() + N::one();
37		Self::Hor(match self {
38			Self::Hor(fov) => fov,
39			Self::Ver(fov) => (max.x / max.y * (fov / two).tan()).atan() * two,
40			Self::Upp(upp) => (max.x / two * upp).atan() * two,
41		})
42	}
43	/// Converts to fixed vertical field of view wrt maximum position in screen space.
44	#[must_use]
45	pub fn to_ver(self, max: &Point2<N>) -> Self {
46		let two = N::one() + N::one();
47		Self::Ver(match self {
48			Self::Hor(fov) => (max.y / max.x * (fov / two).tan()).atan() * two,
49			Self::Ver(fov) => fov,
50			Self::Upp(upp) => (max.y / two * upp).atan() * two,
51		})
52	}
53	/// Converts to fixed unit per pixel on focus plane at distance from eye of one wrt maximum
54	/// position in screen space.
55	#[must_use]
56	pub fn to_upp(self, max: &Point2<N>) -> Self {
57		let two = N::one() + N::one();
58		Self::Upp(match self {
59			Self::Hor(fov) => (fov / two).tan() * two / max.x,
60			Self::Ver(fov) => (fov / two).tan() * two / max.y,
61			Self::Upp(upp) => upp,
62		})
63	}
64	/// Maximum position in camera space and unit per pixel on focus plane wrt distance between
65	/// eye and target and maximum position in screen space.
66	#[must_use]
67	pub fn max_and_upp(&self, zat: N, max: &Point2<N>) -> (Point2<N>, N) {
68		let two = N::one() + N::one();
69		match *self {
70			Self::Hor(fov) => {
71				let x = zat * (fov / two).tan();
72				let y = max.y / max.x * x;
73				(Point2::new(x, y), x * two / max.x)
74			}
75			Self::Ver(fov) => {
76				let y = zat * (fov / two).tan();
77				let x = max.x / max.y * y;
78				(Point2::new(x, y), y * two / max.y)
79			}
80			Self::Upp(upp) => {
81				let upp = upp * zat;
82				(max / two * upp, upp)
83			}
84		}
85	}
86	/// Underlying quantity.
87	#[must_use]
88	pub const fn into_inner(self) -> N {
89		match self {
90			Self::Hor(fov) | Self::Ver(fov) => fov,
91			Self::Upp(upp) => upp,
92		}
93	}
94	/// Casts components to another type, e.g., between [`f32`] and [`f64`].
95	#[must_use]
96	pub fn cast<M: Copy + RealField>(self) -> Fixed<M>
97	where
98		N: SubsetOf<M>,
99	{
100		match self {
101			Self::Hor(fov) => Fixed::Hor(fov.to_superset()),
102			Self::Ver(fov) => Fixed::Ver(fov.to_superset()),
103			Self::Upp(fov) => Fixed::Upp(fov.to_superset()),
104		}
105	}
106}
107
108#[cfg(feature = "rkyv")]
109impl<N: Copy + RealField> rkyv::Archive for Fixed<N> {
110	type Archived = Self;
111	type Resolver = ();
112
113	#[inline]
114	#[allow(unsafe_code)]
115	unsafe fn resolve(&self, _: usize, (): Self::Resolver, out: *mut Self::Archived) {
116		unsafe {
117			out.write(rkyv::to_archived!(*self as Self));
118		}
119	}
120}
121
122#[cfg(feature = "rkyv")]
123impl<Ser: rkyv::Fallible + ?Sized, N: Copy + RealField> rkyv::Serialize<Ser> for Fixed<N> {
124	#[inline]
125	fn serialize(&self, _: &mut Ser) -> Result<Self::Resolver, Ser::Error> {
126		Ok(())
127	}
128}
129
130#[cfg(feature = "rkyv")]
131impl<De: rkyv::Fallible + ?Sized, N: Copy + RealField> rkyv::Deserialize<Self, De> for Fixed<N> {
132	#[inline]
133	fn deserialize(&self, _: &mut De) -> Result<Self, De::Error> {
134		Ok(rkyv::from_archived!(*self))
135	}
136}