X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FScripting%2FNasalPositioned.cxx;h=53a3a41e7eca335acf7d5daa6508c702bfaef641;hb=1ef77b2bc2cc98ff665161b0f7cc7ea80327cb5c;hp=208c34e8fef66fb6075fb562fe8a93d9578f34d2;hpb=1b7b69b49874ad369e80222529d5b29bfd863a49;p=flightgear.git diff --git a/src/Scripting/NasalPositioned.cxx b/src/Scripting/NasalPositioned.cxx index 208c34e8f..53a3a41e7 100644 --- a/src/Scripting/NasalPositioned.cxx +++ b/src/Scripting/NasalPositioned.cxx @@ -39,15 +39,19 @@ #include #include #include +#include #include #include #include
#include
#include #include -#include +#include +#include +#include #include #include +#include using namespace flightgear; @@ -67,17 +71,24 @@ 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); +static void waypointGhostSetMember(naContext c, void* g, naRef field, naRef value); + naGhostType WayptGhostType = { wayptGhostDestroy, "waypoint", wayptGhostGetMember, - 0}; + waypointGhostSetMember}; 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); @@ -108,10 +119,37 @@ 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) == &PositionedGhostType) + if ((naGhost_type(r) == &AirportGhostType) || + (naGhost_type(r) == &NavaidGhostType) || + (naGhost_type(r) == &RunwayGhostType) || + (naGhost_type(r) == &FixGhostType)) + { return (FGPositioned*) naGhost_ptr(r); + } + return 0; } @@ -136,6 +174,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; @@ -147,6 +193,12 @@ static Waypt* wayptGhost(naRef r) { if (naGhost_type(r) == &WayptGhostType) return (Waypt*) naGhost_ptr(r); + + if (naGhost_type(r) == &FPLegGhostType) { + FlightPlan::Leg* leg = (FlightPlan::Leg*) naGhost_ptr(r); + return leg->waypoint(); + } + return 0; } @@ -196,16 +248,6 @@ static naRef geoCoordClass; static naRef fpLegPrototype; static naRef procedurePrototype; -naRef ghostForPositioned(naContext c, const FGPositioned* pos) -{ - if (!pos) { - return naNil(); - } - - FGPositioned::get(pos); // take a ref - return naNewGhost(c, &PositionedGhostType, (void*) pos); -} - naRef ghostForAirport(naContext c, const FGAirport* apt) { if (!apt) { @@ -236,6 +278,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) { @@ -309,6 +362,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")) { @@ -330,6 +384,20 @@ static const char* waypointCommonGetMember(naContext c, Waypt* wpt, const char* return ""; } +static void waypointCommonSetMember(naContext c, Waypt* wpt, const char* fieldName, naRef value) +{ + if (!strcmp(fieldName, "wp_role")) { + if (!naIsString(value)) naRuntimeError(c, "wp_role must be a string"); + if (wpt->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)); + } + + wpt->setFlag(f, true); + } +} + static const char* wayptGhostGetMember(naContext c, void* g, naRef field, naRef* out) { const char* fieldName = naStr_data(field); @@ -374,6 +442,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")) { @@ -396,6 +466,21 @@ static const char* legGhostGetMember(naContext c, void* g, naRef field, naRef* o return ""; // success } +static void waypointGhostSetMember(naContext c, void* g, naRef field, naRef value) +{ + const char* fieldName = naStr_data(field); + Waypt* wpt = (Waypt*) g; + waypointCommonSetMember(c, wpt, fieldName, value); +} + +static void legGhostSetMember(naContext c, void* g, naRef field, naRef value) +{ + const char* fieldName = naStr_data(field); + FlightPlan::Leg* leg = (FlightPlan::Leg*) g; + + waypointCommonSetMember(c, leg->waypoint(), fieldName, value); +} + static const char* flightplanGhostGetMember(naContext c, void* g, naRef field, naRef* out) { const char* fieldName = naStr_data(field); @@ -483,7 +568,7 @@ static void flightplanGhostSetMember(naContext c, void* g, naRef field, naRef va } else if (!strcmp(fieldName, "sid")) { Procedure* proc = procedureGhost(value); if (proc && (proc->type() == PROCEDURE_SID)) { - fp->setSID((SID*) proc); + fp->setSID((flightgear::SID*) proc); return; } // allow a SID transition to be set, implicitly include the SID itself @@ -654,6 +739,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"); @@ -669,17 +769,9 @@ bool geodFromHash(naRef ref, SGGeod& result) if (!naIsHash(ref)) { return false; } + -// first, see if the hash contains a FGPositioned ghost - in which case -// we can read off its position directly - naRef posGhost = naHash_cget(ref, (char*) "_positioned"); - if (!naIsNil(posGhost)) { - FGPositioned* pos = positionedGhost(posGhost); - result = pos->geod(); - return true; - } - -// then check for manual latitude / longitude names +// check for manual latitude / longitude names naRef lat = naHash_cget(ref, (char*) "lat"); naRef lon = naHash_cget(ref, (char*) "lon"); if (naIsNum(lat) && naIsNum(lon)) { @@ -725,6 +817,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; @@ -1225,6 +1322,16 @@ static naRef f_airport_getApproach(naContext c, naRef me, int argc, naRef* args) return ghostForProcedure(c, apt->findApproachWithIdent(ident)); } +static naRef f_airport_toString(naContext c, naRef me, int argc, naRef* args) +{ + FGAirport* apt = airportGhost(me); + if (!apt) { + naRuntimeError(c, "airport.tostring called on non-airport object"); + } + + return stringToNasal(c, "an airport " + apt->ident()); +} + // Returns vector of data hash for navaid of a , nil on error // navaids sorted by ascending distance // navinfo([,],[],[]) @@ -1396,6 +1503,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) @@ -1511,6 +1641,219 @@ static naRef f_route(naContext c, naRef me, int argc, naRef* args) return naNil(); } +class NasalFPDelegate : public FlightPlan::Delegate +{ +public: + NasalFPDelegate(FlightPlan* fp, FGNasalSys* sys, naRef ins) : + _nasal(sys), + _plan(fp), + _instance(ins) + { + SG_LOG(SG_NASAL, SG_INFO, "created Nasal delegate for " << fp); + _gcSaveKey = _nasal->gcSave(ins); + } + + virtual ~NasalFPDelegate() + { + SG_LOG(SG_NASAL, SG_INFO, "destroying Nasal delegate for " << _plan); + _nasal->gcRelease(_gcSaveKey); + } + + virtual void departureChanged() + { + callDelegateMethod("departureChanged"); + } + + virtual void arrivalChanged() + { + callDelegateMethod("arrivalChanged"); + } + + virtual void waypointsChanged() + { + callDelegateMethod("waypointsChanged"); + } + + virtual void currentWaypointChanged() + { + callDelegateMethod("currentWaypointChanged"); + } +private: + + void callDelegateMethod(const char* method) + { + naRef f; + naMember_cget(_nasal->context(), _instance, method, &f); + if (naIsNil(f)) { + return; // no method on the delegate + } + + naRef arg[1]; + arg[0] = ghostForFlightPlan(_nasal->context(), _plan); + _nasal->callMethod(f, _instance, 1, arg, naNil()); + } + + FGNasalSys* _nasal; + FlightPlan* _plan; + naRef _instance; + int _gcSaveKey; +}; + +class NasalFPDelegateFactory : public FlightPlan::DelegateFactory +{ +public: + NasalFPDelegateFactory(naRef code) + { + _nasal = (FGNasalSys*) globals->get_subsystem("nasal"); + _func = code; + _gcSaveKey = _nasal->gcSave(_func); + } + + ~NasalFPDelegateFactory() + { + _nasal->gcRelease(_gcSaveKey); + } + + virtual FlightPlan::Delegate* createFlightPlanDelegate(FlightPlan* fp) + { + naRef args[1]; + args[0] = ghostForFlightPlan(_nasal->context(), fp); + naRef instance = _nasal->call(_func, 1, args, naNil()); + if (naIsNil(instance)) { + return NULL; + } + + return new NasalFPDelegate(fp, _nasal, instance); + } +private: + FGNasalSys* _nasal; + naRef _func; + int _gcSaveKey; +}; + +static naRef f_registerFPDelegate(naContext c, naRef me, int argc, naRef* args) +{ + if ((argc < 1) || !naIsFunc(args[0])) { + naRuntimeError(c, "non-function argument to registerFlightPlanDelegate"); + } + + NasalFPDelegateFactory* factory = new NasalFPDelegateFactory(args[0]); + FlightPlan::registerDelegateFactory(factory); + + return naNil(); +} + +static WayptRef wayptFromArg(naRef arg) +{ + WayptRef r = wayptGhost(arg); + if (r.valid()) { + return r; + } + + 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(); + } + +// special-case for runways + if (pos->type() == FGPositioned::RUNWAY) { + return new RunwayWaypt((FGRunway*) pos, 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"); + return naNil(); + } + + bool highLevel = true; + if ((argc > 2) && naIsString(args[2])) { + if (!strcmp(naStr_data(args[2]), "lowlevel")) { + highLevel = false; + } + } + + WayptVec route; + if (highLevel) { + Airway::highLevel()->route(start, end, route); + } else { + Airway::lowLevel()->route(start, end, route); + } + + 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); + + 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) { + naRuntimeError(c, "createWPFrom: couldn;t convert arg[0] to FGPositioned"); + } + + 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); + } + + return ghostForWaypt(c, wpt); +} + static naRef f_flightplan_getWP(naContext c, naRef me, int argc, naRef* args) { FlightPlan* fp = flightplanGhost(me); @@ -1635,26 +1978,31 @@ static naRef f_flightplan_insertWaypoints(naContext c, naRef me, int argc, naRef return naNil(); } -static naRef f_flightplan_clearPlan(naContext c, naRef me, int argc, naRef* args) +static naRef f_flightplan_deleteWP(naContext c, naRef me, int argc, naRef* args) { FlightPlan* fp = flightplanGhost(me); if (!fp) { - naRuntimeError(c, "flightplan.clearPlan called on non-flightplan object"); + naRuntimeError(c, "flightplan.deleteWP called on non-flightplan object"); } - fp->clear(); + if ((argc < 1) || !naIsNum(args[0])) { + naRuntimeError(c, "bad argument to flightplan.deleteWP"); + } + + int index = (int) args[0].num; + fp->deleteIndex(index); return naNil(); } -static WayptFlag wayptFlagFromString(const char* s) +static naRef f_flightplan_clearPlan(naContext c, naRef me, int argc, naRef* args) { - 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; + FlightPlan* fp = flightplanGhost(me); + if (!fp) { + naRuntimeError(c, "flightplan.clearPlan called on non-flightplan object"); + } - return (WayptFlag) 0; + fp->clear(); + return naNil(); } static naRef f_flightplan_clearWPType(naContext c, naRef me, int argc, naRef* args) @@ -1791,6 +2139,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 }, @@ -1804,7 +2201,12 @@ static struct { const char* name; naCFunction func; } funcs[] = { { "findNavaidByFrequency", f_findNavaidByFrequency }, { "findNavaidsByFrequency", f_findNavaidsByFrequency }, { "findNavaidsByID", f_findNavaidsByIdent }, + { "findFixesByID", f_findFixesByIdent }, { "flightplan", f_route }, + { "registerFlightPlanDelegate", f_registerFPDelegate }, + { "createWP", f_createWP }, + { "createWPFrom", f_createWPFrom }, + { "airwaysRoute", f_airwaySearch }, { "magvar", f_magvar }, { "courseAndDistance", f_courseAndDistance }, { "greatCircleMove", f_greatCircleMove }, @@ -1829,6 +2231,7 @@ naRef initNasalPositioned(naRef globals, naContext c, naRef gcSave) hashset(c, airportPrototype, "getSid", naNewFunc(c, naNewCCode(c, f_airport_getSid))); hashset(c, airportPrototype, "getStar", naNewFunc(c, naNewCCode(c, f_airport_getStar))); hashset(c, airportPrototype, "getIAP", naNewFunc(c, naNewCCode(c, f_airport_getApproach))); + hashset(c, airportPrototype, "tostring", naNewFunc(c, naNewCCode(c, f_airport_toString))); flightplanPrototype = naNewHash(c); hashset(c, gcSave, "flightplanProto", flightplanPrototype); @@ -1839,6 +2242,7 @@ naRef initNasalPositioned(naRef globals, naContext c, naRef gcSave) hashset(c, flightplanPrototype, "getPlanSize", naNewFunc(c, naNewCCode(c, f_flightplan_numWaypoints))); hashset(c, flightplanPrototype, "appendWP", naNewFunc(c, naNewCCode(c, f_flightplan_appendWP))); hashset(c, flightplanPrototype, "insertWP", naNewFunc(c, naNewCCode(c, f_flightplan_insertWP))); + hashset(c, flightplanPrototype, "deleteWP", naNewFunc(c, naNewCCode(c, f_flightplan_deleteWP))); hashset(c, flightplanPrototype, "insertWPAfter", naNewFunc(c, naNewCCode(c, f_flightplan_insertWPAfter))); hashset(c, flightplanPrototype, "insertWaypoints", naNewFunc(c, naNewCCode(c, f_flightplan_insertWaypoints))); hashset(c, flightplanPrototype, "cleanPlan", naNewFunc(c, naNewCCode(c, f_flightplan_clearPlan))); @@ -1854,9 +2258,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);