pub(crate) fn boundary_eps() -> f64 {
2f64.powi(-28)
}
pub(crate) const CELL: [f64; 12] = [
1e5, 1e4, 1e3, 1e2, 1e1, 1.0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6,
];
pub(crate) const POW10_11MP: [i64; 12] = [
100_000_000_000,
10_000_000_000,
1_000_000_000,
100_000_000,
10_000_000,
1_000_000,
100_000,
10_000,
1_000,
100,
10,
1,
];
const TILE_UM: i64 = 100_000_000_000;
pub(crate) const UTM_MGRS_EASTING: (f64, f64) = (100_000.0, 900_000.0);
pub(crate) const UTM_MGRS_NORTHING_ABS: (f64, f64) = (-9_000_000.0, 9_500_000.0);
pub(crate) const UPS_NORTH_MGRS: (f64, f64) = (1_300_000.0, 2_700_000.0);
pub(crate) const UPS_SOUTH_MGRS: (f64, f64) = (800_000.0, 3_200_000.0);
pub(crate) fn axis_fields(value: f64) -> (i64, i64) {
let um = (value * 1e6).floor() as i64;
let tile = um.div_euclid(TILE_UM);
let offset = um.rem_euclid(TILE_UM);
(tile, offset)
}
pub(crate) fn digits_at(offset_um: i64, p: u8) -> i64 {
let div = POW10_11MP.get(usize::from(p)).copied().unwrap_or(1);
offset_um.div_euclid(div)
}
pub(crate) fn cell_size(p: u8) -> f64 {
CELL.get(usize::from(p)).copied().unwrap_or(1.0)
}
pub(crate) fn band_index(lat: f64) -> i64 {
let f = (lat / 8.0).floor();
let ib = if lat < 0.0 && f == 0.0 { -1 } else { f as i64 };
ib.clamp(-10, 9)
}
pub(crate) fn utm_nudge(north: bool, e: f64, n_frame: f64) -> (f64, f64) {
let (_, ehi) = UTM_MGRS_EASTING;
let (_, nhi) = UTM_MGRS_NORTHING_ABS;
let fold = if north { 0.0 } else { 10_000_000.0 };
let e2 = if e == ehi { e - boundary_eps() } else { e };
let n2 = if n_frame == nhi + fold || (!north && n_frame == fold) {
n_frame - boundary_eps()
} else {
n_frame
};
(e2, n2)
}
pub(crate) fn utm_extent(north: bool, e: f64, n_frame: f64) -> Option<(f64, f64)> {
let (elo, ehi) = UTM_MGRS_EASTING;
if !(elo..=ehi).contains(&e) {
return None;
}
let fold = if north { 0.0 } else { 10_000_000.0 };
let (nlo, nhi) = UTM_MGRS_NORTHING_ABS;
if !(nlo + fold..=nhi + fold).contains(&n_frame) {
return None;
}
Some(utm_nudge(north, e, n_frame))
}
pub(crate) fn ups_nudge(north: bool, e: f64, n: f64) -> (f64, f64) {
let (_, hi) = if north {
UPS_NORTH_MGRS
} else {
UPS_SOUTH_MGRS
};
let e2 = if e == hi { e - boundary_eps() } else { e };
let n2 = if n == hi { n - boundary_eps() } else { n };
(e2, n2)
}
pub(crate) fn ups_extent(north: bool, e: f64, n: f64) -> Option<(f64, f64)> {
let (lo, hi) = if north {
UPS_NORTH_MGRS
} else {
UPS_SOUTH_MGRS
};
if !(lo..=hi).contains(&e) || !(lo..=hi).contains(&n) {
return None;
}
Some(ups_nudge(north, e, n))
}
pub(crate) fn cell_center_axis(tile: i64, digits: i64, p: u8) -> f64 {
(tile as f64) * 100_000.0 + ((digits as f64) + 0.5) * cell_size(p)
}
pub(crate) fn frame_northing(n_abs: f64, north: bool) -> f64 {
if north {
n_abs
} else {
n_abs + 10_000_000.0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn boundary_eps_pinned() {
assert_eq!(boundary_eps(), 3.725_290_298_461_914e-9);
assert_eq!(
boundary_eps(),
(2f64).powi(25 - f64::MANTISSA_DIGITS as i32)
);
}
#[test]
fn utm_extent_compares_in_the_frame() {
let just_under = f64::from_bits(1_000_000.0_f64.to_bits() - 1);
assert_eq!(just_under - 10_000_000.0, -9_000_000.0);
assert!(utm_extent(false, 500_000.0, just_under).is_none());
assert!(utm_extent(false, 500_000.0, 1_000_000.0).is_some());
assert!(utm_extent(true, 500_000.0, -9_000_000.0).is_some());
let below_north = f64::from_bits((-9_000_000.0_f64).to_bits() + 1);
assert!(utm_extent(true, 500_000.0, below_north).is_none());
}
#[test]
fn axis_fields_truncates_toward_negative_infinity() {
assert_eq!(axis_fields(585_664.25), (5, 85_664_250_000));
assert_eq!(axis_fields(-0.000_976_562_5), (-1, 99_999_999_023));
assert_eq!(axis_fields(0.0), (0, 0));
}
#[test]
fn digits_nest_by_construction() {
let (_, off) = axis_fields(585_664.121_374_411);
for p in 1..=11u8 {
let fine = digits_at(off, p);
let coarse = digits_at(off, p - 1);
assert_eq!(fine / 10, coarse, "nesting at p {p}");
}
}
}