]> git.mxchange.org Git - flightgear.git/commitdiff
More search functions exposed to Nasal, also airport parking.
authorJames Turner <zakalawe@mac.com>
Tue, 24 Apr 2012 21:12:56 +0000 (22:12 +0100)
committerJames Turner <zakalawe@mac.com>
Tue, 24 Apr 2012 21:12:56 +0000 (22:12 +0100)
src/Main/fg_commands.cxx
src/Main/fg_init.cxx
src/Navaids/navlist.cxx
src/Navaids/navlist.hxx
src/Navaids/positioned.cxx
src/Navaids/positioned.hxx
src/Scripting/NasalPositioned.cxx

index cf36a7777cecedc9bb7f6f5f5e94efc2844e015d..60822e2d9f3f12205d8f445d08a520cd43e0775d 100644 (file)
@@ -37,9 +37,6 @@
 #include <Scripting/NasalSys.hxx>
 #include <Sound/sample_queue.hxx>
 #include <Airports/xmlloader.hxx>
-#include <ATC/CommStation.hxx>
-#include <Navaids/navrecord.hxx>
-#include <Navaids/navlist.hxx>
 #include <Network/HTTPClient.hxx>
 
 #include "fg_init.hxx"
@@ -1495,63 +1492,6 @@ do_release_cockpit_button (const SGPropertyNode *arg)
 
   return true;
 }
-
-static SGGeod commandSearchPos(const SGPropertyNode* arg)
-{
-  if (arg->hasChild("longitude-deg") && arg->hasChild("latitude-deg")) {
-    return SGGeod::fromDeg(arg->getDoubleValue("longitude-deg"),
-                           arg->getDoubleValue("latitude-deg"));
-  }
-  
-  // use current viewer/aircraft position
-  return SGGeod::fromDeg(fgGetDouble("/position/longitude-deg"), 
-                         fgGetDouble("/position/latitude-deg"));
-}
-  
-static bool
-do_comm_search(const SGPropertyNode* arg)
-{
-  SGGeod pos = commandSearchPos(arg);
-  int khz = static_cast<int>(arg->getDoubleValue("frequency-mhz") * 100.0 + 0.25);
-  
-  flightgear::CommStation* sta = flightgear::CommStation::findByFreq(khz, pos, NULL);
-  if (!sta) {
-    return true;
-  }
-  
-  SGPropertyNode* result = fgGetNode(arg->getStringValue("result"));
-  sta->createBinding(result);
-  return true;
-}
-
-static bool
-do_nav_search(const SGPropertyNode* arg)
-{
-  SGGeod pos = commandSearchPos(arg);
-  double mhz = arg->getDoubleValue("frequency-mhz");
-
-  FGNavList* navList = globals->get_navlist();
-  string type(arg->getStringValue("type", "vor"));
-  if (type == "dme") {
-    navList = globals->get_dmelist();
-  } else if (type == "tacan") {
-    navList = globals->get_tacanlist();
-  }
-  
-  FGNavRecord* nav = navList->findByFreq(mhz, pos);
-  if (!nav && (type == "vor")) {
-    // if we're searching VORs, look for localizers too
-    nav = globals->get_loclist()->findByFreq(mhz, pos);
-  }
-  
-  if (!nav) {
-    return true;
-  }
-  
-  SGPropertyNode* result = fgGetNode(arg->getStringValue("result"));
-  nav->createBinding(result);
-  return true;
-}
   
 ////////////////////////////////////////////////////////////////////////
 // Command setup.
@@ -1627,10 +1567,7 @@ static struct {
     { "dump-terrainbranch", do_dump_terrain_branch },
     { "print-visible-scene", do_print_visible_scene_info },
     { "reload-shaders", do_reload_shaders },
-  
-    { "find-navaid", do_nav_search },
-    { "find-comm", do_comm_search },
-  
+
     { 0, 0 }                   // zero-terminated
 };
 
index 21f0624b5b89c7169925f128ab30c9d0b65d1ac4..134a34416c5164691d20879d7054c47d860c8b0c 100644 (file)
@@ -824,7 +824,6 @@ fgInitNav ()
 
     fgAirportDBLoad( aptdb.str(), p_metar.str() );
     FGAirport::installPropertyListener();
-    FGPositioned::installCommands();
     
     FGNavList *navlist = new FGNavList;
     FGNavList *loclist = new FGNavList;
