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:
parent
100efeebab
commit
6baa55b36b
5 changed files with 138 additions and 39 deletions
src
test_suite/unit_tests/Navaids
|
@ -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 {
|
||||
|
|
|
@ -941,46 +941,51 @@ SGGeodVec RoutePath::pathForIndex(int index) const
|
|||
const std::string& ty(w.wpt->type());
|
||||
SGGeodVec r;
|
||||
|
||||
if (d->waypoints[index].skipped) {
|
||||
return SGGeodVec();
|
||||
}
|
||||
if (d->waypoints[index].skipped) {
|
||||
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();
|
||||
// ideally we'd show a stippled line to connect the route?
|
||||
return {};
|
||||
}
|
||||
|
||||
if (ty == "discontinuity") {
|
||||
return SGGeodVec(); // no points for a discontinuity of course
|
||||
return {}; // no points for a discontinuity of course
|
||||
}
|
||||
|
||||
if (ty == "via") {
|
||||
return pathForVia(static_cast<Via*>(d->waypoints[index].wpt.get()), index);
|
||||
return pathForVia(static_cast<Via*>(d->waypoints[index].wpt.get()), index);
|
||||
}
|
||||
|
||||
auto prevIt = d->previousValidWaypoint(index);
|
||||
if (prevIt != d->waypoints.end()) {
|
||||
prevIt->turnExitPath(r);
|
||||
auto prevIt = d->previousValidWaypoint(index);
|
||||
if (prevIt != d->waypoints.end()) {
|
||||
prevIt->turnExitPath(r);
|
||||
|
||||
SGGeod from = prevIt->turnExitPos,
|
||||
to = w.turnEntryPos;
|
||||
SGGeod from = prevIt->turnExitPos,
|
||||
to = w.turnEntryPos;
|
||||
|
||||
// compute rounding offset, we want to round towards the direction of travel
|
||||
// which depends on the east/west sign of the longitude change
|
||||
double lonDelta = to.getLongitudeDeg() - from.getLongitudeDeg();
|
||||
if (fabs(lonDelta) > 0.5) {
|
||||
interpolateGreatCircle(from, to, r);
|
||||
}
|
||||
} // of have previous waypoint
|
||||
|
||||
w.turnEntryPath(r);
|
||||
|
||||
// hold is the normal leg and then the hold waypoints as well
|
||||
if (ty== "hold") {
|
||||
const auto h = static_cast<Hold*>(d->waypoints[index].wpt.get());
|
||||
const auto holdPath = pathForHold(h);
|
||||
r.insert(r.end(), holdPath.begin(), holdPath.end());
|
||||
// compute rounding offset, we want to round towards the direction of travel
|
||||
// which depends on the east/west sign of the longitude change
|
||||
double lonDelta = to.getLongitudeDeg() - from.getLongitudeDeg();
|
||||
if (fabs(lonDelta) > 0.5) {
|
||||
interpolateGreatCircle(from, to, r);
|
||||
}
|
||||
} // of have previous waypoint
|
||||
|
||||
w.turnEntryPath(r);
|
||||
|
||||
// hold is the normal leg and then the hold waypoints as well
|
||||
if (ty== "hold") {
|
||||
const auto h = static_cast<Hold*>(d->waypoints[index].wpt.get());
|
||||
const auto holdPath = pathForHold(h);
|
||||
r.insert(r.end(), holdPath.begin(), holdPath.end());
|
||||
}
|
||||
|
||||
if (ty == "runway") {
|
||||
// runways get an extra point, at the end. this is particularly
|
||||
|
|
|
@ -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)));
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue