use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
use crate::linalg::Vec3;
use super::exact::rational::{r3_eq, R3, R3Key};
pub type EdgeKey = (u32, u32);
pub fn edge_key(a: u32, b: u32) -> EdgeKey {
if a <= b {
(a, b)
} else {
(b, a)
}
}
pub(super) type GeoEdgeKey = (u32, u32);
pub(super) fn geo_edge_key(a: u32, b: u32) -> GeoEdgeKey {
if a <= b {
(a, b)
} else {
(b, a)
}
}
pub(super) type BitEdgeKey = ([u64; 3], [u64; 3]);
pub(super) fn bit_edge_key(a: Vec3, b: Vec3) -> BitEdgeKey {
let (ka, kb) = (f64_key(a), f64_key(b));
if ka <= kb {
(ka, kb)
} else {
(kb, ka)
}
}
#[derive(Default)]
pub(super) struct PointTable {
map: HashMap<R3Key, u32>,
}
impl PointTable {
pub(super) fn intern(&mut self, p: &R3) -> u32 {
let next = self.map.len() as u32;
match self.map.entry(R3Key(p.clone())) {
std::collections::hash_map::Entry::Occupied(e) => *e.get(),
std::collections::hash_map::Entry::Vacant(e) => {
e.insert(next);
next
}
}
}
pub(super) fn len(&self) -> usize {
self.map.len()
}
pub(super) fn resolve(&self) -> Vec<&R3> {
let mut pts: Vec<Option<&R3>> = vec![None; self.map.len()];
for (k, &id) in &self.map {
pts[id as usize] = Some(&k.0);
}
pts.into_iter()
.map(|p| p.expect("ids are dense in 0..len"))
.collect()
}
}
#[derive(Clone, Copy, Debug)]
pub struct Piece {
pub mesh: u8,
pub tri: usize,
pub vi: [u32; 3],
}
pub struct IntersectionGraph {
pub pieces: Vec<Piece>,
pub verts: Vec<R3>,
pub verts_f64: Vec<Vec3>,
pub isect_edges: HashSet<EdgeKey>,
pub any_intersections: bool,
}
impl IntersectionGraph {
pub fn piece_verts(&self, pi: usize) -> [&R3; 3] {
let vi = self.pieces[pi].vi;
[
&self.verts[vi[0] as usize],
&self.verts[vi[1] as usize],
&self.verts[vi[2] as usize],
]
}
}
#[derive(Default)]
pub struct VertInterner {
map: HashMap<R3Key, u32>,
fmap: HashMap<[u64; 3], u32>,
pub verts: Vec<R3>,
pub verts_f64: Vec<Vec3>,
}
pub(super) fn f64_key(v: Vec3) -> [u64; 3] {
let norm = |x: f64| if x == 0.0 { 0.0f64 } else { x }.to_bits();
[norm(v.x), norm(v.y), norm(v.z)]
}
impl VertInterner {
pub fn intern_f64(&mut self, v: Vec3) -> u32 {
let key = f64_key(v);
if let Some(&id) = self.fmap.get(&key) {
return id;
}
let id = self.verts.len() as u32;
self.fmap.insert(key, id);
self.verts.push(R3::from_vec3(v));
self.verts_f64.push(v);
id
}
pub fn intern(&mut self, p: &R3) -> u32 {
let rounded = p.to_vec3_rounded();
if r3_eq(&R3::from_vec3(rounded), p) {
return self.intern_f64(rounded);
}
let next = self.verts.len() as u32;
match self.map.entry(R3Key(p.clone())) {
std::collections::hash_map::Entry::Occupied(e) => *e.get(),
std::collections::hash_map::Entry::Vacant(e) => {
e.insert(next);
self.verts.push(p.clone());
self.verts_f64.push(rounded);
next
}
}
}
}