pub(super) fn swap_zup_to_yup_aabb<T: Copy + std::ops::Neg<Output = T>>(b: [T; 6]) -> [T; 6] {
let [min_x, min_y, min_z, max_x, max_y, max_z] = b;
[min_x, min_z, -max_y, max_x, max_z, -min_y]
}
pub(super) fn swap_zup_to_yup_mat4(m: &[f64; 16]) -> [f64; 16] {
#[rustfmt::skip]
const S: [f64; 16] = [
1.0, 0.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, -1.0, 0.0, 0.0,
0.0, 0.0, 0.0, 1.0,
];
#[rustfmt::skip]
const ST: [f64; 16] = [
1.0, 0.0, 0.0, 0.0,
0.0, 0.0, -1.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 0.0, 1.0,
];
fn matmul(a: &[f64; 16], b: &[f64; 16]) -> [f64; 16] {
let mut out = [0.0; 16];
for r in 0..4 {
for c in 0..4 {
let mut sum = 0.0;
for k in 0..4 {
sum += a[r * 4 + k] * b[k * 4 + c];
}
out[r * 4 + c] = sum;
}
}
out
}
matmul(&matmul(&S, m), &ST)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn zup_to_yup_reverses_min_max_on_the_negated_axis() {
let world = swap_zup_to_yup_aabb([1.0f64, 2.0, 3.0, 4.0, 5.0, 6.0]);
assert_eq!(world, [1.0, 3.0, -5.0, 4.0, 6.0, -2.0]);
assert!(world[2] <= world[5], "min must stay <= max on the negated axis");
let local = swap_zup_to_yup_aabb([1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0]);
assert_eq!(local, [1.0, 3.0, -5.0, 4.0, 6.0, -2.0]);
}
#[test]
fn the_world_box_survives_the_swap_at_national_grid_coordinates() {
let ifc = [
2_600_000.000_5_f64,
1_200_000.000_5,
0.0,
2_600_001.000_5,
1_200_001.000_5,
3.0,
];
let out = swap_zup_to_yup_aabb(ifc);
assert_eq!(out, [ifc[0], ifc[2], -ifc[4], ifc[3], ifc[5], -ifc[1]]);
assert_ne!(
out[2], out[2] as f32 as f64,
"the fixture must be one an f32 round-trip would visibly move"
);
}
}