use std::{collections::BinaryHeap, ops::ControlFlow};
use crate::config::{DEFAULT_NEIGHBOR_QUEUE_CAPACITY, DEFAULT_SEARCH_STACK_CAPACITY};
use crate::geometry::{Box2D, Point2D};
use crate::join::{JoinTree, join_core, self_join_core};
use crate::neighbors::{
NeighborNodeState, NeighborQuery2D, NeighborState, NeighborWorkspace, max_distance_squared,
};
use crate::persistence::{
LoadError, MetaFields, ParsedPayload, PayloadError, build_id_to_leaf, parse_index,
payload_slice, read_f64_le_unchecked, read_u64_le_unchecked, write_index_container,
};
use crate::ray::Ray2D;
use crate::traversal::{SearchWorkspace, prefetch_read, upper_bound_level};
#[inline]
fn prefetch_aos_node(entries: &[Box2D], indices: &[usize], node_index: usize, node_size: usize) {
if node_index < entries.len() {
prefetch_read(entries.as_ptr().wrapping_add(node_index));
prefetch_read(indices.as_ptr().wrapping_add(node_index));
}
let next_line = node_index.saturating_add((64 / std::mem::size_of::<Box2D>()).max(1));
if node_size > 1 && next_line < entries.len() {
prefetch_read(entries.as_ptr().wrapping_add(next_line));
prefetch_read(indices.as_ptr().wrapping_add(next_line));
}
}
pub struct Index2D {
pub(crate) node_size: usize,
pub(crate) num_items: usize,
pub(crate) level_bounds: Vec<usize>,
pub(crate) entries: Vec<Box2D>,
pub(crate) indices: Vec<usize>,
}
impl Index2D {
pub fn num_items(&self) -> usize {
self.num_items
}
pub fn extent(&self) -> Option<Box2D> {
self.entries.last().copied()
}
pub fn node_size(&self) -> usize {
self.node_size
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut out = Vec::new();
self.to_bytes_into(&mut out);
out
}
pub fn to_bytes_into(&self, out: &mut Vec<u8>) {
self.serialize()
.to_bytes_into(out)
.expect("serialization without payloads cannot fail");
}
pub fn to_bytes_with_payloads<P: AsRef<[u8]>>(
&self,
payloads: &[P],
) -> Result<Vec<u8>, PayloadError> {
self.serialize().payloads(payloads).to_bytes()
}
pub fn to_bytes_with_payloads_into<P: AsRef<[u8]>>(
&self,
payloads: &[P],
out: &mut Vec<u8>,
) -> Result<(), PayloadError> {
self.serialize().payloads(payloads).to_bytes_into(out)
}
#[cfg(feature = "stream")]
pub fn to_bytes_interleaved(&self) -> Vec<u8> {
self.serialize()
.interleaved()
.to_bytes()
.expect("serialization without payloads cannot fail")
}
#[cfg(feature = "stream")]
pub fn to_bytes_interleaved_with_payloads<P: AsRef<[u8]>>(
&self,
payloads: &[P],
) -> Result<Vec<u8>, PayloadError> {
self.serialize().interleaved().payloads(payloads).to_bytes()
}
pub fn serialize(&self) -> Serializer2D<'_> {
Serializer2D::new(self)
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, LoadError> {
let view = Index2DView::from_bytes(bytes)?;
let mut level_bounds = Vec::with_capacity(view.level_count);
for i in 0..view.level_count {
level_bounds.push(view.level_bound_unchecked(i));
}
let mut entries = Vec::with_capacity(view.num_nodes);
for i in 0..view.num_nodes {
entries.push(view.entry_at_unchecked(i));
}
let mut indices = Vec::with_capacity(view.num_nodes);
for i in 0..view.num_nodes {
indices.push(view.index_at_unchecked(i));
}
Ok(Self {
node_size: view.node_size,
num_items: view.num_items,
level_bounds,
entries,
indices,
})
}
pub fn search(&self, query: Box2D) -> Vec<usize> {
let mut results = Vec::new();
self.search_into(query, &mut results);
results
}
pub fn search_into(&self, query: Box2D, results: &mut Vec<usize>) {
let mut stack: Vec<usize> = Vec::with_capacity(DEFAULT_SEARCH_STACK_CAPACITY);
self.search_into_stack(query, results, &mut stack);
}
pub fn search_with<'a>(&self, query: Box2D, workspace: &'a mut SearchWorkspace) -> &'a [usize] {
self.search_into_stack(query, &mut workspace.results, &mut workspace.stack);
&workspace.results
}
pub fn any(&self, query: Box2D) -> bool {
self.visit(query, |_| ControlFlow::Break(())).is_break()
}
pub fn first(&self, query: Box2D) -> Option<usize> {
match self.visit(query, ControlFlow::Break) {
ControlFlow::Break(index) => Some(index),
ControlFlow::Continue(()) => None,
}
}
pub fn neighbors(&self, point: Point2D, max_results: usize) -> Vec<usize> {
self.neighbors_within(point, max_results, f64::INFINITY)
}
pub fn neighbors_within(
&self,
point: Point2D,
max_results: usize,
max_distance: f64,
) -> Vec<usize> {
let mut results = Vec::new();
self.neighbors_into(point, max_results, max_distance, &mut results);
results
}
pub fn neighbors_into(
&self,
point: Point2D,
max_results: usize,
max_distance: f64,
results: &mut Vec<usize>,
) {
results.clear();
if max_results == 0 {
return;
}
if max_results == 1 {
let mut queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
if let Some(index) =
self.nearest_one_with_queue(NeighborQuery2D::Point(point), max_distance, &mut queue)
{
results.push(index);
}
return;
}
let mut item_queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
let mut node_queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
self.collect_neighbors_with_queues(
NeighborQuery2D::Point(point),
max_results,
max_distance,
results,
&mut item_queue,
&mut node_queue,
);
}
pub fn neighbors_with<'a>(
&self,
point: Point2D,
max_results: usize,
max_distance: f64,
workspace: &'a mut NeighborWorkspace,
) -> &'a [usize] {
workspace.results.clear();
if max_results == 0 {
workspace.queue.clear();
workspace.node_queue.clear();
return &workspace.results;
}
if max_results == 1 {
workspace.queue.clear();
if let Some(index) = self.nearest_one_with_queue(
NeighborQuery2D::Point(point),
max_distance,
&mut workspace.node_queue,
) {
workspace.results.push(index);
}
return &workspace.results;
}
self.collect_neighbors_with_queues(
NeighborQuery2D::Point(point),
max_results,
max_distance,
&mut workspace.results,
&mut workspace.queue,
&mut workspace.node_queue,
);
&workspace.results
}
pub fn visit_neighbors<B, F>(
&self,
point: Point2D,
max_distance: f64,
mut visitor: F,
) -> ControlFlow<B>
where
F: FnMut(usize, f64) -> ControlFlow<B>,
{
let mut queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
self.visit_neighbors_with_queue(
NeighborQuery2D::Point(point),
max_distance,
&mut queue,
&mut visitor,
)
}
pub fn neighbors_of_box(&self, query: Box2D, max_results: usize) -> Vec<usize> {
self.neighbors_of_box_within(query, max_results, f64::INFINITY)
}
pub fn neighbors_of_box_within(
&self,
query: Box2D,
max_results: usize,
max_distance: f64,
) -> Vec<usize> {
let mut results = Vec::new();
self.neighbors_of_box_into(query, max_results, max_distance, &mut results);
results
}
pub fn neighbors_of_box_into(
&self,
query: Box2D,
max_results: usize,
max_distance: f64,
results: &mut Vec<usize>,
) {
results.clear();
if max_results == 0 {
return;
}
if max_results == 1 {
let mut queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
if let Some(index) =
self.nearest_one_with_queue(NeighborQuery2D::Box(query), max_distance, &mut queue)
{
results.push(index);
}
return;
}
let mut item_queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
let mut node_queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
self.collect_neighbors_with_queues(
NeighborQuery2D::Box(query),
max_results,
max_distance,
results,
&mut item_queue,
&mut node_queue,
);
}
pub fn neighbors_of_box_with<'na>(
&self,
query: Box2D,
max_results: usize,
max_distance: f64,
workspace: &'na mut NeighborWorkspace,
) -> &'na [usize] {
workspace.results.clear();
if max_results == 0 {
workspace.queue.clear();
workspace.node_queue.clear();
return &workspace.results;
}
if max_results == 1 {
workspace.queue.clear();
if let Some(index) = self.nearest_one_with_queue(
NeighborQuery2D::Box(query),
max_distance,
&mut workspace.node_queue,
) {
workspace.results.push(index);
}
return &workspace.results;
}
self.collect_neighbors_with_queues(
NeighborQuery2D::Box(query),
max_results,
max_distance,
&mut workspace.results,
&mut workspace.queue,
&mut workspace.node_queue,
);
&workspace.results
}
pub fn visit_neighbors_of_box<B, F>(
&self,
query: Box2D,
max_distance: f64,
mut visitor: F,
) -> ControlFlow<B>
where
F: FnMut(usize, f64) -> ControlFlow<B>,
{
let mut queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
self.visit_neighbors_with_queue(
NeighborQuery2D::Box(query),
max_distance,
&mut queue,
&mut visitor,
)
}
pub fn visit<B, F>(&self, query: Box2D, visitor: F) -> ControlFlow<B>
where
F: FnMut(usize) -> ControlFlow<B>,
{
let mut stack: Vec<usize> = Vec::with_capacity(DEFAULT_SEARCH_STACK_CAPACITY);
self.visit_with_stack(query, &mut stack, visitor)
}
pub fn search_iter(&self, query: Box2D) -> Search2DIter<'_> {
Search2DIter::new(self, query)
}
pub fn join(&self, other: &Index2D) -> Vec<(usize, usize)> {
let mut out = Vec::new();
let _: ControlFlow<()> = self.join_with(other, |i, j| {
out.push((i, j));
ControlFlow::Continue(())
});
out
}
pub fn join_with<B, F>(&self, other: &Index2D, visitor: F) -> ControlFlow<B>
where
F: FnMut(usize, usize) -> ControlFlow<B>,
{
join_core(self, other, visitor)
}
pub fn self_join(&self) -> Vec<(usize, usize)> {
let mut out = Vec::new();
let _: ControlFlow<()> = self.self_join_with(|i, j| {
out.push((i, j));
ControlFlow::Continue(())
});
out
}
pub fn self_join_with<B, F>(&self, visitor: F) -> ControlFlow<B>
where
F: FnMut(usize, usize) -> ControlFlow<B>,
{
self_join_core(self, visitor)
}
fn collect_neighbors_with_queues(
&self,
query: NeighborQuery2D,
max_results: usize,
max_distance: f64,
results: &mut Vec<usize>,
item_queue: &mut BinaryHeap<NeighborState>,
node_queue: &mut BinaryHeap<NeighborNodeState>,
) {
item_queue.clear();
node_queue.clear();
let Some(max_dist_sq) = max_distance_squared(max_distance) else {
return;
};
if self.num_items == 0 {
return;
}
let root_index = self.entries.len() - 1;
let root_dist = query.distance_squared_to(self.entries[root_index]);
if root_dist > max_dist_sq {
return;
}
node_queue.push(NeighborNodeState::new(root_index, root_dist));
while results.len() < max_results {
while let Some(&node) = node_queue.peek() {
if node.dist > max_dist_sq {
node_queue.clear();
break;
}
if item_queue.peek().is_some_and(|item| item.dist < node.dist) {
break;
}
let node = node_queue.pop().unwrap();
let upper_bound_level = upper_bound_level(&self.level_bounds, node.index);
let end = (node.index + self.node_size).min(self.level_bounds[upper_bound_level]);
let is_leaf = node.index < self.num_items;
if is_leaf {
for pos in node.index..end {
let b = self.entries[pos];
let dist = query.distance_squared_to(b);
if dist <= max_dist_sq {
item_queue.push(NeighborState::new(self.indices[pos], true, dist));
}
}
} else {
for pos in node.index..end {
let b = self.entries[pos];
let dist = query.distance_squared_to(b);
if dist <= max_dist_sq {
node_queue.push(NeighborNodeState::new(self.indices[pos], dist));
}
}
}
}
match item_queue.pop() {
Some(state) if state.dist <= max_dist_sq => results.push(state.index),
_ => return,
}
}
}
fn nearest_one_with_queue(
&self,
query: NeighborQuery2D,
max_distance: f64,
queue: &mut BinaryHeap<NeighborNodeState>,
) -> Option<usize> {
queue.clear();
let mut best_dist = max_distance_squared(max_distance)?;
if self.num_items == 0 {
return None;
}
let mut best_index = None;
let mut node_index = self.entries.len() - 1;
loop {
let upper_bound_level = upper_bound_level(&self.level_bounds, node_index);
let end = (node_index + self.node_size).min(self.level_bounds[upper_bound_level]);
let is_leaf = node_index < self.num_items;
for pos in node_index..end {
let b = self.entries[pos];
let dist = query.distance_squared_to(b);
if dist > best_dist {
continue;
}
if is_leaf {
if dist == 0.0 {
return Some(self.indices[pos]);
}
best_dist = dist;
best_index = Some(self.indices[pos]);
} else {
queue.push(NeighborNodeState::new(self.indices[pos], dist));
}
}
match queue.pop() {
Some(state) if state.dist <= best_dist => node_index = state.index,
_ => return best_index,
}
}
}
fn visit_neighbors_with_queue<B, F>(
&self,
query: NeighborQuery2D,
max_distance: f64,
queue: &mut BinaryHeap<NeighborState>,
visitor: &mut F,
) -> ControlFlow<B>
where
F: FnMut(usize, f64) -> ControlFlow<B>,
{
queue.clear();
let Some(max_dist_sq) = max_distance_squared(max_distance) else {
return ControlFlow::Continue(());
};
if self.num_items == 0 {
return ControlFlow::Continue(());
}
let mut node_index = self.entries.len() - 1;
loop {
let upper_bound_level = upper_bound_level(&self.level_bounds, node_index);
let end = (node_index + self.node_size).min(self.level_bounds[upper_bound_level]);
let is_leaf = node_index < self.num_items;
for pos in node_index..end {
let b = self.entries[pos];
let dist = query.distance_squared_to(b);
if dist > max_dist_sq {
continue;
}
queue.push(NeighborState::new(self.indices[pos], is_leaf, dist));
}
let mut continue_search = false;
while let Some(state) = queue.pop() {
if state.dist > max_dist_sq {
queue.clear();
return ControlFlow::Continue(());
}
if state.is_leaf {
visitor(state.index, state.dist)?;
} else {
node_index = state.index;
continue_search = true;
break;
}
}
if !continue_search {
return ControlFlow::Continue(());
}
}
}
#[doc(hidden)]
pub fn visit_with_stack<B, F>(
&self,
query: Box2D,
stack: &mut Vec<usize>,
visitor: F,
) -> ControlFlow<B>
where
F: FnMut(usize) -> ControlFlow<B>,
{
self.visit_with_stack_impl::<false, B, F>(query, stack, visitor)
}
#[doc(hidden)]
pub fn visit_with_stack_prefetch<B, F>(
&self,
query: Box2D,
stack: &mut Vec<usize>,
visitor: F,
) -> ControlFlow<B>
where
F: FnMut(usize) -> ControlFlow<B>,
{
self.visit_with_stack_impl::<true, B, F>(query, stack, visitor)
}
#[doc(hidden)]
pub fn search_into_stack(
&self,
query: Box2D,
results: &mut Vec<usize>,
stack: &mut Vec<usize>,
) {
self.search_into_stack_contained_impl(query, results, stack);
}
#[doc(hidden)]
pub fn search_into_stack_prefetch(
&self,
query: Box2D,
results: &mut Vec<usize>,
stack: &mut Vec<usize>,
) {
results.clear();
if self.num_items == 0 {
stack.clear();
return;
}
let root = self.entries[self.entries.len() - 1];
if query.contains(root) {
stack.clear();
results.extend_from_slice(&self.indices[..self.num_items]);
return;
}
self.search_into_stack_overlaps_impl::<true>(query, results, stack);
}
fn search_into_stack_overlaps_impl<const PREFETCH: bool>(
&self,
query: Box2D,
results: &mut Vec<usize>,
stack: &mut Vec<usize>,
) {
results.clear();
stack.clear();
if self.num_items == 0 {
return;
}
let mut node_index = self.entries.len() - 1;
let mut level = self.level_bounds.len() - 1;
loop {
let end = (node_index + self.node_size).min(self.level_bounds[level]);
let is_leaf = node_index < self.num_items;
let node_entries = &self.entries[node_index..end];
let node_indices = &self.indices[node_index..end];
if is_leaf {
for (b, &index) in node_entries.iter().zip(node_indices) {
if !b.overlaps(query) {
continue;
}
results.push(index);
}
} else {
let child_level = level - 1;
for (b, &index) in node_entries.iter().zip(node_indices).rev() {
if !b.overlaps(query) {
continue;
}
stack.push(index);
stack.push(child_level);
}
}
if stack.len() > 1 {
if PREFETCH {
prefetch_aos_node(
&self.entries,
&self.indices,
stack[stack.len() - 2],
self.node_size,
);
}
level = stack.pop().unwrap();
node_index = stack.pop().unwrap();
} else {
return;
}
}
}
fn search_into_stack_contained_impl(
&self,
query: Box2D,
results: &mut Vec<usize>,
stack: &mut Vec<usize>,
) {
results.clear();
stack.clear();
if self.num_items == 0 {
return;
}
const CONTAINED_FLAG: usize = 1usize << (usize::BITS - 1);
const LEVEL_MASK: usize = !CONTAINED_FLAG;
let mut node_index = self.entries.len() - 1;
let mut level = self.level_bounds.len() - 1;
let mut contained = false;
loop {
let end = (node_index + self.node_size).min(self.level_bounds[level]);
let is_leaf = node_index < self.num_items;
let node_entries = &self.entries[node_index..end];
let node_indices = &self.indices[node_index..end];
if contained {
self.extend_contained_leaf_indices(node_index, end, level, results);
} else if is_leaf {
for (b, &index) in node_entries.iter().zip(node_indices) {
if !b.overlaps(query) {
continue;
}
results.push(index);
}
} else {
let child_level = level - 1;
for (b, &index) in node_entries.iter().zip(node_indices).rev() {
if !b.overlaps(query) {
continue;
}
stack.push(index);
let encoded_level = if query.contains(*b) {
child_level | CONTAINED_FLAG
} else {
child_level
};
stack.push(encoded_level);
}
}
if stack.len() > 1 {
prefetch_aos_node(
&self.entries,
&self.indices,
stack[stack.len() - 2],
self.node_size,
);
let encoded_level = stack.pop().unwrap();
level = encoded_level & LEVEL_MASK;
contained = (encoded_level & CONTAINED_FLAG) != 0;
node_index = stack.pop().unwrap();
} else {
return;
}
}
}
#[inline]
fn extend_contained_leaf_indices(
&self,
node_index: usize,
end: usize,
level: usize,
results: &mut Vec<usize>,
) {
let start = self.leaf_start_for_entry(node_index, level);
let end = if end < self.level_bounds[level] {
self.leaf_start_for_entry(end, level)
} else {
self.num_items
};
results.extend_from_slice(&self.indices[start..end]);
}
#[inline]
fn leaf_start_for_entry(&self, mut index: usize, mut level: usize) -> usize {
while level > 0 {
index = self.indices[index];
level -= 1;
}
index
}
fn visit_with_stack_impl<const PREFETCH: bool, B, F>(
&self,
query: Box2D,
stack: &mut Vec<usize>,
mut visitor: F,
) -> ControlFlow<B>
where
F: FnMut(usize) -> ControlFlow<B>,
{
stack.clear();
if self.num_items == 0 {
return ControlFlow::Continue(());
}
let mut node_index = self.entries.len() - 1;
let mut level = self.level_bounds.len() - 1;
loop {
let end = (node_index + self.node_size).min(self.level_bounds[level]);
let is_leaf = node_index < self.num_items;
let node_entries = &self.entries[node_index..end];
let node_indices = &self.indices[node_index..end];
if is_leaf {
for (b, &index) in node_entries.iter().zip(node_indices) {
if !b.overlaps(query) {
continue;
}
visitor(index)?;
}
} else {
let child_level = level - 1;
for (b, &index) in node_entries.iter().zip(node_indices).rev() {
if !b.overlaps(query) {
continue;
}
stack.push(index);
stack.push(child_level);
}
}
if stack.len() > 1 {
if PREFETCH {
prefetch_aos_node(
&self.entries,
&self.indices,
stack[stack.len() - 2],
self.node_size,
);
}
level = stack.pop().unwrap();
node_index = stack.pop().unwrap();
} else {
return ControlFlow::Continue(());
}
}
}
#[doc(hidden)]
pub fn search_visited(&self, query: Box2D) -> (usize, usize) {
let mut results = 0usize;
let mut visited = 0usize;
if self.num_items == 0 {
return (0, 0);
}
let mut node_index = self.entries.len() - 1;
let mut level = self.level_bounds.len() - 1;
let mut stack: Vec<usize> = Vec::with_capacity(DEFAULT_SEARCH_STACK_CAPACITY);
loop {
let end = (node_index + self.node_size).min(self.level_bounds[level]);
let is_leaf = node_index < self.num_items;
for pos in node_index..end {
visited += 1;
let b = &self.entries[pos];
if !b.overlaps(query) {
continue;
}
let index = self.indices[pos];
if is_leaf {
results += 1;
} else {
stack.push(index);
stack.push(level - 1);
}
}
if stack.len() > 1 {
level = stack.pop().unwrap();
node_index = stack.pop().unwrap();
} else {
return (results, visited);
}
}
}
}
pub struct Index2DView<'a> {
node_size: usize,
num_items: usize,
num_nodes: usize,
level_count: usize,
level_bounds: Vec<usize>,
entries: &'a [u8],
indices: &'a [u8],
payload: Option<ParsedPayload<'a>>,
id_to_leaf: Option<Vec<u32>>,
}
impl<'a> Index2DView<'a> {
pub fn from_bytes(bytes: &'a [u8]) -> Result<Self, LoadError> {
let (parsed, payload) = parse_index(bytes, 2, 8)?;
let id_to_leaf = payload
.is_some()
.then(|| build_id_to_leaf(parsed.indices, parsed.num_items));
Ok(Self {
node_size: parsed.node_size,
num_items: parsed.num_items,
num_nodes: parsed.num_nodes,
level_count: parsed.level_count,
level_bounds: parsed.level_bounds,
entries: parsed.entries,
indices: parsed.indices,
payload,
id_to_leaf,
})
}
pub fn has_payload(&self) -> bool {
self.payload.is_some()
}
pub fn payload(&self, id: usize) -> Option<&'a [u8]> {
let payload = self.payload.as_ref()?;
let id_to_leaf = self.id_to_leaf.as_ref()?;
let leaf_rank = *id_to_leaf.get(id)? as usize;
Some(payload_slice(payload.offsets, payload.blobs, leaf_rank))
}
pub fn search_payloads(&self, query: Box2D) -> Vec<(usize, &'a [u8])> {
let mut out = Vec::new();
if self.payload.is_none() {
return out;
}
for id in self.search(query) {
if let Some(blob) = self.payload(id) {
out.push((id, blob));
}
}
out
}
pub fn num_items(&self) -> usize {
self.num_items
}
pub fn extent(&self) -> Option<Box2D> {
if self.num_items == 0 {
None
} else {
Some(self.entry_at_unchecked(self.num_nodes - 1))
}
}
pub fn node_size(&self) -> usize {
self.node_size
}
pub fn search(&self, query: Box2D) -> Vec<usize> {
let mut results = Vec::new();
self.search_into(query, &mut results);
results
}
pub fn search_into(&self, query: Box2D, results: &mut Vec<usize>) {
let mut stack: Vec<usize> = Vec::with_capacity(DEFAULT_SEARCH_STACK_CAPACITY);
self.search_into_stack(query, results, &mut stack);
}
pub fn search_with<'b>(&self, query: Box2D, workspace: &'b mut SearchWorkspace) -> &'b [usize] {
self.search_into_stack(query, &mut workspace.results, &mut workspace.stack);
&workspace.results
}
pub fn any(&self, query: Box2D) -> bool {
self.visit(query, |_| ControlFlow::Break(())).is_break()
}
pub fn first(&self, query: Box2D) -> Option<usize> {
match self.visit(query, ControlFlow::Break) {
ControlFlow::Break(index) => Some(index),
ControlFlow::Continue(()) => None,
}
}
pub fn neighbors(&self, point: Point2D, max_results: usize) -> Vec<usize> {
self.neighbors_within(point, max_results, f64::INFINITY)
}
pub fn neighbors_within(
&self,
point: Point2D,
max_results: usize,
max_distance: f64,
) -> Vec<usize> {
let mut results = Vec::new();
self.neighbors_into(point, max_results, max_distance, &mut results);
results
}
pub fn neighbors_into(
&self,
point: Point2D,
max_results: usize,
max_distance: f64,
results: &mut Vec<usize>,
) {
results.clear();
if max_results == 0 {
return;
}
if max_results == 1 {
let mut queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
if let Some(index) =
self.nearest_one_with_queue(NeighborQuery2D::Point(point), max_distance, &mut queue)
{
results.push(index);
}
return;
}
let mut item_queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
let mut node_queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
self.collect_neighbors_with_queues(
NeighborQuery2D::Point(point),
max_results,
max_distance,
results,
&mut item_queue,
&mut node_queue,
);
}
pub fn neighbors_with<'b>(
&self,
point: Point2D,
max_results: usize,
max_distance: f64,
workspace: &'b mut NeighborWorkspace,
) -> &'b [usize] {
workspace.results.clear();
if max_results == 0 {
workspace.queue.clear();
workspace.node_queue.clear();
return &workspace.results;
}
if max_results == 1 {
workspace.queue.clear();
if let Some(index) = self.nearest_one_with_queue(
NeighborQuery2D::Point(point),
max_distance,
&mut workspace.node_queue,
) {
workspace.results.push(index);
}
return &workspace.results;
}
self.collect_neighbors_with_queues(
NeighborQuery2D::Point(point),
max_results,
max_distance,
&mut workspace.results,
&mut workspace.queue,
&mut workspace.node_queue,
);
&workspace.results
}
pub fn visit_neighbors<B, F>(
&self,
point: Point2D,
max_distance: f64,
mut visitor: F,
) -> ControlFlow<B>
where
F: FnMut(usize, f64) -> ControlFlow<B>,
{
let mut queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
self.visit_neighbors_with_queue(
NeighborQuery2D::Point(point),
max_distance,
&mut queue,
&mut visitor,
)
}
pub fn neighbors_of_box(&self, query: Box2D, max_results: usize) -> Vec<usize> {
self.neighbors_of_box_within(query, max_results, f64::INFINITY)
}
pub fn neighbors_of_box_within(
&self,
query: Box2D,
max_results: usize,
max_distance: f64,
) -> Vec<usize> {
let mut results = Vec::new();
self.neighbors_of_box_into(query, max_results, max_distance, &mut results);
results
}
pub fn neighbors_of_box_into(
&self,
query: Box2D,
max_results: usize,
max_distance: f64,
results: &mut Vec<usize>,
) {
results.clear();
if max_results == 0 {
return;
}
if max_results == 1 {
let mut queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
if let Some(index) =
self.nearest_one_with_queue(NeighborQuery2D::Box(query), max_distance, &mut queue)
{
results.push(index);
}
return;
}
let mut item_queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
let mut node_queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
self.collect_neighbors_with_queues(
NeighborQuery2D::Box(query),
max_results,
max_distance,
results,
&mut item_queue,
&mut node_queue,
);
}
pub fn neighbors_of_box_with<'na>(
&self,
query: Box2D,
max_results: usize,
max_distance: f64,
workspace: &'na mut NeighborWorkspace,
) -> &'na [usize] {
workspace.results.clear();
if max_results == 0 {
workspace.queue.clear();
workspace.node_queue.clear();
return &workspace.results;
}
if max_results == 1 {
workspace.queue.clear();
if let Some(index) = self.nearest_one_with_queue(
NeighborQuery2D::Box(query),
max_distance,
&mut workspace.node_queue,
) {
workspace.results.push(index);
}
return &workspace.results;
}
self.collect_neighbors_with_queues(
NeighborQuery2D::Box(query),
max_results,
max_distance,
&mut workspace.results,
&mut workspace.queue,
&mut workspace.node_queue,
);
&workspace.results
}
pub fn visit_neighbors_of_box<B, F>(
&self,
query: Box2D,
max_distance: f64,
mut visitor: F,
) -> ControlFlow<B>
where
F: FnMut(usize, f64) -> ControlFlow<B>,
{
let mut queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
self.visit_neighbors_with_queue(
NeighborQuery2D::Box(query),
max_distance,
&mut queue,
&mut visitor,
)
}
pub fn visit<B, F>(&self, query: Box2D, visitor: F) -> ControlFlow<B>
where
F: FnMut(usize) -> ControlFlow<B>,
{
let mut stack: Vec<usize> = Vec::with_capacity(DEFAULT_SEARCH_STACK_CAPACITY);
self.visit_with_stack(query, &mut stack, visitor)
}
pub fn join(&self, other: &Index2DView<'_>) -> Vec<(usize, usize)> {
let mut out = Vec::new();
let _: ControlFlow<()> = self.join_with(other, |i, j| {
out.push((i, j));
ControlFlow::Continue(())
});
out
}
pub fn join_with<B, F>(&self, other: &Index2DView<'_>, visitor: F) -> ControlFlow<B>
where
F: FnMut(usize, usize) -> ControlFlow<B>,
{
join_core(self, other, visitor)
}
pub fn self_join(&self) -> Vec<(usize, usize)> {
let mut out = Vec::new();
let _: ControlFlow<()> = self.self_join_with(|i, j| {
out.push((i, j));
ControlFlow::Continue(())
});
out
}
pub fn self_join_with<B, F>(&self, visitor: F) -> ControlFlow<B>
where
F: FnMut(usize, usize) -> ControlFlow<B>,
{
self_join_core(self, visitor)
}
fn collect_neighbors_with_queues(
&self,
query: NeighborQuery2D,
max_results: usize,
max_distance: f64,
results: &mut Vec<usize>,
item_queue: &mut BinaryHeap<NeighborState>,
node_queue: &mut BinaryHeap<NeighborNodeState>,
) {
item_queue.clear();
node_queue.clear();
let Some(max_dist_sq) = max_distance_squared(max_distance) else {
return;
};
if self.num_items == 0 {
return;
}
let root_index = self.num_nodes - 1;
let root_dist = query.distance_squared_to(self.entry_at_unchecked(root_index));
if root_dist > max_dist_sq {
return;
}
node_queue.push(NeighborNodeState::new(root_index, root_dist));
while results.len() < max_results {
while let Some(&node) = node_queue.peek() {
if node.dist > max_dist_sq {
node_queue.clear();
break;
}
if item_queue.peek().is_some_and(|item| item.dist < node.dist) {
break;
}
let node = node_queue.pop().unwrap();
let upper_bound_level = self.upper_bound_level(node.index);
let end = (node.index + self.node_size)
.min(self.level_bound_unchecked(upper_bound_level));
let is_leaf = node.index < self.num_items;
if is_leaf {
for pos in node.index..end {
let b = self.entry_at_unchecked(pos);
let dist = query.distance_squared_to(b);
if dist <= max_dist_sq {
item_queue.push(NeighborState::new(
self.index_at_unchecked(pos),
true,
dist,
));
}
}
} else {
for pos in node.index..end {
let b = self.entry_at_unchecked(pos);
let dist = query.distance_squared_to(b);
if dist <= max_dist_sq {
node_queue
.push(NeighborNodeState::new(self.index_at_unchecked(pos), dist));
}
}
}
}
match item_queue.pop() {
Some(state) if state.dist <= max_dist_sq => results.push(state.index),
_ => return,
}
}
}
fn nearest_one_with_queue(
&self,
query: NeighborQuery2D,
max_distance: f64,
queue: &mut BinaryHeap<NeighborNodeState>,
) -> Option<usize> {
queue.clear();
let mut best_dist = max_distance_squared(max_distance)?;
if self.num_items == 0 {
return None;
}
let mut best_index = None;
let mut node_index = self.num_nodes - 1;
loop {
let upper_bound_level = self.upper_bound_level(node_index);
let end =
(node_index + self.node_size).min(self.level_bound_unchecked(upper_bound_level));
let is_leaf = node_index < self.num_items;
for pos in node_index..end {
let b = self.entry_at_unchecked(pos);
let dist = query.distance_squared_to(b);
if dist > best_dist {
continue;
}
if is_leaf {
if dist == 0.0 {
return Some(self.index_at_unchecked(pos));
}
best_dist = dist;
best_index = Some(self.index_at_unchecked(pos));
} else {
queue.push(NeighborNodeState::new(self.index_at_unchecked(pos), dist));
}
}
match queue.pop() {
Some(state) if state.dist <= best_dist => node_index = state.index,
_ => return best_index,
}
}
}
#[doc(hidden)]
pub fn search_into_stack(
&self,
query: Box2D,
results: &mut Vec<usize>,
stack: &mut Vec<usize>,
) {
results.clear();
stack.clear();
if self.num_items == 0 {
return;
}
let root = self.entry_at_unchecked(self.num_nodes - 1);
if query.contains(root) {
for pos in 0..self.num_items {
results.push(self.index_at_unchecked(pos));
}
return;
}
let mut node_index = self.num_nodes - 1;
let mut level = self.level_count - 1;
loop {
let end = (node_index + self.node_size).min(self.level_bound_unchecked(level));
let is_leaf = node_index < self.num_items;
if is_leaf {
for pos in node_index..end {
let b = self.entry_at_unchecked(pos);
if !b.overlaps(query) {
continue;
}
let index = self.index_at_unchecked(pos);
results.push(index);
}
} else {
let child_level = level - 1;
for pos in (node_index..end).rev() {
let b = self.entry_at_unchecked(pos);
if !b.overlaps(query) {
continue;
}
let index = self.index_at_unchecked(pos);
stack.push(index);
stack.push(child_level);
}
}
if stack.len() > 1 {
level = stack.pop().unwrap();
node_index = stack.pop().unwrap();
} else {
return;
}
}
}
#[doc(hidden)]
pub fn visit_with_stack<B, F>(
&self,
query: Box2D,
stack: &mut Vec<usize>,
mut visitor: F,
) -> ControlFlow<B>
where
F: FnMut(usize) -> ControlFlow<B>,
{
stack.clear();
if self.num_items == 0 {
return ControlFlow::Continue(());
}
let mut node_index = self.num_nodes - 1;
let mut level = self.level_count - 1;
loop {
let end = (node_index + self.node_size).min(self.level_bound_unchecked(level));
let is_leaf = node_index < self.num_items;
if is_leaf {
for pos in node_index..end {
let b = self.entry_at_unchecked(pos);
if !b.overlaps(query) {
continue;
}
let index = self.index_at_unchecked(pos);
visitor(index)?;
}
} else {
let child_level = level - 1;
for pos in (node_index..end).rev() {
let b = self.entry_at_unchecked(pos);
if !b.overlaps(query) {
continue;
}
let index = self.index_at_unchecked(pos);
stack.push(index);
stack.push(child_level);
}
}
if stack.len() > 1 {
level = stack.pop().unwrap();
node_index = stack.pop().unwrap();
} else {
return ControlFlow::Continue(());
}
}
}
fn visit_neighbors_with_queue<B, F>(
&self,
query: NeighborQuery2D,
max_distance: f64,
queue: &mut BinaryHeap<NeighborState>,
visitor: &mut F,
) -> ControlFlow<B>
where
F: FnMut(usize, f64) -> ControlFlow<B>,
{
queue.clear();
let Some(max_dist_sq) = max_distance_squared(max_distance) else {
return ControlFlow::Continue(());
};
if self.num_items == 0 {
return ControlFlow::Continue(());
}
let mut node_index = self.num_nodes - 1;
loop {
let upper_bound_level = self.upper_bound_level(node_index);
let end =
(node_index + self.node_size).min(self.level_bound_unchecked(upper_bound_level));
let is_leaf = node_index < self.num_items;
for pos in node_index..end {
let b = self.entry_at_unchecked(pos);
let dist = query.distance_squared_to(b);
if dist > max_dist_sq {
continue;
}
queue.push(NeighborState::new(
self.index_at_unchecked(pos),
is_leaf,
dist,
));
}
let mut continue_search = false;
while let Some(state) = queue.pop() {
if state.dist > max_dist_sq {
queue.clear();
return ControlFlow::Continue(());
}
if state.is_leaf {
visitor(state.index, state.dist)?;
} else {
node_index = state.index;
continue_search = true;
break;
}
}
if !continue_search {
return ControlFlow::Continue(());
}
}
}
fn upper_bound_level(&self, node_index: usize) -> usize {
let mut lo = 0usize;
let mut hi = self.level_count - 1;
while lo < hi {
let mid = (lo + hi) / 2;
if self.level_bound_unchecked(mid) > node_index {
hi = mid;
} else {
lo = mid + 1;
}
}
lo
}
#[inline]
fn level_bound_unchecked(&self, index: usize) -> usize {
self.level_bounds[index]
}
#[inline]
fn entry_at_unchecked(&self, index: usize) -> Box2D {
let offset = index * 32;
Box2D::new(
read_f64_le_unchecked(self.entries, offset),
read_f64_le_unchecked(self.entries, offset + 8),
read_f64_le_unchecked(self.entries, offset + 16),
read_f64_le_unchecked(self.entries, offset + 24),
)
}
#[inline]
fn index_at_unchecked(&self, index: usize) -> usize {
read_u64_le_unchecked(self.indices, index * 8) as usize
}
}
impl JoinTree for Index2D {
type Bounds = Box2D;
#[inline]
fn join_num_items(&self) -> usize {
self.num_items
}
#[inline]
fn join_num_nodes(&self) -> usize {
self.entries.len()
}
#[inline]
fn join_node_size(&self) -> usize {
self.node_size
}
#[inline]
fn join_level_count(&self) -> usize {
self.level_bounds.len()
}
#[inline]
fn join_level_bound(&self, level: usize) -> usize {
self.level_bounds[level]
}
#[inline]
fn join_bounds(&self, pos: usize) -> Box2D {
self.entries[pos]
}
#[inline]
fn join_index(&self, pos: usize) -> usize {
self.indices[pos]
}
#[inline]
fn bounds_overlap(a: Box2D, b: Box2D) -> bool {
a.overlaps(b)
}
#[inline]
fn bounds_contain(outer: Box2D, inner: Box2D) -> bool {
outer.contains(inner)
}
}
impl JoinTree for Index2DView<'_> {
type Bounds = Box2D;
#[inline]
fn join_num_items(&self) -> usize {
self.num_items
}
#[inline]
fn join_num_nodes(&self) -> usize {
self.num_nodes
}
#[inline]
fn join_node_size(&self) -> usize {
self.node_size
}
#[inline]
fn join_level_count(&self) -> usize {
self.level_count
}
#[inline]
fn join_level_bound(&self, level: usize) -> usize {
self.level_bound_unchecked(level)
}
#[inline]
fn join_bounds(&self, pos: usize) -> Box2D {
self.entry_at_unchecked(pos)
}
#[inline]
fn join_index(&self, pos: usize) -> usize {
self.index_at_unchecked(pos)
}
#[inline]
fn bounds_overlap(a: Box2D, b: Box2D) -> bool {
a.overlaps(b)
}
#[inline]
fn bounds_contain(outer: Box2D, inner: Box2D) -> bool {
outer.contains(inner)
}
}
impl Index2D {
pub fn raycast(&self, ray: Ray2D) -> Vec<usize> {
let mut results = Vec::new();
self.raycast_into(ray, &mut results);
results
}
pub fn raycast_into(&self, ray: Ray2D, results: &mut Vec<usize>) {
let mut stack = Vec::with_capacity(DEFAULT_SEARCH_STACK_CAPACITY);
self.raycast_into_stack(ray, results, &mut stack);
}
pub fn raycast_with<'a>(&self, ray: Ray2D, workspace: &'a mut SearchWorkspace) -> &'a [usize] {
self.raycast_into_stack(ray, &mut workspace.results, &mut workspace.stack);
&workspace.results
}
#[doc(hidden)]
pub fn raycast_into_stack(&self, ray: Ray2D, results: &mut Vec<usize>, stack: &mut Vec<usize>) {
results.clear();
stack.clear();
if self.num_items == 0 {
return;
}
let mut node_index = self.entries.len() - 1;
let mut level = self.level_bounds.len() - 1;
loop {
let end = (node_index + self.node_size).min(self.level_bounds[level]);
let is_leaf = node_index < self.num_items;
let node_entries = &self.entries[node_index..end];
let node_indices = &self.indices[node_index..end];
if is_leaf {
for (&bounds, &index) in node_entries.iter().zip(node_indices) {
if ray.intersects_box(bounds) {
results.push(index);
}
}
} else {
let child_level = level - 1;
for (&bounds, &index) in node_entries.iter().zip(node_indices).rev() {
if ray.intersects_box(bounds) {
stack.push(index);
stack.push(child_level);
}
}
}
if stack.len() > 1 {
level = stack.pop().unwrap();
node_index = stack.pop().unwrap();
} else {
return;
}
}
}
pub fn raycast_closest(&self, ray: Ray2D) -> Option<(usize, f64)> {
let mut workspace = NeighborWorkspace::new();
self.raycast_closest_with(ray, &mut workspace)
}
pub fn raycast_closest_with(
&self,
ray: Ray2D,
workspace: &mut NeighborWorkspace,
) -> Option<(usize, f64)> {
let queue = &mut workspace.node_queue;
queue.clear();
if self.num_items == 0 {
return None;
}
let root = self.entries.len() - 1;
let root_t = ray.enter_t(self.entries[root])?;
let mut best_t = ray.max_distance;
let mut best_index = None;
queue.push(NeighborNodeState::new(root, root_t));
while let Some(node) = queue.pop() {
if node.dist >= best_t {
break;
}
let upper = upper_bound_level(&self.level_bounds, node.index);
let end = (node.index + self.node_size).min(self.level_bounds[upper]);
let is_leaf = node.index < self.num_items;
for pos in node.index..end {
let Some(t) = ray.enter_t(self.entries[pos]) else {
continue;
};
if t >= best_t {
continue;
}
if is_leaf {
best_t = t;
best_index = Some(self.indices[pos]);
} else {
queue.push(NeighborNodeState::new(self.indices[pos], t));
}
}
}
best_index.map(|index| (index, best_t))
}
}
impl Index2D {
pub fn visit_raycast<B, F>(&self, ray: Ray2D, mut visitor: F) -> ControlFlow<B>
where
F: FnMut(usize, f64) -> ControlFlow<B>,
{
let mut queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
if self.num_items == 0 {
return ControlFlow::Continue(());
}
let mut node_index = self.entries.len() - 1;
loop {
let upper = upper_bound_level(&self.level_bounds, node_index);
let end = (node_index + self.node_size).min(self.level_bounds[upper]);
let is_leaf = node_index < self.num_items;
for pos in node_index..end {
if let Some(t) = ray.enter_t(self.entries[pos]) {
queue.push(NeighborState::new(self.indices[pos], is_leaf, t));
}
}
let mut continue_search = false;
while let Some(state) = queue.pop() {
if state.is_leaf {
visitor(state.index, state.dist)?;
} else {
node_index = state.index;
continue_search = true;
break;
}
}
if !continue_search {
return ControlFlow::Continue(());
}
}
}
}
impl Index2DView<'_> {
pub fn raycast(&self, ray: Ray2D) -> Vec<usize> {
let mut results = Vec::new();
self.raycast_into(ray, &mut results);
results
}
pub fn raycast_into(&self, ray: Ray2D, results: &mut Vec<usize>) {
let mut stack = Vec::with_capacity(DEFAULT_SEARCH_STACK_CAPACITY);
self.raycast_into_stack(ray, results, &mut stack);
}
pub fn raycast_with<'na>(
&self,
ray: Ray2D,
workspace: &'na mut SearchWorkspace,
) -> &'na [usize] {
self.raycast_into_stack(ray, &mut workspace.results, &mut workspace.stack);
&workspace.results
}
#[doc(hidden)]
pub fn raycast_into_stack(&self, ray: Ray2D, results: &mut Vec<usize>, stack: &mut Vec<usize>) {
results.clear();
stack.clear();
if self.num_items == 0 {
return;
}
let mut node_index = self.num_nodes - 1;
let mut level = self.level_count - 1;
loop {
let end = (node_index + self.node_size).min(self.level_bound_unchecked(level));
let is_leaf = node_index < self.num_items;
for pos in node_index..end {
if !ray.intersects_box(self.entry_at_unchecked(pos)) {
continue;
}
let index = self.index_at_unchecked(pos);
if is_leaf {
results.push(index);
} else {
stack.push(index);
stack.push(level - 1);
}
}
if stack.len() > 1 {
level = stack.pop().unwrap();
node_index = stack.pop().unwrap();
} else {
return;
}
}
}
pub fn raycast_closest(&self, ray: Ray2D) -> Option<(usize, f64)> {
let mut workspace = NeighborWorkspace::new();
self.raycast_closest_with(ray, &mut workspace)
}
pub fn raycast_closest_with(
&self,
ray: Ray2D,
workspace: &mut NeighborWorkspace,
) -> Option<(usize, f64)> {
let queue = &mut workspace.node_queue;
queue.clear();
if self.num_items == 0 {
return None;
}
let root = self.num_nodes - 1;
let root_t = ray.enter_t(self.entry_at_unchecked(root))?;
let mut best_t = ray.max_distance;
let mut best_index = None;
queue.push(NeighborNodeState::new(root, root_t));
while let Some(node) = queue.pop() {
if node.dist >= best_t {
break;
}
let node_index = node.index;
let upper = self.upper_bound_level(node_index);
let end = (node_index + self.node_size).min(self.level_bound_unchecked(upper));
let is_leaf = node_index < self.num_items;
for pos in node_index..end {
let Some(t) = ray.enter_t(self.entry_at_unchecked(pos)) else {
continue;
};
if t >= best_t {
continue;
}
if is_leaf {
best_t = t;
best_index = Some(self.index_at_unchecked(pos));
} else {
queue.push(NeighborNodeState::new(self.index_at_unchecked(pos), t));
}
}
}
best_index.map(|index| (index, best_t))
}
pub fn visit_raycast<B, F>(&self, ray: Ray2D, mut visitor: F) -> ControlFlow<B>
where
F: FnMut(usize, f64) -> ControlFlow<B>,
{
let mut queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
if self.num_items == 0 {
return ControlFlow::Continue(());
}
let mut node_index = self.num_nodes - 1;
loop {
let upper = self.upper_bound_level(node_index);
let end = (node_index + self.node_size).min(self.level_bound_unchecked(upper));
let is_leaf = node_index < self.num_items;
for pos in node_index..end {
if let Some(t) = ray.enter_t(self.entry_at_unchecked(pos)) {
queue.push(NeighborState::new(self.index_at_unchecked(pos), is_leaf, t));
}
}
let mut continue_search = false;
while let Some(state) = queue.pop() {
if state.is_leaf {
visitor(state.index, state.dist)?;
} else {
node_index = state.index;
continue_search = true;
break;
}
}
if !continue_search {
return ControlFlow::Continue(());
}
}
}
}
pub struct Search2DIter<'a> {
index: &'a Index2D,
query: Box2D,
stack: Vec<usize>,
leaf_pos: usize,
leaf_end: usize,
}
impl<'a> Search2DIter<'a> {
fn new(index: &'a Index2D, query: Box2D) -> Self {
let mut stack = Vec::with_capacity(DEFAULT_SEARCH_STACK_CAPACITY);
if index.num_items != 0 {
stack.push(index.entries.len() - 1);
stack.push(index.level_bounds.len() - 1);
}
Self {
index,
query,
stack,
leaf_pos: 0,
leaf_end: 0,
}
}
}
impl Iterator for Search2DIter<'_> {
type Item = usize;
fn next(&mut self) -> Option<usize> {
let index = self.index;
loop {
while self.leaf_pos < self.leaf_end {
let at = self.leaf_pos;
self.leaf_pos += 1;
if index.entries[at].overlaps(self.query) {
return Some(index.indices[at]);
}
}
if self.stack.len() < 2 {
return None;
}
let level = self.stack.pop().unwrap();
let node_index = self.stack.pop().unwrap();
let end = (node_index + index.node_size).min(index.level_bounds[level]);
if node_index < index.num_items {
self.leaf_pos = node_index;
self.leaf_end = end;
} else {
let child_level = level - 1;
for (b, &child) in index.entries[node_index..end]
.iter()
.zip(&index.indices[node_index..end])
.rev()
{
if b.overlaps(self.query) {
self.stack.push(child);
self.stack.push(child_level);
}
}
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(self.index.num_items))
}
}
impl std::iter::FusedIterator for Search2DIter<'_> {}
pub struct Serializer2D<'a> {
index: &'a Index2D,
interleaved: bool,
payloads: Option<Vec<&'a [u8]>>,
meta: MetaFields<'a>,
}
impl<'a> Serializer2D<'a> {
fn new(index: &'a Index2D) -> Self {
Self {
index,
interleaved: false,
payloads: None,
meta: MetaFields::default(),
}
}
pub fn payloads<P: AsRef<[u8]>>(mut self, payloads: &'a [P]) -> Self {
self.payloads = Some(payloads.iter().map(|p| p.as_ref()).collect());
self
}
#[cfg(feature = "stream")]
pub fn interleaved(mut self) -> Self {
self.interleaved = true;
self
}
pub fn crs(mut self, crs: &'a str) -> Self {
self.meta.crs = Some(crs);
self
}
pub fn content_type(mut self, content_type: &'a str) -> Self {
self.meta.content_type = Some(content_type);
self
}
pub fn attribution(mut self, attribution: &'a str) -> Self {
self.meta.attribution = Some(attribution);
self
}
pub fn to_bytes(self) -> Result<Vec<u8>, PayloadError> {
let mut out = Vec::new();
self.to_bytes_into(&mut out)?;
Ok(out)
}
pub fn to_bytes_into(self, out: &mut Vec<u8>) -> Result<(), PayloadError> {
let idx = self.index;
let interleaved = self.interleaved;
write_index_container(
out,
2,
8,
interleaved,
idx.num_items,
idx.entries.len(),
idx.node_size,
|bytes| {
#[cfg(feature = "stream")]
if interleaved {
bytes.write_interleaved_2d(&idx.entries, &idx.indices);
return;
}
bytes.write_box2d_slice(&idx.entries);
bytes.write_usize_slice_as_u64(&idx.indices);
},
self.payloads.as_deref(),
&idx.indices[..idx.num_items],
&self.meta,
)
}
}