]> git.mxchange.org Git - flightgear.git/commitdiff
Expose procedure routing and fixes to Nasal.
authorJames Turner <zakalawe@mac.com>
Fri, 11 May 2012 16:07:56 +0000 (17:07 +0100)
committerJames Turner <zakalawe@mac.com>
Fri, 11 May 2012 16:07:56 +0000 (17:07 +0100)
src/Navaids/procedure.cxx
src/Navaids/route.hxx
src/Scripting/NasalPositioned.cxx

index bff774b4d360d12eaeb3890d33a2302b113d7de0..be3df320436af163ed363a62f647e8e0df78e297 100644 (file)
@@ -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);
index 79ccfd1e749bb295b1b20a2bb1288ebb0c86f5a3..3ea83596ffde9642e41e6d83994e88a014e61217 100644 (file)
@@ -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);
   
   /**
index 6fceec645dd781bc2ed0e99e86c5fb268b956454..031e85f1f64c101752c57052d1370a5d319076e2 100644 (file)
@@ -47,6 +47,7 @@
 #include <ATC/CommStation.hxx>
 #include <Navaids/route.hxx>
 #include <Navaids/waypoint.hxx>
+#include <Navaids/fix.hxx>
 #include <Autopilot/route_mgr.hxx>
 #include <Navaids/procedure.hxx>
 #include <Navaids/airways.hxx>
@@ -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);