Make JetStream 2
[WebKit-https.git] / PerformanceTests / JetStream2 / RexBench / FlightPlanner / convert-nfdc.py
1 # Copyright (C) 2017 Apple Inc. All rights reserved.
2 # Copyright (C) 2016-2017 Michael Saboff. All rights reserved.
3 #
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions
6 # are met:
7 # 1. Redistributions of source code must retain the above copyright
8 #    notice, this list of conditions and the following disclaimer.
9 # 2. Redistributions in binary form must reproduce the above copyright
10 #    notice, this list of conditions and the following disclaimer in the
11 #    documentation and/or other materials provided with the distribution.
12 #
13 # THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 # PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
25 # This parses the legacy FAA NFDC text files APT.txt, AWY.txt, NAV.txt
26 # and FIX.txt into a JavaScript format that he Flight Planner can use.
27 # These text files can be downloaded from the FAA at
28 # https://nfdc.faa.gov/xwiki/bin/view/NFDC/28+Day+NASR+Subscription
29 # This script generates two JavaScript object literal files, one for
30 # waypoints and the other for airways.  Both files create maps, where
31 # the key is the waypoint or airway identifier and the value is the
32 # corresponding data.
33 #
34 # Run this file in a directory where APT.txt, AWY.txt, NAV.txt and FIX.txt
35 # are downloaded.
36
37 import re
38
39 latLongRE = re.compile('\s*(\d+)-(\d{2})-(\d{2}.\d{3,8})([NS])\s*(\d+)-(\d{2})-(\d{2}.\d{3,8})([EW])')
40 statesAbbreviationsToExclude = ['AK', 'HI']
41 navaidsToInclude = ['VOR', 'NDB']
42 airwayFixTypes = frozenset(['CN', 'NDB/DME', 'NDB', 'MIL-REP-PT', 'REP-PT', 'RNAV', 'VOR', 'VOR/DME', 'VORTAC'])
43 airwayTypes = frozenset(['J', 'T', 'Q', 'V'])
44
45
46 class WaypointData:
47     def __init__(self):
48         self.waypoints = []
49         self.allNames = set()
50
51     def parseLatLongDMS(self, latLongString):
52         match = latLongRE.match(latLongString)
53         latitude = float(match.group(1)) + (float(match.group(2)) * 60 + float(match.group(3))) / 3600
54         if match.group(4) == 'S':
55             latitude = -latitude
56
57         longitude = float(match.group(5)) + (float(match.group(6)) * 60 + float(match.group(7))) / 3600
58         if match.group(8) == 'W':
59             longitude = -longitude
60
61         return (latitude, longitude)
62
63     def parseAirportData(self, airportFile):
64         file = open(airportFile, 'r')
65
66         for line in file:
67             if line[0:3] != 'APT':
68                 continue
69
70             if line[48:50] in statesAbbreviationsToExclude:
71                 continue
72
73             facilityType = line[14:27].rstrip().title()
74
75             latLong = self.parseLatLongDMS(line[523:538] + line[550:565])
76
77             description = line[133:183].rstrip().title() + ' ' + facilityType + ', ' + line[93:133].rstrip().title() + ', ' + line[48:50]
78             description = description.replace('"', '\\"');
79
80             name = line[1210:1217].rstrip()
81             if not len(name):
82                 name = line[27:31].rstrip()
83
84             if name in self.allNames:
85                 print('Duplicate airport waypoint name {0}'.format(name))
86                 continue
87
88             self.allNames.add(name)
89             self.waypoints.append((name, facilityType, description, latLong[0], latLong[1]))
90
91         file.close()
92
93     def parseNavAidData(self, navaidFile):
94         file = open(navaidFile, 'r')
95
96         self.ndbs = []
97         for line in file:
98             if line[0:4] != 'NAV1':
99                 continue
100
101             if line[144:147] == 'AIN':
102                 continue
103
104             if not line[8:11] in navaidsToInclude:
105                 continue
106
107             facilityType = line[8:28].rstrip()
108
109             latLong = self.parseLatLongDMS(line[371:385] + line[396:410])
110
111             name = line[4:8].rstrip()
112             description = line[42:72].rstrip().title() + ' ' + line[8:28].rstrip()
113
114             # Since NDBs can have the same name as a VOR, we keep track of them separately
115             # and add NDBs below if the NDB has a unique name.
116             if line[8:11] == 'NDB':
117                 self.ndbs.append((name, facilityType, description, latLong[0], latLong[1]))
118             else:
119                 self.allNames.add(name)
120                 self.waypoints.append((name, facilityType, description, latLong[0], latLong[1]))
121
122         for ndb in self.ndbs:
123             if ndb[0] not in self.allNames:
124                 self.allNames.add(ndb[0])
125                 self.waypoints.append(ndb)
126
127         file.close()
128
129     def parseFixData(self, fixFile):
130         file = open(fixFile, 'r')
131
132         for line in file:
133             if line[0:4] != 'FIX1':
134                 continue
135
136             if line[4] < 'A' or line[4] > 'Z':
137                 continue
138
139             facilityType = 'Intersection'
140
141             latLong = self.parseLatLongDMS(line[66:80] + line[80:94])
142
143             name = line[4:34].rstrip()
144             description = name + ' Intersection'
145
146             if name in self.allNames:
147                 print('Duplicate fix name {0}'.format(name))
148                 continue
149
150             self.allNames.add(name)
151             self.waypoints.append((name, facilityType, description, latLong[0], latLong[1], ''))
152
153         file.close()
154
155     def outputWaypointFile(self, outputFilename):
156         sortedWaypoints = sorted(self.waypoints, key=lambda waypoint: waypoint[0])
157
158         outputFile = open(outputFilename, 'w+')
159
160         outputFile.write('var _faaWaypoints = {\n');
161         isFirst = True
162         for waypoint in sortedWaypoints:
163             if isFirst:
164                 isFirst = False
165             else:
166                 outputFile.write(',\n');
167             outputFile.write('    "{0}":{{ "name":"{0}", "type":"{1}", "description":"{2}", "latitude":{3}, "longitude":{4}}}'.format(waypoint[0], waypoint[1], waypoint[2], waypoint[3], waypoint[4]))
168         outputFile.write('\n};\n');
169
170
171 class AirwayData:
172     def __init__(self):
173         self.airways = []
174
175     def parseAirwayData(self, airwayFile):
176         file = open(airwayFile, 'r')
177
178         self.currentAirway = ''
179         self.airwayPoints = []
180
181         for line in file:
182             airway = line[4:8].rstrip()
183             if airway != self.currentAirway:
184                 if self.currentAirway != '':
185                     self.airways.append((self.currentAirway, self.airwayPoints))
186                 self.currentAirway = ''
187                 self.airwayPoints = []
188
189             if line[0:4] != 'AWY2':
190                 continue
191
192             if line[4] not in airwayTypes:
193                 continue
194
195             if line[9] != ' ':
196                 continue
197
198             if line[45:64].rstrip() not in airwayFixTypes:
199                 continue
200
201             if self.currentAirway == '':
202                 self.currentAirway = airway
203
204             if line[64:79].rstrip() == 'FIX':
205                 self.airwayPoints.append(line[15:45].rstrip())
206             else:
207                 self.airwayPoints.append(line[116:120].rstrip())
208
209         if self.currentAirway != '':
210             self.airways.append((self.currentAirway, self.airwayPoints))
211
212         file.close()
213
214     def outputAirwayFile(self, outputFilename):
215         sortedAirways = sorted(self.airways, key=lambda airways: airways[0])
216
217         outputFile = open(outputFilename, 'w+')
218
219         outputFile.write('var _faaAirways = {\n');
220         isFirst = True
221         for airway in sortedAirways:
222             if isFirst:
223                 isFirst = False
224             else:
225                 outputFile.write(',\n');
226             outputFile.write('    "{0}":{{ "name":"{0}", "fixes":['.format(airway[0]))
227             isFirstFix = True
228             for fix in airway[1]:
229                 if isFirstFix:
230                     isFirstFix = False
231                 else:
232                     outputFile.write(', ');
233
234                 outputFile.write('"{0}"'.format(fix))
235             outputFile.write(']}')
236         outputFile.write('\n};\n');
237
238
239 def main():
240     waypoints = WaypointData()
241     waypoints.parseAirportData('APT.txt')
242     waypoints.parseNavAidData('NAV.txt')
243     waypoints.parseFixData('FIX.txt')
244     waypoints.outputWaypointFile('waypoints.js')
245     airways = AirwayData()
246     airways.parseAirwayData('AWY.txt')
247     airways.outputAirwayFile('airways.js')
248
249
250 if __name__ == "__main__":
251     main()