]> git.mxchange.org Git - flightgear.git/blobdiff - src/Navaids/navrecord.cxx
Directly associate runways objects with their ILS navrecord (if one exists)
[flightgear.git] / src / Navaids / navrecord.cxx
index 2aa25424fe9dfc0c9bb36aa9c0a9a4675eb0f6ef..2689f3d3bc4a3fb4065574c1718509b09d487ec3 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/structure/exception.hxx>
+#include <simgear/debug/logstream.hxx>
+#include <simgear/sg_inlines.h>
+
+#include <Navaids/navrecord.hxx>
+#include <Navaids/navdb.hxx>
+#include <Airports/runways.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);    
+  // fudge elevation to the runway elevation if it's not specified
+  if (fabs(elevation()) < 0.01) {
+    mPosition.setElevationFt(mRunway->elevation());
+  }
+  
+  if (type() == ILS) {
+    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;
-
-    // generate cartesian coordinates
-    n.cart = SGVec3d::fromGeod(n.pos);
-
-    return in;
+   double threshold 
+     = fgGetDouble( "/sim/navdb/localizers/auto-align-threshold-deg", 5.0 );
+    alignLocaliserWithRunway(threshold);
+  }
 }
 
+void FGNavRecord::alignLocaliserWithRunway(double aThreshold)
+{
+// find the distance from the threshold to the localizer
+  SGGeod runwayThreshold(mRunway->threshold());
+  double dist, az1, az2;
+  SGGeodesy::inverse(mPosition, runwayThreshold, az1, az2, dist);
+
+// 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 = newPos;
+    set_multiuse( mRunway->headingDeg() );
+  } else {
+    SG_LOG(SG_GENERAL, SG_WARN, "localizer:" << ident() << ", aligning with runway " 
+      << mRunway->ident() << " exceeded heading threshold");
+  }
+}
 
 FGTACANRecord::FGTACANRecord(void) :
     channel(""),