17#include <simgear/debug/ErrorReportingCallback.hxx>
18#include <simgear/debug/logstream.hxx>
19#include <simgear/misc/sg_path.hxx>
20#include <simgear/props/props.hxx>
21#include <simgear/props/props_io.hxx>
22#include <simgear/sg_inlines.h>
23#include <simgear/structure/exception.hxx>
54 const std::string &
id,
55 const SGGeod& location,
56 const std::string &
name,
62 _has_metar(has_metar),
64 mTowerDataLoaded(false),
66 mRunwaysLoaded(false),
67 mHelipadsLoaded(false),
68 mTaxiwaysLoaded(false),
69 mProceduresLoaded(false),
70 mThresholdDataLoaded(false),
73 mIsClosed = (
name.find(
"[x]") != std::string::npos);
105 return mRunways.size();
112 return mHelipads.size();
119 return mRunways.at(aIndex);
135 double minLengthFt =
fgGetDouble(
"/sim/navdb/min-runway-length-ft");
137 for (
auto rwy : mRunways) {
140 if( rwy->lengthFt() >= minLengthFt )
141 map[ rwy->ident() ] = rwy;
153 for (
auto id : mHelipads) {
155 map[ rwy->
ident() ] = rwy;
165 for (
auto rwy : mRunways) {
166 if (rwy->ident() == aIdent) {
188 for (
auto rwy : mRunways) {
189 if (rwy->ident() == aIdent) {
194 SG_LOG(SG_GENERAL, SG_ALERT,
"no such runway '" << aIdent <<
"' at airport " <<
ident());
195 throw sg_range_exception(
"unknown runway " + aIdent +
" at airport:" +
ident(),
"FGAirport::getRunwayByIdent");
203 SG_LOG(SG_GENERAL, SG_ALERT,
"no such helipad '" << aIdent <<
"' at airport " <<
ident());
204 throw sg_range_exception(
"unknown helipad " + aIdent +
" at airport:" +
ident(),
"FGAirport::getRunwayByIdent");
217 double currentBestQuality = 0.0;
220 if( NULL != parms ) fbrfhp = *parms;
222 SGPropertyNode_ptr searchNode =
fgGetNode(
"/sim/airport/runways/search");
223 if( searchNode.valid() ) {
231 for (
auto rwy : mRunways) {
233 double dev = aHeading - rwy->headingDeg();
234 SG_NORMALIZE_RANGE(dev, -180.0, 180.0);
236 double quality = good / bad;
238 if (quality > currentBestQuality) {
239 currentBestQuality = quality;
253 double currentLowestDev = 180.0;
255 for (
auto rwy : mRunways) {
256 double inboundCourse = SGGeodesy::courseDeg(aPos, rwy->end());
257 double dev = inboundCourse - rwy->headingDeg();
258 SG_NORMALIZE_RANGE(dev, -180.0, 180.0);
261 if (dev < currentLowestDev) {
262 currentLowestDev = dev;
276 for (
auto rwy : mRunways) {
277 if (rwy->isHardSurface() && (rwy->lengthFt() >= aLengthFt)) {
290 for (
auto rwy : mRunways) {
291 if (!r || (r->lengthFt() < rwy->lengthFt())) {
314 for (
auto rwy : mRunways) {
317 FGRunwayList::iterator it = std::find(r.begin(), r.end(), recip);
333 return mTaxiways.size();
353 return mPavements.size();
364 mPavements.push_back(pavement);
370 return mBoundary.size();
381 mBoundary.push_back(boundary);
387 return mLineFeatures.size();
393 return mLineFeatures;
398 mLineFeatures.push_back(linefeature);
413 const auto stationWeather = envMgr->getAircraftEnvironment();
415 double windSpeed = stationWeather->get_wind_speed_kt();
416 if (windSpeed > 0.0) {
417 hdg = stationWeather->get_wind_from_heading_deg();
433 return static_pointer_cast<FGAirport>
440 mMinLengthFt(minLengthFt)
442 if (minLengthFt < 0.0) {
443 mMinLengthFt =
fgGetDouble(
"/sim/navdb/min-runway-length-ft", 0.0);
485 airportCache.clear();
491 AirportCache::iterator it = airportCache.find(aIdent);
492 if (it != airportCache.end())
502 airportCache[aIdent] = r;
513 throw sg_range_exception(
"No such airport with ident: " + aIdent);
538void FGAirport::loadRunways()
const
540 if (mRunwaysLoaded) {
544 loadSceneryDefinitions();
546 mRunwaysLoaded =
true;
548 for (
auto id : rwys) {
553void FGAirport::loadHelipads()
const
555 if (mHelipadsLoaded) {
559 mHelipadsLoaded =
true;
563void FGAirport::loadTaxiways()
const
565 if (mTaxiwaysLoaded) {
569 mTaxiwaysLoaded =
true;
573void FGAirport::loadProcedures()
const
575 if (mProceduresLoaded) {
579 mProceduresLoaded =
true;
582 SG_LOG(SG_GENERAL, SG_INFO,
"no procedures data available for " <<
ident());
586 SG_LOG(SG_GENERAL, SG_INFO,
ident() <<
": loading procedures from " << path);
590void FGAirport::loadRunwayRenames()
const
592 if (mRunwayRenamesLoaded) {
599 mRunwayRenamesLoaded =
true;
604 SGPropertyNode_ptr rootNode =
new SGPropertyNode;
605 readProperties(path, rootNode);
606 const_cast<FGAirport*
>(
this)->parseRunwayRenameData(rootNode);
607 mRunwayRenamesLoaded =
true;
608 }
catch (sg_exception& e) {
609 SG_LOG(SG_NAVAID, SG_WARN,
ident() <<
"loading runway rename XML failed:" << e.getFormattedMessage());
613void FGAirport::loadSceneryDefinitions()
const
615 if (mThresholdDataLoaded) {
619 mThresholdDataLoaded =
true;
627 SGPropertyNode_ptr rootNode =
new SGPropertyNode;
628 readProperties(path, rootNode);
629 const_cast<FGAirport*
>(
this)->readThresholdData(rootNode);
630 }
catch (sg_exception& e) {
631 simgear::reportFailure(simgear::LoadFailure::BadData, simgear::ErrorCode::TerraSync,
632 "Airport threshold data could not be loaded:" + e.getFormattedMessage(),
637void FGAirport::readThresholdData(SGPropertyNode* aRoot)
639 SGPropertyNode* runway;
641 for (; (runway = aRoot->getChild(
"runway", runwayIndex)) != NULL; ++runwayIndex) {
642 SGPropertyNode* t0 = runway->getChild(
"threshold", 0),
643 *t1 = runway->getChild(
"threshold", 1);
645 throw sg_io_exception(
"Mis-configured runway threshold data: exactly two thresholds must be defined",
646 sg_location{runway},
"FGAirport::readThresholdData",
false);
649 processThreshold(t0);
650 processThreshold(t1);
654void FGAirport::processThreshold(SGPropertyNode* aThreshold)
657 std::string rwyIdent(aThreshold->getStringValue(
"rwy"));
661 double lon = aThreshold->getDoubleValue(
"lon"),
662 lat = aThreshold->getDoubleValue(
"lat");
663 SGGeod newThreshold(SGGeod::fromDegM(lon, lat,
elevationM()));
665 double newHeading = aThreshold->getDoubleValue(
"hdg-deg");
666 double newDisplacedThreshold = aThreshold->getDoubleValue(
"displ-m");
667 double newStopway = aThreshold->getDoubleValue(
"stopw-m");
670 const auto runwayIdent =
ident() +
"/" + rwyIdent;
674 throw sg_io_exception(
"Found runway not defined in global data:" + runwayIdent,
675 sg_location{aThreshold},
"FGAirport::processThreshold",
false);
678 double newLength = 0.0, newWidth = 0.0;
680 FGRunway* rwy =
new FGRunway(
id,
guid(), rwyIdent, newThreshold,
683 newDisplacedThreshold, newStopway,
686 mRunways.push_back(rwy);
691 newDisplacedThreshold, newStopway);
699 return mTowerPosition;
702void FGAirport::validateTowerData()
const
704 if (mTowerDataLoaded) {
708 mTowerDataLoaded =
true;
713 if (towers.empty()) {
715 mTowerPosition =
geod();
721 if ((runwayCount > 0) && (runwayCount <= 2)) {
724 mTowerPosition = SGGeodesy::direct(
geod(), hdg, runway->
widthM() * 8);
728 mTowerPosition.setElevationM(
geod().getElevationM() + 20.0);
731 mTowerPosition = tower->geod();
741 SGPropertyNode_ptr rootNode =
new SGPropertyNode;
742 readProperties(path, rootNode);
743 const_cast<FGAirport*
>(
this)->readTowerData(rootNode);
745 }
catch (sg_exception& e){
746 SG_LOG(SG_NAVAID, SG_WARN,
ident() <<
"loading twr XML failed:" << e.getFormattedMessage());
750void FGAirport::readTowerData(SGPropertyNode* aRoot)
752 SGPropertyNode* twrNode = aRoot->getChild(
"tower")->getChild(
"twr");
753 double lat = twrNode->getDoubleValue(
"lat"),
754 lon = twrNode->getDoubleValue(
"lon"),
755 elevM = twrNode->getDoubleValue(
"elev-m");
759 double fieldElevationM =
geod().getElevationM();
760 mTowerPosition = SGGeod::fromDegM(lon, lat, fieldElevationM + elevM);
763void FGAirport::parseRunwayRenameData(SGPropertyNode* aRoot)
765 SGPropertyNode* overrideNode = aRoot->getChild(
"runway-rename");
766 for (
auto rnm : overrideNode->getChildren(
"runway")) {
767 const std::string oldIdent = rnm->getStringValue(
"old-ident");
768 const std::string newIdent = rnm->getStringValue(
"new-ident");
769 if (oldIdent.empty() || newIdent.empty()) {
770 SG_LOG(SG_NAVAID, SG_WARN,
ident() <<
": runway rename: Skipping bad runway rename entry");
775 SG_LOG(SG_NAVAID, SG_WARN,
ident() <<
": no old runway with ident:" << oldIdent);
779 _renamedRunways[newIdent] = oldIdent;
787 auto it = _renamedRunways.find(newIdent);
788 if (it == _renamedRunways.end())
797 if (mILSDataLoaded) {
803 mILSDataLoaded =
true;
811 SGPropertyNode_ptr rootNode =
new SGPropertyNode;
812 readProperties(path, rootNode);
813 readILSData(rootNode);
814 }
catch (sg_exception& e){
815 SG_LOG(SG_NAVAID, SG_WARN,
ident() <<
"loading ils XML failed:" << e.getFormattedMessage());
825void FGAirport::readILSData(SGPropertyNode* aRoot)
829 SGPropertyNode* runwayNode, *ilsNode;
830 for (
int i=0; (runwayNode = aRoot->getChild(
"runway",
i)) != NULL; ++
i) {
831 for (
int j=0; (ilsNode = runwayNode->getChild(
"ils", j)) != NULL; ++j) {
836 ilsNode->getStringValue(
"nav-id"));
838 SG_LOG(SG_GENERAL, SG_INFO,
"reading ILS data for " <<
ident() <<
839 ", couldn't find runway/navaid for:" <<
840 ilsNode->getStringValue(
"rwy") <<
"/" <<
841 ilsNode->getStringValue(
"nav-id"));
845 double hdgDeg = ilsNode->getDoubleValue(
"hdg-deg"),
846 lon = ilsNode->getDoubleValue(
"lon"),
847 lat = ilsNode->getDoubleValue(
"lat"),
848 elevM = ilsNode->getDoubleValue(
"elev-m");
852 nav->updateFromXML(SGGeod::fromDegM(lon, lat, elevM), hdgDeg);
859 mSIDs.push_back(aSid);
864 mSTARs.push_back(aStar);
869 mApproaches.push_back(aApp);
883 return mSIDs[aIndex];
890 for (
unsigned int i=0;
i<mSIDs.size(); ++
i) {
891 if (mSIDs[
i]->
ident() == aIdent) {
910 return mSTARs.size();
917 return mSTARs[aIndex];
924 for (
unsigned int i=0;
i<mSTARs.size(); ++
i) {
925 if (mSTARs[
i]->
ident() == aIdent) {
937 return STARList(mSTARs.begin(), mSTARs.end());
943 return mApproaches.size();
950 return mApproaches[aIndex];
957 for (
unsigned int i=0;
i<mApproaches.size(); ++
i) {
958 if (mApproaches[
i]->
ident() == aIdent) {
959 return mApproaches[
i];
971 return ApproachList(mApproaches.begin(), mApproaches.end());
974 for(
size_t i = 0;
i < mApproaches.size(); ++
i)
977 ret.push_back(mApproaches[
i]);
1018 _sizeMetric +=
static_cast<int>(rwy->
lengthFt());
1024 return _sizeMetric < other._sizeMetric;
1031 unsigned int _sizeMetric;
1037 std::vector<AirportWithSize> annotated;
1038 for (
auto p : airportList) {
1041 std::sort(annotated.begin(), annotated.end());
1043 for (
unsigned int i=0;
i<annotated.size(); ++
i) {
1044 airportList[
i] = annotated[
i].pos();
1055 if (!_groundNetwork.get()) {
1058 _groundNetwork->init();
1061 return _groundNetwork.get();
1067 for (
auto sid : mSIDs) {
1068 auto trans = sid->findTransitionByEnroute(enroute);
1079 for (
auto sid : mSIDs) {
1080 if (runway && !sid->isForRunway(runway))
1083 auto trans = sid->findTransitionByName(aIdent);
1094 for (
auto star : mSTARs) {
1095 auto trans = star->findTransitionByEnroute(enroute);
1106 for (
auto star : mSTARs) {
1107 if (runway && !star->isForRunway(runway))
1110 auto trans = star->findTransitionByName(aIdent);
1138 return SGGeod::fromDegM(0.0, 0.0, -9999.0);
SGGeod fgGetAirportPos(const std::string &id)
const FGAirport * fgFindAirportID(const std::string &id)
double fgGetAirportElev(const std::string &id)
std::map< std::string, FGRunwayRef > FGRunwayMap
SGSharedPtr< FGTaxiway > FGTaxiwayRef
SGSharedPtr< FGAirportDynamics > FGAirportDynamicsRef
std::vector< FGRunwayRef > FGRunwayList
SGSharedPtr< FGHelipad > FGHelipadRef
SGSharedPtr< FGPavement > FGPavementRef
std::vector< FGPavementRef > FGPavementList
std::map< std::string, FGHelipadRef > FGHelipadMap
SGSharedPtr< FGAirport > FGAirportRef
SGSharedPtr< FGRunway > FGRunwayRef
std::vector< FGTaxiwayRef > FGTaxiwayList
bool operator<(const AirportWithSize &other) const
FGPositionedRef pos() const
AirportWithSize(FGPositionedRef pos)
HardSurfaceFilter(double minLengthFt=-1)
virtual bool passAirport(FGAirport *aApt) const override
Filter which passes heliports and seaports in addition to airports.
bool fromTypeString(const std::string &type)
Construct from string containing type (airport, seaport or heliport)
virtual bool pass(FGPositioned *pos) const override
Over-rideable filter method.
double _min_runway_length_ft
FGAirportDynamicsRef getDynamics() const
SGPath sceneryPath() const
unsigned int numRunways() const
std::string findAPTRunwayForNewName(const std::string &newIdent) const
flightgear::STAR * getSTARByIndex(unsigned int aIndex) const
FGRunwayRef findBestRunwayForHeading(double aHeading, struct FindBestRunwayForHeadingParams *parms=NULL) const
FGPavementList getLineFeatures() const
FGHelipadRef getHelipadByIndex(unsigned int aIndex) const
FGRunwayRef findBestRunwayForPos(const SGGeod &aPos) const
return the most likely target runway based on a position.
void validateILSData()
reload the ILS data from XML if required.
unsigned int numApproaches() const
unsigned int numSIDs() const
unsigned int numTaxiways() const
FGRunwayRef getRunwayByIndex(unsigned int aIndex) const
FGRunwayList getRunwaysWithoutReciprocals() const
Retrieve all runways at the airport, but excluding the reciprocal runways.
double getElevation() const
double getLatitude() const
double getLongitude() const
FGRunwayRef getRunwayByIdent(const std::string &aIdent) const
void addLineFeature(FGPavementRef linefeature)
static void sortBySize(FGPositionedList &)
Sort an FGPositionedList of airports by size (number of runways + length) this is meant to prioritise...
flightgear::Transition * selectSIDByEnrouteTransition(FGPositioned *enroute) const
flightgear::CommStationList commStationsOfType(FGPositioned::Type aTy) const
bool hasHardRunwayOfLengthFt(double aLengthFt) const
Useful predicate for FMS/GPS/NAV displays and similar - check if this airport has a hard-surfaced run...
FGPavementList getPavements() const
static FGAirportRef findClosest(const SGGeod &aPos, double aCuttofNm, Filter *filter=NULL)
Syntactic wrapper around FGPositioned::findClosest - find the closest match for filter,...
unsigned int numLineFeatures() const
flightgear::Approach * getApproachByIndex(unsigned int aIndex) const
static void clearAirportsCache()
unsigned int numHelipads() const
flightgear::Transition * selectSTARByTransition(const FGRunway *runway, const std::string &aIdent) const
static FGAirportRef findByIdent(const std::string &aIdent)
Helper to look up an FGAirport instance by unique ident.
flightgear::STAR * findSTARWithIdent(const std::string &aIdent) const
bool hasHelipadWithIdent(const std::string &aIdent) const
void addSID(flightgear::SID *aSid)
void addPavement(FGPavementRef pavement)
static char ** searchNamesAndIdents(const std::string &aFilter)
Specialised helper to implement the AirportList dialog.
virtual const std::string & name() const
Return the name of this positioned.
FGTaxiwayList getTaxiways() const
bool hasRunwayWithIdent(const std::string &aIdent) const
flightgear::ApproachList getApproaches(flightgear::ProcedureType type=flightgear::PROCEDURE_INVALID) const
flightgear::Transition * selectSTARByEnrouteTransition(FGPositioned *enroute) const
FGPavementList getBoundary() const
unsigned int numPavements() const
FGRunwayRef longestRunway() const
void addSTAR(flightgear::STAR *aStar)
FGTaxiwayRef getTaxiwayByIndex(unsigned int aIndex) const
FGRunwayList getRunways() const
Retrieve all runways at the airport.
flightgear::CommStationList commStations() const
flightgear::STARList getSTARs() const
void addApproach(flightgear::Approach *aApp)
SGGeod getTowerLocation() const
FGAirport(PositionedID aGuid, const std::string &id, const SGGeod &location, const std::string &name, bool has_metar, Type aType, SGPath sceneryPath=SGPath())
flightgear::Approach * findApproachWithIdent(const std::string &aIdent) const
void addBoundary(FGPavementRef boundary)
FGRunwayMap getRunwayMap() const
unsigned int numBoundary() const
flightgear::SID * findSIDWithIdent(const std::string &aIdent) const
FGHelipadRef getHelipadByIdent(const std::string &aIdent) const
unsigned int numSTARs() const
flightgear::SID * getSIDByIndex(unsigned int aIndex) const
FGRunwayRef getActiveRunwayForUsage() const
FGHelipadMap getHelipadMap() const
flightgear::Transition * selectSIDByTransition(const FGRunway *runway, const std::string &aIdent) const
FGGroundNetwork * groundNetwork() const
flightgear::SIDList getSIDs() const
static FGAirportRef getByIdent(const std::string &aIdent)
Helper to look up an FGAirport instance by unique ident.
Manage environment information.
Predicate class to support custom filtering of FGPositioned queries Default implementation of this pa...
FGPositioned(PositionedID aGuid, Type ty, const std::string &aIdent, const SGGeod &aPos)
friend class flightgear::NavDataCache
PositionedID guid() const
static std::vector< SGSharedPtr< T > > loadAllById(const PositionedIDVec &id_vec)
virtual const SGGeod & geod() const
static FGPositionedRef findFirstWithIdent(const std::string &aIdent, Filter *aFilter)
static SGSharedPtr< T > loadById(PositionedID id)
@ TOWER
an actual airport tower - not a radio comms facility!
double elevationM() const
const std::string & ident() const
static FGPositionedRef findClosest(const SGGeod &aPos, double aCutoffNm, Filter *aFilter=NULL)
Find the closest item to a position, which pass the specified filter A cutoff range in NM must be spe...
double headingDeg() const
Runway heading in degrees.
void updateThreshold(const SGGeod &newThreshold, double newHeading, double newDisplacedThreshold, double newStopway)
FGRunway * reciprocalRunway() const
static void load(FGRunwayPreference *p)
static bool findAirportData(const std::string &aICAO, const std::string &aFileName, SGPath &aPath)
Search the scenery for a file name of the form: I/C/A/ICAO.filename.xml and return the corresponding ...
static FGAirportDynamicsRef find(const std::string &icao)
Describe an approach procedure, including the missed approach segment.
PositionedID findILS(PositionedID airport, const std::string &runway, const std::string &navIdent)
Given an airport, and runway and ILS identifier, find the corresponding cache entry.
PositionedID airportItemWithIdent(PositionedID apt, FGPositioned::Type ty, const std::string &ident)
find the first match item of the specified type and ident, at an airport
FGPositionedRef loadById(PositionedID guid)
retrieve an FGPositioned from the cache.
static NavDataCache * instance()
char ** searchAirportNamesAndIdents(const std::string &aFilter)
Helper to implement the AirportSearch widget.
PositionedIDVec airportItemsOfType(PositionedID apt, FGPositioned::Type ty, FGPositioned::Type maxTy=FGPositioned::INVALID)
find all items of a specified type (or range of types) at an airport
static void loadAirportProcedures(const SGPath &aPath, FGAirport *aApt)
Encapsulate a transition segment.
FlightPlan.hxx - defines a full flight-plan object, including departure, cruise, arrival information ...
SGSharedPtr< FGPositioned > FGPositionedRef
std::vector< Approach * > ApproachList
std::vector< CommStationRef > CommStationList
std::vector< STAR * > STARList
std::vector< flightgear::SID * > SIDList
std::map< std::string, FGAirport * > AirportCache
SGSharedPtr< FGNavRecord > FGNavRecordRef
std::vector< PositionedID > PositionedIDVec
std::vector< FGPositionedRef > FGPositionedList
double fgGetDouble(const char *name, double defaultValue)
Get a double value for a property.
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.