X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FNavaids%2Fnavrecord.cxx;h=041c12f1a663fc84aef85f6b021682eedb01c089;hb=97a251544371dbe9073a2c77df8b936176b916dc;hp=1e3800ae4aae01ff51ab840fed808085af0534bf;hpb=0603aba9ae0d9deb23bd9c00a5a3768b37f317d8;p=flightgear.git diff --git a/src/Navaids/navrecord.cxx b/src/Navaids/navrecord.cxx index 1e3800ae4..041c12f1a 100644 --- a/src/Navaids/navrecord.cxx +++ b/src/Navaids/navrecord.cxx @@ -27,14 +27,20 @@ #include #include +#include #include -#include #include +#include +#include +#include -#include "Navaids/navrecord.hxx" -#include "Airports/simple.hxx" -#include "Airports/runways.hxx" -#include "Main/fg_props.hxx" +#include +#include +#include +#include +#include + +#include
FGNavRecord::FGNavRecord(Type aTy, const std::string& aIdent, const std::string& aName, const SGGeod& aPos, @@ -44,6 +50,7 @@ FGNavRecord::FGNavRecord(Type aTy, const std::string& aIdent, range(aRange), multiuse(aMultiuse), _name(aName), + mRunway(NULL), serviceable(true), trans_ident(aIdent) { @@ -77,91 +84,28 @@ FGNavRecord::FGNavRecord(Type aTy, const std::string& aIdent, } -static FGPositioned::Type -mapRobinTypeToFGPType(int aTy) -{ - switch (aTy) { - // case 1: - case 2: return FGPositioned::NDB; - case 3: return FGPositioned::VOR; - case 4: return FGPositioned::LOC; - case 5: return FGPositioned::ILS; - case 6: return FGPositioned::GS; - case 7: return FGPositioned::OM; - case 8: return FGPositioned::MM; - case 9: return FGPositioned::IM; - case 12: - case 13: return FGPositioned::DME; - case 99: return FGPositioned::INVALID; // end-of-file code - default: - throw sg_range_exception("Got a nav.dat type we don't recognize", "FGNavRecord::createFromStream"); - } -} - -FGNavRecord* FGNavRecord::createFromStream(std::istream& aStream) -{ - int rawType; - aStream >> rawType; - if (aStream.eof()) { - return NULL; // happens with, eg, carrier_nav.dat - } - - Type type = mapRobinTypeToFGPType(rawType); - if (type == INVALID) return NULL; - - double lat, lon, elev_ft, multiuse; - int freq, range; - std::string name, ident; - aStream >> lat >> lon >> elev_ft >> freq >> range >> multiuse >> ident; - getline(aStream, name); - - // silently multiply adf frequencies by 100 so that adf - // vs. nav/loc frequency lookups can use the same code. - if (type == NDB) { - freq *= 100; - } - - // ensure marker beacons are anonymous, so they don't get added to the - // name index - if ((type >= OM) && (type <= IM)) { - ident.clear(); - } - - FGNavRecord* result = new FGNavRecord(type, ident, - simgear::strutils::strip(name), SGGeod::fromDegFt(lon, lat, elev_ft), - freq, range, multiuse); - - return result; -} - void FGNavRecord::initAirportRelation() { - if ((type() < ILS) || (type() > IM)) { + if ((type() < ILS) || (type() > GS)) { return; // not airport-located } - vector parts = simgear::strutils::split(_name); - if (parts.size() < 2) { - SG_LOG(SG_GENERAL, SG_WARN, "navaid has malformed name:" << _name); - return; - } - - const FGAirport* apt = fgFindAirportID(parts[0]); - - if (!apt) { - SG_LOG(SG_GENERAL, SG_WARN, "navaid " << _name << " associated with bogus airport ID:" << parts[0]); + mRunway = getRunwayFromName(_name); + if (!mRunway) { return; } - runway = apt->getRunwayByIdent(parts[1]); - if (!runway) { - SG_LOG(SG_GENERAL, SG_WARN, "navaid " << _name << " associated with bogus runway ID:" << parts[1]); - return; + if (type() != GS) { + readAirportSceneryData(); } - - // fudge elevation to the field elevation if it's not specified + + // fudge elevation to the runway elevation if it's not specified if (fabs(elevation()) < 0.01) { - mPosition.setElevationFt(apt->getElevation()); + mPosition.setElevationFt(mRunway->elevation()); + } + + if (type() == ILS || type() == LOC) { + mRunway->setILS(this); } // align localizers with their runway @@ -172,36 +116,101 @@ void FGNavRecord::initAirportRelation() double threshold = fgGetDouble( "/sim/navdb/localizers/auto-align-threshold-deg", 5.0 ); - alignLocaliserWithRunway(runway, threshold); + alignLocaliserWithRunway(threshold); + } +} + +void FGNavRecord::readAirportSceneryData() +{ + // allow users to disable the scenery data in the short-term + // longer term, this option can probably disappear + if (!fgGetBool("/sim/use-scenery-airport-data")) { + return; + } + + SGPath path; + SGPropertyNode_ptr rootNode = new SGPropertyNode; + if (!XMLLoader::findAirportData(mRunway->airport()->ident(), "ils", path)) { + return; } + + readProperties(path.str(), rootNode); + SGPropertyNode* runwayNode, *ilsNode; + for (int i=0; (runwayNode = rootNode->getChild("runway", i)) != NULL; ++i) { + for (int j=0; (ilsNode = runwayNode->getChild("ils", j)) != NULL; ++j) { + // must match on both nav-ident and runway ident, to support the following: + // - runways with multiple distinct ILS installations (KEWD, for example) + // - runways where both ends share the same nav ident (LFAT, for example) + if ((ilsNode->getStringValue("nav-id") == ident()) && + (ilsNode->getStringValue("rwy") == mRunway->ident())) { + processSceneryILS(ilsNode); + return; + } + } // of ILS iteration + } // of runway iteration +} + +void FGNavRecord::processSceneryILS(SGPropertyNode* aILSNode) +{ + double hdgDeg = aILSNode->getDoubleValue("hdg-deg"), + lon = aILSNode->getDoubleValue("lon"), + lat = aILSNode->getDoubleValue("lat"), + elevM = aILSNode->getDoubleValue("elev-m"); + + mPosition = SGGeod::fromDegM(lon, lat, elevM); + multiuse = hdgDeg; } -void FGNavRecord::alignLocaliserWithRunway(FGRunway* aRunway, double aThreshold) +void FGNavRecord::alignLocaliserWithRunway(double aThreshold) { // find the distance from the threshold to the localizer - SGGeod runwayThreshold(aRunway->threshold()); - double dist, az1, az2; - SGGeodesy::inverse(mPosition, runwayThreshold, az1, az2, dist); + double dist = SGGeodesy::distanceM(mPosition, mRunway->threshold()); // back project that distance along the runway center line - SGGeod newPos = aRunway->pointOnCenterline(dist); - - double hdg_diff = get_multiuse() - aRunway->headingDeg(); + SGGeod newPos = mRunway->pointOnCenterline(dist); - // clamp to [-180.0 ... 180.0] - if ( hdg_diff < -180.0 ) { - hdg_diff += 360.0; - } else if ( hdg_diff > 180.0 ) { - hdg_diff -= 360.0; - } + double hdg_diff = get_multiuse() - mRunway->headingDeg(); + SG_NORMALIZE_RANGE(hdg_diff, -180.0, 180.0); if ( fabs(hdg_diff) <= aThreshold ) { - mPosition = newPos; - set_multiuse( aRunway->headingDeg() ); + mPosition = SGGeod::fromGeodFt(newPos, mPosition.getElevationFt()); + set_multiuse( mRunway->headingDeg() ); } else { - SG_LOG(SG_GENERAL, SG_WARN, "localizer:" << ident() << ", aligning with runway " - << aRunway->ident() << " exceeded heading threshold"); + SG_LOG(SG_GENERAL, SG_DEBUG, "localizer:" << ident() << ", aligning with runway " + << mRunway->ident() << " exceeded heading threshold"); + } +} + +double FGNavRecord::localizerWidth() const +{ + if (!mRunway) { + return 6.0; + } + + SGVec3d thresholdCart(SGVec3d::fromGeod(mRunway->threshold())); + double axisLength = dist(cart(), thresholdCart); + double landingLength = dist(thresholdCart, SGVec3d::fromGeod(mRunway->end())); + +// Reference: http://dcaa.slv.dk:8000/icaodocs/ +// ICAO standard width at threshold is 210 m = 689 feet = approx 700 feet. +// ICAO 3.1.1 half course = DDM = 0.0775 +// ICAO 3.1.3.7.1 Sensitivity 0.00145 DDM/m at threshold +// implies peg-to-peg of 214 m ... we will stick with 210. +// ICAO 3.1.3.7.1 "Course sector angle shall not exceed 6 degrees." + +// Very short runway: less than 1200 m (4000 ft) landing length: + if (landingLength < 1200.0) { +// ICAO fudges localizer sensitivity for very short runways. +// This produces a non-monotonic sensitivity-versus length relation. + axisLength += 1050.0; } + +// Example: very short: San Diego KMYF (Montgomery Field) ILS RWY 28R +// Example: short: Tom's River KMJX (Robert J. Miller) ILS RWY 6 +// Example: very long: Denver KDEN (Denver) ILS RWY 16R + double raw_width = 210.0 / axisLength * SGD_RADIANS_TO_DEGREES; + return raw_width < 6.0? raw_width : 6.0; + } FGTACANRecord::FGTACANRecord(void) :