use crate::{Clamp, Frame, Plane};
use core::fmt::Debug;
use nalgebra::{Isometry3, Point3, RealField, UnitQuaternion, Vector3};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Bound<N: Copy + RealField> {
pub transform: Isometry3<N>,
pub min_target: Point3<N>,
pub max_target: Point3<N>,
pub min_eye: Point3<N>,
pub max_eye: Point3<N>,
pub min_up: Point3<N>,
pub max_up: Point3<N>,
pub min_distance: N,
pub max_distance: N,
pub hysteresis: N,
}
impl<N: Copy + RealField> Default for Bound<N> {
fn default() -> Self {
let min = N::min_value().unwrap();
let max = N::max_value().unwrap();
Self {
transform: Isometry3::default(),
hysteresis: N::default_epsilon().sqrt(),
min_target: Point3::new(min, min, min),
max_target: Point3::new(max, max, max),
min_eye: Point3::new(min, min, min),
max_eye: Point3::new(max, max, max),
min_up: Point3::new(min, min, min),
max_up: Point3::new(max, max, max),
min_distance: N::zero(),
max_distance: max,
}
}
}
impl<N: Copy + RealField> Clamp<N> for Bound<N> {
fn loops(&self) -> usize {
10
}
fn target(&self, frame: &Frame<N>) -> Option<Plane<N>> {
let target = self.transform.inverse() * frame.target();
let axes = [Vector3::x_axis(), Vector3::y_axis(), Vector3::z_axis()];
for (distance, axis) in axes.into_iter().enumerate() {
let min_plane = Plane::new(axis, self.min_target[distance]);
if min_plane.distance_from(&target) > self.hysteresis {
return Some(min_plane);
}
let max_plane = Plane::new(axis, self.max_target[distance]);
if max_plane.distance_from(&target) < -self.hysteresis {
return Some(max_plane);
}
}
None
}
fn eye(&self, frame: &Frame<N>) -> Option<Plane<N>> {
let distance = frame.distance();
if (self.min_distance - distance) > self.hysteresis {
return Some(Plane::new(frame.roll_axis(), self.min_distance));
}
if (self.max_distance - distance) < -self.hysteresis {
return Some(Plane::new(frame.roll_axis(), self.max_distance));
}
let eye = self.transform.inverse() * frame.eye();
let axes = [Vector3::x_axis(), Vector3::y_axis(), Vector3::z_axis()];
for (distance, axis) in axes.into_iter().enumerate() {
let min_plane = Plane::new(axis, self.min_eye[distance]);
if min_plane.distance_from(&eye) > self.hysteresis {
return Some(min_plane);
}
let max_plane = Plane::new(axis, self.max_eye[distance]);
if max_plane.distance_from(&eye) < -self.hysteresis {
return Some(max_plane);
}
}
None
}
fn up(&self, frame: &Frame<N>) -> Option<Plane<N>> {
let roll_axis = frame.roll_axis();
let yaw = UnitQuaternion::from_axis_angle(
&frame.local_yaw_axis(),
roll_axis.x.atan2(roll_axis.z),
);
let up = yaw * frame.yaw_axis();
let axes = [Vector3::x_axis(), Vector3::y_axis(), Vector3::z_axis()];
for (distance, axis) in axes.into_iter().enumerate() {
let min_plane = Plane::new(yaw.inverse() * axis, self.min_up[distance]);
if min_plane.distance_from(&Point3::from(up.into_inner())) > self.hysteresis {
return Some(min_plane);
}
let max_plane = Plane::new(yaw.inverse() * axis, self.max_up[distance]);
if max_plane.distance_from(&Point3::from(up.into_inner())) < -self.hysteresis {
return Some(max_plane);
}
}
None
}
}
#[cfg(feature = "rkyv")]
impl<N: Copy + RealField> rkyv::Archive for Bound<N> {
type Archived = Self;
type Resolver = ();
#[inline]
#[allow(unsafe_code)]
unsafe fn resolve(&self, _: usize, (): Self::Resolver, out: *mut Self::Archived) {
out.write(rkyv::to_archived!(*self as Self));
}
}
#[cfg(feature = "rkyv")]
impl<Ser: rkyv::Fallible + ?Sized, N: Copy + RealField> rkyv::Serialize<Ser> for Bound<N> {
#[inline]
fn serialize(&self, _: &mut Ser) -> Result<Self::Resolver, Ser::Error> {
Ok(())
}
}
#[cfg(feature = "rkyv")]
impl<De: rkyv::Fallible + ?Sized, N: Copy + RealField> rkyv::Deserialize<Self, De> for Bound<N> {
#[inline]
fn deserialize(&self, _: &mut De) -> Result<Self, De::Error> {
Ok(rkyv::from_archived!(*self))
}
}