Improve coordinate handling and add configurable position sensitivity
- Fix zero coordinate handling to distinguish between invalid coordinates and valid 0.0 (equator/prime meridian) - Add to_float_safe() function that preserves nil for proper coordinate validation - Add comprehensive coordinate validation with descriptive logging in JavaScript - Make position change threshold configurable via application config (default: 0.001°) - Add extensive test coverage for edge cases including nil coordinates and equator crossing - Improve robustness for real-world APRS coordinate edge cases 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
77eb5ac05b
commit
ef141d476f
4 changed files with 61 additions and 9 deletions
|
|
@ -11,7 +11,9 @@ export const InfoMap = {
|
||||||
const symbolHtml = this.el.dataset.symbolHtml;
|
const symbolHtml = this.el.dataset.symbolHtml;
|
||||||
|
|
||||||
// Validate coordinates
|
// Validate coordinates
|
||||||
|
const callsign = this.el.dataset.callsign;
|
||||||
if (isNaN(lat) || isNaN(lon)) {
|
if (isNaN(lat) || isNaN(lon)) {
|
||||||
|
console.warn(`InfoMap: Invalid coordinates lat=${lat}, lon=${lon} for ${callsign} during update`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,7 +63,7 @@ export const InfoMap = {
|
||||||
|
|
||||||
// Validate coordinates
|
// Validate coordinates
|
||||||
if (isNaN(lat) || isNaN(lon)) {
|
if (isNaN(lat) || isNaN(lon)) {
|
||||||
console.error("Invalid coordinates for InfoMap");
|
console.warn(`InfoMap: Invalid coordinates lat=${lat}, lon=${lon} for ${callsign}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,11 @@ config :aprsme, :cleanup_scheduler,
|
||||||
# 6 hours in milliseconds
|
# 6 hours in milliseconds
|
||||||
interval: 6 * 60 * 60 * 1000
|
interval: 6 * 60 * 60 * 1000
|
||||||
|
|
||||||
|
# Configure position tracking sensitivity
|
||||||
|
config :aprsme, :position_tracking,
|
||||||
|
# Position change threshold in degrees (~100 meters at equator)
|
||||||
|
change_threshold: 0.001
|
||||||
|
|
||||||
config :aprsme,
|
config :aprsme,
|
||||||
ecto_repos: [Aprsme.Repo]
|
ecto_repos: [Aprsme.Repo]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -101,16 +101,32 @@ defmodule AprsmeWeb.InfoLive.Show do
|
||||||
|
|
||||||
defp position_changed?(current_packet, new_packet) do
|
defp position_changed?(current_packet, new_packet) do
|
||||||
# Compare lat/lon to see if position actually changed
|
# Compare lat/lon to see if position actually changed
|
||||||
current_lat = to_float(current_packet.lat)
|
current_lat = to_float_safe(current_packet.lat)
|
||||||
current_lon = to_float(current_packet.lon)
|
current_lon = to_float_safe(current_packet.lon)
|
||||||
new_lat = to_float(new_packet.lat)
|
new_lat = to_float_safe(new_packet.lat)
|
||||||
new_lon = to_float(new_packet.lon)
|
new_lon = to_float_safe(new_packet.lon)
|
||||||
|
|
||||||
# Consider position changed if coordinates differ by more than ~100 meters (0.001 degrees)
|
# If any coordinate is invalid, consider it a change
|
||||||
lat_diff = abs(current_lat - new_lat)
|
case {current_lat, current_lon, new_lat, new_lon} do
|
||||||
lon_diff = abs(current_lon - new_lon)
|
{nil, _, _, _} ->
|
||||||
|
true
|
||||||
|
|
||||||
lat_diff > 0.001 or lon_diff > 0.001
|
{_, nil, _, _} ->
|
||||||
|
true
|
||||||
|
|
||||||
|
{_, _, nil, _} ->
|
||||||
|
true
|
||||||
|
|
||||||
|
{_, _, _, nil} ->
|
||||||
|
true
|
||||||
|
|
||||||
|
{curr_lat, curr_lon, new_lat, new_lon} ->
|
||||||
|
# Consider position changed if coordinates differ by more than the configured threshold
|
||||||
|
threshold = Application.get_env(:aprsme, :position_tracking, [])[:change_threshold] || 0.001
|
||||||
|
lat_diff = abs(curr_lat - new_lat)
|
||||||
|
lon_diff = abs(curr_lon - new_lon)
|
||||||
|
lat_diff > threshold or lon_diff > threshold
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Expose for testing
|
# Expose for testing
|
||||||
|
|
@ -186,6 +202,10 @@ defmodule AprsmeWeb.InfoLive.Show do
|
||||||
r * c
|
r * c
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Safe float conversion that preserves nil for invalid coordinates
|
||||||
|
defp to_float_safe(value), do: EncodingUtils.to_float(value)
|
||||||
|
|
||||||
|
# Legacy float conversion that defaults to 0.0 for backward compatibility
|
||||||
defp to_float(value), do: EncodingUtils.to_float(value) || 0.0
|
defp to_float(value), do: EncodingUtils.to_float(value) || 0.0
|
||||||
|
|
||||||
defp format_timestamp_for_display(packet) do
|
defp format_timestamp_for_display(packet) do
|
||||||
|
|
|
||||||
|
|
@ -43,5 +43,30 @@ defmodule AprsmeWeb.InfoLive.PositionChangeTest do
|
||||||
new_packet = %{lat: Decimal.new("40.7200"), lon: Decimal.new("-74.0060")}
|
new_packet = %{lat: Decimal.new("40.7200"), lon: Decimal.new("-74.0060")}
|
||||||
assert Show.position_changed_for_test(current_packet, new_packet)
|
assert Show.position_changed_for_test(current_packet, new_packet)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "handles coordinates at equator/prime meridian (0.0 is valid)" do
|
||||||
|
current_packet = %{lat: 0.0, lon: 0.0}
|
||||||
|
# Small change from valid 0.0
|
||||||
|
new_packet = %{lat: 0.0005, lon: 0.0}
|
||||||
|
refute Show.position_changed_for_test(current_packet, new_packet)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "detects change when coordinates become invalid (nil)" do
|
||||||
|
current_packet = %{lat: 40.7128, lon: -74.0060}
|
||||||
|
new_packet = %{lat: nil, lon: -74.0060}
|
||||||
|
assert Show.position_changed_for_test(current_packet, new_packet)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "detects change when coordinates become valid from invalid" do
|
||||||
|
current_packet = %{lat: nil, lon: -74.0060}
|
||||||
|
new_packet = %{lat: 40.7128, lon: -74.0060}
|
||||||
|
assert Show.position_changed_for_test(current_packet, new_packet)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "handles both coordinates being invalid" do
|
||||||
|
current_packet = %{lat: nil, lon: nil}
|
||||||
|
new_packet = %{lat: nil, lon: nil}
|
||||||
|
assert Show.position_changed_for_test(current_packet, new_packet)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue