runmat_meshing_core/quality/spatial_index/
linear.rs1use 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}