1
0
Fork 0

Some initial tests for route discontinuities.

Probably many more to add, but this is some basic testing at least of
inserting, querying and removing discontinuities.
This commit is contained in:
James Turner 2020-04-15 16:11:33 +01:00
parent fa898e7cd6
commit 4c0965e3c1
4 changed files with 98 additions and 15 deletions

View file

@ -287,7 +287,8 @@ public:
// compute leg courses for all static legs (both ends are fixed) // compute leg courses for all static legs (both ends are fixed)
void initPass1(const WayptData& previous, WayptData* next) void initPass1(const WayptData& previous, WayptData* next)
{ {
if (wpt->type() == "vectors") { const auto ty = wpt->type();
if ((ty == "vectors") || (ty == "discontinuity")) {
// relying on the fact vectors will be followed by a static fix/wpt // relying on the fact vectors will be followed by a static fix/wpt
if (next && next->posValid) { if (next && next->posValid) {
posValid = true; posValid = true;
@ -295,7 +296,7 @@ public:
} }
} }
if (wpt->type() == "via") { if (ty == "via") {
// even though both ends may be known, we don't // even though both ends may be known, we don't
// want to compute a leg course for a VIA // want to compute a leg course for a VIA
} else if (posValid && !legCourseValid && previous.posValid) { } else if (posValid && !legCourseValid && previous.posValid) {
@ -309,7 +310,11 @@ public:
// use the runway departure end pos // use the runway departure end pos
FGRunway* rwy = static_cast<RunwayWaypt*>(previous.wpt.get())->runway(); FGRunway* rwy = static_cast<RunwayWaypt*>(previous.wpt.get())->runway();
legCourseTrue = SGGeodesy::courseDeg(rwy->end(), pos); legCourseTrue = SGGeodesy::courseDeg(rwy->end(), pos);
} else if (wpt->type() != "runway") { } else if (ty == "discontinuity") {
// we want to keep the path across DISCONs sharp (no turn entry/exit)
// so we keep the leg course invalid, even though we actually
// could compute it
} else if (ty != "runway") {
// need to wait to compute runway leg course // need to wait to compute runway leg course
legCourseTrue = SGGeodesy::courseDeg(previous.pos, pos); legCourseTrue = SGGeodesy::courseDeg(previous.pos, pos);
legCourseValid = true; legCourseValid = true;
@ -323,7 +328,7 @@ public:
return; return;
} }
if ((wpt->type() == "discontinuity") || (wpt->type() == "via")) if ((wpt->type() == "via") || (wpt->type() == "discontinuty"))
{ {
// do nothing, we can't compute a valid leg course for these types // do nothing, we can't compute a valid leg course for these types
// we'll generate sharp turns in the path but that's no problem. // we'll generate sharp turns in the path but that's no problem.
@ -792,14 +797,13 @@ public:
WayptDataVec::iterator previousValidWaypoint(unsigned int index) WayptDataVec::iterator previousValidWaypoint(unsigned int index)
{ {
if (index == 0) { do {
return waypoints.end(); if (index == 0) {
} return waypoints.end();
}
while (waypoints[--index].skipped) { --index;
// waypoint zero should be unskippable, this assert verified that } while (waypoints.at(index).skipped || (waypoints.at(index).wpt->type() == "discontinuity"));
assert(index > 0);
}
return waypoints.begin() + index; return waypoints.begin() + index;
} }
@ -822,7 +826,7 @@ public:
} }
++it; ++it;
while ((it != waypoints.end()) && it->skipped) { while ((it != waypoints.end()) && (it->skipped || (it->wpt->type() == "discontinuity"))) {
++it; ++it;
} }
return it; return it;
@ -870,7 +874,8 @@ void RoutePath::commonInit()
for (unsigned int i=1; i<d->waypoints.size(); ++i) { for (unsigned int i=1; i<d->waypoints.size(); ++i) {
WayptData* nextPtr = ((i + 1) < d->waypoints.size()) ? &d->waypoints[i+1] : nullptr; WayptData* nextPtr = ((i + 1) < d->waypoints.size()) ? &d->waypoints[i+1] : nullptr;
d->waypoints[i].initPass1(d->waypoints[i-1], nextPtr); auto prev = d->previousValidWaypoint(i);
d->waypoints[i].initPass1(*prev, nextPtr);
} }
for (unsigned int i=0; i<d->waypoints.size(); ++i) { for (unsigned int i=0; i<d->waypoints.size(); ++i) {
@ -1073,10 +1078,15 @@ double RoutePath::computeDistanceForIndex(int index) const
return 0.0; return 0.0;
} }
if (it->wpt->type() == "via") { const auto ty = it->wpt->type();
if (ty == "via") {
return distanceForVia(static_cast<Via*>(it->wpt.get()), index); return distanceForVia(static_cast<Via*>(it->wpt.get()), index);
} }
if (ty == "discontinuity") {
return 0.0;
}
auto prevIt = d->previousValidWaypoint(index); auto prevIt = d->previousValidWaypoint(index);
assert(prevIt != d->waypoints.end()); assert(prevIt != d->waypoints.end());

View file

@ -156,6 +156,10 @@ void populateFPWithoutNasal(flightgear::FlightPlanRef f,
for (auto ws : simgear::strutils::split(waypoints)) { for (auto ws : simgear::strutils::split(waypoints)) {
WayptRef wpt = f->waypointFromString(ws); WayptRef wpt = f->waypointFromString(ws);
if (!wpt) {
SG_LOG(SG_NAVAID, SG_ALERT, "No waypoint created for:" << ws);
continue;
}
f->insertWayptAtIndex(wpt, -1); f->insertWayptAtIndex(wpt, -1);
} }

View file

@ -394,3 +394,68 @@ void FlightplanTests::testLoadSaveMachRestriction()
CPPUNIT_ASSERT_EQUAL(8, f2->legAtIndex(2)->holdCount()); CPPUNIT_ASSERT_EQUAL(8, f2->legAtIndex(2)->holdCount());
} }
void FlightplanTests::testBasicDiscontinuity()
{
FlightPlanRef fp1 = makeTestFP("LIRF", "34L", "LEBL", "25R",
"ESINO GITRI BALEN MUREN TOSNU");
const auto tdBefore = fp1->totalDistanceNm();
const SGGeod balenPos = fp1->legAtIndex(3)->waypoint()->position();
const SGGeod murenPos = fp1->legAtIndex(4)->waypoint()->position();
// total distance should not change
fp1->insertWayptAtIndex(new Discontinuity(fp1), 4); // betwee BALEN and MUREN
CPPUNIT_ASSERT_DOUBLES_EQUAL(tdBefore, fp1->totalDistanceNm(), 1.0);
CPPUNIT_ASSERT_DOUBLES_EQUAL(fp1->legAtIndex(4)->courseDeg(),
SGGeodesy::courseDeg(balenPos, murenPos), 0.1);
CPPUNIT_ASSERT_DOUBLES_EQUAL(fp1->legAtIndex(4)->distanceNm(), 0.0, 0.1);
CPPUNIT_ASSERT_DOUBLES_EQUAL(fp1->legAtIndex(5)->courseDeg(),
SGGeodesy::courseDeg(balenPos, murenPos), 0.1);
CPPUNIT_ASSERT_DOUBLES_EQUAL(fp1->legAtIndex(5)->distanceNm(),
SGGeodesy::distanceNm(balenPos, murenPos), 0.1);
// remove the discontinuity
fp1->deleteIndex(4);
CPPUNIT_ASSERT_DOUBLES_EQUAL(fp1->legAtIndex(4)->courseDeg(),
SGGeodesy::courseDeg(balenPos, murenPos), 0.1);
CPPUNIT_ASSERT_DOUBLES_EQUAL(fp1->legAtIndex(4)->distanceNm(),
SGGeodesy::distanceNm(balenPos, murenPos), 0.1);
CPPUNIT_ASSERT_DOUBLES_EQUAL(tdBefore, fp1->totalDistanceNm(), 1.0);
}
void FlightplanTests::testOnlyDiscontinuityRoute()
{
FlightPlanRef f = new FlightPlan;
FGAirportRef depApt = FGAirport::getByIdent("LFBD");
f->setDeparture(depApt);
FGAirportRef destApt = FGAirport::getByIdent("EHAM");
f->setDestination(destApt);
f->insertWayptAtIndex(new Discontinuity(f), 0);
RoutePath rp1(f);
// discontinuity should act like a straight segment between preceeding and following
const double d = SGGeodesy::distanceNm(depApt->geod(), destApt->geod());
// CPPUNIT_ASSERT_DOUBLES_EQUAL(rp1.distanceForIndex(0), d, 0.5);
// start inserting waypoints ahead of the DISCON, Boeing FPL style
WayptRef wpt = f->waypointFromString("LMG");
f->insertWayptAtIndex(wpt, 0);
wpt = f->waypointFromString("KUKOR");
f->insertWayptAtIndex(wpt, 1);
wpt = f->waypointFromString("EPL");
f->insertWayptAtIndex(wpt, 2);
}

View file

@ -41,6 +41,8 @@ class FlightplanTests : public CppUnit::TestFixture
CPPUNIT_TEST(testRoutPathWpt0Midflight); CPPUNIT_TEST(testRoutPathWpt0Midflight);
CPPUNIT_TEST(testRoutePathVec); CPPUNIT_TEST(testRoutePathVec);
CPPUNIT_TEST(testLoadSaveMachRestriction); CPPUNIT_TEST(testLoadSaveMachRestriction);
CPPUNIT_TEST(testOnlyDiscontinuityRoute);
CPPUNIT_TEST(testBasicDiscontinuity);
// CPPUNIT_TEST(testParseICAORoute); // CPPUNIT_TEST(testParseICAORoute);
// CPPUNIT_TEST(testParseICANLowLevelRoute); // CPPUNIT_TEST(testParseICANLowLevelRoute);
@ -66,6 +68,8 @@ public:
void testRoutPathWpt0Midflight(); void testRoutPathWpt0Midflight();
void testRoutePathVec(); void testRoutePathVec();
void testLoadSaveMachRestriction(); void testLoadSaveMachRestriction();
void testBasicDiscontinuity();
void testOnlyDiscontinuityRoute();
}; };
#endif // FG_FLIGHTPLAN_UNIT_TESTS_HXX #endif // FG_FLIGHTPLAN_UNIT_TESTS_HXX