Major refactoring of RFCP backend: - Modular propagation models (8 models) - SharedMemoryManager for terrain data - ProcessPoolExecutor parallel processing - WebSocket progress streaming - Building filtering pipeline (351k → 15k) - 82 unit tests Performance: Standard preset 38s → 5s (7.6x speedup) Known issue: Detailed preset timeout (fix in 3.1.0)
51 lines
1.5 KiB
Python
51 lines
1.5 KiB
Python
"""
|
|
Distance calculations using the haversine formula.
|
|
|
|
Supports both scalar and batch (NumPy array) operations.
|
|
"""
|
|
|
|
import numpy as np
|
|
from typing import Tuple
|
|
|
|
EARTH_RADIUS = 6371000 # meters
|
|
|
|
|
|
def haversine_distance(lat1: float, lon1: float, lat2: float, lon2: float) -> float:
|
|
"""Calculate distance between two points in meters."""
|
|
lat1, lon1, lat2, lon2 = map(np.radians, [lat1, lon1, lat2, lon2])
|
|
dlat = lat2 - lat1
|
|
dlon = lon2 - lon1
|
|
a = np.sin(dlat / 2) ** 2 + np.cos(lat1) * np.cos(lat2) * np.sin(dlon / 2) ** 2
|
|
c = 2 * np.arcsin(np.sqrt(a))
|
|
return float(EARTH_RADIUS * c)
|
|
|
|
|
|
def haversine_batch(
|
|
lat1: float, lon1: float,
|
|
lats2: np.ndarray, lons2: np.ndarray,
|
|
) -> np.ndarray:
|
|
"""Distance from one point to many points (meters)."""
|
|
lat1_rad = np.radians(lat1)
|
|
lon1_rad = np.radians(lon1)
|
|
lats2_rad = np.radians(lats2)
|
|
lons2_rad = np.radians(lons2)
|
|
|
|
dlat = lats2_rad - lat1_rad
|
|
dlon = lons2_rad - lon1_rad
|
|
|
|
a = np.sin(dlat / 2) ** 2 + np.cos(lat1_rad) * np.cos(lats2_rad) * np.sin(dlon / 2) ** 2
|
|
c = 2 * np.arcsin(np.sqrt(a))
|
|
|
|
return EARTH_RADIUS * c
|
|
|
|
|
|
def points_to_local_coords(
|
|
ref_lat: float, ref_lon: float,
|
|
lats: np.ndarray, lons: np.ndarray,
|
|
) -> Tuple[np.ndarray, np.ndarray]:
|
|
"""Convert lat/lon to local X/Y meters (equirectangular projection)."""
|
|
cos_lat = np.cos(np.radians(ref_lat))
|
|
x = (lons - ref_lon) * 111320.0 * cos_lat
|
|
y = (lats - ref_lat) * 110540.0
|
|
return x, y
|