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/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
|
2012-05-02 23:50:07 +02:00
|
|
|
* schedule of Flights for an artificially controlled aircraft.
|
2004-06-03 17:59:14 +00:00
|
|
|
*****************************************************************************/
|
|
|
|
FGAISchedule::FGAISchedule()
|
2012-11-24 13:04:59 +01:00
|
|
|
: heavy(false),
|
|
|
|
radius(0),
|
|
|
|
groundOffset(0),
|
|
|
|
distanceToUser(0),
|
|
|
|
score(0),
|
|
|
|
runCount(0),
|
|
|
|
hits(0),
|
|
|
|
lastRun(0),
|
|
|
|
firstRun(false),
|
|
|
|
courseToDest(0),
|
|
|
|
initialized(false),
|
2012-11-25 16:41:10 +01:00
|
|
|
valid(false),
|
|
|
|
scheduleComplete(false)
|
2004-06-03 17:59:14 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2012-11-24 11:59:13 +01:00
|
|
|
|
|
|
|
FGAISchedule::FGAISchedule(const string& model,
|
|
|
|
const string& lvry,
|
|
|
|
const string& port,
|
|
|
|
const string& reg,
|
|
|
|
const string& flightId,
|
2008-11-16 13:45:24 +00:00
|
|
|
bool hvy,
|
2012-11-24 11:59:13 +01:00
|
|
|
const string& act,
|
|
|
|
const string& arln,
|
|
|
|
const string& mclass,
|
|
|
|
const string& fltpe,
|
2008-11-16 13:45:24 +00:00
|
|
|
double rad,
|
|
|
|
double grnd)
|
2012-11-24 13:04:59 +01:00
|
|
|
: heavy(hvy),
|
|
|
|
radius(rad),
|
|
|
|
groundOffset(grnd),
|
|
|
|
distanceToUser(0),
|
|
|
|
score(0),
|
|
|
|
runCount(0),
|
|
|
|
hits(0),
|
|
|
|
lastRun(0),
|
|
|
|
firstRun(true),
|
|
|
|
courseToDest(0),
|
|
|
|
initialized(false),
|
2012-11-25 16:41:10 +01:00
|
|
|
valid(true),
|
|
|
|
scheduleComplete(false)
|
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;
|
|
|
|
/*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))));*/
|
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;
|
2012-11-21 14:49:34 +00:00
|
|
|
aiAircraft = other.aiAircraft;
|
2008-11-16 13:45:24 +00:00
|
|
|
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;
|
2012-11-25 16:41:10 +01:00
|
|
|
courseToDest = other.courseToDest;
|
2010-08-30 21:13:16 +02:00
|
|
|
initialized = other.initialized;
|
2011-04-19 18:01:24 +02:00
|
|
|
valid = other.valid;
|
2012-11-25 16:41:10 +01:00
|
|
|
scheduleComplete = other.scheduleComplete;
|
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()
|
|
|
|
{
|
2012-05-01 10:32:30 +02:00
|
|
|
// remove related object from AI manager
|
2012-11-21 14:49:34 +00:00
|
|
|
if (aiAircraft)
|
2012-05-01 10:32:30 +02:00
|
|
|
{
|
2012-11-21 14:49:34 +00:00
|
|
|
aiAircraft->setDie(true);
|
2012-05-01 10:32:30 +02:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-11-25 16:41:10 +01:00
|
|
|
/**
|
|
|
|
* 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).
|
|
|
|
*/
|
2010-02-19 00:31:38 +00:00
|
|
|
bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
|
2012-11-25 16:41:10 +01:00
|
|
|
{
|
|
|
|
|
|
|
|
time_t totalTimeEnroute,
|
|
|
|
elapsedTimeEnroute,
|
|
|
|
//remainingTimeEnroute,
|
|
|
|
deptime = 0;
|
|
|
|
|
2011-04-19 18:01:24 +02:00
|
|
|
if (!valid) {
|
2012-11-25 16:41:10 +01:00
|
|
|
return true; // processing complete
|
2011-04-19 18:01:24 +02:00
|
|
|
}
|
2012-11-25 16:41:10 +01:00
|
|
|
|
|
|
|
if (!scheduleComplete) {
|
|
|
|
scheduleComplete = scheduleFlights(now);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!scheduleComplete) {
|
|
|
|
return false; // not ready yet, continue processing in next iteration
|
|
|
|
}
|
|
|
|
|
2010-02-19 00:31:38 +00:00
|
|
|
if (flights.empty()) { // No flights available for this aircraft
|
2011-04-19 18:01:24 +02:00
|
|
|
valid = false;
|
2012-11-25 16:41:10 +01:00
|
|
|
return true; // processing complete
|
2008-11-16 13:45:24 +00:00
|
|
|
}
|
2012-11-25 16:41:10 +01: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
|
|
|
|
2012-05-02 23:50:07 +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();
|
2012-11-24 11:59:13 +01:00
|
|
|
//cerr << "Setting departure time " << deptime << endl;
|
2010-04-25 08:32:53 +00:00
|
|
|
}
|
2010-02-19 00:31:38 +00:00
|
|
|
|
2012-11-21 14:49:34 +00:00
|
|
|
if (aiAircraft) {
|
|
|
|
if (aiAircraft->getDie()) {
|
|
|
|
aiAircraft = NULL;
|
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) {
|
2012-11-23 21:14:40 +01:00
|
|
|
SG_LOG (SG_AI, SG_BULK, "Traffic Manager: Flight is in the Past");
|
2010-02-19 00:31:38 +00:00
|
|
|
// 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.
|
2012-05-02 23:50:07 +02:00
|
|
|
flight->update();
|
2010-02-19 00:31:38 +00:00
|
|
|
flights.erase(flights.begin()); // pop_front(), effectively
|
2012-11-25 16:41:10 +01:00
|
|
|
return true; // processing complete
|
2012-05-02 23:50:07 +02:00
|
|
|
}
|
2010-02-19 00:31:38 +00:00
|
|
|
|
|
|
|
FGAirport* dep = flight->getDepartureAirport();
|
|
|
|
FGAirport* arr = flight->getArrivalAirport();
|
|
|
|
if (!dep || !arr) {
|
2012-11-25 16:41:10 +01:00
|
|
|
return true; // processing complete
|
2010-02-19 00:31:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
double speed = 450.0;
|
|
|
|
if (dep != arr) {
|
|
|
|
totalTimeEnroute = flight->getArrivalTime() - flight->getDepartureTime();
|
|
|
|
if (flight->getDepartureTime() < now) {
|
|
|
|
elapsedTimeEnroute = now - flight->getDepartureTime();
|
2012-04-07 16:19:33 +02:00
|
|
|
//remainingTimeEnroute = totalTimeEnroute - elapsedTimeEnroute;
|
2010-02-19 00:31:38 +00:00
|
|
|
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);
|
|
|
|
|
2012-11-23 21:14:40 +01:00
|
|
|
SG_LOG (SG_AI, SG_BULK, "Traffic Manager: Flight is in progress, %=" << x);
|
2010-02-19 00:31:38 +00:00
|
|
|
speed = ((distanceM - coveredDistance) * SG_METER_TO_NM) / 3600.0;
|
|
|
|
} else {
|
|
|
|
// not departed yet
|
2012-04-07 16:19:33 +02:00
|
|
|
//remainingTimeEnroute = totalTimeEnroute;
|
2010-02-19 00:31:38 +00:00
|
|
|
elapsedTimeEnroute = 0;
|
|
|
|
position = dep->geod();
|
2012-11-23 21:14:40 +01:00
|
|
|
SG_LOG (SG_AI, SG_BULK, "Traffic Manager: Flight is pending, departure in "
|
2010-02-19 00:31:38 +00:00
|
|
|
<< flight->getDepartureTime() - now << " seconds ");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// departure / arrival coincident
|
2012-04-07 16:19:33 +02:00
|
|
|
//remainingTimeEnroute = totalTimeEnroute = 0.0;
|
2010-02-19 00:31:38 +00:00
|
|
|
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;
|
|
|
|
|
2012-11-25 16:41:10 +01:00
|
|
|
|
|
|
|
// If distance between user and simulated aircraft is less
|
2010-02-19 00:31:38 +00:00
|
|
|
// 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.
|
2012-11-23 21:14:40 +01:00
|
|
|
SG_LOG (SG_AI, 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.
|
|
|
|
}
|
2012-11-25 16:41:10 +01:00
|
|
|
|
|
|
|
if (!createAIAircraft(flight, speed, deptime)) {
|
|
|
|
valid = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true; // processing complete
|
2010-02-19 00:31:38 +00:00
|
|
|
}
|
|
|
|
|
2012-05-03 11:05:37 +01:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2010-02-19 00:31:38 +00:00
|
|
|
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";
|
2012-11-23 21:14:40 +01:00
|
|
|
SG_LOG(SG_AI, SG_INFO, "Traffic manager: Creating AIModel from:" << flightPlanName);
|
2010-02-19 00:31:38 +00:00
|
|
|
|
|
|
|
// 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()) {
|
2012-11-23 21:14:40 +01:00
|
|
|
SG_LOG(SG_AI, SG_WARN, "TrafficManager: Could not load model " << mp_ai.str());
|
2010-02-19 00:31:38 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-11-21 14:49:34 +00:00
|
|
|
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());
|
2010-02-19 00:31:38 +00:00
|
|
|
//aircraft->setFlightPlan(flightPlanName);
|
2012-11-21 14:49:34 +00:00
|
|
|
aiAircraft->setLatitude(position.getLatitudeDeg());
|
|
|
|
aiAircraft->setLongitude(position.getLongitudeDeg());
|
|
|
|
aiAircraft->setAltitude(flight->getCruiseAlt()*100); // convert from FL to feet
|
|
|
|
aiAircraft->setSpeed(0);
|
|
|
|
aiAircraft->setBank(0);
|
2009-06-09 20:16:08 +00:00
|
|
|
|
2010-02-19 00:31:38 +00:00
|
|
|
courseToDest = SGGeodesy::courseDeg(position, arr->geod());
|
2012-11-21 14:49:34 +00:00
|
|
|
FGAIFlightPlan *fp = new FGAIFlightPlan(aiAircraft, flightPlanName, courseToDest, deptime,
|
2011-04-19 18:01:24 +02:00
|
|
|
dep, arr, true, radius,
|
|
|
|
flight->getCruiseAlt()*100,
|
|
|
|
position.getLatitudeDeg(),
|
|
|
|
position.getLongitudeDeg(),
|
|
|
|
speedKnots, flightType, acType,
|
|
|
|
airline);
|
|
|
|
if (fp->isValidPlan()) {
|
2012-11-21 14:49:34 +00:00
|
|
|
aiAircraft->SetFlightPlan(fp);
|
2011-11-19 15:37:49 +01:00
|
|
|
FGAIManager* aimgr = (FGAIManager *) globals-> get_subsystem("ai-model");
|
2012-11-21 14:49:34 +00:00
|
|
|
aimgr->attach(aiAircraft);
|
2011-04-19 18:01:24 +02:00
|
|
|
return true;
|
|
|
|
} else {
|
2012-11-21 14:49:34 +00:00
|
|
|
aiAircraft = NULL;
|
2011-04-19 18:01:24 +02:00
|
|
|
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());
|
|
|
|
}
|
|
|
|
|
2012-11-25 16:41:10 +01:00
|
|
|
bool FGAISchedule::scheduleFlights(time_t now)
|
2010-02-19 00:31:38 +00:00
|
|
|
{
|
2011-10-26 22:26:37 +02:00
|
|
|
//string startingPort;
|
2012-11-25 16:41:10 +01:00
|
|
|
const string& userPort = fgGetString("/sim/presets/airport-id");
|
2012-11-23 21:14:40 +01:00
|
|
|
SG_LOG(SG_AI, SG_BULK, "Scheduling Flights for : " << modelPath << " " << registration << " " << homePort);
|
2010-02-19 00:31:38 +00:00
|
|
|
FGScheduledFlight *flight = NULL;
|
2012-11-25 16:41:10 +01:00
|
|
|
SGTimeStamp start;
|
|
|
|
start.stamp();
|
|
|
|
|
|
|
|
bool first = true;
|
|
|
|
if (currentDestination.empty())
|
|
|
|
flight = findAvailableFlight(userPort, flightIdentifier, now, (now+6400));
|
|
|
|
|
2010-02-19 00:31:38 +00:00
|
|
|
do {
|
2012-11-25 16:41:10 +01:00
|
|
|
if ((!flight)||(!first)) {
|
2011-10-26 22:26:37 +02:00
|
|
|
flight = findAvailableFlight(currentDestination, flightIdentifier);
|
|
|
|
}
|
2010-02-19 00:31:38 +00:00
|
|
|
if (!flight) {
|
|
|
|
break;
|
2004-06-03 17:59:14 +00:00
|
|
|
}
|
2012-11-25 16:41:10 +01:00
|
|
|
|
|
|
|
first = false;
|
2010-02-19 00:31:38 +00:00
|
|
|
currentDestination = flight->getArrivalAirport()->getId();
|
Added a new startup option. By giving the command line option --parkpos=AVAILABLE you can -in principle- let FlightGear decide what the most optimal parking location is. This option does require a few properties to be set that are also needed for future ATC use. Hence, they are listed under /sim/ATC, but could move to a different location if desired.
/sim/ATC/radius should be a nummeric estimate of the size of your aircraft. A small aircraft fits into a large parking, but a large aircraft does not fit into a small parking space. Because the AI part of radius is also used for slightly different purposes (prioritizing gate assignmments, the given valuem may deviate slightly from the real aircraft size. See http:/wiki.flightgear.org/Aircraft.radii for an overview of currently used values for the redius property.
/sim/ATC/flight-type can be any one of "ga", "cargo", "gate", "mil-fighter", "mil-cargo", or "vtol". See http://wiki.flightgear.org/Interactive_traffic#A_technical_perspective for more information.
optionally, the property /sim/ATC/airline can be set set to a three letter icao airline code. By way of illustration, I will commit a number of startup preset files setting these properties shortly.
Also did some more finetuning to the traffic mananger routing algorithm can be any one of "ga", "cargo", "gate", "mil-fighter", "mil-cargo", or "vtol". See http://wiki.flightgear.org/Interactive_traffic#A_technical_perspective for more information.
optionally, the property /sim/ATC/airline can be set set to a three letter icao airline code. By way of illustration, I will commit a number of startup preset files setting these properties shortly.
Also did some more finetuning to the traffic mananger routing algorithm.
2011-09-17 16:51:00 +02:00
|
|
|
//cerr << "Current destination " << currentDestination << endl;
|
2010-08-30 21:13:16 +02:00
|
|
|
if (!initialized) {
|
2012-11-25 16:41:10 +01:00
|
|
|
const string& departurePort = flight->getDepartureAirport()->getId();
|
Added a new startup option. By giving the command line option --parkpos=AVAILABLE you can -in principle- let FlightGear decide what the most optimal parking location is. This option does require a few properties to be set that are also needed for future ATC use. Hence, they are listed under /sim/ATC, but could move to a different location if desired.
/sim/ATC/radius should be a nummeric estimate of the size of your aircraft. A small aircraft fits into a large parking, but a large aircraft does not fit into a small parking space. Because the AI part of radius is also used for slightly different purposes (prioritizing gate assignmments, the given valuem may deviate slightly from the real aircraft size. See http:/wiki.flightgear.org/Aircraft.radii for an overview of currently used values for the redius property.
/sim/ATC/flight-type can be any one of "ga", "cargo", "gate", "mil-fighter", "mil-cargo", or "vtol". See http://wiki.flightgear.org/Interactive_traffic#A_technical_perspective for more information.
optionally, the property /sim/ATC/airline can be set set to a three letter icao airline code. By way of illustration, I will commit a number of startup preset files setting these properties shortly.
Also did some more finetuning to the traffic mananger routing algorithm can be any one of "ga", "cargo", "gate", "mil-fighter", "mil-cargo", or "vtol". See http://wiki.flightgear.org/Interactive_traffic#A_technical_perspective for more information.
optionally, the property /sim/ATC/airline can be set set to a three letter icao airline code. By way of illustration, I will commit a number of startup preset files setting these properties shortly.
Also did some more finetuning to the traffic mananger routing algorithm.
2011-09-17 16:51:00 +02:00
|
|
|
if (userPort == departurePort) {
|
2011-10-26 22:26:37 +02:00
|
|
|
lastRun = 1;
|
2010-08-30 21:13:16 +02:00
|
|
|
hits++;
|
2011-10-26 22:26:37 +02:00
|
|
|
} else {
|
|
|
|
lastRun = 0;
|
2010-08-30 21:13:16 +02:00
|
|
|
}
|
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
|
|
|
|
2012-11-25 16:41:10 +01:00
|
|
|
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 << ":");
|
|
|
|
}
|
2010-02-19 00:31:38 +00:00
|
|
|
|
|
|
|
flights.push_back(flight);
|
2012-11-25 16:41:10 +01:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2012-11-23 21:14:40 +01:00
|
|
|
SG_LOG(SG_AI, SG_BULK, " Done ");
|
2012-11-25 16:41:10 +01:00
|
|
|
return true;
|
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,
|
Added a new startup option. By giving the command line option --parkpos=AVAILABLE you can -in principle- let FlightGear decide what the most optimal parking location is. This option does require a few properties to be set that are also needed for future ATC use. Hence, they are listed under /sim/ATC, but could move to a different location if desired.
/sim/ATC/radius should be a nummeric estimate of the size of your aircraft. A small aircraft fits into a large parking, but a large aircraft does not fit into a small parking space. Because the AI part of radius is also used for slightly different purposes (prioritizing gate assignmments, the given valuem may deviate slightly from the real aircraft size. See http:/wiki.flightgear.org/Aircraft.radii for an overview of currently used values for the redius property.
/sim/ATC/flight-type can be any one of "ga", "cargo", "gate", "mil-fighter", "mil-cargo", or "vtol". See http://wiki.flightgear.org/Interactive_traffic#A_technical_perspective for more information.
optionally, the property /sim/ATC/airline can be set set to a three letter icao airline code. By way of illustration, I will commit a number of startup preset files setting these properties shortly.
Also did some more finetuning to the traffic mananger routing algorithm can be any one of "ga", "cargo", "gate", "mil-fighter", "mil-cargo", or "vtol". See http://wiki.flightgear.org/Interactive_traffic#A_technical_perspective for more information.
optionally, the property /sim/ATC/airline can be set set to a three letter icao airline code. By way of illustration, I will commit a number of startup preset files setting these properties shortly.
Also did some more finetuning to the traffic mananger routing algorithm.
2011-09-17 16:51:00 +02:00
|
|
|
const string &req,
|
|
|
|
time_t min, time_t max)
|
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");
|
|
|
|
|
2011-11-19 15:37:49 +01:00
|
|
|
FGTrafficManager *tmgr = (FGTrafficManager *) globals->get_subsystem("traffic-manager");
|
2008-11-16 13:45:24 +00:00
|
|
|
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();
|
2011-10-09 23:44:42 +02:00
|
|
|
int groundTime = groundTimeFromRadius();
|
|
|
|
if ((*i)->getDepartureTime() < (arrival+(groundTime)))
|
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
|
|
|
continue;
|
|
|
|
}
|
Added a new startup option. By giving the command line option --parkpos=AVAILABLE you can -in principle- let FlightGear decide what the most optimal parking location is. This option does require a few properties to be set that are also needed for future ATC use. Hence, they are listed under /sim/ATC, but could move to a different location if desired.
/sim/ATC/radius should be a nummeric estimate of the size of your aircraft. A small aircraft fits into a large parking, but a large aircraft does not fit into a small parking space. Because the AI part of radius is also used for slightly different purposes (prioritizing gate assignmments, the given valuem may deviate slightly from the real aircraft size. See http:/wiki.flightgear.org/Aircraft.radii for an overview of currently used values for the redius property.
/sim/ATC/flight-type can be any one of "ga", "cargo", "gate", "mil-fighter", "mil-cargo", or "vtol". See http://wiki.flightgear.org/Interactive_traffic#A_technical_perspective for more information.
optionally, the property /sim/ATC/airline can be set set to a three letter icao airline code. By way of illustration, I will commit a number of startup preset files setting these properties shortly.
Also did some more finetuning to the traffic mananger routing algorithm can be any one of "ga", "cargo", "gate", "mil-fighter", "mil-cargo", or "vtol". See http://wiki.flightgear.org/Interactive_traffic#A_technical_perspective for more information.
optionally, the property /sim/ATC/airline can be set set to a three letter icao airline code. By way of illustration, I will commit a number of startup preset files setting these properties shortly.
Also did some more finetuning to the traffic mananger routing algorithm.
2011-09-17 16:51:00 +02:00
|
|
|
if (min != 0) {
|
|
|
|
time_t dep = (*i)->getDepartureTime();
|
|
|
|
if ((dep < min) || (dep > max))
|
|
|
|
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
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2011-10-09 23:44:42 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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
|
|
|
|