]> git.mxchange.org Git - flightgear.git/blob - src/Airports/runways.cxx
0cc274262409ac74e14849156bee903218d7b5a3
[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  - curt@flightgear.org
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_FUNCTIONAL
38 #include STL_ALGORITHM
39
40 #include "runways.hxx"
41
42 SG_USING_NAMESPACE(std);
43
44 #ifndef _MSC_VER
45 #define NDEBUG                  // MSVC needs this
46 #endif // !_MSC_VER
47
48 #include <mk4.h>
49 #include <mk4str.h>
50
51 #ifndef _MSC_VER
52 #undef NDEBUG
53 #endif // !_MSC_VER
54
55 #ifdef SG_HAVE_STD_INCLUDES
56 #  include <istream>
57 #elif defined( __BORLANDC__ ) || defined (__APPLE__)
58 #  include <iostream>
59 #else
60 #  include <istream.h>
61 #endif
62
63 SG_USING_STD(istream);
64
65 inline istream&
66 operator >> ( istream& in, FGRunway& a )
67 {
68     int tmp;
69
70     return in >> a.rwy_no >> a.lat >> a.lon >> a.heading >> a.length >> a.width
71               >> a.surface_flags >> a.end1_flags >> tmp >> tmp >> a.end2_flags
72               >> tmp >> tmp;
73 }
74
75
76 FGRunways::FGRunways( const string& file ) {
77     // open the specified database readonly
78     storage = new c4_Storage( file.c_str(), false );
79
80     if ( !storage->Strategy().IsValid() ) {
81         SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << file );
82         exit(-1);
83     }
84
85     vRunway = new c4_View;
86     *vRunway = 
87         storage->GetAs("runway[ID:S,Rwy:S,Longitude:F,Latitude:F,Heading:F,Length:F,Width:F,SurfaceFlags:S,End1Flags:S,End2Flags:S]");
88
89     next_index = 0;
90 }
91
92
93 // search for the specified apt id
94 bool FGRunways::search( const string& aptid, FGRunway* r ) {
95     c4_StringProp pID ("ID");
96     c4_StringProp pRwy ("Rwy");
97     c4_FloatProp pLon ("Longitude");
98     c4_FloatProp pLat ("Latitude");
99     c4_FloatProp pHdg ("Heading");
100     c4_FloatProp pLen ("Length");
101     c4_FloatProp pWid ("Width");
102     c4_StringProp pSurf ("SurfaceFlags");
103     c4_StringProp pEnd1 ("End1Flags");
104     c4_StringProp pEnd2 ("End2Flags");
105
106     int index = vRunway->Find(pID[aptid.c_str()]);
107     // cout << "index = " << index << endl;
108
109     if ( index == -1 ) {
110         return false;
111     }
112
113     next_index = index + 1;
114
115     c4_RowRef row = vRunway->GetAt(index);
116
117     r->id =      (const char *) pID(row);
118     r->rwy_no =  (const char *) pRwy(row);
119     r->lon =     (double) pLon(row);
120     r->lat =     (double) pLat(row);
121     r->heading = (double) pHdg(row);
122     r->length =  (double) pLen(row);
123     r->width =   (double) pWid(row);
124     r->surface_flags = (const char *) pSurf(row);
125     r->end1_flags =    (const char *) pEnd1(row);
126     r->end2_flags =    (const char *) pEnd2(row);
127
128     return true;
129 }
130
131
132 // search for the specified apt id and runway no
133 bool FGRunways::search( const string& aptid, const string& rwyno, FGRunway* r )
134 {
135     c4_StringProp pID ("ID");
136     c4_StringProp pRwy ("Rwy");
137     c4_FloatProp pLon ("Longitude");
138     c4_FloatProp pLat ("Latitude");
139     c4_FloatProp pHdg ("Heading");
140     c4_FloatProp pLen ("Length");
141     c4_FloatProp pWid ("Width");
142     c4_StringProp pSurf ("SurfaceFlags");
143     c4_StringProp pEnd1 ("End1Flags");
144     c4_StringProp pEnd2 ("End2Flags");
145
146     int index = vRunway->Find(pID[aptid.c_str()]);
147     // cout << "index = " << index << endl;
148
149     if ( index == -1 ) {
150         return false;
151     }
152
153     c4_RowRef row = vRunway->GetAt(index);
154     string rowid = (const char *) pID(row);
155     string rowrwyno = (const char *) pRwy(row);
156     while ( rowid == aptid ) {
157         next_index = index + 1;
158
159         if ( rowrwyno == rwyno ) {
160             r->id =      (const char *) pID(row);
161             r->rwy_no =  (const char *) pRwy(row);
162             r->lon =     (double) pLon(row);
163             r->lat =     (double) pLat(row);
164             r->heading = (double) pHdg(row);
165             r->length =  (double) pLen(row);
166             r->width =   (double) pWid(row);
167             r->surface_flags = (const char *) pSurf(row);
168             r->end1_flags =    (const char *) pEnd1(row);
169             r->end2_flags =    (const char *) pEnd2(row);
170
171             return true;
172         }
173         
174         // Check reverse rwy number
175         // eg 01 -> 19
176         // 03L -> 21R
177         // cout << "Original rowrwyno = " << rowrwyno << '\n';
178         char buf[4];
179         int rn = atoi(rowrwyno.substr(0,2).c_str());
180         rn += 18;
181         while(rn > 36) {
182             rn -= 36;
183         }
184         sprintf(buf, "%02i", rn);
185         if(rowrwyno.size() == 3) {
186             if(rowrwyno.substr(2,1) == "L") {
187                 buf[2] = 'R';
188                 buf[3] = '\0';
189             } else if (rowrwyno.substr(2,1) == "R") {
190                 buf[2] = 'L';
191                 buf[3] = '\0';
192             } else {
193                 SG_LOG(SG_GENERAL, SG_ALERT, "Unknown runway code "
194                        << rowrwyno << " found in FGRunways.search(...)");
195             }
196         }
197         rowrwyno = buf;
198         // cout << "New rowrwyno = " << rowrwyno << '\n';
199         // Search again with the other-end runway number
200         // Remember we have to munge the heading result if this one matches
201         if ( rowrwyno == rwyno ) {
202             r->id =      (const char *) pID(row);
203             r->rwy_no =  rowrwyno;
204             r->lon =     (double) pLon(row);
205             r->lat =     (double) pLat(row);
206             r->heading = (double) pHdg(row) + 180.0;
207             r->length =  (double) pLen(row);
208             r->width =   (double) pWid(row);
209             r->surface_flags = (const char *) pSurf(row);
210             r->end1_flags =    (const char *) pEnd2(row);
211             r->end2_flags =    (const char *) pEnd1(row);
212             // I've swapped the end flags as well 
213             
214             return true;
215         }
216
217         index++;
218         row = vRunway->GetAt(index);
219         rowid = (const char *) pID(row);
220         rowrwyno = (const char *) pRwy(row);
221     }
222
223     return false;
224 }
225
226
227 FGRunway FGRunways::search( const string& aptid ) {
228     FGRunway a;
229     search( aptid, &a );
230     return a;
231 }
232
233
234 // search for the specified id
235 bool FGRunways::next( FGRunway* r ) {
236     c4_StringProp pID ("ID");
237     c4_StringProp pRwy ("Rwy");
238     c4_FloatProp pLon ("Longitude");
239     c4_FloatProp pLat ("Latitude");
240     c4_FloatProp pHdg ("Heading");
241     c4_FloatProp pLen ("Length");
242     c4_FloatProp pWid ("Width");
243     c4_StringProp pSurf ("SurfaceFlags");
244     c4_StringProp pEnd1 ("End1Flags");
245     c4_StringProp pEnd2 ("End2Flags");
246
247     int size = vRunway->GetSize();
248     // cout << "total records = " << size << endl;
249
250     int index = next_index;
251     // cout << "index = " << index << endl;
252
253     if ( index == -1 || index >= size ) {
254         return false;
255     }
256
257     next_index = index + 1;
258
259     c4_RowRef row = vRunway->GetAt(index);
260
261     r->id =      (const char *) pID(row);
262     r->rwy_no =  (const char *) pRwy(row);
263     r->lon =     (double) pLon(row);
264     r->lat =     (double) pLat(row);
265     r->heading = (double) pHdg(row);
266     r->length =  (double) pLen(row);
267     r->width =   (double) pWid(row);
268     r->surface_flags = (const char *) pSurf(row);
269     r->end1_flags =    (const char *) pEnd1(row);
270     r->end2_flags =    (const char *) pEnd2(row);
271
272     return true;
273 }
274
275
276 // Return the runway closest to a given heading
277 bool FGRunways::search( const string& aptid, const int tgt_hdg,
278                         FGRunway* runway )
279 {
280     string rwyNo = search(aptid, tgt_hdg);
281     return(rwyNo == "NN" ? false : search(aptid, rwyNo, runway));
282 }
283
284
285 // Return the runway number of the runway closest to a given heading
286 string FGRunways::search( const string& aptid, const int tgt_hdg ) {
287     FGRunway r;
288     string rn;
289     double found_dir = 0.0;  
290  
291     if ( !search( aptid, &r ) ) {
292         SG_LOG( SG_GENERAL, SG_ALERT,
293                 "Failed to find " << aptid << " in database." );
294         return "NN";
295     }
296     
297     double diff;
298     double min_diff = 360.0;
299     
300     while ( r.id == aptid ) {
301         // forward direction
302         diff = tgt_hdg - r.heading;
303         while ( diff < -180.0 ) { diff += 360.0; }
304         while ( diff >  180.0 ) { diff -= 360.0; }
305         diff = fabs(diff);
306         // SG_LOG( SG_GENERAL, SG_INFO,
307         //         "Runway " << r.rwy_no << " heading = " << r.heading <<
308         //         " diff = " << diff );
309         if ( diff < min_diff ) {
310             min_diff = diff;
311             rn = r.rwy_no;
312             found_dir = 0;
313         }
314         
315         // reverse direction
316         diff = tgt_hdg - r.heading - 180.0;
317         while ( diff < -180.0 ) { diff += 360.0; }
318         while ( diff >  180.0 ) { diff -= 360.0; }
319         diff = fabs(diff);
320         // SG_LOG( SG_GENERAL, SG_INFO,
321         //         "Runway -" << r.rwy_no << " heading = " <<
322         //         r.heading + 180.0 <<
323         //         " diff = " << diff );
324         if ( diff < min_diff ) {
325             min_diff = diff;
326             rn = r.rwy_no;
327             found_dir = 180.0;
328         }
329         
330         next( &r );
331     }
332     
333     // SG_LOG( SG_GENERAL, SG_INFO, "closest runway = " << r.rwy_no
334     //         << " + " << found_dir );
335     // rn = r.rwy_no;
336     // cout << "In search, rn = " << rn << endl;
337     if ( found_dir == 180 ) {
338         int irn = atoi(rn.c_str());
339         irn += 18;
340         if ( irn > 36 ) {
341             irn -= 36;
342         }
343         char buf[4];            // 2 chars + string terminator + 1 for safety
344         sprintf(buf, "%i", irn);
345         rn = buf;
346     }   
347     
348     return rn;
349 }
350
351
352 // Destructor
353 FGRunways::~FGRunways( void ) {
354     delete storage;
355 }
356
357
358 // Constructor
359 FGRunwaysUtil::FGRunwaysUtil() {
360 }
361
362
363 // load the data
364 int FGRunwaysUtil::load( const string& file ) {
365     FGRunway r;
366     string apt_id;
367
368     runways.erase( runways.begin(), runways.end() );
369
370     sg_gzifstream in( file );
371     if ( !in.is_open() ) {
372         SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << file );
373         exit(-1);
374     }
375
376     // skip first line of file
377     char tmp[2048];
378     in.getline( tmp, 2048 );
379
380     // read in each line of the file
381
382 #ifdef __MWERKS__
383
384     in >> ::skipws;
385     char c = 0;
386     while ( in.get(c) && c != '\0' ) {
387         if ( c == 'A' ) {
388             in >> apt_id;
389             in >> skipeol;
390         } else if ( c == 'R' ) {
391             in >> r;
392             r.id = apt_id;
393             runways.push_back(r);
394         } else {
395             in >> skipeol;
396         }
397         in >> ::skipws;
398     }
399
400 #else
401
402     in >> ::skipws;
403     while ( ! in.eof() ) {
404         char c = 0;
405         in.get(c);
406         if ( c == 'A' ) {
407             in >> apt_id;
408             in >> skipeol;
409         } else if ( c == 'R' ) {
410             in >> r;
411             r.id = apt_id;
412             // cout << apt_id << " " << r.rwy_no << endl;
413             runways.push_back(r);
414         } else {
415             in >> skipeol;
416         }
417         in >> ::skipws;
418     }
419
420 #endif
421
422     return 1;
423 }
424
425
426 // save the data in gdbm format
427 bool FGRunwaysUtil::dump_mk4( const string& file ) {
428     // open database for writing
429     c4_Storage storage( file.c_str(), true );
430
431     // need to do something about error handling here!
432
433     // define the properties
434     c4_StringProp pID ("ID");
435     c4_StringProp pRwy ("Rwy");
436     c4_FloatProp pLon ("Longitude");
437     c4_FloatProp pLat ("Latitude");
438     c4_FloatProp pHdg ("Heading");
439     c4_FloatProp pLen ("Length");
440     c4_FloatProp pWid ("Width");
441     c4_StringProp pSurf ("SurfaceFlags");
442     c4_StringProp pEnd1 ("End1Flags");
443     c4_StringProp pEnd2 ("End2Flags");
444
445     // Start with an empty view of the proper structure.
446     c4_View vRunway =
447         storage.GetAs("runway[ID:S,Rwy:S,Longitude:F,Latitude:F,Heading:F,Length:F,Width:F,SurfaceFlags:S,End1Flags:S,End2Flags:S]");
448
449     c4_Row row;
450
451     iterator current = runways.begin();
452     const_iterator end = runways.end();
453     while ( current != end ) {
454         // add each runway record
455         pID (row) = current->id.c_str();
456         pRwy (row) = current->rwy_no.c_str();
457         pLon (row) = current->lon;
458         pLat (row) = current->lat;
459         pHdg (row) = current->heading;
460         pLen (row) = current->length;
461         pWid (row) = current->width;
462         pSurf (row) = current->surface_flags.c_str();
463         pEnd1 (row) = current->end1_flags.c_str();
464         pEnd2 (row) = current->end2_flags.c_str();
465         vRunway.Add(row);
466
467         ++current;
468     }
469
470     // commit our changes
471     storage.Commit();
472
473     return true;
474 }
475
476
477 #if 0
478 // search for the specified id
479 bool
480 FGRunwaysUtil::search( const string& id, FGRunway* a ) const
481 {
482     const_iterator it = runways.find( FGRunway(id) );
483     if ( it != runways.end() )
484     {
485         *a = *it;
486         return true;
487     }
488     else
489     {
490         return false;
491     }
492 }
493
494
495 FGRunway
496 FGRunwaysUtil::search( const string& id ) const
497 {
498     FGRunway a;
499     this->search( id, &a );
500     return a;
501 }
502 #endif
503
504 // Destructor
505 FGRunwaysUtil::~FGRunwaysUtil( void ) {
506 }
507
508