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,
int cruiseAlt,
const string& deptime,
const string& arrtime,
- const string& rep)
+ const string& rep,
+ const string& reqAC)
{
callsign = cs;
fltRules = fr;
//departureTime = processTimeString(deptime);
//arrivalTime = processTimeString(arrtime);
cruiseAltitude = cruiseAlt;
+ requiredAircraft = reqAC;
// Process the repeat period string
if (rep.find("WEEK",0) != string::npos)
// 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;
}
FGAirport *arrivalPort;
string depId;
string arrId;
+ string requiredAircraft;
time_t departureTime;
time_t arrivalTime;
time_t repeatPeriod;
int cruiseAltitude;
+
bool initialized;
+ bool available;
int cruiseAlt,
const string& deptime,
const string& arrtime,
- const string& rep
+ const string& rep,
+ const string& reqAC
);
~FGScheduledFlight();
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);
radius = 0;
groundOffset = 0;
distanceToUser = 0;
- score = 0;
+ //score = 0;
}
+/*
FGAISchedule::FGAISchedule(string mdl,
string liv,
string reg,
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()
//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.
}
bool FGAISchedule::update(time_t now)
-{
+{
FGAirport *dep;
FGAirport *arr;
double angle;
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();
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;
}
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");
}
-void FGAISchedule::next()
+bool FGAISchedule::next()
+{
+ 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 ¤tDestination,
+ const string &req)
{
- (*flights.begin())->update();
- sort(flights.begin(), flights.end(), compareScheduledFlights);
+ 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()
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);
}
#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;
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
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 (); };
const string& getRegistration () { return registration;};
const string& getFlightRules () { return (*flights.begin())->getFlightRules (); };
bool getHeavy () { return heavy; };
+ FGScheduledFlight*findAvailableFlight (const string ¤tDestination, 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;};
*
**************************************************************************/
-/* 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
*****************************************************************************/
FGTrafficManager::FGTrafficManager()
{
- score = 0;
- runCount = 0;
+ //score = 0;
+ //runCount = 0;
+ acCounter = 0;
}
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)
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");
}
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*/)
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())
}
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)
}
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 () {
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"))
//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 "
void FGTrafficManager::error (const char * message, int line, int column) {
SG_LOG(SG_IO, SG_ALERT, "Error: " << message << " (" << line << ',' << column << ')');
}
+
/**************************************************************************
* 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_
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/xml/easyxml.hxx>
+#include <simgear/misc/sg_path.hxx>
#include "SchedFlight.hxx"
#include "Schedule.hxx"
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();
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 ();