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