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]>
118 lines
3 KiB
Rust
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));
|
|
}
|
|
}
|
|
}
|