trackball/
delta.rs

1use crate::Frame;
2use nalgebra::{Point3, RealField, Unit, UnitQuaternion, Vector3};
3use simba::scalar::SubsetOf;
4
5/// Delta transform from initial to final [`Frame`].
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8pub enum Delta<N: Copy + RealField> {
9	/// Yields frame as identity transform (default).
10	#[default]
11	Frame,
12	/// Orbits target around eye by pitch and yaw preserving roll attitude aka first person view.
13	///
14	/// See [`Frame::look_around()`].
15	First {
16		/// Pitch angle.
17		pitch: N,
18		/// Yaw angle.
19		yaw: N,
20		/// Yaw axis.
21		yaw_axis: Unit<Vector3<N>>,
22	},
23	/// Tracks target which slides by vector in world space.
24	///
25	/// Preserves eye position inclusive its roll attitude.
26	Track {
27		/// Vector in world space of a sliding target to track.
28		vec: Vector3<N>,
29	},
30	/// Orbits eye by rotation in camera space around point in camera space.
31	///
32	/// See [`Frame::local_orbit_around()`].
33	Orbit {
34		/// Rotation in camera space.
35		rot: UnitQuaternion<N>,
36		/// Point in camera space.
37		pos: Point3<N>,
38	},
39	/// Slides camera eye and target by vector in camera space.
40	///
41	/// See [`Frame::local_slide()`].
42	Slide {
43		/// Vector in camera space.
44		vec: Vector3<N>,
45	},
46	/// Scales distance between eye and point in camera space by ratio preserving target position.
47	///
48	/// See [`Frame::local_scale_around()`].
49	Scale {
50		/// Scale ratio.
51		rat: N,
52		/// Point in camera space.
53		pos: Point3<N>,
54	},
55}
56
57impl<N: Copy + RealField> Delta<N> {
58	/// Transforms from initial to final frame.
59	#[must_use]
60	pub fn transform(&self, frame: &Frame<N>) -> Frame<N> {
61		let mut frame = *frame;
62		match self {
63			Self::Frame => {}
64			Self::First {
65				pitch,
66				yaw,
67				yaw_axis,
68			} => frame.look_around(*pitch, *yaw, yaw_axis),
69			Self::Track { vec } => frame.set_target(frame.target() + vec),
70			Self::Orbit { rot, pos } => frame.local_orbit_around(rot, pos),
71			Self::Slide { vec } => frame.local_slide(vec),
72			Self::Scale { rat, pos } => frame.local_scale_around(*rat, pos),
73		}
74		frame
75	}
76	/// Inverses delta transform.
77	///
78	/// Effectively swaps initial with final frame.
79	#[must_use]
80	pub fn inverse(self) -> Self {
81		match self {
82			Self::Frame => Self::Frame,
83			Self::First {
84				pitch,
85				yaw,
86				yaw_axis,
87			} => Self::First {
88				pitch: -pitch,
89				yaw: -yaw,
90				yaw_axis,
91			},
92			Self::Track { vec } => Self::Track { vec: -vec },
93			Self::Orbit { rot, pos } => Self::Orbit {
94				rot: rot.inverse(),
95				pos,
96			},
97			Self::Slide { vec } => Self::Slide { vec: -vec },
98			Self::Scale { rat, pos } => Self::Scale {
99				rat: N::one() + N::one() - rat,
100				pos,
101			},
102		}
103	}
104	/// Interpolates delta transform to a fraction using linear interpolation for the translation
105	/// part, and spherical linear interpolation for the rotation part.
106	///
107	/// # Arguments
108	///
109	///   * `self`: The delta transform to interpolate from.
110	///   * `t`: The interpolation parameter between 0 and 1.
111	#[must_use]
112	pub fn lerp_slerp(&self, t: N) -> Self {
113		match *self {
114			Self::Frame => Self::Frame,
115			Self::First {
116				pitch,
117				yaw,
118				yaw_axis,
119			} => Self::First {
120				pitch: pitch * t,
121				yaw: yaw * t,
122				yaw_axis,
123			},
124			Self::Track { vec } => Self::Track { vec: vec * t },
125			Self::Orbit { rot, pos } => Self::Orbit {
126				rot: rot.powf(t),
127				pos,
128			},
129			Self::Slide { vec } => Self::Slide { vec: vec * t },
130			Self::Scale { rat, pos } => Self::Scale {
131				rat: (rat - N::one()) * t + N::one(),
132				pos,
133			},
134		}
135	}
136	/// Casts components to another type, e.g., between [`f32`] and [`f64`].
137	#[must_use]
138	pub fn cast<M: Copy + RealField>(self) -> Delta<M>
139	where
140		N: SubsetOf<M>,
141	{
142		match self {
143			Self::Frame => Delta::Frame,
144			Self::First {
145				pitch,
146				yaw,
147				yaw_axis,
148			} => Delta::First {
149				pitch: pitch.to_superset(),
150				yaw: yaw.to_superset(),
151				yaw_axis: yaw_axis.cast(),
152			},
153			Self::Track { vec } => Delta::Track { vec: vec.cast() },
154			Self::Orbit { rot, pos } => Delta::Orbit {
155				rot: rot.cast(),
156				pos: pos.cast(),
157			},
158			Self::Slide { vec } => Delta::Slide { vec: vec.cast() },
159			Self::Scale { rat, pos } => Delta::Scale {
160				rat: rat.to_superset(),
161				pos: pos.cast(),
162			},
163		}
164	}
165}
166
167#[cfg(feature = "rkyv")]
168impl<N: Copy + RealField> rkyv::Archive for Delta<N> {
169	type Archived = Self;
170	type Resolver = ();
171
172	#[inline]
173	#[allow(unsafe_code)]
174	unsafe fn resolve(&self, _: usize, (): Self::Resolver, out: *mut Self::Archived) {
175		unsafe {
176			out.write(rkyv::to_archived!(*self as Self));
177		}
178	}
179}
180
181#[cfg(feature = "rkyv")]
182impl<Ser: rkyv::Fallible + ?Sized, N: Copy + RealField> rkyv::Serialize<Ser> for Delta<N> {
183	#[inline]
184	fn serialize(&self, _: &mut Ser) -> Result<Self::Resolver, Ser::Error> {
185		Ok(())
186	}
187}
188
189#[cfg(feature = "rkyv")]
190impl<De: rkyv::Fallible + ?Sized, N: Copy + RealField> rkyv::Deserialize<Self, De> for Delta<N> {
191	#[inline]
192	fn deserialize(&self, _: &mut De) -> Result<Self, De::Error> {
193		Ok(rkyv::from_archived!(*self))
194	}
195}