axiolid_spatial/
index.rs

1//! Zero-allocation spatial index query contract.
2
3use core::ops::ControlFlow;
4
5use axiolid_core::{Aabb, Ray3, Scalar};
6
7/// Key and bounds supplied to an index builder.
8#[derive(Debug, Clone, PartialEq)]
9pub struct SpatialItem<K> {
10    /// Caller-owned identity.
11    pub key: K,
12    /// Broad-phase bounds.
13    pub bounds: Aabb,
14}
15
16impl<K> SpatialItem<K> {
17    /// Construct one caller-keyed broad-phase item.
18    pub const fn new(key: K, bounds: Aabb) -> Self {
19        Self { key, bounds }
20    }
21}
22
23/// Ray hit returned in ascending distance order where supported.
24#[derive(Debug, Clone, PartialEq)]
25pub struct RayHit<K> {
26    /// Caller key.
27    pub key: K,
28    /// Nonnegative ray parameter.
29    pub distance: Scalar,
30}
31
32/// Read-only broad-phase query API. Callback visitation avoids allocating a
33/// result vector for large clash batches.
34pub trait SpatialIndex<K>: core::fmt::Debug + Send + Sync {
35    /// Visit keys whose stored bounds overlap `query`. Returning `Break` stops.
36    fn visit_aabb(&self, query: &Aabb, visitor: &mut dyn FnMut(&K) -> ControlFlow<()>);
37
38    /// Visit broad-phase ray candidates.
39    fn visit_ray(&self, ray: &Ray3, visitor: &mut dyn FnMut(RayHit<&K>) -> ControlFlow<()>);
40
41    /// Number of indexed items.
42    fn len(&self) -> usize;
43
44    /// Whether no items are indexed.
45    fn is_empty(&self) -> bool {
46        self.len() == 0
47    }
48}