# `Sidereon.Observation`
[🔗](https://github.com/neilberkman/sidereon-ex/blob/main/lib/sidereon/observation.ex#L1)

Observational-astronomy geometry primitives.

Small, side-effect-free geometry helpers used when reducing or planning ground-
and space-based observations: the sub-solar point, the day-night terminator, the
parallactic angle, a diffuse-sphere visual-magnitude phase law, and the
sub-observer (central-meridian) point on a rotating body. Each function is a
pure delegation to the `sidereon-core` `astro::observation` kernels.

## Units at the boundary

Angles are in degrees and vectors are `{x, y, z}` tuples in the frame the
function documents. Latitudes are geocentric and returned in degrees on
`[-90, 90]`; longitudes on `(-180, 180]`.

# `surface_point`

```elixir
@type surface_point() :: %{latitude_deg: float(), longitude_deg: float()}
```

# `vec3`

```elixir
@type vec3() :: {number(), number(), number()}
```

# `parallactic_angle_deg`

```elixir
@spec parallactic_angle_deg(number(), number(), number()) ::
  {:ok, float()} | {:error, term()}
```

Parallactic angle (degrees) of a target at a station.

`observer_latitude_deg` is the observer geodetic latitude, `hour_angle_deg` the
local hour angle (positive west of the meridian), and `declination_deg` the
target declination. The result is on `(-180, 180]`: `0` on the meridian,
positive west of it. Returns `{:ok, angle_deg}` or `{:error, reason}`.

# `satellite_visual_magnitude`

```elixir
@spec satellite_visual_magnitude(number(), number(), number(), number()) ::
  {:ok, float()} | {:error, term()}
```

Apparent visual magnitude of a sunlit body from a diffuse-sphere phase law.

`standard_magnitude` is the body's brightness at `reference_range_km` and zero
phase; `range_km` is the observer range and `phase_angle_deg` the solar phase
angle (clamped to `[0, 180]`). Returns `{:ok, magnitude}` or `{:error, reason}`.

# `sub_observer_point`

```elixir
@spec sub_observer_point(vec3(), number(), number(), number()) ::
  {:ok, surface_point()} | {:error, term()}
```

Sub-observer point (planetary central meridian) on a rotating body.

`observer_from_body` is the observer position relative to the body center in an
inertial (ICRF/J2000 equatorial) frame; `pole_ra_deg`/`pole_dec_deg` are the
body's IAU pole and `prime_meridian_deg` its prime-meridian angle `W`. Returns
`{:ok, %{latitude_deg: lat, longitude_deg: lon}}` (planetocentric) or
`{:error, reason}`.

# `sub_solar_point`

```elixir
@spec sub_solar_point(vec3()) :: {:ok, surface_point()} | {:error, term()}
```

Sub-solar point: the geographic point where the Sun is at the zenith.

`sun_ecef` is the geocentric Sun position in an Earth-fixed (ITRS/ECEF) frame
in any length unit (only its direction matters). Returns
`{:ok, %{latitude_deg: lat, longitude_deg: lon}}` or `{:error, reason}` for a
zero or non-finite vector.

# `terminator_latitude_deg`

```elixir
@spec terminator_latitude_deg(surface_point() | {number(), number()}, number()) ::
  {:ok, float()} | {:error, term()}
```

Latitude (degrees) of the day-night terminator at a query longitude.

`sub_solar` is the sub-solar point as `%{latitude_deg: _, longitude_deg: _}` (or
a `{lat, lon}` tuple); `longitude_deg` is the query meridian. Returns
`{:ok, latitude_deg}` or `{:error, reason}`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
