1
0
Fork 0

Waypoint hiding support (for the A320, etc)

To support FMS which delete ‘past’ waypoints, add some helpers:
 - waypoints can be flagged as hidden, this property is exposed to Nasal
 - currentWP() accepts an offset parameter, allowing FlightPlan indexing
   to treat the current WP as index 0
 - a ‘numRemainingWaypoints()’ function on flightPlan in Nasal, again
   to range how many waypoints are left, starting from the current WP

Add some basic tests of these new features to the route-manager tests.
This commit is contained in:
James Turner 2020-04-30 20:00:43 +01:00
parent 100efeebab
commit 6baa55b36b
5 changed files with 138 additions and 39 deletions

View file

@ -76,7 +76,10 @@ typedef enum {
WPT_APPROACH = 1 << 11,
/// waypoint prodcued by expanding a VIA segment
WPT_VIA = 1 << 12
WPT_VIA = 1 << 12,
// waypoint should be hidden from maps, etc
WPT_HIDDEN = 1 << 13
} WayptFlag;
typedef enum {

View file

@ -942,16 +942,21 @@ SGGeodVec RoutePath::pathForIndex(int index) const
SGGeodVec r;
if (d->waypoints[index].skipped) {
return SGGeodVec();
return {};
}
// don't show any path
if (w.wpt->flag(WPT_HIDDEN)) {
return {};
}
if (ty == "vectors") {
// ideally we'd show a stippled line to connect the route?
return SGGeodVec();
return {};
}
if (ty == "discontinuity") {
return SGGeodVec(); // no points for a discontinuity of course
return {}; // no points for a discontinuity of course
}
if (ty == "via") {

View file

@ -561,6 +561,8 @@ static const char* waypointCommonGetMember(naContext c, Waypt* wpt, const char*
} else {
*out = naNil();
}
} else if (!strcmp(fieldName, "hidden")) {
*out = naNum(wpt->flag(WPT_HIDDEN));
} else if (wpt->type() == "hold") {
// hold-specific properties
const auto hold = static_cast<Hold*>(wpt);
@ -603,6 +605,9 @@ static bool waypointCommonSetMember(naContext c, Waypt* wpt, const char* fieldNa
if (!naIsString(value)) naRuntimeError(c, "fly_type must be a string");
bool flyOver = (strcmp(naStr_data(value), "flyOver") == 0);
wpt->setFlag(WPT_OVERFLIGHT, flyOver);
} else if (!strcmp(fieldName, "hidden")) {
if (!naIsNum(value)) naRuntimeError(c, "wpt.hidden must be a number");
wpt->setFlag(WPT_HIDDEN, static_cast<int>(value.num) != 0);
} else if (wpt->type() == "hold") {
const auto hold = static_cast<Hold*>(wpt);
if (!strcmp(fieldName, "hold_heading_radial_deg")) {
@ -2834,7 +2839,17 @@ static naRef f_flightplan_currentWP(naContext c, naRef me, int argc, naRef* args
if (!fp) {
naRuntimeError(c, "flightplan.currentWP called on non-flightplan object");
}
return ghostForLeg(c, fp->currentLeg());
int index = fp->currentIndex();
if (argc > 0) {
index += static_cast<int>(naNumValue(args[0]).num);
}
if ((index < 0) || (index >= fp->numLegs())) {
return naNil();
}
return ghostForLeg(c, fp->legAtIndex(index));
}
static naRef f_flightplan_nextWP(naContext c, naRef me, int argc, naRef* args)
@ -2855,6 +2870,21 @@ static naRef f_flightplan_numWaypoints(naContext c, naRef me, int argc, naRef* a
return naNum(fp->numLegs());
}
static naRef f_flightplan_numRemainingWaypoints(naContext c, naRef me, int argc, naRef* args)
{
FlightPlan* fp = flightplanGhost(me);
if (!fp) {
naRuntimeError(c, "flightplan.f_flightplan_numRemainingWaypoints called on non-flightplan object");
}
// for an inactive flightplan, just reutnr the total number of WPs
if (fp->currentIndex() < 0) {
return naNum(fp->numLegs());
}
return naNum(fp->numLegs() - fp->currentIndex());
}
static naRef f_flightplan_appendWP(naContext c, naRef me, int argc, naRef* args)
{
FlightPlan* fp = flightplanGhost(me);
@ -3382,6 +3412,8 @@ naRef initNasalPositioned(naRef globals, naContext c)
hashset(c, flightplanPrototype, "getPlanSize", naNewFunc(c, naNewCCode(c, f_flightplan_numWaypoints)));
// alias to this name also
hashset(c, flightplanPrototype, "numWaypoints", naNewFunc(c, naNewCCode(c, f_flightplan_numWaypoints)));
hashset(c, flightplanPrototype, "numRemainingWaypoints", naNewFunc(c, naNewCCode(c, f_flightplan_numRemainingWaypoints)));
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)));

View file

@ -11,6 +11,7 @@
#include <Navaids/NavDataCache.hxx>
#include <Navaids/navrecord.hxx>
#include <Navaids/navlist.hxx>
#include <Navaids/routePath.hxx>
// we need a default GPS instrument, hard to test seperately for now
#include <Instrumentation/gps.hxx>
@ -360,6 +361,62 @@ void RouteManagerTests::testDefaultApproach()
}
void RouteManagerTests::testHiddenWaypoints()
{
FlightPlanRef fp1 = makeTestFP("NZCH", "02", "NZAA", "05L",
"ALADA NS WB WN MAMOD KAPTI OH");
fp1->setIdent("testplan");
fp1->setCruiseFlightLevel(360);
auto rm = globals->get_subsystem<FGRouteMgr>();
rm->setFlightPlan(fp1);
auto gpsNode = globals->get_props()->getNode("instrumentation/gps", true);
CPPUNIT_ASSERT(!strcmp("obs", gpsNode->getStringValue("mode")));
// FIXME: use real Nasal test macros soon
auto testNode = globals->get_props()->getNode("test-data", true);
fp1->legAtIndex(3)->waypoint()->setFlag(WPT_HIDDEN);
// ensure no visual path is generated for hidden waypoints
RoutePath path(fp1);
CPPUNIT_ASSERT(path.pathForIndex(3).empty());
bool ok = FGTestApi::executeNasal(R"(
var fp = flightplan(); # retrieve the global flightplan
setprop("/test-data/a", fp.numRemainingWaypoints());
)");
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(fp1->numLegs(), testNode->getIntValue("a"));
rm->activate();
fp1->setCurrentIndex(2);
ok = FGTestApi::executeNasal(R"(
var fp = flightplan(); # retrieve the global flightplan
setprop("/test-data/a", fp.numRemainingWaypoints());
setprop("/test-data/b", fp.currentWP(2).id);
)");
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(7, testNode->getIntValue("a"));
CPPUNIT_ASSERT_EQUAL(std::string{"WN"}, std::string{testNode->getStringValue("b")});
ok = FGTestApi::executeNasal(R"(
var fp = flightplan(); # retrieve the global flightplan
setprop("/test-data/c", fp.currentWP(-1).id);
# ensure invalid offset returns nil
setprop("/test-data/d", fp.currentWP(-100) == nil);
)");
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(std::string{"ALADA"}, std::string{testNode->getStringValue("c")});
CPPUNIT_ASSERT_EQUAL(true, testNode->getBoolValue("d"));
}
void RouteManagerTests::testHoldFromNasal()
{
// FGTestApi::setUp::logPositionToKML("rm_hold_from_nasal");

View file

@ -39,6 +39,7 @@ class RouteManagerTests : public CppUnit::TestFixture
CPPUNIT_TEST(testDirectToLegOnFlightplanAndResume);
CPPUNIT_TEST(testHoldFromNasal);
CPPUNIT_TEST(testSequenceDiscontinuityAndResume);
CPPUNIT_TEST(testHiddenWaypoints);
CPPUNIT_TEST_SUITE_END();
@ -60,6 +61,7 @@ public:
void testDirectToLegOnFlightplanAndResume();
void testHoldFromNasal();
void testSequenceDiscontinuityAndResume();
void testHiddenWaypoints();
private:
GPS* m_gps = nullptr;
};