]> git.mxchange.org Git - flightgear.git/blobdiff - src/Instrumentation/dclgps.cxx
Add a hardwired instrument approach for testing. This will be removed and read from...
[flightgear.git] / src / Instrumentation / dclgps.cxx
index d1ab7ef0279cd1a5857bc08a2082705d15140216..da43c4970c424e1b917f391f5abfea6a08139a69 100644 (file)
 #include "dclgps.hxx"
 
 #include <simgear/sg_inlines.h>
-#include <simgear/structure/commands.hxx>
 #include <simgear/timing/sg_time.hxx>
 #include <simgear/magvar/magvar.hxx>
 
 #include <Main/fg_props.hxx>
 #include <Navaids/fix.hxx>
+#include <Navaids/navrecord.hxx>
+#include <Airports/simple.hxx>
+#include <Airports/runways.hxx>
 
 #include <iostream>
-using std::cout;
 
-//using namespace std;
-
-// Command callbacks for FlightGear
-
-static bool do_kln89_msg_pressed(const SGPropertyNode* arg) {
-       //cout << "do_kln89_msg_pressed called!\n";
-       DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89");
-       gps->MsgPressed();
-       return(true);
-}
-
-static bool do_kln89_obs_pressed(const SGPropertyNode* arg) {
-       //cout << "do_kln89_obs_pressed called!\n";
-       DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89");
-       gps->OBSPressed();
-       return(true);
-}
-
-static bool do_kln89_alt_pressed(const SGPropertyNode* arg) {
-       //cout << "do_kln89_alt_pressed called!\n";
-       DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89");
-       gps->AltPressed();
-       return(true);
-}
-
-static bool do_kln89_nrst_pressed(const SGPropertyNode* arg) {
-       DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89");
-       gps->NrstPressed();
-       return(true);
-}
-
-static bool do_kln89_dto_pressed(const SGPropertyNode* arg) {
-       DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89");
-       gps->DtoPressed();
-       return(true);
-}
-
-static bool do_kln89_clr_pressed(const SGPropertyNode* arg) {
-       DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89");
-       gps->ClrPressed();
-       return(true);
-}
-
-static bool do_kln89_ent_pressed(const SGPropertyNode* arg) {
-       DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89");
-       gps->EntPressed();
-       return(true);
-}
-
-static bool do_kln89_crsr_pressed(const SGPropertyNode* arg) {
-       DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89");
-       gps->CrsrPressed();
-       return(true);
-}
-
-static bool do_kln89_knob1left1(const SGPropertyNode* arg) {
-       DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89");
-       gps->Knob1Left1();
-       return(true);
-}
-
-static bool do_kln89_knob1right1(const SGPropertyNode* arg) {
-       DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89");
-       gps->Knob1Right1();
-       return(true);
-}
-
-static bool do_kln89_knob2left1(const SGPropertyNode* arg) {
-       DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89");
-       gps->Knob2Left1();
-       return(true);
-}
-
-static bool do_kln89_knob2right1(const SGPropertyNode* arg) {
-       DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89");
-       gps->Knob2Right1();
-       return(true);
-}
-
-// End command callbacks
+using namespace std;
 
 GPSWaypoint::GPSWaypoint() {
     appType = GPS_APP_NONE;
@@ -140,31 +62,43 @@ string GPSWaypoint::GetAprId() {
        else return(id);
 }
 
-GPSWaypoint* GPSWaypoint::createFromFix(const FGFix* aFix)
-{
-  assert(aFix);
-  return new GPSWaypoint(aFix->get_ident(), 
-    aFix->get_lat() * SG_DEGREES_TO_RADIANS,
-    aFix->get_lon() * SG_DEGREES_TO_RADIANS,
-    GPS_WP_INT);
-}
-
-GPSWaypoint* GPSWaypoint::createFromNav(const FGNavRecord* aNav)
+static GPSWpType
+GPSWpTypeFromFGPosType(FGPositioned::Type aType)
 {
-  assert(aNav);
-  return new GPSWaypoint(aNav->get_ident(), 
-    aNav->get_lat() * SG_DEGREES_TO_RADIANS,
-    aNav->get_lon() * SG_DEGREES_TO_RADIANS,
-    (aNav->get_fg_type() == FG_NAV_VOR ? GPS_WP_VOR : GPS_WP_NDB));
+  switch (aType) {
+  case FGPositioned::AIRPORT:
+  case FGPositioned::SEAPORT:
+  case FGPositioned::HELIPORT:
+    return GPS_WP_APT;
+  
+  case FGPositioned::VOR:
+    return GPS_WP_VOR;
+  
+  case FGPositioned::NDB:
+    return GPS_WP_NDB;
+  
+  case FGPositioned::WAYPOINT:
+    return GPS_WP_USR;
+  
+  case FGPositioned::FIX:
+    return GPS_WP_INT;
+  
+  default:
+    return GPS_WP_USR;
+  }
 }
 
-GPSWaypoint* GPSWaypoint::createFromAirport(const FGAirport* aApt)
+GPSWaypoint* GPSWaypoint::createFromPositioned(const FGPositioned* aPos)
 {
-  assert(aApt);
-  return new GPSWaypoint(aApt->getId(), 
-    aApt->getLatitude() * SG_DEGREES_TO_RADIANS,
-    aApt->getLongitude() * SG_DEGREES_TO_RADIANS,
-    GPS_WP_APT);
+  if (!aPos) {
+    return NULL; // happens if find returns no match
+  }
+  
+  return new GPSWaypoint(aPos->ident(), 
+    aPos->latitude() * SG_DEGREES_TO_RADIANS,
+    aPos->longitude() * SG_DEGREES_TO_RADIANS,
+    GPSWpTypeFromFGPosType(aPos->type())
+  );
 }
 
 ostream& operator << (ostream& os, GPSAppWpType type) {
@@ -209,59 +143,12 @@ ClockTime::ClockTime(int hr, int min) {
 ClockTime::~ClockTime() {
 }
 
-GPSPage::GPSPage(DCLGPS* parent) {
-       _parent = parent;
-       _subPage = 0;
-}
-
-GPSPage::~GPSPage() {
-}
-
-void GPSPage::Update(double dt) {}
-
-void GPSPage::Knob1Left1() {}
-void GPSPage::Knob1Right1() {}
-
-void GPSPage::Knob2Left1() {
-       _parent->_activePage->LooseFocus();
-       _subPage--;
-       if(_subPage < 0) _subPage = _nSubPages - 1;
-}
-
-void GPSPage::Knob2Right1() {
-       _parent->_activePage->LooseFocus();
-       _subPage++;
-       if(_subPage >= _nSubPages) _subPage = 0;
-}
-
-void GPSPage::CrsrPressed() {}
-void GPSPage::EntPressed() {}
-void GPSPage::ClrPressed() {}
-void GPSPage::DtoPressed() {}
-void GPSPage::NrstPressed() {}
-void GPSPage::AltPressed() {}
-void GPSPage::OBSPressed() {}
-void GPSPage::MsgPressed() {}
-
-string GPSPage::GPSitoa(int n) {
-       char buf[4];
-       // TODO - sanity check n!
-       sprintf(buf, "%i", n);
-       string s = buf;
-       return(s);
-}
-
-void GPSPage::CleanUp() {}
-void GPSPage::LooseFocus() {}
-void GPSPage::SetId(const string& s) {}
-
 // ------------------------------------------------------------------------------------- //
 
 DCLGPS::DCLGPS(RenderArea2D* instrument) {
        _instrument = instrument;
        _nFields = 1;
        _maxFields = 2;
-       _pages.clear();
        
        // Units - lets default to US units - FG can set them to other units from config during startup if desired.
        _altUnits = GPS_ALT_UNITS_FT;
@@ -344,27 +231,105 @@ DCLGPS::~DCLGPS() {
        // TODO - may need to delete the approach database!!
 }
 
-void DCLGPS::draw() {
-       //cout << "draw called!\n";
-       _instrument->draw();
+void DCLGPS::draw(osg::State& state) {
+       _instrument->draw(state);
 }
 
 void DCLGPS::init() {
-       globals->get_commands()->addCommand("kln89_msg_pressed", do_kln89_msg_pressed);
-       globals->get_commands()->addCommand("kln89_obs_pressed", do_kln89_obs_pressed);
-       globals->get_commands()->addCommand("kln89_alt_pressed", do_kln89_alt_pressed);
-       globals->get_commands()->addCommand("kln89_nrst_pressed", do_kln89_nrst_pressed);
-       globals->get_commands()->addCommand("kln89_dto_pressed", do_kln89_dto_pressed);
-       globals->get_commands()->addCommand("kln89_clr_pressed", do_kln89_clr_pressed);
-       globals->get_commands()->addCommand("kln89_ent_pressed", do_kln89_ent_pressed);
-       globals->get_commands()->addCommand("kln89_crsr_pressed", do_kln89_crsr_pressed);
-       globals->get_commands()->addCommand("kln89_knob1left1", do_kln89_knob1left1);
-       globals->get_commands()->addCommand("kln89_knob1right1", do_kln89_knob1right1);
-       globals->get_commands()->addCommand("kln89_knob2left1", do_kln89_knob2left1);
-       globals->get_commands()->addCommand("kln89_knob2right1", do_kln89_knob2right1);
                
        // Not sure if this should be here, but OK for now.
        CreateDefaultFlightPlans();
+
+       // Hack - hardwire some instrument approaches for development.
+       // These will shortly be replaced by a routine to read ARINC data from file instead.
+       FGNPIAP* iap;
+       GPSWaypoint* wp;
+       GPSFlightPlan* fp;
+       const GPSWaypoint* cwp;
+       
+       iap = new FGNPIAP;
+       iap->_id = "KHAF";
+       iap->_name = "RNAV (GPS) Y RWY 12";
+       iap->_abbrev = "R12-Y";
+       iap->_rwyStr = "12";
+       iap->_approachRoutes.clear();
+       iap->_IAP.clear();
+       iap->_MAP.clear();
+       // -------
+       wp = new GPSWaypoint;
+       wp->id = "GOBBS";
+       // Nasty using the find any function here, but it saves converting data from FGFix etc. 
+       cwp = FindFirstByExactId(wp->id);
+       if(cwp) {
+               *wp = *cwp;
+               wp->appType = GPS_IAF;
+               fp = new GPSFlightPlan;
+               fp->waypoints.push_back(wp);
+       } else {
+               //cout << "Unable to find waypoint " << wp->id << '\n';
+       }
+       // -------
+       wp = new GPSWaypoint;
+       wp->id = "FUJCE";
+       cwp = FindFirstByExactId(wp->id);
+       if(cwp) {
+               *wp = *cwp;
+               wp->appType = GPS_IAP;
+               fp->waypoints.push_back(wp);
+               iap->_approachRoutes.push_back(fp);
+               iap->_IAP.push_back(wp);
+       } else {
+               //cout << "Unable to find waypoint " << wp->id << '\n';
+       }
+       // -------
+       wp = new GPSWaypoint;
+       wp->id = "JEVXY";
+       cwp = FindFirstByExactId(wp->id);
+       if(cwp) {
+               *wp = *cwp;
+               wp->appType = GPS_FAF;
+               iap->_IAP.push_back(wp);
+       } else {
+               //cout << "Unable to find waypoint " << wp->id << '\n';
+       }
+       // -------
+       wp = new GPSWaypoint;
+       wp->id = "RW12";
+       wp->appType = GPS_MAP;
+       if(wp->id.substr(0, 2) == "RW" && wp->appType == GPS_MAP) {
+               // Assume that this is a missed-approach point based on the runway number, which appears to be standard for most approaches.
+               const FGAirport* apt = fgFindAirportID(iap->_id);
+               if(apt) {
+                       // TODO - sanity check the waypoint ID to ensure we have a double digit number
+                       FGRunway* rwy = apt->getRunwayByIdent(wp->id.substr(2, 2));
+                       if(rwy) {
+                               wp->lat = rwy->begin().getLatitudeRad();
+                               wp->lon = rwy->begin().getLongitudeRad();
+                       }
+               }
+       } else {
+               cwp = FindFirstByExactId(wp->id);
+               if(cwp) {
+                       *wp = *cwp;
+                       wp->appType = GPS_MAP;
+               } else {
+                       //cout << "Unable to find waypoint " << wp->id << '\n';
+               }
+       }
+       iap->_IAP.push_back(wp);
+       // -------
+       wp = new GPSWaypoint;
+       wp->id = "SEEMS";
+       cwp = FindFirstByExactId(wp->id);
+       if(cwp) {
+               *wp = *cwp;
+               wp->appType = GPS_MAHP;
+               iap->_MAP.push_back(wp);
+       } else {
+               //cout << "Unable to find waypoint " << wp->id << '\n';
+       }
+       // -------
+       _np_iap[iap->_id].push_back(iap);
 }
 
 void DCLGPS::bind() {
@@ -648,6 +613,15 @@ void DCLGPS::update(double dt) {
        }
 }
 
+GPSWaypoint* DCLGPS::GetActiveWaypoint() { 
+       return &_activeWaypoint; 
+}
+       
+// Returns meters
+float DCLGPS::GetDistToActiveWaypoint() { 
+       return _dist2Act;
+}
+
 // I don't yet fully understand all the gotchas about where to source time from.
 // This function sets the initial timer before the clock exports properties
 // and the one below uses the clock to be consistent with the rest of the code.
@@ -698,18 +672,7 @@ void DCLGPS::DtoCancel() {
        _dto = false;
 }
 
-void DCLGPS::Knob1Left1() {}
-void DCLGPS::Knob1Right1() {}
-void DCLGPS::Knob2Left1() {}
-void DCLGPS::Knob2Right1() {}
-void DCLGPS::CrsrPressed() { _activePage->CrsrPressed(); }
-void DCLGPS::EntPressed() { _activePage->EntPressed(); }
-void DCLGPS::ClrPressed() { _activePage->ClrPressed(); }
-void DCLGPS::DtoPressed() {}
-void DCLGPS::NrstPressed() {}
-void DCLGPS::AltPressed() {}
-
-void DCLGPS::OBSPressed() { 
+void DCLGPS::ToggleOBSMode() {
        _obsMode = !_obsMode;
        if(_obsMode) {
                if(!_activeWaypoint.id.empty()) {
@@ -731,8 +694,6 @@ void DCLGPS::SetOBSFromWaypoint() {
        _fromWaypoint.id = "OBSWP";
 }
 
-void DCLGPS::MsgPressed() {}
-
 void DCLGPS::CDIFSDIncrease() {
        if(_currentCdiScaleIndex == 0) {
                _currentCdiScaleIndex = _cdiScales.size() - 1;
@@ -1016,187 +977,92 @@ void DCLGPS::CreateFlightPlan(GPSFlightPlan* fp, vector<string> ids, vector<GPSW
                case GPS_WP_USR:
                        // TODO
                        break;
+               case GPS_WP_VIRT:
+                       // TODO
+                       break;
                }
        }
 }
 
 /***************************************/
 
-/**
- * STL functor for use with algorithms. This comapres strings according to
- * the KLN-89's notion of ordering, with digits after letters.
- * Also implements FGIdentOrdering so it can be passed into the various list
- * find helpers.
- */
-class stringOrderKLN89 : public FGIdentOrdering
+class DCLGPSFilter : public FGPositioned::Filter
 {
 public:
-  bool operator()(const gps_waypoint_map::value_type& aA, const std::string& aB) const
-  {
-    return compare(aA.first, aB);
-  }
-  
-  bool operator()(const std::string& aS1, const std::string& aS2) const
-  {
-    return compare(aS1, aS2);
-  }
-  
-  virtual bool compare(const std::string& aS1, const std::string& aS2) const
-  {
-    if (aS1.empty()) return true;
-    if (aS2.empty()) return false;
-    
-    char* a = (char*) aS1.c_str();
-    char* b = (char*) aS2.c_str();
-    
-    for ( ; *a && *b; ++a, ++b) {
-      if (*a == *b) continue;
-      
-      bool aDigit = isdigit(*a);
-      bool bDigit = isdigit(*b);
-      
-      if (aDigit == bDigit) {
-        return (*a < *b); // we already know they're not equal
-      }
-      
-      // digit-ness differs
-      if (aDigit) return false; // s1 = KS9 goes *after* s2 = KSA
-      assert(bDigit);
-      return true; // s1 = KSF, s2 = KS5, s1 is indeed < s2
+  virtual bool pass(const FGPositioned* aPos) const {
+    switch (aPos->type()) {
+    case FGPositioned::AIRPORT:
+    // how about heliports and seaports?
+    case FGPositioned::NDB:
+    case FGPositioned::VOR:
+    case FGPositioned::WAYPOINT:
+    case FGPositioned::FIX:
+      break;
+    default: return false; // reject all other types
     }
-    
-    if (*b) return true; // *a == 0, s2 is longer
-    return false; // s1 is longer, or strings are equal
+    return true;
   }
 };
 
 GPSWaypoint* DCLGPS::FindFirstById(const string& id) const
 {
-  stringOrderKLN89 ordering;
-  nav_list_type vors = globals->get_navlist()->findFirstByIdent(id, FG_NAV_VOR, false);
-  nav_list_type ndbs = globals->get_navlist()->findFirstByIdent(id, FG_NAV_NDB, false);
-  const FGFix* fix = globals->get_fixlist()->findFirstByIdent(id, &ordering);
-  const FGAirport* apt = globals->get_airports()->findFirstById(id, &ordering);
-  // search local gps waypoints (USR)
-
-// pick the best - ugly logic, sorry. This is a temporary fix to getting rid
-// of the huge local waypoint table, it'll die when there's a way to query
-// this stuff centrally.
-// what we're doing is using map inserts to order the result, then using
-// the first entry (begin()) as the lowest, hence best, match
-  map<string, GPSWpType, stringOrderKLN89> sorter;
-  if (fix) sorter[fix->get_ident()] = GPS_WP_INT;
-  if (apt) sorter[apt->getId()] = GPS_WP_APT;
-  if (!vors.empty()) sorter[vors.front()->get_ident()] = GPS_WP_VOR;
-  if (!ndbs.empty()) sorter[ndbs.front()->get_ident()] = GPS_WP_NDB;
-
-  if (sorter.empty()) return NULL; // no results at all
-  GPSWpType ty = sorter.begin()->second;
-  
-  switch (ty) {
-  case GPS_WP_INT: 
-    return GPSWaypoint::createFromFix(fix);
-  
-  case GPS_WP_APT:
-    return GPSWaypoint::createFromAirport(apt);
-  
-  case GPS_WP_VOR:
-    return GPSWaypoint::createFromNav(vors.front());
-    
-  case GPS_WP_NDB:
-    return GPSWaypoint::createFromNav(ndbs.front());
-  default:
-    return NULL; // can't happen
-  }
+  DCLGPSFilter filter;
+  FGPositionedRef result = FGPositioned::findNextWithPartialId(NULL, id, &filter);
+  return GPSWaypoint::createFromPositioned(result);
 }
 
 GPSWaypoint* DCLGPS::FindFirstByExactId(const string& id) const
 {
-  if (const FGAirport* apt = globals->get_airports()->search(id)) {
-    return GPSWaypoint::createFromAirport(apt);
-  }
-  
-  if (const FGFix* fix = globals->get_fixlist()->search(id)) {
-    return GPSWaypoint::createFromFix(fix);
-  }
-  
-  nav_list_type vors = globals->get_navlist()->findFirstByIdent(id, FG_NAV_VOR, true);
-  if (!vors.empty()) {
-    return GPSWaypoint::createFromNav(vors.front());
-  }
+  SGGeod pos(SGGeod::fromRad(_lon, _lat));
+  FGPositionedRef result = FGPositioned::findClosestWithIdent(id, pos);
+  return GPSWaypoint::createFromPositioned(result);
+}
+
+// TODO - add the ASCII / alphabetical stuff from the Atlas version
+FGPositioned* DCLGPS::FindTypedFirstById(const string& id, FGPositioned::Type ty, bool &multi, bool exact)
+{
+  multi = false;
+  FGPositioned::TypeFilter filter(ty);
   
-  nav_list_type ndbs = globals->get_navlist()->findFirstByIdent(id, FG_NAV_NDB, true);
-  if (!ndbs.empty()) {
-    return GPSWaypoint::createFromNav(ndbs.front());
+  if (exact) {
+    FGPositioned::List matches = 
+      FGPositioned::findAllWithIdentSortedByRange(id, SGGeod::fromRad(_lon, _lat), &filter);
+    multi = (matches.size() > 1);
+    return matches.empty() ? NULL : matches.front().ptr();
   }
   
-  return NULL;
+  return FGPositioned::findNextWithPartialId(NULL, id, &filter);
 }
 
-// Host specific lookup functions
-// TODO - add the ASCII / alphabetical stuff from the Atlas version
-FGNavRecord* DCLGPS::FindFirstVorById(const string& id, bool &multi, bool exact) {
-       // NOTE - at the moment multi is never set.
-       multi = false;
-       //if(exact) return(_overlays->FindFirstVorById(id, exact));
-       
-       nav_list_type nav = globals->get_navlist()->findFirstByIdent(id, FG_NAV_VOR, exact);
-       
-       if(nav.size() > 1) multi = true;
-       //return(nav.empty() ? NULL : *(nav.begin()));
-       
-       // The above is sort of what we want - unfortunately we can't guarantee no NDB/ILS at the moment
-       if(nav.empty()) return(NULL);
-       
-       for(nav_list_iterator it = nav.begin(); it != nav.end(); ++it) {
-               if((*it)->type() == FGPositioned::VOR) return(*it);
-       }
-       return(NULL);   // Shouldn't get here!
+FGNavRecord* DCLGPS::FindFirstVorById(const string& id, bool &multi, bool exact)
+{
+  return dynamic_cast<FGNavRecord*>(FindTypedFirstById(id, FGPositioned::VOR, multi, exact));
 }
 
-// TODO - add the ASCII / alphabetical stuff from the Atlas version
-FGNavRecord* DCLGPS::FindFirstNDBById(const string& id, bool &multi, bool exact) {
-       // NOTE - at the moment multi is never set.
-       multi = false;
-       //if(exact) return(_overlays->FindFirstVorById(id, exact));
-       
-       nav_list_type nav = globals->get_navlist()->findFirstByIdent(id, FG_NAV_NDB, exact);
-       
-       if(nav.size() > 1) multi = true;
-       //return(nav.empty() ? NULL : *(nav.begin()));
-       
-       // The above is sort of what we want - unfortunately we can't guarantee no NDB/ILS at the moment
-       if(nav.empty()) return(NULL);
-       
-       for(nav_list_iterator it = nav.begin(); it != nav.end(); ++it) {
-               if((*it)->type() == FGPositioned::NDB) return(*it);
-       }
-       return(NULL);   // Shouldn't get here!
+FGNavRecord* DCLGPS::FindFirstNDBById(const string& id, bool &multi, bool exact)
+{
+  return dynamic_cast<FGNavRecord*>(FindTypedFirstById(id, FGPositioned::NDB, multi, exact));
 }
 
-const FGFix* DCLGPS::FindFirstIntById(const string& id, bool &multi, bool exact) {
-       // NOTE - at the moment multi is never set, and indeed can't be
-       // since FG can only map one Fix per ID at the moment.
-       multi = false;
-       if (exact) return globals->get_fixlist()->search(id);
-       
-  stringOrderKLN89 ordering;
-  return globals->get_fixlist()->findFirstByIdent(id, &ordering);
+const FGFix* DCLGPS::FindFirstIntById(const string& id, bool &multi, bool exact)
+{
+  return dynamic_cast<FGFix*>(FindTypedFirstById(id, FGPositioned::FIX, multi, exact));
 }
 
-const FGAirport* DCLGPS::FindFirstAptById(const string& id, bool &multi, bool exact) {
-       // NOTE - at the moment multi is never set.
-       //cout << "FindFirstAptById, id = " << id << '\n';
-       multi = false;
-       if(exact) return(globals->get_airports()->search(id));
-       
-  stringOrderKLN89 ordering;
-  return globals->get_airports()->findFirstById(id, &ordering);
+const FGAirport* DCLGPS::FindFirstAptById(const string& id, bool &multi, bool exact)
+{
+  return dynamic_cast<FGAirport*>(FindTypedFirstById(id, FGPositioned::AIRPORT, multi, exact));
 }
 
-FGNavRecord* DCLGPS::FindClosestVor(double lat_rad, double lon_rad) {
-       return(globals->get_navlist()->findClosest(lon_rad, lat_rad, 0.0, FG_NAV_VOR));
+FGNavRecord* DCLGPS::FindClosestVor(double lat_rad, double lon_rad) {  
+  FGPositioned::TypeFilter filter(FGPositioned::VOR);
+  double cutoff = 1000; // nautical miles
+  FGPositionedRef v = FGPositioned::findClosest(SGGeod::fromRad(lon_rad, lat_rad), cutoff, &filter);
+  if (!v) {
+    return NULL;
+  }
+  
+  return dynamic_cast<FGNavRecord*>(v.ptr());
 }
 
 //----------------------------------------------------------------------------------------------------------