use super::{AsCell, CellId, PointId};
use crate::shapes::GeoKind;
use russell_lab::sort4;
use std::collections::{HashMap, HashSet};
use std::fmt;
pub type FaceKey = (usize, usize, usize, usize);
#[derive(Clone, Debug)]
pub struct Face {
pub kind: GeoKind,
pub points: Vec<PointId>,
pub marker: i32,
}
impl Face {
pub fn key(&self) -> FaceKey {
let mut key = if self.points.len() > 3 {
(self.points[0], self.points[1], self.points[2], self.points[3])
} else {
(self.points[0], self.points[1], self.points[2], usize::MAX)
};
sort4(&mut key);
key
}
}
#[derive(Clone, Debug)]
pub struct Faces<'a> {
pub all: Vec<&'a Face>,
}
pub type MapFaceToCells = HashMap<FaceKey, Vec<(CellId, usize)>>;
pub type MapPointToFaces = HashMap<PointId, HashSet<FaceKey>>;
impl<'a> Faces<'a> {
pub fn all_points(&self) -> Vec<PointId> {
let mut points_set = HashSet::new();
for face in &self.all {
for &point in &face.points {
points_set.insert(point);
}
}
let mut points: Vec<_> = points_set.into_iter().collect();
points.sort();
points
}
}
impl AsCell for Face {
fn kind(&self) -> GeoKind {
self.kind
}
fn marker(&self) -> i32 {
self.marker
}
fn points(&self) -> &[PointId] {
&self.points
}
}
impl fmt::Display for Face {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.points.len() == 3 {
let (a, b, c, _) = self.key();
write!(f, "({}, {}, {}, MAX)", a, b, c).unwrap();
} else {
write!(f, "{:?}", self.key()).unwrap();
}
Ok(())
}
}
impl<'a> fmt::Display for Faces<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for i in 0..self.all.len() {
if i > 0 {
write!(f, ", ").unwrap();
}
write!(f, "{}", self.all[i]).unwrap();
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::{Face, Faces};
use crate::shapes::GeoKind;
#[rustfmt::skip]
fn generate_sample_1() -> Vec<Face> {
vec![
Face { kind: GeoKind::Tri3, points: vec![1, 2, 3], marker: 0 },
Face { kind: GeoKind::Tri3, points: vec![4, 5, 6], marker: 0 },
]
}
#[rustfmt::skip]
fn generate_sample_2() -> Vec<Face> {
vec![
Face { kind: GeoKind::Qua4, points: vec![1, 2, 3, 4], marker: 0 },
Face { kind: GeoKind::Qua4, points: vec![2, 5, 6, 3], marker: 0 },
Face { kind: GeoKind::Tri6, points: vec![7, 8, 9, 10, 11, 12], marker: 0 },
]
}
#[test]
fn all_points_works() {
let empty = Faces { all: vec![] };
assert!(empty.all_points().is_empty());
let all = generate_sample_1();
let single = Faces { all: vec![&all[0]] };
assert_eq!(single.all_points(), vec![1, 2, 3]);
let two_faces = Faces {
all: vec![&all[0], &all[1]],
};
assert_eq!(two_faces.all_points(), vec![1, 2, 3, 4, 5, 6]);
let all2 = generate_sample_2();
let mixed = Faces {
all: vec![&all2[0], &all2[1]],
};
assert_eq!(mixed.all_points(), vec![1, 2, 3, 4, 5, 6]);
let higher_order = Faces { all: vec![&all2[2]] };
assert_eq!(higher_order.all_points(), vec![7, 8, 9, 10, 11, 12]);
let all_faces = Faces {
all: vec![&all2[0], &all2[1], &all2[2]],
};
assert_eq!(all_faces.all_points(), vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
}
}