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