1+ import importlib
2+ import os
3+
4+ from numpy import (
5+ arcsin ,
6+ arctan2 ,
7+ cos ,
8+ degrees ,
9+ pi ,
10+ radians ,
11+ sin ,
12+ )
13+ import pandas
14+ import requests
15+
16+
117class rwy_data :
218 ''' Defines a new runway for an airport. Takes the form:
319 Name: Name of the runway, i.e: '01L'
@@ -15,12 +31,12 @@ class rwy_data:
1531 polynomial fit: y = f0 * x^6 + f1 * x^5 ... f6
1632 '''
1733 def __init__ (self , name , mainhdg , heading , rwy , rwy2 , gate ,
18- lons1 , lonm , lonp1 ,
19- lats1 , latm , latp1 ,
20- hdgs1 , hdgm , hdgp1 ,
21- gals1 , galm , galp1 ,
22- alts1 , altm , altp1 ,
23- rocs1 , rocm , rocp1 ):
34+ lons1 = None , lonm = None , lonp1 = None ,
35+ lats1 = None , latm = None , latp1 = None ,
36+ hdgs1 = None , hdgm = None , hdgp1 = None ,
37+ gals1 = None , galm = None , galp1 = None ,
38+ alts1 = None , altm = None , altp1 = None ,
39+ rocs1 = None , rocm = None , rocp1 = None ):
2440
2541 self .name = name
2642 self .mainhdg = mainhdg
@@ -47,3 +63,87 @@ def __init__(self, name, mainhdg, heading, rwy, rwy2, gate,
4763 self .rocm = rocm
4864 self .rocp1 = rocp1
4965
66+ def __eq__ (self , other ):
67+ return vars (self ) == vars (other )
68+
69+ def __repr__ (self ):
70+ return (
71+ 'rwy_data(' +
72+ ', ' .join ([
73+ f'{ key } ={ val !r} '
74+ for key , val in vars (self ).items () if val is not None
75+ ]) +
76+ ')'
77+ )
78+
79+
80+ def gate (rwy , rwy2 , dist = 2.9e3 , R = 6371e3 ):
81+ φ1 , λ1 = radians (rwy [0 ]), radians (rwy [1 ])
82+ φ2 , λ2 = radians (rwy2 [0 ]), radians (rwy2 [1 ])
83+ Δλ = λ2 - λ1
84+ θ = arctan2 (sin (Δλ ) * cos (φ2 ), cos (φ1 ) * sin (φ2 ) -
85+ sin (φ1 ) * cos (φ2 ) * cos (Δλ )) + pi
86+ φ3 = arcsin (sin (φ1 ) * cos (dist / R ) +
87+ cos (φ1 ) * sin (dist / R ) * cos (θ ))
88+ λ3 = λ1 + arctan2 (sin (θ ) * sin (dist / R ) * cos (φ1 ),
89+ cos (dist / R ) - sin (φ1 ) * sin (φ2 ))
90+ return [degrees (φ3 ), degrees (λ3 )]
91+
92+
93+ def retrieve_runway_list (name , runways_csv = 'runways.csv' ):
94+ result = []
95+ if not os .path .exists (runways_csv ):
96+ text = requests .get ('https://ourairports.com/data/runways.csv' ).text
97+ with open (runways_csv , 'w' ) as f :
98+ f .write (text )
99+ runways = pandas .read_csv (runways_csv )
100+ runways = runways .query (f'airport_ident == "{ name } "' )
101+ for idx , row in runways .iterrows ():
102+ le_heading = row .le_heading_degT
103+ he_heading = row .he_heading_degT
104+ if le_heading > 180 :
105+ le_heading = - (360 - le_heading )
106+ if he_heading > 180 :
107+ he_heading = - (360 - he_heading )
108+ result .append (rwy_data (
109+ name = row .le_ident ,
110+ mainhdg = row .le_heading_degT ,
111+ heading = [
112+ le_heading - 10 ,
113+ le_heading ,
114+ le_heading ,
115+ le_heading + 10 ,
116+ ],
117+ rwy = [row .le_latitude_deg , row .le_longitude_deg ],
118+ rwy2 = [row .he_latitude_deg , row .he_longitude_deg ],
119+ gate = gate (
120+ [row .le_latitude_deg , row .le_longitude_deg ],
121+ [row .he_latitude_deg , row .he_longitude_deg ],
122+ ),
123+ ))
124+ result .append (rwy_data (
125+ name = row .he_ident ,
126+ mainhdg = row .he_heading_degT ,
127+ heading = [
128+ he_heading - 10 ,
129+ he_heading ,
130+ he_heading ,
131+ he_heading + 10 ,
132+ ],
133+ rwy = [row .he_latitude_deg , row .he_longitude_deg ],
134+ rwy2 = [row .le_latitude_deg , row .le_longitude_deg ],
135+ gate = gate (
136+ [row .he_latitude_deg , row .he_longitude_deg ],
137+ [row .le_latitude_deg , row .le_longitude_deg ],
138+ ),
139+ ))
140+ return result
141+
142+
143+ def get_runway_list (name ):
144+ try :
145+ module = importlib .import_module (f'OS_Airports.{ name } ' )
146+ except ModuleNotFoundError :
147+ return retrieve_runway_list (name )
148+ else :
149+ return getattr (module , 'rwy_list' )
0 commit comments