#include <simgear/sg_inlines.h>
#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>
#include <AIModel/AIAircraft.hxx>
-#include <Airports/simple.hxx>
+#include <Airports/airport.hxx>
#include <Main/fg_init.hxx> // That's pretty ugly, but I need fgFindAirportID
/******************************************************************************
* 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;
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)
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;
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);
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.
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
}
// 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;
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,
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();
}
// 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)
+{
+ SGPath mp(globals->get_fg_root());
+ SGPath mp_ai = mp;
+
+ mp.append(modelPath);
+ mp_ai.append("AI");
+ mp_ai.append(modelPath);
+
+ return mp.exists() || mp_ai.exists();
}
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);
+ SG_LOG(SG_AI, 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());
mp_ai.append(modelPath);
if (!mp.exists() && !mp_ai.exists()) {
- SG_LOG(SG_GENERAL, SG_WARN, "TrafficManager: Could not load model " << mp.str());
+ SG_LOG(SG_AI, SG_WARN, "TrafficManager: Could not load model " << mp_ai.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());
+ 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(),
speedKnots, flightType, acType,
airline);
if (fp->isValidPlan()) {
- aircraft->SetFlightPlan(fp);
- FGAIManager* aimgr = (FGAIManager *) globals-> get_subsystem("ai_model");
- aimgr->attach(aircraft);
- AIManagerRef = aircraft->getID();
+ aiAircraft->SetFlightPlan(fp);
+ FGAIManager* aimgr = (FGAIManager *) globals-> get_subsystem("ai-model");
+ aimgr->attach(aiAircraft);
return true;
} else {
- delete aircraft;
+ aiAircraft = NULL;
delete fp;
//hand back the flights that had already been scheduled
while (!flights.empty()) {
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);
+ //string startingPort;
+ 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+1800));
- 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++;
+ } else {
+ lastRun = 0;
}
//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 " << 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 (1); //(currentDestination != startingPort);
- 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()
{
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
- FGTrafficManager *tmgr = (FGTrafficManager *) globals->get_subsystem("Traffic Manager");
+ FGTrafficManager *tmgr = (FGTrafficManager *) globals->get_subsystem("traffic-manager");
FGScheduledFlightVecIterator fltBegin, fltEnd;
fltBegin = tmgr->getFirstFlight(req);
fltEnd = tmgr->getLastFlight(req);
}
if (flights.size()) {
time_t arrival = flights.back()->getArrivalTime();
- if ((*i)->getDepartureTime() < (arrival+(20*60)))
+ int groundTime = groundTimeFromRadius();
+ if ((*i)->getDepartureTime() < (arrival+(groundTime)))
continue;
}
if (min != 0) {
return NULL;
}
+int FGAISchedule::groundTimeFromRadius()
+{
+ if (radius < 10)
+ return 15 * 60;
+ else if (radius < 15)
+ return 20 * 60;
+ else if (radius < 20)
+ return 30 * 60;
+ else if (radius < 25)
+ return 50 * 60;
+ else if (radius < 30)
+ return 90 * 60;
+ else
+ return 120 * 60;
+}
+
+
double FGAISchedule::getSpeed()
{
FGScheduledFlightVecIterator i = flights.begin();