1
0
Fork 0

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".
This commit is contained in:
Torsten Dreyer 2011-07-18 11:09:43 +02:00
parent 24383e5194
commit c6d5b6ebdb
4 changed files with 93 additions and 30 deletions

View file

@ -59,6 +59,7 @@
#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>
@ -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;
}
}

View file

@ -59,7 +59,6 @@
#include <Main/viewer.hxx>
#include <Environment/presets.hxx>
#include <simgear/version.h>
#include <osg/Version>
using std::string;
@ -70,6 +69,7 @@ using std::endl;
#if defined( HAVE_VERSION_H ) && HAVE_VERSION_H
# include <Include/version.h>
# include <simgear/version.h>
#else
# include <Include/no_version.h>
#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 },

View file

@ -33,6 +33,8 @@
#include <Airports/runways.hxx>
#include <algorithm>
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<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

View file

@ -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 );