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