1
0
Fork 0

Traffic Manager II source code changes

- Decouple aircraft entities from Flights
- Dynamic runtime flight assignment for each aircraft
This commit is contained in:
durk 2008-11-16 13:45:24 +00:00
parent 66b5a7c53b
commit d8a2726894
6 changed files with 569 additions and 173 deletions

View file

@ -79,21 +79,25 @@
FGScheduledFlight::FGScheduledFlight() FGScheduledFlight::FGScheduledFlight()
{ {
initialized = false;
available = true;
} }
FGScheduledFlight::FGScheduledFlight(const FGScheduledFlight &other) FGScheduledFlight::FGScheduledFlight(const FGScheduledFlight &other)
{ {
callsign = other.callsign; callsign = other.callsign;
fltRules = other.fltRules; fltRules = other.fltRules;
departurePort = other.departurePort; departurePort = other.departurePort;
depId = other.depId; depId = other.depId;
arrId = other.arrId; arrId = other.arrId;
departureTime = other.departureTime; departureTime = other.departureTime;
cruiseAltitude = other.cruiseAltitude; cruiseAltitude = other.cruiseAltitude;
arrivalPort = other.arrivalPort; arrivalPort = other.arrivalPort;
arrivalTime = other.arrivalTime; arrivalTime = other.arrivalTime;
repeatPeriod = other.repeatPeriod; repeatPeriod = other.repeatPeriod;
initialized = other.initialized; initialized = other.initialized;
requiredAircraft = other.requiredAircraft;
available = other.available;
} }
FGScheduledFlight::FGScheduledFlight(const string& cs, FGScheduledFlight::FGScheduledFlight(const string& cs,
@ -103,7 +107,8 @@ FGScheduledFlight::FGScheduledFlight(const string& cs,
int cruiseAlt, int cruiseAlt,
const string& deptime, const string& deptime,
const string& arrtime, const string& arrtime,
const string& rep) const string& rep,
const string& reqAC)
{ {
callsign = cs; callsign = cs;
fltRules = fr; fltRules = fr;
@ -115,6 +120,7 @@ FGScheduledFlight::FGScheduledFlight(const string& cs,
//departureTime = processTimeString(deptime); //departureTime = processTimeString(deptime);
//arrivalTime = processTimeString(arrtime); //arrivalTime = processTimeString(arrtime);
cruiseAltitude = cruiseAlt; cruiseAltitude = cruiseAlt;
requiredAircraft = reqAC;
// Process the repeat period string // Process the repeat period string
if (rep.find("WEEK",0) != string::npos) if (rep.find("WEEK",0) != string::npos)
@ -136,11 +142,13 @@ FGScheduledFlight::FGScheduledFlight(const string& cs,
// arrival times. // arrival times.
departureTime = processTimeString(deptime); departureTime = processTimeString(deptime);
arrivalTime = processTimeString(arrtime); arrivalTime = processTimeString(arrtime);
//departureTime += rand() % 300; // Make sure departure times are not limited to 5 minute increments.
if (departureTime > arrivalTime) if (departureTime > arrivalTime)
{ {
departureTime -= repeatPeriod; departureTime -= repeatPeriod;
} }
initialized = false; initialized = false;
available = true;
} }

View file

@ -55,11 +55,14 @@ private:
FGAirport *arrivalPort; FGAirport *arrivalPort;
string depId; string depId;
string arrId; string arrId;
string requiredAircraft;
time_t departureTime; time_t departureTime;
time_t arrivalTime; time_t arrivalTime;
time_t repeatPeriod; time_t repeatPeriod;
int cruiseAltitude; int cruiseAltitude;
bool initialized; bool initialized;
bool available;
@ -74,7 +77,8 @@ public:
int cruiseAlt, int cruiseAlt,
const string& deptime, const string& deptime,
const string& arrtime, const string& arrtime,
const string& rep const string& rep,
const string& reqAC
); );
~FGScheduledFlight(); ~FGScheduledFlight();
@ -99,11 +103,19 @@ public:
time_t processTimeString(const string& time); time_t processTimeString(const string& time);
const string& getCallSign() {return callsign; }; const string& getCallSign() {return callsign; };
const string& getRequirement() { return requiredAircraft; }
void lock() { available = false; };
void release() { available = true; };
bool isAvailable() { return available; };
}; };
typedef vector<FGScheduledFlight*> FGScheduledFlightVec; typedef vector<FGScheduledFlight*> FGScheduledFlightVec;
typedef vector<FGScheduledFlight*>::iterator FGScheduledFlightVecIterator; typedef vector<FGScheduledFlight*>::iterator FGScheduledFlightVecIterator;
typedef std::map < std::string, FGScheduledFlightVec > FGScheduledFlightMap;
bool compareScheduledFlights(FGScheduledFlight *a, FGScheduledFlight *b); bool compareScheduledFlights(FGScheduledFlight *a, FGScheduledFlight *b);

View file

@ -74,9 +74,10 @@ FGAISchedule::FGAISchedule()
radius = 0; radius = 0;
groundOffset = 0; groundOffset = 0;
distanceToUser = 0; distanceToUser = 0;
score = 0; //score = 0;
} }
/*
FGAISchedule::FGAISchedule(string mdl, FGAISchedule::FGAISchedule(string mdl,
string liv, string liv,
string reg, string reg,
@ -88,59 +89,77 @@ FGAISchedule::FGAISchedule(string mdl,
double rad, double rad,
double grnd, double grnd,
int scre, int scre,
FGScheduledFlightVec flt) FGScheduledFlightVec flt)*/
FGAISchedule::FGAISchedule(string model,
string lvry,
string port,
string reg,
string flightId,
bool hvy,
string act,
string arln,
string mclass,
string fltpe,
double rad,
double grnd)
{ {
modelPath = mdl; modelPath = model;
livery = liv; livery = lvry;
registration = reg; homePort = port;
acType = act; registration = reg;
airline = arln; flightIdentifier = flightId;
m_class = mclass; acType = act;
flightType = fltpe; airline = arln;
lat = 0; m_class = mclass;
lon = 0; flightType = fltpe;
radius = rad; lat = 0;
groundOffset = grnd; lon = 0;
distanceToUser = 0; radius = rad;
heavy = hvy; groundOffset = grnd;
for (FGScheduledFlightVecIterator i = flt.begin(); distanceToUser = 0;
heavy = hvy;
/*for (FGScheduledFlightVecIterator i = flt.begin();
i != flt.end(); i != flt.end();
i++) i++)
flights.push_back(new FGScheduledFlight((*(*i)))); flights.push_back(new FGScheduledFlight((*(*i))));*/
AIManagerRef = 0; AIManagerRef = 0;
score = scre; //score = scre;
firstRun = true; firstRun = true;
} }
FGAISchedule::FGAISchedule(const FGAISchedule &other) FGAISchedule::FGAISchedule(const FGAISchedule &other)
{ {
modelPath = other.modelPath; modelPath = other.modelPath;
livery = other.livery; homePort = other.homePort;
registration = other.registration; livery = other.livery;
heavy = other.heavy; registration = other.registration;
flights = other.flights; heavy = other.heavy;
lat = other.lat; flightIdentifier = other.flightIdentifier;
lon = other.lon; flights = other.flights;
AIManagerRef = other.AIManagerRef; lat = other.lat;
acType = other.acType; lon = other.lon;
airline = other.airline; AIManagerRef = other.AIManagerRef;
m_class = other.m_class; acType = other.acType;
firstRun = other.firstRun; airline = other.airline;
radius = other.radius; m_class = other.m_class;
groundOffset = other.groundOffset; firstRun = other.firstRun;
flightType = other.flightType; radius = other.radius;
score = other.score; groundOffset = other.groundOffset;
distanceToUser = other.distanceToUser; flightType = other.flightType;
//score = other.score;
distanceToUser = other.distanceToUser;
currentDestination = other.currentDestination;
firstRun = other.firstRun;
} }
FGAISchedule::~FGAISchedule() FGAISchedule::~FGAISchedule()
{ {
for (FGScheduledFlightVecIterator flt = flights.begin(); flt != flights.end(); flt++) /* for (FGScheduledFlightVecIterator flt = flights.begin(); flt != flights.end(); flt++)
{ {
delete (*flt); delete (*flt);
} }
flights.clear(); flights.clear();*/
} }
bool FGAISchedule::init() bool FGAISchedule::init()
@ -153,14 +172,14 @@ bool FGAISchedule::init()
//sgTimeFormatTime(&targetTimeDate, buffer); //sgTimeFormatTime(&targetTimeDate, buffer);
//cout << "Scheduled Time " << buffer << endl; //cout << "Scheduled Time " << buffer << endl;
//cout << "Time :" << time(NULL) << " SGTime : " << sgTimeGetGMT(temp) << endl; //cout << "Time :" << time(NULL) << " SGTime : " << sgTimeGetGMT(temp) << endl;
for (FGScheduledFlightVecIterator i = flights.begin(); /*for (FGScheduledFlightVecIterator i = flights.begin();
i != flights.end(); i != flights.end();
i++) i++)
{ {
//i->adjustTime(now); //i->adjustTime(now);
if (!((*i)->initializeAirports())) if (!((*i)->initializeAirports()))
return false; return false;
} } */
//sort(flights.begin(), flights.end()); //sort(flights.begin(), flights.end());
// Since time isn't initialized yet when this function is called, // Since time isn't initialized yet when this function is called,
// Find the closest possible airport. // Find the closest possible airport.
@ -170,7 +189,7 @@ bool FGAISchedule::init()
} }
bool FGAISchedule::update(time_t now) bool FGAISchedule::update(time_t now)
{ {
FGAirport *dep; FGAirport *dep;
FGAirport *arr; FGAirport *arr;
double angle; double angle;
@ -194,40 +213,51 @@ bool FGAISchedule::update(time_t now)
return true; return true;
aimgr = (FGAIManager *) globals-> get_subsystem("ai_model"); aimgr = (FGAIManager *) globals-> get_subsystem("ai_model");
// Before the flight status of this traffic entity is updated // Out-of-work aircraft seeks employment. Willing to work irregular hours ...
// for the first time, we need to roll back it's flight schedule so //cerr << "About to find a flight " << endl;
// so that all the flights are centered around this simulated week's time if (flights.empty()) {
// table. This is to avoid the situation where the first scheduled flight is //execute this loop at least once.
// in the future, causing the traffic manager to not generate traffic until SG_LOG(SG_GENERAL, SG_INFO, "Scheduling for : " << modelPath << " " << registration << " " << homePort);
// simulated time has caught up with the real world time at initialization. FGScheduledFlight *flight = 0;
// This is to counter a more general initialization bug, caused by the fact do {
// that warp is not yet set when the schedule is initialized. This is flight = findAvailableFlight(currentDestination, flightIdentifier);
// especially a problem when using a negative time offset. if (flight) {
// i.e let's say we specify FlightGear to run with --time-offset=-24:00:00. currentDestination = flight->getArrivalAirport()->getId();
// Then the schedule will initialize using today, but we will fly yesterday. time_t arr, dep;
// Thus, it would take a whole day of simulation before the traffic manager dep = flight->getDepartureTime();
// finally kicks in. arr = flight->getArrivalTime();
if (firstRun) string depT = asctime(gmtime(&dep));
{ string arrT = asctime(gmtime(&arr));
if (init() == false)
AIManagerRef = BOGUS; depT = depT.substr(0,24);
arrT = arrT.substr(0,24);
for (FGScheduledFlightVecIterator i = flights.begin(); SG_LOG(SG_GENERAL, SG_INFO, " " << flight->getCallSign() << ":"
i != flights.end(); << " " << flight->getDepartureAirport()->getId() << ":"
i++) << " " << depT << ":"
{ << " \"" << flight->getArrivalAirport()->getId() << "\"" << ":"
(*i)->adjustTime(now); << " " << arrT << ":");
} flights.push_back(flight);
if (fgGetBool("/sim/traffic-manager/instantaneous-action") == true) }
deptime = now + rand() % 300; // Wait up to 5 minutes until traffic starts moving to prevent too many aircraft } while ((currentDestination != homePort) && (flight != 0));
// from cluttering the gate areas. SG_LOG(SG_GENERAL, SG_INFO, cerr << " Done " << endl);
firstRun = false;
} }
//cerr << " Done " << endl;
// No flights available for this aircraft
if (flights.size() == 0) {
return false;
}
// 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.
sort(flights.begin(), flights.end(), compareScheduledFlights); //sort(flights.begin(), flights.end(), compareScheduledFlights);
if (firstRun) {
if (fgGetBool("/sim/traffic-manager/instantaneous-action") == true) {
deptime = now + rand() % 300; // Wait up to 5 minutes until traffic starts moving to prevent too many aircraft
// from cluttering the gate areas.
cerr << "Scheduling " << registration << " for instantaneous action flight " << endl;
}
firstRun = false;
}
if (!deptime) if (!deptime)
deptime = (*flights.begin())->getDepartureTime(); deptime = (*flights.begin())->getDepartureTime();
FGScheduledFlightVecIterator i = flights.begin(); FGScheduledFlightVecIterator i = flights.begin();
@ -251,7 +281,13 @@ bool FGAISchedule::update(time_t now)
if (((*i)->getDepartureTime() < now) && ((*i)->getArrivalTime() < now)) if (((*i)->getDepartureTime() < now) && ((*i)->getArrivalTime() < now))
{ {
SG_LOG (SG_GENERAL, SG_DEBUG, "Traffic Manager: Flight is in the Past"); SG_LOG (SG_GENERAL, SG_DEBUG, "Traffic Manager: Flight is in the Past");
//cerr << modelPath << " " << registration << ": Flights from the past belong to the past :-)" << endl;
//exit(1);
// Don't just update: check whether we need to load a new leg. etc.
// This update occurs for distant aircraft, so we can update the current leg
// and detach it from the current list of aircraft.
(*i)->update(); (*i)->update();
i = flights.erase(i);
return true; return true;
} }
@ -357,7 +393,7 @@ bool FGAISchedule::update(time_t now)
SG_LOG (SG_GENERAL, SG_DEBUG, "Traffic manager: " << registration << " is scheduled for a flight from " SG_LOG (SG_GENERAL, SG_DEBUG, "Traffic manager: " << registration << " is scheduled for a flight from "
<< dep->getId() << " to " << arr->getId() << ". Current distance to user: " << dep->getId() << " to " << arr->getId() << ". Current distance to user: "
<< distanceToUser*SG_METER_TO_NM); << distanceToUser*SG_METER_TO_NM);
if ((distanceToUser*SG_METER_TO_NM) < TRAFFICTOAIDIST) if ((distanceToUser*SG_METER_TO_NM) < TRAFFICTOAIDISTTOSTART)
{ {
string flightPlanName = dep->getId() + string("-") + arr->getId() + string flightPlanName = dep->getId() + string("-") + arr->getId() +
string(".xml"); string(".xml");
@ -441,10 +477,102 @@ bool FGAISchedule::update(time_t now)
} }
void FGAISchedule::next() bool FGAISchedule::next()
{ {
(*flights.begin())->update(); FGScheduledFlightVecIterator i = flights.begin();
sort(flights.begin(), flights.end(), compareScheduledFlights); (*i)->release();
//FIXME: remove first entry,
// load new flights until back at home airport
// Lock loaded flights
//sort(flights.begin(), flights.end(), compareScheduledFlights);
// until that time
i = flights.erase(i);
//cerr << "Next: scheduling for : " << modelPath << " " << registration << endl;
FGScheduledFlight *flight = findAvailableFlight(currentDestination, flightIdentifier);
if (flight) {
currentDestination = flight->getArrivalAirport()->getId();
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);
//cerr << " " << flight->getCallSign() << ":"
// << " " << flight->getDepartureAirport()->getId() << ":"
// << " " << depT << ":"
// << " \"" << flight->getArrivalAirport()->getId() << "\"" << ":"
// << " " << arrT << ":" << endl;
flights.push_back(flight);
return true;
} else {
return false;
}
//cerr << "FGAISchedule :: next needs updating" << endl;
//exit(1);
}
FGScheduledFlight* FGAISchedule::findAvailableFlight (const string &currentDestination,
const string &req)
{
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
FGTrafficManager *tmgr = (FGTrafficManager *) globals->get_subsystem("Traffic Manager");
FGScheduledFlightVecIterator fltBegin, fltEnd;
fltBegin = tmgr->getFirstFlight(req);
fltEnd = tmgr->getLastFlight(req);
//cerr << "Finding available flight " << endl;
// For Now:
// Traverse every registered flight
if (fltBegin == fltEnd) {
//cerr << "No Flights Scheduled for " << req << endl;
}
int counter = 0;
for (FGScheduledFlightVecIterator i = fltBegin; i != fltEnd; i++) {
(*i)->adjustTime(now);
//sort(fltBegin, fltEnd, compareScheduledFlights);
//cerr << counter++ << endl;
}
sort(fltBegin, fltEnd, compareScheduledFlights);
for (FGScheduledFlightVecIterator i = fltBegin; i != fltEnd; i++) {
//bool valid = true;
counter++;
if (!(*i)->isAvailable()) {
//cerr << (*i)->getCallSign() << "is no longer available" << endl;
continue;
}
if (!((*i)->getRequirement() == req)) {
continue;
}
if (!(((*i)->getArrivalAirport()) && ((*i)->getDepartureAirport()))) {
continue;
}
if (!(currentDestination.empty())) {
if (currentDestination != (*i)->getDepartureAirport()->getId()) {
//cerr << (*i)->getCallSign() << "Doesn't match destination" << endl;
//cerr << "Current Destination " << currentDestination << "Doesnt match flight's " <<
// (*i)->getArrivalAirport()->getId() << endl;
continue;
}
}
//TODO: check time
// So, if we actually get here, we have a winner
//cerr << "found flight: " << req << " : " << currentDestination << " : " <<
// (*i)->getArrivalAirport()->getId() << endl;
(*i)->lock();
return (*i);
}
// matches req?
// if currentDestination has a value, does it match departure of next flight?
// is departure time later than planned arrival?
// is departure port valid?
// is arrival port valid?
//cerr << "Ack no flight found: " << endl;
return 0;
} }
double FGAISchedule::getSpeed() double FGAISchedule::getSpeed()
@ -472,12 +600,20 @@ double FGAISchedule::getSpeed()
dest.CourseAndDistance(curr, &courseToDest, &distanceToDest); dest.CourseAndDistance(curr, &courseToDest, &distanceToDest);
speed = (distanceToDest*SG_METER_TO_NM) / speed = (distanceToDest*SG_METER_TO_NM) /
((double) remainingTimeEnroute/3600.0); ((double) remainingTimeEnroute/3600.0);
if (speed < 300) {
//cerr << "Warning : calculated speed for " << (*i)->getCallSign() << " is low : " << speed << " clamping to 300" << endl;
speed = 300.0;
}
if (speed > 500) {
//cerr << "Warning : calculated speed for " << (*i)->getCallSign() << " is high : " << speed << " clamping to 300" << endl;
speed = 500.0;
}
return speed; return speed;
} }
bool compareSchedules(FGAISchedule*a, FGAISchedule*b) bool compareSchedules(FGAISchedule*a, FGAISchedule*b)
{ {
return (*a) < (*b); //return (*a) < (*b);
} }

