]> git.mxchange.org Git - flightgear.git/blob - src/Navaids/navdb.cxx
James Turner: Improved runway management code:
[flightgear.git] / src / Navaids / navdb.cxx
1 // navdb.cxx -- top level navaids management routines
2 //
3 // Written by Curtis Olson, started May 2004.
4 //
5 // Copyright (C) 2004  Curtis L. Olson - http://www.flightgear.org/~curt
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 //
21 // $Id$
22
23 #ifdef HAVE_CONFIG_H
24 #  include "config.h"
25 #endif
26
27 #include <simgear/compiler.h>
28
29 #include <string>
30
31 #include <simgear/debug/logstream.hxx>
32 #include <simgear/math/sg_geodesy.hxx>
33 #include <simgear/misc/strutils.hxx>
34
35 #include <Airports/runways.hxx>
36 #include <Airports/simple.hxx>
37 #include <Main/globals.hxx>
38
39 #include "navrecord.hxx"
40 #include "navdb.hxx"
41
42 using std::string;
43
44
45 // load and initialize the navigational databases
46 bool fgNavDBInit( FGAirportList *airports,
47                   FGNavList *navlist, FGNavList *loclist, FGNavList *gslist,
48                   FGNavList *dmelist, FGNavList *mkrlist, 
49                   FGNavList *tacanlist, FGNavList *carrierlist,
50                   FGTACANList *channellist)
51 {
52     SG_LOG(SG_GENERAL, SG_INFO, "Loading Navaid Databases");
53     // SG_LOG(SG_GENERAL, SG_INFO, "  VOR/NDB");
54     // SGPath p_nav( globals->get_fg_root() );
55     // p_nav.append( "Navaids/default.nav" );
56     // navlist->init( p_nav );
57
58     // SG_LOG(SG_GENERAL, SG_INFO, "  ILS and Marker Beacons");
59     // beacons->init();
60     // SGPath p_ils( globals->get_fg_root() );
61     // p_ils.append( "Navaids/default.ils" );
62     // ilslist->init( p_ils );
63
64
65     SGPath path( globals->get_fg_root() );
66     path.append( "Navaids/nav.dat" );
67
68     sg_gzifstream in( path.str() );
69     if ( !in.is_open() ) {
70         SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << path.str() );
71         exit(-1);
72     }
73
74     // skip first two lines
75     in >> skipeol;
76     in >> skipeol;
77
78     while ( ! in.eof() ) {
79         FGNavRecord *r = new FGNavRecord;
80         in >> (*r);
81         if ( r->get_type() > 95 ) {
82             delete r;
83             break;
84         }
85
86         /*cout << "id = " << r->get_ident() << endl;
87         cout << " type = " << r->get_type() << endl;
88         cout << " lon = " << r->get_lon() << endl;
89         cout << " lat = " << r->get_lat() << endl;
90         cout << " elev = " <<r->get_elev_ft() << endl;
91         cout << " freq = " << r->get_freq() << endl;
92         cout << " range = " << r->get_range() << endl;
93         cout << " name = " << r->get_name() << endl << endl; */
94
95         // fudge elevation to the field elevation if it's not specified
96         if ( fabs(r->get_elev_ft()) < 0.01 && r->get_apt_id().length() ) {
97             // cout << r->get_type() << " " << r->get_apt_id() << " zero elev"
98             //      << endl;
99             const FGAirport* a = airports->search( r->get_apt_id() );
100             if ( a ) {
101                 r->set_elev_ft( a->getElevation() );
102                 // cout << "  setting to " << a.elevation << endl;
103             }
104         }
105
106         if ( r->get_type() == 2 || r->get_type() == 3 ) {
107             // NDB=2, VOR=3
108             navlist->add( r );
109         } else if ( r->get_type() == 4 || r->get_type() == 5 ) {
110             // ILS=4, LOC(only)=5
111             loclist->add( r );
112         } else if ( r->get_type() == 6 ) {
113             // GS=6
114             gslist->add( r );
115         } else if ( r->get_type() == 7 || r->get_type() == 8
116                     || r->get_type() == 9 )
117         {
118             // Marker Beacon = 7,8,9
119             mkrlist->add( r );
120         } else if ( r->get_type() == 12 || r->get_type() == 13) {
121             // DME with ILS=12; standalone DME=13
122             string str1( r->get_name() );
123             string::size_type loc1= str1.find( "TACAN", 0 );
124             string::size_type loc2 = str1.find( "VORTAC", 0 );
125                        
126             if( loc1 != string::npos || loc2 != string::npos ){
127                  //cout << " name = " << r->get_name() ;
128                  //cout << " freq = " << r->get_freq() ;
129                  tacanlist->add( r );
130                  }
131                 
132             dmelist->add( r );
133             
134         }
135                 
136         in >> skipcomment;
137     }
138
139 // load the carrier navaids file
140     
141     string file, name;
142     path = "";
143     path = globals->get_fg_root() ;
144     path.append( "Navaids/carrier_nav.dat" );
145     
146     file = path.str();
147     SG_LOG( SG_GENERAL, SG_INFO, "opening file: " << path.str() );
148     
149     sg_gzifstream incarrier( path.str() );
150     
151     if ( !incarrier.is_open() ) {
152         SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << path.str() );
153         exit(-1);
154     }
155     
156     // skip first two lines
157     //incarrier >> skipeol;
158     //incarrier >> skipeol;
159     
160     while ( ! incarrier.eof() ) {
161         FGNavRecord *r = new FGNavRecord;
162         incarrier >> (*r);
163         carrierlist->add ( r );
164         /*cout << " carrier lon: "<<  r->get_lon() ;
165         cout << " carrier lat: "<<  r->get_lat() ;
166         cout << " freq: " << r->get_freq() ;
167         cout << " carrier name: "<<  r->get_name() << endl;*/
168                 
169         //if ( r->get_type() > 95 ) {
170         //   break;}
171     } // end while
172
173 // end loading the carrier navaids file
174
175 // load the channel/freqency file
176     string channel, freq;
177     path="";
178     path = globals->get_fg_root();
179     path.append( "Navaids/TACAN_freq.dat" );
180     
181     SG_LOG( SG_GENERAL, SG_INFO, "opening file: " << path.str() );
182         
183     sg_gzifstream inchannel( path.str() );
184     
185     if ( !inchannel.is_open() ) {
186         SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << path.str() );
187         exit(-1);
188     }
189     
190     // skip first line
191     inchannel >> skipeol;
192     while ( ! inchannel.eof() ) {
193         FGTACANRecord *r = new FGTACANRecord;
194         inchannel >> (*r);
195         channellist->add ( r );
196         //cout << "channel = " << r->get_channel() ;
197         //cout << " freq = " << r->get_freq() << endl;
198         
199     } // end while
200
201  
202  // end ReadChanFile
203
204
205     return true;
206 }
207
208
209 // Given a localizer record and it's corresponding runway record,
210 // adjust the localizer position so it is in perfect alignment with
211 // the runway.
212 static void update_loc_position( FGNavRecord *loc, FGRunway *rwy,
213                                  double threshold )
214 {
215     double hdg = rwy->_heading;
216     hdg += 180.0;
217     if ( hdg > 360.0 ) {
218         hdg -= 360.0;
219     }
220
221     // calculate runway threshold point
222     double thresh_lat, thresh_lon, return_az;
223     geo_direct_wgs_84 ( 0.0, rwy->_lat, rwy->_lon, hdg,
224                         rwy->_length/2.0 * SG_FEET_TO_METER,
225                         &thresh_lat, &thresh_lon, &return_az );
226     // cout << "Threshold = " << thresh_lat << "," << thresh_lon << endl;
227
228     // calculate distance from threshold to localizer
229     double az1, az2, dist_m;
230     geo_inverse_wgs_84( 0.0, loc->get_lat(), loc->get_lon(),
231                         thresh_lat, thresh_lon,
232                         &az1, &az2, &dist_m );
233     // cout << "Distance = " << dist_m << endl;
234
235     // back project that distance along the runway center line
236     double nloc_lat, nloc_lon;
237     geo_direct_wgs_84 ( 0.0, thresh_lat, thresh_lon, hdg + 180.0, 
238                         dist_m, &nloc_lat, &nloc_lon, &return_az );
239     // printf("New localizer = %.6f %.6f\n", nloc_lat, nloc_lon );
240
241     // sanity check, how far have we moved the localizer?
242     geo_inverse_wgs_84( 0.0, loc->get_lat(), loc->get_lon(),
243                         nloc_lat, nloc_lon,
244                         &az1, &az2, &dist_m );
245     // cout << "Distance moved = " << dist_m << endl;
246
247     // cout << "orig heading = " << loc->get_multiuse() << endl;
248     // cout << "new heading = " << rwy->_heading << endl;
249
250     double hdg_diff = loc->get_multiuse() - rwy->_heading;
251
252     // clamp to [-180.0 ... 180.0]
253     if ( hdg_diff < -180.0 ) {
254         hdg_diff += 360.0;
255     } else if ( hdg_diff > 180.0 ) {
256         hdg_diff -= 360.0;
257     }
258
259     if ( fabs(hdg_diff) <= threshold ) {
260         loc->set_lat( nloc_lat );
261         loc->set_lon( nloc_lon );
262         loc->set_multiuse( rwy->_heading );
263     }
264 }
265
266
267 // This routines traverses the localizer list and attempts to match
268 // each entry with it's corresponding runway.  When it is successful,
269 // it then "moves" the localizer and updates it's heading so it
270 // *perfectly* aligns with the runway, but is still the same distance
271 // from the runway threshold.
272 void fgNavDBAlignLOCwithRunway( FGAirportList *airports, FGNavList *loclist,
273                                 double threshold ) {
274     nav_map_type navmap = loclist->get_navaids();
275
276     nav_map_const_iterator freq = navmap.begin();
277     while ( freq != navmap.end() ) {
278         nav_list_type locs = freq->second;
279         nav_list_const_iterator loc = locs.begin();
280         while ( loc != locs.end() ) {
281           vector<string> parts = simgear::strutils::split((*loc)->get_name());
282           if (parts.size() < 2) {
283             SG_LOG(SG_GENERAL, SG_ALERT, "can't parse navaid " << (*loc)->get_ident() 
284               << " name for airport/runway:" << (*loc)->get_name());
285             continue;
286           }
287           
288           FGAirport* airport = airports->search(parts[0]);
289           if (!airport) continue; // not found
290             
291           FGRunway r = airport->getRunwayByIdent(parts[1]);
292           update_loc_position( (*loc), &r, threshold );
293           ++loc;
294         }
295         ++freq;
296     }
297 }
298