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), firstRun(false),
courseToDest(0), courseToDest(0),
initialized(false), initialized(false),
valid(false) valid(false),
scheduleComplete(false)
{ {
} }
@ -98,7 +99,8 @@ FGAISchedule::FGAISchedule(const string& model,
firstRun(true), firstRun(true),
courseToDest(0), courseToDest(0),
initialized(false), initialized(false),
valid(true) valid(true),
scheduleComplete(false)
{ {
modelPath = model; modelPath = model;
livery = lvry; livery = lvry;
@ -139,8 +141,10 @@ FGAISchedule::FGAISchedule(const FGAISchedule &other)
runCount = other.runCount; runCount = other.runCount;
hits = other.hits; hits = other.hits;
lastRun = other.lastRun; lastRun = other.lastRun;
courseToDest = other.courseToDest;
initialized = other.initialized; initialized = other.initialized;
valid = other.valid; valid = other.valid;
scheduleComplete = other.scheduleComplete;
} }
@ -186,22 +190,37 @@ bool FGAISchedule::init()
return true; 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) bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
{ {
time_t
totalTimeEnroute, time_t totalTimeEnroute,
elapsedTimeEnroute, elapsedTimeEnroute,
//remainingTimeEnroute, //remainingTimeEnroute,
deptime = 0; deptime = 0;
if (!valid) { 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 if (flights.empty()) { // No flights available for this aircraft
valid = false; valid = false;
return false; return true; // processing complete
} }
// Sort all the scheduled flights according to scheduled departure time. // Sort all the scheduled flights according to scheduled departure time.
// Because this is done at every update, we only need to check the status // Because this is done at every update, we only need to check the status
// of the first listed flight. // 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. // and detach it from the current list of aircraft.
flight->update(); flight->update();
flights.erase(flights.begin()); // pop_front(), effectively flights.erase(flights.begin()); // pop_front(), effectively
return true; return true; // processing complete
} }
FGAirport* dep = flight->getDepartureAirport(); FGAirport* dep = flight->getDepartureAirport();
FGAirport* arr = flight->getArrivalAirport(); FGAirport* arr = flight->getArrivalAirport();
if (!dep || !arr) { if (!dep || !arr) {
return false; return true; // processing complete
} }
double speed = 450.0; double speed = 450.0;
@ -285,7 +304,8 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
// large distances involved here: see bug #80 // large distances involved here: see bug #80
distanceToUser = dist(userCart, SGVec3d::fromGeod(position)) * SG_METER_TO_NM; 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 // then 500nm, create this flight. At jet speeds 500 nm is roughly
// one hour flight time, so that would be a good approximate point // one hour flight time, so that would be a good approximate point
// to start a more detailed simulation of this aircraft. // 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) { if (distanceToUser >= TRAFFICTOAIDISTTOSTART) {
return true; // out of visual range, for the moment. 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) 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()); 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 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); SG_LOG(SG_AI, SG_BULK, "Scheduling Flights for : " << modelPath << " " << registration << " " << homePort);
FGScheduledFlight *flight = NULL; FGScheduledFlight *flight = NULL;
SGTimeStamp start;
start.stamp();
bool first = true;
if (currentDestination.empty())
flight = findAvailableFlight(userPort, flightIdentifier, now, (now+6400));
do { do {
if (currentDestination.empty()) { if ((!flight)||(!first)) {
flight = findAvailableFlight(userPort, flightIdentifier, now, (now+6400));
if (!flight)
flight = findAvailableFlight(currentDestination, flightIdentifier);
} else {
flight = findAvailableFlight(currentDestination, flightIdentifier); flight = findAvailableFlight(currentDestination, flightIdentifier);
} }
if (!flight) { if (!flight) {
break; break;
} }
first = false;
currentDestination = flight->getArrivalAirport()->getId(); currentDestination = flight->getArrivalAirport()->getId();
//cerr << "Current destination " << currentDestination << endl; //cerr << "Current destination " << currentDestination << endl;
if (!initialized) { if (!initialized) {
string departurePort = flight->getDepartureAirport()->getId(); const string& departurePort = flight->getDepartureAirport()->getId();
if (userPort == departurePort) { if (userPort == departurePort) {
lastRun = 1; lastRun = 1;
hits++; hits++;
@ -407,23 +435,36 @@ void FGAISchedule::scheduleFlights(time_t now)
initialized = true; initialized = true;
} }
time_t arr, dep; if (sglog().would_log(SG_AI, SG_BULK))
dep = flight->getDepartureTime(); {
arr = flight->getArrivalTime(); time_t arr, dep;
string depT = asctime(gmtime(&dep)); dep = flight->getDepartureTime();
string arrT = asctime(gmtime(&arr)); arr = flight->getArrivalTime();
string depT = asctime(gmtime(&dep));
depT = depT.substr(0,24); string arrT = asctime(gmtime(&arr));
arrT = arrT.substr(0,24); depT = depT.substr(0,24);
SG_LOG(SG_AI, SG_BULK, " Flight " << flight->getCallSign() << ":" arrT = arrT.substr(0,24);
<< " " << flight->getDepartureAirport()->getId() << ":" SG_LOG(SG_AI, SG_BULK, " Flight " << flight->getCallSign() << ":"
<< " " << depT << ":" << " " << flight->getDepartureAirport()->getId() << ":"
<< " \"" << flight->getArrivalAirport()->getId() << "\"" << ":" << " " << depT << ":"
<< " " << arrT << ":"); << " \"" << flight->getArrivalAirport()->getId() << "\"" << ":"
<< " " << arrT << ":");
}
flights.push_back(flight); 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 "); SG_LOG(SG_AI, SG_BULK, " Done ");
return true;
} }
bool FGAISchedule::next() bool FGAISchedule::next()

View file

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

View file

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