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