2005-12-29 13:58:21 +00:00
|
|
|
// dynamics.cxx - Code to manage the higher order airport ground activities
|
|
|
|
// Written by Durk Talsma, started December 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.
|
2005-12-29 13:58:21 +00:00
|
|
|
//
|
|
|
|
// $Id$
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
#include <simgear/compiler.h>
|
|
|
|
|
|
|
|
#include <plib/ul.h>
|
|
|
|
|
|
|
|
#include <Environment/environment_mgr.hxx>
|
|
|
|
#include <Environment/environment.hxx>
|
|
|
|
#include <simgear/misc/sg_path.hxx>
|
|
|
|
#include <simgear/props/props.hxx>
|
|
|
|
#include <simgear/structure/subsystem_mgr.hxx>
|
|
|
|
#include <simgear/debug/logstream.hxx>
|
|
|
|
#include <simgear/route/waypoint.hxx>
|
|
|
|
#include <Main/globals.hxx>
|
|
|
|
#include <Main/fg_props.hxx>
|
|
|
|
#include <Airports/runways.hxx>
|
|
|
|
|
2008-07-25 18:38:29 +00:00
|
|
|
#include <string>
|
2005-12-29 13:58:21 +00:00
|
|
|
#include <vector>
|
|
|
|
|
2008-07-27 16:25:13 +00:00
|
|
|
using std::string;
|
|
|
|
using std::vector;
|
|
|
|
using std::sort;
|
|
|
|
using std::random_shuffle;
|
2005-12-29 13:58:21 +00:00
|
|
|
|
2007-07-04 17:39:03 +00:00
|
|
|
#include "simple.hxx"
|
2005-12-29 13:58:21 +00:00
|
|
|
#include "dynamics.hxx"
|
|
|
|
|
2007-07-04 17:39:03 +00:00
|
|
|
FGAirportDynamics::FGAirportDynamics(FGAirport* ap) :
|
2009-03-08 17:14:05 +00:00
|
|
|
_ap(ap), rwyPrefs(ap), SIDs(ap) {
|
2005-12-29 13:58:21 +00:00
|
|
|
lastUpdate = 0;
|
2009-02-07 17:17:07 +00:00
|
|
|
|
|
|
|
// For testing only. This needs to be refined when we move ATIS functionality over.
|
|
|
|
atisInformation = "Sierra";
|
2005-12-29 13:58:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Note that the ground network should also be copied
|
2007-07-04 17:39:03 +00:00
|
|
|
FGAirportDynamics::FGAirportDynamics(const FGAirportDynamics& other) :
|
2009-03-08 17:14:05 +00:00
|
|
|
rwyPrefs(other.rwyPrefs),
|
|
|
|
SIDs(other.SIDs)
|
2005-12-29 13:58:21 +00:00
|
|
|
{
|
|
|
|
for (FGParkingVecConstIterator ip= other.parkings.begin(); ip != other.parkings.end(); ip++)
|
|
|
|
parkings.push_back(*(ip));
|
2007-07-04 17:39:03 +00:00
|
|
|
// rwyPrefs = other.rwyPrefs;
|
2005-12-29 13:58:21 +00:00
|
|
|
lastUpdate = other.lastUpdate;
|
|
|
|
|
|
|
|
stringVecConstIterator il;
|
|
|
|
for (il = other.landing.begin(); il != other.landing.end(); il++)
|
|
|
|
landing.push_back(*il);
|
|
|
|
for (il = other.takeoff.begin(); il != other.takeoff.end(); il++)
|
|
|
|
takeoff.push_back(*il);
|
|
|
|
lastUpdate = other.lastUpdate;
|
2009-02-07 17:17:07 +00:00
|
|
|
atisInformation = other.atisInformation;
|
2005-12-29 13:58:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Destructor
|
|
|
|
FGAirportDynamics::~FGAirportDynamics()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Initialization required after XMLRead
|
|
|
|
void FGAirportDynamics::init()
|
|
|
|
{
|
|
|
|
// This may seem a bit weird to first randomly shuffle the parkings
|
|
|
|
// and then sort them again. However, parkings are sorted here by ascending
|
|
|
|
// radius. Since many parkings have similar radii, with each radius class they will
|
|
|
|
// still be allocated relatively systematically. Randomizing prior to sorting will
|
|
|
|
// prevent any initial orderings to be destroyed, leading (hopefully) to a more
|
|
|
|
// naturalistic gate assignment.
|
|
|
|
random_shuffle(parkings.begin(), parkings.end());
|
|
|
|
sort(parkings.begin(), parkings.end());
|
|
|
|
// add the gate positions to the ground network.
|
|
|
|
groundNetwork.addNodes(&parkings);
|
|
|
|
groundNetwork.init();
|
2007-07-04 17:39:03 +00:00
|
|
|
groundNetwork.setTowerController(&towerController);
|
|
|
|
groundNetwork.setParent(_ap);
|
2005-12-29 13:58:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool FGAirportDynamics::getAvailableParking(double *lat, double *lon, double *heading, int *gateId, double rad, const string &flType, const string &acType, const string &airline)
|
|
|
|
{
|
|
|
|
bool found = false;
|
|
|
|
bool available = false;
|
|
|
|
//string gateType;
|
|
|
|
|
|
|
|
FGParkingVecIterator i;
|
|
|
|
// if (flType == "cargo")
|
|
|
|
// {
|
|
|
|
// gateType = "RAMP_CARGO";
|
|
|
|
// }
|
|
|
|
// else if (flType == "ga")
|
|
|
|
// {
|
|
|
|
// gateType = "RAMP_GA";
|
|
|
|
// }
|
|
|
|
// else gateType = "GATE";
|
|
|
|
|
|
|
|
if (parkings.begin() == parkings.end())
|
|
|
|
{
|
2007-07-04 17:39:03 +00:00
|
|
|
//cerr << "Could not find parking spot at " << _ap->getId() << endl;
|
|
|
|
*lat = _ap->getLatitude();
|
|
|
|
*lon = _ap->getLongitude();
|
2005-12-29 13:58:21 +00:00
|
|
|
*heading = 0;
|
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// First try finding a parking with a designated airline code
|
|
|
|
for (i = parkings.begin(); !(i == parkings.end() || found); i++)
|
|
|
|
{
|
|
|
|
//cerr << "Gate Id: " << i->getIndex()
|
|
|
|
// << " Type : " << i->getType()
|
|
|
|
// << " Codes : " << i->getCodes()
|
|
|
|
// << " Radius: " << i->getRadius()
|
|
|
|
// << " Name : " << i->getName()
|
|
|
|
// << " Available: " << i->isAvailable() << endl;
|
|
|
|
available = true;
|
|
|
|
// Taken by another aircraft
|
|
|
|
if (!(i->isAvailable()))
|
|
|
|
{
|
|
|
|
available = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// No airline codes, so skip
|
|
|
|
if (i->getCodes().empty())
|
|
|
|
{
|
|
|
|
available = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else // Airline code doesn't match
|
2006-11-11 10:52:05 +00:00
|
|
|
{
|
|
|
|
//cerr << "Code = " << airline << ": Codes " << i->getCodes();
|
|
|
|
if (i->getCodes().find(airline, 0) == string::npos)
|
|
|
|
{
|
|
|
|
available = false;
|
|
|
|
//cerr << "Unavailable" << endl;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//cerr << "Available" << endl;
|
|
|
|
}
|
|
|
|
}
|
2005-12-29 13:58:21 +00:00
|
|
|
// Type doesn't match
|
|
|
|
if (i->getType() != flType)
|
|
|
|
{
|
|
|
|
available = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// too small
|
|
|
|
if (i->getRadius() < rad)
|
|
|
|
{
|
|
|
|
available = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (available)
|
|
|
|
{
|
|
|
|
*lat = i->getLatitude ();
|
|
|
|
*lon = i->getLongitude();
|
|
|
|
*heading = i->getHeading ();
|
|
|
|
*gateId = i->getIndex ();
|
|
|
|
i->setAvailable(false);
|
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// then try again for those without codes.
|
|
|
|
for (i = parkings.begin(); !(i == parkings.end() || found); i++)
|
|
|
|
{
|
|
|
|
available = true;
|
|
|
|
if (!(i->isAvailable()))
|
|
|
|
{
|
|
|
|
available = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!(i->getCodes().empty()))
|
|
|
|
{
|
|
|
|
if ((i->getCodes().find(airline,0) == string::npos))
|
2008-07-13 12:51:06 +00:00
|
|
|
{
|
|
|
|
available = false;
|
|
|
|
continue;
|
|
|
|
}
|
2005-12-29 13:58:21 +00:00
|
|
|
}
|
|
|
|
if (i->getType() != flType)
|
|
|
|
{
|
|
|
|
available = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i->getRadius() < rad)
|
|
|
|
{
|
|
|
|
available = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (available)
|
|
|
|
{
|
|
|
|
*lat = i->getLatitude ();
|
|
|
|
*lon = i->getLongitude();
|
|
|
|
*heading = i->getHeading ();
|
|
|
|
*gateId = i->getIndex ();
|
|
|
|
i->setAvailable(false);
|
|
|
|
found = true;
|
|
|
|
}
|
2008-07-13 12:51:06 +00:00
|
|
|
}
|
2005-12-29 13:58:21 +00:00
|
|
|
// And finally once more if that didn't work. Now ignore the airline codes, as a last resort
|
|
|
|
for (i = parkings.begin(); !(i == parkings.end() || found); i++)
|
|
|
|
{
|
|
|
|
available = true;
|
|
|
|
if (!(i->isAvailable()))
|
|
|
|
{
|
|
|
|
available = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (i->getType() != flType)
|
|
|
|
{
|
|
|
|
available = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i->getRadius() < rad)
|
|
|
|
{
|
|
|
|
available = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (available)
|
|
|
|
{
|
|
|
|
*lat = i->getLatitude ();
|
|
|
|
*lon = i->getLongitude();
|
|
|
|
*heading = i->getHeading ();
|
|
|
|
*gateId = i->getIndex ();
|
|
|
|
i->setAvailable(false);
|
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!found)
|
|
|
|
{
|
2007-07-04 17:39:03 +00:00
|
|
|
//cerr << "Traffic overflow at" << _ap->getId()
|
2005-12-29 13:58:21 +00:00
|
|
|
// << ". flType = " << flType
|
|
|
|
// << ". airline = " << airline
|
|
|
|
// << " Radius = " <<rad
|
|
|
|
// << endl;
|
2007-07-04 17:39:03 +00:00
|
|
|
*lat = _ap->getLatitude();
|
|
|
|
*lon = _ap->getLongitude();
|
2005-12-29 13:58:21 +00:00
|
|
|
*heading = 0;
|
|
|
|
*gateId = -1;
|
|
|
|
//exit(1);
|
|
|
|
}
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FGAirportDynamics::getParking (int id, double *lat, double* lon, double *heading)
|
|
|
|
{
|
|
|
|
if (id < 0)
|
|
|
|
{
|
2007-07-04 17:39:03 +00:00
|
|
|
*lat = _ap->getLatitude();
|
|
|
|
*lon = _ap->getLongitude();
|
2005-12-29 13:58:21 +00:00
|
|
|
*heading = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FGParkingVecIterator i = parkings.begin();
|
|
|
|
for (i = parkings.begin(); i != parkings.end(); i++)
|
|
|
|
{
|
|
|
|
if (id == i->getIndex())
|
|
|
|
{
|
|
|
|
*lat = i->getLatitude();
|
|
|
|
*lon = i->getLongitude();
|
2006-03-19 07:41:48 +00:00
|
|
|
*heading = i->getHeading();
|
2005-12-29 13:58:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-13 12:51:06 +00:00
|
|
|
FGParking *FGAirportDynamics::getParking(int id)
|
2005-12-29 13:58:21 +00:00
|
|
|
{
|
2008-07-13 12:51:06 +00:00
|
|
|
FGParkingVecIterator i = parkings.begin();
|
|
|
|
for (i = parkings.begin(); i != parkings.end(); i++)
|
|
|
|
{
|
|
|
|
if (id == i->getIndex()) {
|
|
|
|
return &(*i);
|
|
|
|
}
|
|
|
|
}
|
2005-12-29 13:58:21 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2008-07-13 12:51:06 +00:00
|
|
|
string FGAirportDynamics::getParkingName(int id)
|
2005-12-29 13:58:21 +00:00
|
|
|
{
|
2008-07-13 12:51:06 +00:00
|
|
|
FGParkingVecIterator i = parkings.begin();
|
|
|
|
for (i = parkings.begin(); i != parkings.end(); i++)
|
|
|
|
{
|
|
|
|
if (id == i->getIndex()) {
|
|
|
|
return i->getName();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-12-29 13:58:21 +00:00
|
|
|
return string("overflow");
|
|
|
|
}
|
|
|
|
void FGAirportDynamics::releaseParking(int id)
|
|
|
|
{
|
|
|
|
if (id >= 0)
|
|
|
|
{
|
|
|
|
|
|
|
|
FGParkingVecIterator i = parkings.begin();
|
|
|
|
for (i = parkings.begin(); i != parkings.end(); i++)
|
|
|
|
{
|
|
|
|
if (id == i->getIndex())
|
|
|
|
{
|
|
|
|
i -> setAvailable(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FGAirportDynamics::setRwyUse(const FGRunwayPreference& ref)
|
|
|
|
{
|
|
|
|
rwyPrefs = ref;
|
|
|
|
//cerr << "Exiting due to not implemented yet" << endl;
|
|
|
|
//exit(1);
|
|
|
|
}
|
2009-01-06 16:56:26 +00:00
|
|
|
|
2009-02-15 15:29:56 +00:00
|
|
|
bool FGAirportDynamics::innerGetActiveRunway(const string &trafficType, int action, string &runway, double heading)
|
2005-12-29 13:58:21 +00:00
|
|
|
{
|
2009-01-06 16:56:26 +00:00
|
|
|
double windSpeed;
|
2005-12-29 13:58:21 +00:00
|
|
|
double windHeading;
|
|
|
|
double maxTail;
|
|
|
|
double maxCross;
|
|
|
|
string name;
|
|
|
|
string type;
|
|
|
|
|
2009-01-06 16:56:26 +00:00
|
|
|
if (!rwyPrefs.available()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
RunwayGroup *currRunwayGroup = 0;
|
|
|
|
int nrActiveRunways = 0;
|
|
|
|
time_t dayStart = fgGetLong("/sim/time/utc/day-seconds");
|
|
|
|
if ((abs((long)(dayStart - lastUpdate)) > 600) || trafficType != prevTrafficType)
|
2005-12-29 13:58:21 +00:00
|
|
|
{
|
|
|
|
landing.clear();
|
|
|
|
takeoff.clear();
|
2006-07-27 14:49:41 +00:00
|
|
|
lastUpdate = dayStart;
|
2005-12-29 13:58:21 +00:00
|
|
|
prevTrafficType = trafficType;
|
|
|
|
|
|
|
|
FGEnvironment
|
|
|
|
stationweather = ((FGEnvironmentMgr *) globals->get_subsystem("environment"))
|
|
|
|
->getEnvironment(getLatitude(),
|
|
|
|
getLongitude(),
|
|
|
|
getElevation());
|
|
|
|
|
|
|
|
windSpeed = stationweather.get_wind_speed_kt();
|
|
|
|
windHeading = stationweather.get_wind_from_heading_deg();
|
|
|
|
string scheduleName;
|
2007-07-04 17:39:03 +00:00
|
|
|
//cerr << "finding active Runway for" << _ap->getId() << endl;
|
2005-12-29 13:58:21 +00:00
|
|
|
//cerr << "Nr of seconds since day start << " << dayStart << endl;
|
2006-03-04 08:49:36 +00:00
|
|
|
|
2005-12-29 13:58:21 +00:00
|
|
|
ScheduleTime *currSched;
|
|
|
|
//cerr << "A"<< endl;
|
|
|
|
currSched = rwyPrefs.getSchedule(trafficType.c_str());
|
|
|
|
if (!(currSched))
|
2009-01-06 16:56:26 +00:00
|
|
|
return false;
|
2005-12-29 13:58:21 +00:00
|
|
|
//cerr << "B"<< endl;
|
|
|
|
scheduleName = currSched->getName(dayStart);
|
|
|
|
maxTail = currSched->getTailWind ();
|
|
|
|
maxCross = currSched->getCrossWind ();
|
|
|
|
//cerr << "SChedule anme = " << scheduleName << endl;
|
|
|
|
if (scheduleName.empty())
|
2009-01-06 16:56:26 +00:00
|
|
|
return false;
|
2005-12-29 13:58:21 +00:00
|
|
|
//cerr << "C"<< endl;
|
|
|
|
currRunwayGroup = rwyPrefs.getGroup(scheduleName);
|
|
|
|
//cerr << "D"<< endl;
|
|
|
|
if (!(currRunwayGroup))
|
2009-01-06 16:56:26 +00:00
|
|
|
return false;
|
2005-12-29 13:58:21 +00:00
|
|
|
nrActiveRunways = currRunwayGroup->getNrActiveRunways();
|
2006-03-04 08:49:36 +00:00
|
|
|
|
2007-07-21 11:05:20 +00:00
|
|
|
// Keep a history of the currently active runways, to ensure
|
|
|
|
// that an already established selection of runways will not
|
|
|
|
// be overridden once a more preferred selection becomes
|
|
|
|
// available as that can lead to random runway swapping.
|
|
|
|
if (trafficType == "com") {
|
|
|
|
currentlyActive = &comActive;
|
|
|
|
} else if (trafficType == "gen") {
|
|
|
|
currentlyActive = &genActive;
|
|
|
|
} else if (trafficType == "mil") {
|
|
|
|
currentlyActive = &milActive;
|
|
|
|
} else if (trafficType == "ul") {
|
|
|
|
currentlyActive = &ulActive;
|
|
|
|
}
|
2006-03-04 08:49:36 +00:00
|
|
|
//
|
2008-08-14 18:13:39 +00:00
|
|
|
currRunwayGroup->setActive(_ap,
|
2006-03-04 08:49:36 +00:00
|
|
|
windSpeed,
|
|
|
|
windHeading,
|
|
|
|
maxTail,
|
|
|
|
maxCross,
|
2007-07-21 11:05:20 +00:00
|
|
|
currentlyActive);
|
2006-03-04 08:49:36 +00:00
|
|
|
|
2007-07-21 11:05:20 +00:00
|
|
|
// Note that I SHOULD keep multiple lists in memory, one for
|
2006-03-04 08:49:36 +00:00
|
|
|
// general aviation, one for commercial and one for military
|
|
|
|
// traffic.
|
2007-07-21 11:05:20 +00:00
|
|
|
currentlyActive->clear();
|
2005-12-29 13:58:21 +00:00
|
|
|
nrActiveRunways = currRunwayGroup->getNrActiveRunways();
|
2007-07-21 11:05:20 +00:00
|
|
|
//cerr << "Choosing runway for " << trafficType << endl;
|
2005-12-29 13:58:21 +00:00
|
|
|
for (int i = 0; i < nrActiveRunways; i++)
|
|
|
|
{
|
|
|
|
type = "unknown"; // initialize to something other than landing or takeoff
|
|
|
|
currRunwayGroup->getActive(i, name, type);
|
|
|
|
if (type == "landing")
|
|
|
|
{
|
|
|
|
landing.push_back(name);
|
2007-07-21 11:05:20 +00:00
|
|
|
currentlyActive->push_back(name);
|
2005-12-29 13:58:21 +00:00
|
|
|
//cerr << "Landing " << name << endl;
|
|
|
|
}
|
|
|
|
if (type == "takeoff")
|
|
|
|
{
|
|
|
|
takeoff.push_back(name);
|
2007-07-21 11:05:20 +00:00
|
|
|
currentlyActive->push_back(name);
|
2005-12-29 13:58:21 +00:00
|
|
|
//cerr << "takeoff " << name << endl;
|
|
|
|
}
|
|
|
|
}
|
2007-07-21 11:05:20 +00:00
|
|
|
//cerr << endl;
|
2005-12-29 13:58:21 +00:00
|
|
|
}
|
2009-01-06 16:56:26 +00:00
|
|
|
|
|
|
|
if (action == 1) // takeoff
|
2005-12-29 13:58:21 +00:00
|
|
|
{
|
|
|
|
int nr = takeoff.size();
|
|
|
|
if (nr)
|
|
|
|
{
|
2006-03-04 08:49:36 +00:00
|
|
|
// Note that the randomization below, is just a placeholder to choose between
|
|
|
|
// multiple active runways for this action. This should be
|
|
|
|
// under ATC control.
|
2009-02-15 15:29:56 +00:00
|
|
|
runway = chooseRwyByHeading (takeoff, heading);
|
2005-12-29 13:58:21 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // Fallback
|
|
|
|
runway = chooseRunwayFallback();
|
|
|
|
}
|
|
|
|
}
|
2009-01-06 16:56:26 +00:00
|
|
|
|
|
|
|
if (action == 2) // landing
|
2005-12-29 13:58:21 +00:00
|
|
|
{
|
|
|
|
int nr = landing.size();
|
|
|
|
if (nr)
|
|
|
|
{
|
2009-02-15 15:29:56 +00:00
|
|
|
runway = chooseRwyByHeading (landing, heading);
|
2005-12-29 13:58:21 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{ //fallback
|
|
|
|
runway = chooseRunwayFallback();
|
|
|
|
}
|
2007-07-21 11:05:20 +00:00
|
|
|
}
|
2009-01-06 16:56:26 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-02-15 15:29:56 +00:00
|
|
|
string FGAirportDynamics::chooseRwyByHeading(stringVec rwys, double heading) {
|
|
|
|
double bestError = 360.0;
|
|
|
|
double rwyHeading, headingError;
|
|
|
|
string runway;
|
|
|
|
for (stringVecIterator i = rwys.begin(); i != rwys.end(); i++) {
|
|
|
|
FGRunway *rwy = _ap->getRunwayByIdent((*i));
|
|
|
|
rwyHeading = rwy->headingDeg();
|
|
|
|
headingError = fabs(heading - rwyHeading);
|
|
|
|
if (headingError > 180)
|
|
|
|
headingError = fabs(headingError - 360);
|
|
|
|
if (headingError < bestError) {
|
|
|
|
runway = (*i);
|
|
|
|
bestError = headingError;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//cerr << "Using active runway " << runway << " for heading " << heading << endl;
|
|
|
|
return runway;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FGAirportDynamics::getActiveRunway(const string &trafficType, int action, string &runway, double heading)
|
2009-01-06 16:56:26 +00:00
|
|
|
{
|
2009-02-15 15:29:56 +00:00
|
|
|
bool ok = innerGetActiveRunway(trafficType, action, runway, heading);
|
2009-01-06 16:56:26 +00:00
|
|
|
if (!ok) {
|
|
|
|
runway = chooseRunwayFallback();
|
|
|
|
}
|
2005-12-29 13:58:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
string FGAirportDynamics::chooseRunwayFallback()
|
|
|
|
{
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
FGRunway* rwy = _ap->getActiveRunwayForUsage();
|
|
|
|
return rwy->ident();
|
2007-07-04 17:39:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FGAirportDynamics::addParking(FGParking& park) {
|
|
|
|
parkings.push_back(park);
|
|
|
|
}
|
|
|
|
|
|
|
|
double FGAirportDynamics::getLatitude() const {
|
|
|
|
return _ap->getLatitude();
|
|
|
|
}
|
|
|
|
|
|
|
|
double FGAirportDynamics::getLongitude() const {
|
|
|
|
return _ap->getLongitude();
|
|
|
|
}
|
|
|
|
|
|
|
|
double FGAirportDynamics::getElevation() const {
|
|
|
|
return _ap->getElevation();
|
|
|
|
}
|
|
|
|
|
|
|
|
const string& FGAirportDynamics::getId() const {
|
|
|
|
return _ap->getId();
|
2005-12-29 13:58:21 +00:00
|
|
|
}
|
2009-02-07 17:17:07 +00:00
|
|
|
|
|
|
|
// Experimental: Return a different ground frequency depending on the leg of the
|
|
|
|
// Flight. Leg should always have a minimum value of two when this function is called.
|
|
|
|
// Note that in this scheme, the assignment of various frequencies to various ground
|
|
|
|
// operations is completely arbitrary. As such, is a short cut I need to take now,
|
|
|
|
// so that at least I can start working on assigning different frequencies to different
|
|
|
|
// operations.
|
|
|
|
|
|
|
|
int FGAirportDynamics::getGroundFrequency(int leg) {
|
|
|
|
//return freqGround.size() ? freqGround[0] : 0; };
|
|
|
|
int groundFreq;
|
|
|
|
if (leg < 2) {
|
|
|
|
SG_LOG(SG_ATC, SG_ALERT, "Leg value is smaller than two at " << SG_ORIGIN);
|
|
|
|
}
|
|
|
|
if (freqGround.size() == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if ((freqGround.size() >= leg-1) && (leg > 1)) {
|
|
|
|
groundFreq = freqGround[leg-1];
|
|
|
|
}
|
|
|
|
if ((freqGround.size() < leg-1) && (leg > 1)) {
|
|
|
|
groundFreq = (freqGround.size() < (leg-2)) ? freqGround[freqGround.size()-1] : freqGround[leg-2];
|
|
|
|
}
|
|
|
|
if ((freqGround.size() >= leg-1) && (leg > 1)) {
|
|
|
|
groundFreq = freqGround[leg-2];
|
|
|
|
}
|
|
|
|
return groundFreq;
|
2009-03-08 17:14:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FGAIFlightPlan *FGAirportDynamics::getSID(string activeRunway, double heading)
|
|
|
|
{
|
|
|
|
return SIDs.getBest(activeRunway, heading);
|
2009-03-16 16:37:39 +00:00
|
|
|
}
|