X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FNavaids%2Fnavdb.cxx;h=99453022a826c45185b2b48a032939adffd3ca1e;hb=c3c0f68f76c031adcf610fdd3dbeee59bc33d553;hp=385e1db22510cc2e29ede392965fe15ed3e8dae3;hpb=8d3e1b06be9ad55b17b90a9ee4c38b97cb362913;p=flightgear.git diff --git a/src/Navaids/navdb.cxx b/src/Navaids/navdb.cxx index 385e1db22..99453022a 100644 --- a/src/Navaids/navdb.cxx +++ b/src/Navaids/navdb.cxx @@ -24,10 +24,9 @@ # include "config.h" #endif -#include - -#include +#include "navdb.hxx" +#include #include #include #include @@ -35,24 +34,21 @@ #include #include #include +#include #include "navrecord.hxx" #include "navlist.hxx" -#include "navdb.hxx" #include
#include -#include +#include #include #include #include
+#include using std::string; using std::vector; -typedef std::map AirportPropertyMap; - -static AirportPropertyMap static_airportIlsData; - static FGPositioned::Type mapRobinTypeToFGPType(int aTy) { @@ -63,6 +59,9 @@ mapRobinTypeToFGPType(int aTy) case 4: return FGPositioned::ILS; case 5: return FGPositioned::LOC; 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 @@ -71,12 +70,72 @@ mapRobinTypeToFGPType(int aTy) } } -static FGNavRecord* createNavFromStream(std::istream& aStream) +static bool autoAlignLocalizers = false; +static double autoAlignThreshold = 0.0; + +/** + * Given a runway, and proposed localizer data (ident, positioned and heading), + * precisely align the localizer with the actual runway heading, providing the + * difference between the localizer course and runway heading is less than a + * threshold. (To allow for localizers such as Kai-Tak requiring a turn on final). + * + * The positioned and heading argument are modified if changes are made. + */ +void alignLocaliserWithRunway(FGRunway* rwy, const string& ident, SGGeod& pos, double& heading) { + assert(rwy); + // find the distance from the threshold to the localizer + double dist = SGGeodesy::distanceM(pos, rwy->threshold()); + + // back project that distance along the runway center line + SGGeod newPos = rwy->pointOnCenterline(dist); + + double hdg_diff = heading - rwy->headingDeg(); + SG_NORMALIZE_RANGE(hdg_diff, -180.0, 180.0); + + if ( fabs(hdg_diff) <= autoAlignThreshold ) { + pos = SGGeod::fromGeodFt(newPos, pos.getElevationFt()); + heading = rwy->headingDeg(); + } else { + SG_LOG(SG_NAVAID, SG_DEBUG, "localizer:" << ident << ", aligning with runway " + << rwy->ident() << " exceeded heading threshold"); + } +} + +static double defaultNavRange(const string& ident, FGPositioned::Type type) +{ + // Ranges are included with the latest data format, no need to + // assign our own defaults, unless the range is not set for some + // reason. + SG_LOG(SG_NAVAID, SG_DEBUG, "navaid " << ident << " has no range set, using defaults"); + switch (type) { + case FGPositioned::NDB: + case FGPositioned::VOR: + return FG_NAV_DEFAULT_RANGE; + + case FGPositioned::LOC: + case FGPositioned::ILS: + case FGPositioned::GS: + return FG_LOC_DEFAULT_RANGE; + + case FGPositioned::DME: return FG_DME_DEFAULT_RANGE; + default: return FG_LOC_DEFAULT_RANGE; + } +} + + +namespace flightgear +{ + +static PositionedID readNavFromStream(std::istream& aStream, + FGPositioned::Type type = FGPositioned::INVALID) +{ + NavDataCache* cache = NavDataCache::instance(); + int rawType; aStream >> rawType; if (aStream.eof() || (rawType == 99)) { - return NULL; // happens with, eg, carrier_nav.dat + return 0; // happens with, eg, carrier_nav.dat } double lat, lon, elev_ft, multiuse; @@ -88,133 +147,156 @@ static FGNavRecord* createNavFromStream(std::istream& aStream) SGGeod pos(SGGeod::fromDegFt(lon, lat, elev_ft)); name = simgear::strutils::strip(name); - if ((rawType >= 7) && (rawType <= 9)) { - // marker beacons use a different run-time class now - FGMarkerBeaconRecord::create(rawType, name, pos); - return NULL; // not a nav-record, but that's okay +// the type can be forced by our caller, but normally we use th value +// supplied in the .dat file + if (type == FGPositioned::INVALID) { + type = mapRobinTypeToFGPType(rawType); } - - FGPositioned::Type type = mapRobinTypeToFGPType(rawType); if (type == FGPositioned::INVALID) { - return NULL; + return 0; } + + if ((type >= FGPositioned::OM) && (type <= FGPositioned::IM)) { + AirportRunwayPair arp(cache->findAirportRunway(name)); + if (arp.second && (elev_ft < 0.01)) { + // snap to runway elevation + FGPositioned* runway = cache->loadById(arp.second); + assert(runway); + pos.setElevationFt(runway->geod().getElevationFt()); + } + + return cache->insertNavaid(type, string(), name, pos, 0, 0, 0, + arp.first, arp.second); + } + + if (range < 0.01) { + range = defaultNavRange(ident, type); + } + + AirportRunwayPair arp; + FGRunway* runway = NULL; + PositionedID navaid_dme = 0; + + if (type == FGPositioned::DME) { + FGPositioned::TypeFilter f(FGPositioned::INVALID); + if ( name.find("VOR-DME") != std::string::npos ) { + f.addType(FGPositioned::VOR); + } else if ( name.find("DME-ILS") != std::string::npos ) { + f.addType(FGPositioned::ILS); + f.addType(FGPositioned::LOC); + } else if ( name.find("VORTAC") != std::string::npos ) { + f.addType(FGPositioned::VOR); + } else if ( name.find("NDB-DME") != std::string::npos ) { + f.addType(FGPositioned::NDB); + } else if ( name.find("TACAN") != std::string::npos ) { + f.addType(FGPositioned::VOR); + } + + if (f.maxType() > 0) { + FGPositionedRef ref = FGPositioned::findClosestWithIdent(ident, pos, &f); + if (ref.valid()) { + string_list dme_part = simgear::strutils::split(name , 0 ,1); + string_list navaid_part = simgear::strutils::split(ref.get()->name(), 0 ,1); + + if ( simgear::strutils::uppercase(navaid_part[0]) == simgear::strutils::uppercase(dme_part[0]) ) { + navaid_dme = ref.get()->guid(); + } + } + } + } + + if ((type >= FGPositioned::ILS) && (type <= FGPositioned::GS)) { + arp = cache->findAirportRunway(name); + if (arp.second) { + runway = FGPositioned::loadById(arp.second); + assert(runway); +#if 0 + // code is disabled since it's causing some problems, see + // http://code.google.com/p/flightgear-bugs/issues/detail?id=926 + if (elev_ft < 0.01) { + // snap to runway elevation + pos.setElevationFt(runway->geod().getElevationFt()); + } +#endif + } // of found runway in the DB + } // of type is runway-related + bool isLoc = (type == FGPositioned::ILS) || (type == FGPositioned::LOC); + if (runway && autoAlignLocalizers && isLoc) { + alignLocaliserWithRunway(runway, ident, pos, multiuse); + } + // silently multiply adf frequencies by 100 so that adf // vs. nav/loc frequency lookups can use the same code. if (type == FGPositioned::NDB) { freq *= 100; } - return new FGNavRecord(type, ident, name, pos, - freq, range, multiuse); -} + PositionedID r = cache->insertNavaid(type, ident, name, pos, freq, range, multiuse, + arp.first, arp.second); + + if (isLoc) { + cache->setRunwayILS(arp.second, r); + } + if (navaid_dme) { + cache->setNavaidColocated(navaid_dme, r); + } + + return r; +} + // load and initialize the navigational databases -bool fgNavDBInit( FGNavList *navlist, FGNavList *loclist, FGNavList *gslist, - FGNavList *dmelist, - FGNavList *tacanlist, FGNavList *carrierlist, - FGTACANList *channellist) +bool navDBInit(const SGPath& path) { - SG_LOG(SG_GENERAL, SG_INFO, "Loading Navaid Databases"); - - SGPath path( globals->get_fg_root() ); - path.append( "Navaids/nav.dat" ); - sg_gzifstream in( path.str() ); if ( !in.is_open() ) { - SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << path.str() ); - exit(-1); + SG_LOG( SG_NAVAID, SG_ALERT, "Cannot open file: " << path.str() ); + return false; } + + autoAlignLocalizers = fgGetBool("/sim/navdb/localizers/auto-align", true); + autoAlignThreshold = fgGetDouble( "/sim/navdb/localizers/auto-align-threshold-deg", 5.0 ); // skip first two lines in >> skipeol; in >> skipeol; while (!in.eof()) { - FGNavRecord *r = createNavFromStream(in); - if (!r) { - continue; - } - - switch (r->type()) { - case FGPositioned::NDB: - case FGPositioned::VOR: - navlist->add(r); - break; - - case FGPositioned::ILS: - case FGPositioned::LOC: - loclist->add(r); - break; - - case FGPositioned::GS: - gslist->add(r); - break; - - case FGPositioned::DME: - { - dmelist->add(r); - string::size_type loc1= r->name().find( "TACAN", 0 ); - string::size_type loc2 = r->name().find( "VORTAC", 0 ); - - if( loc1 != string::npos || loc2 != string::npos) { - tacanlist->add(r); - } - - break; - } - - default: - throw sg_range_exception("got unsupported NavRecord type", "fgNavDBInit"); - } - + readNavFromStream(in); in >> skipcomment; } // of stream data loop - -// load the carrier navaids file - - string file, name; - path = globals->get_fg_root() ; - path.append( "Navaids/carrier_nav.dat" ); - - file = path.str(); - SG_LOG( SG_GENERAL, SG_INFO, "opening file: " << path.str() ); - + + return true; +} + + +bool loadCarrierNav(const SGPath& path) +{ + SG_LOG( SG_NAVAID, SG_INFO, "opening file: " << path.str() ); sg_gzifstream incarrier( path.str() ); if ( !incarrier.is_open() ) { - SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << path.str() ); - exit(-1); + SG_LOG( SG_NAVAID, SG_ALERT, "Cannot open file: " << path.str() ); + return false; } - // skip first two lines - //incarrier >> skipeol; - //incarrier >> skipeol; - while ( ! incarrier.eof() ) { - FGNavRecord *r = createNavFromStream(incarrier); - if (!r) { - continue; - } - - carrierlist->add (r); + // force the type to be MOBILE_TACAN + readNavFromStream(incarrier, FGPositioned::MOBILE_TACAN); } // end while -// end loading the carrier navaids file - -// load the channel/freqency file - string channel, freq; - path=""; - path = globals->get_fg_root(); - path.append( "Navaids/TACAN_freq.dat" ); - - SG_LOG( SG_GENERAL, SG_INFO, "opening file: " << path.str() ); - + return true; +} + +bool loadTacan(const SGPath& path, FGTACANList *channellist) +{ + SG_LOG( SG_NAVAID, SG_INFO, "opening file: " << path.str() ); sg_gzifstream inchannel( path.str() ); if ( !inchannel.is_open() ) { - SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << path.str() ); - exit(-1); + SG_LOG( SG_NAVAID, SG_ALERT, "Cannot open file: " << path.str() ); + return false; } // skip first line @@ -223,85 +305,10 @@ bool fgNavDBInit( FGNavList *navlist, FGNavList *loclist, FGNavList *gslist, FGTACANRecord *r = new FGTACANRecord; inchannel >> (*r); channellist->add ( r ); - //cout << "channel = " << r->get_channel() ; - //cout << " freq = " << r->get_freq() << endl; } // end while - - // end ReadChanFile - - - // flush all the parsed ils.xml data, we don't need it anymore, - // since it's been meregd into the FGNavRecords - static_airportIlsData.clear(); - return true; } - -SGPropertyNode* ilsDataForRunwayAndNavaid(FGRunway* aRunway, const std::string& aNavIdent) -{ - if (!aRunway) { - return NULL; - } - - FGAirport* apt = aRunway->airport(); -// find (or load) the airprot ILS data - AirportPropertyMap::iterator it = static_airportIlsData.find(apt); - if (it == static_airportIlsData.end()) { - SGPath path; - if (!XMLLoader::findAirportData(apt->ident(), "ils", path)) { - // no ils.xml file for this airpot, insert a NULL entry so we don't - // check again - static_airportIlsData.insert(it, std::make_pair(apt, SGPropertyNode_ptr())); - return NULL; - } - - SGPropertyNode_ptr rootNode = new SGPropertyNode; - readProperties(path.str(), rootNode); - it = static_airportIlsData.insert(it, std::make_pair(apt, rootNode)); - } // of ils.xml file not loaded - - if (!it->second) { - return NULL; - } - -// find the entry matching the runway - SGPropertyNode* runwayNode, *ilsNode; - for (int i=0; (runwayNode = it->second->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") == aNavIdent) && - (ilsNode->getStringValue("rwy") == aRunway->ident())) - { - return ilsNode; - } - } // of ILS iteration - } // of runway iteration - - return NULL; -} - -FGRunway* getRunwayFromName(const std::string& aName) -{ - vector parts = simgear::strutils::split(aName); - if (parts.size() < 2) { - SG_LOG(SG_GENERAL, SG_WARN, "getRunwayFromName: malformed name:" << aName); - return NULL; - } - - const FGAirport* apt = fgFindAirportID(parts[0]); - if (!apt) { - SG_LOG(SG_GENERAL, SG_DEBUG, "navaid " << aName << " associated with bogus airport ID:" << parts[0]); - return NULL; - } - if (!apt->hasRunwayWithIdent(parts[1])) { - SG_LOG(SG_GENERAL, SG_DEBUG, "navaid " << aName << " associated with bogus runway ID:" << parts[1]); - return NULL; - } - - return apt->getRunwayByIdent(parts[1]); -} +} // of namespace flightgear