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:
parent
fa898e7cd6
commit
4c0965e3c1
4 changed files with 98 additions and 15 deletions
|
@ -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)
|
||||||
{
|
{
|
||||||
|
do {
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
return waypoints.end();
|
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());
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue