Traffic Manager II source code changes
- Decouple aircraft entities from Flights - Dynamic runtime flight assignment for each aircraft
This commit is contained in:
parent
66b5a7c53b
commit
d8a2726894
6 changed files with 569 additions and 173 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
|
|
|
@ -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 ¤tDestination,
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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 ¤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;};
|
||||
|
||||
|
|
|
@ -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 << ')');
|
||||
}
|
||||
|
||||
|
|
|
@ -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 ();
|
||||
|
|
Loading…
Reference in a new issue