use core::fmt::Debug;
use nalgebra as na;
use serde_derive::Deserialize;
use serde_derive::Serialize;
use std::collections::HashSet;
use std::hash::{Hash, Hasher};
pub(crate) trait CoordinateSpace {
type Coordinate;
}
impl<T: na::Scalar> CoordinateSpace for na::Point3<T> {
type Coordinate = na::Point3<T>;
}
impl<T: na::Scalar> CoordinateSpace for na::Vector3<T> {
type Coordinate = na::Vector3<T>;
}
#[derive(Eq, Copy, Clone, Debug, Serialize, Deserialize)]
pub(crate) struct Boundary<T: PartialEq>(pub T, pub T);
impl<T: PartialEq> PartialEq for Boundary<T> {
fn eq(&self, other: &Boundary<T>) -> bool {
(self.0 == other.0 && self.1 == other.1) || (self.0 == other.1 && self.1 == other.0)
}
}
impl<T: Hash + Eq + PartialOrd> Hash for Boundary<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
if self.0 < self.1 {
self.0.hash(state);
self.1.hash(state);
} else {
self.1.hash(state);
self.0.hash(state);
}
}
}
pub(crate) trait Tiling<T, V, S>
where
T: Eq + Hash,
V: Eq + Hash + PartialOrd,
S: CoordinateSpace,
{
fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = &T> + 'a>;
fn adjacent(&self, tile: &T) -> Vec<(Boundary<V>, Option<&T>)>;
fn vertex_position(&self, vertex: &V) -> S::Coordinate;
fn tile_position(&self, tile: &T) -> S::Coordinate;
fn adjacent_any(&self, tiles: &[&T]) -> Vec<(Boundary<V>, Option<&T>)> {
let mut result = HashSet::new();
for node in tiles {
let adjacent = self.adjacent(node);
result.extend(adjacent);
}
result
.into_iter()
.filter(|(_boundary, node)| match node {
Some(node) => !tiles.contains(node),
None => true,
})
.collect()
}
}