first commit
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
The `atmospheric` module provides the two physics primitives every planetary renderer, sky-colour solver, and observation-quality estimator needs: the local density of an atmospheric column at altitude, and the relative path length light travels through that column for a given elevation angle. Both functions accept a `PlanetConfig` so the same code path serves Earth, Mars, Titan, or any other modelled body.
|
||||
|
||||
These primitives are intentionally pure and free of vendor coupling so they can be reused by `@suaveplan/universe`, `@suaveplan/gaming-environment-lighting`, server-side astronomical computations, and offline analysis without dragging a graphics runtime into the call site.
|
||||
|
||||
## Features
|
||||
|
||||
- `atmosphericDensity(planet, altitudeMetres)` — exponential isothermal scale-height model that returns `0` for airless bodies
|
||||
- `airMass(altitudeDeg)` — Kasten–Young 1989 air-mass approximation valid from zenith down to the horizon
|
||||
- Numerical-stable horizon handling: negative altitudes are clamped to `0` so the formula remains finite at the bound
|
||||
- Pure functions: no I/O, no side effects, no global state — safe for `Worker` threads, SSR, and deterministic tests
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Example
|
||||
|
||||
```ts
|
||||
import { atmosphericDensity } from "@suaveplan/geo-planet";
|
||||
import type { PlanetConfig } from "@suaveplan/geo-planet";
|
||||
|
||||
const earth: PlanetConfig = {
|
||||
name: "Earth",
|
||||
mass: 5.972e24,
|
||||
radius: 6_378_137,
|
||||
polarRadius: 6_356_752,
|
||||
surfaceGravity: 9.81,
|
||||
rotationPeriod: 86_164,
|
||||
axialTilt: 23.44,
|
||||
atmosphere: {
|
||||
surfacePressure: 101_325,
|
||||
scaleHeight: 8_500,
|
||||
rayleighCoefficient: 5.8e-6,
|
||||
mieCoefficient: 21e-6,
|
||||
extinctionPerAirMass: 0.13,
|
||||
},
|
||||
satellites: [],
|
||||
};
|
||||
|
||||
const surface = atmosphericDensity(earth, 0); // 101325 Pa
|
||||
const cruise = atmosphericDensity(earth, 11_000); // ~27 kPa
|
||||
```
|
||||
|
||||
### Advanced Example
|
||||
|
||||
```ts
|
||||
import { airMass, atmosphericDensity } from "@suaveplan/geo-planet";
|
||||
import type { PlanetConfig } from "@suaveplan/geo-planet";
|
||||
|
||||
function transmittance(
|
||||
planet: PlanetConfig,
|
||||
altitudeMetres: number,
|
||||
sunElevationDeg: number,
|
||||
): number {
|
||||
if (!planet.atmosphere) return 1;
|
||||
const density = atmosphericDensity(planet, altitudeMetres);
|
||||
const am = airMass(sunElevationDeg);
|
||||
const tau = planet.atmosphere.extinctionPerAirMass * am;
|
||||
return Math.exp(-tau) * (density / planet.atmosphere.surfacePressure);
|
||||
}
|
||||
|
||||
// Use at every camera step in a sky shader, or to score
|
||||
// observability for ground-station pass scheduling.
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `atmosphericDensity(planet: PlanetConfig, altitudeMetres: number): number`
|
||||
|
||||
Returns the local pressure (`Pa`) using `p₀ · exp(-h / H)` where `p₀` is `planet.atmosphere.surfacePressure` and `H` is `planet.atmosphere.scaleHeight`. Returns `0` when `planet.atmosphere === null`. No clamping is applied to altitude; negative altitudes (subterranean, sub-sea-level) yield pressures above `p₀`, which is the physically correct extrapolation for a barometric law.
|
||||
|
||||
### `airMass(altitudeDeg: number): number`
|
||||
|
||||
Returns the Kasten–Young air mass:
|
||||
|
||||
`1 / (sin(alt) + 0.50572 · (alt + 6.07995)^-1.6364)`
|
||||
|
||||
with `alt` in degrees. Negative altitudes are clamped to `0` so the result remains finite at the horizon (returning ≈ `38`). At zenith the return value approaches `1`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The density function uses the isothermal barometric equation rather than a layered ISA model because every consumer in this project treats density as a smooth analytic function for shader sampling. The Kasten–Young formulation was chosen over the simpler `1 / sin(alt)` secant model because it remains stable down to the horizon and only diverges by ≈ `0.4%` from full atmospheric ray-tracing above 5° elevation. Both functions are allocation-free hot-path code; consumers can call them once per pixel without GC pressure.
|
||||
Reference in New Issue
Block a user