From c6d5b6ebdb34954ca9fc43bb49ace4b6d3b47754 Mon Sep 17 00:00:00 2001 From: Torsten Dreyer Date: Mon, 18 Jul 2011 11:09:43 +0200 Subject: [PATCH] Partial fix for #228: ambiguous navaid-names This fixes at least the startup process. If an ambigous fix name was presented with --vor=ID or --ndb=ID present a list of matching records along with frequency and position in the console to give the user the chance to pick the correct one by adding the frequency with --vor-frequency=nnn.nn It does not yes solve the issue when the user relocates using the GUI dialog. This requires some GUI and Nasal hacking along with a new Nasal helper function "navaidinfo". --- src/Main/fg_init.cxx | 46 +++++++++++++++++++++++--------- src/Main/options.cxx | 4 ++- src/Navaids/navlist.cxx | 59 ++++++++++++++++++++++++++++++++--------- src/Navaids/navlist.hxx | 14 +++++++--- 4 files changed, 93 insertions(+), 30 deletions(-) diff --git a/src/Main/fg_init.cxx b/src/Main/fg_init.cxx index 9fd101b65..cc62744cd 100644 --- a/src/Main/fg_init.cxx +++ b/src/Main/fg_init.cxx @@ -59,6 +59,7 @@ #include #include #include +#include #include #include @@ -996,18 +997,37 @@ static void fgSetDistOrAltFromGlideSlope() { // Set current_options lon/lat given an airport id and heading (degrees) -static bool fgSetPosFromNAV( const string& id, const double& freq ) { - FGNavRecord *nav - = globals->get_navlist()->findByIdentAndFreq( id.c_str(), freq ); +static bool fgSetPosFromNAV( const string& id, const double& freq, FGPositioned::Type type ) { - if (!nav) { - SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate NAV = " - << id << ":" << freq ); - return false; - } - - fgApplyStartOffset(nav->geod(), fgGetDouble("/sim/presets/heading-deg")); - return true; + const nav_list_type navlist + = globals->get_navlist()->findByIdentAndFreq( id.c_str(), freq, type ); + + if (navlist.size() == 0 ) { + SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate NAV = " + << id << ":" << freq ); + return false; + } + + if( navlist.size() > 1 ) { + ostringstream buf; + buf << "Ambigous NAV-ID: '" << id << "'. Specify id and frequency. Available stations:" << endl; + for( nav_list_type::const_iterator it = navlist.begin(); it != navlist.end(); ++it ) { + // NDB stored in kHz, VOR stored in MHz * 100 :-P + double factor = (*it)->type() == FGPositioned::NDB ? 1.0 : 1/100.0; + string unit = (*it)->type() == FGPositioned::NDB ? "kHz" : "MHz"; + buf << (*it)->ident() << " " + << setprecision(5) << (double)((*it)->get_freq() * factor) << " " + << (*it)->get_lat() << "/" << (*it)->get_lon() + << endl; + } + + SG_LOG( SG_GENERAL, SG_ALERT, buf.str() ); + return false; + } + + FGNavRecord *nav = navlist[0]; + fgApplyStartOffset(nav->geod(), fgGetDouble("/sim/presets/heading-deg")); + return true; } // Set current_options lon/lat given an aircraft carrier id @@ -1219,14 +1239,14 @@ bool fgInitPosition() { if ( !set_pos && !vor.empty() ) { // a VOR is requested - if ( fgSetPosFromNAV( vor, vor_freq ) ) { + if ( fgSetPosFromNAV( vor, vor_freq, FGPositioned::VOR ) ) { set_pos = true; } } if ( !set_pos && !ndb.empty() ) { // an NDB is requested - if ( fgSetPosFromNAV( ndb, ndb_freq ) ) { + if ( fgSetPosFromNAV( ndb, ndb_freq, FGPositioned::NDB ) ) { set_pos = true; } } diff --git a/src/Main/options.cxx b/src/Main/options.cxx index 9e1b5c55b..00ace6e4b 100644 --- a/src/Main/options.cxx +++ b/src/Main/options.cxx @@ -59,7 +59,6 @@ #include
#include -#include #include using std::string; @@ -70,6 +69,7 @@ using std::endl; #if defined( HAVE_VERSION_H ) && HAVE_VERSION_H # include +# include #else # include #endif @@ -1341,7 +1341,9 @@ struct OptionDesc { {"airport", true, OPTION_STRING, "/sim/presets/airport-id", false, "", 0 }, {"runway", true, OPTION_FUNC, "", false, "", fgOptRunway }, {"vor", true, OPTION_FUNC, "", false, "", fgOptVOR }, + {"vor-frequency", true, OPTION_DOUBLE, "/sim/presets/vor-freq", false, "", fgOptVOR }, {"ndb", true, OPTION_FUNC, "", false, "", fgOptNDB }, + {"ndb-frequency", true, OPTION_DOUBLE, "/sim/presets/ndb-freq", false, "", fgOptVOR }, {"carrier", true, OPTION_FUNC, "", false, "", fgOptCarrier }, {"parkpos", true, OPTION_FUNC, "", false, "", fgOptParkpos }, {"fix", true, OPTION_FUNC, "", false, "", fgOptFIX }, diff --git a/src/Navaids/navlist.cxx b/src/Navaids/navlist.cxx index bbe3eb424..6bbf59fa3 100644 --- a/src/Navaids/navlist.cxx +++ b/src/Navaids/navlist.cxx @@ -33,6 +33,8 @@ #include +#include + using std::string; // FGNavList ------------------------------------------------------------------ @@ -73,41 +75,74 @@ FGNavRecord *FGNavList::findByFreq( double freq, const SGGeod& position) return findNavFromList( position, stations ); } -class VORNDBFilter : public FGPositioned::Filter +class TypeFilter : public FGPositioned::Filter { public: + TypeFilter( const FGPositioned::Type mintype, const FGPositioned::Type maxtype ) : _mintype(mintype), _maxtype(maxtype) {} + virtual FGPositioned::Type minType() const { - return FGPositioned::VOR; + return _mintype; } virtual FGPositioned::Type maxType() const { - return FGPositioned::NDB; + return _maxtype; } +private: + FGPositioned::Type _mintype; + FGPositioned::Type _maxtype; }; // Given an Ident and optional freqency, return the first matching // station. -FGNavRecord *FGNavList::findByIdentAndFreq(const string& ident, const double freq ) +const nav_list_type FGNavList::findByIdentAndFreq(const string& ident, const double freq, const FGPositioned::Type type ) { FGPositionedRef cur; - VORNDBFilter filter; + TypeFilter filter( + type == FGPositioned::INVALID ? FGPositioned::VOR : type, + type == FGPositioned::INVALID ? FGPositioned::NDB : type ); + nav_list_type reply; + cur = FGPositioned::findNextWithPartialId(cur, ident, &filter); - if (freq <= 0.0) { - return static_cast(cur.ptr()); // might be null - } - int f = (int)(freq*100.0 + 0.5); while (cur) { FGNavRecord* nav = static_cast(cur.ptr()); - if (nav->get_freq() == f) { - return nav; + if ( f <= 0.0 || nav->get_freq() == f) { + reply.push_back( nav ); } cur = FGPositioned::findNextWithPartialId(cur, ident, &filter); } - return NULL; + return reply; +} + +class NavRecordDistanceSortPredicate +{ +public: + NavRecordDistanceSortPredicate( const SGGeod & position ) : + _position(SGVec3d::fromGeod(position)) {} + + bool operator()( const nav_rec_ptr & n1, const nav_rec_ptr & n2 ) + { + if( n1 == NULL || n2 == NULL ) return false; + return distSqr(n1->cart(), _position) < distSqr(n2->cart(), _position); + } +private: + SGVec3d _position; + +}; + +// Given an Ident and optional freqency and type , +// return a list of matching stations sorted by distance to the given position +const nav_list_type FGNavList::findByIdentAndFreq( const SGGeod & position, + const std::string& ident, const double freq, const FGPositioned::Type type ) +{ + nav_list_type reply = findByIdentAndFreq( ident, freq, type ); + NavRecordDistanceSortPredicate sortPredicate( position ); + std::sort( reply.begin(), reply.end(), sortPredicate ); + + return reply; } // discount navids if they conflict with another on the same frequency diff --git a/src/Navaids/navlist.hxx b/src/Navaids/navlist.hxx index f54e5db93..6b4b6365c 100644 --- a/src/Navaids/navlist.hxx +++ b/src/Navaids/navlist.hxx @@ -76,10 +76,16 @@ public: */ FGNavRecord *findByFreq( double freq, const SGGeod& position); - // Given an Ident and optional freqency, return the first matching - // station. - FGNavRecord *findByIdentAndFreq( const std::string& ident, - const double freq = 0.0 ); + // Given an Ident and optional freqency and type , + // return a list of matching stations. + const nav_list_type findByIdentAndFreq( const std::string& ident, + const double freq = 0.0, const FGPositioned::Type = FGPositioned::INVALID ); + + // Given an Ident and optional freqency and type , + // return a list of matching stations sorted by distance to the given position + const nav_list_type findByIdentAndFreq( const SGGeod & position, + const std::string& ident, const double freq = 0.0, + const FGPositioned::Type = FGPositioned::INVALID ); // given a frequency returns the first matching entry FGNavRecord *findStationByFreq( double frequency ); -- 2.39.5