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 = (R3Key, R3Key);
pub(super) fn geo_edge_key(a: &R3, b: &R3) -> GeoEdgeKey {
if a <= b {
(R3Key(a.clone()), R3Key(b.clone()))
} else {
(R3Key(b.clone()), R3Key(a.clone()))
}
}
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(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
}
}
}
}