]> git.mxchange.org Git - flightgear.git/blobdiff - src/Navaids/navdb.cxx
Prepare and implement reinit methods for instruments
[flightgear.git] / src / Navaids / navdb.cxx
index 40f487c5c22ea9b5699615cd23f9231a90749857..385e1db22510cc2e29ede392965fe15ed3e8dae3 100644 (file)
 #include <simgear/misc/sg_path.hxx>
 #include <simgear/structure/exception.hxx>
 #include <simgear/misc/sgstream.hxx>
+#include <simgear/props/props_io.hxx>
 
 #include "navrecord.hxx"
 #include "navlist.hxx"
 #include "navdb.hxx"
-#include "Main/globals.hxx"
+#include <Main/globals.hxx>
+#include <Navaids/markerbeacon.hxx>
+#include <Airports/simple.hxx>
+#include <Airports/runways.hxx>
+#include <Airports/xmlloader.hxx>
+#include <Main/fg_props.hxx>
 
 using std::string;
+using std::vector;
 
+typedef std::map<FGAirport*, SGPropertyNode_ptr> AirportPropertyMap;
+
+static AirportPropertyMap static_airportIlsData;
+
+static FGPositioned::Type
+mapRobinTypeToFGPType(int aTy)
+{
+  switch (aTy) {
+ // case 1:
+  case 2: return FGPositioned::NDB;
+  case 3: return FGPositioned::VOR;
+  case 4: return FGPositioned::ILS;
+  case 5: return FGPositioned::LOC;
+  case 6: return FGPositioned::GS;
+  case 12:
+  case 13: return FGPositioned::DME;
+  case 99: return FGPositioned::INVALID; // end-of-file code
+  default:
+    throw sg_range_exception("Got a nav.dat type we don't recognize", "FGNavRecord::createFromStream");
+  }
+}
+
+static FGNavRecord* createNavFromStream(std::istream& aStream)
+{
+  int rawType;
+  aStream >> rawType;
+  if (aStream.eof() || (rawType == 99)) {
+    return NULL; // happens with, eg, carrier_nav.dat
+  }
+  
+  double lat, lon, elev_ft, multiuse;
+  int freq, range;
+  std::string name, ident;
+  aStream >> lat >> lon >> elev_ft >> freq >> range >> multiuse >> ident;
+  getline(aStream, name);
+  
+  SGGeod pos(SGGeod::fromDegFt(lon, lat, elev_ft));
+  name = simgear::strutils::strip(name);
+  
+  if ((rawType >= 7) && (rawType <= 9)) {
+    // marker beacons use a different run-time class now
+     FGMarkerBeaconRecord::create(rawType, name, pos);
+     return NULL; // not a nav-record, but that's okay
+  }
+  
+  FGPositioned::Type type = mapRobinTypeToFGPType(rawType);
+  if (type == FGPositioned::INVALID) {
+    return NULL;
+  }
+  
+  // silently multiply adf frequencies by 100 so that adf
+  // vs. nav/loc frequency lookups can use the same code.
+  if (type == FGPositioned::NDB) {
+    freq *= 100;
+  }
+  
+  return new FGNavRecord(type, ident, name, pos,
+    freq, range, multiuse);
+}
 
 // load and initialize the navigational databases
 bool fgNavDBInit( FGNavList *navlist, FGNavList *loclist, FGNavList *gslist,
@@ -50,17 +116,6 @@ bool fgNavDBInit( FGNavList *navlist, FGNavList *loclist, FGNavList *gslist,
                   FGTACANList *channellist)
 {
     SG_LOG(SG_GENERAL, SG_INFO, "Loading Navaid Databases");
-    // SG_LOG(SG_GENERAL, SG_INFO, "  VOR/NDB");
-    // SGPath p_nav( globals->get_fg_root() );
-    // p_nav.append( "Navaids/default.nav" );
-    // navlist->init( p_nav );
-
-    // SG_LOG(SG_GENERAL, SG_INFO, "  ILS and Marker Beacons");
-    // beacons->init();
-    // SGPath p_ils( globals->get_fg_root() );
-    // p_ils.append( "Navaids/default.ils" );
-    // ilslist->init( p_ils );
-
 
     SGPath path( globals->get_fg_root() );
     path.append( "Navaids/nav.dat" );
@@ -76,9 +131,9 @@ bool fgNavDBInit( FGNavList *navlist, FGNavList *loclist, FGNavList *gslist,
     in >> skipeol;
 
     while (!in.eof()) {
-      FGNavRecord *r = FGNavRecord::createFromStream(in);
+      FGNavRecord *r = createNavFromStream(in);
       if (!r) {
-        break;
+        continue;
       }
       
       switch (r->type()) {
@@ -96,12 +151,6 @@ bool fgNavDBInit( FGNavList *navlist, FGNavList *loclist, FGNavList *gslist,
         gslist->add(r);
         break;
       
-      case FGPositioned::OM:
-      case FGPositioned::MM:
-      case FGPositioned::IM:
-        // no need to add this to a list, never searched by frequency
-        break;
-      
       case FGPositioned::DME:
       {
         dmelist->add(r);
@@ -143,7 +192,7 @@ bool fgNavDBInit( FGNavList *navlist, FGNavList *loclist, FGNavList *gslist,
     //incarrier >> skipeol;
     
     while ( ! incarrier.eof() ) {
-      FGNavRecord *r = FGNavRecord::createFromStream(incarrier);
+      FGNavRecord *r = createNavFromStream(incarrier);
       if (!r) {
         continue;
       }
@@ -183,5 +232,76 @@ bool fgNavDBInit( FGNavList *navlist, FGNavList *loclist, FGNavList *gslist,
  // end ReadChanFile
 
 
+  // flush all the parsed ils.xml data, we don't need it anymore,
+  // since it's been meregd into the FGNavRecords
+    static_airportIlsData.clear();
+
     return true;
 }
+
+SGPropertyNode* ilsDataForRunwayAndNavaid(FGRunway* aRunway, const std::string& aNavIdent)
+{
+  if (!aRunway) {
+    return NULL;
+  }
+  
+  FGAirport* apt = aRunway->airport();
+// find (or load) the airprot ILS data
+  AirportPropertyMap::iterator it = static_airportIlsData.find(apt);
+  if (it == static_airportIlsData.end()) {
+    SGPath path;
+    if (!XMLLoader::findAirportData(apt->ident(), "ils", path)) {
+    // no ils.xml file for this airpot, insert a NULL entry so we don't
+    // check again
+      static_airportIlsData.insert(it, std::make_pair(apt, SGPropertyNode_ptr()));
+      return NULL;
+    }
+    
+    SGPropertyNode_ptr rootNode = new SGPropertyNode;
+    readProperties(path.str(), rootNode);
+    it = static_airportIlsData.insert(it, std::make_pair(apt, rootNode));
+  } // of ils.xml file not loaded
+  
+  if (!it->second) {
+    return NULL;
+  }
+  
+// find the entry matching the runway
+  SGPropertyNode* runwayNode, *ilsNode;
+  for (int i=0; (runwayNode = it->second->getChild("runway", i)) != NULL; ++i) {
+    for (int j=0; (ilsNode = runwayNode->getChild("ils", j)) != NULL; ++j) {
+      // must match on both nav-ident and runway ident, to support the following:
+      // - runways with multiple distinct ILS installations (KEWD, for example)
+      // - runways where both ends share the same nav ident (LFAT, for example)
+      if ((ilsNode->getStringValue("nav-id") == aNavIdent) &&
+          (ilsNode->getStringValue("rwy") == aRunway->ident())) 
+      {
+        return ilsNode;
+      }
+    } // of ILS iteration
+  } // of runway iteration
+
+  return NULL;
+}
+
+FGRunway* getRunwayFromName(const std::string& aName)
+{
+  vector<string> parts = simgear::strutils::split(aName);
+  if (parts.size() < 2) {
+    SG_LOG(SG_GENERAL, SG_WARN, "getRunwayFromName: malformed name:" << aName);
+    return NULL;
+  }
+  
+  const FGAirport* apt = fgFindAirportID(parts[0]);
+  if (!apt) {
+    SG_LOG(SG_GENERAL, SG_DEBUG, "navaid " << aName << " associated with bogus airport ID:" << parts[0]);
+    return NULL;
+  }
+  
+  if (!apt->hasRunwayWithIdent(parts[1])) {
+    SG_LOG(SG_GENERAL, SG_DEBUG, "navaid " << aName << " associated with bogus runway ID:" << parts[1]);
+    return NULL;
+  }
+
+  return apt->getRunwayByIdent(parts[1]);
+}