From: durk Date: Sun, 16 Nov 2008 13:45:24 +0000 (+0000) Subject: Traffic Manager II source code changes X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=d8a2726894bf9f26ff456d1ff393e6d2a2b26bc0;p=flightgear.git Traffic Manager II source code changes - Decouple aircraft entities from Flights - Dynamic runtime flight assignment for each aircraft --- diff --git a/src/Traffic/SchedFlight.cxx b/src/Traffic/SchedFlight.cxx index 52661664d..0fad5b88d 100644 --- a/src/Traffic/SchedFlight.cxx +++ b/src/Traffic/SchedFlight.cxx @@ -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; } diff --git a/src/Traffic/SchedFlight.hxx b/src/Traffic/SchedFlight.hxx index 63ba6c7fd..0ee3eb6bd 100644 --- a/src/Traffic/SchedFlight.hxx +++ b/src/Traffic/SchedFlight.hxx @@ -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 FGScheduledFlightVec; typedef vector::iterator FGScheduledFlightVecIterator; +typedef std::map < std::string, FGScheduledFlightVec > FGScheduledFlightMap; + bool compareScheduledFlights(FGScheduledFlight *a, FGScheduledFlight *b); diff --git a/src/Traffic/Schedule.cxx b/src/Traffic/Schedule.cxx index 699aa144c..2e365d522 100644 --- a/src/Traffic/Schedule.cxx +++ b/src/Traffic/Schedule.cxx @@ -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() +{ + 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() @@ -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); } diff --git a/src/Traffic/Schedule.hxx b/src/Traffic/Schedule.hxx index f18d7492e..5511a7d1a 100644 --- a/src/Traffic/Schedule.hxx +++ b/src/Traffic/Schedule.hxx @@ -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;}; diff --git a/src/Traffic/TrafficMgr.cxx b/src/Traffic/TrafficMgr.cxx index 3a8eb5513..07d0cd0ab 100644 --- a/src/Traffic/TrafficMgr.cxx +++ b/src/Traffic/TrafficMgr.cxx @@ -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 tokens, depTime,arrTime; + vector ::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& 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 << ')'); } + diff --git a/src/Traffic/TrafficMgr.hxx b/src/Traffic/TrafficMgr.hxx index 23d9b4c6c..c1a4465a8 100644 --- a/src/Traffic/TrafficMgr.hxx +++ b/src/Traffic/TrafficMgr.hxx @@ -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 #include +#include #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& 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 ();