More search functions exposed to Nasal, also airport parking.
This commit is contained in:
parent
3d46809ea8
commit
fb66aeade1
7 changed files with 339 additions and 274 deletions
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -824,7 +824,6 @@ fgInitNav ()
|
|||
|
||||
fgAirportDBLoad( aptdb.str(), p_metar.str() );
|
||||
FGAirport::installPropertyListener();
|
||||
FGPositioned::installCommands();
|
||||
|
||||
FGNavList *navlist = new FGNavList;
|
||||
FGNavList *loclist = new FGNavList;
|
||||
|
|
|
@ -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) {}
|
||||
|
||||
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,
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue