use crate::point::{max_inline, Point, PointExt};
use crate::{Envelope, RTreeObject};
use num_traits::{Bounded, One, Zero};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Copy, PartialEq, Eq, Ord, PartialOrd)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct AABB<P>
where
P: Point,
{
lower: P,
upper: P,
}
impl<P> AABB<P>
where
P: Point,
{
pub fn from_point(p: P) -> Self {
AABB { lower: p, upper: p }
}
pub fn lower(&self) -> P {
self.lower
}
pub fn upper(&self) -> P {
self.upper
}
pub fn from_corners(p1: P, p2: P) -> Self {
AABB {
lower: p1.min_point(&p2),
upper: p1.max_point(&p2),
}
}
pub fn from_points<'a, I>(i: I) -> Self
where
I: IntoIterator<Item = &'a P> + 'a,
P: 'a,
{
i.into_iter()
.fold(Self::new_empty(), |aabb, p| aabb.add_point(p))
}
fn add_point(&self, point: &P) -> Self {
AABB {
lower: self.lower.min_point(point),
upper: self.upper.max_point(point),
}
}
pub fn min_point(&self, point: &P) -> P {
self.upper.min_point(&self.lower.max_point(point))
}
pub fn distance_2(&self, point: &P) -> P::Scalar {
if self.contains_point(point) {
Zero::zero()
} else {
self.min_point(point).sub(point).length_2()
}
}
}
impl<P> Envelope for AABB<P>
where
P: Point,
{
type Point = P;
fn new_empty() -> Self {
new_empty()
}
fn contains_point(&self, point: &P) -> bool {
self.lower.all_component_wise(point, |x, y| x <= y)
&& self.upper.all_component_wise(point, |x, y| x >= y)
}
fn contains_envelope(&self, other: &Self) -> bool {
self.lower.all_component_wise(&other.lower, |l, r| l <= r)
&& self.upper.all_component_wise(&other.upper, |l, r| l >= r)
}
fn merge(&mut self, other: &Self) {
self.lower = self.lower.min_point(&other.lower);
self.upper = self.upper.max_point(&other.upper);
}
fn merged(&self, other: &Self) -> Self {
AABB {
lower: self.lower.min_point(&other.lower),
upper: self.upper.max_point(&other.upper),
}
}
fn intersects(&self, other: &Self) -> bool {
self.lower.all_component_wise(&other.upper, |l, r| l <= r)
&& self.upper.all_component_wise(&other.lower, |l, r| l >= r)
}
fn area(&self) -> P::Scalar {
let zero = P::Scalar::zero();
let one = P::Scalar::one();
let diag = self.upper.sub(&self.lower);
diag.fold(one, |acc, cur| max_inline(cur, zero) * acc)
}
fn distance_2(&self, point: &P) -> P::Scalar {
self.distance_2(point)
}
fn min_max_dist_2(&self, point: &P) -> <P as Point>::Scalar {
let l = self.lower.sub(point);
let u = self.upper.sub(point);
let mut max_diff = Zero::zero();
let mut result: <P as Point>::Scalar = Zero::zero();
for i in 0..P::DIMENSIONS {
let mut min = l.nth(i);
let mut max = u.nth(i);
max = max * max;
min = min * min;
if max < min {
std::mem::swap(&mut min, &mut max);
}
let diff = max - min;
result = result + max;
if diff > max_diff {
max_diff = diff;
}
}
result - max_diff
}
fn center(&self) -> Self::Point {
let one = <Self::Point as Point>::Scalar::one();
let two = one + one;
self.lower.component_wise(&self.upper, |x, y| (x + y) / two)
}
fn intersection_area(&self, other: &Self) -> <Self::Point as Point>::Scalar {
AABB {
lower: self.lower.max_point(&other.lower),
upper: self.upper.min_point(&other.upper),
}
.area()
}
fn perimeter_value(&self) -> P::Scalar {
let diag = self.upper.sub(&self.lower);
let zero = P::Scalar::zero();
max_inline(diag.fold(zero, |acc, value| acc + value), zero)
}
fn sort_envelopes<T: RTreeObject<Envelope = Self>>(axis: usize, envelopes: &mut [T]) {
envelopes.sort_by(|l, r| {
l.envelope()
.lower
.nth(axis)
.partial_cmp(&r.envelope().lower.nth(axis))
.unwrap()
});
}
fn partition_envelopes<T: RTreeObject<Envelope = Self>>(
axis: usize,
envelopes: &mut [T],
selection_size: usize,
) {
::pdqselect::select_by(envelopes, selection_size, |l, r| {
l.envelope()
.lower
.nth(axis)
.partial_cmp(&r.envelope().lower.nth(axis))
.unwrap()
});
}
}
fn new_empty<P: Point>() -> AABB<P> {
let max = P::Scalar::max_value();
let min = P::Scalar::min_value();
AABB {
lower: P::from_value(max),
upper: P::from_value(min),
}
}