@mytec: iter3.2.2 ready for test
This commit is contained in:
@@ -47,6 +47,7 @@ from app.services.materials_service import materials_service
|
||||
from app.services.dominant_path_service import (
|
||||
dominant_path_service, find_dominant_paths_vectorized,
|
||||
get_lod_level, LODLevel, SIMPLIFIED_MAX_BUILDINGS,
|
||||
_filter_buildings_by_distance,
|
||||
)
|
||||
from app.services.street_canyon_service import street_canyon_service, Street
|
||||
from app.services.reflection_service import reflection_service
|
||||
@@ -853,6 +854,16 @@ class CoverageService:
|
||||
if spatial_idx else buildings
|
||||
)
|
||||
|
||||
# Cap building count for the intersection loop — query_line can
|
||||
# return hundreds of buildings; sort by proximity so the first
|
||||
# intersecting building is found faster (loop breaks early).
|
||||
if len(nearby_buildings) > 50:
|
||||
nearby_buildings = _filter_buildings_by_distance(
|
||||
nearby_buildings,
|
||||
(site.lat, site.lon), (lat, lon),
|
||||
max_count=50, max_distance=500,
|
||||
)
|
||||
|
||||
if settings.use_buildings and nearby_buildings:
|
||||
site_total_h = site.height + site_elevation
|
||||
point_total_h = 1.5 + point_elevation
|
||||
@@ -897,22 +908,22 @@ class CoverageService:
|
||||
try:
|
||||
# LOD_SIMPLIFIED: limit buildings for mid-range points (1.5-3km)
|
||||
dp_buildings = nearby_buildings
|
||||
dp_spatial = spatial_idx
|
||||
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]
|
||||
dp_spatial = None # Skip spatial queries, use filtered list only
|
||||
else:
|
||||
timing.setdefault("lod_full", 0)
|
||||
timing["lod_full"] += 1
|
||||
|
||||
# nearby_buildings already filtered via spatial index —
|
||||
# don't pass spatial_idx to avoid redundant query_line()
|
||||
# and query_point() inside the vectorized function.
|
||||
dominant = find_dominant_paths_vectorized(
|
||||
site.lat, site.lon, site.height,
|
||||
lat, lon, 1.5,
|
||||
site.frequency, dp_buildings,
|
||||
spatial_idx=dp_spatial,
|
||||
)
|
||||
if dominant['path_type'] == 'direct':
|
||||
has_los = True
|
||||
|
||||
@@ -167,10 +167,14 @@ def find_dominant_paths_vectorized(
|
||||
3. Vectorized reflection point calculation
|
||||
4. Simplified diffraction estimate
|
||||
|
||||
Callers should pass pre-filtered buildings and spatial_idx=None
|
||||
to avoid redundant spatial queries (coverage_service already filters).
|
||||
|
||||
Returns dict with:
|
||||
has_los, path_type, total_loss, path_length, reflection_point
|
||||
"""
|
||||
global _vec_log_count
|
||||
t_total = time.perf_counter()
|
||||
|
||||
# Fast path: no buildings at all → direct LOS, skip all numpy work
|
||||
has_spatial_data = spatial_idx is not None and spatial_idx._grid
|
||||
@@ -183,11 +187,13 @@ def find_dominant_paths_vectorized(
|
||||
'reflection_point': None,
|
||||
}
|
||||
|
||||
# Get nearby buildings via spatial index (same filtering as sync version)
|
||||
# Get nearby buildings via spatial index or use pre-filtered list
|
||||
t0 = time.perf_counter()
|
||||
if spatial_idx:
|
||||
line_buildings = spatial_idx.query_line(tx_lat, tx_lon, rx_lat, rx_lon)
|
||||
else:
|
||||
line_buildings = buildings
|
||||
t_query = time.perf_counter() - t0
|
||||
|
||||
# No nearby buildings along this line → direct LOS
|
||||
if not line_buildings:
|
||||
@@ -199,12 +205,14 @@ def find_dominant_paths_vectorized(
|
||||
'reflection_point': None,
|
||||
}
|
||||
|
||||
t0 = time.perf_counter()
|
||||
line_buildings = _filter_buildings_by_distance(
|
||||
line_buildings,
|
||||
(tx_lat, tx_lon), (rx_lat, rx_lon),
|
||||
max_count=MAX_BUILDINGS_FOR_LINE,
|
||||
max_distance=MAX_DISTANCE_FROM_PATH,
|
||||
)
|
||||
t_filter = time.perf_counter() - t0
|
||||
|
||||
# Reference point for local coordinate system
|
||||
ref_lat = (tx_lat + rx_lat) / 2
|
||||
@@ -219,19 +227,11 @@ def find_dominant_paths_vectorized(
|
||||
direct_dist = np.linalg.norm(rx - tx)
|
||||
|
||||
# Convert buildings to arrays
|
||||
t0 = time.perf_counter()
|
||||
walls_start, walls_end, wall_to_bldg, poly_x, poly_y, poly_lengths = (
|
||||
_buildings_to_arrays(line_buildings, ref_lat, ref_lon)
|
||||
)
|
||||
|
||||
# Diagnostic log for first few points
|
||||
_vec_log_count += 1
|
||||
if _vec_log_count <= 3:
|
||||
print(
|
||||
f"[DOMINANT_PATH_VEC] Point #{_vec_log_count}: "
|
||||
f"buildings={len(line_buildings)}, walls={len(walls_start)}, "
|
||||
f"dist={direct_dist:.0f}m",
|
||||
flush=True,
|
||||
)
|
||||
t_arrays = time.perf_counter() - t0
|
||||
|
||||
# No buildings → direct LOS
|
||||
if len(poly_lengths) == 0 or np.all(poly_lengths < 3):
|
||||
@@ -244,9 +244,22 @@ def find_dominant_paths_vectorized(
|
||||
}
|
||||
|
||||
# Step 1: Vectorized direct LOS check
|
||||
t0 = time.perf_counter()
|
||||
intersects, _ = line_intersects_polygons_batch(tx, rx, poly_x, poly_y, poly_lengths)
|
||||
t_los = time.perf_counter() - t0
|
||||
|
||||
if not np.any(intersects):
|
||||
t_total_ms = (time.perf_counter() - t_total) * 1000
|
||||
_vec_log_count += 1
|
||||
if _vec_log_count <= 10:
|
||||
print(
|
||||
f"[DP_TIMING] #{_vec_log_count} LOS_CLEAR "
|
||||
f"bldgs={len(line_buildings)} walls={len(walls_start)} "
|
||||
f"query={t_query*1000:.1f}ms filter={t_filter*1000:.1f}ms "
|
||||
f"arrays={t_arrays*1000:.1f}ms los={t_los*1000:.1f}ms "
|
||||
f"total={t_total_ms:.1f}ms",
|
||||
flush=True,
|
||||
)
|
||||
return {
|
||||
'has_los': True,
|
||||
'path_type': 'direct',
|
||||
@@ -256,7 +269,8 @@ def find_dominant_paths_vectorized(
|
||||
}
|
||||
|
||||
# Step 2: Vectorized reflection path finding
|
||||
# Use all line buildings for reflection walls
|
||||
# Reuse line buildings for reflection (no separate spatial query)
|
||||
t0 = time.perf_counter()
|
||||
if spatial_idx:
|
||||
mid_lat = (tx_lat + rx_lat) / 2
|
||||
mid_lon = (tx_lon + rx_lon) / 2
|
||||
@@ -280,14 +294,33 @@ def find_dominant_paths_vectorized(
|
||||
else:
|
||||
r_walls_start, r_walls_end, r_wall_to_bldg = walls_start, walls_end, wall_to_bldg
|
||||
r_poly_x, r_poly_y, r_poly_lengths = poly_x, poly_y, poly_lengths
|
||||
t_refl_setup = time.perf_counter() - t0
|
||||
|
||||
t0 = time.perf_counter()
|
||||
refl_point, refl_length, refl_loss = find_best_reflection_path_vectorized(
|
||||
tx, rx,
|
||||
r_walls_start, r_walls_end, r_wall_to_bldg,
|
||||
r_poly_x, r_poly_y, r_poly_lengths,
|
||||
max_candidates=30,
|
||||
max_walls=100,
|
||||
max_los_checks=10,
|
||||
max_los_checks=5,
|
||||
)
|
||||
t_refl_calc = time.perf_counter() - t0
|
||||
|
||||
t_total_ms = (time.perf_counter() - t_total) * 1000
|
||||
|
||||
# Diagnostic log for first few points
|
||||
_vec_log_count += 1
|
||||
if _vec_log_count <= 10:
|
||||
print(
|
||||
f"[DP_TIMING] #{_vec_log_count} LOS_BLOCKED "
|
||||
f"bldgs={len(line_buildings)} walls={len(walls_start)} "
|
||||
f"dist={direct_dist:.0f}m "
|
||||
f"query={t_query*1000:.1f}ms filter={t_filter*1000:.1f}ms "
|
||||
f"arrays={t_arrays*1000:.1f}ms los={t_los*1000:.1f}ms "
|
||||
f"refl_setup={t_refl_setup*1000:.1f}ms refl_calc={t_refl_calc*1000:.1f}ms "
|
||||
f"total={t_total_ms:.1f}ms",
|
||||
flush=True,
|
||||
)
|
||||
|
||||
if refl_point is not None:
|
||||
|
||||
Reference in New Issue
Block a user