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