#![expect(
clippy::cast_sign_loss,
reason = "level (i32) clamped to valid range then cast to u8; exponent computation always non-negative"
)]
#![expect(
clippy::cast_possible_truncation,
reason = "level (i32->u8) after clamping and exponent arithmetic"
)]
use crate::s2::coords::{Level, MAX_CELL_LEVEL};
fn ilogb(x: f64) -> i32 {
let bits = x.to_bits();
let exp = ((bits >> 52) & 0x7ff) as i32;
exp - 1023
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Metric {
pub dim: u8,
pub deriv: f64,
}
impl Metric {
pub const fn new(dim: u8, deriv: f64) -> Self {
Metric { dim, deriv }
}
pub fn value(&self, level: impl Into<Level>) -> f64 {
let exp = -(i32::from(self.dim) * level.into().as_i32());
self.deriv * f64::from_bits(((1023i64 + i64::from(exp)) as u64) << 52)
}
pub fn min_level(&self, val: f64) -> Level {
debug_assert!(!val.is_nan(), "min_level: value must not be NaN");
if val <= 0.0 || val.is_nan() {
return Level::MAX;
}
let level = -(ilogb(val / self.deriv) >> (i32::from(self.dim) - 1));
let level = Level::new(level.clamp(0, i32::from(MAX_CELL_LEVEL)) as u8);
debug_assert!(level == Level::MAX || self.value(level) <= val);
debug_assert!(level == Level::MIN || self.value(level - 1) > val);
level
}
pub fn max_level(&self, val: f64) -> Level {
debug_assert!(!val.is_nan(), "max_level: value must not be NaN");
if val <= 0.0 || val.is_nan() {
return Level::MAX;
}
let level = Level::new(
(ilogb(self.deriv / val) >> (i32::from(self.dim) - 1))
.clamp(0, i32::from(MAX_CELL_LEVEL)) as u8,
);
debug_assert!(level == Level::MIN || self.value(level) >= val);
debug_assert!(level == Level::MAX || self.value(level + 1) < val);
level
}
pub fn closest_level(&self, val: f64) -> Level {
let factor = if self.dim == 2 {
2.0
} else {
std::f64::consts::SQRT_2
};
self.min_level(factor * val)
}
}
pub const MIN_ANGLE_SPAN: Metric = Metric::new(1, 4.0 / 3.0);
pub const AVG_ANGLE_SPAN: Metric = Metric::new(1, std::f64::consts::FRAC_PI_2);
pub const MAX_ANGLE_SPAN: Metric = Metric::new(1, 1.704_897_179_199_218_5);
pub const MIN_WIDTH: Metric = Metric::new(1, 2.0 * std::f64::consts::SQRT_2 / 3.0);
pub const AVG_WIDTH: Metric = Metric::new(1, 1.434_523_672_886_099_5);
pub const MAX_WIDTH: Metric = Metric::new(1, MAX_ANGLE_SPAN.deriv);
pub const MIN_EDGE: Metric = Metric::new(1, 2.0 * std::f64::consts::SQRT_2 / 3.0);
pub const AVG_EDGE: Metric = Metric::new(1, 1.459_213_746_386_106_1);
pub const MAX_EDGE: Metric = Metric::new(1, MAX_ANGLE_SPAN.deriv);
pub const MAX_EDGE_ASPECT: f64 = 1.442_615_274_452_683;
pub const MIN_DIAG: Metric = Metric::new(1, 8.0 * std::f64::consts::SQRT_2 / 9.0);
pub const AVG_DIAG: Metric = Metric::new(1, 2.060_422_738_998_471_7);
pub const MAX_DIAG: Metric = Metric::new(1, 2.438_654_594_434_021);
pub const MAX_DIAG_ASPECT: f64 = 1.7320508075688772;
pub const MIN_AREA: Metric = Metric::new(2, 8.0 * std::f64::consts::SQRT_2 / 9.0);
pub const AVG_AREA: Metric = Metric::new(2, 4.0 * std::f64::consts::PI / 6.0);
pub const MAX_AREA: Metric = Metric::new(2, 2.635_799_256_963_161_4);
#[cfg(test)]
#[expect(
clippy::assertions_on_constants,
reason = "compile-time metric sanity checks"
)]
mod tests {
use super::*;
#[test]
fn test_value_at_level_zero() {
assert_eq!(MIN_ANGLE_SPAN.value(0), MIN_ANGLE_SPAN.deriv);
assert_eq!(AVG_AREA.value(0), AVG_AREA.deriv);
}
#[test]
fn test_value_halves_per_level_for_length() {
let v0 = AVG_EDGE.value(0);
let v1 = AVG_EDGE.value(1);
assert!((v1 - v0 / 2.0).abs() < 1e-15);
}
#[test]
fn test_value_quarters_per_level_for_area() {
let v0 = AVG_AREA.value(0);
let v1 = AVG_AREA.value(1);
assert!((v1 - v0 / 4.0).abs() < 1e-15);
}
#[test]
fn test_min_max_avg_ordering() {
for level in 0..=MAX_CELL_LEVEL {
assert!(
MIN_ANGLE_SPAN.value(level) <= AVG_ANGLE_SPAN.value(level),
"level {level}"
);
assert!(
AVG_ANGLE_SPAN.value(level) <= MAX_ANGLE_SPAN.value(level),
"level {level}"
);
assert!(
MIN_WIDTH.value(level) <= AVG_WIDTH.value(level),
"level {level}"
);
assert!(
AVG_WIDTH.value(level) <= MAX_WIDTH.value(level),
"level {level}"
);
assert!(
MIN_EDGE.value(level) <= AVG_EDGE.value(level),
"level {level}"
);
assert!(
AVG_EDGE.value(level) <= MAX_EDGE.value(level),
"level {level}"
);
assert!(
MIN_DIAG.value(level) <= AVG_DIAG.value(level),
"level {level}"
);
assert!(
AVG_DIAG.value(level) <= MAX_DIAG.value(level),
"level {level}"
);
assert!(
MIN_AREA.value(level) <= AVG_AREA.value(level),
"level {level}"
);
assert!(
AVG_AREA.value(level) <= MAX_AREA.value(level),
"level {level}"
);
}
}
#[test]
fn test_metric_relationships() {
for level in 0..=MAX_CELL_LEVEL {
assert!(
MIN_WIDTH.value(level) <= MIN_ANGLE_SPAN.value(level) + 1e-15,
"level {level}"
);
assert!(
MIN_EDGE.value(level) <= MIN_DIAG.value(level) + 1e-15,
"level {level}"
);
assert!(
MAX_EDGE.value(level) <= MAX_DIAG.value(level) + 1e-15,
"level {level}"
);
}
}
#[test]
fn test_min_level() {
assert_eq!(MIN_WIDTH.min_level(1e10), 0);
assert_eq!(MIN_WIDTH.min_level(1e-30), MAX_CELL_LEVEL);
assert_eq!(MIN_WIDTH.min_level(-1.0), MAX_CELL_LEVEL);
assert_eq!(MIN_WIDTH.min_level(0.0), MAX_CELL_LEVEL);
assert_eq!(MAX_WIDTH.min_level(-1.0), MAX_CELL_LEVEL);
assert_eq!(MAX_WIDTH.min_level(0.0), MAX_CELL_LEVEL);
}
#[test]
fn test_max_level() {
assert_eq!(MIN_WIDTH.max_level(1e10), 0);
assert_eq!(MIN_WIDTH.max_level(1e-30), MAX_CELL_LEVEL);
assert_eq!(MIN_WIDTH.max_level(0.0), MAX_CELL_LEVEL);
assert_eq!(MIN_WIDTH.max_level(-1.0), MAX_CELL_LEVEL);
assert_eq!(MIN_WIDTH.max_level(4.0), 0);
assert_eq!(MAX_WIDTH.max_level(4.0), 0);
assert_eq!(MIN_WIDTH.max_level(f64::INFINITY), 0);
assert_eq!(MAX_WIDTH.max_level(f64::INFINITY), 0);
}
#[test]
fn test_closest_level() {
let level = AVG_EDGE.closest_level(0.1);
let v = AVG_EDGE.value(level);
assert!(v > 0.05 && v < 0.3, "closest_level gave value {v}");
}
#[test]
fn test_min_level_boundary() {
for level in 0..=MAX_CELL_LEVEL {
let val = MIN_DIAG.value(level);
assert_eq!(MIN_DIAG.min_level(val), level);
}
}
#[test]
fn test_max_level_boundary() {
for level in 0..=MAX_CELL_LEVEL {
let val = MIN_DIAG.value(level);
assert_eq!(MIN_DIAG.max_level(val), level);
}
}
#[test]
fn test_aspect_ratio_bounds() {
assert!(MAX_EDGE_ASPECT >= 1.0);
assert!(MAX_EDGE_ASPECT <= MAX_EDGE.deriv / MIN_EDGE.deriv);
assert!(MAX_DIAG_ASPECT >= 1.0);
assert!(MAX_DIAG_ASPECT <= MAX_DIAG.deriv / MIN_DIAG.deriv);
}
#[test]
fn test_width_edge_diag_relationships() {
assert!(MIN_WIDTH.deriv <= MIN_ANGLE_SPAN.deriv);
assert!(MAX_WIDTH.deriv <= MAX_ANGLE_SPAN.deriv);
assert!(AVG_WIDTH.deriv <= AVG_ANGLE_SPAN.deriv);
assert!(MIN_WIDTH.deriv <= MIN_EDGE.deriv);
assert!(MAX_WIDTH.deriv <= MAX_EDGE.deriv);
assert!(AVG_WIDTH.deriv <= AVG_EDGE.deriv);
assert!(MIN_EDGE.deriv <= MIN_DIAG.deriv);
assert!(MAX_EDGE.deriv <= MAX_DIAG.deriv);
assert!(AVG_EDGE.deriv <= AVG_DIAG.deriv);
}
#[test]
fn test_area_bounds() {
assert!(MIN_AREA.deriv >= MIN_WIDTH.deriv * MIN_EDGE.deriv - 1e-15);
assert!(MAX_AREA.deriv <= MAX_WIDTH.deriv * MAX_EDGE.deriv + 1e-15);
}
#[test]
fn test_level_boundary_and_non_boundary() {
for level in -2..=(i32::from(MAX_CELL_LEVEL) + 3) {
let mut width_val = MIN_WIDTH.deriv * 2.0_f64.powi(-level);
if level >= i32::from(MAX_CELL_LEVEL) + 3 {
width_val = 0.0;
}
let expected = (level.clamp(0, i32::from(MAX_CELL_LEVEL))) as u8;
assert_eq!(
MIN_WIDTH.min_level(width_val),
expected,
"min_level boundary at level {level}"
);
assert_eq!(
MIN_WIDTH.max_level(width_val),
expected,
"max_level boundary at level {level}"
);
assert_eq!(
MIN_WIDTH.closest_level(width_val),
expected,
"closest_level boundary at level {level}"
);
assert_eq!(
MIN_WIDTH.min_level(1.2 * width_val),
expected,
"min_level non-boundary 1.2x at level {level}"
);
assert_eq!(
MIN_WIDTH.max_level(0.8 * width_val),
expected,
"max_level non-boundary 0.8x at level {level}"
);
assert_eq!(
MIN_WIDTH.closest_level(1.2 * width_val),
expected,
"closest_level non-boundary 1.2x at level {level}"
);
assert_eq!(
MIN_WIDTH.closest_level(0.8 * width_val),
expected,
"closest_level non-boundary 0.8x at level {level}"
);
let mut area_val = MIN_AREA.deriv * 4.0_f64.powi(-level);
if level <= -3 {
area_val = 0.0;
}
assert_eq!(
MIN_AREA.min_level(area_val),
expected,
"area min_level boundary at level {level}"
);
assert_eq!(
MIN_AREA.max_level(area_val),
expected,
"area max_level boundary at level {level}"
);
assert_eq!(
MIN_AREA.closest_level(area_val),
expected,
"area closest_level boundary at level {level}"
);
assert_eq!(
MIN_AREA.min_level(1.2 * area_val),
expected,
"area min_level non-boundary 1.2x at level {level}"
);
assert_eq!(
MIN_AREA.max_level(0.8 * area_val),
expected,
"area max_level non-boundary 0.8x at level {level}"
);
assert_eq!(
MIN_AREA.closest_level(1.2 * area_val),
expected,
"area closest_level non-boundary 1.2x at level {level}"
);
assert_eq!(
MIN_AREA.closest_level(0.8 * area_val),
expected,
"area closest_level non-boundary 0.8x at level {level}"
);
}
}
#[test]
fn test_avg_area_consistency() {
let face_area = AVG_AREA.value(0);
let total = face_area * 6.0;
assert!(
(total - 4.0 * std::f64::consts::PI).abs() < 1e-14,
"6 * avg_area(0) = {total}, expected 4π"
);
}
}