2004-06-03 17:59:14 +00:00
|
|
|
/******************************************************************************
|
|
|
|
* Schedule.cxx
|
|
|
|
* Written by Durk Talsma, started May 5, 2004.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License as
|
|
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
|
|
* License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
2006-02-21 01:16:04 +00:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2004-06-03 17:59:14 +00:00
|
|
|
*
|
|
|
|
*
|
|
|
|
****************************************************************************
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
2006-02-18 13:58:09 +00:00
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
|
|
|
|
2006-07-29 18:17:19 +00:00
|
|
|
#define BOGUS 0xFFFF
|
|
|
|
|
2004-06-03 17:59:14 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <iostream>
|
|
|
|
#include <fstream>
|
|
|
|
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
2004-06-06 08:35:09 +00:00
|
|
|
#include <algorithm>
|
2004-06-03 17:59:14 +00:00
|
|
|
|
|
|
|
#include <simgear/compiler.h>
|
2009-01-04 17:11:25 +00:00
|
|
|
#include <simgear/sg_inlines.h>
|
2004-06-03 17:59:14 +00:00
|
|
|
#include <simgear/math/sg_geodesy.hxx>
|
|
|
|
#include <simgear/props/props.hxx>
|
|
|
|
#include <simgear/route/waypoint.hxx>
|
|
|
|
#include <simgear/structure/subsystem_mgr.hxx>
|
|
|
|
#include <simgear/xml/easyxml.hxx>
|
|
|
|
|
|
|
|
#include <AIModel/AIFlightPlan.hxx>
|
|
|
|
#include <AIModel/AIManager.hxx>
|
2006-02-11 13:16:56 +00:00
|
|
|
#include <AIModel/AIAircraft.hxx>
|
2004-06-03 17:59:14 +00:00
|
|
|
#include <Airports/simple.hxx>
|
|
|
|
#include <Main/fg_init.hxx> // That's pretty ugly, but I need fgFindAirportID
|
|
|
|
|
|
|
|
|
|
|
|
#include "SchedFlight.hxx"
|
|
|
|
#include "TrafficMgr.hxx"
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
* the FGAISchedule class contains data members and code to maintain a
|
|
|
|
* schedule of Flights for an articically controlled aircraft.
|
|
|
|
*****************************************************************************/
|
|
|
|
FGAISchedule::FGAISchedule()
|
|
|
|
{
|
|
|
|
firstRun = true;
|
|
|
|
AIManagerRef = 0;
|
2005-12-06 18:32:07 +00:00
|
|
|
|
|
|
|
heavy = false;
|
|
|
|
radius = 0;
|
|
|
|
groundOffset = 0;
|
|
|
|
distanceToUser = 0;
|
2011-04-19 18:01:24 +02:00
|
|
|
valid = true;
|
A number of cosmetic and/or infrastructural changes.
Traffic Manager:
* Just continue routing until we run out of flights. This change removes one of the major requirements for setting the "Home port" field.
* Add a time restriction requirement for the aircraft scheduler; this became necessary after removing the limited-to-home-port routing restriction.
* Added a new field to the heuristics calculation: take into account whether an aircraft has already been used in a previous session. Rotate aircraft assignments for greater variability across sessions.
* Added a revision number to the cache files, so that old cache results, which are no longer compatible with the new file format, are discarded.
Groundnetwork and traffic control:
* Added a revision number to the cache files, so that old and incompatible results are discarded.
* The caching algorithm probably didn't store the correct data for airports that were processed while the user was quite far away. This is now corrected by checking whether the cached elevation data are equal to the generic airport elevation.
AIAircraft:
* I've been searching for the infamous aircraft bend-over-backward bug, that can occur during initialization, but to no avail yet. The only variable potentially responsible (tgt_vs) wich can explain the irregular jumping behavior, as well as the weird pitch results is initialized in AIAircraft's only constructor (through AIBase), and I can't find any situation in the ground handling code where this variable could get bizarre values. But,
* a couple of tgt_vs. calculations appear to be completely redundant. This value was calculated twice inside the ProcessFlightplan function, and subsequently again in the updateSecondaryTargetValues function. I have removed the calculations in the process flightplan function, without any apparent side effect.
2011-09-04 20:27:36 +02:00
|
|
|
lastRun = 0;
|
2008-11-16 13:45:24 +00:00
|
|
|
//score = 0;
|
2004-06-03 17:59:14 +00:00
|
|
|
}
|
|
|
|
|
2008-11-16 13:45:24 +00:00
|
|
|
/*
|
2004-06-03 17:59:14 +00:00
|
|
|
FGAISchedule::FGAISchedule(string mdl,
|
|
|
|
string liv,
|
|
|
|
string reg,
|
|
|
|
bool hvy,
|
2005-02-10 09:01:51 +00:00
|
|
|
string act,
|
|
|
|
string arln,
|
|
|
|
string mclass,
|
|
|
|
string fltpe,
|
|
|
|
double rad,
|
|
|
|
double grnd,
|
2006-07-29 18:17:19 +00:00
|
|
|
int scre,
|
2008-11-16 13:45:24 +00:00
|
|
|
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)
|
2004-06-03 17:59:14 +00:00
|
|
|
{
|
2008-11-16 13:45:24 +00:00
|
|
|
modelPath = model;
|
|
|
|
livery = lvry;
|
|
|
|
homePort = port;
|
|
|
|
registration = reg;
|
|
|
|
flightIdentifier = flightId;
|
|
|
|
acType = act;
|
|
|
|
airline = arln;
|
|
|
|
m_class = mclass;
|
|
|
|
flightType = fltpe;
|
|
|
|
radius = rad;
|
|
|
|
groundOffset = grnd;
|
|
|
|
distanceToUser = 0;
|
|
|
|
heavy = hvy;
|
|
|
|
/*for (FGScheduledFlightVecIterator i = flt.begin();
|
2004-06-03 17:59:14 +00:00
|
|
|
i != flt.end();
|
|
|
|
i++)
|
2008-11-16 13:45:24 +00:00
|
|
|
flights.push_back(new FGScheduledFlight((*(*i))));*/
|
|
|
|
AIManagerRef = 0;
|
2010-08-30 21:13:16 +02:00
|
|
|
score = 0;
|
2008-11-16 13:45:24 +00:00
|
|
|
firstRun = true;
|
2010-08-30 21:13:16 +02:00
|
|
|
runCount = 0;
|
|
|
|
hits = 0;
|
A number of cosmetic and/or infrastructural changes.
Traffic Manager:
* Just continue routing until we run out of flights. This change removes one of the major requirements for setting the "Home port" field.
* Add a time restriction requirement for the aircraft scheduler; this became necessary after removing the limited-to-home-port routing restriction.
* Added a new field to the heuristics calculation: take into account whether an aircraft has already been used in a previous session. Rotate aircraft assignments for greater variability across sessions.
* Added a revision number to the cache files, so that old cache results, which are no longer compatible with the new file format, are discarded.
Groundnetwork and traffic control:
* Added a revision number to the cache files, so that old and incompatible results are discarded.
* The caching algorithm probably didn't store the correct data for airports that were processed while the user was quite far away. This is now corrected by checking whether the cached elevation data are equal to the generic airport elevation.
AIAircraft:
* I've been searching for the infamous aircraft bend-over-backward bug, that can occur during initialization, but to no avail yet. The only variable potentially responsible (tgt_vs) wich can explain the irregular jumping behavior, as well as the weird pitch results is initialized in AIAircraft's only constructor (through AIBase), and I can't find any situation in the ground handling code where this variable could get bizarre values. But,
* a couple of tgt_vs. calculations appear to be completely redundant. This value was calculated twice inside the ProcessFlightplan function, and subsequently again in the updateSecondaryTargetValues function. I have removed the calculations in the process flightplan function, without any apparent side effect.
2011-09-04 20:27:36 +02:00
|
|
|
lastRun = 0;
|
2010-08-30 21:13:16 +02:00
|
|
|
initialized = false;
|
2011-04-19 18:01:24 +02:00
|
|
|
valid = true;
|
2004-06-03 17:59:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FGAISchedule::FGAISchedule(const FGAISchedule &other)
|
|
|
|
{
|
2008-11-16 13:45:24 +00:00
|
|
|
modelPath = other.modelPath;
|
|
|
|
homePort = other.homePort;
|
|
|
|
livery = other.livery;
|
|
|
|
registration = other.registration;
|
|
|
|
heavy = other.heavy;
|
|
|
|
flightIdentifier = other.flightIdentifier;
|
|
|
|
flights = other.flights;
|
|
|
|
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;
|
2010-08-30 21:13:16 +02:00
|
|
|
score = other.score;
|
2008-11-16 13:45:24 +00:00
|
|
|
distanceToUser = other.distanceToUser;
|
|
|
|
currentDestination = other.currentDestination;
|
|
|
|
firstRun = other.firstRun;
|
2010-08-30 21:13:16 +02:00
|
|
|
runCount = other.runCount;
|
|
|
|
hits = other.hits;
|
A number of cosmetic and/or infrastructural changes.
Traffic Manager:
* Just continue routing until we run out of flights. This change removes one of the major requirements for setting the "Home port" field.
* Add a time restriction requirement for the aircraft scheduler; this became necessary after removing the limited-to-home-port routing restriction.
* Added a new field to the heuristics calculation: take into account whether an aircraft has already been used in a previous session. Rotate aircraft assignments for greater variability across sessions.
* Added a revision number to the cache files, so that old cache results, which are no longer compatible with the new file format, are discarded.
Groundnetwork and traffic control:
* Added a revision number to the cache files, so that old and incompatible results are discarded.
* The caching algorithm probably didn't store the correct data for airports that were processed while the user was quite far away. This is now corrected by checking whether the cached elevation data are equal to the generic airport elevation.
AIAircraft:
* I've been searching for the infamous aircraft bend-over-backward bug, that can occur during initialization, but to no avail yet. The only variable potentially responsible (tgt_vs) wich can explain the irregular jumping behavior, as well as the weird pitch results is initialized in AIAircraft's only constructor (through AIBase), and I can't find any situation in the ground handling code where this variable could get bizarre values. But,
* a couple of tgt_vs. calculations appear to be completely redundant. This value was calculated twice inside the ProcessFlightplan function, and subsequently again in the updateSecondaryTargetValues function. I have removed the calculations in the process flightplan function, without any apparent side effect.
2011-09-04 20:27:36 +02:00
|
|
|
lastRun = other.lastRun;
|
2010-08-30 21:13:16 +02:00
|
|
|
initialized = other.initialized;
|
2011-04-19 18:01:24 +02:00
|
|
|
valid = other.valid;
|
2004-06-03 17:59:14 +00:00
|
|
|
}
|
|
|
|
|
2005-02-10 09:01:51 +00:00
|
|
|
|
2010-08-30 21:13:16 +02:00
|
|
|
|
2004-06-03 17:59:14 +00:00
|
|
|
FGAISchedule::~FGAISchedule()
|
|
|
|
{
|
2008-11-16 13:45:24 +00:00
|
|
|
/* for (FGScheduledFlightVecIterator flt = flights.begin(); flt != flights.end(); flt++)
|
2006-10-06 17:36:31 +00:00
|
|
|
{
|
|
|
|
delete (*flt);
|
|
|
|
}
|
2008-11-16 13:45:24 +00:00
|
|
|
flights.clear();*/
|
2004-06-03 17:59:14 +00:00
|
|
|
}
|
|
|
|
|
2005-02-10 09:01:51 +00:00
|
|
|
bool FGAISchedule::init()
|
|
|
|
{
|
|
|
|
//tm targetTimeDate;
|
|
|
|
//SGTime* currTimeDate = globals->get_time_params();
|
|
|
|
|
|
|
|
//tm *temp = currTimeDate->getGmt();
|
|
|
|
//char buffer[512];
|
|
|
|
//sgTimeFormatTime(&targetTimeDate, buffer);
|
|
|
|
//cout << "Scheduled Time " << buffer << endl;
|
|
|
|
//cout << "Time :" << time(NULL) << " SGTime : " << sgTimeGetGMT(temp) << endl;
|
2008-11-16 13:45:24 +00:00
|
|
|
/*for (FGScheduledFlightVecIterator i = flights.begin();
|
2005-02-10 09:01:51 +00:00
|
|
|
i != flights.end();
|
|
|
|
i++)
|
|
|
|
{
|
|
|
|
//i->adjustTime(now);
|
2006-10-06 17:36:31 +00:00
|
|
|
if (!((*i)->initializeAirports()))
|
2005-02-10 09:01:51 +00:00
|
|
|
return false;
|
2008-11-16 13:45:24 +00:00
|
|
|
} */
|
2005-02-10 09:01:51 +00:00
|
|
|
//sort(flights.begin(), flights.end());
|
|
|
|
// Since time isn't initialized yet when this function is called,
|
|
|
|
// Find the closest possible airport.
|
|
|
|
// This should give a reasonable initialization order.
|
2006-07-29 18:17:19 +00:00
|
|
|
//setClosestDistanceToUser();
|
2005-02-10 09:01:51 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-02-19 00:31:38 +00:00
|
|
|
bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
|
2008-11-16 13:45:24 +00:00
|
|
|
{
|
2004-06-03 17:59:14 +00:00
|
|
|
time_t
|
|
|
|
totalTimeEnroute,
|
|
|
|
elapsedTimeEnroute,
|
2010-02-19 00:31:38 +00:00
|
|
|
remainingTimeEnroute,
|
|
|
|
deptime = 0;
|
2011-04-19 18:01:24 +02:00
|
|
|
if (!valid) {
|
|
|
|
return false;
|
|
|
|
}
|
2010-02-19 00:31:38 +00:00
|
|
|
scheduleFlights();
|
|
|
|
if (flights.empty()) { // No flights available for this aircraft
|
2011-04-19 18:01:24 +02:00
|
|
|
valid = false;
|
2008-11-16 13:45:24 +00:00
|
|
|
return false;
|
|
|
|
}
|
2010-02-19 00:31:38 +00:00
|
|
|
|
2004-06-03 17:59:14 +00:00
|
|
|
// 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.
|
2008-11-16 13:45:24 +00:00
|
|
|
//sort(flights.begin(), flights.end(), compareScheduledFlights);
|
2010-02-19 00:31:38 +00:00
|
|
|
|
|
|
|
if (firstRun) {
|
2008-11-16 13:45:24 +00:00
|
|
|
if (fgGetBool("/sim/traffic-manager/instantaneous-action") == true) {
|
2010-04-25 08:32:53 +00:00
|
|
|
deptime = now; // + rand() % 300; // Wait up to 5 minutes until traffic starts moving to prevent too many aircraft
|
2008-11-16 13:45:24 +00:00
|
|
|
// from cluttering the gate areas.
|
|
|
|
}
|
|
|
|
firstRun = false;
|
|
|
|
}
|
2010-02-19 00:31:38 +00:00
|
|
|
|
2011-04-19 18:01:24 +02:00
|
|
|
FGScheduledFlight* flight = flights.front();
|
2010-04-25 08:32:53 +00:00
|
|
|
if (!deptime) {
|
2010-02-19 00:31:38 +00:00
|
|
|
deptime = flight->getDepartureTime();
|
2010-04-25 08:32:53 +00:00
|
|
|
//cerr << "Settiing departure time " << deptime << endl;
|
|
|
|
}
|
2010-02-19 00:31:38 +00:00
|
|
|
|
|
|
|
if (AIManagerRef) {
|
|
|
|
// Check if this aircraft has been released.
|
|
|
|
FGTrafficManager *tmgr = (FGTrafficManager *) globals->get_subsystem("Traffic Manager");
|
|
|
|
if (tmgr->isReleased(AIManagerRef)) {
|
2011-07-17 19:31:28 +02:00
|
|
|
AIManagerRef = 0;
|
2010-02-19 00:31:38 +00:00
|
|
|
} else {
|
|
|
|
return true; // in visual range, let the AIManager handle it
|
2004-11-29 09:41:43 +00:00
|
|
|
}
|
2010-02-19 00:31:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
2005-02-10 09:01:51 +00:00
|
|
|
return true;
|
2004-06-03 17:59:14 +00:00
|
|
|
}
|
2010-02-19 00:31:38 +00:00
|
|
|
|
|
|
|
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;
|
2004-11-29 09:41:43 +00:00
|
|
|
|
2010-02-19 00:31:38 +00:00
|
|
|
// 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 "
|
2008-05-08 06:11:43 +00:00
|
|
|
<< dep->getId() << " to " << arr->getId() << ". Current distance to user: "
|
2009-06-09 20:16:08 +00:00
|
|
|
<< distanceToUser);
|
2010-02-19 00:31:38 +00:00
|
|
|
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);
|
2009-06-09 20:16:08 +00:00
|
|
|
|
2010-02-19 00:31:38 +00:00
|
|
|
courseToDest = SGGeodesy::courseDeg(position, arr->geod());
|
2011-04-19 18:01:24 +02:00
|
|
|
FGAIFlightPlan *fp = new FGAIFlightPlan(aircraft, flightPlanName, courseToDest, deptime,
|
|
|
|
dep, arr, true, radius,
|
|
|
|
flight->getCruiseAlt()*100,
|
|
|
|
position.getLatitudeDeg(),
|
|
|
|
position.getLongitudeDeg(),
|
|
|
|
speedKnots, flightType, acType,
|
|
|
|
airline);
|
|
|
|
if (fp->isValidPlan()) {
|
|
|
|
aircraft->SetFlightPlan(fp);
|
|
|
|
FGAIManager* aimgr = (FGAIManager *) globals-> get_subsystem("ai_model");
|
|
|
|
aimgr->attach(aircraft);
|
|
|
|
AIManagerRef = aircraft->getID();
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
delete aircraft;
|
|
|
|
delete fp;
|
|
|
|
//hand back the flights that had already been scheduled
|
|
|
|
while (!flights.empty()) {
|
|
|
|
flights.front()->release();
|
|
|
|
flights.erase(flights.begin());
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2010-02-19 00:31:38 +00:00
|
|
|
}
|
2004-07-22 18:50:29 +00:00
|
|
|
|
2011-04-12 23:28:48 +02:00
|
|
|
// Create an initial heading for user controlled aircraft.
|
|
|
|
void FGAISchedule::setHeading()
|
|
|
|
{
|
|
|
|
courseToDest = SGGeodesy::courseDeg((*flights.begin())->getDepartureAirport()->geod(), (*flights.begin())->getArrivalAirport()->geod());
|
|
|
|
}
|
|
|
|
|
2010-02-19 00:31:38 +00:00
|
|
|
void FGAISchedule::scheduleFlights()
|
|
|
|
{
|
|
|
|
if (!flights.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
A number of cosmetic and/or infrastructural changes.
Traffic Manager:
* Just continue routing until we run out of flights. This change removes one of the major requirements for setting the "Home port" field.
* Add a time restriction requirement for the aircraft scheduler; this became necessary after removing the limited-to-home-port routing restriction.
* Added a new field to the heuristics calculation: take into account whether an aircraft has already been used in a previous session. Rotate aircraft assignments for greater variability across sessions.
* Added a revision number to the cache files, so that old cache results, which are no longer compatible with the new file format, are discarded.
Groundnetwork and traffic control:
* Added a revision number to the cache files, so that old and incompatible results are discarded.
* The caching algorithm probably didn't store the correct data for airports that were processed while the user was quite far away. This is now corrected by checking whether the cached elevation data are equal to the generic airport elevation.
AIAircraft:
* I've been searching for the infamous aircraft bend-over-backward bug, that can occur during initialization, but to no avail yet. The only variable potentially responsible (tgt_vs) wich can explain the irregular jumping behavior, as well as the weird pitch results is initialized in AIAircraft's only constructor (through AIBase), and I can't find any situation in the ground handling code where this variable could get bizarre values. But,
* a couple of tgt_vs. calculations appear to be completely redundant. This value was calculated twice inside the ProcessFlightplan function, and subsequently again in the updateSecondaryTargetValues function. I have removed the calculations in the process flightplan function, without any apparent side effect.
2011-09-04 20:27:36 +02:00
|
|
|
SG_LOG(SG_GENERAL, SG_BULK, "Scheduling Flights for : " << modelPath << " " << registration << " " << homePort);
|
2010-02-19 00:31:38 +00:00
|
|
|
FGScheduledFlight *flight = NULL;
|
|
|
|
do {
|
|
|
|
flight = findAvailableFlight(currentDestination, flightIdentifier);
|
|
|
|
if (!flight) {
|
|
|
|
break;
|
2004-06-03 17:59:14 +00:00
|
|
|
}
|
2010-02-19 00:31:38 +00:00
|
|
|
|
|
|
|
currentDestination = flight->getArrivalAirport()->getId();
|
2010-08-30 21:13:16 +02:00
|
|
|
if (!initialized) {
|
|
|
|
string departurePort = flight->getDepartureAirport()->getId();
|
2010-09-03 10:47:05 +02:00
|
|
|
//cerr << "Scheduled " << registration << " " << score << " for Flight "
|
|
|
|
// << flight-> getCallSign() << " from " << departurePort << " to " << currentDestination << endl;
|
2010-08-30 21:13:16 +02:00
|
|
|
if (fgGetString("/sim/presets/airport-id") == departurePort) {
|
|
|
|
hits++;
|
|
|
|
}
|
2010-09-03 10:47:05 +02:00
|
|
|
//runCount++;
|
2010-08-30 21:13:16 +02:00
|
|
|
initialized = true;
|
|
|
|
}
|
2010-02-19 00:31:38 +00:00
|
|
|
|
|
|
|
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);
|
A number of cosmetic and/or infrastructural changes.
Traffic Manager:
* Just continue routing until we run out of flights. This change removes one of the major requirements for setting the "Home port" field.
* Add a time restriction requirement for the aircraft scheduler; this became necessary after removing the limited-to-home-port routing restriction.
* Added a new field to the heuristics calculation: take into account whether an aircraft has already been used in a previous session. Rotate aircraft assignments for greater variability across sessions.
* Added a revision number to the cache files, so that old cache results, which are no longer compatible with the new file format, are discarded.
Groundnetwork and traffic control:
* Added a revision number to the cache files, so that old and incompatible results are discarded.
* The caching algorithm probably didn't store the correct data for airports that were processed while the user was quite far away. This is now corrected by checking whether the cached elevation data are equal to the generic airport elevation.
AIAircraft:
* I've been searching for the infamous aircraft bend-over-backward bug, that can occur during initialization, but to no avail yet. The only variable potentially responsible (tgt_vs) wich can explain the irregular jumping behavior, as well as the weird pitch results is initialized in AIAircraft's only constructor (through AIBase), and I can't find any situation in the ground handling code where this variable could get bizarre values. But,
* a couple of tgt_vs. calculations appear to be completely redundant. This value was calculated twice inside the ProcessFlightplan function, and subsequently again in the updateSecondaryTargetValues function. I have removed the calculations in the process flightplan function, without any apparent side effect.
2011-09-04 20:27:36 +02:00
|
|
|
SG_LOG(SG_GENERAL, SG_BULK, " Flight " << flight->getCallSign() << ":"
|
|
|
|
<< " " << flight->getDepartureAirport()->getId() << ":"
|
|
|
|
<< " " << depT << ":"
|
|
|
|
<< " \"" << flight->getArrivalAirport()->getId() << "\"" << ":"
|
|
|
|
<< " " << arrT << ":");
|
2010-02-19 00:31:38 +00:00
|
|
|
|
|
|
|
flights.push_back(flight);
|
A number of cosmetic and/or infrastructural changes.
Traffic Manager:
* Just continue routing until we run out of flights. This change removes one of the major requirements for setting the "Home port" field.
* Add a time restriction requirement for the aircraft scheduler; this became necessary after removing the limited-to-home-port routing restriction.
* Added a new field to the heuristics calculation: take into account whether an aircraft has already been used in a previous session. Rotate aircraft assignments for greater variability across sessions.
* Added a revision number to the cache files, so that old cache results, which are no longer compatible with the new file format, are discarded.
Groundnetwork and traffic control:
* Added a revision number to the cache files, so that old and incompatible results are discarded.
* The caching algorithm probably didn't store the correct data for airports that were processed while the user was quite far away. This is now corrected by checking whether the cached elevation data are equal to the generic airport elevation.
AIAircraft:
* I've been searching for the infamous aircraft bend-over-backward bug, that can occur during initialization, but to no avail yet. The only variable potentially responsible (tgt_vs) wich can explain the irregular jumping behavior, as well as the weird pitch results is initialized in AIAircraft's only constructor (through AIBase), and I can't find any situation in the ground handling code where this variable could get bizarre values. But,
* a couple of tgt_vs. calculations appear to be completely redundant. This value was calculated twice inside the ProcessFlightplan function, and subsequently again in the updateSecondaryTargetValues function. I have removed the calculations in the process flightplan function, without any apparent side effect.
2011-09-04 20:27:36 +02:00
|
|
|
} while (1); //while (currentDestination != homePort);
|
2010-02-19 00:31:38 +00:00
|
|
|
SG_LOG(SG_GENERAL, SG_BULK, " Done ");
|
2004-06-03 17:59:14 +00:00
|
|
|
}
|
2004-11-29 09:41:43 +00:00
|
|
|
|
2008-11-16 13:45:24 +00:00
|
|
|
bool FGAISchedule::next()
|
|
|
|
{
|
2010-02-19 00:31:38 +00:00
|
|
|
if (!flights.empty()) {
|
|
|
|
flights.front()->release();
|
|
|
|
flights.erase(flights.begin());
|
|
|
|
}
|
|
|
|
|
2008-11-16 13:45:24 +00:00
|
|
|
FGScheduledFlight *flight = findAvailableFlight(currentDestination, flightIdentifier);
|
2010-02-19 00:31:38 +00:00
|
|
|
if (!flight) {
|
|
|
|
return false;
|
2008-11-16 13:45:24 +00:00
|
|
|
}
|
2010-02-19 00:31:38 +00:00
|
|
|
|
|
|
|
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;
|
2008-11-16 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FGScheduledFlight* FGAISchedule::findAvailableFlight (const string ¤tDestination,
|
|
|
|
const string &req)
|
2004-11-29 09:41:43 +00:00
|
|
|
{
|
2008-11-16 13:45:24 +00:00
|
|
|
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;
|
|
|
|
}
|
2010-02-19 00:31:38 +00:00
|
|
|
std::sort(fltBegin, fltEnd, compareScheduledFlights);
|
2008-11-16 13:45:24 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
A number of cosmetic and/or infrastructural changes.
Traffic Manager:
* Just continue routing until we run out of flights. This change removes one of the major requirements for setting the "Home port" field.
* Add a time restriction requirement for the aircraft scheduler; this became necessary after removing the limited-to-home-port routing restriction.
* Added a new field to the heuristics calculation: take into account whether an aircraft has already been used in a previous session. Rotate aircraft assignments for greater variability across sessions.
* Added a revision number to the cache files, so that old cache results, which are no longer compatible with the new file format, are discarded.
Groundnetwork and traffic control:
* Added a revision number to the cache files, so that old and incompatible results are discarded.
* The caching algorithm probably didn't store the correct data for airports that were processed while the user was quite far away. This is now corrected by checking whether the cached elevation data are equal to the generic airport elevation.
AIAircraft:
* I've been searching for the infamous aircraft bend-over-backward bug, that can occur during initialization, but to no avail yet. The only variable potentially responsible (tgt_vs) wich can explain the irregular jumping behavior, as well as the weird pitch results is initialized in AIAircraft's only constructor (through AIBase), and I can't find any situation in the ground handling code where this variable could get bizarre values. But,
* a couple of tgt_vs. calculations appear to be completely redundant. This value was calculated twice inside the ProcessFlightplan function, and subsequently again in the updateSecondaryTargetValues function. I have removed the calculations in the process flightplan function, without any apparent side effect.
2011-09-04 20:27:36 +02:00
|
|
|
if (flights.size()) {
|
|
|
|
time_t arrival = flights.back()->getArrivalTime();
|
|
|
|
if ((*i)->getDepartureTime() < arrival)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2008-11-16 13:45:24 +00:00
|
|
|
// 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;
|
2010-02-19 00:31:38 +00:00
|
|
|
return NULL;
|
2004-11-29 09:41:43 +00:00
|
|
|
}
|
|
|
|
|
2005-02-10 09:01:51 +00:00
|
|
|
double FGAISchedule::getSpeed()
|
|
|
|
{
|
|
|
|
FGScheduledFlightVecIterator i = flights.begin();
|
|
|
|
|
2009-01-04 17:11:25 +00:00
|
|
|
FGAirport* dep = (*i)->getDepartureAirport(),
|
|
|
|
*arr = (*i)->getArrivalAirport();
|
|
|
|
double dist = SGGeodesy::distanceNm(dep->geod(), arr->geod());
|
|
|
|
double remainingTimeEnroute = (*i)->getArrivalTime() - (*i)->getDepartureTime();
|
|
|
|
|
|
|
|
double speed = dist / (remainingTimeEnroute/3600.0);
|
|
|
|
SG_CLAMP_RANGE(speed, 300.0, 500.0);
|
2005-02-10 09:01:51 +00:00
|
|
|
return speed;
|
|
|
|
}
|
2010-08-30 21:13:16 +02:00
|
|
|
|
2010-08-31 13:21:30 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2010-09-03 10:47:05 +02:00
|
|
|
runCount++;
|
2010-08-31 13:21:30 +02:00
|
|
|
}
|
|
|
|
|
2006-10-06 17:36:31 +00:00
|
|
|
bool compareSchedules(FGAISchedule*a, FGAISchedule*b)
|
|
|
|
{
|
2010-08-30 21:13:16 +02:00
|
|
|
return (*a) < (*b);
|
2006-10-06 17:36:31 +00:00
|
|
|
}
|
2010-08-30 21:13:16 +02:00
|
|
|
|
A number of cosmetic and/or infrastructural changes.
Traffic Manager:
* Just continue routing until we run out of flights. This change removes one of the major requirements for setting the "Home port" field.
* Add a time restriction requirement for the aircraft scheduler; this became necessary after removing the limited-to-home-port routing restriction.
* Added a new field to the heuristics calculation: take into account whether an aircraft has already been used in a previous session. Rotate aircraft assignments for greater variability across sessions.
* Added a revision number to the cache files, so that old cache results, which are no longer compatible with the new file format, are discarded.
Groundnetwork and traffic control:
* Added a revision number to the cache files, so that old and incompatible results are discarded.
* The caching algorithm probably didn't store the correct data for airports that were processed while the user was quite far away. This is now corrected by checking whether the cached elevation data are equal to the generic airport elevation.
AIAircraft:
* I've been searching for the infamous aircraft bend-over-backward bug, that can occur during initialization, but to no avail yet. The only variable potentially responsible (tgt_vs) wich can explain the irregular jumping behavior, as well as the weird pitch results is initialized in AIAircraft's only constructor (through AIBase), and I can't find any situation in the ground handling code where this variable could get bizarre values. But,
* a couple of tgt_vs. calculations appear to be completely redundant. This value was calculated twice inside the ProcessFlightplan function, and subsequently again in the updateSecondaryTargetValues function. I have removed the calculations in the process flightplan function, without any apparent side effect.
2011-09-04 20:27:36 +02:00
|
|
|
bool FGAISchedule::operator< (const FGAISchedule &other) const
|
|
|
|
{
|
|
|
|
//cerr << "Sorting " << registration << " and " << other.registration << endl;
|
|
|
|
double currentScore = score * (1.5 - lastRun);
|
|
|
|
double otherScore = other.score * (1.5 - other.lastRun);
|
|
|
|
return currentScore > otherScore;
|
|
|
|
}
|
2006-10-06 17:36:31 +00:00
|
|
|
|