]> git.mxchange.org Git - flightgear.git/blob - src/Airports/runways.cxx
e437dda08c4f444a13bde16a419be65a4e3c2547
[flightgear.git] / src / Airports / runways.cxx
1 // runways.cxx -- a simple class to manage airport runway info
2 //
3 // Written by Curtis Olson, started August 2000.
4 //
5 // Copyright (C) 2000  Curtis L. Olson  - http://www.flightgear.org/~curt
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 // $Id$
22
23
24 #ifdef HAVE_CONFIG_H
25 #  include <config.h>
26 #endif
27
28 #include <math.h>               // fabs()
29 #include <stdio.h>              // sprintf()
30
31 #include <simgear/compiler.h>
32
33 #include <simgear/debug/logstream.hxx>
34 #include <simgear/misc/sgstream.hxx>
35
36 #include STL_STRING
37 #include STL_IOSTREAM
38 #include <map>
39
40 #include "runways.hxx"
41
42 SG_USING_NAMESPACE(std);
43 SG_USING_STD(istream);
44 SG_USING_STD(multimap);
45
46 inline istream&
47 operator >> ( istream& in, FGRunway& a )
48 {
49     string type;
50     int tmp;
51
52     in >> a.type;
53     if ( a.type == "R" ) {
54         in >> a.id >> a.rwy_no >> a.lat >> a.lon >> a.heading
55            >> a.length >> a.width >> a.surface_flags >> a.end1_flags
56            >> tmp >> tmp >> a.end2_flags >> tmp >> tmp;
57     } else if ( a.type == "T" ) {
58         // in >> a.id >> a.rwy_no >> a.lat >> a.lon >> a.heading
59         //    >> a.length >> a.width >> a.surface_flags;
60         in >> skipeol;
61     } else {
62         in >> skipeol;
63     }
64
65     return in;
66 }
67
68
69 FGRunwayList::FGRunwayList( const string& file ) {
70     SG_LOG( SG_GENERAL, SG_DEBUG, "Reading runway list: " << file );
71
72     // open the specified file for reading
73     sg_gzifstream in( file );
74     if ( !in.is_open() ) {
75         SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << file );
76         exit(-1);
77     }
78
79     // skip header line
80     in >> skipeol;
81
82     FGRunway rwy;
83     while ( in ) {
84         in >> rwy;
85         if(rwy.type == "R") {
86             runways.insert(pair<const string, FGRunway>(rwy.id, rwy));
87         }
88     }
89 }
90
91
92 // Return reverse rwy number
93 // eg 01 -> 19
94 // 03L -> 21R
95 static string GetReverseRunwayNo(string rwyno) {        
96     // cout << "Original rwyno = " << rwyNo << '\n';
97     
98     // standardize input number
99     string tmp = rwyno.substr(1, 1);
100     if (( tmp == "L" || tmp == "R" || tmp == "C" ) || (rwyno.size() == 1)) {
101         tmp = rwyno;
102         rwyno = "0" + tmp;
103         SG_LOG( SG_GENERAL, SG_INFO,
104                 "Standardising rwy number from " << tmp << " to " << rwyno );
105     }
106     
107     char buf[4];
108     int rn = atoi(rwyno.substr(0,2).c_str());
109     rn += 18;
110     while(rn > 36) {
111         rn -= 36;
112     }
113     sprintf(buf, "%02i", rn);
114     if(rwyno.size() == 3) {
115         if(rwyno.substr(2,1) == "L") {
116             buf[2] = 'R';
117             buf[3] = '\0';
118         } else if (rwyno.substr(2,1) == "R") {
119             buf[2] = 'L';
120             buf[3] = '\0';
121         } else if (rwyno.substr(2,1) == "C") {
122             buf[2] = 'C';
123             buf[3] = '\0';
124         } else if (rwyno.substr(2,1) == "T") {
125             buf[2] = 'T';
126             buf[3] = '\0';
127         } else {
128             SG_LOG(SG_GENERAL, SG_ALERT, "Unknown runway code "
129             << rwyno << " passed to GetReverseRunwayNo(...)");
130         }
131     }
132     return(buf);
133 }
134
135
136 // search for the specified apt id (wierd!)
137 bool FGRunwayList::search( const string& aptid, FGRunway* r ) {
138     runway_map_iterator pos;
139
140     pos = runways.lower_bound(aptid);
141     if ( pos != runways.end() ) {
142         current = pos;
143         *r = pos->second;
144         return true;
145     } else {
146         return false;
147     }
148 }
149
150
151 // search for the specified apt id and runway no
152 bool FGRunwayList::search( const string& aptid, const string& rwyno,
153                            FGRunway *r )
154 {
155     string revrwyno = "";
156     string runwayno = rwyno;
157     if ( runwayno.length() ) {
158         // standardize input number
159         string tmp = runwayno.substr(1, 1);
160         if (( tmp == "L" || tmp == "R" || tmp == "C" )
161             || (runwayno.size() == 1))
162         {
163             tmp = runwayno;
164             runwayno = "0" + tmp;
165             SG_LOG( SG_GENERAL, SG_INFO, "Standardising rwy number from "
166                     << tmp << " to " << runwayno );
167         }
168         revrwyno = GetReverseRunwayNo(runwayno);
169     }
170     runway_map_iterator pos;
171     for ( pos = runways.lower_bound( aptid );
172           pos != runways.upper_bound( aptid ); ++pos)
173     {
174         if ( pos->second.rwy_no == runwayno ) {
175             current = pos;
176             *r = pos->second;
177             return true;
178         } else if ( pos->second.rwy_no == revrwyno ) {
179             // Search again with the other-end runway number.
180             // Remember we have to munge the heading and rwy_no
181             // results if this one matches
182             current = pos;
183             *r = pos->second;
184             // NOTE - matching revrwyno implies that runwayno was
185             // actually correct.
186             r->rwy_no = runwayno;
187             r->heading += 180.0;
188             string tmp = r->end1_flags;
189             r->end1_flags = r->end2_flags;
190             r->end2_flags = tmp;
191             return true;
192         }
193     }
194
195     return false;
196 }
197
198
199 // (wierd!)
200 FGRunway FGRunwayList::search( const string& aptid ) {
201     FGRunway a;
202     search( aptid, &a );
203     return a;
204 }
205
206
207 // Return the runway closest to a given heading
208 bool FGRunwayList::search( const string& aptid, const int tgt_hdg,
209                            FGRunway *runway )
210 {
211     string rwyNo = search(aptid, tgt_hdg);
212     return(rwyNo == "NN" ? false : search(aptid, rwyNo, runway));
213 }
214
215
216 // Return the runway number of the runway closest to a given heading
217 string FGRunwayList::search( const string& aptid, const int tgt_hdg ) {
218     FGRunway r;
219     FGRunway tmp_r;     
220     string rn;
221     double found_dir = 0.0;  
222  
223     if ( !search( aptid, &tmp_r ) ) {
224         SG_LOG( SG_GENERAL, SG_ALERT,
225                 "Failed to find " << aptid << " in database." );
226         return "NN";
227     }
228     
229     double diff;
230     double min_diff = 360.0;
231     
232     while ( tmp_r.id == aptid ) {
233         r = tmp_r;
234         
235         // forward direction
236         diff = tgt_hdg - r.heading;
237         while ( diff < -180.0 ) { diff += 360.0; }
238         while ( diff >  180.0 ) { diff -= 360.0; }
239         diff = fabs(diff);
240         // SG_LOG( SG_GENERAL, SG_INFO,
241         //         "Runway " << r.rwy_no << " heading = " << r.heading <<
242         //         " diff = " << diff );
243         if ( diff < min_diff ) {
244             min_diff = diff;
245             rn = r.rwy_no;
246             found_dir = 0;
247         }
248         
249         // reverse direction
250         diff = tgt_hdg - r.heading - 180.0;
251         while ( diff < -180.0 ) { diff += 360.0; }
252         while ( diff >  180.0 ) { diff -= 360.0; }
253         diff = fabs(diff);
254         // SG_LOG( SG_GENERAL, SG_INFO,
255         //         "Runway -" << r.rwy_no << " heading = " <<
256         //         r.heading + 180.0 <<
257         //         " diff = " << diff );
258         if ( diff < min_diff ) {
259             min_diff = diff;
260             rn = r.rwy_no;
261             found_dir = 180.0;
262         }
263         
264         next( &tmp_r );
265     }
266     
267     // SG_LOG( SG_GENERAL, SG_INFO, "closest runway = " << r.rwy_no
268     //         << " + " << found_dir );
269     rn = r.rwy_no;
270     // cout << "In search, rn = " << rn << endl;
271     if ( found_dir == 180 ) {
272         rn = GetReverseRunwayNo(rn);
273         //cout << "New rn = " << rn << '\n';
274     }   
275     
276     return rn;
277 }
278
279
280 bool FGRunwayList::next( FGRunway* runway ) {
281     ++current;
282     if ( current != runways.end() ) {
283         *runway = current->second;
284         return true;
285     } else {
286         return false;
287     }
288 }
289
290
291 FGRunway FGRunwayList::next() {
292     FGRunway result;
293
294     ++current;
295     if ( current != runways.end() ) {
296         result = current->second;
297     }
298
299     return result;
300 }
301
302
303 // Destructor
304 FGRunwayList::~FGRunwayList( void ) {
305 }