diff --git a/src/Main/fg_commands.cxx b/src/Main/fg_commands.cxx index cf36a7777..60822e2d9 100644 --- a/src/Main/fg_commands.cxx +++ b/src/Main/fg_commands.cxx @@ -37,9 +37,6 @@ #include #include #include -#include -#include -#include #include #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(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 }; diff --git a/src/Main/fg_init.cxx b/src/Main/fg_init.cxx index 21f0624b5..134a34416 100644 --- a/src/Main/fg_init.cxx +++ b/src/Main/fg_init.cxx @@ -824,7 +824,6 @@ fgInitNav () fgAirportDBLoad( aptdb.str(), p_metar.str() ); FGAirport::installPropertyListener(); - FGPositioned::installCommands(); FGNavList *navlist = new FGNavList; FGNavList *loclist = new FGNavList; diff --git a/src/Navaids/navlist.cxx b/src/Navaids/navlist.cxx index 6bbf59fa3..ea2cf5c3c 100644 --- a/src/Navaids/navlist.cxx +++ b/src/Navaids/navlist.cxx @@ -25,6 +25,9 @@ # include #endif +#include +#include + #include #include #include @@ -33,12 +36,42 @@ #include -#include - 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, diff --git a/src/Navaids/navlist.hxx b/src/Navaids/navlist.hxx index 6b4b6365c..ef49e3e79 100644 --- a/src/Navaids/navlist.hxx +++ b/src/Navaids/navlist.hxx @@ -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; + }; }; diff --git a/src/Navaids/positioned.cxx b/src/Navaids/positioned.cxx index 7aa183eba..6193d7b2f 100644 --- a/src/Navaids/positioned.cxx +++ b/src/Navaids/positioned.cxx @@ -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 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; igetStringValue("results"); - if (resultPath.empty()) { - SG_LOG(SG_GENERAL, SG_WARN, "commandFindByIdent: no results path defined"); - return false; - } - - std::auto_ptr 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; iaddCommand("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::const_iterator it = types.begin(), end = types.end(); for (; it != end; ++it) { diff --git a/src/Navaids/positioned.hxx b/src/Navaids/positioned.hxx index 6d77d3420..1ed162523 100644 --- a/src/Navaids/positioned.hxx +++ b/src/Navaids/positioned.hxx @@ -156,9 +156,7 @@ public: private: std::vector 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); diff --git a/src/Scripting/NasalPositioned.cxx b/src/Scripting/NasalPositioned.cxx index 979ef06a8..78e1bc8d7 100644 --- a/src/Scripting/NasalPositioned.cxx +++ b/src/Scripting/NasalPositioned.cxx @@ -35,6 +35,8 @@ #include #include +#include +#include #include #include #include
@@ -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(, [, ]); 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 , 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; igetNrOfParkings(); ++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 , nil on error // navaids sorted by ascending distance // navinfo([,],[],[]) @@ -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);