# `PhoenixKit.Modules.Storage.Geo`
[🔗](https://github.com/BeamLabEU/phoenix_kit/blob/v2.62.1/lib/modules/storage/geo.ex#L1)

Photos on a map: "what was taken in this area?" as one indexed lookup.

A photo's EXIF position is in `phoenix_kit_files.latitude` / `longitude`
(V215). The index is a GiST index on `point(longitude, latitude)`, which
Postgres has built in (no PostGIS), and a box on the map is

    point(longitude, latitude) <@ box(point(west, south), point(east, north))

A **bounds** is `{south, west, north, east}` in degrees, the corners of the
visible map: latitude -90..90, longitude -180..180. A box that crosses the
antimeridian (the Pacific, Fiji, eastern Russia) has `west > east`, and is
searched as two.

    Storage.list_files_in_scope(nil, bounds: {46.0, 14.0, 48.0, 16.0})
    Geo.within(File, {46.0, 14.0, 48.0, 16.0})
    Geo.parse_bounds("46,14,48,16")

A file with no position is never inside any box.

# `bounds`

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

# `parse_bounds`

```elixir
@spec parse_bounds(term()) :: bounds() | nil
```

A bounds from what a URL or a form carries: `"south,west,north,east"`, a list
of four, or a map with `"south"`, `"west"`, `"north"`, `"east"`. `nil` when it
is not four numbers, or the south is above the north.

# `within`

```elixir
@spec within(Ecto.Queryable.t(), bounds() | nil) :: Ecto.Query.t()
```

Narrows a query over files to those inside `bounds`. `nil` leaves it as it is.
A bounds that is not four numbers raises, so a typo does not become "no filter".

---

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