Fix coordinate normalization bug

Added proper latitude/longitude normalization to prevent invalid coordinates:
- Longitude now wraps to -180 to 180 range (e.g., 199.0 -> -161.0)
- Latitude now clamps to -90 to 90 range
- Applied normalization before creating geometry in Packet module

Fixed 7 existing packets with invalid coordinates:
- WB6WWJ-N: 199.0 -> -161.0
- BI7MCK-1: 320.3 -> -39.7

This prevents map display issues and ensures PostGIS spatial queries
work correctly.
This commit is contained in:
Graham McIntire 2026-03-22 13:15:49 -05:00
parent a3aa2c61e0
commit 57f243d5b6
No known key found for this signature in database
2 changed files with 36 additions and 2 deletions

View file

@ -177,8 +177,12 @@ defmodule Aprsme.Packet do
defp extract_coordinates_from_data_extended(_), do: {nil, nil}
defp create_geometry_from_coordinates(changeset, lat, lon) do
if valid_coordinates?(lat, lon) do
create_and_set_location(changeset, lat, lon)
# Normalize coordinates to valid ranges
normalized_lat = CoordinateUtils.normalize_latitude(lat)
normalized_lon = CoordinateUtils.normalize_longitude(lon)
if valid_coordinates?(normalized_lat, normalized_lon) do
create_and_set_location(changeset, normalized_lat, normalized_lon)
else
changeset
end

View file

@ -86,6 +86,36 @@ defmodule AprsmeWeb.Live.Shared.CoordinateUtils do
def normalize_coordinate(%Decimal{} = decimal), do: Decimal.to_float(decimal)
def normalize_coordinate(coord), do: coord
@doc """
Normalize longitude to the -180 to 180 range.
"""
@spec normalize_longitude(number()) :: number()
def normalize_longitude(lon) when is_number(lon) do
# Wrap longitude to -180 to 180 range
cond do
lon > 180 -> normalize_longitude(lon - 360)
lon < -180 -> normalize_longitude(lon + 360)
true -> lon
end
end
def normalize_longitude(lon), do: lon
@doc """
Clamp latitude to the -90 to 90 range.
Latitude cannot wrap, so we clamp to valid range.
"""
@spec normalize_latitude(number()) :: number()
def normalize_latitude(lat) when is_number(lat) do
cond do
lat > 90 -> 90.0
lat < -90 -> -90.0
true -> lat
end
end
def normalize_latitude(lat), do: lat
@doc """
Calculate distance between two lat/lon points in meters using Haversine formula.
"""