+/**
+ * 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) );
+}
+
+//------------------------------------------------------------------------------
+
+static naRef f_courseAndDistance(nasal::CallContext ctx)
+{
+ 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);
+}
+
+//------------------------------------------------------------------------------
+// Get difference between two lists of positioned objects.
+//
+// For every element in old_list not in new_list the callback cb_remove is
+// called with the removed element as single argument. For every element in
+// new_list not in old_list cb_add is called.
+//
+// diff(old_list, new_list, cb_add[, cb_remove])
+//
+// example:
+// # Print all fixes within a distance of 320 to 640 miles
+// diff( findWithinRange(320, "fix"),
+// findWithinRange(640, "fix"),
+// func(p) print('found fix: ', p.id) );
+static naRef f_diff(nasal::CallContext ctx)
+{
+ typedef simgear::ListDiff<FGPositionedRef> Diff;
+ Diff::List old_list = ctx.requireArg<FGPositionedList>(0),
+ new_list = ctx.requireArg<FGPositionedList>(1);
+ Diff::Callback cb_add = ctx.requireArg<Diff::Callback>(2),
+ cb_rm = ctx.getArg<Diff::Callback>(3);
+
+ // Note that FGPositionedRef instances are only compared for pointer equality.
+ // As the NavCache caches every queried positioned instance it is guaranteed
+ // that only one instance of every positioned object can exist. Therefore we
+ // can make the comparison faster by just comparing pointers and not also the
+ // guid.
+ // (On my machine the difference is 0.27s vs 0.17s)
+ Diff::inplace(old_list, new_list, cb_add, cb_rm);
+
+ return naNil();
+}
+