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]>
77 lines
2.8 KiB
Rust
77 lines
2.8 KiB
Rust
//! Bridge from orbital propagation to the standard's address space.
|
|
//!
|
|
//! A live satellite occupies the `F3` (feature / live-entity) tier. Its
|
|
//! ground-relative address is its **sub-point**: the geodetic position of the
|
|
//! propagated state, projected to an S2 cell at the requested level, with the
|
|
//! altitude band for its altitude and the time bucket for the instant. This puts
|
|
//! a satellite on the same 4D grid (SPEC §2) as every other tile, so an entity
|
|
//! feed and a basemap share one index.
|
|
|
|
use chrono::{DateTime, Utc};
|
|
use map_index::volume::TimeTier;
|
|
use map_schema::{CellKey, Lod};
|
|
|
|
use crate::{satellite_position, GeodeticPosition, OrbitalResult, Sgp4State};
|
|
|
|
/// The [`CellKey`] for a geodetic position at an instant: S2 cell at `level`,
|
|
/// the altitude band for `alt_km`, and the time bucket at `tier`.
|
|
pub fn geodetic_cell_key(
|
|
geo: &GeodeticPosition,
|
|
level: u8,
|
|
time_secs: i64,
|
|
tier: TimeTier,
|
|
lod: Lod,
|
|
) -> CellKey {
|
|
map_index::cell_key(
|
|
geo.lat_deg,
|
|
geo.lon_deg,
|
|
level,
|
|
map_index::alt_band(geo.alt_km * 1000.0),
|
|
map_index::time_bucket(time_secs, tier),
|
|
lod,
|
|
)
|
|
}
|
|
|
|
/// Propagate `state` to `dt` and return the satellite sub-point's [`CellKey`].
|
|
pub fn subpoint_cell_key(
|
|
state: &Sgp4State,
|
|
dt: &DateTime<Utc>,
|
|
level: u8,
|
|
tier: TimeTier,
|
|
lod: Lod,
|
|
) -> OrbitalResult<CellKey> {
|
|
let geo = satellite_position(state, dt)?;
|
|
Ok(geodetic_cell_key(&geo, level, dt.timestamp(), tier, lod))
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use crate::tle::parse_tle;
|
|
|
|
const ISS_NAME: &str = "ISS (ZARYA)";
|
|
const ISS_L1: &str = "1 25544U 98067A 24001.50000000 .00016717 00000-0 10270-3 0 9009";
|
|
const ISS_L2: &str = "2 25544 51.6416 247.4627 0006703 30.0000 10.0000 15.49560000000007";
|
|
|
|
#[test]
|
|
fn iss_subpoint_lands_in_leo_band() {
|
|
let tle = parse_tle(ISS_NAME, ISS_L1, ISS_L2).unwrap();
|
|
let state = Sgp4State::initialize(&tle).unwrap();
|
|
// Realtime tier (1 s buckets) is right for a live satellite.
|
|
let key = subpoint_cell_key(&state, &tle.epoch, 10, TimeTier::Realtime, Lod(0)).unwrap();
|
|
// The ISS orbits at ~408 km → the LEO altitude band (schema index 4).
|
|
assert_eq!(key.alt, map_schema::AltBand(4), "ISS should be in the LEO band");
|
|
// Horizontal address is a valid S2 cell at the requested level.
|
|
assert_eq!(key.s2.level(), Some(10));
|
|
// Realtime bucket is 1 s wide.
|
|
assert_eq!(key.time.width_ms, 1_000);
|
|
}
|
|
|
|
#[test]
|
|
fn geodetic_cell_key_maps_surface_to_band_zero() {
|
|
let geo = GeodeticPosition { lat_deg: 37.77, lon_deg: -122.42, alt_km: 0.0 };
|
|
let key = geodetic_cell_key(&geo, 14, 0, TimeTier::Recent, Lod(0));
|
|
assert_eq!(key.alt, map_schema::AltBand(0));
|
|
assert_eq!(key.s2.level(), Some(14));
|
|
}
|
|
}
|