X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FAirports%2Fdynamics.cxx;h=398920f329e99cb0ec04fc31256ae1bc375a8f1a;hb=f9a5f921a4853f7e64d467d63e19acf8f6f84979;hp=e8eb6f6e32ff3a60ecf414b511a68fe11ebf4056;hpb=4be621fbe96114a246ed74aefe9b9a98bbf99b44;p=flightgear.git diff --git a/src/Airports/dynamics.cxx b/src/Airports/dynamics.cxx index e8eb6f6e3..398920f32 100644 --- a/src/Airports/dynamics.cxx +++ b/src/Airports/dynamics.cxx @@ -14,7 +14,7 @@ // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // $Id$ @@ -22,17 +22,10 @@ # include #endif -#ifdef _MSC_VER -# define _USE_MATH_DEFINES -#endif -//#include #include #include -#include -#include - #include #include #include @@ -43,588 +36,534 @@ #include
#include
#include -#include -#include STL_STRING +#include #include -SG_USING_STD(string); -SG_USING_STD(vector); -SG_USING_STD(sort); -SG_USING_STD(random_shuffle); +using std::string; +using std::vector; +using std::sort; +using std::random_shuffle; -#include "parking.hxx" -#include "groundnetwork.hxx" -#include "runwayprefs.hxx" +#include "simple.hxx" #include "dynamics.hxx" -/********** FGAirport Dynamics *********************************************/ - -FGAirportDynamics::FGAirportDynamics(double lat, double lon, double elev, string id) : - _latitude(lat), - _longitude(lon), - _elevation(elev), - _id(id) +FGAirportDynamics::FGAirportDynamics(FGAirport * ap): +_ap(ap), rwyPrefs(ap), SIDs(ap),startupController(this) { - lastUpdate = 0; - for (int i = 0; i < 10; i++) - { - avWindHeading [i] = 0; - avWindSpeed [i] = 0; - } -} + lastUpdate = 0; + // For testing only. This needs to be refined when we move ATIS functionality over. + atisInformation = "Sierra"; +} // Note that the ground network should also be copied -FGAirportDynamics::FGAirportDynamics(const FGAirportDynamics& other) +FGAirportDynamics:: +FGAirportDynamics(const FGAirportDynamics & other):rwyPrefs(other. + rwyPrefs), +SIDs(other.SIDs), startupController(other.startupController) { - for (FGParkingVecConstIterator ip= other.parkings.begin(); ip != other.parkings.end(); ip++) - parkings.push_back(*(ip)); - rwyPrefs = other.rwyPrefs; - 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; - for (int i = 0; i < 10; i++) - { - avWindHeading [i] = other.avWindHeading[i]; - avWindSpeed [i] = other.avWindSpeed [i]; - } + for (FGParkingVecConstIterator ip = other.parkings.begin(); + ip != other.parkings.end(); ip++) + parkings.push_back(*(ip)); + // rwyPrefs = other.rwyPrefs; + 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; + atisInformation = other.atisInformation; } // Destructor FGAirportDynamics::~FGAirportDynamics() { - } // Initialization required after XMLRead -void FGAirportDynamics::init() +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(); + // 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.setParent(_ap); + groundNetwork.addNodes(&parkings); + groundNetwork.init(); + groundNetwork.setTowerController(&towerController); + } -bool FGAirportDynamics::getAvailableParking(double *lat, double *lon, double *heading, int *gateId, double rad, const string &flType, const string &acType, const string &airline) +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()) - { - //cerr << "Could not find parking spot at " << _id << endl; - *lat = _latitude; - *lon = _longitude; - *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 - if (i->getCodes().find(airline, 0) == string::npos) - { - available = false; - continue; - } - // 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)) - { - 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; - } - } - // 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; - } - } + bool found = false; + bool available = false; + + + FGParkingVecIterator i; + if (parkings.begin() == parkings.end()) { + //cerr << "Could not find parking spot at " << _ap->getId() << endl; + *lat = _ap->getLatitude(); + *lon = _ap->getLongitude(); + *heading = 0; + found = true; + } else { + // First try finding a parking with a designated airline code + for (i = parkings.begin(); !(i == parkings.end() || found); i++) { + 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 + //cerr << "Code = " << airline << ": Codes " << i->getCodes(); + if (i->getCodes().find(airline, 0) == string::npos) { + available = false; + //cerr << "Unavailable" << endl; + continue; + } else { + //cerr << "Available" << endl; + } + } + // 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)) { + 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; + } + } + // 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) - { - //cerr << "Traffic overflow at" << _id - // << ". flType = " << flType - // << ". airline = " << airline - // << " Radius = " <getId() + // << ". flType = " << flType + // << ". airline = " << airline + // << " Radius = " <getLatitude(); + *lon = _ap->getLongitude(); + *heading = 0; + *gateId = -1; + //exit(1); } - return found; + return found; } -void FGAirportDynamics::getParking (int id, double *lat, double* lon, double *heading) +void FGAirportDynamics::getParking(int id, double *lat, double *lon, + double *heading) { - if (id < 0) - { - *lat = _latitude; - *lon = _longitude; - *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(); - *heading = i->getLongitude(); - } - } + if (id < 0) { + *lat = _ap->getLatitude(); + *lon = _ap->getLongitude(); + *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(); + *heading = i->getHeading(); + } + } } -} +} -FGParking *FGAirportDynamics::getParking(int i) -{ - if (i < (int)parkings.size()) - return &(parkings[i]); - else +FGParking *FGAirportDynamics::getParking(int id) +{ + FGParkingVecIterator i = parkings.begin(); + for (i = parkings.begin(); i != parkings.end(); i++) { + if (id == i->getIndex()) { + return &(*i); + } + } return 0; } -string FGAirportDynamics::getParkingName(int i) -{ - if (i < (int)parkings.size() && i >= 0) - return (parkings[i].getName()); - else + +string FGAirportDynamics::getParkingName(int id) +{ + FGParkingVecIterator i = parkings.begin(); + for (i = parkings.begin(); i != parkings.end(); i++) { + if (id == i->getIndex()) { + return i->getName(); + } + } + 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); - } - } + if (id >= 0) { + + FGParkingVecIterator i = parkings.begin(); + for (i = parkings.begin(); i != parkings.end(); i++) { + if (id == i->getIndex()) { + i->setAvailable(true); + } + } } } - -void FGAirportDynamics::startXML () { - //cout << "Start XML" << endl; -} -void FGAirportDynamics::endXML () { - //cout << "End XML" << endl; +void FGAirportDynamics::setRwyUse(const FGRunwayPreference & ref) +{ + rwyPrefs = ref; + //cerr << "Exiting due to not implemented yet" << endl; + //exit(1); } -void FGAirportDynamics::startElement (const char * name, const XMLAttributes &atts) { - // const char *attval; - FGParking park; - FGTaxiNode taxiNode; - FGTaxiSegment taxiSegment; - int index = 0; - taxiSegment.setIndex(index); - //cout << "Start element " << name << endl; - string attname; - string value; - string gateName; - string gateNumber; - string lat; - string lon; - if (name == string("Parking")) - { - for (int i = 0; i < atts.size(); i++) - { - //cout << " " << atts.getName(i) << '=' << atts.getValue(i) << endl; - attname = atts.getName(i); - if (attname == string("index")) - park.setIndex(atoi(atts.getValue(i))); - else if (attname == string("type")) - park.setType(atts.getValue(i)); - else if (attname == string("name")) - gateName = atts.getValue(i); - else if (attname == string("number")) - gateNumber = atts.getValue(i); - else if (attname == string("lat")) - park.setLatitude(atts.getValue(i)); - else if (attname == string("lon")) - park.setLongitude(atts.getValue(i)); - else if (attname == string("heading")) - park.setHeading(atof(atts.getValue(i))); - else if (attname == string("radius")) { - string radius = atts.getValue(i); - if (radius.find("M") != string::npos) - radius = radius.substr(0, radius.find("M",0)); - //cerr << "Radius " << radius < 600) + || trafficType != prevTrafficType) { + landing.clear(); + takeoff.clear(); + lastUpdate = dayStart; + prevTrafficType = trafficType; + /* + FGEnvironment + stationweather = + ((FGEnvironmentMgr *) globals->get_subsystem("environment")) + ->getEnvironment(getLatitude(), getLongitude(), + getElevation()); + */ + windSpeed = fgGetInt("/environment/metar/base-wind-speed-kt"); //stationweather.get_wind_speed_kt(); + windHeading = fgGetInt("/environment/metar/base-wind-dir-deg"); + //stationweather.get_wind_from_heading_deg(); + string scheduleName; + //cerr << "finding active Runway for : " << _ap->getId() << endl; + //cerr << "Wind Heading : " << windHeading << endl; + //cerr << "Wind Speed : " << windSpeed << endl; + + //cerr << "Nr of seconds since day start << " << dayStart << endl; + + ScheduleTime *currSched; + //cerr << "A"<< endl; + currSched = rwyPrefs.getSchedule(trafficType.c_str()); + if (!(currSched)) + return false; + //cerr << "B"<< endl; + scheduleName = currSched->getName(dayStart); + maxTail = currSched->getTailWind(); + maxCross = currSched->getCrossWind(); + //cerr << "Current Schedule = : " << scheduleName << endl; + if (scheduleName.empty()) + return false; + //cerr << "C"<< endl; + currRunwayGroup = rwyPrefs.getGroup(scheduleName); + //cerr << "D"<< endl; + if (!(currRunwayGroup)) + return false; + nrActiveRunways = currRunwayGroup->getNrActiveRunways(); + + // 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; + } + + //cerr << "Durrently active selection for " << trafficType << ": "; + for (stringVecIterator it = currentlyActive->begin(); + it != currentlyActive->end(); it++) { + //cerr << (*it) << " "; + } + //cerr << endl; + + currRunwayGroup->setActive(_ap, + windSpeed, + windHeading, + maxTail, maxCross, currentlyActive); + + // Note that I SHOULD keep multiple lists in memory, one for + // general aviation, one for commercial and one for military + // traffic. + currentlyActive->clear(); + nrActiveRunways = currRunwayGroup->getNrActiveRunways(); + //cerr << "Choosing runway for " << trafficType << endl; + 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); + currentlyActive->push_back(name); + //cerr << "Landing " << name << endl; + } + if (type == "takeoff") { + takeoff.push_back(name); + currentlyActive->push_back(name); + //cerr << "takeoff " << name << endl; + } + } + //cerr << endl; + } + + if (action == 1) // takeoff { - for (int i = 0; i < atts.size() ; i++) - { - attname = atts.getName(i); - if (attname == string("index")) - taxiNode.setIndex(atoi(atts.getValue(i))); - if (attname == string("lat")) - taxiNode.setLatitude(atts.getValue(i)); - if (attname == string("lon")) - taxiNode.setLongitude(atts.getValue(i)); - } - groundNetwork.addNode(taxiNode); + int nr = takeoff.size(); + if (nr) { + // Note that the randomization below, is just a placeholder to choose between + // multiple active runways for this action. This should be + // under ATC control. + runway = chooseRwyByHeading(takeoff, heading); + } else { // Fallback + runway = chooseRunwayFallback(); + } } - if (name == string("arc")) + + if (action == 2) // landing { - taxiSegment.setIndex(++index); - for (int i = 0; i < atts.size() ; i++) - { - attname = atts.getName(i); - if (attname == string("begin")) - taxiSegment.setStartNodeRef(atoi(atts.getValue(i))); - if (attname == string("end")) - taxiSegment.setEndNodeRef(atoi(atts.getValue(i))); - } - groundNetwork.addSegment(taxiSegment); + int nr = landing.size(); + if (nr) { + runway = chooseRwyByHeading(landing, heading); + } else { //fallback + runway = chooseRunwayFallback(); + } + } + + return true; +} + +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++) { + if (!_ap->hasRunwayWithIdent(*i)) { + SG_LOG(SG_ATC, SG_WARN, "chooseRwyByHeading: runway " << *i << + " not found at " << _ap->ident()); + continue; + } + + 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) +{ + bool ok = innerGetActiveRunway(trafficType, action, runway, heading); + if (!ok) { + runway = chooseRunwayFallback(); } - // sort by radius, in asending order, so that smaller gates are first in the list } -void FGAirportDynamics::endElement (const char * name) { - //cout << "End element " << name << endl; +string FGAirportDynamics::chooseRunwayFallback() +{ + FGRunway *rwy = _ap->getActiveRunwayForUsage(); + return rwy->ident(); +} +void FGAirportDynamics::addParking(FGParking & park) +{ + parkings.push_back(park); } -void FGAirportDynamics::data (const char * s, int len) { - string token = string(s,len); - //cout << "Character data " << string(s,len) << endl; - //if ((token.find(" ") == string::npos && (token.find('\n')) == string::npos)) - //value += token; - //else - //value = string(""); +double FGAirportDynamics::getLatitude() const +{ + return _ap->getLatitude(); } -void FGAirportDynamics::pi (const char * target, const char * data) { - //cout << "Processing instruction " << target << ' ' << data << endl; +double FGAirportDynamics::getLongitude() const +{ + return _ap->getLongitude(); } -void FGAirportDynamics::warning (const char * message, int line, int column) { - cout << "Warning: " << message << " (" << line << ',' << column << ')' - << endl; +double FGAirportDynamics::getElevation() const +{ + return _ap->getElevation(); } -void FGAirportDynamics::error (const char * message, int line, int column) { - cout << "Error: " << message << " (" << line << ',' << column << ')' - << endl; +const string & FGAirportDynamics::getId() const +{ + return _ap->getId(); } -void FGAirportDynamics::setRwyUse(const FGRunwayPreference& ref) +// 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(unsigned leg) { - rwyPrefs = ref; - //cerr << "Exiting due to not implemented yet" << endl; - //exit(1); + //return freqGround.size() ? freqGround[0] : 0; }; + int groundFreq = 0; + 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 - 1)) ? freqGround[freqGround.size() - + 1] : freqGround[leg - 2]; + } + if ((freqGround.size() >= leg - 1) && (leg > 1)) { + groundFreq = freqGround[leg - 2]; + } + return groundFreq; } -void FGAirportDynamics::getActiveRunway(const string &trafficType, int action, string &runway) + +int FGAirportDynamics::getTowerFrequency(unsigned nr) { - double windSpeed; - double windHeading; - double maxTail; - double maxCross; - string name; - string type; - - if (!(rwyPrefs.available())) - { - runway = chooseRunwayFallback(); - return; // generic fall back goes here + int towerFreq = 0; + if (nr < 2) { + SG_LOG(SG_ATC, SG_ALERT, + "Leg value is smaller than two at " << SG_ORIGIN); } - else - { - RunwayGroup *currRunwayGroup = 0; - int nrActiveRunways = 0; - time_t dayStart = fgGetLong("/sim/time/utc/day-seconds"); - if (((dayStart - lastUpdate) > 600) || trafficType != prevTrafficType) - { - landing.clear(); - takeoff.clear(); - //lastUpdate = dayStart; - 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(); - double averageWindSpeed = 0; - double averageWindHeading = 0; - double cosHeading = 0; - double sinHeading = 0; - // Initialize at the beginning of the next day or startup - if ((lastUpdate == 0) || (dayStart < lastUpdate)) - { - for (int i = 0; i < 10; i++) - { - avWindHeading [i] = windHeading; - avWindSpeed [i] = windSpeed; - } - } - else - { - if (windSpeed != avWindSpeed[9]) // update if new metar data - { - // shift the running average - for (int i = 0; i < 9 ; i++) - { - avWindHeading[i] = avWindHeading[i+1]; - avWindSpeed [i] = avWindSpeed [i+1]; - } - } - avWindHeading[9] = windHeading; - avWindSpeed [9] = windSpeed; - } - - for (int i = 0; i < 10; i++) - { - averageWindSpeed += avWindSpeed [i]; - //averageWindHeading += avWindHeading [i]; - cosHeading += cos(avWindHeading[i] * SG_DEGREES_TO_RADIANS); - sinHeading += sin(avWindHeading[i] * SG_DEGREES_TO_RADIANS); - } - averageWindSpeed /= 10; - //averageWindHeading /= 10; - cosHeading /= 10; - sinHeading /= 10; - averageWindHeading = atan2(sinHeading, cosHeading) *SG_RADIANS_TO_DEGREES; - if (averageWindHeading < 0) - averageWindHeading += 360.0; - //cerr << "Wind Heading " << windHeading << " average " << averageWindHeading << endl; - //cerr << "Wind Speed " << windSpeed << " average " << averageWindSpeed << endl; - lastUpdate = dayStart; - //if (wind_speed == 0) { - // wind_heading = 270; This forces West-facing rwys to be used in no-wind situations - // which is consistent with Flightgear's initial setup. - //} - - //string rwy_no = globals->get_runways()->search(apt->getId(), int(wind_heading)); - string scheduleName; - //cerr << "finding active Runway for" << _id << endl; - //cerr << "Nr of seconds since day start << " << dayStart << endl; - ScheduleTime *currSched; - //cerr << "A"<< endl; - currSched = rwyPrefs.getSchedule(trafficType.c_str()); - if (!(currSched)) - return; - //cerr << "B"<< endl; - scheduleName = currSched->getName(dayStart); - maxTail = currSched->getTailWind (); - maxCross = currSched->getCrossWind (); - //cerr << "SChedule anme = " << scheduleName << endl; - if (scheduleName.empty()) - return; - //cerr << "C"<< endl; - currRunwayGroup = rwyPrefs.getGroup(scheduleName); - //cerr << "D"<< endl; - if (!(currRunwayGroup)) - return; - nrActiveRunways = currRunwayGroup->getNrActiveRunways(); - //cerr << "Nr of Active Runways = " << nrActiveRunways << endl; - currRunwayGroup->setActive(_id, averageWindSpeed, averageWindHeading, maxTail, maxCross); - nrActiveRunways = currRunwayGroup->getNrActiveRunways(); - 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); - //cerr << "Landing " << name << endl; - } - if (type == "takeoff") - { - takeoff.push_back(name); - //cerr << "takeoff " << name << endl; - } - } - } - if (action == 1) // takeoff - { - int nr = takeoff.size(); - if (nr) - { - runway = takeoff[(rand() % nr)]; - } - else - { // Fallback - runway = chooseRunwayFallback(); - } - } - if (action == 2) // landing - { - int nr = landing.size(); - if (nr) - { - runway = landing[(rand() % nr)]; - } - else - { //fallback - runway = chooseRunwayFallback(); - } - } - - //runway = globals->get_runways()->search(_id, int(windHeading)); - //cerr << "Seleceted runway: " << runway << endl; + if (freqTower.size() == 0) { + return 0; + } + if ((freqTower.size() > nr - 1) && (nr > 1)) { + towerFreq = freqTower[nr - 1]; } + if ((freqTower.size() < nr - 1) && (nr > 1)) { + towerFreq = + (freqTower.size() < + (nr - 1)) ? freqTower[freqTower.size() - + 1] : freqTower[nr - 2]; + } + if ((freqTower.size() >= nr - 1) && (nr > 1)) { + towerFreq = freqTower[nr - 2]; + } + return towerFreq; } -string FGAirportDynamics::chooseRunwayFallback() -{ - FGEnvironment - stationweather = ((FGEnvironmentMgr *) globals->get_subsystem("environment")) - ->getEnvironment(getLatitude(), - getLongitude(), - getElevation()); - - double windSpeed = stationweather.get_wind_speed_kt(); - double windHeading = stationweather.get_wind_from_heading_deg(); - if (windSpeed == 0) { - windHeading = 270; // This forces West-facing rwys to be used in no-wind situations - //which is consistent with Flightgear's initial setup. - } - - return globals->get_runways()->search(_id, int(windHeading)); + +FGAIFlightPlan *FGAirportDynamics::getSID(string activeRunway, + double heading) +{ + return SIDs.getBest(activeRunway, heading); }