index 6bbf59fa3c7f1475543d875b49391246f5a16b7b..ea2cf5c3ca829117fbb96205347cba3c22aaf3bd 100644 (file)
@@ -25,6 +25,9 @@
 #  include <config.h>
 #endif
 
+#include <boost/foreach.hpp>
+#include <algorithm>
+
 #include <simgear/debug/logstream.hxx>
 #include <simgear/math/sg_geodesy.hxx>
 #include <simgear/sg_inlines.h>
 
 #include <Airports/runways.hxx>
 
-#include <algorithm>
-
 using std::string;
 
+namespace { // anonymous
+
+class NavRecordDistanceSortPredicate
+{
+public:
+  NavRecordDistanceSortPredicate( const SGGeod & position ) :
+  _position(SGVec3d::fromGeod(position)) {}
+  
+  bool operator()( const nav_rec_ptr & n1, const nav_rec_ptr & n2 )
+  {
+    if( n1 == NULL || n2 == NULL ) return false;
+    return distSqr(n1->cart(), _position) < distSqr(n2->cart(), _position);
+  }
+private:
+  SGVec3d _position;
+  
+};
+
+} // of anonymous namespace
+
 // FGNavList ------------------------------------------------------------------
 
+
+FGNavList::TypeFilter::TypeFilter(const FGPositioned::Type type)
+{
+  if (type == FGPositioned::INVALID) {
+    _mintype = FGPositioned::VOR;
+    _maxtype = FGPositioned::GS;
+  } else {
+    _mintype = _maxtype = type;
+  }
+}
+
+
 FGNavList::FGNavList( void )
 {
 }
@@ -75,31 +108,29 @@ FGNavRecord *FGNavList::findByFreq( double freq, const SGGeod& position)
     return findNavFromList( position, stations );
 }
 
