]> git.mxchange.org Git - flightgear.git/blobdiff - src/Scripting/NasalPositioned_cppbind.cxx
Reset: Nasal can be shutdown.
[flightgear.git] / src / Scripting / NasalPositioned_cppbind.cxx
index aeede726b87a8ebc5194890e2b3b303b4e6a5797..cc3568c4b67f8ee16984e675774f12ea3b15da28 100644 (file)
 
 #include <Airports/airport.hxx>
 #include <Airports/dynamics.hxx>
+#include <Airports/pavement.hxx>
 #include <ATC/CommStation.hxx>
 #include <Main/globals.hxx>
 #include <Navaids/NavDataCache.hxx>
+#include <Navaids/navlist.hxx>
+#include <Navaids/navrecord.hxx>
+#include <Navaids/fix.hxx>
 
 typedef nasal::Ghost<FGPositionedRef> NasalPositioned;
 typedef nasal::Ghost<FGRunwayRef> NasalRunway;
 typedef nasal::Ghost<FGParkingRef> NasalParking;
 typedef nasal::Ghost<FGAirportRef> NasalAirport;
 typedef nasal::Ghost<flightgear::CommStationRef> NasalCommStation;
-
-//------------------------------------------------------------------------------
-naRef to_nasal_helper(naContext c, FGPositioned* positioned)
-{
-  return NasalPositioned::create(c, positioned);
-}
-
-//------------------------------------------------------------------------------
-naRef to_nasal_helper(naContext c, FGPavement* rwy)
-{
-  return NasalPositioned::create(c, (FGPositioned*)rwy);
-}
-
-//------------------------------------------------------------------------------
-naRef to_nasal_helper(naContext c, FGRunwayBase* rwy)
-{
-  return NasalPositioned::create(c, (FGPositioned*)rwy);
-}
-
-//------------------------------------------------------------------------------
-naRef to_nasal_helper(naContext c, FGParking* parking)
-{
-  return NasalParking::create(c, parking);
-}
+typedef nasal::Ghost<FGNavRecordRef> NasalNavRecord;
+typedef nasal::Ghost<FGRunwayRef> NasalRunway;
+typedef nasal::Ghost<FGFixRef> NasalFix;
 
 //------------------------------------------------------------------------------
 naRef to_nasal_helper(naContext c, flightgear::SID* sid)
@@ -94,23 +77,19 @@ naRef to_nasal_helper(naContext c, flightgear::Approach* iap)
 }
 
 //------------------------------------------------------------------------------
-naRef to_nasal_helper(naContext c, FGAirport* apt)
+static naRef f_navaid_course(naContext, FGNavRecord& nav)
 {
-  return NasalAirport::create(c, apt);
-}
+  if( !(  nav.type() == FGPositioned::ILS
+       || nav.type() == FGPositioned::LOC
+       ) )
+    return naNil();
 
-//------------------------------------------------------------------------------
-naRef to_nasal_helper(naContext c, const SGGeod& pos)
-{
-  nasal::Hash hash(c);
-  hash.set("lat", pos.getLatitudeDeg());
-  hash.set("lon", pos.getLongitudeDeg());
-  hash.set("elevation", pos.getElevationM());
-  return hash.get_naRef();
+  double radial = nav.get_multiuse();
+  return naNum(SGMiscd::normalizePeriodic(0.5, 360.5, radial));
 }
 
 //------------------------------------------------------------------------------
