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$
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <config.h>
#include "airport.hxx"
@ -592,6 +590,29 @@ void FGAirport::loadProcedures() const
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
{
if (mThresholdDataLoaded) {
@ -736,6 +757,38 @@ void FGAirport::readTowerData(SGPropertyNode* aRoot)
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()
{
if (mILSDataLoaded) {

View file

@ -152,7 +152,9 @@ class FGAirport : public FGPositioned
*/
FGRunwayList getRunways() const;
/**
std::string findAPTRunwayForNewName(const std::string& newIdent) const;
/**
* Useful predicate for FMS/GPS/NAV displays and similar - check if this
* 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
// only for use by the test-suite, not available outside of it.
void testSuiteInjectGroundnetXML(const SGPath& path);
private:
static flightgear::AirportCache airportCache;
@ -343,19 +346,26 @@ private:
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);
/**
* 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;
std::string _name;
bool _has_metar;
bool _has_metar = false;
void loadRunways() const;
void loadHelipads() const;
void loadTaxiways() const;
void loadProcedures() const;
void loadRunwayRenames() const;
mutable bool mTowerDataLoaded;
mutable bool mHasTower;
@ -365,6 +375,7 @@ private:
mutable bool mHelipadsLoaded;
mutable bool mTaxiwaysLoaded;
mutable bool mProceduresLoaded;
mutable bool mRunwayRenamesLoaded = false;
bool mIsClosed;
mutable bool mThresholdDataLoaded;
bool mILSDataLoaded;
@ -386,6 +397,10 @@ private:
std::vector<ApproachRef> mApproaches;
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

View file

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