use super::classify::dot3;
pub(super) fn coincident_planes(n_own: [f64; 3], n_face: [f64; 3]) -> bool {
let (a, b) = (pow2_normalized(n_own), pow2_normalized(n_face));
let d = dot3(a, b);
2.0 * d * d >= dot3(a, a) * dot3(b, b)
}
fn pow2_normalized(n: [f64; 3]) -> [f64; 3] {
let m = n[0].abs().max(n[1].abs()).max(n[2].abs());
if m == 0.0 || !m.is_finite() {
return n;
}
let e = (m.to_bits() >> 52) & 0x7ff;
let s = f64::from_bits((2046 - e).max(1) << 52);
[n[0] * s, n[1] * s, n[2] * s]
}
#[cfg(test)]
mod tests {
use super::coincident_planes;
use crate::kernel::arrangement::classify::{cross3, sub_f64};
fn tilted(deg: f64) -> [f64; 3] {
let r = deg.to_radians();
[r.sin(), 0.0, r.cos()]
}
#[test]
fn parallel_and_antiparallel_faces_are_coincident_and_perpendicular_ones_are_not() {
let z = [0.0, 0.0, 1.0];
assert!(coincident_planes(z, [0.0, 0.0, 3.5]));
assert!(coincident_planes(z, [0.0, 0.0, -0.25]));
assert!(!coincident_planes(z, [1.0, 0.0, 0.0]));
assert!(!coincident_planes(z, [0.0, -2.0, 0.0]));
}
#[test]
fn the_cutoff_is_45_degrees_and_independent_of_either_magnitude() {
for s in [1.0e-8, 1.0, 1.0e8] {
let z = [0.0, 0.0, s];
assert!(coincident_planes(z, tilted(44.0)), "44° at scale {s}");
assert!(!coincident_planes(z, tilted(46.0)), "46° at scale {s}");
assert!(!coincident_planes(z, tilted(58.0)), "58° at scale {s}");
}
}
#[test]
fn the_verdict_survives_magnitudes_where_the_raw_products_overflow_or_underflow() {
let scale = |v: [f64; 3], s: f64| [v[0] * s, v[1] * s, v[2] * s];
let x = [1.0, 0.0, 0.0];
let z = [0.0, 0.0, 1.0];
for s in [1.0e-160, 1.0e-100, 1.0e100, 1.0e160, f64::MAX / 4.0, f64::MIN_POSITIVE / 8.0] {
let zs = scale(z, s);
assert!(coincident_planes(zs, scale(z, s)), "parallel at scale {s:e}");
assert!(coincident_planes(zs, scale(tilted(44.0), s)), "44° at scale {s:e}");
assert!(!coincident_planes(zs, scale(tilted(46.0), s)), "46° at scale {s:e}");
assert!(!coincident_planes(zs, scale(x, s)), "perpendicular at scale {s:e}");
if (1.0 / s).is_finite() {
assert!(coincident_planes(zs, scale(z, 1.0 / s)), "parallel, mixed scales {s:e}");
assert!(!coincident_planes(zs, scale(x, 1.0 / s)), "perpendicular, mixed scales {s:e}");
}
}
let raw = |a: [f64; 3], b: [f64; 3]| {
let d = super::dot3(a, b);
2.0 * d * d >= super::dot3(a, a) * super::dot3(b, b)
};
assert!(raw(scale(z, 1.0e160), scale(tilted(46.0), 1.0e160)), "inf >= inf");
assert!(raw(scale(z, 1.0e-160), scale(x, 1.0e-160)), "0 >= 0");
}
#[test]
fn a_flush_cap_tilt_passes_and_a_zero_normal_keeps_the_old_path() {
let z = [0.0, 0.0, 1.0];
assert!(coincident_planes(z, tilted(1.0e-3_f64.to_degrees())));
assert!(coincident_planes([0.0, 0.0, 0.0], z));
}
#[test]
fn the_4439_needle_is_not_coincident_with_the_perpendicular_face_it_hugs() {
let p = [
[7.483367919921875, 8.65240478515625, 2.1023867130279541],
[7.483344554901123, 8.65240478515625, 3.145187377929688],
[7.483367919921875, 8.65240478515625, 3.143897294998169],
];
let n_needle = cross3(sub_f64(p[1], p[0]), sub_f64(p[2], p[0]));
assert_eq!((n_needle[0], n_needle[2]), (0.0, 0.0));
assert!(n_needle[1] != 0.0, "a 23 µm sliver has a plane of its own");
let n_b_xmax = [19.44, 0.0, 0.0];
assert!(!coincident_planes(n_needle, n_b_xmax));
assert!(!coincident_planes(n_b_xmax, n_needle));
}
}