From 5affa1334856c4b20718a823bf9865e6b4eb30e8 Mon Sep 17 00:00:00 2001 From: James Turner <zakalawe@mac.com> Date: Wed, 9 Jan 2019 00:02:46 +0000 Subject: [PATCH] Nasal: expose airways data and via options --- src/Scripting/NasalPositioned.cxx | 223 ++++++++++++++++++++++++++++-- 1 file changed, 215 insertions(+), 8 deletions(-) diff --git a/src/Scripting/NasalPositioned.cxx b/src/Scripting/NasalPositioned.cxx index e4227950f..ef4a94b96 100644 --- a/src/Scripting/NasalPositioned.cxx +++ b/src/Scripting/NasalPositioned.cxx @@ -18,9 +18,7 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif +#include "config.h" #include <cstring> @@ -111,6 +109,12 @@ static naGhostType ProcedureGhostType = { routeBaseGhostDestroy, procedureGhostGetMember, 0}; +static const char* airwayGhostGetMember(naContext c, void* g, naRef field, naRef* out); +static naGhostType AirwayGhostType = { routeBaseGhostDestroy, + "airway", + airwayGhostGetMember, + 0}; + static void hashset(naContext c, naRef hash, const char* key, naRef val) { naRef s = naNewString(c); @@ -260,6 +264,13 @@ static FlightPlan* flightplanGhost(naRef r) return 0; } +static Airway* airwayGhost(naRef r) +{ + if (naGhost_type(r) == &AirwayGhostType) + return (Airway*) naGhost_ptr(r); + return 0; +} + static void routeBaseGhostDestroy(void* g) { RouteBase* r = (RouteBase*) g; @@ -272,6 +283,7 @@ static naRef flightplanPrototype; static naRef geoCoordClass; static naRef fpLegPrototype; static naRef procedurePrototype; +static naRef airwayPrototype; naRef ghostForAirport(naContext c, const FGAirport* apt) { @@ -373,6 +385,17 @@ naRef ghostForProcedure(naContext c, const Procedure* proc) return naNewGhost2(c, &ProcedureGhostType, (void*) proc); } +naRef ghostForAirway(naContext c, const Airway* awy) +{ + if (!awy) { + return naNil(); + } + + Airway::get(awy); // take a ref + return naNewGhost2(c, &AirwayGhostType, (void*) awy); +} + + static const char* airportGhostGetMember(naContext c, void* g, naRef field, naRef* out) { const char* fieldName = naStr_data(field); @@ -432,6 +455,9 @@ static const char* airportGhostGetMember(naContext c, void* g, naRef field, naRe static naRef waypointNavaid(naContext c, Waypt* wpt) { FGPositioned* pos = wpt->source(); + if (pos && pos->type() == FGPositioned::FIX) { + return ghostForFix(c, fgpositioned_cast<FGFix>(pos)); + } if (!FGPositioned::isNavaidType(pos)) { return naNil(); @@ -476,10 +502,28 @@ static const char* waypointCommonGetMember(naContext c, Waypt* wpt, const char* else if (!strcmp(fieldName, "wp_lon") || !strcmp(fieldName, "lon")) *out = naNum(wpt->position().getLongitudeDeg()); else if (!strcmp(fieldName, "wp_parent_name")) { Procedure* proc = dynamic_cast<Procedure*>(wpt->owner()); - *out = proc ? stringToNasal(c, proc->ident()) : naNil(); + if (proc) { + *out = stringToNasal(c, proc->ident()); + } else { + Airway* airway = dynamic_cast<Airway*>(wpt->owner()); + if (airway) { + *out = stringToNasal(c, airway->ident()); + } else { + *out = naNil(); + } + } } else if (!strcmp(fieldName, "wp_parent")) { Procedure* proc = dynamic_cast<Procedure*>(wpt->owner()); - *out = ghostForProcedure(c, proc); + if (proc) { + *out = ghostForProcedure(c, proc); + } else { + Airway* airway = dynamic_cast<Airway*>(wpt->owner()); + if (airway) { + *out = ghostForAirway(c, airway); + } else { + *out = naNil(); + } + } } else if (!strcmp(fieldName, "fly_type")) { if (wpt->type() == "hold") { *out = stringToNasal(c, "Hold"); @@ -494,6 +538,14 @@ static const char* waypointCommonGetMember(naContext c, Waypt* wpt, const char* *out = waypointAirport(c, wpt); } else if (!strcmp(fieldName, "runway")) { *out = waypointRunway(c, wpt); + } else if (!strcmp(fieldName, "airway")) { + if (wpt->type() == "via") { + AirwayRef awy = static_cast<Via*>(wpt)->airway(); + assert(awy); + *out = ghostForAirway(c, awy); + } else { + *out = naNil(); + } } else if (wpt->type() == "hold") { // hold-specific properties const auto hold = static_cast<Hold*>(wpt); @@ -941,6 +993,30 @@ static const char* procedureGhostGetMember(naContext c, void* g, naRef field, na return ""; } +static const char* airwayGhostGetMember(naContext c, void* g, naRef field, naRef* out) +{ + const char* fieldName = naStr_data(field); + Airway* awy = (Airway*) g; + + if (!strcmp(fieldName, "parents")) { + *out = naNewVector(c); + naVec_append(*out, airwayPrototype); + } else if (!strcmp(fieldName, "id")) *out = stringToNasal(c, awy->ident()); + else if (!strcmp(fieldName, "level")) { + const auto level = awy->level(); + switch (level) { + case Airway::HighLevel: *out = stringToNasal(c, "high"); break; + case Airway::LowLevel: *out = stringToNasal(c, "low"); break; + case Airway::Both: *out = stringToNasal(c, "both"); break; + default: *out = naNil(); + } + } else { + return 0; + } + + return ""; +} + static const char* runwayGhostGetMember(naContext c, void* g, naRef field, naRef* out) { const char* fieldName = naStr_data(field); @@ -1114,6 +1190,11 @@ static int geodFromArgs(naRef* args, int offset, int argc, SGGeod& result) result = wayptGhost(args[offset])->position(); return 1; } + + if (gt == &FPLegGhostType) { + result = fpLegGhost(args[offset])->waypoint()->position(); + return 1; + } } if (geodFromHash(args[offset], result)) { @@ -2350,6 +2431,64 @@ static naRef f_airwaySearch(naContext c, naRef me, int argc, naRef* args) return convertWayptVecToNasal(c, route); } +static FGPositionedRef positionedFromArg(naRef ref) +{ + if (!naIsGhost(ref)) + return {}; + + naGhostType* gt = naGhost_type(ref); + if (gt == &AirportGhostType) + return airportGhost(ref); + + if (gt == &NavaidGhostType) + return navaidGhost(ref); + + if (gt == &RunwayGhostType) + return runwayGhost(ref); + + if (gt == &TaxiwayGhostType) + return taxiwayGhost(ref); + + if (gt == &FixGhostType) + return fixGhost(ref); + + if ((gt == &WayptGhostType) || (gt == &FPLegGhostType)) + return wayptGhost(ref)->source(); + + return {}; +} + +static naRef f_findAirway(naContext c, naRef me, int argc, naRef* args) +{ + if ((argc < 1) || !naIsString(args[0])) { + naRuntimeError(c, "findAirway needs at least one string arguments"); + } + + std::string ident = naStr_data(args[0]); + FGPositionedRef pos; + Airway::Level level = Airway::Both; + if (argc >= 2) { + pos = positionedFromArg(args[1]); + if (naIsString(args[1])) { + // level spec, + } + } + + AirwayRef awy; + if (pos) { + SG_LOG(SG_NASAL, SG_INFO, "Pevious navaid for airway():" << pos->ident()); + awy = Airway::findByIdentAndNavaid(ident, pos); + } else { + awy = Airway::findByIdent(ident, level); + } + + if (!awy) + return naNil(); + + return ghostForAirway(c, awy.get()); +} + + static naRef f_createWP(naContext c, naRef me, int argc, naRef* args) { SGGeod pos; @@ -2412,9 +2551,10 @@ static naRef f_createViaTo(naContext c, naRef me, int argc, naRef* args) } std::string airwayName = naStr_data(args[0]); - Airway* airway = Airway::findByIdent(airwayName, Airway::UnknownLevel); + AirwayRef airway = Airway::findByIdent(airwayName, Airway::Both); if (!airway) { - naRuntimeError(c, "createViaTo: couldn't find airway with provided name"); + naRuntimeError(c, "createViaTo: couldn't find airway with provided name: %s", + naStr_data(args[0])); } FGPositionedRef nav; @@ -2437,7 +2577,50 @@ static naRef f_createViaTo(naContext c, naRef me, int argc, naRef* args) naRuntimeError(c, "createViaTo: navaid not on airway"); } - Via* via = new Via(NULL, airwayName, nav); + Via* via = new Via(nullptr, airway, nav); + return ghostForWaypt(c, via); +} + +static naRef f_createViaFromTo(naContext c, naRef me, int argc, naRef* args) +{ + if (argc != 3) { + naRuntimeError(c, "createViaFromTo: needs exactly three arguments"); + } + + auto from = positionedFromArg(args[0]); + if (!from) { + naRuntimeError(c, "createViaFromTo: from wp not found"); + } + + std::string airwayName = naStr_data(args[1]); + AirwayRef airway = Airway::findByIdentAndNavaid(airwayName, from); + if (!airway) { + naRuntimeError(c, "createViaFromTo: couldn't find airway with provided name: %s from wp %s", + naStr_data(args[0]), + from->ident().c_str()); + } + + FGPositionedRef nav; + if (naIsString(args[2])) { + WayptRef enroute = airway->findEnroute(naStr_data(args[2])); + if (!enroute) { + naRuntimeError(c, "unknown waypoint on airway %s: %s", + naStr_data(args[1]), naStr_data(args[2])); + } + + nav = enroute->source(); + } else { + nav = positionedFromArg(args[2]); + if (!nav) { + naRuntimeError(c, "createViaFromTo: arg[2] is not a navaid"); + } + } + + if (!airway->containsNavaid(nav)) { + naRuntimeError(c, "createViaFromTo: navaid not on airway"); + } + + Via* via = new Via(nullptr, airway, nav); return ghostForWaypt(c, via); } @@ -2926,6 +3109,24 @@ static naRef f_procedure_route(naContext c, naRef me, int argc, naRef* args) return convertWayptVecToNasal(c, r); } +static naRef f_airway_contains(naContext c, naRef me, int argc, naRef* args) +{ + Airway* awy = airwayGhost(me); + if (!awy) { + naRuntimeError(c, "airway.contains called on non-airway object"); + } + + if (argc < 1) { + naRuntimeError(c, "missing arg to airway.contains"); + } + + auto pos = positionedFromArg(args[0]); + if (!pos) { + return naNum(0); + } + + return naNum(awy->containsNavaid(pos)); +} // Table of extension functions. Terminate with zeros. static struct { const char* name; naCFunction func; } funcs[] = { @@ -2953,8 +3154,10 @@ static struct { const char* name; naCFunction func; } funcs[] = { { "createWP", f_createWP }, { "createWPFrom", f_createWPFrom }, { "createViaTo", f_createViaTo }, + { "createViaFromTo", f_createViaFromTo }, { "createDiscontinuity", f_createDiscontinuity }, { "airwaysRoute", f_airwaySearch }, + { "airway", f_findAirway }, { "magvar", f_magvar }, { "courseAndDistance", f_courseAndDistance }, { "greatCircleMove", f_greatCircleMove }, @@ -3021,6 +3224,10 @@ naRef initNasalPositioned(naRef globals, naContext c) hashset(c, fpLegPrototype, "path", naNewFunc(c, naNewCCode(c, f_leg_path))); hashset(c, fpLegPrototype, "courseAndDistanceFrom", naNewFunc(c, naNewCCode(c, f_leg_courseAndDistanceFrom))); + airwayPrototype = naNewHash(c); + naSave(c, airwayPrototype); + hashset(c, airwayPrototype, "contains", naNewFunc(c, naNewCCode(c, f_airway_contains))); + for(int i=0; funcs[i].name; i++) { hashset(c, globals, funcs[i].name, naNewFunc(c, naNewCCode(c, funcs[i].func)));