1
0
Fork 0

More search functions exposed to Nasal, also airport parking.

This commit is contained in:
James Turner 2012-04-24 22:12:56 +01:00
parent 3d46809ea8
commit fb66aeade1
7 changed files with 339 additions and 274 deletions

View 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"
@ -1496,63 +1493,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.
////////////////////////////////////////////////////////////////////////
@ -1628,9 +1568,6 @@ static struct {
{ "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
};

View file

@ -824,7 +824,6 @@ fgInitNav ()
fgAirportDBLoad( aptdb.str(), p_metar.str() );
FGAirport::installPropertyListener();
FGPositioned::installCommands();
FGNavList *navlist = new FGNavList;
FGNavList *loclist = new FGNavList;

View 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>
@ -33,12 +36,42 @@
#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) {}
nav_list_type stations;
TypeFilter filter(type);
virtual FGPositioned::Type minType() const {
return _mintype;
BOOST_FOREACH(nav_rec_ptr nav, navaids[(int)(freq*100.0 + 0.5)]) {
if (filter.pass(nav.ptr())) {
stations.push_back(nav);
}
}
virtual FGPositioned::Type maxType() const {
return _maxtype;
}
private:
FGPositioned::Type _mintype;
FGPositioned::Type _maxtype;
};
NavRecordDistanceSortPredicate sortPredicate( position );
std::sort( stations.begin(), stations.end(), sortPredicate );
return stations;
}
// 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,

View 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;
};
};

View 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)
{
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) {

View file

@ -157,8 +157,6 @@ public:
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);

View 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");
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
}
from = SGGeod::fromDeg(naNumValue(args[1]).num, naNumValue(args[0]).num);
to = SGGeod::fromDeg(naNumValue(args[3]).num, naNumValue(args[2]).num);
} else {
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);