]> git.mxchange.org Git - flightgear.git/blob - src/Navaids/navdb.cxx
fix trx and rx heights and improve calculations
[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 #include <simgear/misc/sg_path.hxx>
35 #include <simgear/structure/exception.hxx>
36 #include <simgear/misc/sgstream.hxx>
37 #include <simgear/props/props_io.hxx>
38
39 #include "navrecord.hxx"
40 #include "navlist.hxx"
41 #include "navdb.hxx"
42 #include <Main/globals.hxx>
43 #include <Navaids/markerbeacon.hxx>
44 #include <Airports/simple.hxx>
45 #include <Airports/runways.hxx>
46 #include <Airports/xmlloader.hxx>
47 #include <Main/fg_props.hxx>
48
49 using std::string;
50
51 typedef std::map<FGAirport*, SGPropertyNode_ptr> AirportPropertyMap;
52
53 static AirportPropertyMap static_airportIlsData;
54
55 static FGPositioned::Type
56 mapRobinTypeToFGPType(int aTy)
57 {
58   switch (aTy) {
59  // case 1:
60   case 2: return FGPositioned::NDB;
61   case 3: return FGPositioned::VOR;
62   case 4: return FGPositioned::ILS;
63   case 5: return FGPositioned::LOC;
64   case 6: return FGPositioned::GS;
65   case 12:
66   case 13: return FGPositioned::DME;
67   case 99: return FGPositioned::INVALID; // end-of-file code
68   default:
69     throw sg_range_exception("Got a nav.dat type we don't recognize", "FGNavRecord::createFromStream");
70   }
71 }
72
73 static FGNavRecord* createNavFromStream(std::istream& aStream)
74 {
75   int rawType;
76   aStream >> rawType;
77   if (aStream.eof() || (rawType == 99)) {
78     return NULL; // happens with, eg, carrier_nav.dat
79   }
80   
81   double lat, lon, elev_ft, multiuse;
82   int freq, range;
83   std::string name, ident;
84   aStream >> lat >> lon >> elev_ft >> freq >> range >> multiuse >> ident;
85   getline(aStream, name);
86   
87   SGGeod pos(SGGeod::fromDegFt(lon, lat, elev_ft));
88   name = simgear::strutils::strip(name);
89   
90   if ((rawType >= 7) && (rawType <= 9)) {
91     // marker beacons use a different run-time class now
92      FGMarkerBeaconRecord::create(rawType, name, pos);
93      return NULL; // not a nav-record, but that's okay
94   }
95   
96   FGPositioned::Type type = mapRobinTypeToFGPType(rawType);
97   if (type == FGPositioned::INVALID) {
98     return NULL;
99   }
100   
101   // silently multiply adf frequencies by 100 so that adf
102   // vs. nav/loc frequency lookups can use the same code.
103   if (type == FGPositioned::NDB) {
104     freq *= 100;
105   }
106   
107   return new FGNavRecord(type, ident, name, pos,
108     freq, range, multiuse);
109 }
110
111 // load and initialize the navigational databases
112 bool fgNavDBInit( FGNavList *navlist, FGNavList *loclist, FGNavList *gslist,
113                   FGNavList *dmelist, 
114                   FGNavList *tacanlist, FGNavList *carrierlist,
115                   FGTACANList *channellist)
116 {
117     SG_LOG(SG_GENERAL, SG_INFO, "Loading Navaid Databases");
118
119     SGPath path( globals->get_fg_root() );
120     path.append( "Navaids/nav.dat" );
121
122     sg_gzifstream in( path.str() );
123     if ( !in.is_open() ) {
124         SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << path.str() );
125         exit(-1);
126     }
127
128     // skip first two lines
129     in >> skipeol;
130     in >> skipeol;
131
132     while (!in.eof()) {
133       FGNavRecord *r = createNavFromStream(in);
134       if (!r) {
135         continue;
136       }
137       
138       switch (r->type()) {
139       case FGPositioned::NDB:
140       case FGPositioned::VOR:
141         navlist->add(r);
142         break;
143         
144       case FGPositioned::ILS:
145       case FGPositioned::LOC:
146         loclist->add(r);
147         break;
148         
149       case FGPositioned::GS:
150         gslist->add(r);
151         break;
152       
153       case FGPositioned::DME:
154       {
155         dmelist->add(r);
156         string::size_type loc1= r->name().find( "TACAN", 0 );
157         string::size_type loc2 = r->name().find( "VORTAC", 0 );
158                        
159         if( loc1 != string::npos || loc2 != string::npos) {
160           tacanlist->add(r);
161         }
162
163         break;
164       }
165       
166       default:
167         throw sg_range_exception("got unsupported NavRecord type", "fgNavDBInit");
168       }
169
170       in >> skipcomment;
171     } // of stream data loop
172
173 // load the carrier navaids file
174     
175     string file, name;
176     path = globals->get_fg_root() ;
177     path.append( "Navaids/carrier_nav.dat" );
178     
179     file = path.str();
180     SG_LOG( SG_GENERAL, SG_INFO, "opening file: " << path.str() );
181     
182     sg_gzifstream incarrier( path.str() );
183     
184     if ( !incarrier.is_open() ) {
185         SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << path.str() );
186         exit(-1);
187     }
188     
189     // skip first two lines
190     //incarrier >> skipeol;
191     //incarrier >> skipeol;
192     
193     while ( ! incarrier.eof() ) {
194       FGNavRecord *r = createNavFromStream(incarrier);
195       if (!r) {
196         continue;
197       }
198       
199       carrierlist->add (r);
200     } // end while
201
202 // end loading the carrier navaids file
203
204 // load the channel/freqency file
205     string channel, freq;
206     path="";
207     path = globals->get_fg_root();
208     path.append( "Navaids/TACAN_freq.dat" );
209     
210     SG_LOG( SG_GENERAL, SG_INFO, "opening file: " << path.str() );
211         
212     sg_gzifstream inchannel( path.str() );
213     
214     if ( !inchannel.is_open() ) {
215         SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << path.str() );
216         exit(-1);
217     }
218     
219     // skip first line
220     inchannel >> skipeol;
221     while ( ! inchannel.eof() ) {
222         FGTACANRecord *r = new FGTACANRecord;
223         inchannel >> (*r);
224         channellist->add ( r );
225         //cout << "channel = " << r->get_channel() ;
226         //cout << " freq = " << r->get_freq() << endl;
227         
228     } // end while
229
230  
231  // end ReadChanFile
232
233
234   // flush all the parsed ils.xml data, we don't need it anymore,
235   // since it's been meregd into the FGNavRecords
236     static_airportIlsData.clear();
237
238     return true;
239 }
240
241 SGPropertyNode* ilsDataForRunwayAndNavaid(FGRunway* aRunway, const std::string& aNavIdent)
242 {
243   if (!fgGetBool("/sim/paths/use-custom-scenery-data")) {
244     return NULL; 
245   }
246   
247   if (!aRunway) {
248     return NULL;
249   }
250   
251   FGAirport* apt = aRunway->airport();
252 // find (or load) the airprot ILS data
253   AirportPropertyMap::iterator it = static_airportIlsData.find(apt);
254   if (it == static_airportIlsData.end()) {
255     SGPath path;
256     if (!XMLLoader::findAirportData(apt->ident(), "ils", path)) {
257     // no ils.xml file for this airpot, insert a NULL entry so we don't
258     // check again
259       static_airportIlsData.insert(it, std::make_pair(apt, SGPropertyNode_ptr()));
260       return NULL;
261     }
262     
263     SGPropertyNode_ptr rootNode = new SGPropertyNode;
264     readProperties(path.str(), rootNode);
265     it = static_airportIlsData.insert(it, std::make_pair(apt, rootNode));
266   } // of ils.xml file not loaded
267   
268   if (!it->second) {
269     return NULL;
270   }
271   
272 // find the entry matching the runway
273   SGPropertyNode* runwayNode, *ilsNode;
274   for (int i=0; (runwayNode = it->second->getChild("runway", i)) != NULL; ++i) {
275     for (int j=0; (ilsNode = runwayNode->getChild("ils", j)) != NULL; ++j) {
276       // must match on both nav-ident and runway ident, to support the following:
277       // - runways with multiple distinct ILS installations (KEWD, for example)
278       // - runways where both ends share the same nav ident (LFAT, for example)
279       if ((ilsNode->getStringValue("nav-id") == aNavIdent) &&
280           (ilsNode->getStringValue("rwy") == aRunway->ident())) 
281       {
282         return ilsNode;
283       }
284     } // of ILS iteration
285   } // of runway iteration
286
287   return NULL;
288 }
289
290 FGRunway* getRunwayFromName(const std::string& aName)
291 {
292   vector<string> parts = simgear::strutils::split(aName);
293   if (parts.size() < 2) {
294     SG_LOG(SG_GENERAL, SG_WARN, "getRunwayFromName: malformed name:" << aName);
295     return NULL;
296   }
297   
298   const FGAirport* apt = fgFindAirportID(parts[0]);
299   if (!apt) {
300     SG_LOG(SG_GENERAL, SG_DEBUG, "navaid " << aName << " associated with bogus airport ID:" << parts[0]);
301     return NULL;
302   }
303   
304   if (!apt->hasRunwayWithIdent(parts[1])) {
305     SG_LOG(SG_GENERAL, SG_DEBUG, "navaid " << aName << " associated with bogus runway ID:" << parts[1]);
306     return NULL;
307   }
308
309   return apt->getRunwayByIdent(parts[1]);
310 }