1
0
Fork 0

Add ability to override airport runway definitions by creating a rwy_override.xml file which allows procedures to be loaded for airports which have new runway numbering

This commit is contained in:
legoboyvdlp R 2021-08-02 16:31:54 +01:00 committed by James Turner
parent 20155df3f6
commit 01216e4c19
3 changed files with 99 additions and 18 deletions

View file

@ -21,9 +21,7 @@
// //
// $Id$ // $Id$
#ifdef HAVE_CONFIG_H #include <config.h>
# include <config.h>
#endif
#include "airport.hxx" #include "airport.hxx"
@ -592,6 +590,29 @@ void FGAirport::loadProcedures() const
RouteBase::loadAirportProcedures(path, const_cast<FGAirport*>(this)); RouteBase::loadAirportProcedures(path, const_cast<FGAirport*>(this));
} }
void FGAirport::loadRunwayRenames() const
{
if (mRunwayRenamesLoaded) {
return;
}
SGPath path;
if (!XMLLoader::findAirportData(ident(), "runway_rename", path)) {
// No rename for airport; ignore
mRunwayRenamesLoaded = true;
return;
}
try {
SGPropertyNode_ptr rootNode = new SGPropertyNode;
readProperties(path, rootNode);
const_cast<FGAirport*>(this)->parseRunwayRenameData(rootNode);
mRunwayRenamesLoaded = true;
} catch (sg_exception& e) {
SG_LOG(SG_NAVAID, SG_WARN, ident() << "loading runrway rename XML failed:" << e.getFormattedMessage());
}
}
void FGAirport::loadSceneryDefinitions() const void FGAirport::loadSceneryDefinitions() const
{ {
if (mThresholdDataLoaded) { if (mThresholdDataLoaded) {
@ -736,6 +757,38 @@ void FGAirport::readTowerData(SGPropertyNode* aRoot)
mTowerPosition = SGGeod::fromDegM(lon, lat, fieldElevationM + elevM); mTowerPosition = SGGeod::fromDegM(lon, lat, fieldElevationM + elevM);
} }
void FGAirport::parseRunwayRenameData(SGPropertyNode* aRoot)
{
SGPropertyNode* overrideNode = aRoot->getChild("runway-rename");
for (auto rnm : overrideNode->getChildren("runway")) {
const std::string oldIdent = rnm->getStringValue("old-ident");
const std::string newIdent = rnm->getStringValue("new-ident");
if (oldIdent.empty() || newIdent.empty()) {
SG_LOG(SG_NAVAID, SG_WARN, ident() << ": runway rename: Skipping bad runway rename entry");
continue;
}
if (!hasRunwayWithIdent(oldIdent)) {
SG_LOG(SG_NAVAID, SG_WARN, ident() << ": no old runway with ident:" << oldIdent);
continue;
}
_renamedRunways[newIdent] = oldIdent;
}
}
std::string FGAirport::findAPTRunwayForNewName(const std::string& newIdent) const
{
loadRunwayRenames();
auto it = _renamedRunways.find(newIdent);
if (it == _renamedRunways.end())
return {};
return it->second;
}
void FGAirport::validateILSData() void FGAirport::validateILSData()
{ {
if (mILSDataLoaded) { if (mILSDataLoaded) {

View file

@ -152,7 +152,9 @@ class FGAirport : public FGPositioned
*/ */
FGRunwayList getRunways() const; FGRunwayList getRunways() const;
/** std::string findAPTRunwayForNewName(const std::string& newIdent) const;
/**
* Useful predicate for FMS/GPS/NAV displays and similar - check if this * Useful predicate for FMS/GPS/NAV displays and similar - check if this
* aiport has a hard-surfaced runway of at least the specified length. * aiport has a hard-surfaced runway of at least the specified length.
*/ */
@ -320,6 +322,7 @@ class FGAirport : public FGPositioned
// helper to allow testing without needing a full Airports hierarchy // helper to allow testing without needing a full Airports hierarchy
// only for use by the test-suite, not available outside of it. // only for use by the test-suite, not available outside of it.
void testSuiteInjectGroundnetXML(const SGPath& path); void testSuiteInjectGroundnetXML(const SGPath& path);
private: private:
static flightgear::AirportCache airportCache; static flightgear::AirportCache airportCache;
@ -343,19 +346,26 @@ private:
void validateTowerData() const; void validateTowerData() const;
/** /**
* Helper to parse property data loaded from an ICAO.twr.xml file * Helpers to parse property data loaded from an ICAO.twr.xml file
*/ */
void readTowerData(SGPropertyNode* aRoot); void readTowerData(SGPropertyNode* aRoot);
/**
* Helpers to parse property data loaded from an ICAO.rwy_override.xml file
* or a ICAO.rwy_override.xml file
*/
void parseRunwayRenameData(SGPropertyNode* aRoot);
PositionedIDVec itemsOfType(FGPositioned::Type ty) const; PositionedIDVec itemsOfType(FGPositioned::Type ty) const;
std::string _name; std::string _name;
bool _has_metar; bool _has_metar = false;
void loadRunways() const; void loadRunways() const;
void loadHelipads() const; void loadHelipads() const;
void loadTaxiways() const; void loadTaxiways() const;
void loadProcedures() const; void loadProcedures() const;
void loadRunwayRenames() const;
mutable bool mTowerDataLoaded; mutable bool mTowerDataLoaded;
mutable bool mHasTower; mutable bool mHasTower;
@ -365,6 +375,7 @@ private:
mutable bool mHelipadsLoaded; mutable bool mHelipadsLoaded;
mutable bool mTaxiwaysLoaded; mutable bool mTaxiwaysLoaded;
mutable bool mProceduresLoaded; mutable bool mProceduresLoaded;
mutable bool mRunwayRenamesLoaded = false;
bool mIsClosed; bool mIsClosed;
mutable bool mThresholdDataLoaded; mutable bool mThresholdDataLoaded;
bool mILSDataLoaded; bool mILSDataLoaded;
@ -386,6 +397,10 @@ private:
std::vector<ApproachRef> mApproaches; std::vector<ApproachRef> mApproaches;
mutable std::unique_ptr<FGGroundNetwork> _groundNetwork; mutable std::unique_ptr<FGGroundNetwork> _groundNetwork;
using RunwayRenameMap = std::map<std::string, std::string>;
// map from new name (eg in Navigraph) to old name (in apt.dat)
RunwayRenameMap _renamedRunways;
}; };
// find basic airport location info from airport database // find basic airport location info from airport database

View file

@ -115,10 +115,15 @@ void NavdataVisitor::processRunways(ArrivalDeparture* aProc, const XMLAttributes
auto rwys = simgear::strutils::split_on_any_of(v, " ,"); auto rwys = simgear::strutils::split_on_any_of(v, " ,");
for (auto rwy : rwys) { for (auto rwy : rwys) {
if (!_airport->hasRunwayWithIdent(rwy)) { if (!_airport->hasRunwayWithIdent(rwy)) {
SG_LOG(SG_NAVAID, SG_DEV_WARN, "Procedure file " << _path << " references unknown airport runway:" << rwy); const auto renamed = _airport->findAPTRunwayForNewName(rwy);
continue; if (!renamed.empty()) {
rwy = renamed;
} else {
SG_LOG(SG_NAVAID, SG_DEV_WARN, "Procedure file " << _path << " references unknown airport runway:" << rwy);
continue;
}
} }
aProc->addRunway(_airport->getRunwayByIdent(rwy)); aProc->addRunway(_airport->getRunwayByIdent(rwy));
} }
} }
@ -241,15 +246,23 @@ Waypt* NavdataVisitor::buildWaypoint(RouteBase* owner)
wp = new BasicWaypt(pos, _wayptName, owner); wp = new BasicWaypt(pos, _wayptName, owner);
} else if (_wayptType == "Runway") { } else if (_wayptType == "Runway") {
string ident = _wayptName.substr(2); string ident = _wayptName.substr(2);
if (_airport->hasRunwayWithIdent(ident)) { if (!_airport->hasRunwayWithIdent(ident)) {
FGRunwayRef rwy = _airport->getRunwayByIdent(ident); const auto renamed = _airport->findAPTRunwayForNewName(ident);
wp = new RunwayWaypt(rwy, owner); if (renamed.empty()) {
} else { SG_LOG(SG_NAVAID, SG_DEV_WARN, "Missing runway " << ident << " reading " << _path);
SG_LOG(SG_NAVAID, SG_DEV_WARN, "Missing runway " << ident << " reading " << _path); SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
SGGeod pos(SGGeod::fromDeg(_longitude, _latitude)); // fall back to a basic WP
// fall back to a basic WP wp = new BasicWaypt(pos, _wayptName, owner);
wp = new BasicWaypt(pos, _wayptName, owner); ident.clear();
} } else {
ident = renamed;
}
}
if (!ident.empty()) {
FGRunwayRef rwy = _airport->getRunwayByIdent(ident);
wp = new RunwayWaypt(rwy, owner);
}
} else if (_wayptType == "Hold") { } else if (_wayptType == "Hold") {
SGGeod pos(SGGeod::fromDeg(_longitude, _latitude)); SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
Hold* h = new Hold(pos, _wayptName, owner); Hold* h = new Hold(pos, _wayptName, owner);