X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FNavaids%2Fnavdb.cxx;h=99453022a826c45185b2b48a032939adffd3ca1e;hb=c3c0f68f76c031adcf610fdd3dbeee59bc33d553;hp=92253f357eb7f63381f91430d3a1049581f915da;hpb=a08f4c084b7d8bd21ac446aa536bf3d0ed0f57c0;p=flightgear.git diff --git a/src/Navaids/navdb.cxx b/src/Navaids/navdb.cxx index 92253f357..99453022a 100644 --- a/src/Navaids/navdb.cxx +++ b/src/Navaids/navdb.cxx @@ -2,7 +2,7 @@ // // Written by Curtis Olson, started May 2004. // -// Copyright (C) 2004 Curtis L. Olson - curt@flightgear.org +// Copyright (C) 2004 Curtis L. Olson - http://www.flightgear.org/~curt // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as @@ -16,193 +16,299 @@ // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // $Id$ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif -#include - -#include STL_STRING +#include "navdb.hxx" +#include #include +#include +#include +#include +#include +#include +#include +#include -#include +#include "navrecord.hxx" +#include "navlist.hxx" #include
+#include +#include +#include +#include +#include
+#include -#include "navrecord.hxx" -#include "navdb.hxx" +using std::string; +using std::vector; + +static FGPositioned::Type +mapRobinTypeToFGPType(int aTy) +{ + switch (aTy) { + // case 1: + case 2: return FGPositioned::NDB; + case 3: return FGPositioned::VOR; + 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 + default: + throw sg_range_exception("Got a nav.dat type we don't recognize", "FGNavRecord::createFromStream"); + } +} -SG_USING_STD( string ); +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; + } +} -// load and initialize the navigational databases -bool fgNavDBInit( FGNavList *navlist, FGNavList *loclist, FGNavList *gslist, - FGNavList *dmelist, FGNavList *mkrlist ) + +namespace flightgear { - SG_LOG(SG_GENERAL, SG_INFO, "Loading Navaid Databases"); - // SG_LOG(SG_GENERAL, SG_INFO, " VOR/NDB"); - // SGPath p_nav( globals->get_fg_root() ); - // p_nav.append( "Navaids/default.nav" ); - // navlist->init( p_nav ); - // SG_LOG(SG_GENERAL, SG_INFO, " ILS and Marker Beacons"); - // beacons->init(); - // SGPath p_ils( globals->get_fg_root() ); - // p_ils.append( "Navaids/default.ils" ); - // ilslist->init( p_ils ); +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 0; // happens with, eg, carrier_nav.dat + } + + 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); + + SGGeod pos(SGGeod::fromDegFt(lon, lat, elev_ft)); + name = simgear::strutils::strip(name); + +// 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); + } + if (type == FGPositioned::INVALID) { + 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); + } - SGPath path( globals->get_fg_root() ); - path.append( "Navaids/nav.dat" ); + 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; + } + + 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 navDBInit(const SGPath& path) +{ 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; - -#ifdef __MWERKS__ - char c = 0; - while ( in.get(c) && c != '\0' ) { - in.putback(c); -#else - while ( ! in.eof() ) { -#endif - - FGNavRecord *r = new FGNavRecord; - in >> (*r); - if ( r->get_type() > 95 ) { - break; - } - - /* cout << "id = " << n.get_ident() << endl; - cout << " type = " << n.get_type() << endl; - cout << " lon = " << n.get_lon() << endl; - cout << " lat = " << n.get_lat() << endl; - cout << " elev = " << n.get_elev() << endl; - cout << " freq = " << n.get_freq() << endl; - cout << " range = " << n.get_range() << endl << endl; */ - - if ( r->get_type() == 2 || r->get_type() == 3 ) { - // NDB=2, VOR=3 - navlist->add( r ); - } else if ( r->get_type() == 4 || r->get_type() == 5 ) { - // ILS=4, LOC(only)=5 - loclist->add( r ); - } else if ( r->get_type() == 6 ) { - // GS=6 - gslist->add( r ); - } else if ( r->get_type() == 7 || r->get_type() == 8 - || r->get_type() == 9 ) - { - // Marker Beacon = 7,8,9 - mkrlist->add( r ); - } else if ( r->get_type() == 12 ) { - // DME=12 - dmelist->add( r ); - } - - in >> skipcomment; + while (!in.eof()) { + readNavFromStream(in); + in >> skipcomment; + } // of stream data loop + + 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_NAVAID, SG_ALERT, "Cannot open file: " << path.str() ); + return false; } + + while ( ! incarrier.eof() ) { + // force the type to be MOBILE_TACAN + readNavFromStream(incarrier, FGPositioned::MOBILE_TACAN); + } // end while - // cout << "min freq = " << min << endl; - // cout << "max freq = " << max << endl; - - return true; + return true; } - - -// Given a localizer record and it's corresponding runway record, -// adjust the localizer position so it is in perfect alignment with -// the runway. -static void update_loc_position( FGNavRecord *loc, FGRunway *rwy, - double threshold ) + +bool loadTacan(const SGPath& path, FGTACANList *channellist) { - double hdg = rwy->heading; - hdg += 180.0; - if ( hdg > 360.0 ) { - hdg -= 360.0; - } - - // calculate runway threshold point - double thresh_lat, thresh_lon, return_az; - geo_direct_wgs_84 ( 0.0, rwy->lat, rwy->lon, hdg, - rwy->length/2.0 * SG_FEET_TO_METER, - &thresh_lat, &thresh_lon, &return_az ); - // cout << "Threshold = " << thresh_lat << "," << thresh_lon << endl; - - // calculate distance from threshold to localizer - double az1, az2, dist_m; - geo_inverse_wgs_84( 0.0, loc->get_lat(), loc->get_lon(), - thresh_lat, thresh_lon, - &az1, &az2, &dist_m ); - // cout << "Distance = " << dist_m << endl; - - // back project that distance along the runway center line - double nloc_lat, nloc_lon; - geo_direct_wgs_84 ( 0.0, thresh_lat, thresh_lon, hdg + 180.0, - dist_m, &nloc_lat, &nloc_lon, &return_az ); - // printf("New localizer = %.6f %.6f\n", nloc_lat, nloc_lon ); - - // sanity check, how far have we moved the localizer? - geo_inverse_wgs_84( 0.0, loc->get_lat(), loc->get_lon(), - nloc_lat, nloc_lon, - &az1, &az2, &dist_m ); - // cout << "Distance moved = " << dist_m << endl; - - // cout << "orig heading = " << loc->get_multiuse() << endl; - // cout << "new heading = " << rwy->heading << endl; - - double hdg_diff = loc->get_multiuse() - rwy->heading; - - // 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; - } - - if ( fabs(hdg_diff) <= threshold ) { - loc->set_lat( nloc_lat ); - loc->set_lon( nloc_lon ); - loc->set_multiuse( rwy->heading ); + SG_LOG( SG_NAVAID, SG_INFO, "opening file: " << path.str() ); + sg_gzifstream inchannel( path.str() ); + + if ( !inchannel.is_open() ) { + SG_LOG( SG_NAVAID, SG_ALERT, "Cannot open file: " << path.str() ); + return false; } -} - + + // skip first line + inchannel >> skipeol; + while ( ! inchannel.eof() ) { + FGTACANRecord *r = new FGTACANRecord; + inchannel >> (*r); + channellist->add ( r ); + + } // end while -// This routines traverses the localizer list and attempts to match -// each entry with it's corresponding runway. When it is successful, -// it then "moves" the localizer and updates it's heading so it -// *perfectly* aligns with the runway, but is still the same distance -// from the runway threshold. -void fgNavDBAlignLOCwithRunway( FGRunwayList *runways, FGNavList *loclist, - double threshold ) { - nav_map_type navmap = loclist->get_navaids(); - - nav_map_iterator freq = navmap.begin(); - while ( freq != navmap.end() ) { - nav_list_type locs = freq->second; - nav_list_iterator loc = locs.begin(); - while ( loc != locs.end() ) { - string name = (*loc)->get_name(); - string::size_type pos1 = name.find(" "); - string id = name.substr(0, pos1); - name = name.substr(pos1+1); - string::size_type pos2 = name.find(" "); - string rwy = name.substr(0, pos2); - - FGRunway r; - if ( runways->search(id, rwy, &r) ) { - update_loc_position( (*loc), &r, threshold ); - } - ++loc; - } - ++freq; - } + return true; } + +} // of namespace flightgear