#![forbid(unsafe_code)]
use crate::core::collections::{
FastHashMap, MAX_PRACTICAL_DIMENSION_SIZE, SmallBuffer, VertexToSimplicesMap,
};
use crate::core::edge::EdgeKey;
use crate::core::tds::{SimplexKey, VertexKey};
use thiserror::Error;
#[derive(Clone, Debug, Error, PartialEq, Eq)]
#[non_exhaustive]
pub enum AdjacencyIndexBuildError {
#[error("Simplex {simplex_key:?} references missing vertex key {vertex_key:?}")]
MissingVertexKey {
simplex_key: SimplexKey,
vertex_key: VertexKey,
},
#[error("Simplex {simplex_key:?} references missing neighbor simplex {neighbor_key:?}")]
MissingNeighborSimplex {
simplex_key: SimplexKey,
neighbor_key: SimplexKey,
},
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct AdjacencyIndex {
pub vertex_to_edges: FastHashMap<VertexKey, SmallBuffer<EdgeKey, MAX_PRACTICAL_DIMENSION_SIZE>>,
pub vertex_to_simplices: VertexToSimplicesMap,
pub simplex_to_neighbors:
FastHashMap<SimplexKey, SmallBuffer<SimplexKey, MAX_PRACTICAL_DIMENSION_SIZE>>,
}
impl AdjacencyIndex {
#[must_use = "this iterator is lazy and does nothing unless consumed"]
#[inline]
pub fn adjacent_simplices(&self, v: VertexKey) -> impl Iterator<Item = SimplexKey> + '_ {
self.vertex_to_simplices
.get(&v)
.into_iter()
.flat_map(|simplices| simplices.iter().copied())
}
#[must_use]
#[inline]
pub fn number_of_adjacent_simplices(&self, v: VertexKey) -> usize {
self.vertex_to_simplices.get(&v).map_or(0, SmallBuffer::len)
}
#[must_use = "this iterator is lazy and does nothing unless consumed"]
#[inline]
pub fn incident_edges(&self, v: VertexKey) -> impl Iterator<Item = EdgeKey> + '_ {
self.vertex_to_edges
.get(&v)
.into_iter()
.flat_map(|edges| edges.iter().copied())
}
#[must_use]
#[inline]
pub fn number_of_incident_edges(&self, v: VertexKey) -> usize {
self.vertex_to_edges.get(&v).map_or(0, SmallBuffer::len)
}
#[must_use = "this iterator is lazy and does nothing unless consumed"]
#[inline]
pub fn simplex_neighbors(&self, c: SimplexKey) -> impl Iterator<Item = SimplexKey> + '_ {
self.simplex_to_neighbors
.get(&c)
.into_iter()
.flat_map(|neighbors| neighbors.iter().copied())
}
#[must_use]
#[inline]
pub fn number_of_simplex_neighbors(&self, c: SimplexKey) -> usize {
self.simplex_to_neighbors
.get(&c)
.map_or(0, SmallBuffer::len)
}
#[must_use = "this iterator is lazy and does nothing unless consumed"]
pub fn edges(&self) -> impl Iterator<Item = EdgeKey> + '_ {
self.vertex_to_edges.iter().flat_map(|(vk, edges)| {
let vk = *vk;
edges.iter().copied().filter(move |edge| edge.v0() == vk)
})
}
#[must_use]
pub fn number_of_edges(&self) -> usize {
self.edges().count()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::DelaunayTriangulation;
use crate::vertex;
use slotmap::SlotMap;
use std::collections::HashSet;
#[test]
fn adjacency_index_build_error_display_is_informative() {
let mut vertices: SlotMap<VertexKey, ()> = SlotMap::with_key();
let mut simplices: SlotMap<SimplexKey, ()> = SlotMap::with_key();
let vk = vertices.insert(());
let ck = simplices.insert(());
let err = AdjacencyIndexBuildError::MissingVertexKey {
simplex_key: ck,
vertex_key: vk,
};
let msg = err.to_string();
assert!(msg.contains("references missing vertex key"));
let err = AdjacencyIndexBuildError::MissingNeighborSimplex {
simplex_key: ck,
neighbor_key: ck,
};
let msg = err.to_string();
assert!(msg.contains("references missing neighbor simplex"));
}
#[test]
fn adjacency_index_is_send_sync_unpin() {
fn assert_auto_traits<T: Send + Sync + Unpin>() {}
assert_auto_traits::<AdjacencyIndex>();
}
#[test]
fn adjacency_index_query_helpers_are_consistent() {
let vertices: Vec<_> = vec![
vertex!([0.0, 0.0, 0.0]),
vertex!([2.0, 0.0, 0.0]),
vertex!([1.0, 2.0, 0.0]),
vertex!([1.0, 0.7, 1.5]),
vertex!([1.0, 0.7, -1.5]),
];
let dt: DelaunayTriangulation<_, (), (), 3> =
DelaunayTriangulation::new(&vertices).unwrap();
let tri = dt.as_triangulation();
let index = tri.build_adjacency_index().unwrap();
let shared_vertex_key = tri
.vertices()
.find_map(|(vk, _)| (tri.vertex_coords(vk)? == [0.0, 0.0, 0.0]).then_some(vk))
.unwrap();
assert_eq!(
index.adjacent_simplices(shared_vertex_key).count(),
index.number_of_adjacent_simplices(shared_vertex_key)
);
assert_eq!(
index.incident_edges(shared_vertex_key).count(),
index.number_of_incident_edges(shared_vertex_key)
);
assert!(index.number_of_incident_edges(shared_vertex_key) > 0);
let simplex_keys: Vec<_> = tri.simplices().map(|(ck, _)| ck).collect();
for &ck in &simplex_keys {
assert_eq!(
index.simplex_neighbors(ck).count(),
index.number_of_simplex_neighbors(ck)
);
assert_eq!(index.number_of_simplex_neighbors(ck), 1);
}
let edges: HashSet<_> = index.edges().collect();
assert_eq!(edges.len(), index.number_of_edges());
assert!(edges.iter().all(|e| e.v0() <= e.v1()));
assert_eq!(index.adjacent_simplices(VertexKey::default()).count(), 0);
assert_eq!(index.number_of_adjacent_simplices(VertexKey::default()), 0);
assert_eq!(index.incident_edges(VertexKey::default()).count(), 0);
assert_eq!(index.number_of_incident_edges(VertexKey::default()), 0);
assert_eq!(index.simplex_neighbors(SimplexKey::default()).count(), 0);
assert_eq!(index.number_of_simplex_neighbors(SimplexKey::default()), 0);
}
}