use glam::{DVec3, Vec3};
#[must_use]
pub fn min_lanes(accumulator: Vec3, point: Vec3) -> Vec3 {
Vec3::new(
accumulator.x.min(point.x),
accumulator.y.min(point.y),
accumulator.z.min(point.z),
)
}
#[must_use]
pub fn max_lanes(accumulator: Vec3, point: Vec3) -> Vec3 {
Vec3::new(
accumulator.x.max(point.x),
accumulator.y.max(point.y),
accumulator.z.max(point.z),
)
}
#[must_use]
pub fn min_lanes_d(accumulator: DVec3, point: DVec3) -> DVec3 {
DVec3::new(
accumulator.x.min(point.x),
accumulator.y.min(point.y),
accumulator.z.min(point.z),
)
}
#[must_use]
pub fn max_lanes_d(accumulator: DVec3, point: DVec3) -> DVec3 {
DVec3::new(
accumulator.x.max(point.x),
accumulator.y.max(point.y),
accumulator.z.max(point.z),
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_nan_is_skipped_from_any_position_in_a_fold() {
let nan = Vec3::new(f32::NAN, 0.0, 0.0);
let low = Vec3::splat(-1.0);
let high = Vec3::splat(1.0);
for (label, points) in [
("leading", vec![nan, low, high]),
("middle", vec![low, nan, high]),
("trailing", vec![low, high, nan]),
] {
let mut min = Vec3::splat(f32::INFINITY);
let mut max = Vec3::splat(f32::NEG_INFINITY);
for point in points {
min = min_lanes(min, point);
max = max_lanes(max, point);
}
assert_eq!(min, low, "a NaN {label} moved the minimum");
assert_eq!(max, high, "a NaN {label} moved the maximum");
}
}
#[test]
fn an_infinity_is_kept_where_a_nan_is_skipped() {
let infinite = Vec3::new(f32::INFINITY, 0.0, 0.0);
assert_eq!(max_lanes(Vec3::ZERO, infinite).x, f32::INFINITY);
assert_eq!(
min_lanes(Vec3::splat(f32::INFINITY), Vec3::new(f32::NAN, 2.0, 2.0)),
Vec3::new(f32::INFINITY, 2.0, 2.0),
"the NaN lane keeps the seed, which is what leaves a wholly NaN lane detectable"
);
}
#[test]
fn the_double_width_pair_skips_a_nan_the_same_way() {
let nan = DVec3::new(f64::NAN, 0.0, 0.0);
let low = DVec3::splat(-1.0);
let high = DVec3::splat(1.0);
let mut min = DVec3::splat(f64::INFINITY);
let mut max = DVec3::splat(f64::NEG_INFINITY);
for point in [low, nan, high] {
min = min_lanes_d(min, point);
max = max_lanes_d(max, point);
}
assert_eq!(min, low);
assert_eq!(max, high);
}
}