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:
parent
20155df3f6
commit
01216e4c19
3 changed files with 99 additions and 18 deletions
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue