@mytec: iter3.4.0 start

This commit is contained in:
2026-02-02 21:30:00 +02:00
parent 7f0b4d2269
commit 867ee3d0f4
29 changed files with 1386 additions and 324 deletions

View File

@@ -485,7 +485,16 @@ class CoverageService:
)
streets = _filter_osm_list_to_bbox(streets, min_lat, min_lon, max_lat, max_lon)
water_bodies = _filter_osm_list_to_bbox(water_bodies, min_lat, min_lon, max_lat, max_lon)
vegetation_areas = _filter_osm_list_to_bbox(vegetation_areas, min_lat, min_lon, max_lat, max_lon)
# Cap vegetation at 5000 — each area requires O(samples × areas)
# point-in-polygon checks per grid point. 20k+ areas with dominant
# path enabled causes OOM via worker memory explosion.
vegetation_areas = _filter_osm_list_to_bbox(
vegetation_areas, min_lat, min_lon, max_lat, max_lon,
max_count=5000,
)
_clog(f"Filtered OSM data: {len(buildings)} bldgs, {len(streets)} streets, "
f"{len(water_bodies)} water, {len(vegetation_areas)} veg")
# Build spatial index for buildings
spatial_idx: Optional[SpatialIndex] = None
@@ -650,10 +659,13 @@ class CoverageService:
sites: List[SiteParams],
settings: CoverageSettings,
cancel_token: Optional[CancellationToken] = None,
progress_fn: Optional[Callable[[str, float], None]] = None,
) -> List[CoveragePoint]:
"""
Calculate combined coverage from multiple sites
Best server (strongest signal) wins at each point
progress_fn(phase, pct): optional callback for progress updates (0.0-1.0).
"""
if not sites:
return []
@@ -661,10 +673,26 @@ class CoverageService:
# Apply preset once
settings = apply_preset(settings)
# Per-site progress tracking for averaged overall progress
num_sites = len(sites)
_site_progress = [0.0] * num_sites
def _make_site_progress(idx: int):
"""Create a progress_fn for one site that reports scaled overall progress."""
def _site_fn(phase: str, pct: float, _eta=None):
_site_progress[idx] = pct
if progress_fn:
overall = sum(_site_progress) / num_sites
progress_fn(f"Site {idx + 1}/{num_sites}: {phase}", overall)
return _site_fn
# Get all individual coverages
all_coverages = await asyncio.gather(*[
self.calculate_coverage(site, settings, cancel_token)
for site in sites
self.calculate_coverage(
site, settings, cancel_token,
progress_fn=_make_site_progress(i) if progress_fn else None,
)
for i, site in enumerate(sites)
])
# Combine by best signal
@@ -751,7 +779,8 @@ class CoverageService:
points = []
timing = {"los": 0.0, "buildings": 0.0, "antenna": 0.0,
"dominant_path": 0.0, "street_canyon": 0.0,
"reflection": 0.0, "vegetation": 0.0}
"reflection": 0.0, "vegetation": 0.0,
"lod_none": 0, "lod_simplified": 0, "lod_full": 0}
total = len(grid)
log_interval = max(1, total // 20)
@@ -901,7 +930,6 @@ class CoverageService:
# LOD_NONE: skip dominant path entirely for distant points (>3km)
if lod == LODLevel.NONE:
timing.setdefault("lod_none", 0)
timing["lod_none"] += 1
else:
t0 = time.time()
@@ -909,12 +937,10 @@ class CoverageService:
# LOD_SIMPLIFIED: limit buildings for mid-range points (1.5-3km)
dp_buildings = nearby_buildings
if lod == LODLevel.SIMPLIFIED:
timing.setdefault("lod_simplified", 0)
timing["lod_simplified"] += 1
if len(nearby_buildings) > SIMPLIFIED_MAX_BUILDINGS:
dp_buildings = nearby_buildings[:SIMPLIFIED_MAX_BUILDINGS]
else:
timing.setdefault("lod_full", 0)
timing["lod_full"] += 1
# nearby_buildings already filtered via spatial index —