use {
nalgebra::{
Scalar, ClosedAddAssign, ClosedSubAssign, ClosedMulAssign, ClosedDivAssign,
Rotation as NaRotation,
},
num_traits::{Float, Signed, Zero},
crate::sdf::{
Lipschitz, Union, Subtraction, Intersection, SmoothMin,
Shell, Offset, Extrude, Revolve
}
};
pub type Point<T, const D: usize> = nalgebra::Point<T, D>;
pub type Vector<T, const D: usize> = nalgebra::SVector<T, D>;
pub type P2<T> = Point<T, 2>;
pub type V2<T> = Vector<T, 2>;
pub trait Real:
Float + Signed + Scalar
+ ClosedAddAssign + ClosedSubAssign + ClosedMulAssign + ClosedDivAssign {}
impl<T> Real for T where T:
Float + Signed + Scalar
+ ClosedAddAssign + ClosedSubAssign + ClosedMulAssign + ClosedDivAssign {}
pub trait VectorExt<T> {
fn length(&self) -> T;
fn robust_normalize(&self) -> Self;
}
impl<T: Real, const D: usize> VectorExt<T> for Vector<T, D> {
#[inline]
fn length(&self) -> T {
self.iter().fold(T::zero(), |acc, &x| acc + x * x).sqrt()
}
#[inline]
fn robust_normalize(&self) -> Self {
let len = self.length();
if len > T::zero() { self / len } else { Self::zeros() }
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Aabb<T: Scalar, const D: usize> {
pub min: Point<T, D>,
pub max: Point<T, D>,
}
impl<T: Scalar, const D: usize> Aabb<T, D> {
#[inline]
pub fn new(min: Point<T, D>, max: Point<T, D>) -> Self {
Self { min, max }
}
}
impl<T: Scalar + ClosedSubAssign, const D: usize> Aabb<T, D> {
#[inline]
pub fn size(&self) -> Vector<T, D> {
&self.max - &self.min
}
}
impl<T: Real, const D: usize> Aabb<T, D> {
#[inline]
pub fn unit() -> Self {
Self {
min: Point::from(Vector::repeat(T::zero())),
max: Point::from(Vector::repeat(T::one())),
}
}
#[inline]
pub fn symmetric(half: T) -> Self {
Self {
min: Point::from(Vector::repeat(-half)),
max: Point::from(Vector::repeat(half)),
}
}
pub fn from_points(points: impl IntoIterator<Item = Point<T, D>>) -> Self {
let mut iter = points.into_iter();
let first = match iter.next() {
Some(p) => p,
None => Point::from(Vector::repeat(T::zero())),
};
let init = Self { min: first, max: first };
iter.fold(init, |acc, p| Self {
min: acc.min.coords.zip_map(&p.coords, |a, b| a.min(b)).into(),
max: acc.max.coords.zip_map(&p.coords, |a, b| a.max(b)).into(),
})
}
#[inline]
pub fn center(&self) -> Point<T, D> {
let two = T::one() + T::one();
self.min + (self.max - self.min) / two
}
#[inline]
pub fn contains(&self, pt: &Point<T, D>) -> bool {
(0..D).all(|a| self.min[a] <= pt[a] && pt[a] < self.max[a])
}
#[inline]
pub fn intersects(&self, other: &Self) -> bool {
(0..D).all(|a| self.min[a] < other.max[a] && other.min[a] < self.max[a])
}
#[inline]
pub fn clamp_point(&self, pt: &Point<T, D>) -> Point<T, D> {
Point::from(std::array::from_fn(|a| pt[a].max(self.min[a]).min(self.max[a])))
}
pub fn merge(&self, other: &Self) -> Self {
Self {
min: self.min.coords.zip_map(&other.min.coords, |a, b| a.min(b)).into(),
max: self.max.coords.zip_map(&other.max.coords, |a, b| a.max(b)).into(),
}
}
pub fn clip(&self, other: &Self) -> Option<Self> {
let ret = Self {
min: self.min.coords.zip_map(&other.min.coords, |a, b| a.max(b)).into(),
max: self.max.coords.zip_map(&other.max.coords, |a, b| a.min(b)).into(),
};
(0..D).all(|a| ret.min[a] < ret.max[a]).then_some(ret)
}
#[inline]
pub fn shift(&self, offset: Vector<T, D>) -> Self {
Self { min: self.min + offset, max: self.max + offset }
}
#[inline]
pub fn inflate(&self, amount: T) -> Self {
let v = Vector::repeat(amount);
Self { min: self.min - v, max: self.max + v }
}
}
pub trait BoundingBox<T: Scalar, const D: usize> {
fn bounding_box(&self) -> Aabb<T, D>;
}
pub trait Combinator: Sized {
fn translate<T: Scalar, const D: usize>(self, offset: Vector<T, D>)
-> Translation<Self, T, D> {
Translation { shape: self, offset }
}
fn rotate<T: Scalar, const D: usize>(self, rotation: NaRotation<T, D>)
-> Rotation<Self, T, D> {
Rotation { shape: self, rotation }
}
fn scale<T>(self, scale: T) -> Scale<Self, T> {
Scale { shape: self, scale }
}
fn union<U>(self, other: U) -> Union<Self, U> {
Union { s1: self, s2: other }
}
fn subtraction<U>(self, other: U) -> Subtraction<Self, U> {
Subtraction { s1: self, s2: other }
}
fn intersection<U>(self, other: U) -> Intersection<Self, U> {
Intersection { s1: self, s2: other }
}
fn smooth_min<T, U>(self, other: U, k: T) -> SmoothMin<T, Self, U> {
SmoothMin { s1: self, s2: other, k }
}
fn shell<T>(self, half_width: T) -> Shell<Self, T> {
Shell { shape: self, half_width }
}
fn offset<T>(self, radius: T) -> Offset<Self, T> {
Offset { shape: self, radius }
}
fn extrude<T>(self, half_height: T) -> Extrude<Self, T> {
Extrude { shape: self, half_height }
}
fn revolve<T>(self, radius: T) -> Revolve<Self, T> {
Revolve { shape: self, radius }
}
}
impl<S> Combinator for S {}
#[derive(Debug, Copy, Clone)]
pub struct Translation<S, T: Scalar, const D: usize> {
pub shape: S,
pub offset: Vector<T, D>
}
impl <S, T, const D: usize> BoundingBox<T, D> for Translation<S, T, D>
where S: BoundingBox<T, D>,
T: Real {
fn bounding_box(&self) -> Aabb<T, D> {
self.shape.bounding_box().shift(self.offset)
}
}
impl <S, T: Scalar, const D: usize> Lipschitz<T> for Translation<S, T, D>
where S: Lipschitz<T> {
fn lipschitz(&self) -> T {
self.shape.lipschitz()
}
}
#[derive(Debug, Copy, Clone)]
pub struct Rotation<S, T: Scalar, const D: usize> {
pub shape: S,
pub rotation: NaRotation<T, D>
}
impl <S, T, const D: usize> BoundingBox<T, D> for Rotation<S, T, D>
where S: BoundingBox<T, D>,
T: Real
{
fn bounding_box(&self) -> Aabb<T, D> {
let bounding = self.shape.bounding_box();
let pivot = bounding.center();
let two = T::one() + T::one();
let half = bounding.size() / two;
let half = self.rotation.matrix().abs() * half;
Aabb { min: pivot - half, max: pivot + half }
}
}
impl <S, T: Scalar, const D: usize> Lipschitz<T> for Rotation<S, T, D>
where S: Lipschitz<T> {
fn lipschitz(&self) -> T {
self.shape.lipschitz()
}
}
#[derive(Debug, Copy, Clone)]
pub struct Scale<S, T> {
pub shape: S,
pub scale: T
}
impl <S, T, const D: usize> BoundingBox<T, D> for Scale<S, T>
where S: BoundingBox<T, D>,
T: Real
{
fn bounding_box(&self) -> Aabb<T, D> {
let bounding = self.shape.bounding_box();
let c = bounding.center();
Aabb {
min: c + (bounding.min - c) * self.scale,
max: c + (bounding.max - c) * self.scale,
}
}
}
impl <S, T> Lipschitz<T> for Scale<S, T>
where S: Lipschitz<T> {
fn lipschitz(&self) -> T {
self.shape.lipschitz()
}
}
#[derive(Copy, Clone, Debug)]
pub struct DistPoint<T, P: Scalar, const D: usize> {
pub distance: T,
pub point: Point<P, D>
}
impl<T: Float, P: Scalar + Zero, const D: usize> Default for DistPoint<T, P, D> {
fn default() -> Self {
Self {
distance: T::max_value() / (T::one() + T::one()),
point: Point::from(Vector::zeros())
}
}
}
impl<T: PartialEq, P: Scalar, const D: usize> PartialEq for DistPoint<T, P, D> {
fn eq(&self, other: &Self) -> bool {
self.distance.eq(&other.distance)
}
}
impl<T: PartialOrd, P: Scalar, const D: usize> PartialOrd for DistPoint<T, P, D> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.distance.partial_cmp(&other.distance)
}
}
impl<T: PartialEq, P: Scalar, const D: usize> Eq for DistPoint<T, P, D> {}
impl<P: Scalar, const D: usize> std::cmp::Ord for DistPoint<f32, P, D> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.distance.total_cmp(&other.distance)
}
}