For each (rover cell, fixed station) pair, sample SRTM along the great-circle path and add a per-link dB bonus proportional to the rover's elevation above the highest intermediate terrain. Rover spots on hilltops with clear sight to multiple stations now rise to the top. Also vendor Leaflet's layers control PNGs and copy them under priv/static/assets/css/images/ on build so /rover stops 404'ing on layers-2x.png.
108 lines
3 KiB
Elixir
108 lines
3 KiB
Elixir
defmodule Microwaveprop.Rover.ComputeTest do
|
|
use ExUnit.Case, async: true
|
|
|
|
alias Microwaveprop.Rover.Compute
|
|
|
|
defp build_grid(home_lat, home_lon) do
|
|
# 3x3 grid of cells around home spaced 0.1 deg apart
|
|
for dlat <- [-0.1, 0.0, 0.1], dlon <- [-0.1, 0.0, 0.1] do
|
|
%{
|
|
lat: Float.round(home_lat + dlat, 4),
|
|
lon: Float.round(home_lon + dlon, 4),
|
|
score: 80
|
|
}
|
|
end
|
|
end
|
|
|
|
test "returns top_candidates ordered by score desc with required fields" do
|
|
home = %{lat: 33.0, lon: -96.0, elev_m: 200}
|
|
stations = [%{callsign: "W5LUA", lat: 33.10, lon: -96.625, selected: true}]
|
|
grid = build_grid(home.lat, home.lon)
|
|
|
|
scores_at = fn _band, _t, _bbox -> grid end
|
|
elev_lookup = fn points -> Map.new(points, fn p -> {p, 250} end) end
|
|
clearance_lookup = fn _cells, _stations -> %{} end
|
|
|
|
args = %{
|
|
home: home,
|
|
stations: stations,
|
|
band_mhz: 10_000,
|
|
valid_time: ~U[2026-04-25 12:00:00Z],
|
|
mode: :ssb,
|
|
max_distance_km: 65.0,
|
|
min_elev_gain: 0
|
|
}
|
|
|
|
result =
|
|
Compute.run(args,
|
|
scores_at: scores_at,
|
|
elev_lookup: elev_lookup,
|
|
clearance_lookup: clearance_lookup
|
|
)
|
|
|
|
assert is_map(result)
|
|
assert Map.has_key?(result, :cells)
|
|
assert Map.has_key?(result, :top_candidates)
|
|
|
|
assert is_list(result.cells)
|
|
assert length(result.top_candidates) <= 5
|
|
refute result.top_candidates == []
|
|
|
|
# Sorted by score desc.
|
|
scores = Enum.map(result.top_candidates, & &1.score)
|
|
assert scores == Enum.sort(scores, :desc)
|
|
|
|
# Required candidate fields.
|
|
cand = hd(result.top_candidates)
|
|
|
|
for key <- [
|
|
:grid,
|
|
:lat,
|
|
:lon,
|
|
:elev_m,
|
|
:drive_min,
|
|
:score,
|
|
:tier_color,
|
|
:distance_km,
|
|
:bearing_compass,
|
|
:name
|
|
] do
|
|
assert Map.has_key?(cand, key), "expected candidate to have key #{inspect(key)}"
|
|
end
|
|
|
|
assert is_binary(cand.grid)
|
|
assert is_binary(cand.tier_color)
|
|
assert is_binary(cand.bearing_compass)
|
|
assert is_binary(cand.name)
|
|
end
|
|
|
|
test "filters cells failing min_elev_gain" do
|
|
home = %{lat: 33.0, lon: -96.0, elev_m: 500}
|
|
stations = [%{callsign: "W5LUA", lat: 33.1, lon: -96.6, selected: true}]
|
|
grid = build_grid(home.lat, home.lon)
|
|
|
|
# All elevations below home — nothing should pass min_elev_gain=200.
|
|
scores_at = fn _band, _t, _bbox -> grid end
|
|
elev_lookup = fn points -> Map.new(points, fn p -> {p, 100} end) end
|
|
clearance_lookup = fn _cells, _stations -> %{} end
|
|
|
|
result =
|
|
Compute.run(
|
|
%{
|
|
home: home,
|
|
stations: stations,
|
|
band_mhz: 10_000,
|
|
valid_time: ~U[2026-04-25 12:00:00Z],
|
|
mode: :ssb,
|
|
max_distance_km: 65.0,
|
|
min_elev_gain: 200
|
|
},
|
|
scores_at: scores_at,
|
|
elev_lookup: elev_lookup,
|
|
clearance_lookup: clearance_lookup
|
|
)
|
|
|
|
assert result.cells == []
|
|
assert result.top_candidates == []
|
|
end
|
|
end
|