added subprox

This commit is contained in:
2026-06-11 09:32:33 +03:00
parent 94e2b772e8
commit c2f26c8ec3
15 changed files with 694 additions and 12 deletions
+112 -12
View File
@@ -315,6 +315,117 @@ def _offset_m(lat: float, lon: float, north_m: float, east_m: float) -> tuple[fl
return lat + dlat, lon + dlon
_MAX_GRID_POINTS = 2500
def _auto_step_m(radius_m: float) -> float:
if radius_m <= 150:
return 10.0
if radius_m <= 300:
return 15.0
return 20.0
def _sample_circular_grid(
lat: float,
lon: float,
radius_m: float,
step_m: float,
) -> list[tuple[int, int, float, float, float]]:
steps = int(radius_m / step_m)
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)
cells.append((i, j, la, lo, dist))
return cells
def _resolve_grid_step(lat: float, lon: float, radius_m: float, step_m: float) -> float:
if step_m <= 0:
step_m = _auto_step_m(radius_m)
step_m = max(5.0, min(float(step_m), 100.0))
while len(_sample_circular_grid(lat, lon, radius_m, step_m)) > _MAX_GRID_POINTS:
step_m = math.ceil(step_m * 1.25)
if step_m >= radius_m:
break
return step_m
def build_elevation_grid(
lat: float,
lon: float,
radius_m: float = 200.0,
step_m: float = 0.0,
) -> dict[str, Any]:
"""Circular elevation grid for heatmap (delta relative to center)."""
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(100.0, min(float(radius_m), 500.0))
step_m = _resolve_grid_step(lat, lon, radius_m, step_m)
center_elev = fetch_elevation_m(lat, lon)
if center_elev is None:
return {"ok": False, "error": "no elevation at center"}
grid_cells = _sample_circular_grid(lat, lon, radius_m, step_m)
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)
points: list[dict[str, Any]] = []
deltas: list[float] = []
for (i, j, la, lo, dist), elev in zip(grid_cells, elevations):
if elev is None:
continue
delta = float(elev) - center_elev
deltas.append(delta)
points.append(
{
"i": i,
"j": j,
"lat": round(la, 6),
"lon": round(lo, 6),
"dist_m": round(dist, 1),
"elevation_m": float(elev),
"delta_m": round(delta, 1),
}
)
if not points:
return {"ok": False, "error": "no elevation values in grid"}
return {
"ok": True,
"center": {
"lat": round(lat, 6),
"lon": round(lon, 6),
"elevation_m": center_elev,
},
"radius_m": radius_m,
"step_m": step_m,
"points": points,
"min_delta_m": round(min(deltas), 1),
"max_delta_m": round(max(deltas), 1),
"api_source": "elevation",
"elevation_url": ELEVATION_API_URL,
}
def find_nearest_hill(
lat: float,
lon: float,
@@ -339,18 +450,7 @@ def find_nearest_hill(
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))
grid_cells = _sample_circular_grid(lat, lon, radius_m, step_m)
if not grid_cells:
return {"ok": False, "error": "empty search grid"}