runmat-meshing-core 0.6.0

Deterministic meshing preparation contracts for RunMat
Documentation
use serde::{Deserialize, Serialize};

use crate::quality::predicate::{distance_squared, Point3};

use super::types::{Aabb3, SpatialEntry};

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct LinearSpatialIndex<T> {
    entries: Vec<SpatialEntry<T>>,
}

impl<T> Default for LinearSpatialIndex<T> {
    fn default() -> Self {
        Self {
            entries: Vec::new(),
        }
    }
}

impl<T> LinearSpatialIndex<T> {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn with_entries(entries: Vec<SpatialEntry<T>>) -> Self {
        Self { entries }
    }

    pub fn insert(&mut self, bounds: Aabb3, payload: T) {
        self.entries.push(SpatialEntry { bounds, payload });
    }

    pub fn len(&self) -> usize {
        self.entries.len()
    }

    pub fn is_empty(&self) -> bool {
        self.entries.is_empty()
    }

    pub fn entries(&self) -> &[SpatialEntry<T>] {
        &self.entries
    }

    pub fn query_point(&self, point: Point3) -> impl Iterator<Item = &SpatialEntry<T>> {
        self.entries
            .iter()
            .filter(move |entry| entry.bounds.contains_point(point))
    }

    pub fn query_bounds(&self, bounds: Aabb3) -> impl Iterator<Item = &SpatialEntry<T>> {
        self.entries
            .iter()
            .filter(move |entry| entry.bounds.intersects(bounds))
    }

    pub fn nearest_by_center(&self, point: Point3) -> Option<&SpatialEntry<T>> {
        self.entries.iter().min_by(|left, right| {
            distance_squared(left.bounds.center_m(), point)
                .total_cmp(&distance_squared(right.bounds.center_m(), point))
        })
    }
}