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

Ground-observer Sun and Moon geometry.

From a ground station and a UTC instant, answer the "observe the sky from a
site" questions: the topocentric azimuth/elevation/range of the Sun or Moon,
the Moon's illuminated fraction, and the Moon's rise/set and meridian-transit
events over a window. The azimuth/elevation convention matches the satellite
look-angle path; the Moon vector is geocentric, so the station-to-target
reduction applies the diurnal parallax that matters for the nearby Moon.

Precision follows the underlying analytic Sun/Moon series (sub-degree
positions); this is a planning/visualization lens, not an almanac-grade
reduction. The ephemeris, topocentric reduction, phase-angle geometry, and
event refinement all live in the `sidereon-core` Rust core.

A `station` is `{latitude_deg, longitude_deg, altitude_km}` or a map with
`:latitude_deg`, `:longitude_deg`, `:altitude_km`. A time is a `DateTime`, a
`NaiveDateTime` (interpreted as UTC), or a `{{y, m, d}, {h, min, s, us}}`
tuple.

# `az_el`

```elixir
@type az_el() :: %{azimuth_deg: float(), elevation_deg: float(), range_km: float()}
```

Topocentric look angle of a body from a site.

# `event`

```elixir
@type event() :: %{time: DateTime.t(), kind: atom(), elevation_deg: float()}
```

A Moon rise/set or meridian-transit event.

# `station`

```elixir
@type station() ::
  {number(), number(), number()}
  | %{latitude_deg: number(), longitude_deg: number(), altitude_km: number()}
```

# `time`

```elixir
@type time() :: DateTime.t() | NaiveDateTime.t() | {tuple(), tuple()}
```

# `find_moon_elevation_crossings`

```elixir
@spec find_moon_elevation_crossings(station(), time(), time(), keyword()) ::
  {:ok, [event()]} | {:error, atom()}
```

Moon elevation-threshold crossings (moonrise / moonset) over a UTC window.

## Options

  * `:elevation_threshold_deg` - crossing threshold (default `-0.833`, the
    standard upper-limb-on-the-horizon convention).
  * `:step_seconds` - event-finder scan step (default `600.0`).
  * `:time_tolerance_seconds` - crossing-time refinement tolerance (default
    `1.0`).

Returns `{:ok, [%{time: DateTime, kind: :rising | :setting, elevation_deg:}]}`.

# `find_moon_transits`

```elixir
@spec find_moon_transits(station(), time(), time(), keyword()) ::
  {:ok, [event()]} | {:error, atom()}
```

Moon meridian transits (upper and lower culminations) over a UTC window.

## Options

  * `:step_seconds` - event-finder scan step (default `600.0`).
  * `:time_tolerance_seconds` - crossing-time refinement tolerance (default
    `1.0`).

Returns `{:ok, [%{time: DateTime, kind: :upper | :lower, elevation_deg:}]}`.

# `moon_az_el`

```elixir
@spec moon_az_el(station(), time()) :: {:ok, az_el()} | {:error, atom()}
```

Topocentric azimuth/elevation/range of the Moon from a site.

# `moon_elevation_deg`

```elixir
@spec moon_elevation_deg(station(), time()) :: {:ok, float()} | {:error, atom()}
```

Topocentric geometric Moon (disk-center) elevation at a site, degrees.

# `moon_illumination`

```elixir
@spec moon_illumination(station(), time()) ::
  {:ok, %{illuminated_fraction: float(), phase_angle_deg: float()}}
  | {:error, atom()}
```

Illuminated fraction of the Moon as seen from a site.

Returns `{:ok, %{illuminated_fraction: k, phase_angle_deg: a}}` with `k` in
`[0, 1]` (0 = new, 1 = full) and the Sun-Moon-observer phase angle in degrees.

# `sun_az_el`

```elixir
@spec sun_az_el(station(), time()) :: {:ok, az_el()} | {:error, atom()}
```

Topocentric azimuth/elevation/range of the Sun from a site.

---

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