Skip to main content

lib/ex_srp_phat/geo.ex

defmodule ExSrpPhat.Geo do
  @moduledoc """
  WGS-84 geodetic ↔ ECEF conversion, delegated to the Rust NIF so the transform
  matches the solver's geometry exactly (and so callers need no separate geodesy
  dependency).

  Constants: semi-major axis `a = 6_378_137.0` m, flattening
  `f = 1 / 298.257223563`, first eccentricity² `e² = f(2 − f)`. The forward
  transform is exact closed form; the inverse uses Bowring's method.
  """

  alias ExSrpPhat.Native

  @doc "Geodetic latitude/longitude (degrees) + height (m, HAE) → ECEF `{x, y, z}` meters."
  @spec latlon_to_ecef(number(), number(), number()) :: {float(), float(), float()}
  def latlon_to_ecef(lat_deg, lon_deg, alt_m \\ 0.0) do
    Native.latlon_to_ecef_nif(lat_deg * 1.0, lon_deg * 1.0, alt_m * 1.0)
  end

  @doc "ECEF `{x, y, z}` meters → geodetic `{lat_deg, lon_deg, alt_m}`."
  @spec ecef_to_latlon(number(), number(), number()) :: {float(), float(), float()}
  def ecef_to_latlon(x, y, z) do
    Native.ecef_to_latlon_nif(x * 1.0, y * 1.0, z * 1.0)
  end
end