1
0
Fork 0

Reposition: tolerate more scenarios in ATC_mgr

When starting at an airport, but not at parking or a runway, create
an empty AIFlightPlan, and ensure the AIManager code doesn’t choke on
empty FPs.

Add a unit-test which simulates the C172 tutorial reposition logic,
which is a little gnarly.
This commit is contained in:
James Turner 2020-10-27 18:05:23 +00:00
parent 46435edf19
commit 423c754009
7 changed files with 113 additions and 31 deletions

View file

@ -1022,7 +1022,7 @@ void FGAIAircraft::controlSpeed(FGAIWaypoint* curr, FGAIWaypoint* next) {
* Update target values (heading, alt, speed) depending on flight plan or control properties
*/
void FGAIAircraft::updatePrimaryTargetValues(double dt, bool& flightplanActive, bool& aiOutOfSight) {
if (fp) // AI object has a flightplan
if (fp && fp->isValidPlan()) // AI object has a flightplan
{
//TODO make this a function of AIBase
time_t now = globals->get_time_params()->get_cur_time();

View file

@ -327,12 +327,15 @@ FGAIWaypoint* FGAIFlightPlan::getLastWaypoint()
FGAIWaypoint* FGAIFlightPlan::getPreviousWaypoint( void ) const
{
if (wpt_iterator == waypoints.begin()) {
return nullptr;
} else {
wpt_vector_iterator prev = wpt_iterator;
return *(--prev);
}
if (empty())
return nullptr;
if (wpt_iterator == waypoints.begin()) {
return nullptr;
} else {
wpt_vector_iterator prev = wpt_iterator;
return *(--prev);
}
}
FGAIWaypoint* FGAIFlightPlan::getCurrentWaypoint( void ) const
@ -357,6 +360,9 @@ FGAIWaypoint* FGAIFlightPlan::getNextWaypoint( void ) const
void FGAIFlightPlan::IncrementWaypoint(bool eraseWaypoints )
{
if (empty())
return;
if (eraseWaypoints)
{
if (wpt_iterator == waypoints.begin())
@ -376,11 +382,17 @@ void FGAIFlightPlan::IncrementWaypoint(bool eraseWaypoints )
void FGAIFlightPlan::DecrementWaypoint()
{
wpt_iterator--;
if (empty())
return;
wpt_iterator--;
}
void FGAIFlightPlan::eraseLastWaypoint()
{
if (empty())
return;
delete (waypoints.back());
waypoints.pop_back();;
wpt_iterator = waypoints.begin();
@ -559,3 +571,15 @@ FGAirportRef FGAIFlightPlan::arrivalAirport() const
{
return arrival;
}
FGAIFlightPlan* FGAIFlightPlan::createDummyUserPlan()
{
FGAIFlightPlan* fp = new FGAIFlightPlan;
fp->isValid = false;
return fp;
}
bool FGAIFlightPlan::empty() const
{
return waypoints.empty();
}

View file

@ -150,6 +150,12 @@ public:
~FGAIFlightPlan();
/**
@brief create a neatrly empty FlightPlan for the user aircraft, based
on the current position and route-manager data.
*/
static FGAIFlightPlan* createDummyUserPlan();
/**
@brief read a flight-plan from a file.
All current contents of the flight-plan are replaxced, and the current waypoint is reset to the beginning
*/
@ -220,6 +226,9 @@ public:
FGAirportRef departureAirport() const;
FGAirportRef arrivalAirport() const;
bool empty() const;
private:
FGAIFlightPlan *sid;
typedef std::vector <FGAIWaypoint*> wpt_vector_type;

View file

@ -191,19 +191,20 @@ void FGATCManager::postinit()
userAircraft->setTakeOffStatus(2);
} else {
// We're on the ground somewhere. Handle this case later.
// important : we are on the ground, so reset the AIFlightPlan back to
// an empty one. Otherwise, in the reposition case, we end up with a
// a dummy one. Otherwise, in the reposition case, we end up with a
// stale flight-plan which confuses other code (eg, PositionInit::finalizeForParking)
// see unit test: PosInitTests::testRepositionAtOccupied
fp.reset(FGAIFlightPlan::createDummyUserPlan());
userAircraft->FGAIBase::setFlightPlan(std::move(fp));
controller = nullptr;
initSucceeded = true; // should be false?
return;
}
if (fp) {
if (fp && !fp->empty()) {
fp->getLastWaypoint()->setName( fp->getLastWaypoint()->getName() + string("legend"));
}
} else {
@ -222,7 +223,9 @@ void FGATCManager::postinit()
if (controller) {
FGAIFlightPlan* plan = userAircraft->GetFlightPlan();
controller->announcePosition(userAircraft->getID(), plan, plan->getCurrentWaypoint()->getRouteIndex(),
const int routeIndex = (plan && plan->getCurrentWaypoint()) ? plan->getCurrentWaypoint()->getRouteIndex() : 0;
controller->announcePosition(userAircraft->getID(), plan,
routeIndex,
userAircraft->_getLatitude(),
userAircraft->_getLongitude(),
userAircraft->_getHeading(),
@ -319,7 +322,6 @@ void FGATCManager::update ( double time ) {
// user should be able to select a new route, but for now just shut down the
// system.
if (size < 3) {
SG_LOG(SG_ATC, SG_INFO, "Shutting down the atc_mgr - ran out of waypoints");
return;
}
#if 0

View file

@ -600,6 +600,10 @@ bool initPosition()
bool set_pos = false;
// clear this value, so we don't preserve an old value and confuse
// the ATC manager. We will set it again if it's valid
fgSetString("/sim/atc/runway", "");
// If glideslope is specified, then calculate offset-distance or
// altitude relative to glide slope if either of those was not
// specified.
@ -683,9 +687,6 @@ bool initPosition()
// until position finalisation
// the rest of the work happens in finalizePosFromParkpos
if ( airportParkingSetVicinity( apt ) ) {
// set tower position
fgSetString("/sim/airport/closest-airport-id", apt.c_str());
fgSetString("/sim/tower/airport-id", apt.c_str());
set_pos = true;
}
}
@ -693,10 +694,6 @@ bool initPosition()
if ( !set_pos && !apt.empty() && !rwy_no.empty() ) {
// An airport + runway is requested
if ( fgSetPosFromAirportIDandRwy( apt, rwy_no, rwy_req ) ) {
// set tower position (a little off the heading for single
// runway airports)
fgSetString("/sim/airport/closest-airport-id", apt.c_str());
fgSetString("/sim/tower/airport-id", apt.c_str());
set_pos = true;
}
}
@ -704,14 +701,18 @@ bool initPosition()
if ( !set_pos && !apt.empty() ) {
// An airport is requested (find runway closest to hdg)
if ( setPosFromAirportIDandHdg( apt, hdg ) ) {
// set tower position (a little off the heading for single
// runway airports)
fgSetString("/sim/airport/closest-airport-id", apt.c_str());
fgSetString("/sim/tower/airport-id", apt.c_str());
set_pos = true;
}
}
// if an airport ID was requested, set closest-airport-id
// and tower based upon it.
if (!apt.empty() && set_pos) {
// set tower position
fgSetString("/sim/airport/closest-airport-id", apt.c_str());
fgSetString("/sim/tower/airport-id", apt.c_str());
}
if (original_hdg < 9990.0) {
// The user-set heading may be overridden by the setPosFromAirportID above.
SG_LOG(SG_GENERAL, SG_ALERT, "Setting heading preset to : " << original_hdg);

View file

@ -177,10 +177,6 @@ void PosInitTests::testAirportAltitudeOffsetStartup()
CPPUNIT_ASSERT(fgGetBool("/sim/presets/airport-requested"));
initPosition();
initPosition();
SGGeod expectedPos = SGGeodesy::direct(FGAirport::getByIdent("EDDF")->geod(), 270, 5 * SG_NM_TO_METER);
checkPosition(expectedPos, 5000.0);
@ -616,6 +612,53 @@ void PosInitTests::testAirportRepositionAirport()
}
// this simulates what the C172 preflight tutorial does,
// where the user is likely at a random airport (on a runway), and starts
// the preflight tutorial, which repositions them to a ramp location
// at PHTO
void PosInitTests::testAirportRunwayRepositionAirport()
{
{
Options* opts = Options::sharedInstance();
opts->setShouldLoadDefaultConfig(false);
const char* args[] = {"dummypath", "--airport=EDDS", "--runway=07"};
opts->init(3, (char**)args, SGPath());
opts->processOptions();
}
CPPUNIT_ASSERT(fgGetBool("/sim/presets/airport-requested"));
CPPUNIT_ASSERT(fgGetBool("/sim/presets/runway-requested"));
checkRunway(std::string("07"));
initPosition();
simulateFinalizePosition();
checkClosestAirport(std::string("EDDS"));
checkPosition(FGAirport::getByIdent("EDDS")->geod(), 10000.0);
// Now re-position to PHTO runway
// Reset the Lat/Lon as these will be used in preference to the airport ID
fgSetDouble("/sim/presets/longitude-deg", -155.0597483);
fgSetDouble("/sim/presets/latitude-deg", 19.71731272);
fgSetString("/sim/presets/airport-id", "PHTO");
fgSetDouble("/sim/presets/heading-deg", 125);
fgSetBool("/sim/presets/on-ground", true);
fgSetBool("/sim/presets/runway-requested", true);
fgSetBool("/sim/presets/airport-requested", true);
fgSetBool("/sim/presets/parking-requested", true);
simulateStartReposition();
finalizePosition();
FGTestApi::runForTime(1.0);
checkClosestAirport(std::string("PHTO"));
checkPosition(FGAirport::getByIdent("PHTO")->geod(), 5000.0);
checkHeading(125);
checkOnGround();
FGTestApi::runForTime(1.0);
}
void PosInitTests::testParkInvalid()
{
{

View file

@ -46,8 +46,9 @@ class PosInitTests : public CppUnit::TestFixture
CPPUNIT_TEST(testRepositionAtParking);
CPPUNIT_TEST(testParkAtOccupied);
CPPUNIT_TEST(testParkInvalid);
CPPUNIT_TEST(testAirportRunwayRepositionAirport);
// Navaid tests
CPPUNIT_TEST(testVOROnlyStartup);
CPPUNIT_TEST(testVOROffsetAltitudeHeadingStartup);
@ -116,6 +117,8 @@ public:
void testRepositionAtSameParking();
void testRepositionAtOccupied();
void testRepositionAtInvalid();
void testAirportRunwayRepositionAirport();
private:
// Helper functions for tests. Return void as they use CPPUNIT_ASSERT
void checkAlt(float value);