From: James Turner Date: Fri, 11 May 2012 16:07:56 +0000 (+0100) Subject: Expose procedure routing and fixes to Nasal. X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=acd8fa25e655ddd647413386f778032c92db94de;p=flightgear.git Expose procedure routing and fixes to Nasal. --- diff --git a/src/Navaids/procedure.cxx b/src/Navaids/procedure.cxx index bff774b4d..be3df3204 100644 --- a/src/Navaids/procedure.cxx +++ b/src/Navaids/procedure.cxx @@ -93,21 +93,23 @@ void Approach::addTransition(Transition* aTrans) bool Approach::route(WayptRef aIAF, WayptVec& aWps) { - WptTransitionMap::iterator it; - bool haveTrans = false; - for (it = _transitions.begin(); it != _transitions.end(); ++it) { - Transition* t= it->second; - if (t->enroute()->matches(aIAF)) { - t->route(aWps); - haveTrans = true; - break; + if (aIAF.valid()) { + WptTransitionMap::iterator it; + bool haveTrans = false; + for (it = _transitions.begin(); it != _transitions.end(); ++it) { + Transition* t= it->second; + if (t->enroute()->matches(aIAF)) { + t->route(aWps); + haveTrans = true; + break; + } + } // of transitions iteration + + if (!haveTrans) { + SG_LOG(SG_GENERAL, SG_INFO, "approach " << ident() << " has no transition " << + "for IAF: " << aIAF->ident()); + return false; } - } // of transitions iteration - - if (!haveTrans) { - SG_LOG(SG_GENERAL, SG_INFO, "approach " << ident() << " has no transition " << - "for IAF: " << aIAF->ident()); - return false; } return routeFromVectors(aWps); diff --git a/src/Navaids/route.hxx b/src/Navaids/route.hxx index 79ccfd1e7..3ea83596f 100644 --- a/src/Navaids/route.hxx +++ b/src/Navaids/route.hxx @@ -151,6 +151,9 @@ public: */ virtual bool flag(WayptFlag aFlag) const; + virtual unsigned int flags() const + { return _flags; } + void setFlag(WayptFlag aFlag, bool aV = true); /** diff --git a/src/Scripting/NasalPositioned.cxx b/src/Scripting/NasalPositioned.cxx index 6fceec645..031e85f1f 100644 --- a/src/Scripting/NasalPositioned.cxx +++ b/src/Scripting/NasalPositioned.cxx @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -69,6 +70,9 @@ naGhostType NavaidGhostType = { positionedGhostDestroy, "navaid", navaidGhostGet static const char* runwayGhostGetMember(naContext c, void* g, naRef field, naRef* out); naGhostType RunwayGhostType = { positionedGhostDestroy, "runway", runwayGhostGetMember, 0 }; +static const char* fixGhostGetMember(naContext c, void* g, naRef field, naRef* out); +naGhostType FixGhostType = { positionedGhostDestroy, "fix", fixGhostGetMember, 0 }; + static const char* wayptGhostGetMember(naContext c, void* g, naRef field, naRef* out); naGhostType WayptGhostType = { wayptGhostDestroy, "waypoint", @@ -76,10 +80,12 @@ naGhostType WayptGhostType = { wayptGhostDestroy, 0}; static const char* legGhostGetMember(naContext c, void* g, naRef field, naRef* out); +static void legGhostSetMember(naContext c, void* g, naRef field, naRef value); + naGhostType FPLegGhostType = { legGhostDestroy, "flightplan-leg", legGhostGetMember, - 0}; + legGhostSetMember}; static const char* flightplanGhostGetMember(naContext c, void* g, naRef field, naRef* out); static void flightplanGhostSetMember(naContext c, void* g, naRef field, naRef value); @@ -110,11 +116,33 @@ static naRef stringToNasal(naContext c, const std::string& s) s.length()); } +static WayptFlag wayptFlagFromString(const char* s) +{ + if (!strcmp(s, "sid")) return WPT_DEPARTURE; + if (!strcmp(s, "star")) return WPT_ARRIVAL; + if (!strcmp(s, "approach")) return WPT_APPROACH; + if (!strcmp(s, "missed")) return WPT_MISS; + if (!strcmp(s, "pseudo")) return WPT_PSEUDO; + + return (WayptFlag) 0; +} + +static naRef wayptFlagToNasal(naContext c, unsigned int flags) +{ + if (flags & WPT_PSEUDO) return stringToNasal(c, "pseudo"); + if (flags & WPT_DEPARTURE) return stringToNasal(c, "sid"); + if (flags & WPT_ARRIVAL) return stringToNasal(c, "star"); + if (flags & WPT_MISS) return stringToNasal(c, "missed"); + if (flags & WPT_APPROACH) return stringToNasal(c, "approach"); + return naNil(); +} + static FGPositioned* positionedGhost(naRef r) { if ((naGhost_type(r) == &AirportGhostType) || (naGhost_type(r) == &NavaidGhostType) || - (naGhost_type(r) == &RunwayGhostType)) + (naGhost_type(r) == &RunwayGhostType) || + (naGhost_type(r) == &FixGhostType)) { return (FGPositioned*) naGhost_ptr(r); } @@ -143,6 +171,14 @@ static FGRunway* runwayGhost(naRef r) return 0; } +static FGFix* fixGhost(naRef r) +{ + if (naGhost_type(r) == &FixGhostType) + return (FGFix*) naGhost_ptr(r); + return 0; +} + + static void positionedGhostDestroy(void* g) { FGPositioned* pos = (FGPositioned*)g; @@ -239,6 +275,17 @@ naRef ghostForRunway(naContext c, const FGRunway* r) return naNewGhost2(c, &RunwayGhostType, (void*) r); } +naRef ghostForFix(naContext c, const FGFix* r) +{ + if (!r) { + return naNil(); + } + + FGPositioned::get(r); // take a ref + return naNewGhost2(c, &FixGhostType, (void*) r); +} + + naRef ghostForWaypt(naContext c, const Waypt* wpt) { if (!wpt) { @@ -312,6 +359,7 @@ static const char* waypointCommonGetMember(naContext c, Waypt* wpt, const char* { if (!strcmp(fieldName, "wp_name")) *out = stringToNasal(c, wpt->ident()); else if (!strcmp(fieldName, "wp_type")) *out = stringToNasal(c, wpt->type()); + else if (!strcmp(fieldName, "wp_role")) *out = wayptFlagToNasal(c, wpt->flags()); else if (!strcmp(fieldName, "wp_lat")) *out = naNum(wpt->position().getLatitudeDeg()); else if (!strcmp(fieldName, "wp_lon")) *out = naNum(wpt->position().getLongitudeDeg()); else if (!strcmp(fieldName, "wp_parent_name")) { @@ -377,6 +425,8 @@ static const char* legGhostGetMember(naContext c, void* g, naRef field, naRef* o if (!strcmp(fieldName, "parents")) { *out = naNewVector(c); naVec_append(*out, fpLegPrototype); + } else if (!strcmp(fieldName, "index")) { + *out = naNum(leg->index()); } else if (!strcmp(fieldName, "alt_cstr")) { *out = naNum(leg->altitudeFt()); } else if (!strcmp(fieldName, "alt_cstr_type")) { @@ -399,6 +449,23 @@ static const char* legGhostGetMember(naContext c, void* g, naRef field, naRef* o return ""; // success } +static void legGhostSetMember(naContext c, void* g, naRef field, naRef value) +{ + const char* fieldName = naStr_data(field); + FlightPlan::Leg* leg = (FlightPlan::Leg*) g; + + if (!strcmp(fieldName, "wp_role")) { + if (!naIsString(value)) naRuntimeError(c, "wp_role must be a string"); + if (leg->waypoint()->owner() != NULL) naRuntimeError(c, "cannot override wp_role on waypoint with parent"); + WayptFlag f = wayptFlagFromString(naStr_data(value)); + if (f == 0) { + naRuntimeError(c, "unrecognized wp_role value %s", naStr_data(value)); + } + + leg->waypoint()->setFlag(f, true); + } +} + static const char* flightplanGhostGetMember(naContext c, void* g, naRef field, naRef* out) { const char* fieldName = naStr_data(field); @@ -657,6 +724,21 @@ static const char* navaidGhostGetMember(naContext c, void* g, naRef field, naRef return ""; } +static const char* fixGhostGetMember(naContext c, void* g, naRef field, naRef* out) +{ + const char* fieldName = naStr_data(field); + FGFix* fix = (FGFix*) g; + + if (!strcmp(fieldName, "id")) *out = stringToNasal(c, fix->ident()); + else if (!strcmp(fieldName, "lat")) *out = naNum(fix->get_lat()); + else if (!strcmp(fieldName, "lon")) *out = naNum(fix->get_lon()); + else { + return 0; + } + + return ""; +} + static bool hashIsCoord(naRef h) { naRef parents = naHash_cget(h, (char*) "parents"); @@ -720,6 +802,11 @@ static int geodFromArgs(naRef* args, int offset, int argc, SGGeod& result) return 1; } + if (gt == &FixGhostType) { + result = fixGhost(args[offset])->geod(); + return 1; + } + if (gt == &WayptGhostType) { result = wayptGhost(args[offset])->position(); return 1; @@ -1391,6 +1478,29 @@ static naRef f_findNavaidsByIdent(naContext c, naRef me, int argc, naRef* args) return r; } +static naRef f_findFixesByIdent(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, "findFixesByIdent expectes ident string as arg %d", argOffset); + } + + string ident(naStr_data(args[argOffset])); + naRef r = naNewVector(c); + + FGPositioned::TypeFilter filter(FGPositioned::FIX); + FGPositioned::List fixes = FGPositioned::findAllWithIdent(ident, &filter); + FGPositioned::sortByRange(fixes, pos); + + BOOST_FOREACH(FGPositionedRef f, fixes) { + naVec_append(r, ghostForFix(c, (FGFix*) f.ptr())); + } + + return r; +} // Convert a cartesian point to a geodetic lat/lon/altitude. static naRef f_magvar(naContext c, naRef me, int argc, naRef* args) @@ -1506,22 +1616,46 @@ static naRef f_route(naContext c, naRef me, int argc, naRef* args) return naNil(); } -static naRef f_airwaySearch(naContext c, naRef me, int argc, naRef* args) +static WayptRef wayptFromArg(naRef arg) { - if (argc < 2) { - naRuntimeError(c, "airwaysSearch needs at least two arguments"); + WayptRef r = wayptGhost(arg); + if (r.valid()) { + return r; } - WayptRef start = wayptGhost(args[0]), - end = wayptGhost(args[1]); + FGPositioned* pos = positionedGhost(arg); + if (!pos) { + // let's check if the arg is hash, coudl extra a geod and hence build + // a simple waypoint + + return WayptRef(); + } - if (!start && positionedGhost(args[0])) { - start = new NavaidWaypoint(positionedGhost(args[0]), NULL); +// special-case for runways + if (pos->type() == FGPositioned::RUNWAY) { + return new RunwayWaypt((FGRunway*) pos, NULL); } - if (!end && positionedGhost(args[1])) { - end = new NavaidWaypoint(positionedGhost(args[1]), NULL); + return new NavaidWaypoint(pos, NULL); +} + +static naRef convertWayptVecToNasal(naContext c, const WayptVec& wps) +{ + naRef result = naNewVector(c); + BOOST_FOREACH(WayptRef wpt, wps) { + naVec_append(result, ghostForWaypt(c, wpt.get())); } + return result; +} + +static naRef f_airwaySearch(naContext c, naRef me, int argc, naRef* args) +{ + if (argc < 2) { + naRuntimeError(c, "airwaysSearch needs at least two arguments"); + } + + WayptRef start = wayptFromArg(args[0]), + end = wayptFromArg(args[1]); if (!start || !end) { SG_LOG(SG_NASAL, SG_WARN, "airwaysSearch: start or end points are invalid"); @@ -1542,34 +1676,54 @@ static naRef f_airwaySearch(naContext c, naRef me, int argc, naRef* args) Airway::lowLevel()->route(start, end, route); } - naRef result = naNewVector(c); - BOOST_FOREACH(WayptRef wpt, route) { - naVec_append(result, ghostForWaypt(c, wpt.get())); - } - return result; + return convertWayptVecToNasal(c, route); } static naRef f_createWP(naContext c, naRef me, int argc, naRef* args) { SGGeod pos; int argOffset = geodFromArgs(args, 0, argc, pos); - string ident; -// if we were created from an FGPositioned, we can use its ident + if (((argc - argOffset) < 1) || !naIsString(args[argOffset])) { + naRuntimeError(c, "createWP: no identifier supplied"); + } + + string ident = naStr_data(args[argOffset++]); + WayptRef wpt = new BasicWaypt(pos, ident, NULL); + +// set waypt flags - approach, departure, pseudo, etc + if (argc > argOffset) { + WayptFlag f = wayptFlagFromString(naStr_data(args[argOffset++])); + wpt->setFlag(f); + } + + return ghostForWaypt(c, wpt); +} + +static naRef f_createWPFrom(naContext c, naRef me, int argc, naRef* args) +{ + if (argc < 1) { + naRuntimeError(c, "createWPFrom: need at least one argument"); + } + FGPositioned* positioned = positionedGhost(args[0]); - if (positioned) { - ident = positioned->ident(); + if (!positioned) { + naRuntimeError(c, "createWPFrom: couldn;t convert arg[0] to FGPositioned"); } - if (ident.empty()) { - if (((argc - argOffset) < 1) || !naIsString(args[argOffset])) { - naRuntimeError(c, "createWP: no identifier supplied"); - } - - ident = naStr_data(args[argOffset++]); + WayptRef wpt; + if (positioned->type() == FGPositioned::RUNWAY) { + wpt = new RunwayWaypt((FGRunway*) positioned, NULL); + } else { + wpt = new NavaidWaypoint(positioned, NULL); + } + + // set waypt flags - approach, departure, pseudo, etc + if (argc > 1) { + WayptFlag f = wayptFlagFromString(naStr_data(args[1])); + wpt->setFlag(f); } - WayptRef wpt = new BasicWaypt(pos, ident, NULL); return ghostForWaypt(c, wpt); } @@ -1724,17 +1878,6 @@ static naRef f_flightplan_clearPlan(naContext c, naRef me, int argc, naRef* args return naNil(); } -static WayptFlag wayptFlagFromString(const char* s) -{ - if (!strcmp(s, "sid")) return WPT_DEPARTURE; - if (!strcmp(s, "star")) return WPT_ARRIVAL; - if (!strcmp(s, "approach")) return WPT_APPROACH; - if (!strcmp(s, "missed")) return WPT_MISS; - if (!strcmp(s, "pseudo")) return WPT_PSEUDO; - - return (WayptFlag) 0; -} - static naRef f_flightplan_clearWPType(naContext c, naRef me, int argc, naRef* args) { FlightPlan* fp = flightplanGhost(me); @@ -1869,6 +2012,55 @@ static naRef f_procedure_transition(naContext c, naRef me, int argc, naRef* args return ghostForProcedure(c, trans); } +static naRef f_procedure_route(naContext c, naRef me, int argc, naRef* args) +{ + Procedure* proc = procedureGhost(me); + if (!proc) { + naRuntimeError(c, "procedure.route called on non-procedure object"); + } + +// wrapping up tow different routines here - approach routing from the IAF +// to the associated runway, and SID/STAR routing via an enroute transition +// and possibly a runway transition or not. + if (Approach::isApproach(proc->type())) { + WayptRef iaf; + if (argc > 0) { + iaf = wayptFromArg(args[0]); + } + + WayptVec r; + Approach* app = (Approach*) proc; + if (!app->route(iaf, r)) { + SG_LOG(SG_NASAL, SG_WARN, "procedure.route failed for Approach somehow"); + return naNil(); + } + + return convertWayptVecToNasal(c, r); + } else if ((proc->type() != PROCEDURE_SID) && (proc->type() != PROCEDURE_STAR)) { + naRuntimeError(c, "procedure.route called on unsuitable procedure type"); + } + + int argOffset = 0; + FGRunway* rwy = runwayGhost(args[0]); + if (rwy) ++argOffset; + + ArrivalDeparture* ad = (ArrivalDeparture*) proc; + Transition* trans = NULL; + if (argOffset < argc) { + trans = (Transition*) procedureGhost(args[argOffset]); + } + + // note either runway or trans may be NULL - that's ok + WayptVec r; + if (!ad->route(rwy, trans, r)) { + SG_LOG(SG_NASAL, SG_WARN, "prcoedure.route failed for ArrvialDeparture somehow"); + return naNil(); + } + + return convertWayptVecToNasal(c, r); +} + + // Table of extension functions. Terminate with zeros. static struct { const char* name; naCFunction func; } funcs[] = { { "carttogeod", f_carttogeod }, @@ -1882,8 +2074,10 @@ static struct { const char* name; naCFunction func; } funcs[] = { { "findNavaidByFrequency", f_findNavaidByFrequency }, { "findNavaidsByFrequency", f_findNavaidsByFrequency }, { "findNavaidsByID", f_findNavaidsByIdent }, + { "findFixesByID", f_findFixesByIdent }, { "flightplan", f_route }, { "createWP", f_createWP }, + { "createWPFrom", f_createWPFrom }, { "airwaysRoute", f_airwaySearch }, { "magvar", f_magvar }, { "courseAndDistance", f_courseAndDistance }, @@ -1935,9 +2129,8 @@ naRef initNasalPositioned(naRef globals, naContext c, naRef gcSave) procedurePrototype = naNewHash(c); hashset(c, gcSave, "procedureProto", procedurePrototype); - // hashset(c, procedurePrototype, "runwayTransition", naNewFunc(c, naNewCCode(c, f_procedure_runwayTransition))); hashset(c, procedurePrototype, "transition", naNewFunc(c, naNewCCode(c, f_procedure_transition))); - // hashset(c, procedurePrototype, "buildPath", naNewFunc(c, naNewCCode(c, f_procedure_build))); + hashset(c, procedurePrototype, "route", naNewFunc(c, naNewCCode(c, f_procedure_route))); fpLegPrototype = naNewHash(c); hashset(c, gcSave, "fpLegProto", fpLegPrototype);