feat(rover): "only use known ideal locations" toggle
Adds a checkbox in the rover sidebar that constrains the suggested candidate spots to lat/lon points tagged as :ideal in /rover-locations. When enabled, Compute.run replaces grid cells with synthetic cells at each ideal location's exact coordinates, inheriting the propagation score from the nearest grid cell so atmospheric forecast still factors in. Path-clearance, terrain, building, and canopy penalties run unchanged on those snapped candidates.
This commit is contained in:
parent
5094ea0837
commit
488b968cdc
2 changed files with 69 additions and 2 deletions
|
|
@ -131,8 +131,17 @@ defmodule Microwaveprop.Rover.Compute do
|
|||
step.("Loading propagation grid")
|
||||
raw_cells = time_step("scores_at", fn -> scores_at.(band_mhz, valid_time, bbox) end)
|
||||
|
||||
ideal_locations = Map.get(args, :ideal_locations, nil)
|
||||
|
||||
candidate_cells =
|
||||
case ideal_locations do
|
||||
nil -> raw_cells
|
||||
[] -> raw_cells
|
||||
locations -> snap_cells_to_locations(locations, raw_cells)
|
||||
end
|
||||
|
||||
in_radius =
|
||||
Enum.filter(raw_cells, fn cell ->
|
||||
Enum.filter(candidate_cells, fn cell ->
|
||||
DriveTime.haversine_km({home.lat, home.lon}, {cell.lat, cell.lon}) <= radius_km
|
||||
end)
|
||||
|
||||
|
|
@ -325,6 +334,27 @@ defmodule Microwaveprop.Rover.Compute do
|
|||
|> Canopy.lookup_many()
|
||||
end
|
||||
|
||||
# When the user constrains candidates to known ideal locations, build
|
||||
# synthetic cells at each location's exact lat/lon, inheriting the
|
||||
# propagation score from the nearest grid cell (so atmospheric forecast
|
||||
# still factors in even though the spot itself isn't a grid centroid).
|
||||
defp snap_cells_to_locations(locations, raw_cells) do
|
||||
Enum.flat_map(locations, fn loc ->
|
||||
case nearest_grid_cell(raw_cells, loc) do
|
||||
nil -> []
|
||||
cell -> [%{lat: loc.lat, lon: loc.lon, score: cell.score}]
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
defp nearest_grid_cell([], _loc), do: nil
|
||||
|
||||
defp nearest_grid_cell(cells, loc) do
|
||||
Enum.min_by(cells, fn c ->
|
||||
DriveTime.haversine_km({c.lat, c.lon}, {loc.lat, loc.lon})
|
||||
end)
|
||||
end
|
||||
|
||||
defp terrain_db(nil), do: 0.0
|
||||
|
||||
defp terrain_db(clearance_m) do
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ defmodule MicrowavepropWeb.RoverLive do
|
|||
home_form_error: nil,
|
||||
scoring_loading: false,
|
||||
scoring_step: nil,
|
||||
only_ideal_locations: false,
|
||||
url_loaded?: false
|
||||
)}
|
||||
end
|
||||
|
|
@ -193,6 +194,10 @@ defmodule MicrowavepropWeb.RoverLive do
|
|||
|> push_event("update_drive_radius", %{km: radius_km})}
|
||||
end
|
||||
|
||||
def handle_event("toggle_only_ideal", _params, socket) do
|
||||
{:noreply, assign(socket, only_ideal_locations: not socket.assigns.only_ideal_locations)}
|
||||
end
|
||||
|
||||
def handle_event("toggle_station", %{"id" => id}, socket) do
|
||||
handle_station_mutation(socket, id, &toggle_station/2)
|
||||
end
|
||||
|
|
@ -713,7 +718,7 @@ defmodule MicrowavepropWeb.RoverLive do
|
|||
end
|
||||
|
||||
defp scoring_args(socket) do
|
||||
%{
|
||||
base = %{
|
||||
home: socket.assigns.home,
|
||||
stations: stations_for_compute(socket.assigns.fixed_stations),
|
||||
band_mhz: socket.assigns.band,
|
||||
|
|
@ -722,6 +727,17 @@ defmodule MicrowavepropWeb.RoverLive do
|
|||
max_distance_km: socket.assigns.drive_radius_km,
|
||||
min_elev_gain: 0
|
||||
}
|
||||
|
||||
if socket.assigns.only_ideal_locations do
|
||||
ideals =
|
||||
Rover.list_locations()
|
||||
|> Enum.filter(&(&1.status == :ideal))
|
||||
|> Enum.map(fn l -> %{lat: l.lat, lon: l.lon} end)
|
||||
|
||||
Map.put(base, :ideal_locations, ideals)
|
||||
else
|
||||
base
|
||||
end
|
||||
end
|
||||
|
||||
defp find_candidate(candidates, grid) do
|
||||
|
|
@ -1163,6 +1179,27 @@ defmodule MicrowavepropWeb.RoverLive do
|
|||
</div>
|
||||
</.sidebar_section>
|
||||
|
||||
<.sidebar_section title="CANDIDATES">
|
||||
<label class="flex items-start gap-2 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={@only_ideal_locations}
|
||||
phx-click="toggle_only_ideal"
|
||||
class="checkbox checkbox-sm checkbox-primary mt-0.5"
|
||||
/>
|
||||
<span class="text-xs leading-tight">
|
||||
Only use known ideal locations
|
||||
<span class="block text-[10px] opacity-60 mt-0.5">
|
||||
Restricts suggestions to spots tagged "ideal" in <a
|
||||
href={~p"/rover-locations"}
|
||||
class="link"
|
||||
target="_blank"
|
||||
>/rover-locations</a>.
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
</.sidebar_section>
|
||||
|
||||
<div class="mt-auto p-3 text-[11px] text-neutral-content/50 border-t border-base-300/50">
|
||||
Tip: click any cell to see per-station predicted SNR.
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue