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

View file

@ -55,11 +55,14 @@ private:
FGAirport *arrivalPort;
string depId;
string arrId;
string requiredAircraft;
time_t departureTime;
time_t arrivalTime;
time_t repeatPeriod;
int cruiseAltitude;
bool initialized;
bool available;
@ -74,7 +77,8 @@ public:
int cruiseAlt,
const string& deptime,
const string& arrtime,
const string& rep
const string& rep,
const string& reqAC
);
~FGScheduledFlight();
@ -99,11 +103,19 @@ public:
time_t processTimeString(const string& time);
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*>::iterator FGScheduledFlightVecIterator;
typedef std::map < std::string, FGScheduledFlightVec > FGScheduledFlightMap;
bool compareScheduledFlights(FGScheduledFlight *a, FGScheduledFlight *b);

View file

@ -74,9 +74,10 @@ FGAISchedule::FGAISchedule()
radius = 0;
groundOffset = 0;
distanceToUser = 0;
score = 0;
//score = 0;
}
/*
FGAISchedule::FGAISchedule(string mdl,
string liv,
string reg,
@ -88,59 +89,77 @@ FGAISchedule::FGAISchedule(string mdl,
double rad,
double grnd,
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;
livery = liv;
registration = reg;
acType = act;
airline = arln;
m_class = mclass;
flightType = fltpe;
lat = 0;
lon = 0;
radius = rad;
groundOffset = grnd;
distanceToUser = 0;
heavy = hvy;
for (FGScheduledFlightVecIterator i = flt.begin();
modelPath = model;
livery = lvry;
homePort = port;
registration = reg;
flightIdentifier = flightId;
acType = act;
airline = arln;
m_class = mclass;
flightType = fltpe;
lat = 0;
lon = 0;
radius = rad;
groundOffset = grnd;
distanceToUser = 0;
heavy = hvy;
/*for (FGScheduledFlightVecIterator i = flt.begin();
i != flt.end();
i++)
flights.push_back(new FGScheduledFlight((*(*i))));
AIManagerRef = 0;
score = scre;
firstRun = true;
flights.push_back(new FGScheduledFlight((*(*i))));*/
AIManagerRef = 0;
//score = scre;
firstRun = true;
}
FGAISchedule::FGAISchedule(const FGAISchedule &other)
{
modelPath = other.modelPath;
livery = other.livery;
registration = other.registration;
heavy = other.heavy;
flights = other.flights;
lat = other.lat;
lon = other.lon;
AIManagerRef = other.AIManagerRef;
acType = other.acType;
airline = other.airline;
m_class = other.m_class;
firstRun = other.firstRun;
radius = other.radius;
groundOffset = other.groundOffset;
flightType = other.flightType;
score = other.score;
distanceToUser = other.distanceToUser;
modelPath = other.modelPath;
homePort = other.homePort;
livery = other.livery;
registration = other.registration;
heavy = other.heavy;
flightIdentifier = other.flightIdentifier;
flights = other.flights;
lat = other.lat;
lon = other.lon;
AIManagerRef = other.AIManagerRef;
acType = other.acType;
airline = other.airline;
m_class = other.m_class;
firstRun = other.firstRun;
radius = other.radius;
groundOffset = other.groundOffset;
flightType = other.flightType;
//score = other.score;
distanceToUser = other.distanceToUser;
currentDestination = other.currentDestination;
firstRun = other.firstRun;
}
FGAISchedule::~FGAISchedule()
{
for (FGScheduledFlightVecIterator flt = flights.begin(); flt != flights.end(); flt++)
/* for (FGScheduledFlightVecIterator flt = flights.begin(); flt != flights.end(); flt++)
{
delete (*flt);
}
flights.clear();
flights.clear();*/
}
bool FGAISchedule::init()
@ -153,14 +172,14 @@ bool FGAISchedule::init()
//sgTimeFormatTime(&targetTimeDate, buffer);
//cout << "Scheduled Time " << buffer << endl;
//cout << "Time :" << time(NULL) << " SGTime : " << sgTimeGetGMT(temp) << endl;
for (FGScheduledFlightVecIterator i = flights.begin();
/*for (FGScheduledFlightVecIterator i = flights.begin();
i != flights.end();
i++)
{
//i->adjustTime(now);
if (!((*i)->initializeAirports()))
return false;
}
} */
//sort(flights.begin(), flights.end());
// Since time isn't initialized yet when this function is called,
// Find the closest possible airport.
@ -170,7 +189,7 @@ bool FGAISchedule::init()
}
bool FGAISchedule::update(time_t now)
{
{
FGAirport *dep;
FGAirport *arr;
double angle;
@ -194,40 +213,51 @@ bool FGAISchedule::update(time_t now)
return true;
aimgr = (FGAIManager *) globals-> get_subsystem("ai_model");
// Before the flight status of this traffic entity is updated
// for the first time, we need to roll back it's flight schedule so
// so that all the flights are centered around this simulated week's time
// table. This is to avoid the situation where the first scheduled flight is
// in the future, causing the traffic manager to not generate traffic until
// simulated time has caught up with the real world time at initialization.
// This is to counter a more general initialization bug, caused by the fact
// that warp is not yet set when the schedule is initialized. This is
// especially a problem when using a negative time offset.
// i.e let's say we specify FlightGear to run with --time-offset=-24:00:00.
// Then the schedule will initialize using today, but we will fly yesterday.
// Thus, it would take a whole day of simulation before the traffic manager
// finally kicks in.
if (firstRun)
{
if (init() == false)
AIManagerRef = BOGUS;
for (FGScheduledFlightVecIterator i = flights.begin();
i != flights.end();
i++)
{
(*i)->adjustTime(now);
}
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.
firstRun = false;
// Out-of-work aircraft seeks employment. Willing to work irregular hours ...
//cerr << "About to find a flight " << endl;
if (flights.empty()) {
//execute this loop at least once.
SG_LOG(SG_GENERAL, SG_INFO, "Scheduling for : " << modelPath << " " << registration << " " << homePort);
FGScheduledFlight *flight = 0;
do {
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);
SG_LOG(SG_GENERAL, SG_INFO, " " << flight->getCallSign() << ":"
<< " " << flight->getDepartureAirport()->getId() << ":"
<< " " << depT << ":"
<< " \"" << flight->getArrivalAirport()->getId() << "\"" << ":"
<< " " << arrT << ":");
flights.push_back(flight);
}
} while ((currentDestination != homePort) && (flight != 0));
SG_LOG(SG_GENERAL, SG_INFO, cerr << " Done " << endl);
}
//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.
// Because this is done at every update, we only need to check the status
// 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)
deptime = (*flights.begin())->getDepartureTime();
FGScheduledFlightVecIterator i = flights.begin();
@ -251,7 +281,13 @@ bool FGAISchedule::update(time_t now)
if (((*i)->getDepartureTime() < now) && ((*i)->getArrivalTime() < now))
{
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 = flights.erase(i);
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 "
<< dep->getId() << " to " << arr->getId() << ". Current distance to user: "
<< 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(".xml");
@ -441,10 +477,102 @@ bool FGAISchedule::update(time_t now)
}
void FGAISchedule::next()
bool FGAISchedule::next()
{
(*flights.begin())->update();
sort(flights.begin(), flights.end(), compareScheduledFlights);
FGScheduledFlightVecIterator i = flights.begin();
(*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()
@ -472,12 +600,20 @@ double FGAISchedule::getSpeed()
dest.CourseAndDistance(curr, &courseToDest, &distanceToDest);
speed = (distanceToDest*SG_METER_TO_NM) /
((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;
}
bool compareSchedules(FGAISchedule*a, FGAISchedule*b)
{
return (*a) < (*b);
//return (*a) < (*b);
}

View file

@ -29,19 +29,23 @@
#ifndef _FGSCHEDULE_HXX_
#define _FGSCHEDULE_HXX_
#define TRAFFICTOAIDIST 150.0
#define TRAFFICTOAIDISTTOSTART 150.0
#define TRAFFICTOAIDISTTODIE 200.0
class FGAISchedule
{
private:
string modelPath;
string homePort;
string livery;
string registration;
string airline;
string acType;
string m_class;
string flightType;
string flightIdentifier;
string currentDestination;
bool heavy;
FGScheduledFlightVec flights;
float lat;
@ -50,14 +54,25 @@ class FGAISchedule
double groundOffset;
double distanceToUser;
int AIManagerRef;
int score;
//int score;
bool firstRun;
public:
FGAISchedule(); // constructor
FGAISchedule(string, string, string, bool, string, string, string, string, double, double,
int, FGScheduledFlightVec); // construct & init
FGAISchedule(string model,
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
@ -69,9 +84,10 @@ class FGAISchedule
double getSpeed ();
//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 * getArrivalAirport () { return (*flights.begin())->getArrivalAirport (); };
int getCruiseAlt () { return (*flights.begin())->getCruiseAlt (); };
@ -84,9 +100,10 @@ class FGAISchedule
const string& getRegistration () { return registration;};
const string& getFlightRules () { return (*flights.begin())->getFlightRules (); };
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
// 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; };
//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,
* where each aircraft listed in this file is at the current time.
/*
* Traffic manager parses airlines timetable-like data and uses this to
* 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:
* 1) The earth is a perfect sphere
@ -77,8 +79,9 @@ using std::sort;
*****************************************************************************/
FGTrafficManager::FGTrafficManager()
{
score = 0;
runCount = 0;
//score = 0;
//runCount = 0;
acCounter = 0;
}
FGTrafficManager:: ~FGTrafficManager()
@ -88,50 +91,22 @@ FGTrafficManager:: ~FGTrafficManager()
delete (*sched);
}
scheduledAircraft.clear();
// for (FGScheduledFlightVecIterator flt = flights.begin(); flt != flights.end(); flt++)
// {
// delete (*flt);
// }
// flights.clear();
flights.clear();
}
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;
ulDirEnt* dent, *dent2;
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;
path.append("Traffic/fgtraffic.xml");
if (path.exists())
readXML(path.str(),*this);
aircraftDir.append("AI/Aircraft");
aircraftDir.append("AI/Traffic");
if ((d = ulOpenDir(aircraftDir.c_str())) != NULL)
{
while((dent = ulReadDir(d)) != NULL) {
//cerr << "Scanning : " << dent->d_name << endl;
if (string(dent->d_name) != string(".") &&
string(dent->d_name) != string("..") &&
dent->d_isdir)
@ -145,7 +120,6 @@ void FGTrafficManager::init()
currFile.append(dent2->d_name);
if (currFile.extension() == string("xml"))
{
//cerr << "found " << dent2->d_name << " for parsing" << endl;
SGPath currFile = currACDir;
currFile.append(dent2->d_name);
SG_LOG(SG_GENERAL, SG_INFO, "Scanning " << currFile.str() << " for traffic");
@ -157,12 +131,10 @@ void FGTrafficManager::init()
}
ulCloseDir(d);
}
// Sort by points: Aircraft with frequent visits to the
// startup airport will be processed first
sort(scheduledAircraft.begin(), scheduledAircraft.end(), compareSchedules);
currAircraft = scheduledAircraft.begin();
currAircraftClosest = scheduledAircraft.begin();
//cerr << "Done initializing schedules" << endl;
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
currAircraft = scheduledAircraft.begin();
currAircraftClosest = scheduledAircraft.begin();
}
void FGTrafficManager::update(double /*dt*/)
@ -170,7 +142,6 @@ void FGTrafficManager::update(double /*dt*/)
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
if (scheduledAircraft.size() == 0) {
//SG_LOG( SG_GENERAL, SG_INFO, "Returned Running TrafficManager::Update() ");
return;
}
if(currAircraft == scheduledAircraft.end())
@ -179,12 +150,12 @@ void FGTrafficManager::update(double /*dt*/)
}
if (!((*currAircraft)->update(now)))
{
// NOTE: With traffic manager II, this statement below is no longer true
// after proper initialization, we shouldnt get here.
// 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++;
//SG_LOG( SG_GENERAL, SG_INFO, "Done Running TrafficManager::Update() ");
}
void FGTrafficManager::release(int id)
@ -206,9 +177,181 @@ bool FGTrafficManager::isReleased(int id)
}
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 () {
//cout << "Start XML" << endl;
requiredAircraft = "";
homePort = "";
}
void FGTrafficManager::endXML () {
@ -245,12 +388,16 @@ void FGTrafficManager::endElement (const char * name) {
mdl = value;
else if (element == string("livery"))
livery = value;
else if (element == string("home-port"))
homePort = value;
else if (element == string("registration"))
registration = value;
else if (element == string("airline"))
airline = value;
else if (element == string("actype"))
acType = value;
else if (element == string("required-aircraft"))
requiredAircraft = value;
else if (element == string("flighttype"))
flighttype = value;
else if (element == string("radius"))
@ -299,42 +446,91 @@ void FGTrafficManager::endElement (const char * name) {
//Prioritize aircraft
string apt = fgGetString("/sim/presets/airport-id");
//cerr << "Airport information: " << apt << " " << departurePort << " " << arrivalPort << endl;
if (departurePort == apt) score++;
flights.push_back(new FGScheduledFlight(callsign,
fltrules,
departurePort,
arrivalPort,
cruiseAlt,
departureTime,
arrivalTime,
repeat));
//if (departurePort == apt) score++;
//flights.push_back(new FGScheduledFlight(callsign,
// fltrules,
// departurePort,
// arrivalPort,
// cruiseAlt,
// departureTime,
// arrivalTime,
// 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"))
{
int proportion = (int) (fgGetDouble("/sim/traffic-manager/proportion") * 100);
int randval = rand() & 100;
if (randval < proportion) {
scheduledAircraft.push_back(new FGAISchedule(mdl,
livery,
registration,
heavy,
acType,
airline,
m_class,
flighttype,
radius,
offset,
score,
flights));
//scheduledAircraft.push_back(new FGAISchedule(mdl,
// livery,
// registration,
// heavy,
// acType,
// airline,
// m_class,
// flighttype,
// radius,
// offset,
// score,
// 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()) {
// flights.pop_back();
// }
}
for (FGScheduledFlightVecIterator flt = flights.begin(); flt != flights.end(); flt++)
{
delete (*flt);
}
flights.clear();
}
acCounter++;
requiredAircraft = "";
homePort = "";
//for (FGScheduledFlightVecIterator flt = flights.begin(); flt != flights.end(); flt++)
// {
// delete (*flt);
// }
//flights.clear();
SG_LOG( SG_GENERAL, SG_BULK, "Reading aircraft : "
<< registration
<< " 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) {
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
* 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_
@ -29,6 +48,7 @@
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/xml/easyxml.hxx>
#include <simgear/misc/sg_path.hxx>
#include "SchedFlight.hxx"
#include "Schedule.hxx"
@ -47,15 +67,18 @@ private:
string mdl, livery, registration, callsign, fltrules,
port, timeString, departurePort, departureTime, arrivalPort, arrivalTime,
repeat, acType, airline, m_class, flighttype;
repeat, acType, airline, m_class, flighttype, requiredAircraft, homePort;
int cruiseAlt;
int score, runCount;
int score, runCount, acCounter;
double radius, offset;
bool heavy;
IdList releaseList;
FGScheduledFlightVec flights;
FGScheduledFlightMap flights;
//void readTimeTableFromFile(SGPath infilename);
//void Tokenize(const string& str, vector<string>& tokens, const string& delimiters = " ");
public:
FGTrafficManager();
@ -65,6 +88,9 @@ public:
void release(int ref);
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
virtual void startXML ();
virtual void endXML ();