-static FGRunwayBase* f_airport_runway(FGAirport& apt, std::string ident)
+static FGRunwayBaseRef f_airport_runway(FGAirport& apt, std::string ident)
 {
   boost::to_upper(ident);
 
@@ -124,7 +103,7 @@ static FGRunwayBase* f_airport_runway(FGAirport& apt, std::string ident)
 
 //------------------------------------------------------------------------------
 template<class T, class C1, class C2>
-std::vector<T> extract( const std::vector<C1*>& in,
+std::vector<T> extract( const std::vector<C1>& in,
                         T (C2::*getter)() const )
 {
   std::vector<T> ret(in.size());
@@ -224,7 +203,7 @@ static naRef f_airport_approaches(FGAirport& apt, const nasal::CallContext& ctx)
 
 //------------------------------------------------------------------------------
 static FGParkingList
-f_airport_parking(FGAirport& apt, const nasal::CallContext& ctx)
+f_airport_parking(FGAirport& apt, nasal::CallContext ctx)
 {
   std::string type = ctx.getArg<std::string>(0);
   bool only_available = ctx.getArg<bool>(1);
@@ -251,6 +230,81 @@ f_airport_parking(FGAirport& apt, const nasal::CallContext& ctx)
   return ret;
 }
 
+/**
+ * Extract a SGGeod from a nasal function argument list.
+ *
+ * <lat>, <lon>
+ * {"lat": <lat-deg>, "lon": <lon-deg>}
+ * geo.Coord.new() (aka. {"_lat": <lat-rad>, "_lon": <lon-rad>})
+ */
+static bool extractGeod(nasal::CallContext& ctx, SGGeod& result)
+{
+  if( !ctx.argc )
+    return false;
+
+  if( ctx.isGhost(0) )
+  {
+    FGPositioned* pos =
+      NasalPositioned::fromNasal(ctx.c, ctx.requireArg<naRef>(0));
+
+    if( pos )
+    {
+      result = pos->geod();
+      ctx.popFront();
+      return true;
+    }
+  }
+  else if( ctx.isHash(0) )
+  {
+    nasal::Hash pos_hash = ctx.requireArg<nasal::Hash>(0);
+
+    // check for manual latitude / longitude names
+    naRef lat = pos_hash.get("lat"),
+          lon = pos_hash.get("lon");
+    if( naIsNum(lat) && naIsNum(lon) )
+    {
+      result = SGGeod::fromDeg( ctx.from_nasal<double>(lon),
+                                ctx.from_nasal<double>(lat) );
+      ctx.popFront();
+      return true;
+    }
+
+    // geo.Coord uses _lat/_lon in radians
+    // TODO should we check if its really a geo.Coord?
+    lat = pos_hash.get("_lat");
+    lon = pos_hash.get("_lon");
+    if( naIsNum(lat) && naIsNum(lon) )
+    {
+      result = SGGeod::fromRad( ctx.from_nasal<double>(lon),
+                                ctx.from_nasal<double>(lat) );
+      ctx.popFront();
+      return true;
+    }
+  }
+  else if( ctx.isNumeric(0) && ctx.isNumeric(1) )
+  {
+    // lat, lon
+    result = SGGeod::fromDeg( ctx.requireArg<double>(1),
+                              ctx.requireArg<double>(0) );
+    ctx.popFront(2);
+    return true;
+  }
+
+  return false;
+}
+
+/**
+ * Extract position from ctx or return current aircraft position if not given.
+ */
+static SGGeod getPosition(nasal::CallContext& ctx)
+{
+  SGGeod pos;
+  if( !extractGeod(ctx, pos) )
+    pos = globals->get_aircraft_position();
+
+  return pos;
+}
+
 //------------------------------------------------------------------------------
 // Returns Nasal ghost for particular or nearest airport of a <type>, or nil
 // on error.
@@ -259,31 +313,17 @@ f_airport_parking(FGAirport& apt, const nasal::CallContext& ctx)
 // airportinfo(<type>);                 type := ("airport"|"seaport"|"heliport")
 // airportinfo()                        same as  airportinfo("airport")
 // airportinfo(<lat>, <lon> [, <type>]);
-static naRef f_airportinfo(naContext c, naRef me, int argc, naRef* args)
+static naRef f_airportinfo(nasal::CallContext ctx)
 {
-  nasal::CallContext ctx(c, argc, args);
-  // TODO think of something comfortable to overload functions or use variable
-  //      number/types of arguments.
+  SGGeod pos = getPosition(ctx);
 
-  std::string ident = "airport";
-  SGGeod pos = globals->get_aircraft_position();
+  if( ctx.argc > 1 )
+    naRuntimeError(ctx.c, "airportinfo() with invalid function arguments");
 
-  if( ctx.argc == 1 )
-  {
+  // optional type/ident
+  std::string ident("airport");
+  if( ctx.isString(0) )
     ident = ctx.requireArg<std::string>(0);
-  }
-  else if( ctx.argc >= 2 )
-  {
-    // Why are lat/lon swapped?
-    pos = SGGeod::fromDeg( ctx.requireArg<double>(1),
-                           ctx.requireArg<double>(0) );
-
-    if( ctx.argc >= 3 )
-      ident = ctx.requireArg<std::string>(2);
-
-    if( ctx.argc > 3 )
-      naRuntimeError(ctx.c, "airportinfo() with invalid function arguments");
-  }
 
   FGAirport::TypeRunwayFilter filter;
   if( !filter.fromTypeString(ident) )
@@ -294,23 +334,157 @@ static naRef f_airportinfo(naContext c, naRef me, int argc, naRef* args)
   return ctx.to_nasal( FGAirport::findClosest(pos, maxRange, &filter) );
 }
 
+/**
+ * findAirportsWithinRange([<position>,] <range-nm> [, type])
+ */
+static naRef f_findAirportsWithinRange(nasal::CallContext ctx)
+{
+  SGGeod pos = getPosition(ctx);
+  double range_nm = ctx.requireArg<double>(0);
+
+  FGAirport::TypeRunwayFilter filter; // defaults to airports only
+  filter.fromTypeString( ctx.getArg<std::string>(1) );
+
+  FGPositionedList apts = FGPositioned::findWithinRange(pos, range_nm, &filter);
+  FGPositioned::sortByRange(apts, pos);
+
+  return ctx.to_nasal(apts);
+}
+
+/**
+ * findAirportsByICAO(<ident/prefix> [, type])
+ */
+static naRef f_findAirportsByICAO(nasal::CallContext ctx)
+{
+  std::string prefix = ctx.requireArg<std::string>(0);
+
+  FGAirport::TypeRunwayFilter filter; // defaults to airports only
+  filter.fromTypeString( ctx.getArg<std::string>(1) );
+
+  return ctx.to_nasal( FGPositioned::findAllWithIdent(prefix, &filter, false) );
+}
+
+// Returns vector of data hash for navaid of a <type>, nil on error
+// navaids sorted by ascending distance
+// navinfo([<lat>,<lon>],[<type>],[<id>])
+// lat/lon (numeric): use latitude/longitude instead of ac position
+// type:              ("fix"|"vor"|"ndb"|"ils"|"dme"|"tacan"|"any")
+// id:                (partial) id of the fix
+// examples:
+// navinfo("vor")     returns all vors
+// navinfo("HAM")     return all navaids who's name start with "HAM"
+// navinfo("vor", "HAM") return all vor who's name start with "HAM"
+//navinfo(34,48,"vor","HAM") return all vor who's name start with "HAM"
+//                           sorted by distance relative to lat=34, lon=48
+static naRef f_navinfo(nasal::CallContext ctx)
+{
+  SGGeod pos = getPosition(ctx);
+  std::string id = ctx.getArg<std::string>(0);
+
+  FGNavList::TypeFilter filter;
+  if( filter.fromTypeString(id) )
+    id = ctx.getArg<std::string>(1);
+  else if( ctx.argc > 1 )
+    naRuntimeError(ctx.c, "navinfo() already got an ident");
+
+  return ctx.to_nasal( FGNavList::findByIdentAndFreq(pos, id, 0.0, &filter) );
+}
+
+//------------------------------------------------------------------------------
+static naRef f_findWithinRange(nasal::CallContext ctx)
+{
+  SGGeod pos = getPosition(ctx);
+  double range_nm = ctx.requireArg<double>(0);
+
+    std::string typeSpec = ctx.getArg<std::string>(1);
+    FGPositioned::TypeFilter filter(FGPositioned::TypeFilter::fromString(typeSpec));
+    
+  FGPositionedList items = FGPositioned::findWithinRange(pos, range_nm, &filter);
+  FGPositioned::sortByRange(items, pos);
+  return ctx.to_nasal(items);
+}
+
+static naRef f_findByIdent(nasal::CallContext ctx)
+{
+  std::string prefix = ctx.requireArg<std::string>(0);
+  std::string typeSpec = ctx.getArg<std::string>(1);
+  FGPositioned::TypeFilter filter(FGPositioned::TypeFilter::fromString(typeSpec));
+  bool exact = ctx.getArg<bool>(2, false);
+
+  return ctx.to_nasal( FGPositioned::findAllWithIdent(prefix, &filter, exact) );
+}
+
+static naRef f_findByName(nasal::CallContext ctx)
+{
+  std::string prefix = ctx.requireArg<std::string>(0);
+  std::string typeSpec = ctx.getArg<std::string>(1);
+  FGPositioned::TypeFilter filter(FGPositioned::TypeFilter::fromString(typeSpec));
+  
+  return ctx.to_nasal( FGPositioned::findAllWithName(prefix, &filter, false) );
+}
+
 //------------------------------------------------------------------------------
-naRef initNasalPositioned_cppbind(naRef globalsRef, naContext c, naRef gcSave)
+
+static naRef f_courseAndDistance(nasal::CallContext ctx)
 {
-  NasalPositioned::init("FGPositioned")
+  SGGeod from = globals->get_aircraft_position(), to, pos;
+  bool ok = extractGeod(ctx, pos);
+  if (!ok) {
+    naRuntimeError(ctx.c, "invalid arguments to courseAndDistance");
+  }
+  
+  if (extractGeod(ctx, to)) {
+    from = pos; // we parsed both FROM and TO args, so first was FROM
+  } else {
+    to = pos; // only parsed one arg, so FROM is current
+  }
+  
+  double course, course2, d;
+  SGGeodesy::inverse(from, to, course, course2, d);
+  
+  naRef result = naNewVector(ctx.c);
+  naVec_append(result, naNum(course));
+  naVec_append(result, naNum(d * SG_METER_TO_NM));
+  return result;
+}
+
+static naRef f_sortByRange(nasal::CallContext ctx)
+{
+  FGPositionedList items = ctx.requireArg<FGPositionedList>(0);
+  ctx.popFront();
+  FGPositioned::sortByRange(items, getPosition(ctx));
+  return ctx.to_nasal(items);
+}
+
+//------------------------------------------------------------------------------
+naRef initNasalPositioned_cppbind(naRef globalsRef, naContext c)
+{
+    if (!NasalPositioned::isInit()) {
+    
+  NasalPositioned::init("Positioned")
     .member("id", &FGPositioned::ident)
     .member("ident", &FGPositioned::ident) // TODO to we really need id and ident?
     .member("name", &FGPositioned::name)
+    .member("type", &FGPositioned::typeString)
     .member("lat", &FGPositioned::latitude)
     .member("lon", &FGPositioned::longitude)
     .member("elevation", &FGPositioned::elevationM);
-  NasalRunway::init("FGRunway")
+  NasalRunway::init("Runway")
     .bases<NasalPositioned>();
-  NasalParking::init("FGParking")
+  NasalParking::init("Parking")
     .bases<NasalPositioned>();
   NasalCommStation::init("CommStation")
     .bases<NasalPositioned>()
     .member("frequency", &flightgear::CommStation::freqMHz);
+  NasalNavRecord::init("Navaid")
+    .bases<NasalPositioned>()
+    .member("frequency", &FGNavRecord::get_freq)
+    .member("range_nm", &FGNavRecord::get_range)
+    .member("course", &f_navaid_course);
+
+  NasalFix::init("Fix")
+    .bases<NasalPositioned>();
+  
   NasalAirport::init("FGAirport")
     .bases<NasalPositioned>()
     .member("has_metar", &FGAirport::getMetar)
@@ -330,11 +504,21 @@ naRef initNasalPositioned_cppbind(naRef globalsRef, naContext c, naRef gcSave)
     .method("getStar", &FGAirport::findSTARWithIdent)
     .method("getIAP", &FGAirport::findApproachWithIdent)
     .method("tostring", &FGAirport::toString);
-
+  }
+    
   nasal::Hash globals(globalsRef, c),
               positioned( globals.createHash("positioned") );
 
   positioned.set("airportinfo", &f_airportinfo);
-
+  positioned.set("findAirportsWithinRange", f_findAirportsWithinRange);
+  positioned.set("findAirportsByICAO", &f_findAirportsByICAO);
+  positioned.set("navinfo", &f_navinfo);
+  
+  positioned.set("findWithinRange", &f_findWithinRange);
+  positioned.set("findByIdent", &f_findByIdent);
+  positioned.set("findByName", &f_findByName);
+  positioned.set("courseAndDistance", &f_courseAndDistance);
+  positioned.set("sortByRange", &f_sortByRange);
+  
   return naNil();
 }