pub(super) fn weld_near_coincident_2d(
ring: &[nalgebra::Point2<f64>],
) -> Vec<nalgebra::Point2<f64>> {
let n = ring.len();
if n < 4 {
return ring.to_vec();
}
let (mut minx, mut miny, mut maxx, mut maxy) = (f64::MAX, f64::MAX, f64::MIN, f64::MIN);
for p in ring {
minx = minx.min(p.x);
miny = miny.min(p.y);
maxx = maxx.max(p.x);
maxy = maxy.max(p.y);
}
let extent = (maxx - minx).max(maxy - miny);
if !extent.is_finite() || extent <= 0.0 {
return ring.to_vec();
}
let eps = (floor_pow2(extent) * 2.0_f64.powi(-13)).min(2.0_f64.powi(-12));
let eps2 = eps * eps;
let mut kept: Vec<nalgebra::Point2<f64>> = Vec::with_capacity(n);
for &p in ring {
let dup = kept.last().is_some_and(|q| {
let dx = p.x - q.x;
let dy = p.y - q.y;
dx * dx + dy * dy < eps2
});
if !dup {
kept.push(p);
}
}
if kept.len() >= 2 {
let (first, last) = (kept[0], *kept.last().unwrap());
let dx = last.x - first.x;
let dy = last.y - first.y;
if dx * dx + dy * dy < eps2 {
kept.pop();
}
}
if kept.len() >= 3 {
kept
} else {
ring.to_vec()
}
}
pub(super) fn simplify_2d_collinear(ring: &[nalgebra::Point2<f64>]) -> Vec<nalgebra::Point2<f64>> {
let n = ring.len();
if n < 4 {
return ring.to_vec();
}
let mut keep = vec![true; n];
let mut changed = true;
while changed {
changed = false;
for i in 0..n {
if !keep[i] {
continue;
}
let prev = (1..n).map(|k| (i + n - k) % n).find(|&k| keep[k]);
let next = (1..n).map(|k| (i + k) % n).find(|&k| keep[k]);
let (prev, next) = match (prev, next) {
(Some(p), Some(n)) if p != i && n != i && p != n => (p, n),
_ => continue,
};
let a = ring[prev];
let b = ring[i];
let c = ring[next];
let e1x = b.x - a.x;
let e1y = b.y - a.y;
let e2x = c.x - b.x;
let e2y = c.y - b.y;
let cross = e1x * e2y - e1y * e2x;
let len1 = (e1x * e1x + e1y * e1y).sqrt();
let len2 = (e2x * e2x + e2y * e2y).sqrt();
let denom = len1 * len2;
if denom < 1.0e-18 || (cross.abs() / denom) < 1.0e-4 {
keep[i] = false;
changed = true;
}
}
}
ring.iter()
.zip(keep.iter())
.filter_map(|(p, k)| if *k { Some(*p) } else { None })
.collect()
}
pub(super) fn floor_pow2(x: f64) -> f64 {
if !x.is_finite() || x <= 0.0 {
return 0.0;
}
let exp = x.to_bits() >> 52 & 0x7ff; let unbiased = exp as i64 - 1023;
2.0_f64.powi(unbiased as i32)
}