X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FTraffic%2FSchedule.cxx;h=a47dfd2ca3493c2485be2d0b1181736b07747e0d;hb=070dba29f9390806457206c2660f2daebd3d847c;hp=85343db293fb8d605537eb8e2aea936ec8f06b6e;hpb=0025dfb9bccc45d7f96b1badbe7c867679669c9e;p=flightgear.git diff --git a/src/Traffic/Schedule.cxx b/src/Traffic/Schedule.cxx index 85343db29..a47dfd2ca 100644 --- a/src/Traffic/Schedule.cxx +++ b/src/Traffic/Schedule.cxx @@ -36,68 +36,74 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include #include #include -#include +#include #include
// That's pretty ugly, but I need fgFindAirportID #include "SchedFlight.hxx" #include "TrafficMgr.hxx" +using std::string; + /****************************************************************************** * the FGAISchedule class contains data members and code to maintain a - * schedule of Flights for an articically controlled aircraft. + * schedule of Flights for an artificially controlled aircraft. *****************************************************************************/ FGAISchedule::FGAISchedule() + : heavy(false), + radius(0), + groundOffset(0), + distanceToUser(0), + score(0), + runCount(0), + hits(0), + lastRun(0), + firstRun(false), + courseToDest(0), + initialized(false), + valid(false), + scheduleComplete(false) { - firstRun = true; - AIManagerRef = 0; - - heavy = false; - radius = 0; - groundOffset = 0; - distanceToUser = 0; - valid = true; - lastRun = 0; - //score = 0; } -/* -FGAISchedule::FGAISchedule(string mdl, - string liv, - string reg, - bool hvy, - string act, - string arln, - string mclass, - string fltpe, - double rad, - double grnd, - int scre, - FGScheduledFlightVec flt)*/ -FGAISchedule::FGAISchedule(string model, - string lvry, - string port, - string reg, - string flightId, + +FGAISchedule::FGAISchedule(const string& model, + const string& lvry, + const string& port, + const string& reg, + const string& flightId, bool hvy, - string act, - string arln, - string mclass, - string fltpe, + const string& act, + const string& arln, + const string& mclass, + const string& fltpe, double rad, double grnd) + : heavy(hvy), + radius(rad), + groundOffset(grnd), + distanceToUser(0), + score(0), + runCount(0), + hits(0), + lastRun(0), + firstRun(true), + courseToDest(0), + initialized(false), + valid(true), + scheduleComplete(false) { modelPath = model; livery = lvry; @@ -108,22 +114,10 @@ FGAISchedule::FGAISchedule(string model, airline = arln; m_class = mclass; flightType = fltpe; - 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 = 0; - firstRun = true; - runCount = 0; - hits = 0; - lastRun = 0; - initialized = false; - valid = true; } FGAISchedule::FGAISchedule(const FGAISchedule &other) @@ -135,7 +129,7 @@ FGAISchedule::FGAISchedule(const FGAISchedule &other) heavy = other.heavy; flightIdentifier = other.flightIdentifier; flights = other.flights; - AIManagerRef = other.AIManagerRef; + aiAircraft = other.aiAircraft; acType = other.acType; airline = other.airline; m_class = other.m_class; @@ -150,14 +144,22 @@ FGAISchedule::FGAISchedule(const FGAISchedule &other) runCount = other.runCount; hits = other.hits; lastRun = other.lastRun; + courseToDest = other.courseToDest; initialized = other.initialized; valid = other.valid; + scheduleComplete = other.scheduleComplete; } FGAISchedule::~FGAISchedule() { + // remove related object from AI manager + if (aiAircraft) + { + aiAircraft->setDie(true); + } + /* for (FGScheduledFlightVecIterator flt = flights.begin(); flt != flights.end(); flt++) { delete (*flt); @@ -191,22 +193,37 @@ bool FGAISchedule::init() return true; } +/** + * Returns true when processing is complete. + * Returns false when processing was aborted due to timeout, so + * more time required - and another call is requested (next sim iteration). + */ bool FGAISchedule::update(time_t now, const SGVec3d& userCart) -{ - time_t - totalTimeEnroute, - elapsedTimeEnroute, - remainingTimeEnroute, - deptime = 0; +{ + + time_t totalTimeEnroute, + elapsedTimeEnroute, + //remainingTimeEnroute, + deptime = 0; + if (!valid) { - return false; + return true; // processing complete + } + + if (!scheduleComplete) { + scheduleComplete = scheduleFlights(now); + } + + if (!scheduleComplete) { + return false; // not ready yet, continue processing in next iteration } - scheduleFlights(now); + if (flights.empty()) { // No flights available for this aircraft valid = false; - return false; + return true; // processing complete } - + + // 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. @@ -220,17 +237,15 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart) firstRun = false; } - FGScheduledFlight* flight = flights.front(); + FGScheduledFlight* flight = flights.front(); if (!deptime) { deptime = flight->getDepartureTime(); - //cerr << "Settiing departure time " << deptime << endl; + //cerr << "Setting departure time " << deptime << endl; } - if (AIManagerRef) { - // Check if this aircraft has been released. - FGTrafficManager *tmgr = (FGTrafficManager *) globals->get_subsystem("traffic-manager"); - if (tmgr->isReleased(AIManagerRef)) { - AIManagerRef = 0; + if (aiAircraft) { + if (aiAircraft->getDie()) { + aiAircraft = NULL; } else { return true; // in visual range, let the AIManager handle it } @@ -239,19 +254,19 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart) // This flight entry is entirely in the past, do we need to // push it forward in time to the next scheduled departure. if (flight->getArrivalTime() < now) { - SG_LOG (SG_GENERAL, SG_BULK, "Traffic Manager: Flight is in the Past"); + SG_LOG (SG_AI, SG_BULK, "Traffic Manager: Flight is in the Past"); // 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. - flight->update(); + flight->update(); flights.erase(flights.begin()); // pop_front(), effectively - return true; - } + return true; // processing complete + } FGAirport* dep = flight->getDepartureAirport(); FGAirport* arr = flight->getArrivalAirport(); if (!dep || !arr) { - return false; + return true; // processing complete } double speed = 450.0; @@ -259,7 +274,7 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart) totalTimeEnroute = flight->getArrivalTime() - flight->getDepartureTime(); if (flight->getDepartureTime() < now) { elapsedTimeEnroute = now - flight->getDepartureTime(); - remainingTimeEnroute = totalTimeEnroute - elapsedTimeEnroute; + //remainingTimeEnroute = totalTimeEnroute - elapsedTimeEnroute; double x = elapsedTimeEnroute / (double) totalTimeEnroute; // current pos is based on great-circle course between departure/arrival, @@ -271,19 +286,19 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart) SGGeodesy::direct(dep->geod(), course, coveredDistance, position, az2); - SG_LOG (SG_GENERAL, SG_BULK, "Traffic Manager: Flight is in progress, %=" << x); + SG_LOG (SG_AI, SG_BULK, "Traffic Manager: Flight is in progress, %=" << x); speed = ((distanceM - coveredDistance) * SG_METER_TO_NM) / 3600.0; } else { // not departed yet - remainingTimeEnroute = totalTimeEnroute; + //remainingTimeEnroute = totalTimeEnroute; elapsedTimeEnroute = 0; position = dep->geod(); - SG_LOG (SG_GENERAL, SG_BULK, "Traffic Manager: Flight is pending, departure in " + SG_LOG (SG_AI, SG_BULK, "Traffic Manager: Flight is pending, departure in " << flight->getDepartureTime() - now << " seconds "); } } else { // departure / arrival coincident - remainingTimeEnroute = totalTimeEnroute = 0.0; + //remainingTimeEnroute = totalTimeEnroute = 0.0; elapsedTimeEnroute = 0; position = dep->geod(); } @@ -292,17 +307,50 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart) // large distances involved here: see bug #80 distanceToUser = dist(userCart, SGVec3d::fromGeod(position)) * SG_METER_TO_NM; - // If distance between user and simulated aircaft is less + + // If distance between user and simulated aircraft is less // then 500nm, create this flight. At jet speeds 500 nm is roughly // one hour flight time, so that would be a good approximate point // to start a more detailed simulation of this aircraft. - SG_LOG (SG_GENERAL, SG_BULK, "Traffic manager: " << registration << " is scheduled for a flight from " + SG_LOG (SG_AI, SG_BULK, "Traffic manager: " << registration << " is scheduled for a flight from " << dep->getId() << " to " << arr->getId() << ". Current distance to user: " << distanceToUser); if (distanceToUser >= TRAFFICTOAIDISTTOSTART) { return true; // out of visual range, for the moment. } - return createAIAircraft(flight, speed, deptime); + + if (!createAIAircraft(flight, speed, deptime)) { + valid = false; + } + + + return true; // processing complete +} + +bool FGAISchedule::validModelPath(const std::string& modelPath) +{ + return (resolveModelPath(modelPath) != SGPath()); +} + +SGPath FGAISchedule::resolveModelPath(const std::string& modelPath) +{ + BOOST_FOREACH(SGPath aiPath, globals->get_data_paths("AI")) { + aiPath.append(modelPath); + if (aiPath.exists()) { + return aiPath; + } + } + + // check aircraft dirs + BOOST_FOREACH(std::string aircraftPath, globals->get_aircraft_paths()) { + SGPath mp(aircraftPath); + mp.append(modelPath); + if (mp.exists()) { + return mp; + } + } + + return SGPath(); } bool FGAISchedule::createAIAircraft(FGScheduledFlight* flight, double speedKnots, time_t deptime) @@ -310,35 +358,22 @@ bool FGAISchedule::createAIAircraft(FGScheduledFlight* flight, double speedKnots FGAirport* dep = flight->getDepartureAirport(); FGAirport* arr = flight->getArrivalAirport(); string flightPlanName = dep->getId() + "-" + arr->getId() + ".xml"; - SG_LOG(SG_GENERAL, SG_INFO, "Traffic manager: Creating AIModel from:" << flightPlanName); - - // Only allow traffic to be created when the model path (or the AI version of mp) exists - SGPath mp(globals->get_fg_root()); - SGPath mp_ai = mp; - - mp.append(modelPath); - mp_ai.append("AI"); - mp_ai.append(modelPath); - - if (!mp.exists() && !mp_ai.exists()) { - SG_LOG(SG_GENERAL, SG_WARN, "TrafficManager: Could not load model " << mp.str()); - return true; - } + SG_LOG(SG_AI, SG_DEBUG, "Traffic manager: Creating AIModel from:" << flightPlanName); - FGAIAircraft *aircraft = new FGAIAircraft(this); - aircraft->setPerformance(m_class); //"jet_transport"; - aircraft->setCompany(airline); //i->getAirline(); - aircraft->setAcType(acType); //i->getAcType(); - aircraft->setPath(modelPath.c_str()); + aiAircraft = new FGAIAircraft(this); + aiAircraft->setPerformance(acType, m_class); //"jet_transport"; + aiAircraft->setCompany(airline); //i->getAirline(); + aiAircraft->setAcType(acType); //i->getAcType(); + aiAircraft->setPath(modelPath.c_str()); //aircraft->setFlightPlan(flightPlanName); - aircraft->setLatitude(position.getLatitudeDeg()); - aircraft->setLongitude(position.getLongitudeDeg()); - aircraft->setAltitude(flight->getCruiseAlt()*100); // convert from FL to feet - aircraft->setSpeed(speedKnots); - aircraft->setBank(0); + aiAircraft->setLatitude(position.getLatitudeDeg()); + aiAircraft->setLongitude(position.getLongitudeDeg()); + aiAircraft->setAltitude(flight->getCruiseAlt()*100); // convert from FL to feet + aiAircraft->setSpeed(0); + aiAircraft->setBank(0); courseToDest = SGGeodesy::courseDeg(position, arr->geod()); - FGAIFlightPlan *fp = new FGAIFlightPlan(aircraft, flightPlanName, courseToDest, deptime, + FGAIFlightPlan *fp = new FGAIFlightPlan(aiAircraft, flightPlanName, courseToDest, deptime, dep, arr, true, radius, flight->getCruiseAlt()*100, position.getLatitudeDeg(), @@ -346,13 +381,12 @@ bool FGAISchedule::createAIAircraft(FGScheduledFlight* flight, double speedKnots speedKnots, flightType, acType, airline); if (fp->isValidPlan()) { - aircraft->SetFlightPlan(fp); + aiAircraft->SetFlightPlan(fp); FGAIManager* aimgr = (FGAIManager *) globals-> get_subsystem("ai-model"); - aimgr->attach(aircraft); - AIManagerRef = aircraft->getID(); + aimgr->attach(aiAircraft); return true; } else { - delete aircraft; + aiAircraft = NULL; delete fp; //hand back the flights that had already been scheduled while (!flights.empty()) { @@ -369,35 +403,32 @@ void FGAISchedule::setHeading() courseToDest = SGGeodesy::courseDeg((*flights.begin())->getDepartureAirport()->geod(), (*flights.begin())->getArrivalAirport()->geod()); } -void FGAISchedule::scheduleFlights(time_t now) +bool FGAISchedule::scheduleFlights(time_t now) { - if (!flights.empty()) { - return; - } //string startingPort; - string userPort = fgGetString("/sim/presets/airport-id"); - SG_LOG(SG_GENERAL, SG_BULK, "Scheduling Flights for : " << modelPath << " " << registration << " " << homePort); + const string& userPort = fgGetString("/sim/presets/airport-id"); + SG_LOG(SG_AI, SG_BULK, "Scheduling Flights for : " << modelPath << " " << registration << " " << homePort); FGScheduledFlight *flight = NULL; + SGTimeStamp start; + start.stamp(); + + bool first = true; + if (currentDestination.empty()) + flight = findAvailableFlight(userPort, flightIdentifier, now, (now+6400)); + do { - if (currentDestination.empty()) { - flight = findAvailableFlight(userPort, flightIdentifier, now, (now+6400)); - if (!flight) - flight = findAvailableFlight(currentDestination, flightIdentifier); - } else { + if ((!flight)||(!first)) { flight = findAvailableFlight(currentDestination, flightIdentifier); } if (!flight) { break; } - //if (startingPort.empty()) { - // startingPort = flight->getDepartureAirport()->getId(); - //} + + first = false; currentDestination = flight->getArrivalAirport()->getId(); //cerr << "Current destination " << currentDestination << endl; if (!initialized) { - string departurePort = flight->getDepartureAirport()->getId(); - //cerr << "Scheduled " << registration << " " << score << " for Flight " - // << flight-> getCallSign() << " from " << departurePort << " to " << currentDestination << endl; + const string& departurePort = flight->getDepartureAirport()->getId(); if (userPort == departurePort) { lastRun = 1; hits++; @@ -408,23 +439,36 @@ void FGAISchedule::scheduleFlights(time_t now) initialized = true; } - 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_BULK, " Flight " << flight->getCallSign() << ":" - << " " << flight->getDepartureAirport()->getId() << ":" - << " " << depT << ":" - << " \"" << flight->getArrivalAirport()->getId() << "\"" << ":" - << " " << arrT << ":"); + if (sglog().would_log(SG_AI, SG_BULK)) + { + 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_AI, SG_BULK, " Flight " << flight->getCallSign() << ":" + << " " << flight->getDepartureAirport()->getId() << ":" + << " " << depT << ":" + << " \"" << flight->getArrivalAirport()->getId() << "\"" << ":" + << " " << arrT << ":"); + } flights.push_back(flight); - } while (currentDestination != homePort); - SG_LOG(SG_GENERAL, SG_BULK, " Done "); + + // continue processing until complete, or preempt after timeout + } while ((currentDestination != homePort)&& + (start.elapsedMSec()<3.0)); + + if (flight && (currentDestination != homePort)) + { + // processing preempted, need to continue in next iteration + return false; + } + + SG_LOG(SG_AI, SG_BULK, " Done "); + return true; } bool FGAISchedule::next() @@ -505,7 +549,7 @@ FGScheduledFlight* FGAISchedule::findAvailableFlight (const string ¤tDesti continue; } } - if (flights.size()) { + if (! flights.empty()) { time_t arrival = flights.back()->getArrivalTime(); int groundTime = groundTimeFromRadius(); if ((*i)->getDepartureTime() < (arrival+(groundTime)))