@mytec: iter1.6 ready for testing

This commit is contained in:
2026-01-31 12:10:55 +02:00
parent 5821de9a8f
commit 7a5b27bd87
13 changed files with 773 additions and 101 deletions

View File

@@ -1,3 +1,4 @@
import re
import httpx
import asyncio
from typing import List, Optional
@@ -34,6 +35,33 @@ class BuildingsService:
self._memory_cache: dict[str, List[Building]] = {}
self._max_cache_size = 50 # bbox regions
@staticmethod
def _safe_int(value) -> Optional[int]:
"""Safely parse int from OSM tag (handles '1а', '2-3', '5+', etc.)"""
if not value:
return None
try:
return int(value)
except (ValueError, TypeError):
match = re.search(r'\d+', str(value))
if match:
return int(match.group())
return None
@staticmethod
def _safe_float(value) -> Optional[float]:
"""Safely parse float from OSM tag (handles '10 m', '~12', '10m')"""
if not value:
return None
try:
cleaned = str(value).lower().replace('m', '').replace('~', '').strip()
return float(cleaned)
except (ValueError, TypeError):
match = re.search(r'[\d.]+', str(value))
if match:
return float(match.group())
return None
def _bbox_key(self, min_lat: float, min_lon: float, max_lat: float, max_lon: float) -> str:
"""Generate cache key for bbox"""
# Round to 0.01 degree (~1km) grid for cache efficiency
@@ -157,7 +185,7 @@ class BuildingsService:
id=element["id"],
geometry=geometry,
height=height,
levels=int(tags.get("building:levels", 0)) or None,
levels=self._safe_int(tags.get("building:levels")),
building_type=tags.get("building"),
material=material_str,
tags=tags
@@ -169,22 +197,15 @@ class BuildingsService:
"""Estimate building height from OSM tags"""
# Explicit height tag
if "height" in tags:
try:
h = tags["height"]
# Handle "10 m" or "10m" format
if isinstance(h, str):
h = h.replace("m", "").replace(" ", "")
return float(h)
except (ValueError, TypeError):
pass
h = self._safe_float(tags["height"])
if h is not None and h > 0:
return h
# Calculate from levels
if "building:levels" in tags:
try:
levels = int(tags["building:levels"])
levels = self._safe_int(tags["building:levels"])
if levels is not None and levels > 0:
return levels * self.DEFAULT_LEVEL_HEIGHT
except (ValueError, TypeError):
pass
# Default based on building type
building_type = tags.get("building", "yes")