double _width;
double _displ_thresh;
double _stopway;
+
+ /** surface, as defined by:
+ * http://www.x-plane.org/home/robinp/Apt810.htm#RwySfcCodes
+ */
int _surface_code;
public:
bool isSeaport() const;
bool isHeliport() const;
+ virtual const std::string& name() const
+ { return _name; }
+
const SGGeod& getTowerLocation() const { return _tower_location; }
void setMetar(bool value) { _has_metar = value; }
}
if(_subPage == 0) {
// TODO - trim VOR-DME from the name, convert to uppercase, abbreviate, etc
- _kln89->DrawText(np->get_name(), 2, 0, 2);
+ _kln89->DrawText(np->name(), 2, 0, 2);
_kln89->DrawLatitude(np->get_lat(), 2, 3, 1);
_kln89->DrawLongitude(np->get_lon(), 2, 3, 0);
} else {
//// TODO - will almost certainly have to process freq below for FG
_kln89->DrawFreq(np->get_freq(), 2, 9, 3);
// TODO - trim VOR-DME from the name, convert to uppercase, abbreviate, etc
- _kln89->DrawText(np->get_name(), 2, 0, 2);
+ _kln89->DrawText(np->name(), 2, 0, 2);
//cout << np->lat << "... ";
_kln89->DrawLatitude(np->get_lat(), 2, 3, 1);
_kln89->DrawLongitude(np->get_lon(), 2, 3, 0);
_time_before_search_sec = 1.0;
// try the ILS list first
- FGNavRecord *nav =
- globals->get_navlist()->findByFreq(frequency_khz, longitude_rad,
- latitude_rad, altitude_m);
+ FGNavRecord *nav = globals->get_navlist()->findByFreq(frequency_khz,
+ SGGeod::fromRadM(longitude_rad, latitude_rad, altitude_m));
_transmitter_valid = (nav != NULL);
if ( _transmitter_valid ) {
ident = nav->get_trans_ident();
if ( ident != _last_ident ) {
- _transmitter_pos = nav->get_pos();
- _transmitter_cart = nav->get_cart();
+ _transmitter_pos = nav->geod();
+ _transmitter_cart = nav->cart();
_transmitter_range_nm = nav->get_range();
}
}
_time_before_search_sec = 1.0;
// try the ILS list first
- FGNavRecord *dme
- = globals->get_dmelist()->findByFreq( frequency_mhz, longitude_rad,
- latitude_rad, altitude_m);
+
+ FGNavRecord *dme = globals->get_dmelist()->findByFreq( frequency_mhz,
+ SGGeod::fromRadM(longitude_rad, latitude_rad, altitude_m));
_transmitter_valid = (dme != NULL);
if ( _transmitter_valid ) {
- _transmitter = dme->get_cart();
+ _transmitter = dme->cart();
_transmitter_elevation_ft = dme->get_elev_ft();
_transmitter_range_nm = dme->get_range();
_transmitter_bias = dme->get_multiuse();
// Update current nav/adf radio stations based on current postition
void FGKR_87::search() {
- double acft_lon = lon_node->getDoubleValue() * SGD_DEGREES_TO_RADIANS;
- double acft_lat = lat_node->getDoubleValue() * SGD_DEGREES_TO_RADIANS;
- double acft_elev = alt_node->getDoubleValue() * SG_FEET_TO_METER;
-
+ SGGeod pos = SGGeod::fromDegFt(lon_node->getDoubleValue(),
+ lat_node->getDoubleValue(), alt_node->getDoubleValue());
+
// FIXME: the panel should handle this
static string last_ident = "";
// ADF.
////////////////////////////////////////////////////////////////////////
- FGNavRecord *adf
- = globals->get_navlist()->findByFreq( freq, acft_lon, acft_lat,
- acft_elev );
+
+ FGNavRecord *adf = globals->get_navlist()->findByFreq( freq, pos);
if ( adf != NULL ) {
char sfreq[128];
snprintf( sfreq, 10, "%d", freq );
stn_lat = adf->get_lat();
stn_elev = adf->get_elev_ft();
range = adf->get_range();
- effective_range = kludgeRange(stn_elev, acft_elev, range);
- xyz = adf->get_cart();
+ effective_range = kludgeRange(stn_elev, pos.getElevationM(), range);
+ xyz = adf->cart();
if ( globals->get_soundmgr()->exists( "adf-ident" ) ) {
globals->get_soundmgr()->remove( "adf-ident" );
#include <simgear/compiler.h>
#include <simgear/math/sg_random.h>
+#include <simgear/misc/sg_path.hxx>
#include <Aircraft/aircraft.hxx>
#include <Navaids/navlist.hxx>
static bool check_beacon_range( const SGGeod& pos,
- FGNavRecord *b )
+ FGPositioned *b )
{
- double d = distSqr(b->get_cart(), SGVec3d::fromGeod(pos));
+ double d = distSqr(b->cart(), SGVec3d::fromGeod(pos));
// cout << " distance = " << d << " ("
// << FG_ILS_DEFAULT_RANGE * SG_NM_TO_METER
// * FG_ILS_DEFAULT_RANGE * SG_NM_TO_METER
// << ")" << endl;
- // cout << " range = " << sqrt(d) << endl;
+ //std::cout << " range = " << sqrt(d) << std::endl;
// cout << "elev = " << elev * SG_METER_TO_FEET
// << " current->get_elev() = " << current->get_elev() << endl;
double elev_ft = pos.getElevationFt();
- double delev = elev_ft - b->get_elev_ft();
+ double delev = elev_ft - b->elevation();
// max range is the area under r = 2.4 * alt or r^2 = 4000^2 - alt^2
// whichever is smaller. The intersection point is 1538 ...
maxrange2 = 0.0;
}
maxrange2 *= SG_FEET_TO_METER * SG_FEET_TO_METER; // convert to meter^2
- // cout << "delev = " << delev << " maxrange = " << maxrange << endl;
+ //std::cout << "delev = " << delev << " maxrange = " << sqrt(maxrange2) << std::endl;
// match up to twice the published range so we can model
// reduced signal strength
}
}
+class BeaconFilter : public FGPositioned::Filter
+{
+public:
+ virtual bool pass(FGPositioned* aPos) const
+ {
+ return (aPos->type() >= FGPositioned::OM) && (aPos->type() <= FGPositioned::IM);
+ }
+};
+
// Update current nav/adf radio stations based on current postition
void FGMarkerBeacon::search()
{
-
// reset search time
_time_before_search_sec = 1.0;
// Beacons.
////////////////////////////////////////////////////////////////////////
- // get closest marker beacon
- FGNavRecord *b
- = globals->get_mkrlist()->findClosest( pos.getLongitudeRad(),
- pos.getLatitudeRad(),
- pos.getElevationM() );
-
- // cout << "marker beacon = " << b << " (" << b->get_type() << ")" << endl;
-
+ // get closest marker beacon - within a 1nm cutoff
+ BeaconFilter filter;
+ FGPositionedRef b = FGPositioned::findClosest(pos, 1.0, &filter);
+
fgMkrBeacType beacon_type = NOBEACON;
bool inrange = false;
if ( b != NULL ) {
} else if ( b->type() == FGPositioned::IM ) {
beacon_type = INNER;
}
- inrange = check_beacon_range( pos, b );
- // cout << " inrange = " << inrange << endl;
+ inrange = check_beacon_range( pos, b.ptr() );
}
outer_marker = middle_marker = inner_marker = false;
#include <simgear/timing/sg_time.hxx>
#include <simgear/math/vector.hxx>
#include <simgear/math/sg_random.h>
+#include <simgear/misc/sg_path.hxx>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/structure/exception.hxx>
_time_before_search_sec = 1.0;
// cache values locally for speed
- double lon = lon_node->getDoubleValue() * SGD_DEGREES_TO_RADIANS;
- double lat = lat_node->getDoubleValue() * SGD_DEGREES_TO_RADIANS;
- double elev = alt_node->getDoubleValue() * SG_FEET_TO_METER;
-
+ SGGeod pos = SGGeod::fromDegFt(lon_node->getDoubleValue(),
+ lat_node->getDoubleValue(), alt_node->getDoubleValue());
FGNavRecord *nav = NULL;
FGNavRecord *loc = NULL;
FGNavRecord *dme = NULL;
////////////////////////////////////////////////////////////////////////
double freq = freq_node->getDoubleValue();
- nav = globals->get_navlist()->findByFreq(freq, lon, lat, elev);
- dme = globals->get_dmelist()->findByFreq(freq, lon, lat, elev);
+ nav = globals->get_navlist()->findByFreq(freq, pos);
+ dme = globals->get_dmelist()->findByFreq(freq, pos);
if ( nav == NULL ) {
- loc = globals->get_loclist()->findByFreq(freq, lon, lat, elev);
- gs = globals->get_gslist()->findByFreq(freq, lon, lat, elev);
+ loc = globals->get_loclist()->findByFreq(freq, pos);
+ gs = globals->get_gslist()->findByFreq(freq, pos);
}
string nav_id = "";
while ( target_radial > 360.0 ) { target_radial -= 360.0; }
loc_lon = loc->get_lon();
loc_lat = loc->get_lat();
- nav_xyz = loc->get_cart();
+ nav_xyz = loc->cart();
last_nav_id = nav_id;
last_nav_vor = false;
loc_node->setBoolValue( true );
nav_elev = gs->get_elev_ft();
int tmp = (int)(gs->get_multiuse() / 1000.0);
target_gs = (double)tmp / 100.0;
- gs_xyz = gs->get_cart();
+ gs_xyz = gs->cart();
// derive GS baseline (perpendicular to the runay
// along the ground)
nav_elev = nav->get_elev_ft();
twist = nav->get_multiuse();
range = nav->get_range();
- effective_range = adjustNavRange(nav_elev, elev, range);
+ effective_range = adjustNavRange(nav_elev, pos.getElevationM(), range);
target_gs = 0.0;
target_radial = sel_radial_node->getDoubleValue();
- nav_xyz = nav->get_cart();
+ nav_xyz = nav->cart();
if ( globals->get_soundmgr()->exists( nav_fx_name ) ) {
globals->get_soundmgr()->remove( nav_fx_name );
if ( freq_valid ) {
- string str1( mobile_tacan->get_name() );
+ string str1( mobile_tacan->name() );
SGPropertyNode * branch = fgGetNode("ai/models", true);
vector<SGPropertyNode_ptr> carrier = branch->getChildren("carrier");
_mobile_elevation_ft = mobile_tacan->get_elev_ft();
_mobile_range_nm = mobile_tacan->get_range();
_mobile_bias = mobile_tacan->get_multiuse();
- _mobile_name = mobile_tacan->get_name();
+ _mobile_name = mobile_tacan->name();
_mobile_ident = mobile_tacan->get_trans_ident();
_mobile_valid = true;
SG_LOG( SG_INSTR, SG_DEBUG, " carrier transmitter valid " << _mobile_valid );
_mobile_elevation_ft = tanker[i]->getDoubleValue("position/altitude-ft");
_mobile_range_nm = mobile_tacan->get_range();
_mobile_bias = mobile_tacan->get_multiuse();
- _mobile_name = mobile_tacan->get_name();
+ _mobile_name = mobile_tacan->name();
_mobile_ident = mobile_tacan->get_trans_ident();
_mobile_valid = true;
SG_LOG( SG_INSTR, SG_DEBUG, " tanker transmitter valid " << _mobile_valid );
_mobile_elevation_ft = mp_tanker[i]->getDoubleValue("position/altitude-ft");
_mobile_range_nm = mobile_tacan->get_range();
_mobile_bias = mobile_tacan->get_multiuse();
- _mobile_name = mobile_tacan->get_name();
+ _mobile_name = mobile_tacan->name();
_mobile_ident = mobile_tacan->get_trans_ident();
_mobile_valid = true;
}
// try the TACAN/VORTAC list next
- FGNavRecord *tacan
- = globals->get_tacanlist()->findByFreq( frequency_mhz, longitude_rad,
- latitude_rad, altitude_m);
+ FGNavRecord *tacan = globals->get_tacanlist()->findByFreq( frequency_mhz,
+ SGGeod::fromRadM(longitude_rad, latitude_rad, altitude_m));
_transmitter_valid = (tacan != NULL);
if ( _transmitter_valid ) {
SG_LOG( SG_INSTR, SG_DEBUG, "transmitter valid " << _transmitter_valid );
- _transmitter_pos = tacan->get_pos();
+ _transmitter_pos = tacan->geod();
_transmitter_range_nm = tacan->get_range();
_transmitter_bias = tacan->get_multiuse();
- _transmitter_name = tacan->get_name();
+ _transmitter_name = tacan->name();
_name_node->setStringValue(_transmitter_name.c_str());
_transmitter_ident = tacan->get_trans_ident();
_ident_node->setStringValue(_transmitter_ident.c_str());
#include <Navaids/navdb.hxx>
#include <Navaids/navlist.hxx>
#include <Navaids/fix.hxx>
+#include <Navaids/fixlist.hxx>
#include <Scenery/scenery.hxx>
#include <Scenery/tilemgr.hxx>
#include <Scripting/NasalSys.hxx>
FGNavList *loclist = new FGNavList;
FGNavList *gslist = new FGNavList;
FGNavList *dmelist = new FGNavList;
- FGNavList *mkrlist = new FGNavList;
FGNavList *tacanlist = new FGNavList;
FGNavList *carrierlist = new FGNavList;
FGTACANList *channellist = new FGTACANList;
globals->set_loclist( loclist );
globals->set_gslist( gslist );
globals->set_dmelist( dmelist );
- globals->set_mkrlist( mkrlist );
globals->set_tacanlist( tacanlist );
globals->set_carrierlist( carrierlist );
globals->set_channellist( channellist );
- if ( !fgNavDBInit(navlist, loclist, gslist, dmelist, mkrlist, tacanlist, carrierlist, channellist) ) {
+ if ( !fgNavDBInit(navlist, loclist, gslist, dmelist, tacanlist, carrierlist, channellist) ) {
SG_LOG( SG_GENERAL, SG_ALERT,
"Problems loading one or more navigational database" );
}
loclist( NULL ),
gslist( NULL ),
dmelist( NULL ),
- mkrlist( NULL ),
tacanlist( NULL ),
carrierlist( NULL ),
channellist( NULL ),
delete loclist;
delete gslist;
delete dmelist;
- delete mkrlist;
delete tacanlist;
delete carrierlist;
delete channellist;
FGNavList *loclist;
FGNavList *gslist;
FGNavList *dmelist;
- FGNavList *mkrlist;
FGNavList *tacanlist;
FGNavList *carrierlist;
FGTACANList *channellist;
inline void set_tacanlist( FGNavList *n ) { tacanlist = n; }
inline FGNavList *get_carrierlist() const { return carrierlist; }
inline void set_carrierlist( FGNavList *n ) { carrierlist = n; }
- inline FGNavList *get_mkrlist() const { return mkrlist; }
- inline void set_mkrlist( FGNavList *n ) { mkrlist = n; }
inline FGTACANList *get_channellist() const { return channellist; }
inline void set_channellist( FGTACANList *c ) { channellist = c; }
#include <simgear/debug/logstream.hxx>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/misc/strutils.hxx>
+#include <simgear/misc/sg_path.hxx>
#include <simgear/structure/exception.hxx>
#include <simgear/misc/sgstream.hxx>
#include "navrecord.hxx"
+#include "navlist.hxx"
#include "navdb.hxx"
#include "Main/globals.hxx"
// load and initialize the navigational databases
bool fgNavDBInit( FGNavList *navlist, FGNavList *loclist, FGNavList *gslist,
- FGNavList *dmelist, FGNavList *mkrlist,
+ FGNavList *dmelist,
FGNavList *tacanlist, FGNavList *carrierlist,
FGTACANList *channellist)
{
case FGPositioned::OM:
case FGPositioned::MM:
case FGPositioned::IM:
- mkrlist->add(r);
+ // no need to add this to a list, never searched by frequency
break;
case FGPositioned::DME:
{
dmelist->add(r);
- string::size_type loc1= r->get_name().find( "TACAN", 0 );
- string::size_type loc2 = r->get_name().find( "VORTAC", 0 );
+ 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);
#include <simgear/compiler.h>
-#include <simgear/misc/sg_path.hxx>
-#include "navlist.hxx"
-#include "fixlist.hxx"
+class FGNavList;
+class FGTACANList;
// load and initialize the navigational databases
bool fgNavDBInit( FGNavList *navlist, FGNavList *loclist, FGNavList *gslist,
- FGNavList *dmelist, FGNavList *mkrbeacons,
+ FGNavList *dmelist,
FGNavList *tacanlist, FGNavList *carrierlist,
FGTACANList *channellist );
#endif
#include <simgear/debug/logstream.hxx>
-#include <simgear/misc/sgstream.hxx>
#include <simgear/math/sg_geodesy.hxx>
+#include <simgear/sg_inlines.h>
#include "navlist.hxx"
-
-// Return true if the nav record matches the type
-static bool isTypeMatch(const FGNavRecord* n, fg_nav_types type)
-{
- if (type == FG_NAV_ANY) return true;
- return type == n->type();
-}
-
-
+using std::string;
// FGNavList ------------------------------------------------------------------
FGNavList::~FGNavList( void )
{
- navaids_by_tile.erase( navaids_by_tile.begin(), navaids_by_tile.end() );
nav_list_type navlist = navaids.begin()->second;
navaids.erase( navaids.begin(), navaids.end() );
}
// since we're using an SGSharedPointer
nav_list_type navlist = navaids.begin()->second;
navaids.erase( navaids.begin(), navaids.end() );
- navaids_by_tile.erase( navaids_by_tile.begin(), navaids_by_tile.end() );
- ident_navaids.erase( ident_navaids.begin(), ident_navaids.end() );
-
return true;
}
-
-// real add a marker beacon
-static void real_add( nav_map_type &navmap, const int master_index,
- FGNavRecord *n )
-{
- navmap[master_index].push_back( n );
-}
-
-
-// front end for add a marker beacon
-static void tile_add( nav_map_type &navmap, FGNavRecord *n )
-{
- double diff = 0;
-
- double lon = n->get_lon();
- double lat = n->get_lat();
-
- int lonidx = (int)lon;
- diff = lon - (double)lonidx;
- if ( (lon < 0.0) && (fabs(diff) > SG_EPSILON) ) {
- lonidx -= 1;
- }
- double lonfrac = lon - (double)lonidx;
- lonidx += 180;
-
- int latidx = (int)lat;
- diff = lat - (double)latidx;
- if ( (lat < 0.0) && (fabs(diff) > SG_EPSILON) ) {
- latidx -= 1;
- }
- double latfrac = lat - (double)latidx;
- latidx += 90;
-
- int master_index = lonidx * 1000 + latidx;
- // cout << "lonidx = " << lonidx << " latidx = " << latidx << " ";
- // cout << "Master index = " << master_index << endl;
-
- // add to the actual bucket
- real_add( navmap, master_index, n );
-
- // if we are close to the edge, add to adjacent buckets so we only
- // have to search one bucket at run time
-
- // there are 8 cases since there are 8 adjacent tiles
-
- if ( lonfrac < 0.2 ) {
- real_add( navmap, master_index - 1000, n );
- if ( latfrac < 0.2 ) {
- real_add( navmap, master_index - 1000 - 1, n );
- } else if ( latfrac > 0.8 ) {
- real_add( navmap, master_index - 1000 + 1, n );
- }
- } else if ( lonfrac > 0.8 ) {
- real_add( navmap, master_index + 1000, n );
- if ( latfrac < 0.2 ) {
- real_add( navmap, master_index + 1000 - 1, n );
- } else if ( latfrac > 0.8 ) {
- real_add( navmap, master_index + 1000 + 1, n );
- }
- } else if ( latfrac < 0.2 ) {
- real_add( navmap, master_index - 1, n );
- } else if ( latfrac > 0.8 ) {
- real_add( navmap, master_index + 1, n );
- }
-}
-
-
// add an entry to the lists
bool FGNavList::add( FGNavRecord *n )
{
navaids[n->get_freq()].push_back(n);
- ident_navaids[n->get_ident()].push_back(n);
- tile_add( navaids_by_tile, n );
return true;
}
-FGNavRecord *FGNavList::findByFreq( double freq, double lon, double lat, double elev )
+FGNavRecord *FGNavList::findByFreq( double freq, const SGGeod& position)
{
const nav_list_type& stations = navaids[(int)(freq*100.0 + 0.5)];
-
- SGGeod geod = SGGeod::fromRadM(lon, lat, elev);
- SGVec3d aircraft = SGVec3d::fromGeod(geod);
SG_LOG( SG_INSTR, SG_DEBUG, "findbyFreq " << freq << " size " << stations.size() );
-
- return findNavFromList( aircraft, stations );
+ return findNavFromList( position, stations );
}
-
-FGNavRecord *FGNavList::findByIdent( const char* ident,
- const double lon, const double lat )
+class VORNDBFilter : public FGPositioned::Filter
{
- const nav_list_type& stations = ident_navaids[ident];
- SGGeod geod = SGGeod::fromRad(lon, lat);
- SGVec3d aircraft = SGVec3d::fromGeod(geod);
- return findNavFromList( aircraft, stations );
-}
-
-
-
+public:
+ virtual bool pass(FGPositioned* aPos) const
+ {
+ return (aPos->type() == FGPositioned::VOR) || (aPos->type() == FGPositioned::NDB);
+ }
+};
// Given an Ident and optional freqency, return the first matching
// station.
-FGNavRecord *FGNavList::findByIdentAndFreq( const char* ident, const double freq )
+FGNavRecord *FGNavList::findByIdentAndFreq(const string& ident, const double freq )
{
- nav_list_type stations = ident_navaids[ident];
- SG_LOG( SG_INSTR, SG_DEBUG, "findByIdent " << ident<< " size " << stations.size() );
- if ( freq > 0.0 ) {
- // sometimes there can be duplicated idents. If a freq is
- // specified, use it to refine the search.
- int f = (int)(freq*100.0 + 0.5);
- nav_list_const_iterator it, end = stations.end();
- for ( it = stations.begin(); it != end; ++it ) {
- if ( f == (*it)->get_freq() ) {
- return (*it);
- }
- }
- } else if (!stations.empty()) {
- return stations[0];
+ FGPositionedRef cur;
+ VORNDBFilter filter;
+ 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;
}
+
+ cur = FGPositioned::findNextWithPartialId(cur, ident, &filter);
+ }
- return NULL;
+ return NULL;
}
// LOC, ILS, GS, and DME antenna's could potentially be
// directional atennas and only when there is a chance it is
// the closest station.)
-static bool penaltyForNav(FGNavRecord* aNav, const SGVec3d &aPos)
+static bool penaltyForNav(FGNavRecord* aNav, const SGGeod &aGeod)
{
switch (aNav->type()) {
case FGPositioned::ILS:
hdg_deg = aNav->get_multiuse();
}
- double az1 = 0.0, az2 = 0.0, s = 0.0;
- SGGeod geod = SGGeod::fromCart(aPos);
- geo_inverse_wgs_84( geod, aNav->geod(), &az1, &az2, &s);
+ double az1, az2, s;
+ SGGeodesy::inverse(aGeod, aNav->geod(), az1, az2, s);
az1 = az1 - hdg_deg;
-
- if ( az1 > 180.0) az1 -= 360.0;
- if ( az1 < -180.0) az1 += 360.0;
-
+ SG_NORMALIZE_RANGE(az1, -180.0, 180.0);
return fabs(az1) > 90.0;
}
// Given a point and a list of stations, return the closest one to the
// specified point.
-FGNavRecord *FGNavList::findNavFromList( const SGVec3d &aircraft,
+FGNavRecord *FGNavList::findNavFromList( const SGGeod &aircraft,
const nav_list_type &stations )
{
FGNavRecord *nav = NULL;
double d2; // in meters squared
double min_dist
= FG_NAV_MAX_RANGE*SG_NM_TO_METER*FG_NAV_MAX_RANGE*SG_NM_TO_METER;
-
+ SGVec3d aircraftCart = SGVec3d::fromGeod(aircraft);
+
nav_list_const_iterator it;
nav_list_const_iterator end = stations.end();
// find the closest station within a sensible range (FG_NAV_MAX_RANGE)
for ( it = stations.begin(); it != end; ++it ) {
FGNavRecord *station = *it;
// cout << "testing " << current->get_ident() << endl;
- d2 = distSqr(station->get_cart(), aircraft);
+ d2 = distSqr(station->cart(), aircraftCart);
if ( d2 < min_dist && penaltyForNav(station, aircraft))
{
double dist = sqrt(d2);
return nav;
}
-
-// returns the closest entry to the give lon/lat/elev
-FGNavRecord *FGNavList::findClosest( double lon_rad, double lat_rad,
- double elev_m, fg_nav_types type)
-{
- FGNavRecord *result = NULL;
- double diff;
-
- double lon_deg = lon_rad * SG_RADIANS_TO_DEGREES;
- double lat_deg = lat_rad * SG_RADIANS_TO_DEGREES;
- int lonidx = (int)lon_deg;
- diff = lon_deg - (double)lonidx;
- if ( (lon_deg < 0.0) && (fabs(diff) > SG_EPSILON) ) {
- lonidx -= 1;
- }
- lonidx += 180;
-
- int latidx = (int)lat_deg;
- diff = lat_deg - (double)latidx;
- if ( (lat_deg < 0.0) && (fabs(diff) > SG_EPSILON) ) {
- latidx -= 1;
- }
- latidx += 90;
-
- int master_index = lonidx * 1000 + latidx;
-
- const nav_list_type& navs = navaids_by_tile[ master_index ];
- // cout << "Master index = " << master_index << endl;
- // cout << "beacon search length = " << beacons.size() << endl;
-
- nav_list_const_iterator current = navs.begin();
- nav_list_const_iterator last = navs.end();
-
- SGGeod geod = SGGeod::fromRadM(lon_rad, lat_rad, elev_m);
- SGVec3d aircraft = SGVec3d::fromGeod(geod);
-
- double min_dist = 999999999.0;
-
- for ( ; current != last ; ++current ) {
- if(isTypeMatch(*current, type)) {
- // cout << " testing " << (*current)->get_ident() << endl;
-
- double d = distSqr((*current)->get_cart(), aircraft);
- // cout << " distance = " << d << " ("
- // << FG_ILS_DEFAULT_RANGE * SG_NM_TO_METER
- // * FG_ILS_DEFAULT_RANGE * SG_NM_TO_METER
- // << ")" << endl;
-
- // cout << " range = " << sqrt(d) << endl;
-
- if ( d < min_dist ) {
- min_dist = d;
- result = (*current);
- }
- }
- }
-
- // cout << "lon = " << lon << " lat = " << lat
- // << " closest beacon = " << sqrt( min_dist ) << endl;
-
- return result;
-}
-
// Given a frequency, return the first matching station.
FGNavRecord *FGNavList::findStationByFreq( double freq )
{
#include <simgear/compiler.h>
-#include <simgear/misc/sg_path.hxx>
+
#include <simgear/structure/SGSharedPtr.hxx>
-#include <simgear/structure/SGReferenced.hxx>
#include <map>
#include <vector>
#include "navrecord.hxx"
-using std::map;
-using std::vector;
-using std::string;
-
-
+// forward decls
+class SGGeod;
// FGNavList ------------------------------------------------------------------
typedef SGSharedPtr<FGNavRecord> nav_rec_ptr;
-typedef vector < nav_rec_ptr > nav_list_type;
+typedef std::vector < nav_rec_ptr > nav_list_type;
typedef nav_list_type::iterator nav_list_iterator;
typedef nav_list_type::const_iterator nav_list_const_iterator;
-typedef map < int, nav_list_type > nav_map_type;
+typedef std::map < int, nav_list_type > nav_map_type;
typedef nav_map_type::iterator nav_map_iterator;
typedef nav_map_type::const_iterator nav_map_const_iterator;
-typedef map < string, nav_list_type > nav_ident_map_type;
-typedef nav_ident_map_type::iterator nav_ident_map_iterator;
-
-
class FGNavList {
nav_list_type carrierlist;
nav_map_type navaids;
- nav_map_type navaids_by_tile;
- nav_ident_map_type ident_navaids;
// Given a point and a list of stations, return the closest one to
// the specified point.
- FGNavRecord *findNavFromList( const SGVec3d &aircraft,
+ FGNavRecord *findNavFromList( const SGGeod &aircraft,
const nav_list_type &stations );
public:
/** Query the database for the specified station. It is assumed
* that there will be multiple stations with matching frequencies
- * so a position must be specified. Lon and lat are in radians,
- * elev is in meters.
+ * so a position must be specified.
*/
- FGNavRecord *findByFreq( double freq, double lon, double lat, double elev );
-
- // locate closest item in the DB matching the requested ident
- FGNavRecord *findByIdent( const char* ident, const double lon, const double lat );
+ FGNavRecord *findByFreq( double freq, const SGGeod& position);
// Given an Ident and optional freqency, return the first matching
// station.
- FGNavRecord *findByIdentAndFreq( const char* ident,
+ FGNavRecord *findByIdentAndFreq( const std::string& ident,
const double freq = 0.0 );
- // returns the closest entry to the give lon/lat/elev
- FGNavRecord *findClosest( double lon_rad, double lat_rad, double elev_m,
- FGPositioned::Type type = FG_NAV_ANY );
-
// given a frequency returns the first matching entry
FGNavRecord *findStationByFreq( double frequency );
-
- inline const nav_map_type& get_navaids() const { return navaids; }
};
typedef SGSharedPtr<FGTACANRecord> tacan_rec_ptr;
-typedef vector < tacan_rec_ptr > tacan_list_type;
-typedef map < int, tacan_list_type > tacan_map_type;
-typedef map < string, tacan_list_type > tacan_ident_map_type;
-
+typedef std::vector < tacan_rec_ptr > tacan_list_type;
+typedef std::map < int, tacan_list_type > tacan_map_type;
+typedef std::map < std::string, tacan_list_type > tacan_ident_map_type;
class FGTACANList {
bool add( FGTACANRecord *r );
// Given a TACAN Channel, return the appropriate frequency.
- FGTACANRecord *findByChannel( const string& channel );
+ FGTACANRecord *findByChannel( const std::string& channel );
};
freq(aFreq),
range(aRange),
multiuse(aMultiuse),
- name(aName),
+ _name(aName),
serviceable(true),
trans_ident(aIdent)
{
}
-SGVec3d FGNavRecord::get_cart() const
-{
- return SGVec3d::fromGeod(geod());
-}
-
-
static FGPositioned::Type
mapRobinTypeToFGPType(int aTy)
{
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 recgonize", "FGNavRecord::createFromStream");
+ throw sg_range_exception("Got a nav.dat type we don't recognize", "FGNavRecord::createFromStream");
}
}
double lat, lon, elev_ft, multiuse;
int freq, range;
- std::string apt_id, name, ident;
+ std::string name, ident;
aStream >> lat >> lon >> elev_ft >> freq >> range >> multiuse >> ident;
getline(aStream, name);
freq *= 100;
}
+ // ensure marker beacons are anonymous, so they don't get added to the
+ // name index
+ if ((type >= OM) && (type <= IM)) {
+ ident.clear();
+ }
+
FGNavRecord* result = new FGNavRecord(type, ident,
simgear::strutils::strip(name), SGGeod::fromDegFt(lon, lat, elev_ft),
freq, range, multiuse);
void FGNavRecord::initAirportRelation()
{
- if (type() < ILS || type() > IM) {
+ if ((type() < ILS) || (type() > IM)) {
return; // not airport-located
}
- vector<string> parts = simgear::strutils::split(name);
- apt_id = parts[0];
- const FGAirport* apt = fgFindAirportID(apt_id);
+ vector<string> parts = simgear::strutils::split(_name);
+ if (parts.size() < 2) {
+ SG_LOG(SG_GENERAL, SG_WARN, "navaid has malformed name:" << _name);
+ return;
+ }
+
+ const FGAirport* apt = fgFindAirportID(parts[0]);
if (!apt) {
- SG_LOG(SG_GENERAL, SG_WARN, "navaid " << ident() << " associated with bogus airport ID:" << apt_id);
+ SG_LOG(SG_GENERAL, SG_WARN, "navaid " << _name << " associated with bogus airport ID:" << parts[0]);
return;
}
+ runway = apt->getRunwayByIdent(parts[1]);
+ if (!runway) {
+ SG_LOG(SG_GENERAL, SG_WARN, "navaid " << _name << " associated with bogus runway ID:" << parts[1]);
+ return;
+ }
+
// fudge elevation to the field elevation if it's not specified
if (fabs(elevation()) < 0.01) {
mPosition.setElevationFt(apt->getElevation());
return;
}
- if (parts.size() < 2) {
- SG_LOG(SG_GENERAL, SG_ALERT, "can't parse navaid " << ident()
- << " name for airport/runway:" << name);
- return;
- }
-
- double threshold
- = fgGetDouble( "/sim/navdb/localizers/auto-align-threshold-deg",
- 5.0 );
- FGRunway* runway = apt->getRunwayByIdent(parts[1]);
+ double threshold
+ = fgGetDouble( "/sim/navdb/localizers/auto-align-threshold-deg", 5.0 );
alignLocaliserWithRunway(runway, threshold);
}
}
// (degrees) or localizer heading
// (degrees) or dme bias (nm)
- std::string name; // verbose name in nav database
- std::string apt_id; // corresponding airport id
-
+ std::string _name; // verbose name in nav database
+ FGRunway* runway;
bool serviceable; // for failure modeling
std::string trans_ident; // for failure modeling
inline double get_lon() const { return longitude(); } // degrees
inline double get_lat() const { return latitude(); } // degrees
inline double get_elev_ft() const { return elevation(); }
-
- const SGGeod& get_pos() const { return geod(); }
- SGVec3d get_cart() const;
-
- Type get_fg_type() const { return type(); }
-
+
inline int get_freq() const { return freq; }
inline int get_range() const { return range; }
inline double get_multiuse() const { return multiuse; }
inline void set_multiuse( double m ) { multiuse = m; }
inline const char *get_ident() const { return ident().c_str(); }
- inline const std::string& get_name() const { return name; }
- inline const std::string& get_apt_id() const { return apt_id; }
+
inline bool get_serviceable() const { return serviceable; }
inline const char *get_trans_ident() const { return trans_ident.c_str(); }
-
+ virtual const std::string& name() const
+ { return _name; }
};
class FGTACANRecord : public SGReferenced {
#include <set>
#include <algorithm>
+#include <iostream>
+
#include <simgear/math/sg_geodesy.hxx>
#include "positioned.hxx"
{
public:
RangePredictate(const SGGeod& aOrigin, double aRange) :
- mOrigin(aOrigin),
- mRange(aRange)
+ mOrigin(SGVec3d::fromGeod(aOrigin)),
+ mRangeSqr(aRange * aRange)
{ ; }
bool operator()(const FGPositionedRef& aPos)
{
- double d, az1, az2;
- SGGeodesy::inverse(aPos->geod(), mOrigin, az1, az2, d);
- return (d > mRange);
+ double dSqr = distSqr(aPos->cart(), mOrigin);
+ return (dSqr > mRangeSqr);
}
private:
- SGGeod mOrigin;
- double mRange;
+ SGVec3d mOrigin;
+ double mRangeSqr;
};
static void
{
public:
DistanceOrdering(const SGGeod& aPos) :
- mPos(aPos)
+ mPos(SGVec3d::fromGeod(aPos))
{ }
bool operator()(const FGPositionedRef& a, const FGPositionedRef& b) const
{
- double dA, dB, az1, az2;
- SGGeodesy::inverse(mPos, a->geod(), az1, az2, dA);
- SGGeodesy::inverse(mPos, b->geod(), az1, az2, dB);
+ double dA = distSqr(a->cart(), mPos),
+ dB = distSqr(b->cart(), mPos);
return dA < dB;
}
private:
- SGGeod mPos;
+ SGVec3d mPos;
};
static void
double minDist = HUGE_VAL;
FGPositionedRef result;
NamedPositionedIndex::const_iterator it = range.first;
-
+ SGVec3d cartOrigin(SGVec3d::fromGeod(aOrigin));
+
for (; it != range.second; ++it) {
if (aFilter && !aFilter->pass(range.first->second)) {
continue;
}
// find distance
- double d, az1, az2;
- SGGeodesy::inverse(aOrigin, it->second->geod(), az1, az2, d);
- if (d < minDist) {
- minDist = d;
+ double d2 = distSqr(cartOrigin, it->second->cart());
+ if (d2 < minDist) {
+ minDist = d2;
result = it->second;
}
}
result.insert(result.end(), hits.begin(), hits.end()); // append
} // of outer loop
+ sortByDistance(aPos, result);
if (result.size() > aN) {
result.resize(aN); // truncate at requested number of matches
}
- sortByDistance(aPos, result);
return result;
}
FGPositioned::~FGPositioned()
{
+ //std::cout << "destroying:" << mIdent << "/" << nameForType(mType) << std::endl;
removeFromIndices(this);
}
return SGBucket(mPosition);
}
+SGVec3d
+FGPositioned::cart() const
+{
+ return SGVec3d::fromGeod(mPosition);
+}
+
const char* FGPositioned::nameForType(Type aTy)
{
switch (aTy) {
+ case RUNWAY: return "runway";
+ case TAXIWAY: return "taxiway";
+ case PARK_STAND: return "parking stand";
case FIX: return "fix";
case VOR: return "VOR";
case NDB: return "NDB";
+ case ILS: return "ILS";
+ case LOC: return "localiser";
+ case GS: return "glideslope";
case OM: return "outer-marker";
case MM: return "middle-marker";
case IM: return "inner-marker";
case HELIPORT: return "heliport";
case SEAPORT: return "seaport";
case WAYPOINT: return "waypoint";
+ case DME: return "dme";
+ case TACAN: return "tacan";
default:
return "unknown";
}
const SGGeod& geod() const
{ return mPosition; }
+ /**
+ * Compute the cartesian position associated with this object
+ */
+ SGVec3d cart() const;
+
SGBucket bucket() const;
double latitude() const