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:
parent
7d88714e2d
commit
b682ae91d6
3 changed files with 88 additions and 46 deletions
|
@ -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()
|
||||||
|
|
|
@ -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; };
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Add table
Reference in a new issue