use fmt::Debug;
use std::fmt;
use std::{
cmp::{max, min},
collections::BinaryHeap,
};
use crate::{IndexableNum, AABB};
#[derive(Debug, PartialEq)]
pub enum StaticAABB2DIndexBuildError {
ZeroItemsError,
ItemCountError {
added: usize,
expected: usize,
},
NumericCastError,
}
impl std::error::Error for StaticAABB2DIndexBuildError {}
impl fmt::Display for StaticAABB2DIndexBuildError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
StaticAABB2DIndexBuildError::ZeroItemsError => {
write!(f, "item count given cannot be zero")
}
StaticAABB2DIndexBuildError::ItemCountError { added, expected } => write!(
f,
"added item count should equal static size given to builder \
(added: {}, expected: {})",
added, expected
),
StaticAABB2DIndexBuildError::NumericCastError => write!(
f,
"numeric cast to/from type T to u16 failed (may be due to overflow/underflow)"
),
}
}
}
#[derive(Debug, Clone)]
pub struct StaticAABB2DIndexBuilder<T = f64>
where
T: IndexableNum,
{
min_x: T,
min_y: T,
max_x: T,
max_y: T,
node_size: usize,
num_items: usize,
level_bounds: Vec<usize>,
boxes: Vec<AABB<T>>,
indices: Vec<usize>,
pos: usize,
}
#[derive(Debug, Clone)]
pub struct StaticAABB2DIndex<T = f64>
where
T: IndexableNum,
{
min_x: T,
min_y: T,
max_x: T,
max_y: T,
node_size: usize,
num_items: usize,
level_bounds: Vec<usize>,
boxes: Vec<AABB<T>>,
indices: Vec<usize>,
}
#[cfg(not(feature = "allow_unsafe"))]
macro_rules! get_at_index {
($container:expr, $index:expr) => {
&$container[$index]
};
}
#[cfg(feature = "allow_unsafe")]
macro_rules! get_at_index {
($container:expr, $index:expr) => {
unsafe { $container.get_unchecked($index) }
};
}
#[cfg(not(feature = "allow_unsafe"))]
macro_rules! set_at_index {
($container:expr, $index:expr, $value:expr) => {
$container[$index] = $value
};
}
#[cfg(feature = "allow_unsafe")]
macro_rules! set_at_index {
($container:expr, $index:expr, $value:expr) => {
unsafe { *$container.get_unchecked_mut($index) = $value }
};
}
impl<T> StaticAABB2DIndexBuilder<T>
where
T: IndexableNum,
{
fn init(num_items: usize, node_size: usize) -> Self {
if num_items == 0 {
return StaticAABB2DIndexBuilder {
min_x: T::max_value(),
min_y: T::max_value(),
max_x: T::min_value(),
max_y: T::min_value(),
node_size,
num_items,
level_bounds: Vec::new(),
boxes: Vec::new(),
indices: Vec::new(),
pos: 0,
};
}
let node_size = min(max(node_size, 2), 65535);
let mut n = num_items;
let mut num_nodes = num_items;
let mut level_bounds: Vec<usize> = Vec::new();
level_bounds.push(n);
loop {
n = (n as f64 / node_size as f64).ceil() as usize;
num_nodes += n;
level_bounds.push(num_nodes);
if n == 1 {
break;
}
}
#[cfg(feature = "allow_unsafe")]
let init_boxes = || {
let mut boxes = Vec::with_capacity(num_nodes);
unsafe {
boxes.set_len(num_nodes);
}
boxes
};
#[cfg(not(feature = "allow_unsafe"))]
let init_boxes = || vec![AABB::default(); num_nodes];
let boxes = init_boxes();
StaticAABB2DIndexBuilder {
min_x: T::max_value(),
min_y: T::max_value(),
max_x: T::min_value(),
max_y: T::min_value(),
node_size,
num_items,
level_bounds,
boxes,
indices: (0..num_nodes).collect(),
pos: 0,
}
}
#[inline]
pub fn new(count: usize) -> Self {
StaticAABB2DIndexBuilder::init(count, 16)
}
#[inline]
pub fn new_with_node_size(count: usize, node_size: usize) -> Self {
StaticAABB2DIndexBuilder::init(count, node_size)
}
pub fn add(&mut self, min_x: T, min_y: T, max_x: T, max_y: T) -> &mut Self {
if self.pos >= self.num_items {
self.pos += 1;
return self;
}
debug_assert!(min_x <= max_x);
debug_assert!(min_y <= max_y);
set_at_index!(self.boxes, self.pos, AABB::new(min_x, min_y, max_x, max_y));
self.pos += 1;
self.min_x = T::min(self.min_x, min_x);
self.min_y = T::min(self.min_y, min_y);
self.max_x = T::max(self.max_x, max_x);
self.max_y = T::max(self.max_y, max_y);
self
}
pub fn build(mut self) -> Result<StaticAABB2DIndex<T>, StaticAABB2DIndexBuildError> {
if self.pos != self.num_items {
return Err(StaticAABB2DIndexBuildError::ItemCountError {
added: self.pos,
expected: self.num_items,
});
}
if self.num_items == 0 {
return Err(StaticAABB2DIndexBuildError::ZeroItemsError);
}
if self.num_items <= self.node_size {
set_at_index!(self.indices, self.pos, 0);
set_at_index!(
self.boxes,
self.pos,
AABB::new(self.min_x, self.min_y, self.max_x, self.max_y)
);
return Ok(StaticAABB2DIndex {
min_x: self.min_x,
min_y: self.min_y,
max_x: self.max_x,
max_y: self.max_y,
node_size: self.node_size,
num_items: self.num_items,
level_bounds: self.level_bounds,
boxes: self.boxes,
indices: self.indices,
});
}
let width = self.max_x - self.min_x;
let height = self.max_y - self.min_y;
let hilbert_max = T::from(u16::MAX).ok_or(StaticAABB2DIndexBuildError::NumericCastError)?;
let two = T::from(2u16).ok_or(StaticAABB2DIndexBuildError::NumericCastError)?;
let mut hilbert_values: Vec<u32> = Vec::with_capacity(self.num_items);
for aabb in self.boxes.iter().take(self.num_items) {
let x = if width == T::zero() {
0
} else {
(hilbert_max * ((aabb.min_x + aabb.max_x) / two - self.min_x) / width)
.to_u16()
.ok_or(StaticAABB2DIndexBuildError::NumericCastError)?
};
let y = if height == T::zero() {
0
} else {
(hilbert_max * ((aabb.min_y + aabb.max_y) / two - self.min_y) / height)
.to_u16()
.ok_or(StaticAABB2DIndexBuildError::NumericCastError)?
};
hilbert_values.push(hilbert_xy_to_index(x, y));
}
sort(
&mut hilbert_values,
&mut self.boxes,
&mut self.indices,
0,
self.num_items - 1,
self.node_size,
);
let mut pos = 0;
for i in 0..self.level_bounds.len() - 1 {
let end = *get_at_index!(self.level_bounds, i);
while pos < end {
let mut node_min_x = T::max_value();
let mut node_min_y = T::max_value();
let mut node_max_x = T::min_value();
let mut node_max_y = T::min_value();
let node_index = pos;
let mut j = 0;
while j < self.node_size && pos < end {
let aabb = get_at_index!(self.boxes, pos);
pos += 1;
node_min_x = T::min(node_min_x, aabb.min_x);
node_min_y = T::min(node_min_y, aabb.min_y);
node_max_x = T::max(node_max_x, aabb.max_x);
node_max_y = T::max(node_max_y, aabb.max_y);
j += 1;
}
set_at_index!(self.indices, self.pos, node_index);
set_at_index!(
self.boxes,
self.pos,
AABB::new(node_min_x, node_min_y, node_max_x, node_max_y)
);
self.pos += 1;
}
}
Ok(StaticAABB2DIndex {
min_x: self.min_x,
min_y: self.min_y,
max_x: self.max_x,
max_y: self.max_y,
node_size: self.node_size,
num_items: self.num_items,
level_bounds: self.level_bounds,
boxes: self.boxes,
indices: self.indices,
})
}
}
pub fn hilbert_xy_to_index(x: u16, y: u16) -> u32 {
let x = x as u32;
let y = y as u32;
let mut a_1 = x ^ y;
let mut b_1 = 0xFFFF ^ a_1;
let mut c_1 = 0xFFFF ^ (x | y);
let mut d_1 = x & (y ^ 0xFFFF);
let mut a_2 = a_1 | (b_1 >> 1);
let mut b_2 = (a_1 >> 1) ^ a_1;
let mut c_2 = ((c_1 >> 1) ^ (b_1 & (d_1 >> 1))) ^ c_1;
let mut d_2 = ((a_1 & (c_1 >> 1)) ^ (d_1 >> 1)) ^ d_1;
a_1 = a_2;
b_1 = b_2;
c_1 = c_2;
d_1 = d_2;
a_2 = (a_1 & (a_1 >> 2)) ^ (b_1 & (b_1 >> 2));
b_2 = (a_1 & (b_1 >> 2)) ^ (b_1 & ((a_1 ^ b_1) >> 2));
c_2 ^= (a_1 & (c_1 >> 2)) ^ (b_1 & (d_1 >> 2));
d_2 ^= (b_1 & (c_1 >> 2)) ^ ((a_1 ^ b_1) & (d_1 >> 2));
a_1 = a_2;
b_1 = b_2;
c_1 = c_2;
d_1 = d_2;
a_2 = (a_1 & (a_1 >> 4)) ^ (b_1 & (b_1 >> 4));
b_2 = (a_1 & (b_1 >> 4)) ^ (b_1 & ((a_1 ^ b_1) >> 4));
c_2 ^= (a_1 & (c_1 >> 4)) ^ (b_1 & (d_1 >> 4));
d_2 ^= (b_1 & (c_1 >> 4)) ^ ((a_1 ^ b_1) & (d_1 >> 4));
a_1 = a_2;
b_1 = b_2;
c_1 = c_2;
d_1 = d_2;
c_2 ^= (a_1 & (c_1 >> 8)) ^ (b_1 & (d_1 >> 8));
d_2 ^= (b_1 & (c_1 >> 8)) ^ ((a_1 ^ b_1) & (d_1 >> 8));
a_1 = c_2 ^ (c_2 >> 1);
b_1 = d_2 ^ (d_2 >> 1);
let mut i0 = x ^ y;
let mut i1 = b_1 | (0xFFFF ^ (i0 | a_1));
i0 = (i0 | (i0 << 8)) & 0x00FF00FF;
i0 = (i0 | (i0 << 4)) & 0x0F0F0F0F;
i0 = (i0 | (i0 << 2)) & 0x33333333;
i0 = (i0 | (i0 << 1)) & 0x55555555;
i1 = (i1 | (i1 << 8)) & 0x00FF00FF;
i1 = (i1 | (i1 << 4)) & 0x0F0F0F0F;
i1 = (i1 | (i1 << 2)) & 0x33333333;
i1 = (i1 | (i1 << 1)) & 0x55555555;
(i1 << 1) | i0
}
fn sort<T>(
values: &mut Vec<u32>,
boxes: &mut Vec<AABB<T>>,
indices: &mut Vec<usize>,
left: usize,
right: usize,
node_size: usize,
) where
T: IndexableNum,
{
debug_assert!(left <= right);
if left / node_size >= right / node_size {
return;
}
let pivot = *get_at_index!(values, (left + right) >> 1);
let mut i = left.wrapping_sub(1);
let mut j = right.wrapping_add(1);
loop {
loop {
i = i.wrapping_add(1);
if *get_at_index!(values, i) >= pivot {
break;
}
}
loop {
j = j.wrapping_sub(1);
if *get_at_index!(values, j) <= pivot {
break;
}
}
if i >= j {
break;
}
swap(values, boxes, indices, i, j);
}
sort(values, boxes, indices, left, j, node_size);
sort(values, boxes, indices, j.wrapping_add(1), right, node_size);
}
#[inline]
fn swap<T>(
values: &mut Vec<u32>,
boxes: &mut Vec<AABB<T>>,
indices: &mut Vec<usize>,
i: usize,
j: usize,
) where
T: IndexableNum,
{
values.swap(i, j);
boxes.swap(i, j);
indices.swap(i, j);
}
struct QueryIterator<'a, T>
where
T: IndexableNum,
{
aabb_index: &'a StaticAABB2DIndex<T>,
stack: Vec<usize>,
min_x: T,
min_y: T,
max_x: T,
max_y: T,
node_index: usize,
level: usize,
pos: usize,
end: usize,
}
impl<'a, T> QueryIterator<'a, T>
where
T: IndexableNum,
{
#[inline]
fn new(
aabb_index: &'a StaticAABB2DIndex<T>,
min_x: T,
min_y: T,
max_x: T,
max_y: T,
) -> QueryIterator<'a, T> {
let node_index = aabb_index.boxes.len() - 1;
let pos = node_index;
let level = aabb_index.level_bounds.len() - 1;
let end = min(
node_index + aabb_index.node_size,
*get_at_index!(aabb_index.level_bounds, level),
);
QueryIterator {
aabb_index,
stack: Vec::with_capacity(16),
min_x,
min_y,
max_x,
max_y,
node_index,
level,
pos,
end,
}
}
}
impl<'a, T> Iterator for QueryIterator<'a, T>
where
T: IndexableNum,
{
type Item = usize;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
loop {
while self.pos < self.end {
let current_pos = self.pos;
self.pos += 1;
let aabb = get_at_index!(self.aabb_index.boxes, current_pos);
if !aabb.overlaps(self.min_x, self.min_y, self.max_x, self.max_y) {
continue;
}
let index = *get_at_index!(self.aabb_index.indices, current_pos);
if self.node_index < self.aabb_index.num_items {
return Some(index);
} else {
self.stack.push(index);
self.stack.push(self.level - 1);
}
}
if self.stack.len() > 1 {
self.level = self.stack.pop().unwrap();
self.node_index = self.stack.pop().unwrap();
self.pos = self.node_index;
self.end = min(
self.node_index + self.aabb_index.node_size,
*get_at_index!(self.aabb_index.level_bounds, self.level),
);
} else {
return None;
}
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
if self.pos >= self.end && self.stack.len() < 2 {
(0, Some(0))
} else {
(0, Some(self.aabb_index.num_items))
}
}
}
struct QueryIteratorStackRef<'a, T>
where
T: IndexableNum,
{
aabb_index: &'a StaticAABB2DIndex<T>,
stack: &'a mut Vec<usize>,
min_x: T,
min_y: T,
max_x: T,
max_y: T,
node_index: usize,
level: usize,
pos: usize,
end: usize,
}
impl<'a, T> QueryIteratorStackRef<'a, T>
where
T: IndexableNum,
{
#[inline]
fn new(
aabb_index: &'a StaticAABB2DIndex<T>,
stack: &'a mut Vec<usize>,
min_x: T,
min_y: T,
max_x: T,
max_y: T,
) -> QueryIteratorStackRef<'a, T> {
let node_index = aabb_index.boxes.len() - 1;
let pos = node_index;
let level = aabb_index.level_bounds.len() - 1;
let end = min(
node_index + aabb_index.node_size,
*get_at_index!(aabb_index.level_bounds, level),
);
stack.clear();
QueryIteratorStackRef {
aabb_index,
stack,
min_x,
min_y,
max_x,
max_y,
node_index,
level,
pos,
end,
}
}
}
impl<'a, T> Iterator for QueryIteratorStackRef<'a, T>
where
T: IndexableNum,
{
type Item = usize;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
loop {
while self.pos < self.end {
let current_pos = self.pos;
self.pos += 1;
let aabb = get_at_index!(self.aabb_index.boxes, current_pos);
if !aabb.overlaps(self.min_x, self.min_y, self.max_x, self.max_y) {
continue;
}
let index = *get_at_index!(self.aabb_index.indices, current_pos);
if self.node_index < self.aabb_index.num_items {
return Some(index);
} else {
self.stack.push(index);
self.stack.push(self.level - 1);
}
}
if self.stack.len() > 1 {
self.level = self.stack.pop().unwrap();
self.node_index = self.stack.pop().unwrap();
self.pos = self.node_index;
self.end = min(
self.node_index + self.aabb_index.node_size,
*get_at_index!(self.aabb_index.level_bounds, self.level),
);
} else {
return None;
}
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
if self.pos >= self.end && self.stack.len() < 2 {
(0, Some(0))
} else {
(0, Some(self.aabb_index.num_items))
}
}
}
pub type NeighborPriorityQueue<T> = BinaryHeap<NeighborsState<T>>;
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct NeighborsState<T>
where
T: IndexableNum,
{
index: usize,
is_leaf_node: bool,
dist: T,
}
impl<T> NeighborsState<T>
where
T: IndexableNum,
{
fn new(index: usize, is_leaf_node: bool, dist: T) -> Self {
NeighborsState {
index,
is_leaf_node,
dist,
}
}
}
impl<T> Eq for NeighborsState<T> where T: IndexableNum {}
impl<T> Ord for NeighborsState<T>
where
T: IndexableNum,
{
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
if let Some(ord) = self.partial_cmp(other) {
ord
} else {
std::cmp::Ordering::Equal
}
}
}
impl<T> PartialOrd for NeighborsState<T>
where
T: IndexableNum,
{
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
other.dist.partial_cmp(&self.dist)
}
}
impl<T> StaticAABB2DIndex<T>
where
T: IndexableNum,
{
#[inline]
pub fn min_x(&self) -> T {
self.min_x
}
#[inline]
pub fn min_y(&self) -> T {
self.min_y
}
#[inline]
pub fn max_x(&self) -> T {
self.max_x
}
#[inline]
pub fn max_y(&self) -> T {
self.max_y
}
#[inline]
pub fn count(&self) -> usize {
self.num_items
}
#[inline]
pub fn query(&self, min_x: T, min_y: T, max_x: T, max_y: T) -> Vec<usize> {
let mut results = Vec::new();
let mut visitor = |i| {
results.push(i);
true
};
self.visit_query(min_x, min_y, max_x, max_y, &mut visitor);
results
}
#[inline]
pub fn query_iter<'a>(
&'a self,
min_x: T,
min_y: T,
max_x: T,
max_y: T,
) -> impl Iterator<Item = usize> + 'a {
QueryIterator::<'a, T>::new(&self, min_x, min_y, max_x, max_y)
}
#[inline]
pub fn query_iter_with_stack<'a>(
&'a self,
min_x: T,
min_y: T,
max_x: T,
max_y: T,
stack: &'a mut Vec<usize>,
) -> impl Iterator<Item = usize> + 'a {
QueryIteratorStackRef::<'a, T>::new(&self, stack, min_x, min_y, max_x, max_y)
}
#[inline]
pub fn visit_query<F>(&self, min_x: T, min_y: T, max_x: T, max_y: T, visitor: &mut F)
where
F: FnMut(usize) -> bool,
{
let mut stack: Vec<usize> = Vec::with_capacity(16);
self.visit_query_with_stack(min_x, min_y, max_x, max_y, visitor, &mut stack);
}
#[inline]
pub fn item_boxes(&self) -> &[AABB<T>] {
&self.boxes[0..self.num_items]
}
#[inline]
pub fn node_size(&self) -> usize {
self.node_size
}
#[inline]
pub fn level_bounds(&self) -> &[usize] {
&self.level_bounds
}
#[inline]
pub fn all_boxes(&self) -> &[AABB<T>] {
&self.boxes
}
#[inline]
pub fn map_all_boxes_index(&self, all_boxes_index: usize) -> usize {
self.indices[all_boxes_index]
}
#[inline]
pub fn query_with_stack(
&self,
min_x: T,
min_y: T,
max_x: T,
max_y: T,
stack: &mut Vec<usize>,
) -> Vec<usize> {
let mut results = Vec::new();
let mut visitor = |i| {
results.push(i);
true
};
self.visit_query_with_stack(min_x, min_y, max_x, max_y, &mut visitor, stack);
results
}
pub fn visit_query_with_stack<F>(
&self,
min_x: T,
min_y: T,
max_x: T,
max_y: T,
visitor: &mut F,
stack: &mut Vec<usize>,
) where
F: FnMut(usize) -> bool,
{
let mut node_index = self.boxes.len() - 1;
let mut level = self.level_bounds.len() - 1;
stack.clear();
'search_loop: loop {
let end = min(
node_index + self.node_size,
*get_at_index!(self.level_bounds, level),
);
for pos in node_index..end {
let aabb = get_at_index!(self.boxes, pos);
if !aabb.overlaps(min_x, min_y, max_x, max_y) {
continue;
}
let index = *get_at_index!(self.indices, pos);
if node_index < self.num_items {
if !visitor(index) {
break 'search_loop;
}
} else {
stack.push(index);
stack.push(level - 1);
}
}
if stack.len() > 1 {
level = stack.pop().unwrap();
node_index = stack.pop().unwrap();
} else {
break 'search_loop;
}
}
}
#[inline]
pub fn visit_neighbors<F>(&self, x: T, y: T, visitor: &mut F)
where
F: FnMut(usize, T) -> bool,
{
let mut queue = NeighborPriorityQueue::new();
self.visit_neighbors_with_queue(x, y, visitor, &mut queue);
}
pub fn visit_neighbors_with_queue<F>(
&self,
x: T,
y: T,
visitor: &mut F,
queue: &mut NeighborPriorityQueue<T>,
) where
F: FnMut(usize, T) -> bool,
{
fn axis_dist<U>(k: U, min: U, max: U) -> U
where
U: IndexableNum,
{
if k < min {
min - k
} else if k > max {
k - max
} else {
U::zero()
}
}
let mut node_index = self.boxes.len() - 1;
queue.clear();
'search_loop: loop {
let upper_bound_level_index = match self.level_bounds.binary_search(&node_index) {
Ok(i) => i + 1,
Err(i) => i,
};
let end = min(
node_index + self.node_size,
self.level_bounds[upper_bound_level_index],
);
for pos in node_index..end {
let aabb = get_at_index!(self.boxes, pos);
let dx = axis_dist(x, aabb.min_x, aabb.max_x);
let dy = axis_dist(y, aabb.min_y, aabb.max_y);
let dist = dx * dx + dy * dy;
let index = *get_at_index!(self.indices, pos);
let is_leaf_node = node_index < self.num_items;
queue.push(NeighborsState::new(index, is_leaf_node, dist));
}
let mut continue_search = false;
while let Some(state) = queue.pop() {
if state.is_leaf_node {
if !visitor(state.index, state.dist) {
break 'search_loop;
}
} else {
node_index = state.index;
continue_search = true;
break;
}
}
if !continue_search {
break 'search_loop;
}
}
}
}