use crate::Vec3;
use rustc_hash::FxHashMap as HashMap;
pub fn canonical_bits(value: f64) -> u64 {
if value == 0.0 {
0
} else {
value.to_bits()
}
}
fn cell(point: Vec3, tolerance: f64) -> [i64; 3] {
let size = 2.0 * tolerance;
[
(point.x / size).floor() as i64,
(point.y / size).floor() as i64,
(point.z / size).floor() as i64,
]
}
pub(crate) fn weld_vertex(
point: Vec3,
tolerance: f64,
vertices: &mut Vec<Vec3>,
buckets: &mut HashMap<[i64; 3], Vec<usize>>,
) -> usize {
let key = cell(point, tolerance);
let mut matched: Option<usize> = None;
for dx in -1..=1 {
for dy in -1..=1 {
for dz in -1..=1 {
if let Some(indices) = buckets.get(&[key[0] + dx, key[1] + dy, key[2] + dz]) {
if let Some(index) = indices
.iter()
.copied()
.find(|index| vertices[*index].sub(point).length() <= tolerance)
{
matched = Some(matched.map_or(index, |current| current.min(index)));
}
}
}
}
}
if let Some(index) = matched {
return index;
}
let index = vertices.len();
vertices.push(point);
buckets.entry(key).or_default().push(index);
index
}
#[derive(Clone, Debug, Default)]
pub struct VertexWeld {
tolerance: f64,
vertices: Vec<Vec3>,
buckets: HashMap<[i64; 3], Vec<usize>>,
}
impl VertexWeld {
pub fn new(tolerance: f64) -> Self {
Self {
tolerance,
..Self::default()
}
}
pub fn weld(&mut self, point: [f64; 3]) -> usize {
weld_vertex(
Vec3::new(point[0], point[1], point[2]),
self.tolerance,
&mut self.vertices,
&mut self.buckets,
)
}
pub fn vertex(&self, index: usize) -> [f64; 3] {
let v = self.vertices[index];
[v.x, v.y, v.z]
}
pub fn len(&self) -> usize {
self.vertices.len()
}
pub fn is_empty(&self) -> bool {
self.vertices.is_empty()
}
}
pub(crate) fn edge_key(first: usize, second: usize) -> (usize, usize) {
if first < second {
(first, second)
} else {
(second, first)
}
}