]> git.mxchange.org Git - flightgear.git/blobdiff - src/Navaids/navrecord.cxx
Merge branch 'jmt/cleanup' into next
[flightgear.git] / src / Navaids / navrecord.cxx
index 2aa25424fe9dfc0c9bb36aa9c0a9a4675eb0f6ef..6bb71a54c9d2e40e3506b4e17e451b910e80fd94 100644 (file)
 #endif
 
 #include <istream>
-#include <simgear/misc/sgstream.hxx>
-#include "Navaids/navrecord.hxx"
-
-FGNavRecord::FGNavRecord(void) :
-    type(0),
-    pos(SGGeod::fromDeg(0, 0)),
-    cart(0, 0, 0),
-    freq(0),
-    range(0),
-    multiuse(0.0),
-    ident(""),
-    name(""),
-    apt_id(""),
-    serviceable(true),
-    trans_ident("")
-{
-}
 
-FGNavRecord::FGNavRecord(int aTy, const std::string& aIdent, 
-  const std::string& aName, const std::string& aAirport,
-  double lat, double lon, int aFreq, int aRange, double aMultiuse) :
-  type(aTy),
+#include <simgear/misc/sgstream.hxx>
+#include <simgear/misc/sg_path.hxx>
+#include <simgear/structure/exception.hxx>
+#include <simgear/debug/logstream.hxx>
+#include <simgear/sg_inlines.h>
+#include <simgear/props/props.hxx>
+#include <simgear/props/props_io.hxx>
+
+#include <Navaids/navrecord.hxx>
+#include <Navaids/navdb.hxx>
+#include <Airports/runways.hxx>
+#include <Airports/simple.hxx>
+#include <Airports/xmlloader.hxx>
+
+#include <Main/fg_props.hxx>
+
+FGNavRecord::FGNavRecord(Type aTy, const std::string& aIdent, 
+  const std::string& aName, const SGGeod& aPos,
+  int aFreq, int aRange, double aMultiuse) :
+  FGPositioned(aTy, aIdent, aPos),
   freq(aFreq),
   range(aRange),
   multiuse(aMultiuse),
-  ident(aIdent),
-  name(aName),
-  apt_id(aAirport),
+  _name(aName),
+  mRunway(NULL),
   serviceable(true),
   trans_ident(aIdent)
