fix: дистанции до воды/НП — real = merc×cos + метры→км (было 850 «км» до озера)
Два бага в одной строке: водные дистанции делились на cos (вместо умножения, как дороги) и отдавались как км без /1000. Результат — 850.671 «км» до озера в Браславе (реально 271 м). Верифицировано против geography: merc×cos = 271.0 м ≈ geo 271.5 м (дельта 0.1%). Теперь Браслав SE: water 0.271 км, settle 0.119 км. 197 passed.
This commit is contained in:
@@ -0,0 +1,10 @@
|
|||||||
|
-- Верификация масштаба дистанций: mercator vs geography (Браслав)
|
||||||
|
WITH s AS (
|
||||||
|
SELECT ST_Transform(ST_SetSRID(ST_MakePoint(27.03, 55.64), 4326), 3857) AS c_m,
|
||||||
|
ST_SetSRID(ST_MakePoint(27.03, 55.64), 4326) AS c_g
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
(SELECT MIN(ST_Distance(p.way, c_m)) FROM planet_osm_polygon p, s
|
||||||
|
WHERE (p."natural"='water' OR p.landuse='reservoir') AND p.way && ST_Expand(s.c_m, 30000)) AS merc_m,
|
||||||
|
(SELECT MIN(ST_Distance(ST_Transform(p.way, 4326)::geography, c_g::geography)) FROM planet_osm_polygon p, s
|
||||||
|
WHERE (p."natural"='water' OR p.landuse='reservoir') AND p.way && ST_Expand(s.c_m, 30000)) AS geo_m;
|
||||||
+10
-9
@@ -100,19 +100,19 @@ def get_zone_features_postgis(lat: float, lon: float, direction: str, radius_m:
|
|||||||
AND p.way && s.sector
|
AND p.way && s.sector
|
||||||
),
|
),
|
||||||
water_near AS (
|
water_near AS (
|
||||||
SELECT MIN(ST_Distance(p.way, s.center_m)) / :scale AS meters
|
SELECT MIN(ST_Distance(p.way, s.center_m)) AS meters
|
||||||
FROM planet_osm_polygon p, s
|
FROM planet_osm_polygon p, s
|
||||||
WHERE (p."natural" = 'water' OR p.landuse = 'reservoir')
|
WHERE (p."natural" = 'water' OR p.landuse = 'reservoir')
|
||||||
AND p.way && ST_Transform(ST_SetSRID(ST_GeomFromText(:sector_wkt), 4326), 3857)
|
AND p.way && s.sector
|
||||||
),
|
),
|
||||||
waterway_near AS (
|
waterway_near AS (
|
||||||
SELECT MIN(ST_Distance(l.way, s.center_m)) / :scale AS meters
|
SELECT MIN(ST_Distance(l.way, s.center_m)) AS meters
|
||||||
FROM planet_osm_line l, s
|
FROM planet_osm_line l, s
|
||||||
WHERE l.waterway IN ('river','stream','canal','ditch','drain')
|
WHERE l.waterway IN ('river','stream','canal','ditch','drain')
|
||||||
AND l.way && s.sector
|
AND l.way && s.sector
|
||||||
),
|
),
|
||||||
settle_near AS (
|
settle_near AS (
|
||||||
SELECT MIN(ST_Distance(p.way, s.center_m)) / :scale AS meters
|
SELECT MIN(ST_Distance(p.way, s.center_m)) AS meters
|
||||||
FROM planet_osm_point p, s
|
FROM planet_osm_point p, s
|
||||||
WHERE p.place IN ('village','town','city')
|
WHERE p.place IN ('village','town','city')
|
||||||
AND p.way && s.sector
|
AND p.way && s.sector
|
||||||
@@ -137,10 +137,11 @@ def get_zone_features_postgis(lat: float, lon: float, direction: str, radius_m:
|
|||||||
# real = mercator * cos(lat) (проверено: merc/geo = 1/cos(lat) точно).
|
# real = mercator * cos(lat) (проверено: merc/geo = 1/cos(lat) точно).
|
||||||
roads_km = float(row[0] or 0) / 1000.0 * scale
|
roads_km = float(row[0] or 0) / 1000.0 * scale
|
||||||
forest_m2 = float(row[1] or 0) * (scale * scale) # mercator-м² → реальные м²
|
forest_m2 = float(row[1] or 0) * (scale * scale) # mercator-м² → реальные м²
|
||||||
# Расстояния (row[2..4]) уже поделены на scale в SQL → вернулись в метры
|
# Дистанции: mercator-метры → реальные метры (та же поправка, что у дорог:
|
||||||
water_poly_m = row[2]
|
# раньше деление на cos здесь ДВОИЛО раздувание — 850 «км» до озера в Браславе).
|
||||||
waterway_m = row[3]
|
water_poly_m = float(row[2]) * scale if row[2] is not None else None
|
||||||
settle_m = row[4]
|
waterway_m = float(row[3]) * scale if row[3] is not None else None
|
||||||
|
settle_m = float(row[4]) * scale if row[4] is not None else None
|
||||||
|
|
||||||
search_area_km2 = math.pi * (radius_m / 1000.0) ** 2
|
search_area_km2 = math.pi * (radius_m / 1000.0) ** 2
|
||||||
road_density = roads_km / search_area_km2 if search_area_km2 > 0 else 0.0
|
road_density = roads_km / search_area_km2 if search_area_km2 > 0 else 0.0
|
||||||
@@ -153,7 +154,7 @@ def get_zone_features_postgis(lat: float, lon: float, direction: str, radius_m:
|
|||||||
if forest_m2 > 0 and search_area_km2 > 0:
|
if forest_m2 > 0 and search_area_km2 > 0:
|
||||||
forest_pct = round(min(1.0, (forest_m2 / 1e6) / search_area_km2), 3)
|
forest_pct = round(min(1.0, (forest_m2 / 1e6) / search_area_km2), 3)
|
||||||
|
|
||||||
water_candidates = [float(m) for m in (water_poly_m, waterway_m) if m is not None]
|
water_candidates = [float(m) / 1000.0 for m in (water_poly_m, waterway_m) if m is not None]
|
||||||
water_distance_km = round(min(water_candidates), 3) if water_candidates else None
|
water_distance_km = round(min(water_candidates), 3) if water_candidates else None
|
||||||
settlement_distance_km = round(float(settle_m) / 1000.0, 3) if settle_m is not None else None
|
settlement_distance_km = round(float(settle_m) / 1000.0, 3) if settle_m is not None else None
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user