-class TypeFilter : public FGPositioned::Filter
+nav_list_type FGNavList::findAllByFreq( double freq, const SGGeod& position, const FGPositioned::Type type)
 {
-public:
-    TypeFilter( const FGPositioned::Type mintype, const FGPositioned::Type maxtype ) : _mintype(mintype), _maxtype(maxtype) {}
-
-  virtual FGPositioned::Type minType() const {
-    return _mintype;
+  nav_list_type stations;
+  TypeFilter filter(type);
+  
+  BOOST_FOREACH(nav_rec_ptr nav, navaids[(int)(freq*100.0 + 0.5)]) {
+    if (filter.pass(nav.ptr())) {
+      stations.push_back(nav);
+    }
   }
+  
+  NavRecordDistanceSortPredicate sortPredicate( position );
+  std::sort( stations.begin(), stations.end(), sortPredicate );
+  return stations;
+}
 
-  virtual FGPositioned::Type maxType()  const {
-    return _maxtype;
-  }
-private:
-    FGPositioned::Type _mintype;
-    FGPositioned::Type _maxtype;
-};
 
 // Given an Ident and optional freqency, return the first matching
 // station.
 const nav_list_type FGNavList::findByIdentAndFreq(const string& ident, const double freq, const FGPositioned::Type type )
 {
   FGPositionedRef cur;
-  TypeFilter filter( 
-      type == FGPositioned::INVALID ? FGPositioned::VOR : type,
-      type == FGPositioned::INVALID ? FGPositioned::NDB : type );
+  TypeFilter filter(type);
   nav_list_type reply;
 
   cur = FGPositioned::findNextWithPartialId(cur, ident, &filter);
@@ -117,22 +148,6 @@ const nav_list_type FGNavList::findByIdentAndFreq(const string& ident, const dou
   return reply;
 }
 
-class NavRecordDistanceSortPredicate
-{
-public:
-    NavRecordDistanceSortPredicate( const SGGeod & position ) :
-    _position(SGVec3d::fromGeod(position)) {}
-
-    bool operator()( const nav_rec_ptr & n1, const nav_rec_ptr & n2 )
-    {
-        if( n1 == NULL || n2 == NULL ) return false;
-        return distSqr(n1->cart(), _position) < distSqr(n2->cart(), _position);
-    }
-private:
-    SGVec3d _position;
-
-};
-
 // Given an Ident and optional freqency and type , 
 // return a list of matching stations sorted by distance to the given position
 const nav_list_type FGNavList::findByIdentAndFreq( const SGGeod & position,
index 6b4b6365c1342659530617ba7d56af36b04cc20b..ef49e3e79811d1b0c52961dcd8d87c50e5ef1745 100644 (file)
@@ -76,6 +76,9 @@ public:
       */
     FGNavRecord *findByFreq( double freq, const SGGeod& position);
 
+    nav_list_type findAllByFreq( double freq, const SGGeod& position, 
+                                const FGPositioned::Type type = FGPositioned::INVALID);
+  
     // Given an Ident and optional freqency and type , 
     // return a list of matching stations.
     const nav_list_type findByIdentAndFreq( const std::string& ident,
@@ -89,6 +92,23 @@ public:
 
     // given a frequency returns the first matching entry
     FGNavRecord *findStationByFreq( double frequency );
+  
+  class TypeFilter : public FGPositioned::Filter
+  {
+  public:
+    TypeFilter(const FGPositioned::Type type);
+    
+    virtual FGPositioned::Type minType() const {
+      return _mintype;
+    }
+    
+    virtual FGPositioned::Type maxType()  const {
+      return _maxtype;
+    }
+  private:
+    FGPositioned::Type _mintype;
+    FGPositioned::Type _maxtype;
+  };
 };
 
 
index 7aa183eba02be4a831f782f39b433c4871b210fc..6193d7b2fcdd06cbd76e5afc7a9317b39e39ef98 100644 (file)
@@ -629,6 +629,9 @@ FGPositioned::Type FGPositioned::typeFromName(const std::string& aName)
   const NameTypeEntry names[] = {
     {"airport", AIRPORT},
     {"vor", VOR},
+    {"loc", LOC},
+    {"ils", ILS},
+    {"gs", GS},
     {"ndb", NDB},
     {"wpt", WAYPOINT},
     {"fix", FIX},
@@ -839,138 +842,28 @@ FGPositioned::sortByRange(List& aResult, const SGGeod& aPos)
   }
 }
 
-FGPositioned::Filter* createSearchFilter(const SGPropertyNode* arg)
-{
-    string sty(arg->getStringValue("type", "any"));
-    FGPositioned::Type ty = FGPositioned::typeFromName(sty);
-    double minRunwayLenFt = arg->getDoubleValue("min-runway-length-ft", -1.0);
-    
-    if ((ty == FGPositioned::AIRPORT) && (minRunwayLenFt > 0.0)) {
-        return new FGAirport::HardSurfaceFilter(minRunwayLenFt);
-    } else if (ty != FGPositioned::INVALID) {
-        FGPositioned::TypeFilter* tf = new FGPositioned::TypeFilter(ty);
-        
-        for (int t=1; arg->hasChild("type", t); ++t) {
-            sty = arg->getChild("type", t)->getStringValue();
-            tf->addType(FGPositioned::typeFromName(sty));
-        }
-        
-        return tf;
-    }
-    
-    return NULL;
-}
-
-static SGGeod commandSearchPos(const SGPropertyNode* arg)
-{
-    if (arg->hasChild("longitude-deg") && arg->hasChild("latitude-deg")) {
-        return SGGeod::fromDeg(arg->getDoubleValue("longitude-deg"),
-            arg->getDoubleValue("latitude-deg"));
-    }
-    
-    // use current viewer/aircraft position
-    return SGGeod::fromDeg(fgGetDouble("/position/longitude-deg"), 
-            fgGetDouble("/position/latitude-deg"));
-}
-
-void commandClearExisting(const SGPropertyNode* arg)
-{
-    if (arg->getBoolValue("clear", true)) {
-    // delete all existing result children from their parent
-        string resultPath = arg->getStringValue("results");
-        SGPropertyNode* n = fgGetNode(resultPath.c_str(), 0, true);
-        SGPropertyNode* pr = n->getParent();
-        pr->removeChildren(n->getName(), false /* keep=false, i.e delete nodes */);
-    }
-}
-
-bool commandFindClosest(const SGPropertyNode* arg)
-{
-    int n = arg->getIntValue("max-results", 1);
-    if ((n < 1) || (n > 100)) {
-        SG_LOG(SG_GENERAL, SG_WARN, "commandFindClosest: max-results invalid:" << n);
-        return false;
-    }
-    
-    string resultPath = arg->getStringValue("results");
-    if (resultPath.empty()) {
-        SG_LOG(SG_GENERAL, SG_WARN, "commandFindClosest: no results path defined");
-        return false;
-    }
-
-    std::auto_ptr<FGPositioned::Filter> filt(createSearchFilter(arg));    
-// cap search range, since huge ranges will overload everything
-    double cutoff = arg->getDoubleValue("cutoff-nm", 400.0);
-    SG_CLAMP_RANGE(cutoff, 0.0, 1000.0);
-    
-    SGGeod pos = commandSearchPos(arg);
-    commandClearExisting(arg);
-    
-    FGPositioned::List results = FGPositioned::findClosestN(pos, n, cutoff, filt.get());
-    for (unsigned int i=0; i<results.size(); ++i) {
-       SGPropertyNode* resultsNode = fgGetNode(resultPath.c_str(), i, true);
-       flightgear::PositionedBinding::bind(results[i], resultsNode);
-    }
-    
-    return true;
-}
-
-bool commandFindByIdent(const SGPropertyNode* arg)
-{
-    string resultPath = arg->getStringValue("results");
-    if (resultPath.empty()) {
-        SG_LOG(SG_GENERAL, SG_WARN, "commandFindByIdent: no results path defined");
-        return false;
-    }
-    
-    std::auto_ptr<FGPositioned::Filter> filt(createSearchFilter(arg));    
-    SGGeod pos = commandSearchPos(arg);
-    commandClearExisting(arg);
-    
-    FGPositioned::List results;
-    bool exact = arg->getBoolValue("exact", true);
-    if (arg->hasChild("name")) {
-        results = FGPositioned::findAllWithName(arg->getStringValue("name"), filt.get(), exact);
-    } else if (arg->hasChild("ident")) {
-        results = FGPositioned::findAllWithIdent(arg->getStringValue("ident"), filt.get(), exact);
-    } else {
-        SG_LOG(SG_GENERAL, SG_WARN, "commandFindByIdent: no search term defined");
-        return false;
-    }
-    
-    bool orderByRange = arg->getBoolValue("order-by-distance", true);
-    if (orderByRange) {
-        FGPositioned::sortByRange(results, pos);
-    }
-      
-    for (unsigned int i=0; i<results.size(); ++i) {
-       SGPropertyNode* resultsNode = fgGetNode(resultPath.c_str(), i, true);
-       flightgear::PositionedBinding::bind(results[i], resultsNode);
-    }
-      
-    return true;
-}
-
-void
-FGPositioned::installCommands()
-{
-    SGCommandMgr::instance()->addCommand("find-nearest", commandFindClosest);
-    SGCommandMgr::instance()->addCommand("find-by-ident", commandFindByIdent);
-}
-
 FGPositioned::TypeFilter::TypeFilter(Type aTy)
 {
-    types.push_back(aTy);
+  addType(aTy);
 }
 
 void FGPositioned::TypeFilter::addType(Type aTy)
 {
-    types.push_back(aTy);
+  if (aTy == INVALID) {
+    return;
+    
+  }
+  
+  types.push_back(aTy);
 }
 
 bool
 FGPositioned::TypeFilter::pass(FGPositioned* aPos) const
 {
+  if (types.empty()) {
+    return true;
+  }
+  
     std::vector<Type>::const_iterator it = types.begin(),
         end = types.end();
     for (; it != end; ++it) {
index 6d77d34208bfa2c4d9f0b6fa63f6608fb690e533..1ed162523847522dcedf71dc9444f8e7e85fa1df 100644 (file)
@@ -156,9 +156,7 @@ public:
   private:
       std::vector<Type> types;
   };
-  
-  static void installCommands();
-  
+    
   static List findWithinRange(const SGGeod& aPos, double aRangeNm, Filter* aFilter = NULL);
         
   static FGPositionedRef findClosestWithIdent(const std::string& aIdent, const SGGeod& aPos, Filter* aFilter = NULL);
index 979ef06a8dcaa57a379dddc493a0946373448c48..78e1bc8d7316dd126cd09be4a9ea6497d2981a59 100644 (file)
@@ -35,6 +35,8 @@
 
 #include <Airports/runways.hxx>
 #include <Airports/simple.hxx>
+#include <Airports/dynamics.hxx>
+#include <Airports/parking.hxx>
 #include <Navaids/navlist.hxx>
 #include <Navaids/procedure.hxx>
 #include <Main/globals.hxx>
@@ -275,6 +277,26 @@ bool geodFromHash(naRef ref, SGGeod& result)
   return false;
 }
 
+static int geodFromArgs(naRef* args, int offset, int argc, SGGeod& result)
+{
+  if (offset >= argc) {
+    return 0;
+  }
+  
+  if (geodFromHash(args[offset], result)) {
+    return 1;
+  }
+  
+  if (((argc - offset) >= 2) && naIsNum(args[offset]) && naIsNum(args[offset + 1])) {
+    double lat = naNumValue(args[0]).num,
+    lon = naNumValue(args[1]).num;
+    result = SGGeod::fromDeg(lon, lat);
+    return 2;
+  }
+  
+  return 0;
+}
+
 // Convert a cartesian point to a geodetic lat/lon/altitude.
 static naRef f_carttogeod(naContext c, naRef me, int argc, naRef* args)
 {
@@ -353,6 +375,18 @@ public:
   AirportInfoFilter() : type(FGPositioned::AIRPORT) {
   }
   
+  bool fromArg(naRef arg)
+  {
+    const char *s = naStr_data(arg);
+    if(!strcmp(s, "airport")) type = FGPositioned::AIRPORT;
+    else if(!strcmp(s, "seaport")) type = FGPositioned::SEAPORT;
+    else if(!strcmp(s, "heliport")) type = FGPositioned::HELIPORT;
+    else
+      return false;
+    
+    return true;
+  }
+  
   virtual FGPositioned::Type minType() const {
     return type;
   }
@@ -373,15 +407,13 @@ public:
 // airportinfo(<lat>, <lon> [, <type>]);
 static naRef f_airportinfo(naContext c, naRef me, int argc, naRef* args)
 {
-  SGGeod pos;
+  SGGeod pos = globals->get_aircraft_position();
   FGAirport* apt = NULL;
   
   if(argc >= 2 && naIsNum(args[0]) && naIsNum(args[1])) {
     pos = SGGeod::fromDeg(args[1].num, args[0].num);
     args += 2;
     argc -= 2;
-  } else {
-    pos = globals->get_aircraft_position();
   }
   
   double maxRange = 10000.0; // expose this? or pick a smaller value?
@@ -391,13 +423,11 @@ static naRef f_airportinfo(naContext c, naRef me, int argc, naRef* args)
   if(argc == 0) {
     // fall through and use AIRPORT
   } else if(argc == 1 && naIsString(args[0])) {
-    const char *s = naStr_data(args[0]);
-    if(!strcmp(s, "airport")) filter.type = FGPositioned::AIRPORT;
-    else if(!strcmp(s, "seaport")) filter.type = FGPositioned::SEAPORT;
-    else if(!strcmp(s, "heliport")) filter.type = FGPositioned::HELIPORT;
-    else {
+    if (filter.fromArg(args[0])) {
+      // done!
+    } else {
       // user provided an <id>, hopefully
-      apt = FGAirport::findByIdent(s);
+      apt = FGAirport::findByIdent(naStr_data(args[0]));
       if (!apt) {
         // return nil here, but don't raise a runtime error; this is a
         // legitamate way to validate an ICAO code, for example in a
@@ -418,6 +448,60 @@ static naRef f_airportinfo(naContext c, naRef me, int argc, naRef* args)
   return hashForAirport(c, apt);
 }
 
+static naRef f_findAirportsWithinRange(naContext c, naRef me, int argc, naRef* args)
+{
+  int argOffset = 0;
+  SGGeod pos = globals->get_aircraft_position();
+  argOffset += geodFromArgs(args, 0, argc, pos);
+  
+  if (!naIsNum(args[argOffset])) {
+    naRuntimeError(c, "findAirportsWithinRange expected range (in nm) as arg %d", argOffset);
+  }
+  
+  AirportInfoFilter filter; // defaults to airports only
+  double rangeNm = args[argOffset++].num;
+  if (argOffset < argc) {
+    filter.fromArg(args[argOffset++]);
+  }
+  
+  naRef r = naNewVector(c);
+  
+  FGPositioned::List apts = FGPositioned::findWithinRange(pos, rangeNm, &filter);
+  FGPositioned::sortByRange(apts, pos);
+  
+  BOOST_FOREACH(FGPositionedRef a, apts) {
+    FGAirport* apt = (FGAirport*) a.get();
+    naVec_append(r, hashForAirport(c, apt));
+  }
+  
+  return r;
+}
+
+static naRef f_findAirportsByICAO(naContext c, naRef me, int argc, naRef* args)
+{
+  if (!naIsString(args[0])) {
+    naRuntimeError(c, "findAirportsByICAO expects string as arg 0");
+  }
+  
+  int argOffset = 0;
+  string prefix(naStr_data(args[argOffset++]));
+  AirportInfoFilter filter; // defaults to airports only
+  if (argOffset < argc) {
+    filter.fromArg(args[argOffset++]);
+  }
+  
+  naRef r = naNewVector(c);
+  
+  FGPositioned::List apts = FGPositioned::findAllWithIdent(prefix, &filter, false);
+  
+  BOOST_FOREACH(FGPositionedRef a, apts) {
+    FGAirport* apt = (FGAirport*) a.get();
+    naVec_append(r, hashForAirport(c, apt));
+  }
+  
+  return r;
+}
+
 static FGAirport* airportFromMe(naRef me)
 {  
     naRef ghost = naHash_cget(me, (char*) "_positioned");
@@ -540,6 +624,44 @@ static naRef f_airport_stars(naContext c, naRef me, int argc, naRef* args)
   return stars;
 }
 
+static naRef f_airport_parking(naContext c, naRef me, int argc, naRef* args)
+{
+  FGAirport* apt = airportFromMe(me);
+  if (!apt) {
+    naRuntimeError(c, "airport.parking called on non-airport object");
+  }
+  
+  naRef r = naNewVector(c);
+  std::string type;
+  bool onlyAvailable = false;
+  
+  if (argc > 0 && naIsString(args[0])) {
+    type = naStr_data(args[0]);
+  }
+  
+  if ((argc > 1) && naIsNum(args[1])) {
+    onlyAvailable = (args[1].num != 0.0);
+  }
+  
+  FGAirportDynamics* dynamics = apt->getDynamics();
+  for (int i=0; i<dynamics->getNrOfParkings(); ++i) {
+    FGParking* park = dynamics->getParking(i);
+  // filter out based on availability and type
+    if (onlyAvailable && !park->isAvailable()) {
+      continue;
+    }
+    
+    if (!type.empty() && (park->getType() != type)) {
+      continue;
+    }
+    
+    naRef nm = stringToNasal(c, park->getName());
+    naVec_append(r, nm);
+  }
+  
+  return r;
+}
+
 // Returns vector of data hash for navaid of a <type>, nil on error
 // navaids sorted by ascending distance 
 // navinfo([<lat>,<lon>],[<type>],[<id>])
@@ -606,18 +728,120 @@ static naRef f_navinfo(naContext c, naRef me, int argc, naRef* args)
   return reply;
 }
 
+static naRef f_findNavaidsWithinRange(naContext c, naRef me, int argc, naRef* args)
+{
+  int argOffset = 0;
+  SGGeod pos = globals->get_aircraft_position();
+  argOffset += geodFromArgs(args, 0, argc, pos);
+  
+  if (!naIsNum(args[argOffset])) {
+    naRuntimeError(c, "findNavaidsWithinRange expected range (in nm) as arg %d", argOffset);
+  }
+  
+  FGPositioned::Type type = FGPositioned::INVALID;
+  double rangeNm = args[argOffset++].num;
+  if (argOffset < argc) {
+    type = FGPositioned::typeFromName(naStr_data(args[argOffset]));
+  }
+  
+  naRef r = naNewVector(c);
+  FGNavList::TypeFilter filter(type);
+  FGPositioned::List navs = FGPositioned::findWithinRange(pos, rangeNm, &filter);
+  FGPositioned::sortByRange(navs, pos);
+  
+  BOOST_FOREACH(FGPositionedRef a, navs) {
+    FGNavRecord* nav = (FGNavRecord*) a.get();
+    naVec_append(r, hashForNavRecord(c, nav, pos));
+  }
+  
+  return r;
+}
+
+static naRef f_findNavaidByFrequency(naContext c, naRef me, int argc, naRef* args)
+{
+  int argOffset = 0;
+  SGGeod pos = globals->get_aircraft_position();
+  argOffset += geodFromArgs(args, 0, argc, pos);
+  
+  if (!naIsNum(args[argOffset])) {
+    naRuntimeError(c, "findNavaidByFrequency expectes frequency (in Mhz) as arg %d", argOffset);
+  }
+  
+  FGPositioned::Type type = FGPositioned::INVALID;
+  double freqMhz = args[argOffset++].num;
+  if (argOffset < argc) {
+    type = FGPositioned::typeFromName(naStr_data(args[argOffset]));
+  }
+  
+  nav_list_type navs = globals->get_navlist()->findAllByFreq(freqMhz, pos, type);
+  if (navs.empty()) {
+    return naNil();
+  }
+  
+  return hashForNavRecord(c, navs.front().ptr(), pos);
+}
+
+static naRef f_findNavaidsByFrequency(naContext c, naRef me, int argc, naRef* args)
+{
+  int argOffset = 0;
+  SGGeod pos = globals->get_aircraft_position();
+  argOffset += geodFromArgs(args, 0, argc, pos);
+  
+  if (!naIsNum(args[argOffset])) {
+    naRuntimeError(c, "findNavaidsByFrequency expectes frequency (in Mhz) as arg %d", argOffset);
+  }
+  
+  FGPositioned::Type type = FGPositioned::INVALID;
+  double freqMhz = args[argOffset++].num;
+  if (argOffset < argc) {
+    type = FGPositioned::typeFromName(naStr_data(args[argOffset]));
+  }
+  
+  naRef r = naNewVector(c);
+  nav_list_type navs = globals->get_navlist()->findAllByFreq(freqMhz, pos, type);
+  
+  BOOST_FOREACH(nav_rec_ptr a, navs) {
+    naVec_append(r, hashForNavRecord(c, a.ptr(), pos));
+  }
+  
+  return r;
+}
+
+static naRef f_findNavaidsByIdent(naContext c, naRef me, int argc, naRef* args)
+{
+  int argOffset = 0;
+  SGGeod pos = globals->get_aircraft_position();
+  argOffset += geodFromArgs(args, 0, argc, pos);
+  
+  if (!naIsString(args[argOffset])) {
+    naRuntimeError(c, "findNavaidsByIdent expectes ident string as arg %d", argOffset);
+  }
+  
+  FGPositioned::Type type = FGPositioned::INVALID;
+  string ident = naStr_data(args[argOffset++]);
+  if (argOffset < argc) {
+    type = FGPositioned::typeFromName(naStr_data(args[argOffset]));
+  }
+  
+  naRef r = naNewVector(c);
+  nav_list_type navs = globals->get_navlist()->findByIdentAndFreq(pos, ident, 0.0, type);
+  
+  BOOST_FOREACH(nav_rec_ptr a, navs) {
+    naVec_append(r, hashForNavRecord(c, a.ptr(), pos));
+  }
+  
+  return r;
+}
+
+
 // Convert a cartesian point to a geodetic lat/lon/altitude.
 static naRef f_magvar(naContext c, naRef me, int argc, naRef* args)
 {
   SGGeod pos = globals->get_aircraft_position();
   if (argc == 0) {
     // fine, use aircraft position
-  } else if ((argc == 1) && geodFromHash(args[0], pos)) {
+  } else if (geodFromArgs(args, 0, argc, pos)) {
     // okay
-  } else if ((argc == 2) && naIsNum(args[0]) && naIsNum(args[1])) {
-    double lat = naNumValue(args[0]).num,
-      lon = naNumValue(args[1]).num;
-    pos = SGGeod::fromDeg(lon, lat);
   } else {
     naRuntimeError(c, "magvar() expects no arguments, a positioned hash or lat,lon pair");
   }
@@ -629,32 +853,15 @@ static naRef f_magvar(naContext c, naRef me, int argc, naRef* args)
 
 static naRef f_courseAndDistance(naContext c, naRef me, int argc, naRef* args)
 {
-    SGGeod from = globals->get_aircraft_position(), to;
-    if ((argc == 1) && geodFromHash(args[0], to)) {
-        // done
-    } else if ((argc == 2) && naIsNum(args[0]) && naIsNum(args[1])) {
-        // two number arguments, from = current pos, to = lat+lon
-        double lat = naNumValue(args[0]).num,
-            lon = naNumValue(args[1]).num;
-        to = SGGeod::fromDeg(lon, lat);
-    } else if ((argc == 2) && geodFromHash(args[0], from) && geodFromHash(args[1], to)) {
-        // done
-    } else if ((argc == 3) && geodFromHash(args[0], from) && naIsNum(args[1]) && naIsNum(args[2])) {
-        double lat = naNumValue(args[1]).num,
-            lon = naNumValue(args[2]).num;
-        to = SGGeod::fromDeg(lon, lat);
-    } else if ((argc == 3) && naIsNum(args[0]) && naIsNum(args[1]) && geodFromHash(args[2], to)) {
-        double lat = naNumValue(args[0]).num,
-            lon = naNumValue(args[1]).num;
-        from = SGGeod::fromDeg(lon, lat);
-    } else if (argc == 4) {
-        if (!naIsNum(args[0]) || !naIsNum(args[1]) || !naIsNum(args[2]) || !naIsNum(args[3])) {
-            naRuntimeError(c, "invalid arguments to courseAndDistance - expected four numbers");
-        }
-        
-        from = SGGeod::fromDeg(naNumValue(args[1]).num, naNumValue(args[0]).num);
-        to = SGGeod::fromDeg(naNumValue(args[3]).num, naNumValue(args[2]).num);
+    SGGeod from = globals->get_aircraft_position(), to, p;
+    int argOffset = geodFromArgs(args, 0, argc, p);
+    if (geodFromArgs(args, argOffset, argc, to)) {
+      from = p; // we parsed both FROM and TO args, so first was from
     } else {
+      to = p; // only parsed one arg, so FROM is current
+    }
+  
+    if (argOffset == 0) {
         naRuntimeError(c, "invalid arguments to courseAndDistance");
     }
     
@@ -670,18 +877,7 @@ static naRef f_courseAndDistance(naContext c, naRef me, int argc, naRef* args)
 static naRef f_tilePath(naContext c, naRef me, int argc, naRef* args)
 {
     SGGeod pos = globals->get_aircraft_position();
-    if (argc == 0) {
-        // fine, use aircraft position
-    } else if ((argc == 1) && geodFromHash(args[0], pos)) {
-        // okay
-    } else if ((argc == 2) && naIsNum(args[0]) && naIsNum(args[1])) {
-        double lat = naNumValue(args[0]).num,
-        lon = naNumValue(args[1]).num;
-        pos = SGGeod::fromDeg(lon, lat);
-    } else {
-        naRuntimeError(c, "bucketPath() expects no arguments, a positioned hash or lat,lon pair");
-    }
-    
+    geodFromArgs(args, 0, argc, pos);
     SGBucket b(pos);
     return stringToNasal(c, b.gen_base_path());
 }
@@ -819,7 +1015,13 @@ static struct { const char* name; naCFunction func; } funcs[] = {
   { "geodtocart", f_geodtocart },
   { "geodinfo", f_geodinfo },
   { "airportinfo", f_airportinfo },
+  { "findAirportsWithinRange", f_findAirportsWithinRange },
+  { "findAirportsByICAO", f_findAirportsByICAO },
   { "navinfo", f_navinfo },
+  { "findNavaidsWithinRange", f_findNavaidsWithinRange },
+  { "findNavaidByFrequency", f_findNavaidByFrequency },
+  { "findNavaidsByFrequency", f_findNavaidsByFrequency },
+  { "findNavaidsByID", f_findNavaidsByIdent },
   { "route", f_route },
   { "magvar", f_magvar },
   { "courseAndDistance", f_courseAndDistance },
@@ -837,6 +1039,7 @@ naRef initNasalPositioned(naRef globals, naContext c, naRef gcSave)
     hashset(c, airportPrototype, "comms", naNewFunc(c, naNewCCode(c, f_airport_comms)));
     hashset(c, airportPrototype, "sids", naNewFunc(c, naNewCCode(c, f_airport_sids)));
     hashset(c, airportPrototype, "stars", naNewFunc(c, naNewCCode(c, f_airport_stars)));
+    hashset(c, airportPrototype, "parking", naNewFunc(c, naNewCCode(c, f_airport_parking)));
   
     routePrototype = naNewHash(c);
     hashset(c, gcSave, "routeProto", routePrototype);