Auto-download missing SRTM tiles, treat water areas as 0m elevation
SRTM profiles no longer abort on missing tiles — water/ocean areas return 0m elevation instead of failing the entire profile and falling back to the rate-limited API. Elevation client and viewshed now pass download: true to auto-fetch missing tiles from S3. NFS mount changed to writable so downloaded tiles persist across pods.
This commit is contained in:
parent
80d1169f71
commit
e74adf0036
6 changed files with 32 additions and 56 deletions
|
|
@ -105,10 +105,8 @@ spec:
|
|||
volumeMounts:
|
||||
- name: srtm-data
|
||||
mountPath: /srtm
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: srtm-data
|
||||
nfs:
|
||||
server: 204.110.191.8
|
||||
path: /data/srtm
|
||||
readOnly: true
|
||||
|
|
|
|||
|
|
@ -16,14 +16,8 @@ defmodule Microwaveprop.Terrain.ElevationClient do
|
|||
fetch_elevation_profile_api(lat1, lon1, lat2, lon2, n)
|
||||
|
||||
tiles_dir ->
|
||||
case Srtm.fetch_elevation_profile(lat1, lon1, lat2, lon2, tiles_dir, n, opts) do
|
||||
{:ok, _profile} = ok ->
|
||||
ok
|
||||
|
||||
{:error, reason} ->
|
||||
Logger.warning("SRTM failed (#{inspect(reason)}), falling back to API")
|
||||
fetch_elevation_profile_api(lat1, lon1, lat2, lon2, n)
|
||||
end
|
||||
srtm_opts = Keyword.merge([download: true], opts)
|
||||
Srtm.fetch_elevation_profile(lat1, lon1, lat2, lon2, tiles_dir, n, srtm_opts)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -84,26 +84,19 @@ defmodule Microwaveprop.Terrain.Srtm do
|
|||
pts = sample_path(lat1, lon1, lat2, lon2, n)
|
||||
dist_km = haversine_km(lat1, lon1, lat2, lon2)
|
||||
|
||||
results =
|
||||
Enum.reduce_while(pts, {:ok, []}, fn pt, {:ok, acc} ->
|
||||
case lookup(pt.lat, pt.lon, tiles_dir, opts) do
|
||||
{:ok, elev} ->
|
||||
entry = %{
|
||||
lat: pt.lat,
|
||||
lon: pt.lon,
|
||||
d: pt.d,
|
||||
elev: elev,
|
||||
dist_km: pt.d * dist_km
|
||||
}
|
||||
profile =
|
||||
Enum.map(pts, fn pt ->
|
||||
elev =
|
||||
case lookup(pt.lat, pt.lon, tiles_dir, opts) do
|
||||
{:ok, elev} -> elev
|
||||
# Missing tile (water/ocean) or void value — treat as sea level
|
||||
{:error, _} -> 0
|
||||
end
|
||||
|
||||
{:cont, {:ok, acc ++ [entry]}}
|
||||
|
||||
{:error, reason} ->
|
||||
{:halt, {:error, reason}}
|
||||
end
|
||||
%{lat: pt.lat, lon: pt.lon, d: pt.d, elev: elev, dist_km: pt.d * dist_km}
|
||||
end)
|
||||
|
||||
results
|
||||
{:ok, profile}
|
||||
end
|
||||
|
||||
defp read_elevation(fd, lat, lon) do
|
||||
|
|
|
|||
|
|
@ -151,25 +151,21 @@ defmodule Microwaveprop.Terrain.Viewshed do
|
|||
terrain_check_km = min(radio_horizon_km(ant_height_m) * 2.0, max_range_km)
|
||||
{end_lat, end_lon} = destination_point(origin_lat, origin_lon, bearing, terrain_check_km)
|
||||
|
||||
case Srtm.fetch_elevation_profile(origin_lat, origin_lon, end_lat, end_lon, tiles_dir) do
|
||||
{:ok, profile} ->
|
||||
analysis =
|
||||
TerrainAnalysis.analyse(profile, terrain_check_km, freq_ghz, ant_ht_a: ant_height_m, ant_ht_b: ant_height_m)
|
||||
{:ok, profile} =
|
||||
Srtm.fetch_elevation_profile(origin_lat, origin_lon, end_lat, end_lon, tiles_dir, 64, download: true)
|
||||
|
||||
reach_km = effective_reach_km(analysis, max_range_km, score)
|
||||
{reach_lat, reach_lon} = destination_point(origin_lat, origin_lon, bearing, reach_km)
|
||||
analysis =
|
||||
TerrainAnalysis.analyse(profile, terrain_check_km, freq_ghz, ant_ht_a: ant_height_m, ant_ht_b: ant_height_m)
|
||||
|
||||
%{
|
||||
bearing: bearing,
|
||||
reach_km: reach_km,
|
||||
lat: reach_lat,
|
||||
lon: reach_lon
|
||||
}
|
||||
reach_km = effective_reach_km(analysis, max_range_km, score)
|
||||
{reach_lat, reach_lon} = destination_point(origin_lat, origin_lon, bearing, reach_km)
|
||||
|
||||
{:error, _} ->
|
||||
{end_lat2, end_lon2} = destination_point(origin_lat, origin_lon, bearing, max_range_km)
|
||||
%{bearing: bearing, reach_km: max_range_km, lat: end_lat2, lon: end_lon2}
|
||||
end
|
||||
%{
|
||||
bearing: bearing,
|
||||
reach_km: reach_km,
|
||||
lat: reach_lat,
|
||||
lon: reach_lon
|
||||
}
|
||||
end
|
||||
|
||||
# Radio horizon distance in km for a given antenna height (K=4/3 atmosphere)
|
||||
|
|
|
|||
|
|
@ -148,21 +148,14 @@ defmodule Microwaveprop.Terrain.ElevationClientSrtmTest do
|
|||
end
|
||||
|
||||
@tag :srtm
|
||||
test "falls back to API when SRTM tiles missing" do
|
||||
test "returns zero elevation when SRTM tiles missing (no API fallback)" do
|
||||
Application.put_env(:microwaveprop, :srtm_tiles_dir, "/nonexistent/tiles")
|
||||
|
||||
Req.Test.stub(ElevationClient, fn conn ->
|
||||
Req.Test.json(conn, %{"elevation" => [200.0, 250.0, 180.0]})
|
||||
end)
|
||||
assert {:ok, profile} =
|
||||
ElevationClient.fetch_elevation_profile(32.9, -97.0, 30.3, -97.7, 2)
|
||||
|
||||
{result, _log} =
|
||||
with_log(fn ->
|
||||
ElevationClient.fetch_elevation_profile(32.9, -97.0, 30.3, -97.7, 2)
|
||||
end)
|
||||
|
||||
assert {:ok, profile} = result
|
||||
assert length(profile) == 3
|
||||
assert hd(profile).elev == 200.0
|
||||
assert Enum.all?(profile, fn p -> p.elev == 0 end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -190,9 +190,11 @@ defmodule Microwaveprop.Terrain.SrtmTest do
|
|||
assert last.dist_km > 0
|
||||
end
|
||||
|
||||
test "returns error when tiles dir does not exist" do
|
||||
assert {:error, _} =
|
||||
test "returns zero elevation when tiles dir does not exist" do
|
||||
assert {:ok, profile} =
|
||||
Srtm.fetch_elevation_profile(32.78, -96.8, 32.5, -96.5, "/nonexistent", 4)
|
||||
|
||||
assert Enum.all?(profile, fn p -> p.elev == 0 end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue