full frontend refactor

This commit is contained in:
2026-01-25 10:26:23 +01:00
parent 317ee96ba3
commit 559a4c3e9f
18 changed files with 2803 additions and 1224 deletions

View File

@@ -266,4 +266,70 @@ defmodule MoundHunters.MoundParser do
end
end
end
@doc """
Converts Web Mercator coordinates (EPSG:3857) to WGS84 lat/lng (EPSG:4326).
Web Mercator uses meters from origin, this converts back to decimal degrees.
## Examples
iex> MoundHunters.MoundParser.web_mercator_to_latlon(0, 0)
{0.0, 0.0}
iex> MoundHunters.MoundParser.web_mercator_to_latlon(1113194.91, 5009377.09)
{10.0, 40.0}
"""
@spec web_mercator_to_latlon(float(), float()) :: {lat :: float(), lon :: float()}
def web_mercator_to_latlon(x, y) do
# Web Mercator origin offset (meters)
origin_shift = :math.pi() * 6_378_137.0
# Convert x to longitude
lon = x / origin_shift * 180.0
# Convert y to latitude
lat = y / origin_shift * 180.0
lat =
180.0 / :math.pi() *
(2.0 * :math.atan(:math.exp(lat * :math.pi() / 180.0)) - :math.pi() / 2.0)
{lat, lon}
end
@doc """
Converts a bounding box from Web Mercator to lat/lng.
Returns a map with min/max lat/lng values.
## Examples
iex> MoundHunters.MoundParser.bounds_web_mercator_to_latlon(
...> %{min_x: -9_000_000, max_x: -8_900_000, min_y: 4_900_000, max_y: 5_000_000}
...> )
%{min_lat: ..., max_lat: ..., min_lng: ..., max_lng: ...}
"""
@spec bounds_web_mercator_to_latlon(%{
min_x: float(),
max_x: float(),
min_y: float(),
max_y: float()
}) :: %{
min_lat: float(),
max_lat: float(),
min_lng: float(),
max_lng: float()
}
def bounds_web_mercator_to_latlon(%{min_x: min_x, max_x: max_x, min_y: min_y, max_y: max_y}) do
{min_lat, min_lng} = web_mercator_to_latlon(min_x, min_y)
{max_lat, max_lng} = web_mercator_to_latlon(max_x, max_y)
%{
min_lat: min_lat,
max_lat: max_lat,
min_lng: min_lng,
max_lng: max_lng
}
end
end