# `Rover.Geo`
[🔗](https://github.com/nseaSeb/rover/blob/v0.4.0/lib/rover/geo.ex#L1)

Coordinate handling for Rover.

Rover speaks **`{latitude, longitude}`** everywhere — the order humans use when
they read a coordinate out loud. OpenLayers works
internally in `[x, y]` (i.e. `[longitude, latitude]`) projected to Web
Mercator; that flip happens once, in the JavaScript runtime, and never leaks
into your application code.

Mixing the two up is the single most common OpenLayers bug, so this module is
deliberately strict: latitudes outside `-90..90` and longitudes outside
`-180..180` raise instead of silently placing your marker in the ocean.

    iex> Rover.Geo.coord!({45.75, 4.85})
    {45.75, 4.85}

    iex> Rover.Geo.coord!(%{lat: 45.75, lng: 4.85})
    {45.75, 4.85}

# `bbox`

```elixir
@type bbox() :: {lat(), lon(), lat(), lon()}
```

A bounding box, as `{south, west, north, east}`.

# `coord`

```elixir
@type coord() :: {lat(), lon()}
```

A latitude/longitude pair, in that order.

# `coordish`

```elixir
@type coordish() :: coord() | map()
```

Anything Rover accepts as a coordinate: a `{lat, lon}` tuple, or a map with
`:lat`/`:latitude` and `:lon`/`:lng`/`:longitude` keys (atom or string).

# `lat`

```elixir
@type lat() :: float()
```

# `lon`

```elixir
@type lon() :: float()
```

# `bbox`

```elixir
@spec bbox([coordish()]) :: bbox() | nil
```

Returns the bounding box `{south, west, north, east}` enclosing `coords`.

Returns `nil` for an empty list. Note that this is a plain min/max box: it does
not handle geometries straddling the antimeridian.

## Examples

    iex> Rover.Geo.bbox([{45.0, 4.0}, {46.0, 5.0}])
    {45.0, 4.0, 46.0, 5.0}

    iex> Rover.Geo.bbox([])
    nil

# `coord`

```elixir
@spec coord(coordish()) :: {:ok, coord()} | :error
```

Same as `coord!/1` but returns `{:ok, coord}` or `:error`.

# `coord!`

```elixir
@spec coord!(coordish()) :: coord()
```

Normalises `value` into a `{lat, lon}` tuple of floats.

Raises `ArgumentError` when the shape is unrecognised or the values are out of
range.

## Examples

    iex> Rover.Geo.coord!({45.75, 4.85})
    {45.75, 4.85}

    iex> Rover.Geo.coord!(%{"latitude" => 48, "longitude" => 2})
    {48.0, 2.0}

A latitude of `145.75` is not a latitude, so Rover rejects it rather than
quietly drawing your marker somewhere impossible:

    iex> Rover.Geo.coord(%{lat: 145.75, lon: 4.85})
    :error

# `distance`

```elixir
@spec distance(coordish(), coordish()) :: float()
```

Great-circle distance between two coordinates, in metres (haversine).

## Examples

    iex> Rover.Geo.distance({45.75, 4.85}, {48.85, 2.35}) |> round()
    392834

# `to_lon_lat`

```elixir
@spec to_lon_lat(coordish()) :: [float()]
```

Renders a coordinate as the `[lon, lat]` pair OpenLayers expects.

You should not need this — the JavaScript runtime handles the flip — but it is
public so that `Rover.Geo` stays useful when you drop down to raw GeoJSON.

    iex> Rover.Geo.to_lon_lat({45.75, 4.85})
    [4.85, 45.75]

---

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