use crate::*;
use std::marker::PhantomData;
#[derive(Clone)]
pub enum AABBTree2D<HB>
where
HB: HasBoundingBox2D + Clone,
{
Empty,
Leaf(AABBTree2DLeaf<HB>),
Branch(AABBTree2DBranch<HB>),
}
impl<HB> AABBTree2D<HB>
where
HB: HasBoundingBox2D + Clone,
{
pub fn new(data: Vec<HB>, maxdepth: usize, allowed_bucket_size: usize) -> Self {
Self::new_rec(data, maxdepth, allowed_bucket_size, 0)
}
pub fn any<'a>(&'a self, f: &dyn Fn(&HB) -> bool) -> bool {
match self {
Self::Empty => false,
Self::Leaf(leaf) => leaf.any(f),
Self::Branch(branch) => branch.any(f),
}
}
pub fn for_each_collision_candidate<'a>(&'a self, bb: &BoundingBox2D, f: &mut dyn FnMut(&HB)) {
match self {
Self::Empty => (),
Self::Leaf(leaf) => leaf.for_each_collision_candidate(bb, f),
Self::Branch(branch) => branch.for_each_collision_candidate(bb, f),
}
}
pub fn bb_colliding<'a>(&'a self, bb: &BoundingBox2D, result: &mut Vec<&'a HB>) {
match self {
Self::Empty => (),
Self::Leaf(leaf) => leaf.bb_colliding(bb, result),
Self::Branch(branch) => branch.bb_colliding(bb, result),
}
}
pub fn bb_crossing_x_value<'a>(&'a self, x: f64, result: &mut Vec<&'a HB>) {
match self {
Self::Empty => (),
Self::Leaf(leaf) => leaf.bb_crossing_x_value(x, result),
Self::Branch(branch) => branch.bb_crossing_x_value(x, result),
}
}
pub fn bb_crossing_y_value<'a>(&'a self, y: f64, result: &mut Vec<&'a HB>) {
match self {
Self::Empty => (),
Self::Leaf(leaf) => leaf.bb_crossing_y_value(y, result),
Self::Branch(branch) => branch.bb_crossing_y_value(y, result),
}
}
fn new_rec(data: Vec<HB>, maxdepth: usize, allowed_bucket_size: usize, depth: usize) -> Self {
match data.len() {
0 => AABBTree2D::Empty,
1 => {
let bb = Self::bb_of(&data).unwrap(); AABBTree2D::Leaf(AABBTree2DLeaf::new(data, bb))
}
_ => {
if depth >= maxdepth || data.len() <= allowed_bucket_size {
let bb = Self::bb_of(&data).unwrap(); AABBTree2D::Leaf(AABBTree2DLeaf::new(data, bb))
} else {
let compx = depth % 2 != 0;
let bb = Self::bb_of(&data).unwrap(); let center = bb.center_bb();
let dleft = data
.iter()
.cloned()
.filter(|x| Self::is_left_of(compx, &x.bounding_box(), ¢er))
.collect::<Vec<_>>();
let dright = data
.iter()
.cloned()
.filter(|x| Self::is_right_of(compx, &x.bounding_box(), ¢er))
.collect::<Vec<_>>();
if (dleft.len() == dright.len()) && dleft.len() == data.len() {
AABBTree2D::Leaf(AABBTree2DLeaf::new(data, bb))
} else {
let left = Box::new(Self::new_rec(
dleft,
maxdepth,
allowed_bucket_size,
depth + 1,
));
let right = Box::new(Self::new_rec(
dright,
maxdepth,
allowed_bucket_size,
depth + 1,
));
AABBTree2D::Branch(AABBTree2DBranch::new(left, right, bb))
}
}
}
}
}
fn is_left_of(compx: bool, bb: &BoundingBox2D, center: &Point2D) -> bool {
if compx {
bb.min_p().x() < center.x()
} else {
bb.min_p().y() < center.y()
}
}
fn is_right_of(compx: bool, bb: &BoundingBox2D, center: &Point2D) -> bool {
if compx {
bb.max_p().x() >= center.x()
} else {
bb.max_p().y() >= center.y()
}
}
fn bb_of(data: &Vec<HB>) -> Result<BoundingBox2D> {
if data.len() == 0 {
return Err(ErrorKind::TooFewPoints);
}
let mut result = data[0].bounding_box();
for x in data.iter() {
result.consume(x.bounding_box());
}
Ok(result)
}
}
#[derive(Clone)]
pub struct AABBTree2DLeaf<HB>
where
HB: HasBoundingBox2D,
{
data: Vec<HB>,
bb: BoundingBox2D,
_marker: PhantomData<HB>,
}
impl<HB> AABBTree2DLeaf<HB>
where
HB: HasBoundingBox2D + Clone,
{
pub fn new(data: Vec<HB>, bb: BoundingBox2D) -> Self {
AABBTree2DLeaf {
data,
bb,
_marker: PhantomData,
}
}
pub fn any<'a>(&'a self, f: &dyn Fn(&HB) -> bool) -> bool {
for x in self.data.iter() {
if f(x) {
return true;
}
}
false
}
pub fn for_each_collision_candidate<'a>(&'a self, bb: &BoundingBox2D, f: &mut dyn FnMut(&HB)) {
if !self.bb.collides_with(bb) {
return;
}
for x in self.data.iter() {
if x.bounding_box().collides_with(bb) {
f(x)
}
}
}
pub fn bb_colliding<'a>(&'a self, bb: &BoundingBox2D, result: &mut Vec<&'a HB>) {
if self.bb.collides_with(bb) {
for x in self.data.iter() {
if x.bounding_box().collides_with(bb) {
result.push(x)
}
}
}
}
pub fn bb_crossing_x_value<'a>(&'a self, x: f64, result: &mut Vec<&'a HB>) {
if self.bb.crossing_x_value(x) {
for d in self.data.iter() {
if d.bounding_box().crossing_x_value(x) {
result.push(d)
}
}
}
}
pub fn bb_crossing_y_value<'a>(&'a self, y: f64, result: &mut Vec<&'a HB>) {
if self.bb.crossing_y_value(y) {
for d in self.data.iter() {
if d.bounding_box().crossing_y_value(y) {
result.push(d)
}
}
}
}
}
#[derive(Clone)]
pub struct AABBTree2DBranch<HB>
where
HB: HasBoundingBox2D + Clone,
{
left: Box<AABBTree2D<HB>>,
right: Box<AABBTree2D<HB>>,
bb: BoundingBox2D,
_marker: PhantomData<HB>,
}
impl<HB> AABBTree2DBranch<HB>
where
HB: HasBoundingBox2D + Clone,
{
pub fn new(left: Box<AABBTree2D<HB>>, right: Box<AABBTree2D<HB>>, bb: BoundingBox2D) -> Self {
AABBTree2DBranch {
left,
right,
bb,
_marker: PhantomData,
}
}
pub fn any<'a>(&'a self, f: &dyn Fn(&HB) -> bool) -> bool {
self.left.any(f) || self.right.any(f)
}
pub fn for_each_collision_candidate<'a>(&'a self, bb: &BoundingBox2D, f: &mut dyn FnMut(&HB)) {
if !self.bb.collides_with(bb) {
return;
}
self.left.for_each_collision_candidate(bb, f);
self.right.for_each_collision_candidate(bb, f);
}
pub fn bb_colliding<'a>(&'a self, bb: &BoundingBox2D, result: &mut Vec<&'a HB>) {
if self.bb.collides_with(bb) {
self.left.bb_colliding(bb, result);
self.right.bb_colliding(bb, result);
}
}
pub fn bb_crossing_x_value<'a>(&'a self, x: f64, result: &mut Vec<&'a HB>) {
if self.bb.crossing_x_value(x) {
self.left.bb_crossing_x_value(x, result);
self.right.bb_crossing_x_value(x, result);
}
}
pub fn bb_crossing_y_value<'a>(&'a self, y: f64, result: &mut Vec<&'a HB>) {
if self.bb.crossing_y_value(y) {
self.left.bb_crossing_y_value(y, result);
self.right.bb_crossing_y_value(y, result);
}
}
}