pub use self::aabb2::Aabb2;
pub use self::aabb3::Aabb3;
use std::cmp::{Ordering, PartialOrd};
use cgmath::{BaseNum, Point2, Point3};
use cgmath::prelude::*;
use crate::traits::Bound;
mod aabb2;
mod aabb3;
pub(crate) fn min<S: PartialOrd + Copy>(lhs: S, rhs: S) -> S {
match lhs.partial_cmp(&rhs) {
Some(Ordering::Less) | Some(Ordering::Equal) | None => lhs,
_ => rhs,
}
}
pub(crate) fn max<S: PartialOrd + Copy>(lhs: S, rhs: S) -> S {
match lhs.partial_cmp(&rhs) {
Some(Ordering::Greater) | Some(Ordering::Equal) | None => lhs,
_ => rhs,
}
}
pub trait MinMax {
fn min(a: Self, b: Self) -> Self;
fn max(a: Self, b: Self) -> Self;
}
impl<S: PartialOrd> MinMax for Point2<S>
where
S: BaseNum,
{
fn min(a: Point2<S>, b: Point2<S>) -> Point2<S> {
Point2::new(min(a.x, b.x), min(a.y, b.y))
}
fn max(a: Point2<S>, b: Point2<S>) -> Point2<S> {
Point2::new(max(a.x, b.x), max(a.y, b.y))
}
}
impl<S: PartialOrd> MinMax for Point3<S>
where
S: BaseNum,
{
fn min(a: Point3<S>, b: Point3<S>) -> Point3<S> {
Point3::new(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z))
}
fn max(a: Point3<S>, b: Point3<S>) -> Point3<S> {
Point3::new(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z))
}
}
pub trait Aabb: Sized {
type Scalar: BaseNum;
type Diff: VectorSpace<Scalar = Self::Scalar> + ElementWise + Array<Element = Self::Scalar>;
type Point: EuclideanSpace<Scalar = Self::Scalar, Diff = Self::Diff> + MinMax;
fn new(p1: Self::Point, p2: Self::Point) -> Self;
fn zero() -> Self {
let p = Self::Point::origin();
Self::new(p, p)
}
fn min(&self) -> Self::Point;
fn max(&self) -> Self::Point;
#[inline]
fn dim(&self) -> Self::Diff {
self.max() - self.min()
}
#[inline]
fn volume(&self) -> Self::Scalar {
self.dim().product()
}
#[inline]
fn center(&self) -> Self::Point {
let two = Self::Scalar::one() + Self::Scalar::one();
self.min() + self.dim() / two
}
fn grow(&self, p: Self::Point) -> Self {
Aabb::new(MinMax::min(self.min(), p), MinMax::max(self.max(), p))
}
#[inline]
fn add_v(&self, v: Self::Diff) -> Self {
Aabb::new(self.min() + v, self.max() + v)
}
fn add_margin(&self, margin: Self::Diff) -> Self;
#[inline]
fn mul_s(&self, s: Self::Scalar) -> Self {
Aabb::new(self.min() * s, self.max() * s)
}
fn mul_v(&self, v: Self::Diff) -> Self {
let min = Self::Point::from_vec(self.min().to_vec().mul_element_wise(v));
let max = Self::Point::from_vec(self.max().to_vec().mul_element_wise(v));
Aabb::new(min, max)
}
fn transform<T>(&self, transform: &T) -> Self
where
T: Transform<Self::Point>;
}
impl<A> Bound for A
where
A: Aabb,
A::Point: EuclideanSpace,
{
type Point = A::Point;
fn min_extent(&self) -> A::Point {
self.min()
}
fn max_extent(&self) -> A::Point {
self.max()
}
fn with_margin(&self, add: <A::Point as EuclideanSpace>::Diff) -> Self {
self.add_margin(add)
}
fn transform_volume<T>(&self, transform: &T) -> Self
where
T: Transform<Self::Point>,
{
self.transform(transform)
}
fn empty() -> Self {
A::zero()
}
}