View file

@ -29,19 +29,23 @@
#ifndef _FGSCHEDULE_HXX_ #ifndef _FGSCHEDULE_HXX_
#define _FGSCHEDULE_HXX_ #define _FGSCHEDULE_HXX_
#define TRAFFICTOAIDIST 150.0 #define TRAFFICTOAIDISTTOSTART 150.0
#define TRAFFICTOAIDISTTODIE 200.0
class FGAISchedule class FGAISchedule
{ {
private: private:
string modelPath; string modelPath;
string homePort;
string livery; string livery;
string registration; string registration;
string airline; string airline;
string acType; string acType;
string m_class; string m_class;
string flightType; string flightType;
string flightIdentifier;
string currentDestination;
bool heavy; bool heavy;
FGScheduledFlightVec flights; FGScheduledFlightVec flights;
float lat; float lat;
@ -50,14 +54,25 @@ class FGAISchedule
double groundOffset; double groundOffset;
double distanceToUser; double distanceToUser;
int AIManagerRef; int AIManagerRef;
int score; //int score;
bool firstRun; bool firstRun;
public: public:
FGAISchedule(); // constructor FGAISchedule(); // constructor
FGAISchedule(string, string, string, bool, string, string, string, string, double, double, FGAISchedule(string model,
int, FGScheduledFlightVec); // construct & init string livery,
string homePort,
string registration,
string flightId,
bool heavy,
string acType,
string airline,
string m_class,
string flight_type,
double radius,
double offset); // construct & init
FGAISchedule(const FGAISchedule &other); // copy constructor FGAISchedule(const FGAISchedule &other); // copy constructor
@ -69,9 +84,10 @@ class FGAISchedule
double getSpeed (); double getSpeed ();
//void setClosestDistanceToUser(); //void setClosestDistanceToUser();
void next(); // forces the schedule to move on to the next flight. bool next(); // forces the schedule to move on to the next flight.
time_t getDepartureTime () { return (*flights.begin())->getDepartureTime (); }; // TODO: rework these four functions
time_t getDepartureTime () { return (*flights.begin())->getDepartureTime (); };
FGAirport * getDepartureAirport () { return (*flights.begin())->getDepartureAirport(); }; FGAirport * getDepartureAirport () { return (*flights.begin())->getDepartureAirport(); };
FGAirport * getArrivalAirport () { return (*flights.begin())->getArrivalAirport (); }; FGAirport * getArrivalAirport () { return (*flights.begin())->getArrivalAirport (); };
int getCruiseAlt () { return (*flights.begin())->getCruiseAlt (); }; int getCruiseAlt () { return (*flights.begin())->getCruiseAlt (); };
@ -84,9 +100,10 @@ class FGAISchedule
const string& getRegistration () { return registration;}; const string& getRegistration () { return registration;};
const string& getFlightRules () { return (*flights.begin())->getFlightRules (); }; const string& getFlightRules () { return (*flights.begin())->getFlightRules (); };
bool getHeavy () { return heavy; }; bool getHeavy () { return heavy; };
FGScheduledFlight*findAvailableFlight (const string &currentDestination, const string &req);
// used to sort in decending order of score: I've probably found a better way to // used to sort in decending order of score: I've probably found a better way to
// decending order sorting, but still need to test that. // decending order sorting, but still need to test that.
bool operator< (const FGAISchedule &other) const { return (score > other.score); }; //bool operator< (const FGAISchedule &other) const { return (score > other.score); };
//void * getAiRef () { return AIManagerRef; }; //void * getAiRef () { return AIManagerRef; };
//FGAISchedule* getAddress () { return this;}; //FGAISchedule* getAddress () { return this;};

View file

@ -19,9 +19,11 @@
* *
**************************************************************************/ **************************************************************************/
/* This a prototype version of a top-level flight plan manager for Flightgear. /*
* It parses the fgtraffic.txt file and determine for a specific time/date, * Traffic manager parses airlines timetable-like data and uses this to
* where each aircraft listed in this file is at the current time. * determine the approximate position of each AI aircraft in its database.
* When an AI aircraft is close to the user's position, a more detailed
* AIModels based simulation is set up.
* *
* I'm currently assuming the following simplifications: * I'm currently assuming the following simplifications:
* 1) The earth is a perfect sphere * 1) The earth is a perfect sphere
@ -77,8 +79,9 @@ using std::sort;
*****************************************************************************/ *****************************************************************************/
FGTrafficManager::FGTrafficManager() FGTrafficManager::FGTrafficManager()
{ {
score = 0; //score = 0;
runCount = 0; //runCount = 0;
acCounter = 0;
} }
FGTrafficManager:: ~FGTrafficManager() FGTrafficManager:: ~FGTrafficManager()
@ -88,50 +91,22 @@ FGTrafficManager:: ~FGTrafficManager()
delete (*sched); delete (*sched);
} }
scheduledAircraft.clear(); scheduledAircraft.clear();
// for (FGScheduledFlightVecIterator flt = flights.begin(); flt != flights.end(); flt++) flights.clear();
// {
// delete (*flt);
// }
// flights.clear();
} }
void FGTrafficManager::init() void FGTrafficManager::init()
{ {
//cerr << "Initializing Schedules" << endl;
//time_t now = time(NULL) + fgGetLong("/sim/time/warp");
//currAircraft = scheduledAircraft.begin();
//while (currAircraft != scheduledAircraft.end())
// {
// if (!(currAircraft->init()))
// {
// currAircraft=scheduledAircraft.erase(currAircraft);
// //cerr << "Erasing " << currAircraft->getRegistration() << endl;
// }
// else
// {
// currAircraft++;
// }
// }
// Sort by points: Aircraft with frequent visits to the
// startup airport will be processed first
ulDir* d, *d2; ulDir* d, *d2;
ulDirEnt* dent, *dent2; ulDirEnt* dent, *dent2;
SGPath aircraftDir = globals->get_fg_root(); SGPath aircraftDir = globals->get_fg_root();
/* keep the following three lines (which mimicks the old "fixed path" behavior)
* until we have some AI models with traffic in the base package
*/
SGPath path = aircraftDir; SGPath path = aircraftDir;
path.append("Traffic/fgtraffic.xml");
if (path.exists()) aircraftDir.append("AI/Traffic");
readXML(path.str(),*this);
aircraftDir.append("AI/Aircraft");
if ((d = ulOpenDir(aircraftDir.c_str())) != NULL) if ((d = ulOpenDir(aircraftDir.c_str())) != NULL)
{ {
while((dent = ulReadDir(d)) != NULL) { while((dent = ulReadDir(d)) != NULL) {
//cerr << "Scanning : " << dent->d_name << endl;
if (string(dent->d_name) != string(".") && if (string(dent->d_name) != string(".") &&
string(dent->d_name) != string("..") && string(dent->d_name) != string("..") &&
dent->d_isdir) dent->d_isdir)
@ -145,7 +120,6 @@ void FGTrafficManager::init()
currFile.append(dent2->d_name); currFile.append(dent2->d_name);
if (currFile.extension() == string("xml")) if (currFile.extension() == string("xml"))
{ {
//cerr << "found " << dent2->d_name << " for parsing" << endl;
SGPath currFile = currACDir; SGPath currFile = currACDir;
currFile.append(dent2->d_name); currFile.append(dent2->d_name);
SG_LOG(SG_GENERAL, SG_INFO, "Scanning " << currFile.str() << " for traffic"); SG_LOG(SG_GENERAL, SG_INFO, "Scanning " << currFile.str() << " for traffic");
@ -157,12 +131,10 @@ void FGTrafficManager::init()
} }
ulCloseDir(d); ulCloseDir(d);
} }
// Sort by points: Aircraft with frequent visits to the time_t now = time(NULL) + fgGetLong("/sim/time/warp");
// startup airport will be processed first
sort(scheduledAircraft.begin(), scheduledAircraft.end(), compareSchedules); currAircraft = scheduledAircraft.begin();
currAircraft = scheduledAircraft.begin(); currAircraftClosest = scheduledAircraft.begin();
currAircraftClosest = scheduledAircraft.begin();
//cerr << "Done initializing schedules" << endl;
} }
void FGTrafficManager::update(double /*dt*/) void FGTrafficManager::update(double /*dt*/)
@ -170,7 +142,6 @@ void FGTrafficManager::update(double /*dt*/)
time_t now = time(NULL) + fgGetLong("/sim/time/warp"); time_t now = time(NULL) + fgGetLong("/sim/time/warp");
if (scheduledAircraft.size() == 0) { if (scheduledAircraft.size() == 0) {
//SG_LOG( SG_GENERAL, SG_INFO, "Returned Running TrafficManager::Update() ");
return; return;
} }
if(currAircraft == scheduledAircraft.end()) if(currAircraft == scheduledAircraft.end())
@ -179,12 +150,12 @@ void FGTrafficManager::update(double /*dt*/)
} }
if (!((*currAircraft)->update(now))) if (!((*currAircraft)->update(now)))
{ {
// NOTE: With traffic manager II, this statement below is no longer true
// after proper initialization, we shouldnt get here. // after proper initialization, we shouldnt get here.
// But let's make sure // But let's make sure
SG_LOG( SG_GENERAL, SG_ALERT, "Failed to update aircraft schedule in traffic manager"); //SG_LOG( SG_GENERAL, SG_ALERT, "Failed to update aircraft schedule in traffic manager");
} }
currAircraft++; currAircraft++;
//SG_LOG( SG_GENERAL, SG_INFO, "Done Running TrafficManager::Update() ");
} }
void FGTrafficManager::release(int id) void FGTrafficManager::release(int id)
@ -206,9 +177,181 @@ bool FGTrafficManager::isReleased(int id)
} }
return false; return false;
} }
/*
void FGTrafficManager::readTimeTableFromFile(SGPath infileName)
{
string model;
string livery;
string homePort;
string registration;
string flightReq;
bool isHeavy;
string acType;
string airline;
string m_class;
string FlightType;
double radius;
double offset;
char buffer[256];
string buffString;
vector <string> tokens, depTime,arrTime;
vector <string>::iterator it;
ifstream infile(infileName.str().c_str());
while (1) {
infile.getline(buffer, 256);
if (infile.eof()) {
break;
}
//cerr << "Read line : " << buffer << endl;
buffString = string(buffer);
tokens.clear();
Tokenize(buffString, tokens, " \t");
//for (it = tokens.begin(); it != tokens.end(); it++) {
// cerr << "Tokens: " << *(it) << endl;
//}
//cerr << endl;
if (!tokens.empty()) {
if (tokens[0] == string("AC")) {
if (tokens.size() != 13) {
SG_LOG(SG_GENERAL, SG_ALERT, "Error parsing traffic file " << infileName.str() << " at " << buffString);
exit(1);
}
model = tokens[12];
livery = tokens[6];
homePort = tokens[1];
registration = tokens[2];
if (tokens[11] == string("false")) {
isHeavy = false;
} else {
isHeavy = true;
}
acType = tokens[4];
airline = tokens[5];
flightReq = tokens[3] + tokens[5];
m_class = tokens[10];
FlightType = tokens[9];
radius = atof(tokens[8].c_str());
offset = atof(tokens[7].c_str());;
//cerr << "Found AC string " << model << " " << livery << " " << homePort << " "
// << registration << " " << flightReq << " " << isHeavy << " " << acType << " " << airline << " " << m_class
// << " " << FlightType << " " << radius << " " << offset << endl;
scheduledAircraft.push_back(new FGAISchedule(model,
livery,
homePort,
registration,
flightReq,
isHeavy,
acType,
airline,
m_class,
FlightType,
radius,
offset));
}
if (tokens[0] == string("FLIGHT")) {
//cerr << "Found flight " << buffString << " size is : " << tokens.size() << endl;
if (tokens.size() != 10) {
SG_LOG(SG_GENERAL, SG_ALERT, "Error parsing traffic file " << infileName.str() << " at " << buffString);
exit(1);
}
string callsign = tokens[1];
string fltrules = tokens[2];
string weekdays = tokens[3];
string departurePort = tokens[5];
string arrivalPort = tokens[7];
int cruiseAlt = atoi(tokens[8].c_str());
string depTimeGen = tokens[4];
string arrTimeGen = tokens[6];
string repeat = "WEEK";
string requiredAircraft = tokens[9];
if (weekdays.size() != 7) {
cerr << "Found misconfigured weekdays string" << weekdays << endl;
exit(1);
}
depTime.clear();
arrTime.clear();
Tokenize(depTimeGen, depTime, ":");
Tokenize(arrTimeGen, arrTime, ":");
double dep = atof(depTime[0].c_str()) + (atof(depTime[1].c_str()) / 60.0);
double arr = atof(arrTime[0].c_str()) + (atof(arrTime[1].c_str()) / 60.0);
//cerr << "Using " << dep << " " << arr << endl;
bool arrivalWeekdayNeedsIncrement = false;
if (arr < dep) {
arrivalWeekdayNeedsIncrement = true;
}
for (int i = 0; i < 7; i++) {
if (weekdays[i] != '.') {
char buffer[4];
snprintf(buffer, 4, "%d/", i);
string departureTime = string(buffer) + depTimeGen + string(":00");
string arrivalTime;
if (!arrivalWeekdayNeedsIncrement) {
arrivalTime = string(buffer) + arrTimeGen + string(":00");
}
if (arrivalWeekdayNeedsIncrement && i != 6 ) {
snprintf(buffer, 4, "%d/", i+1);
arrivalTime = string(buffer) + arrTimeGen + string(":00");
}
if (arrivalWeekdayNeedsIncrement && i == 6 ) {
snprintf(buffer, 4, "%d/", 0);
arrivalTime = string(buffer) + arrTimeGen + string(":00");
}
cerr << "Adding flight: " << callsign << " "
<< fltrules << " "
<< departurePort << " "
<< arrivalPort << " "
<< cruiseAlt << " "
<< departureTime << " "
<< arrivalTime << " "
<< repeat << " "
<< requiredAircraft << endl;
flights[requiredAircraft].push_back(new FGScheduledFlight(callsign,
fltrules,
departurePort,
arrivalPort,
cruiseAlt,
departureTime,
arrivalTime,
repeat,
requiredAircraft));
}
}
}
}
}
//exit(1);
}*/
/*
void FGTrafficManager::Tokenize(const string& str,
vector<string>& tokens,
const string& delimiters)
{
// Skip delimiters at beginning.
string::size_type lastPos = str.find_first_not_of(delimiters, 0);
// Find first "non-delimiter".
string::size_type pos = str.find_first_of(delimiters, lastPos);
while (string::npos != pos || string::npos != lastPos)
{
// Found a token, add it to the vector.
tokens.push_back(str.substr(lastPos, pos - lastPos));
// Skip delimiters. Note the "not_of"
lastPos = str.find_first_not_of(delimiters, pos);
// Find next "non-delimiter"
pos = str.find_first_of(delimiters, lastPos);
}
}
*/
void FGTrafficManager::startXML () { void FGTrafficManager::startXML () {
//cout << "Start XML" << endl; //cout << "Start XML" << endl;
requiredAircraft = "";
homePort = "";
} }
void FGTrafficManager::endXML () { void FGTrafficManager::endXML () {
@ -245,12 +388,16 @@ void FGTrafficManager::endElement (const char * name) {
mdl = value; mdl = value;
else if (element == string("livery")) else if (element == string("livery"))
livery = value; livery = value;
else if (element == string("home-port"))
homePort = value;
else if (element == string("registration")) else if (element == string("registration"))
registration = value; registration = value;
else if (element == string("airline")) else if (element == string("airline"))
airline = value; airline = value;
else if (element == string("actype")) else if (element == string("actype"))
acType = value; acType = value;
else if (element == string("required-aircraft"))
requiredAircraft = value;
else if (element == string("flighttype")) else if (element == string("flighttype"))
flighttype = value; flighttype = value;
else if (element == string("radius")) else if (element == string("radius"))
@ -299,42 +446,91 @@ void FGTrafficManager::endElement (const char * name) {
//Prioritize aircraft //Prioritize aircraft
string apt = fgGetString("/sim/presets/airport-id"); string apt = fgGetString("/sim/presets/airport-id");
//cerr << "Airport information: " << apt << " " << departurePort << " " << arrivalPort << endl; //cerr << "Airport information: " << apt << " " << departurePort << " " << arrivalPort << endl;
if (departurePort == apt) score++; //if (departurePort == apt) score++;
flights.push_back(new FGScheduledFlight(callsign, //flights.push_back(new FGScheduledFlight(callsign,
fltrules, // fltrules,
departurePort, // departurePort,
arrivalPort, // arrivalPort,
cruiseAlt, // cruiseAlt,
departureTime, // departureTime,
arrivalTime, // arrivalTime,
repeat)); // repeat));
if (requiredAircraft == "") {
char buffer[16];
snprintf(buffer, 16, "%d", acCounter);
requiredAircraft = buffer;
} }
SG_LOG(SG_GENERAL, SG_DEBUG, "Adding flight: " << callsign << " "
<< fltrules << " "
<< departurePort << " "
<< arrivalPort << " "
<< cruiseAlt << " "
<< departureTime << " "
<< arrivalTime << " "
<< repeat << " "
<< requiredAircraft);
flights[requiredAircraft].push_back(new FGScheduledFlight(callsign,
fltrules,
departurePort,
arrivalPort,
cruiseAlt,
departureTime,
arrivalTime,
repeat,
requiredAircraft));
requiredAircraft = "";
}
else if (element == string("aircraft")) else if (element == string("aircraft"))
{ {
int proportion = (int) (fgGetDouble("/sim/traffic-manager/proportion") * 100); int proportion = (int) (fgGetDouble("/sim/traffic-manager/proportion") * 100);
int randval = rand() & 100; int randval = rand() & 100;
if (randval < proportion) { if (randval < proportion) {
scheduledAircraft.push_back(new FGAISchedule(mdl, //scheduledAircraft.push_back(new FGAISchedule(mdl,
livery, // livery,
registration, // registration,
heavy, // heavy,
acType, // acType,
airline, // airline,
m_class, // m_class,
flighttype, // flighttype,
radius, // radius,
offset, // offset,
score, // score,
flights)); // flights));
if (requiredAircraft == "") {
char buffer[16];
snprintf(buffer, 16, "%d", acCounter);
requiredAircraft = buffer;
}
if (homePort == "") {
homePort = departurePort;
}
scheduledAircraft.push_back(new FGAISchedule(mdl,
livery,
homePort,
registration,
requiredAircraft,
heavy,
acType,
airline,
m_class,
flighttype,
radius,
offset));
// while(flights.begin() != flights.end()) { // while(flights.begin() != flights.end()) {
// flights.pop_back(); // flights.pop_back();
// } // }
} }
for (FGScheduledFlightVecIterator flt = flights.begin(); flt != flights.end(); flt++) acCounter++;
{ requiredAircraft = "";
delete (*flt); homePort = "";
} //for (FGScheduledFlightVecIterator flt = flights.begin(); flt != flights.end(); flt++)
flights.clear(); // {
// delete (*flt);
// }
//flights.clear();
SG_LOG( SG_GENERAL, SG_BULK, "Reading aircraft : " SG_LOG( SG_GENERAL, SG_BULK, "Reading aircraft : "
<< registration << registration
<< " with prioritization score " << " with prioritization score "
@ -360,3 +556,4 @@ void FGTrafficManager::warning (const char * message, int line, int column) {
void FGTrafficManager::error (const char * message, int line, int column) { void FGTrafficManager::error (const char * message, int line, int column) {
SG_LOG(SG_IO, SG_ALERT, "Error: " << message << " (" << line << ',' << column << ')'); SG_LOG(SG_IO, SG_ALERT, "Error: " << message << " (" << line << ',' << column << ')');
} }

View file

@ -22,6 +22,25 @@
/************************************************************************** /**************************************************************************
* This file contains the class definitions for a (Top Level) traffic * This file contains the class definitions for a (Top Level) traffic
* manager for FlightGear. * manager for FlightGear.
*
* This is traffic manager version II. The major difference from version
* I is that the Flight Schedules are decoupled from the AIAircraft
* entities. This allows for a much greater flexibility in setting up
* Irregular schedules. Traffic Manager II also makes no longer use of .xml
* based configuration files.
*
* Here is a step plan to achieve the goal of creating Traffic Manager II
*
* 1) Read aircraft data from a simple text file, like the one provided by
* Gabor Toth
* 2) Create a new database structure of SchedFlights. This new database
* should not be part of the Schedule class, but of TrafficManager itself
* 3) Each aircraft should have a list of possible Flights it can operate
* (i.e. airline and AC type match).
* 4) Aircraft processing proceeds as current. During initialization, we seek
* the most urgent flight that needs to be operated
* 5) Modify the getNextLeg function so that the next flight is loaded smoothly.
**************************************************************************/ **************************************************************************/
#ifndef _TRAFFICMGR_HXX_ #ifndef _TRAFFICMGR_HXX_
@ -29,6 +48,7 @@
#include <simgear/structure/subsystem_mgr.hxx> #include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/xml/easyxml.hxx> #include <simgear/xml/easyxml.hxx>
#include <simgear/misc/sg_path.hxx>
#include "SchedFlight.hxx" #include "SchedFlight.hxx"
#include "Schedule.hxx" #include "Schedule.hxx"
@ -47,15 +67,18 @@ private:
string mdl, livery, registration, callsign, fltrules, string mdl, livery, registration, callsign, fltrules,
port, timeString, departurePort, departureTime, arrivalPort, arrivalTime, port, timeString, departurePort, departureTime, arrivalPort, arrivalTime,
repeat, acType, airline, m_class, flighttype; repeat, acType, airline, m_class, flighttype, requiredAircraft, homePort;
int cruiseAlt; int cruiseAlt;
int score, runCount; int score, runCount, acCounter;
double radius, offset; double radius, offset;
bool heavy; bool heavy;
IdList releaseList; IdList releaseList;
FGScheduledFlightVec flights; FGScheduledFlightMap flights;
//void readTimeTableFromFile(SGPath infilename);
//void Tokenize(const string& str, vector<string>& tokens, const string& delimiters = " ");
public: public:
FGTrafficManager(); FGTrafficManager();
@ -65,6 +88,9 @@ public:
void release(int ref); void release(int ref);
bool isReleased(int id); bool isReleased(int id);
FGScheduledFlightVecIterator getFirstFlight(const string &ref) { return flights[ref].begin(); }
FGScheduledFlightVecIterator getLastFlight(const string &ref) { return flights[ref].end(); }
// Some overloaded virtual XMLVisitor members // Some overloaded virtual XMLVisitor members
virtual void startXML (); virtual void startXML ();
virtual void endXML (); virtual void endXML ();