1
0
Fork 0

Traffic: preemptable flight scheduling

FGAISchedule::update can be time consuming. Preempt when necessary to
avoid simulation lags, and call it every sim iteration, until the flight
plan is complete.
This commit is contained in:
ThorstenB 2012-11-25 16:41:10 +01:00
parent 7d88714e2d
commit b682ae91d6
3 changed files with 88 additions and 46 deletions

View file

@ -70,7 +70,8 @@ FGAISchedule::FGAISchedule()
firstRun(false),
courseToDest(0),
initialized(false),
valid(false)
valid(false),
scheduleComplete(false)
{
}
@ -98,7 +99,8 @@ FGAISchedule::FGAISchedule(const string& model,
firstRun(true),
courseToDest(0),
initialized(false),
valid(true)
valid(true),
scheduleComplete(false)
{
modelPath = model;
livery = lvry;
@ -139,8 +141,10 @@ FGAISchedule::FGAISchedule(const FGAISchedule &other)
runCount = other.runCount;
hits = other.hits;
lastRun = other.lastRun;
courseToDest = other.courseToDest;
initialized = other.initialized;
valid = other.valid;
scheduleComplete = other.scheduleComplete;
}
@ -186,22 +190,37 @@ bool FGAISchedule::init()
return true;
}
/**
* Returns true when processing is complete.
* Returns false when processing was aborted due to timeout, so
* more time required - and another call is requested (next sim iteration).
*/
bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
{
time_t
totalTimeEnroute,
elapsedTimeEnroute,
//remainingTimeEnroute,
deptime = 0;
{
time_t totalTimeEnroute,
elapsedTimeEnroute,
//remainingTimeEnroute,
deptime = 0;
if (!valid) {
return false;
return true; // processing complete
}
scheduleFlights(now);
if (!scheduleComplete) {
scheduleComplete = scheduleFlights(now);
}
if (!scheduleComplete) {
return false; // not ready yet, continue processing in next iteration
}
if (flights.empty()) { // No flights available for this aircraft
valid = false;
return false;
return true; // processing complete
}
// Sort all the scheduled flights according to scheduled departure time.
// Because this is done at every update, we only need to check the status
// of the first listed flight.
@ -238,13 +257,13 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
// and detach it from the current list of aircraft.
flight->update();
flights.erase(flights.begin()); // pop_front(), effectively
return true;
return true; // processing complete
}
FGAirport* dep = flight->getDepartureAirport();
FGAirport* arr = flight->getArrivalAirport();
if (!dep || !arr) {
return false;
return true; // processing complete
}
double speed = 450.0;
@ -285,7 +304,8 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
// large distances involved here: see bug #80
distanceToUser = dist(userCart, SGVec3d::fromGeod(position)) * SG_METER_TO_NM;
// If distance between user and simulated aircaft is less
// If distance between user and simulated aircraft is less
// then 500nm, create this flight. At jet speeds 500 nm is roughly
// one hour flight time, so that would be a good approximate point
// to start a more detailed simulation of this aircraft.
@ -295,7 +315,13 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
if (distanceToUser >= TRAFFICTOAIDISTTOSTART) {
return true; // out of visual range, for the moment.
}
return createAIAircraft(flight, speed, deptime);
if (!createAIAircraft(flight, speed, deptime)) {
valid = false;
}
return true; // processing complete
}
bool FGAISchedule::validModelPath(const std::string& modelPath)
@ -373,30 +399,32 @@ void FGAISchedule::setHeading()
courseToDest = SGGeodesy::courseDeg((*flights.begin())->getDepartureAirport()->geod(), (*flights.begin())->getArrivalAirport()->geod());
}
void FGAISchedule::scheduleFlights(time_t now)
bool FGAISchedule::scheduleFlights(time_t now)
{
if (!flights.empty()) {
return;
}
//string startingPort;
string userPort = fgGetString("/sim/presets/airport-id");
const string& userPort = fgGetString("/sim/presets/airport-id");
SG_LOG(SG_AI, SG_BULK, "Scheduling Flights for : " << modelPath << " " << registration << " " << homePort);
FGScheduledFlight *flight = NULL;
SGTimeStamp start;
start.stamp();
bool first = true;
if (currentDestination.empty())
flight = findAvailableFlight(userPort, flightIdentifier, now, (now+6400));
do {
if (currentDestination.empty()) {
flight = findAvailableFlight(userPort, flightIdentifier, now, (now+6400));
if (!flight)
flight = findAvailableFlight(currentDestination, flightIdentifier);
} else {
if ((!flight)||(!first)) {
flight = findAvailableFlight(currentDestination, flightIdentifier);
}
if (!flight) {
break;
}
first = false;
currentDestination = flight->getArrivalAirport()->getId();
//cerr << "Current destination " << currentDestination << endl;
if (!initialized) {
string departurePort = flight->getDepartureAirport()->getId();
const string& departurePort = flight->getDepartureAirport()->getId();
if (userPort == departurePort) {
lastRun = 1;
hits++;
@ -407,23 +435,36 @@ void FGAISchedule::scheduleFlights(time_t now)
initialized = true;
}
time_t arr, dep;
dep = flight->getDepartureTime();
arr = flight->getArrivalTime();
string depT = asctime(gmtime(&dep));
string arrT = asctime(gmtime(&arr));
depT = depT.substr(0,24);
arrT = arrT.substr(0,24);
SG_LOG(SG_AI, SG_BULK, " Flight " << flight->getCallSign() << ":"
<< " " << flight->getDepartureAirport()->getId() << ":"
<< " " << depT << ":"
<< " \"" << flight->getArrivalAirport()->getId() << "\"" << ":"
<< " " << arrT << ":");
if (sglog().would_log(SG_AI, SG_BULK))
{
time_t arr, dep;
dep = flight->getDepartureTime();
arr = flight->getArrivalTime();
string depT = asctime(gmtime(&dep));
string arrT = asctime(gmtime(&arr));
depT = depT.substr(0,24);
arrT = arrT.substr(0,24);
SG_LOG(SG_AI, SG_BULK, " Flight " << flight->getCallSign() << ":"
<< " " << flight->getDepartureAirport()->getId() << ":"
<< " " << depT << ":"
<< " \"" << flight->getArrivalAirport()->getId() << "\"" << ":"
<< " " << arrT << ":");
}
flights.push_back(flight);
} while (currentDestination != homePort);
// continue processing until complete, or preempt after timeout
} while ((currentDestination != homePort)&&
(start.elapsedMSec()<3.0));
if (flight && (currentDestination != homePort))
{
// processing preempted, need to continue in next iteration
return false;
}
SG_LOG(SG_AI, SG_BULK, " Done ");
return true;
}
bool FGAISchedule::next()

View file

@ -62,8 +62,9 @@ class FGAISchedule
double courseToDest;
bool initialized;
bool valid;
bool scheduleComplete;
void scheduleFlights(time_t now);
bool scheduleFlights(time_t now);
int groundTimeFromRadius();
/**
@ -132,7 +133,6 @@ class FGAISchedule
// used to sort in descending order of score: I've probably found a better way to
// descending order sorting, but still need to test that.
bool operator< (const FGAISchedule &other) const;
void taint() { valid = false; };
int getLastUsed() { return lastRun; };
void setLastUsed(unsigned int val) {lastRun = val; };
//void * getAiRef () { return AIManagerRef; };

View file

@ -411,11 +411,12 @@ void FGTrafficManager::update(double dt)
if (currAircraft == scheduledAircraft.end()) {
currAircraft = scheduledAircraft.begin();
}
//cerr << "Processing << " << (*currAircraft)->getRegistration() << " with score " << (*currAircraft)->getScore() << endl;
if (!((*currAircraft)->update(now, userCart))) {
(*currAircraft)->taint();
if ((*currAircraft)->update(now, userCart)) {
// schedule is done - process another aircraft in next iteration
currAircraft++;
}
currAircraft++;
}
void FGTrafficManager::readTimeTableFromFile(SGPath infileName)