Skip to main content

runmat_meshing_core/quality/spatial_index/
linear.rs

1use serde::{Deserialize, Serialize};
2
3use crate::quality::predicate::{distance_squared, Point3};
4
5use super::types::{Aabb3, SpatialEntry};
6
7#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8pub struct LinearSpatialIndex<T> {
9    entries: Vec<SpatialEntry<T>>,
10}
11
12impl<T> Default for LinearSpatialIndex<T> {
13    fn default() -> Self {
14        Self {
15            entries: Vec::new(),
16        }
17    }
18}
19
20impl<T> LinearSpatialIndex<T> {
21    pub fn new() -> Self {
22        Self::default()
23    }
24
25    pub fn with_entries(entries: Vec<SpatialEntry<T>>) -> Self {
26        Self { entries }
27    }
28
29    pub fn insert(&mut self, bounds: Aabb3, payload: T) {
30        self.entries.push(SpatialEntry { bounds, payload });
31    }
32
33    pub fn len(&self) -> usize {
34        self.entries.len()
35    }
36
37    pub fn is_empty(&self) -> bool {
38        self.entries.is_empty()
39    }
40
41    pub fn entries(&self) -> &[SpatialEntry<T>] {
42        &self.entries
43    }
44
45    pub fn query_point(&self, point: Point3) -> impl Iterator<Item = &SpatialEntry<T>> {
46        self.entries
47            .iter()
48            .filter(move |entry| entry.bounds.contains_point(point))
49    }
50
51    pub fn query_bounds(&self, bounds: Aabb3) -> impl Iterator<Item = &SpatialEntry<T>> {
52        self.entries
53            .iter()
54            .filter(move |entry| entry.bounds.intersects(bounds))
55    }
56
57    pub fn nearest_by_center(&self, point: Point3) -> Option<&SpatialEntry<T>> {
58        self.entries.iter().min_by(|left, right| {
59            distance_squared(left.bounds.center_m(), point)
60                .total_cmp(&distance_squared(right.bounds.center_m(), point))
61        })
62    }
63}