Quazim0t0's picture
Upload 34 files
41e0c9e verified
Raw
History Blame Contribute Delete
2.34 kB
"""Great-circle geometry helpers for projecting estimated flight paths."""
from __future__ import annotations
import math
EARTH_RADIUS_KM = 6371.0088
KNOTS_TO_KMH = 1.852
def destination_point(lat: float, lon: float, bearing_deg: float, distance_km: float):
"""Great-circle destination given a start point, bearing and distance."""
ang = distance_km / EARTH_RADIUS_KM
brg = math.radians(bearing_deg)
lat1 = math.radians(lat)
lon1 = math.radians(lon)
lat2 = math.asin(
math.sin(lat1) * math.cos(ang) + math.cos(lat1) * math.sin(ang) * math.cos(brg)
)
lon2 = lon1 + math.atan2(
math.sin(brg) * math.sin(ang) * math.cos(lat1),
math.cos(ang) - math.sin(lat1) * math.sin(lat2),
)
return math.degrees(lat2), (math.degrees(lon2) + 540) % 360 - 180
def haversine_km(lat1, lon1, lat2, lon2):
p1, p2 = math.radians(lat1), math.radians(lat2)
dphi = math.radians(lat2 - lat1)
dlmb = math.radians(lon2 - lon1)
a = math.sin(dphi / 2) ** 2 + math.cos(p1) * math.cos(p2) * math.sin(dlmb / 2) ** 2
return 2 * EARTH_RADIUS_KM * math.asin(math.sqrt(a))
def initial_bearing(lat1, lon1, lat2, lon2):
p1, p2 = math.radians(lat1), math.radians(lat2)
dl = math.radians(lon2 - lon1)
y = math.sin(dl) * math.cos(p2)
x = math.cos(p1) * math.sin(p2) - math.sin(p1) * math.cos(p2) * math.cos(dl)
return (math.degrees(math.atan2(y, x)) + 360) % 360
def estimate_endpoint(lat, lon, track_deg, gspeed_knots, seconds_remaining,
dest_lat=None, dest_lon=None):
"""Return (end_lat, end_lon, distance_km, used_dest).
If we know the destination airport coords, the arc goes there. Otherwise we
dead-reckon forward along the current track for the remaining ETA.
"""
if dest_lat is not None and dest_lon is not None:
d = haversine_km(lat, lon, dest_lat, dest_lon)
return dest_lat, dest_lon, d, True
if not gspeed_knots or not seconds_remaining or seconds_remaining <= 0:
# Fall back to a short forward stub so the arc is still visible.
seconds_remaining = 1800
gspeed_knots = gspeed_knots or 450
dist_km = gspeed_knots * KNOTS_TO_KMH * (seconds_remaining / 3600.0)
elat, elon = destination_point(lat, lon, track_deg or 0, dist_km)
return elat, elon, dist_km, False