-{
-  pos = SGGeod::fromDeg(lon, lat);
-  cart = SGVec3d::fromGeod(pos);
-}
-
-fg_nav_types FGNavRecord::get_fg_type() const {
-    switch(type) {
-    case 2: return(FG_NAV_NDB);
-    case 3: return(FG_NAV_VOR);
-    case 4: return(FG_NAV_ILS);
-    default: return(FG_NAV_ANY);
+{ 
+  initAirportRelation();
+
+  // Ranges are included with the latest data format, no need to
+  // assign our own defaults, unless the range is not set for some
+  // reason.
+  if (range < 0.1) {
+    SG_LOG(SG_GENERAL, SG_WARN, "navaid " << ident() << " has no range set, using defaults");
+    switch (type()) {
+    case NDB:
+    case VOR:
+      range = FG_NAV_DEFAULT_RANGE;
+      break;
+    
+    case LOC:
+    case ILS:
+    case GS:
+      range = FG_LOC_DEFAULT_RANGE;
+      break;
+      
+    case DME:
+      range = FG_DME_DEFAULT_RANGE;
+      break;
+    
+    default:
+      range = FG_LOC_DEFAULT_RANGE;
     }
+  }
+  
 }
 
-
-std::istream& operator>>( std::istream& in, FGNavRecord& n )
+void FGNavRecord::initAirportRelation()
 {
-    in >> n.type;
-    
-    if ( n.type == 99 ) {
-        return in >> skipeol;
-    }
-
-    double lat, lon, elev_ft;
-    in >> lat >> lon >> elev_ft >> n.freq >> n.range >> n.multiuse
-       >> n.ident;
-    n.pos.setLatitudeDeg(lat);
-    n.pos.setLongitudeDeg(lon);
-    n.pos.setElevationFt(elev_ft);
-    getline( in, n.name );
-
-    // silently multiply adf frequencies by 100 so that adf
-    // vs. nav/loc frequency lookups can use the same code.
-    if ( n.type == 2 ) {
-        n.freq *= 100;
-    }
-
-    // Remove any leading spaces before the name
-    while ( n.name.substr(0,1) == " " ) {
-        n.name = n.name.erase(0,1);
+  if ((type() < ILS) || (type() > GS)) {
+    return; // not airport-located
+  }
+  
+  mRunway = getRunwayFromName(_name);  
+  
+  if (type() != GS) {
+    readAirportSceneryData();
+  }
+        
+  // fudge elevation to the runway elevation if it's not specified
+  if (fabs(elevation()) < 0.01) {
+    mPosition.setElevationFt(mRunway->elevation());
+  }
+  
+  if (type() == ILS || type() == LOC) {
+    mRunway->setILS(this);
+  }
+  
+  // align localizers with their runway
+  if ((type() == ILS) || (type() == LOC)) {
+    if (!fgGetBool("/sim/navdb/localizers/auto-align", true)) {
+      return;
     }
-
-    if ( n.type >= 4 && n.type <= 9 ) {
-        // these types are always associated with an airport id
-        std::string::size_type pos = n.name.find(" ");
-        n.apt_id = n.name.substr(0, pos);
-    }
-
-    // Ranges are included with the latest data format, no need to
-    // assign our own defaults, unless the range is not set for some
-    // reason.
-
-    if ( n.range < 0.1 ) {
-        // assign default ranges
     
-        if ( n.type == 2 || n.type == 3 ) {
-            n.range = FG_NAV_DEFAULT_RANGE;
-        } else if ( n.type == 4 || n.type == 5 || n.type == 6 ) {
-            n.range = FG_LOC_DEFAULT_RANGE;
-        } else if ( n.type == 12 ) {
-            n.range = FG_DME_DEFAULT_RANGE;
-        } else {
-            n.range = FG_LOC_DEFAULT_RANGE;
-        }
-    }
-
-    // transmitted ident (same as ident unless modeling a fault)
-    n.trans_ident = n.ident;
+   double threshold 
+     = fgGetDouble( "/sim/navdb/localizers/auto-align-threshold-deg", 5.0 );
+    alignLocaliserWithRunway(threshold);
+  }
+}
 
-    // generate cartesian coordinates
-    n.cart = SGVec3d::fromGeod(n.pos);
+void FGNavRecord::readAirportSceneryData()
+{
+  // allow users to disable the scenery data in the short-term
+  // longer term, this option can probably disappear
+  if (!fgGetBool("/sim/use-scenery-airport-data")) {
+    return; 
+  }
+  
+  SGPath path;
+  SGPropertyNode_ptr rootNode = new SGPropertyNode;
+  if (!XMLLoader::findAirportData(mRunway->airport()->ident(), "ils", path)) {
+    return;
+  }
+  
+  readProperties(path.str(), rootNode);
+  SGPropertyNode* runwayNode, *ilsNode;
+  for (int i=0; (runwayNode = rootNode->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") == ident()) &&
+          (ilsNode->getStringValue("rwy") == mRunway->ident())) {
+        processSceneryILS(ilsNode);
+        return;
+      }
+    } // of ILS iteration
+  } // of runway iteration
+}
 
-    return in;
+void FGNavRecord::processSceneryILS(SGPropertyNode* aILSNode)
+{
+  double hdgDeg = aILSNode->getDoubleValue("hdg-deg"),
+    lon = aILSNode->getDoubleValue("lon"),
+    lat = aILSNode->getDoubleValue("lat"),
+    elevM = aILSNode->getDoubleValue("elev-m");
+    
+  mPosition = SGGeod::fromDegM(lon, lat, elevM);
+  multiuse = hdgDeg;
 }
 
+void FGNavRecord::alignLocaliserWithRunway(double aThreshold)
+{
+// find the distance from the threshold to the localizer
+  double dist = SGGeodesy::distanceM(mPosition, mRunway->threshold());
+
+// back project that distance along the runway center line
+  SGGeod newPos = mRunway->pointOnCenterline(dist);
+
+  double hdg_diff = get_multiuse() - mRunway->headingDeg();
+  SG_NORMALIZE_RANGE(hdg_diff, -180.0, 180.0);
+
+  if ( fabs(hdg_diff) <= aThreshold ) {
+    mPosition = SGGeod::fromGeodFt(newPos, mPosition.getElevationFt());
+    set_multiuse( mRunway->headingDeg() );
+  } else {
+    SG_LOG(SG_GENERAL, SG_DEBUG, "localizer:" << ident() << ", aligning with runway " 
+      << mRunway->ident() << " exceeded heading threshold");
+  }
+}
 
 FGTACANRecord::FGTACANRecord(void) :
     channel(""),