generated from Grigo/AndroidTemplate
added subproxy
This commit is contained in:
Binary file not shown.
@@ -307,3 +307,129 @@ def build_elevation_profile(
|
||||
if not elev_vals:
|
||||
result["api_error"] = "elevation API returned no values"
|
||||
return result
|
||||
|
||||
|
||||
def _offset_m(lat: float, lon: float, north_m: float, east_m: float) -> tuple[float, float]:
|
||||
dlat = north_m / 111_320.0
|
||||
dlon = east_m / (111_320.0 * max(math.cos(math.radians(lat)), 1e-6))
|
||||
return lat + dlat, lon + dlon
|
||||
|
||||
|
||||
def find_nearest_hill(
|
||||
lat: float,
|
||||
lon: float,
|
||||
radius_m: float = 5000.0,
|
||||
step_m: float = 300.0,
|
||||
min_prominence_m: float = 8.0,
|
||||
) -> dict[str, Any]:
|
||||
"""Find nearest local elevation maximum around a point."""
|
||||
probe = probe_elevation_api()
|
||||
if not probe["ok"]:
|
||||
return {
|
||||
"ok": False,
|
||||
"error": f"elevation API unreachable: {probe['error']}",
|
||||
"elevation_url": ELEVATION_API_URL,
|
||||
}
|
||||
|
||||
radius_m = max(500.0, min(float(radius_m), 15_000.0))
|
||||
step_m = max(100.0, min(float(step_m), 500.0))
|
||||
min_prominence_m = max(3.0, min(float(min_prominence_m), 100.0))
|
||||
|
||||
center_elev = fetch_elevation_m(lat, lon)
|
||||
if center_elev is None:
|
||||
return {"ok": False, "error": "no elevation at center"}
|
||||
|
||||
steps = int(radius_m / step_m)
|
||||
grid_cells: list[tuple[int, int, float, float, float]] = []
|
||||
for i in range(-steps, steps + 1):
|
||||
for j in range(-steps, steps + 1):
|
||||
north = i * step_m
|
||||
east = j * step_m
|
||||
dist = math.hypot(north, east)
|
||||
if dist > radius_m:
|
||||
continue
|
||||
la, lo = _offset_m(lat, lon, north, east)
|
||||
grid_cells.append((i, j, la, lo, dist))
|
||||
|
||||
if not grid_cells:
|
||||
return {"ok": False, "error": "empty search grid"}
|
||||
|
||||
lats = [c[2] for c in grid_cells]
|
||||
lons = [c[3] for c in grid_cells]
|
||||
elevations = fetch_elevations_batch(lats, lons)
|
||||
|
||||
grid: dict[tuple[int, int], dict[str, Any]] = {}
|
||||
for (i, j, la, lo, dist), elev in zip(grid_cells, elevations):
|
||||
grid[(i, j)] = {
|
||||
"lat": round(la, 6),
|
||||
"lon": round(lo, 6),
|
||||
"dist_m": round(dist, 1),
|
||||
"elevation_m": elev,
|
||||
}
|
||||
|
||||
def is_local_max(i: int, j: int, elev: float) -> bool:
|
||||
for di in (-1, 0, 1):
|
||||
for dj in (-1, 0, 1):
|
||||
if di == 0 and dj == 0:
|
||||
continue
|
||||
n = grid.get((i + di, j + dj))
|
||||
if n and n["elevation_m"] is not None and n["elevation_m"] >= elev:
|
||||
return False
|
||||
return True
|
||||
|
||||
candidates: list[dict[str, Any]] = []
|
||||
for (i, j), cell in grid.items():
|
||||
elev = cell.get("elevation_m")
|
||||
if elev is None:
|
||||
continue
|
||||
prominence = float(elev) - center_elev
|
||||
if prominence < min_prominence_m:
|
||||
continue
|
||||
if is_local_max(i, j, float(elev)):
|
||||
candidates.append({**cell, "prominence_m": round(prominence, 1)})
|
||||
|
||||
if not candidates:
|
||||
best = None
|
||||
for cell in grid.values():
|
||||
elev = cell.get("elevation_m")
|
||||
if elev is None:
|
||||
continue
|
||||
prominence = float(elev) - center_elev
|
||||
if prominence < min_prominence_m * 0.5:
|
||||
continue
|
||||
if best is None or cell["dist_m"] < best["dist_m"]:
|
||||
best = {
|
||||
**cell,
|
||||
"prominence_m": round(prominence, 1),
|
||||
"is_local_max": False,
|
||||
}
|
||||
if best is None:
|
||||
return {
|
||||
"ok": False,
|
||||
"error": "no hill found in radius",
|
||||
"center": {
|
||||
"lat": round(lat, 6),
|
||||
"lon": round(lon, 6),
|
||||
"elevation_m": center_elev,
|
||||
},
|
||||
"radius_m": radius_m,
|
||||
}
|
||||
hill = best
|
||||
else:
|
||||
candidates.sort(key=lambda c: c["dist_m"])
|
||||
hill = {**candidates[0], "is_local_max": True}
|
||||
|
||||
return {
|
||||
"ok": True,
|
||||
"center": {
|
||||
"lat": round(lat, 6),
|
||||
"lon": round(lon, 6),
|
||||
"elevation_m": center_elev,
|
||||
},
|
||||
"hill": hill,
|
||||
"candidates": len(candidates),
|
||||
"radius_m": radius_m,
|
||||
"step_m": step_m,
|
||||
"api_source": "elevation",
|
||||
"elevation_url": ELEVATION_API_URL,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user