open-standards/map/map-rs/crates/map-index/src/metrics.rs
Transaction Science ba1212361f Add aac, map, sandbox standards; catalog the standards family
Commit the previously-untracked standard directories and catalog them in the
root README alongside proof:

- aac/    — communication cargo class: portable boards + a ten-level
            offline-first cascade (Apache-2.0 code / CC-BY-4.0 spec).
- map/    — geospatial cargo class: range-requestable signed tilesets +
            an F0–F4 fidelity cascade (Apache-2.0 code / CC-BY-4.0 spec).
- sandbox/— isolated, metered, attested execution across the heterogeneous
            compute fabric (Apache-2.0 code / CC-BY-4.0 spec).
- jouleclaw-otel-authz, jouleclaw-trust — new jouleclaw reference crates.

Root README now lists aac, map, sandbox, and proof in the catalog, the tree,
and the contribution guide.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-07 17:04:36 -04:00

118 lines
3 KiB
Rust

// S2 cell metrics — area and edge length at each level.
//
// Earth radius: 6,371,000 m.
// Total surface area: 4 * PI * R^2 = ~5.1e14 m^2.
// At level 0, there are 6 face cells. Each covers ~8.5e13 m^2.
// At each subsequent level, the area is divided by 4.
use std::f64::consts::PI;
/// Mean Earth radius in meters (IUGG definition).
pub const EARTH_RADIUS_M: f64 = 6_371_000.0;
/// Earth surface area in m^2.
pub const EARTH_AREA_M2: f64 = 4.0 * PI * EARTH_RADIUS_M * EARTH_RADIUS_M;
/// Average area of an S2 cell at the given level, in m^2.
/// There are 6 * 4^level cells at level L.
#[inline]
pub fn avg_area_m2(level: u8) -> f64 {
EARTH_AREA_M2 / (6.0 * 4.0_f64.powi(level as i32))
}
/// Average edge length of an S2 cell at the given level, in meters.
/// Approximation: edge ~ sqrt(area).
#[inline]
pub fn avg_edge_m(level: u8) -> f64 {
avg_area_m2(level).sqrt()
}
/// Maximum edge length of an S2 cell at the given level, in meters.
/// The maximum edge is about 1.41x the average (diagonal factor for quad cells).
#[inline]
pub fn max_edge_m(level: u8) -> f64 {
avg_edge_m(level) * 1.414
}
/// Minimum edge length of an S2 cell at the given level, in meters.
/// The minimum is about 0.71x the average.
#[inline]
pub fn min_edge_m(level: u8) -> f64 {
avg_edge_m(level) * 0.707
}
/// Average angular edge length in radians at the given level.
#[inline]
pub fn avg_edge_radians(level: u8) -> f64 {
avg_edge_m(level) / EARTH_RADIUS_M
}
/// Number of cells at a given level.
#[inline]
pub fn num_cells(level: u8) -> u64 {
6u64 * (1u64 << (2 * level as u32))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn level_0_area() {
let area = avg_area_m2(0);
// ~85,011 km^2 per face
let area_km2 = area / 1e6;
assert!(
(area_km2 - 85_011_012.0).abs() / 85_011_012.0 < 0.01,
"level 0 area: {area_km2} km^2"
);
}
#[test]
fn area_halves_each_level() {
for level in 0..29u8 {
let a = avg_area_m2(level);
let b = avg_area_m2(level + 1);
let ratio = a / b;
assert!(
(ratio - 4.0).abs() < 1e-10,
"area ratio at level {level}: {ratio}"
);
}
}
#[test]
fn level_30_area() {
let area = avg_area_m2(30);
// At level 30, ~0.48 cm^2 per cell
let area_cm2 = area * 1e4;
assert!(area_cm2 > 0.0 && area_cm2 < 10.0, "level 30 area: {area_cm2} cm^2");
}
#[test]
fn num_cells_level_0() {
assert_eq!(num_cells(0), 6);
}
#[test]
fn num_cells_level_1() {
assert_eq!(num_cells(1), 24);
}
#[test]
fn edge_length_reasonable() {
// Level 12 should have edges around 2-3 km.
let edge_km = avg_edge_m(12) / 1000.0;
assert!(
edge_km > 0.5 && edge_km < 10.0,
"level 12 edge: {edge_km} km"
);
}
#[test]
fn max_edge_greater_than_avg() {
for level in 0..30u8 {
assert!(max_edge_m(level) > avg_edge_m(level));
}
}
}