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".
#include <simgear/misc/sg_path.hxx>
#include <simgear/misc/sg_dir.hxx>
#include <simgear/misc/sgstream.hxx>
+#include <simgear/misc/strutils.hxx>
#include <simgear/misc/interpolator.hxx>
#include <simgear/scene/material/matlib.hxx>
// 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
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;
}
}
#include <Main/viewer.hxx>
#include <Environment/presets.hxx>
-#include <simgear/version.h>
#include <osg/Version>
using std::string;
#if defined( HAVE_VERSION_H ) && HAVE_VERSION_H
# include <Include/version.h>
+# include <simgear/version.h>
#else
# include <Include/no_version.h>
#endif
{"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 },
#include <Airports/runways.hxx>
+#include <algorithm>
+
using std::string;
// FGNavList ------------------------------------------------------------------
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<FGNavRecord*>(cur.ptr()); // might be null
- }
-
int f = (int)(freq*100.0 + 0.5);
while (cur) {
FGNavRecord* nav = static_cast<FGNavRecord*>(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
*/
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 );