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