1 // navdb.cxx -- top level navaids management routines
3 // Written by Curtis Olson, started May 2004.
5 // Copyright (C) 2004 Curtis L. Olson - http://www.flightgear.org/~curt
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.
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.
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.
27 #include <simgear/compiler.h>
31 #include <simgear/debug/logstream.hxx>
33 #include <Airports/runways.hxx>
34 #include <Airports/simple.hxx>
35 #include <Main/globals.hxx>
37 #include "navrecord.hxx"
40 SG_USING_STD( string );
43 // load and initialize the navigational databases
44 bool fgNavDBInit( FGAirportList *airports,
45 FGNavList *navlist, FGNavList *loclist, FGNavList *gslist,
46 FGNavList *dmelist, FGNavList *mkrlist,
47 FGNavList *tacanlist, FGNavList *carrierlist,
48 FGTACANList *channellist)
50 SG_LOG(SG_GENERAL, SG_INFO, "Loading Navaid Databases");
51 // SG_LOG(SG_GENERAL, SG_INFO, " VOR/NDB");
52 // SGPath p_nav( globals->get_fg_root() );
53 // p_nav.append( "Navaids/default.nav" );
54 // navlist->init( p_nav );
56 // SG_LOG(SG_GENERAL, SG_INFO, " ILS and Marker Beacons");
58 // SGPath p_ils( globals->get_fg_root() );
59 // p_ils.append( "Navaids/default.ils" );
60 // ilslist->init( p_ils );
63 SGPath path( globals->get_fg_root() );
64 path.append( "Navaids/nav.dat" );
66 sg_gzifstream in( path.str() );
67 if ( !in.is_open() ) {
68 SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << path.str() );
72 // skip first two lines
79 // FIXME -- Please complain to the FlightGear mailing list, if you still need this hack.
82 // while ( in.get(c) && c != '\0' ) {
85 while ( ! in.eof() ) {
88 FGNavRecord *r = new FGNavRecord;
90 if ( r->get_type() > 95 ) {
95 /*cout << "id = " << r->get_ident() << endl;
96 cout << " type = " << r->get_type() << endl;
97 cout << " lon = " << r->get_lon() << endl;
98 cout << " lat = " << r->get_lat() << endl;
99 cout << " elev = " <<r->get_elev_ft() << endl;
100 cout << " freq = " << r->get_freq() << endl;
101 cout << " range = " << r->get_range() << endl;
102 cout << " name = " << r->get_name() << endl << endl; */
104 // fudge elevation to the field elevation if it's not specified
105 if ( fabs(r->get_elev_ft()) < 0.01 && r->get_apt_id().length() ) {
106 // cout << r->get_type() << " " << r->get_apt_id() << " zero elev"
108 const FGAirport* a = airports->search( r->get_apt_id() );
110 r->set_elev_ft( a->getElevation() );
111 // cout << " setting to " << a.elevation << endl;
115 if ( r->get_type() == 2 || r->get_type() == 3 ) {
118 } else if ( r->get_type() == 4 || r->get_type() == 5 ) {
119 // ILS=4, LOC(only)=5
121 } else if ( r->get_type() == 6 ) {
124 } else if ( r->get_type() == 7 || r->get_type() == 8
125 || r->get_type() == 9 )
127 // Marker Beacon = 7,8,9
129 } else if ( r->get_type() == 12 || r->get_type() == 13) {
130 // DME with ILS=12; standalone DME=13
131 string str1( r->get_name() );
132 string::size_type loc1= str1.find( "TACAN", 0 );
133 string::size_type loc2 = str1.find( "VORTAC", 0 );
135 if( loc1 != string::npos || loc2 != string::npos ){
136 //cout << " name = " << r->get_name() ;
137 //cout << " freq = " << r->get_freq() ;
148 // load the carrier navaids file
152 path = globals->get_fg_root() ;
153 path.append( "Navaids/carrier_nav.dat" );
156 SG_LOG( SG_GENERAL, SG_INFO, "opening file: " << path.str() );
158 sg_gzifstream incarrier( path.str() );
160 if ( !incarrier.is_open() ) {
161 SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << path.str() );
165 // skip first two lines
166 //incarrier >> skipeol;
167 //incarrier >> skipeol;
171 while ( incarrier.get(c) && c != '\0' ) {
172 incarrier.putback(c);
174 while ( ! incarrier.eof() ) {
177 FGNavRecord *r = new FGNavRecord;
179 carrierlist->add ( r );
180 /*cout << " carrier lon: "<< r->get_lon() ;
181 cout << " carrier lat: "<< r->get_lat() ;
182 cout << " freq: " << r->get_freq() ;
183 cout << " carrier name: "<< r->get_name() << endl;*/
185 //if ( r->get_type() > 95 ) {
189 // end loading the carrier navaids file
191 // load the channel/freqency file
192 string channel, freq;
194 path = globals->get_fg_root();
195 path.append( "Navaids/TACAN_freq.dat" );
197 SG_LOG( SG_GENERAL, SG_INFO, "opening file: " << path.str() );
199 sg_gzifstream inchannel( path.str() );
201 if ( !inchannel.is_open() ) {
202 SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << path.str() );
207 inchannel >> skipeol;
211 while ( inchannel.get(c) && c != '\0' ) {
214 while ( ! inchannel.eof() ) {
217 FGTACANRecord *r = new FGTACANRecord;
219 channellist->add ( r );
220 //cout << "channel = " << r->get_channel() ;
221 //cout << " freq = " << r->get_freq() << endl;
233 // Given a localizer record and it's corresponding runway record,
234 // adjust the localizer position so it is in perfect alignment with
236 static void update_loc_position( FGNavRecord *loc, FGRunway *rwy,
239 double hdg = rwy->_heading;
245 // calculate runway threshold point
246 double thresh_lat, thresh_lon, return_az;
247 geo_direct_wgs_84 ( 0.0, rwy->_lat, rwy->_lon, hdg,
248 rwy->_length/2.0 * SG_FEET_TO_METER,
249 &thresh_lat, &thresh_lon, &return_az );
250 // cout << "Threshold = " << thresh_lat << "," << thresh_lon << endl;
252 // calculate distance from threshold to localizer
253 double az1, az2, dist_m;
254 geo_inverse_wgs_84( 0.0, loc->get_lat(), loc->get_lon(),
255 thresh_lat, thresh_lon,
256 &az1, &az2, &dist_m );
257 // cout << "Distance = " << dist_m << endl;
259 // back project that distance along the runway center line
260 double nloc_lat, nloc_lon;
261 geo_direct_wgs_84 ( 0.0, thresh_lat, thresh_lon, hdg + 180.0,
262 dist_m, &nloc_lat, &nloc_lon, &return_az );
263 // printf("New localizer = %.6f %.6f\n", nloc_lat, nloc_lon );
265 // sanity check, how far have we moved the localizer?
266 geo_inverse_wgs_84( 0.0, loc->get_lat(), loc->get_lon(),
268 &az1, &az2, &dist_m );
269 // cout << "Distance moved = " << dist_m << endl;
271 // cout << "orig heading = " << loc->get_multiuse() << endl;
272 // cout << "new heading = " << rwy->_heading << endl;
274 double hdg_diff = loc->get_multiuse() - rwy->_heading;
276 // clamp to [-180.0 ... 180.0]
277 if ( hdg_diff < -180.0 ) {
279 } else if ( hdg_diff > 180.0 ) {
283 if ( fabs(hdg_diff) <= threshold ) {
284 loc->set_lat( nloc_lat );
285 loc->set_lon( nloc_lon );
286 loc->set_multiuse( rwy->_heading );
291 // This routines traverses the localizer list and attempts to match
292 // each entry with it's corresponding runway. When it is successful,
293 // it then "moves" the localizer and updates it's heading so it
294 // *perfectly* aligns with the runway, but is still the same distance
295 // from the runway threshold.
296 void fgNavDBAlignLOCwithRunway( FGRunwayList *runways, FGNavList *loclist,
298 nav_map_type navmap = loclist->get_navaids();
300 nav_map_const_iterator freq = navmap.begin();
301 while ( freq != navmap.end() ) {
302 nav_list_type locs = freq->second;
303 nav_list_const_iterator loc = locs.begin();
304 while ( loc != locs.end() ) {
305 string name = (*loc)->get_name();
306 string::size_type pos1 = name.find(" ");
307 string id = name.substr(0, pos1);
308 name = name.substr(pos1+1);
309 string::size_type pos2 = name.find(" ");
310 string rwy = name.substr(0, pos2);
313 if ( runways->search(id, rwy, &r) ) {
314 update_loc_position( (*loc), &r, threshold );