X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FTraffic%2FSchedule.cxx;h=3b8e7636db1946dca5d873df945a2236272323ff;hb=474789269b7656509f62339c17e62a55b6157d43;hp=309d9340b1b0b9694d494a401b00424070942766;hpb=13ec36af4218402eda39c680e8da6ca2c198733c;p=flightgear.git diff --git a/src/Traffic/Schedule.cxx b/src/Traffic/Schedule.cxx index 309d9340b..3b8e7636d 100644 --- a/src/Traffic/Schedule.cxx +++ b/src/Traffic/Schedule.cxx @@ -55,8 +55,6 @@ #include "SchedFlight.hxx" #include "TrafficMgr.hxx" -using std::sort; - /****************************************************************************** * the FGAISchedule class contains data members and code to maintain a * schedule of Flights for an articically controlled aircraft. @@ -67,8 +65,6 @@ FGAISchedule::FGAISchedule() AIManagerRef = 0; heavy = false; - lat = 0; - lon = 0; radius = 0; groundOffset = 0; distanceToUser = 0; @@ -110,8 +106,6 @@ FGAISchedule::FGAISchedule(string model, airline = arln; m_class = mclass; flightType = fltpe; - lat = 0; - lon = 0; radius = rad; groundOffset = grnd; distanceToUser = 0; @@ -121,8 +115,11 @@ FGAISchedule::FGAISchedule(string model, i++) flights.push_back(new FGScheduledFlight((*(*i))));*/ AIManagerRef = 0; - //score = scre; + score = 0; firstRun = true; + runCount = 0; + hits = 0; + initialized = false; } FGAISchedule::FGAISchedule(const FGAISchedule &other) @@ -134,8 +131,6 @@ FGAISchedule::FGAISchedule(const FGAISchedule &other) heavy = other.heavy; flightIdentifier = other.flightIdentifier; flights = other.flights; - lat = other.lat; - lon = other.lon; AIManagerRef = other.AIManagerRef; acType = other.acType; airline = other.airline; @@ -144,13 +139,17 @@ FGAISchedule::FGAISchedule(const FGAISchedule &other) radius = other.radius; groundOffset = other.groundOffset; flightType = other.flightType; - //score = other.score; + score = other.score; distanceToUser = other.distanceToUser; currentDestination = other.currentDestination; firstRun = other.firstRun; + runCount = other.runCount; + hits = other.hits; + initialized = other.initialized; } + FGAISchedule::~FGAISchedule() { /* for (FGScheduledFlightVecIterator flt = flights.begin(); flt != flights.end(); flt++) @@ -186,308 +185,243 @@ bool FGAISchedule::init() return true; } -bool FGAISchedule::update(time_t now) +bool FGAISchedule::update(time_t now, const SGVec3d& userCart) { - FGAirport *dep; - FGAirport *arr; - double angle; - - FGAIManager *aimgr; - string airport; - - double speed; - + if (!fgGetBool("/sim/traffic-manager/enabled")) + return true; + time_t totalTimeEnroute, elapsedTimeEnroute, - remainingTimeEnroute, deptime = 0; - double - userLatitude, - userLongitude; - - SGVec3d newPos(0, 0, 0); - - - if (fgGetBool("/sim/traffic-manager/enabled") == false) - return true; + remainingTimeEnroute, + deptime = 0; - aimgr = (FGAIManager *) globals-> get_subsystem("ai_model"); - // 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_BULK, "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_BULK, " " << flight->getCallSign() << ":" - << " " << flight->getDepartureAirport()->getId() << ":" - << " " << depT << ":" - << " \"" << flight->getArrivalAirport()->getId() << "\"" << ":" - << " " << arrT << ":"); - flights.push_back(flight); - } - } while ((currentDestination != homePort) && (flight != 0)); - SG_LOG(SG_GENERAL, SG_BULK, cerr << " Done " << endl); - } - //cerr << " Done " << endl; - // No flights available for this aircraft - if (flights.size() == 0) { + scheduleFlights(); + if (flights.empty()) { // No flights available for this aircraft 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); - if (firstRun) { + + 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 + 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(); - SG_LOG (SG_GENERAL, SG_DEBUG,"Traffic Manager: Processing registration " << registration << " with callsign " << (*i)->getCallSign()); - if (AIManagerRef) - { - // Check if this aircraft has been released. - FGTrafficManager *tmgr = (FGTrafficManager *) globals->get_subsystem("Traffic Manager"); - if (tmgr->isReleased(AIManagerRef)) - AIManagerRef = 0; + + FGScheduledFlight* flight = flights.front(); + if (!deptime) { + deptime = flight->getDepartureTime(); + //cerr << "Settiing 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 = NULL; + } else { + return true; // in visual range, let the AIManager handle it } - - if (!AIManagerRef) - { - userLatitude = fgGetDouble("/position/latitude-deg"); - userLongitude = fgGetDouble("/position/longitude-deg"); - - //cerr << "Estimated minimum distance to user: " << distanceToUser << endl; - // This flight entry is entirely in the past, do we need to - // push it forward in time to the next scheduled departure. - 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); + } + + // 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"); + // 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(); + flights.erase(flights.begin()); // pop_front(), effectively return true; } - - // Departure time in the past and arrival time in the future. - // This flight is in progress, so we need to calculate it's - // approximate position and -if in range- create an AIAircraft - // object for it. - //if ((i->getDepartureTime() < now) && (i->getArrivalTime() > now)) + + FGAirport* dep = flight->getDepartureAirport(); + FGAirport* arr = flight->getArrivalAirport(); + if (!dep || !arr) { + return false; + } + + double speed = 450.0; + if (dep != arr) { + totalTimeEnroute = flight->getArrivalTime() - flight->getDepartureTime(); + if (flight->getDepartureTime() < now) { + elapsedTimeEnroute = now - flight->getDepartureTime(); + remainingTimeEnroute = totalTimeEnroute - elapsedTimeEnroute; + double x = elapsedTimeEnroute / (double) totalTimeEnroute; - // Part of this flight is in the future. - if ((*i)->getArrivalTime() > now) - { - - dep = (*i)->getDepartureAirport(); - arr = (*i)->getArrivalAirport (); - if (!(dep && arr)) - return false; - - if (dep != arr) { - SGVec3d a = SGVec3d::fromGeoc(SGGeoc::fromDegM(dep->getLongitude(), - dep->getLatitude(), 1)); - SGVec3d b = SGVec3d::fromGeoc(SGGeoc::fromDegM(arr->getLongitude(), - arr->getLatitude(), 1)); - SGVec3d _cross = cross(b, a); - - angle = sgACos(dot(a, b)); - - // Okay, at this point we have the angle between departure and - // arrival airport, in degrees. From here we can interpolate the - // position of the aircraft by calculating the ratio between - // total time enroute and elapsed time enroute. - - totalTimeEnroute = (*i)->getArrivalTime() - (*i)->getDepartureTime(); - if (now > (*i)->getDepartureTime()) - { - //err << "Lat = " << lat << ", lon = " << lon << endl; - //cerr << "Time diff: " << now-i->getDepartureTime() << endl; - elapsedTimeEnroute = now - (*i)->getDepartureTime(); - remainingTimeEnroute = (*i)->getArrivalTime() - now; - SG_LOG (SG_GENERAL, SG_DEBUG, "Traffic Manager: Flight is in progress."); - } - else - { - lat = dep->getLatitude(); - lon = dep->getLongitude(); - elapsedTimeEnroute = 0; - remainingTimeEnroute = totalTimeEnroute; - SG_LOG (SG_GENERAL, SG_DEBUG, "Traffic Manager: Flight is pending."); - } - angle *= ( (double) elapsedTimeEnroute/ (double) totalTimeEnroute); - //cout << "a = " << a[0] << " " << a[1] << " " << a[2] - // << "b = " << b[0] << " " << b[1] << " " << b[2] << endl; - sgdMat4 matrix; - sgdMakeRotMat4(matrix, angle, _cross.data()); - for(int j = 0; j < 3; j++) { - for (int k = 0; k<3; k++) { - newPos[j] += matrix[j][k]*a[k]; - } - } - } - SGGeod current; - if ((now > (*i)->getDepartureTime() && (dep != arr))) { - current = SGGeod::fromCart(newPos); - speed = SGGeodesy::distanceNm(current, arr->geod()) / - ((double) remainingTimeEnroute/3600.0); - } else { - current = dep->geod(); - speed = 450; - } - SGGeod user = SGGeod::fromDegM(userLongitude, userLatitude, (*i)->getCruiseAlt()); - - distanceToUser = SGGeodesy::distanceNm(current, user); - - // If distance between user and simulated aircaft 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_DEBUG, "Traffic manager: " << registration << " is scheduled for a flight from " + // current pos is based on great-circle course between departure/arrival, + // with percentage of distance travelled, based upon percentage of time + // enroute elapsed. + double course, az2, distanceM; + SGGeodesy::inverse(dep->geod(), arr->geod(), course, az2, distanceM); + double coveredDistance = distanceM * x; + + SGGeodesy::direct(dep->geod(), course, coveredDistance, position, az2); + + SG_LOG (SG_GENERAL, SG_BULK, "Traffic Manager: Flight is in progress, %=" << x); + speed = ((distanceM - coveredDistance) * SG_METER_TO_NM) / 3600.0; + } else { + // not departed yet + remainingTimeEnroute = totalTimeEnroute; + elapsedTimeEnroute = 0; + position = dep->geod(); + SG_LOG (SG_GENERAL, SG_BULK, "Traffic Manager: Flight is pending, departure in " + << flight->getDepartureTime() - now << " seconds "); + } + } else { + // departure / arrival coincident + remainingTimeEnroute = totalTimeEnroute = 0.0; + elapsedTimeEnroute = 0; + position = dep->geod(); + } + + // cartesian calculations are more numerically stable over the (potentially) + // 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 + // 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 " << dep->getId() << " to " << arr->getId() << ". Current distance to user: " << distanceToUser); - if (distanceToUser < TRAFFICTOAIDISTTOSTART) - { - string flightPlanName = dep->getId() + string("-") + arr->getId() + - string(".xml"); - SG_LOG (SG_GENERAL, SG_DEBUG, "Traffic manager: Creating AIModel"); - //int alt; - //if ((i->getDepartureTime() < now)) - //{ - // alt = i->getCruiseAlt() *100; - // } - //else - //{ - // alt = dep->_elevation+19; - // } - - // 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()) - { - 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()); - //aircraft->setFlightPlan(flightPlanName); - aircraft->setLatitude(lat); - aircraft->setLongitude(lon); - aircraft->setAltitude((*i)->getCruiseAlt()*100); // convert from FL to feet - aircraft->setSpeed(speed); - aircraft->setBank(0); + if (distanceToUser >= TRAFFICTOAIDISTTOSTART) { + return true; // out of visual range, for the moment. + } + return createAIAircraft(flight, speed, deptime); +} + +bool FGAISchedule::createAIAircraft(FGScheduledFlight* flight, double speedKnots, time_t deptime) +{ + 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_INPUT, SG_WARN, "TrafficManager: Could not load model " << mp.str()); + return true; + } + + 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()); + //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); - courseToDest = SGGeodesy::courseDeg(current, arr->geod()); - aircraft->SetFlightPlan(new FGAIFlightPlan(aircraft, flightPlanName, courseToDest, deptime, - dep, arr,true, radius, - (*i)->getCruiseAlt()*100, - lat, lon, speed, flightType, acType, + courseToDest = SGGeodesy::courseDeg(position, arr->geod()); + aircraft->SetFlightPlan(new FGAIFlightPlan(aircraft, flightPlanName, courseToDest, deptime, + dep, arr, true, radius, + flight->getCruiseAlt()*100, + position.getLatitudeDeg(), + position.getLongitudeDeg(), + speedKnots, flightType, acType, airline)); - aimgr->attach(aircraft); - - - AIManagerRef = aircraft->getID(); - //cerr << "Class: " << m_class << ". acType: " << acType << ". Airline: " << airline << ". Speed = " << speed << ". From " << dep->getId() << " to " << arr->getId() << ". Time Fraction = " << (remainingTimeEnroute/(double) totalTimeEnroute) << endl; - //cerr << "Latitude : " << lat << ". Longitude : " << lon << endl; - //cerr << "Dep : " << dep->getLatitude()<< ", "<< dep->getLongitude() << endl; - //cerr << "Arr : " << arr->getLatitude()<< ", "<< arr->getLongitude() << endl; - //cerr << "Time remaining = " << (remainingTimeEnroute/3600.0) << endl; - //cerr << "Total time = " << (totalTimeEnroute/3600.0) << endl; - //cerr << "Distance remaining = " << distanceToDest*SG_METER_TO_NM << endl; - } - else - { - SG_LOG(SG_INPUT, SG_WARN, "TrafficManager: Could not load model " << mp.str()); - } - } - return true; - } + + + FGAIManager* aimgr = (FGAIManager *) globals-> get_subsystem("ai_model"); + aimgr->attach(aircraft); + AIManagerRef = aircraft->getID(); + return true; +} - // Both departure and arrival time are in the future, so this - // the aircraft is parked at the departure airport. - // Currently this status is mostly ignored, but in future - // versions, code should go here that -if within user range- - // positions these aircraft at parking locations at the airport. - if (((*i)->getDepartureTime() > now) && ((*i)->getArrivalTime() > now)) - { - dep = (*i)->getDepartureAirport(); - return true; - } +void FGAISchedule::scheduleFlights() +{ + if (!flights.empty()) { + return; + } + + SG_LOG(SG_GENERAL, SG_BULK, "Scheduling for : " << modelPath << " " << registration << " " << homePort); + FGScheduledFlight *flight = NULL; + do { + flight = findAvailableFlight(currentDestination, flightIdentifier); + if (!flight) { + break; } - //cerr << "Traffic schedule got to beyond last clause" << endl; - // EMH: prevent a warning, should this be 'true' instead? - // DT: YES. Originally, this code couldn't be reached, but - // when the "if(!(AIManagerManager))" clause is false we - // fall through right to the end. This is a valid flow. - // the actual value is pretty innocent, only it triggers - // warning in TrafficManager::update(). - // (which was added as a sanity check for myself in the first place. :-) - return true; + + currentDestination = flight->getArrivalAirport()->getId(); + if (!initialized) { + string departurePort = flight->getDepartureAirport()->getId(); + //cerr << "Scheduled " << registration << " " << score << " for Flight " + // << flight-> getCallSign() << " from " << departurePort << " to " << currentDestination << endl; + if (fgGetString("/sim/presets/airport-id") == departurePort) { + hits++; + } + //runCount++; + 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->getCallSign() << ":" + << " " << flight->getDepartureAirport()->getId() << ":" + << " " << depT << ":" + << " \"" << flight->getArrivalAirport()->getId() << "\"" << ":" + << " " << arrT << ":"); + + flights.push_back(flight); + } while (currentDestination != homePort); + SG_LOG(SG_GENERAL, SG_BULK, " Done "); } - 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; + if (!flights.empty()) { + flights.front()->release(); + flights.erase(flights.begin()); + } + 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; + if (!flight) { + return false; } - //cerr << "FGAISchedule :: next needs updating" << endl; - //exit(1); + + 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; } FGScheduledFlight* FGAISchedule::findAvailableFlight (const string ¤tDestination, @@ -513,7 +447,7 @@ FGScheduledFlight* FGAISchedule::findAvailableFlight (const string ¤tDesti //sort(fltBegin, fltEnd, compareScheduledFlights); //cerr << counter++ << endl; } - sort(fltBegin, fltEnd, compareScheduledFlights); + std::sort(fltBegin, fltEnd, compareScheduledFlights); for (FGScheduledFlightVecIterator i = fltBegin; i != fltEnd; i++) { //bool valid = true; counter++; @@ -548,7 +482,7 @@ FGScheduledFlight* FGAISchedule::findAvailableFlight (const string ¤tDesti // is departure port valid? // is arrival port valid? //cerr << "Ack no flight found: " << endl; - return 0; + return NULL; } double FGAISchedule::getSpeed() @@ -564,12 +498,26 @@ double FGAISchedule::getSpeed() SG_CLAMP_RANGE(speed, 300.0, 500.0); return speed; } -/* + +void FGAISchedule::setScore () +{ + if (runCount) { + score = ((double) hits / (double) runCount); + } else { + if (homePort == fgGetString("/sim/presets/airport-id")) { + score = 0.1; + } else { + score = 0.0; + } + } + runCount++; +} + bool compareSchedules(FGAISchedule*a, FGAISchedule*b) { - //return (*a) < (*b); + return (*a) < (*b); } -*/ + // void FGAISchedule::setClosestDistanceToUser() // { @@ -578,7 +526,6 @@ bool compareSchedules(FGAISchedule*a, FGAISchedule*b) // double course; // double dist; -// Point3D temp; // time_t // totalTimeEnroute, // elapsedTimeEnroute;