1
0
Fork 0

James Turner:

Convert FGNavRecord to inherit FGPositioned. This is much more self-contained than the FGRunway change, since FGNavRecord already had good encapsulation of its state. However, it's a large diff due to moving around two nasty pieces of code - the 'align navaid with extended runway centerline' logic and the 'penalise transmitters at the opposite runway end' logic.

In general things are more readable because I've replaced the Navaid type enum, and the use of Robin's integer type codes, with   switches on the FGPositioned::Type code - no more trying to recall that '6' is an outer marker in Robin's data. The creation code path is also pushed down from navdb into navrecord itself.
This commit is contained in:
ehofman 2008-09-12 08:46:15 +00:00
parent a18a0593d4
commit bb2b03c7e3
9 changed files with 318 additions and 391 deletions

View file

@ -1150,7 +1150,7 @@ FGNavRecord* DCLGPS::FindFirstVorById(const string& id, bool &multi, bool exact)
if(nav.empty()) return(NULL);
for(nav_list_iterator it = nav.begin(); it != nav.end(); ++it) {
if((*it)->get_type() == 3) return(*it);
if((*it)->type() == FGPositioned::VOR) return(*it);
}
return(NULL); // Shouldn't get here!
}
@ -1170,7 +1170,7 @@ FGNavRecord* DCLGPS::FindFirstNDBById(const string& id, bool &multi, bool exact)
if(nav.empty()) return(NULL);
for(nav_list_iterator it = nav.begin(); it != nav.end(); ++it) {
if((*it)->get_type() == 2) return(*it);
if((*it)->type() == FGPositioned::NDB) return(*it);
}
return(NULL); // Shouldn't get here!
}

View file

@ -269,11 +269,11 @@ void FGMarkerBeacon::search()
fgMkrBeacType beacon_type = NOBEACON;
bool inrange = false;
if ( b != NULL ) {
if ( b->get_type() == 7 ) {
if ( b->type() == FGPositioned::OM ) {
beacon_type = OUTER;
} else if ( b->get_type() == 8 ) {
} else if ( b->type() == FGPositioned::MM ) {
beacon_type = MIDDLE;
} else if ( b->get_type() == 9 ) {
} else if ( b->type() == FGPositioned::IM ) {
beacon_type = INNER;
}
inrange = check_beacon_range( pos, b );

View file

@ -1159,22 +1159,11 @@ fgInitNav ()
globals->set_carrierlist( carrierlist );
globals->set_channellist( channellist );
if ( !fgNavDBInit(airports, navlist, loclist, gslist, dmelist, mkrlist, tacanlist, carrierlist, channellist) ) {
if ( !fgNavDBInit(navlist, loclist, gslist, dmelist, mkrlist, tacanlist, carrierlist, channellist) ) {
SG_LOG( SG_GENERAL, SG_ALERT,
"Problems loading one or more navigational database" );
}
if ( fgGetBool("/sim/navdb/localizers/auto-align", true) ) {
// align all the localizers with their corresponding runways
// since data sources are good for cockpit navigation
// purposes, but not always to the error tolerances needed to
// exactly place these items.
double threshold
= fgGetDouble( "/sim/navdb/localizers/auto-align-threshold-deg",
5.0 );
fgNavDBAlignLOCwithRunway( airports, loclist, threshold );
}
SG_LOG(SG_GENERAL, SG_INFO, " Fixes");
SGPath p_fix( globals->get_fg_root() );
p_fix.append( "Navaids/fix.dat" );

View file

@ -29,24 +29,20 @@
#include <string>
#include <simgear/debug/logstream.hxx>
#include <simgear/misc/sgstream.hxx>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/misc/strutils.hxx>
#include <Airports/runways.hxx>
#include <Airports/simple.hxx>
#include <Main/globals.hxx>
#include <simgear/structure/exception.hxx>
#include <simgear/misc/sgstream.hxx>
#include "navrecord.hxx"
#include "navdb.hxx"
#include "Main/globals.hxx"
using std::string;
// load and initialize the navigational databases
bool fgNavDBInit( FGAirportList *airports,
FGNavList *navlist, FGNavList *loclist, FGNavList *gslist,
bool fgNavDBInit( FGNavList *navlist, FGNavList *loclist, FGNavList *gslist,
FGNavList *dmelist, FGNavList *mkrlist,
FGNavList *tacanlist, FGNavList *carrierlist,
FGTACANList *channellist)
@ -77,71 +73,56 @@ bool fgNavDBInit( FGAirportList *airports,
in >> skipeol;
in >> skipeol;
while ( ! in.eof() ) {
FGNavRecord *r = new FGNavRecord;
in >> (*r);
if ( r->get_type() > 95 ) {
delete r;
while (!in.eof()) {
FGNavRecord *r = FGNavRecord::createFromStream(in);
if (!r) {
break;
}
/*cout << "id = " << r->get_ident() << endl;
cout << " type = " << r->get_type() << endl;
cout << " lon = " << r->get_lon() << endl;
cout << " lat = " << r->get_lat() << endl;
cout << " elev = " <<r->get_elev_ft() << endl;
cout << " freq = " << r->get_freq() << endl;
cout << " range = " << r->get_range() << endl;
cout << " name = " << r->get_name() << endl << endl; */
switch (r->type()) {
case FGPositioned::NDB:
case FGPositioned::VOR:
navlist->add(r);
break;
// fudge elevation to the field elevation if it's not specified
if ( fabs(r->get_elev_ft()) < 0.01 && r->get_apt_id().length() ) {
// cout << r->get_type() << " " << r->get_apt_id() << " zero elev"
// << endl;
const FGAirport* a = airports->search( r->get_apt_id() );
if ( a ) {
r->set_elev_ft( a->getElevation() );
// cout << " setting to " << a.elevation << endl;
}
}
case FGPositioned::ILS:
case FGPositioned::LOC:
loclist->add(r);
break;
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 )
case FGPositioned::GS:
gslist->add(r);
break;
case FGPositioned::OM:
case FGPositioned::MM:
case FGPositioned::IM:
mkrlist->add(r);
break;
case FGPositioned::DME:
{
// Marker Beacon = 7,8,9
mkrlist->add( r );
} else if ( r->get_type() == 12 || r->get_type() == 13) {
// DME with ILS=12; standalone DME=13
string str1( r->get_name() );
string::size_type loc1= str1.find( "TACAN", 0 );
string::size_type loc2 = str1.find( "VORTAC", 0 );
dmelist->add(r);
string::size_type loc1= r->get_name().find( "TACAN", 0 );
string::size_type loc2 = r->get_name().find( "VORTAC", 0 );
if( loc1 != string::npos || loc2 != string::npos ){
//cout << " name = " << r->get_name() ;
//cout << " freq = " << r->get_freq() ;
tacanlist->add( r );
if( loc1 != string::npos || loc2 != string::npos) {
tacanlist->add(r);
}
dmelist->add( r );
break;
}
default:
throw sg_range_exception("got unsupported NavRecord type", "fgNavDBInit");
}
in >> skipcomment;
}
} // of stream data loop
// load the carrier navaids file
string file, name;
path = "";
path = globals->get_fg_root() ;
path.append( "Navaids/carrier_nav.dat" );
@ -160,16 +141,12 @@ bool fgNavDBInit( FGAirportList *airports,
//incarrier >> skipeol;
while ( ! incarrier.eof() ) {
FGNavRecord *r = new FGNavRecord;
incarrier >> (*r);
carrierlist->add ( r );
/*cout << " carrier lon: "<< r->get_lon() ;
cout << " carrier lat: "<< r->get_lat() ;
cout << " freq: " << r->get_freq() ;
cout << " carrier name: "<< r->get_name() << endl;*/
FGNavRecord *r = FGNavRecord::createFromStream(incarrier);
if (!r) {
continue;
}
//if ( r->get_type() > 95 ) {
// break;}
carrierlist->add (r);
} // end while
// end loading the carrier navaids file
@ -206,95 +183,3 @@ bool fgNavDBInit( FGAirportList *airports,
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 )
{
double hdg = rwy->headingDeg();
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->latitude(), rwy->longitude(), hdg,
rwy->lengthM() * 0.5,
&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->headingDeg();
// 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->headingDeg() );
}
}
// 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( FGAirportList *airports, FGNavList *loclist,
double threshold ) {
nav_map_type navmap = loclist->get_navaids();
nav_map_const_iterator freq = navmap.begin();
while ( freq != navmap.end() ) {
nav_list_type locs = freq->second;
nav_list_const_iterator loc = locs.begin();
while ( loc != locs.end() ) {
vector<string> parts = simgear::strutils::split((*loc)->get_name());
if (parts.size() < 2) {
SG_LOG(SG_GENERAL, SG_ALERT, "can't parse navaid " << (*loc)->get_ident()
<< " name for airport/runway:" << (*loc)->get_name());
continue;
}
FGAirport* airport = airports->search(parts[0]);
if (!airport) continue; // not found
FGRunway* r = airport->getRunwayByIdent(parts[1]);
update_loc_position( (*loc), r, threshold );
++loc;
}
++freq;
}
}

View file

@ -28,31 +28,14 @@
#include <simgear/compiler.h>
#include <simgear/misc/sg_path.hxx>
// #include <map>
// #include <vector>
// #include <string>
#include "navlist.hxx"
#include "fixlist.hxx"
// using std::map;
// using std::vector;
// using std::string;
// load and initialize the navigational databases
bool fgNavDBInit( FGAirportList *airports,
FGNavList *navlist, FGNavList *loclist, FGNavList *gslist,
bool fgNavDBInit( FGNavList *navlist, FGNavList *loclist, FGNavList *gslist,
FGNavList *dmelist, FGNavList *mkrbeacons,
FGNavList *tacanlist, FGNavList *carrierlist,
FGTACANList *channellist );
// 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( FGAirportList *airport, FGNavList *loclist,
double threshold );
#endif // _FG_NAVDB_HXX

View file

@ -33,14 +33,10 @@
// Return true if the nav record matches the type
static bool isTypeMatch(const FGNavRecord* n, fg_nav_types type) {
switch(type) {
case FG_NAV_ANY: return(true);
case FG_NAV_VOR: return(n->get_type() == 3);
case FG_NAV_NDB: return(n->get_type() == 2);
case FG_NAV_ILS: return(n->get_type() == 4); // Note - very simplified, only matches loc as part of full ILS.
default: return false;
}
static bool isTypeMatch(const FGNavRecord* n, fg_nav_types type)
{
if (type == FG_NAV_ANY) return true;
return type == n->type();
}
@ -177,10 +173,9 @@ nav_list_type FGNavList::findFirstByIdent( const string& ident, fg_nav_types typ
nav_list_type n2;
n2.clear();
int iType;
if(type == FG_NAV_VOR) iType = 3;
else if(type == FG_NAV_NDB) iType = 2;
else return(n2);
if ((type != FG_NAV_VOR) && (type != FG_NAV_NDB)) {
return n2;
}
nav_ident_map_iterator it;
if(exact) {
@ -195,7 +190,7 @@ nav_list_type FGNavList::findFirstByIdent( const string& ident, fg_nav_types typ
// Remove the types that don't match request.
for(nav_list_iterator it0 = n0.begin(); it0 != n0.end();) {
FGNavRecord* nv = *it0;
if(nv->get_type() == iType) {
if(nv->type() == type) {
typeMatch = true;
++it0;
} else {
@ -231,7 +226,7 @@ nav_list_type FGNavList::findFirstByIdent( const string& ident, fg_nav_types typ
n2.clear();
for(nav_list_iterator it2 = n1.begin(); it2 != n1.end(); ++it2) {
FGNavRecord* nv = *it2;
if(nv->get_type() == iType) n2.push_back(nv);
if(nv->type() == type) n2.push_back(nv);
}
return(n2);
}
@ -261,6 +256,48 @@ FGNavRecord *FGNavList::findByIdentAndFreq( const char* ident, const double freq
return NULL;
}
// LOC, ILS, GS, and DME antenna's could potentially be
// installed at the opposite end of the runway. So it's not
// enough to simply find the closest antenna with the right
// frequency. We need the closest antenna with the right
// frequency that is most oriented towards us. (We penalize
// stations that are facing away from us by adding 5000 meters
// which is further than matching stations would ever be
// placed from each other. (Do the expensive check only for
// directional atennas and only when there is a chance it is
// the closest station.)
static bool penaltyForNav(FGNavRecord* aNav, const SGVec3d &aPos)
{
switch (aNav->type()) {
case FGPositioned::ILS:
case FGPositioned::LOC:
case FGPositioned::GS:
// FIXME
// case FGPositioned::DME: we can't get the heading for a DME transmitter, oops
break;
default:
return false;
}
double hdg_deg = 0.0;
if (aNav->type() == FGPositioned::GS) {
int tmp = (int)(aNav->get_multiuse() / 1000.0);
hdg_deg = aNav->get_multiuse() - (tmp * 1000);
} else {
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);
az1 = az1 - hdg_deg;
if ( az1 > 180.0) az1 -= 360.0;
if ( az1 < -180.0) az1 += 360.0;
return fabs(az1 > 90.0);
}
// Given a point and a list of stations, return the closest one to the
// specified point.
@ -279,53 +316,11 @@ FGNavRecord *FGNavList::findNavFromList( const SGVec3d &aircraft,
FGNavRecord *station = *it;
// cout << "testing " << current->get_ident() << endl;
d2 = distSqr(station->get_cart(), aircraft);
// cout << " dist = " << sqrt(d)
// << " range = " << current->get_range() * SG_NM_TO_METER
// << endl;
// LOC, ILS, GS, and DME antenna's could potentially be
// installed at the opposite end of the runway. So it's not
// enough to simply find the closest antenna with the right
// frequency. We need the closest antenna with the right
// frequency that is most oriented towards us. (We penalize
// stations that are facing away from us by adding 5000 meters
// which is further than matching stations would ever be
// placed from each other. (Do the expensive check only for
// directional atennas and only when there is a chance it is
// the closest station.)
int type = station->get_type();
if ( d2 < min_dist &&
(type == 4 || type == 5 || type == 6 || type == 12 || type == 13) )
if ( d2 < min_dist && penaltyForNav(station, aircraft))
{
double hdg_deg = 0.0;
if ( type == 4 || type == 5 ){
hdg_deg = station->get_multiuse();
} else if ( type == 6 ) {
int tmp = (int)(station->get_multiuse() / 1000.0);
hdg_deg = station->get_multiuse() - (tmp * 1000);
} else if ( type == 12 || type == 13 ) {
// oops, Robin's data format doesn't give us the
// needed information to compute a heading for a DME
// transmitter. FIXME Robin!
}
double az1 = 0.0, az2 = 0.0, s = 0.0;
SGGeod geod = SGGeod::fromCart(aircraft);
geo_inverse_wgs_84( geod, station->get_pos(), &az1, &az2, &s);
az1 = az1 - station->get_multiuse();
if ( az1 > 180.0) az1 -= 360.0;
if ( az1 < -180.0) az1 += 360.0;
// penalize opposite facing stations by adding 5000 meters
// (squared) which is further than matching stations would
// ever be placed from each other.
if ( fabs(az1) > 90.0 ) {
double dist = sqrt(d2);
d2 = (dist + 5000) * (dist + 5000);
}
}
if ( d2 < min_dist ) {
min_dist = d2;

View file

@ -94,7 +94,7 @@ public:
// (by ASCII code value) to that supplied.
// Supplying true for exact forces only exact matches to be returned (similar to above function)
// Returns an empty list if no match found - calling function should check for this!
nav_list_type findFirstByIdent( const string& ident, fg_nav_types type, bool exact = false );
nav_list_type findFirstByIdent( const string& ident, FGPositioned::Type type, bool exact = false );
// Given an Ident and optional freqency, return the first matching
// station.
@ -102,7 +102,8 @@ public:
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, fg_nav_types type = FG_NAV_ANY );
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 );

View file

@ -25,111 +25,183 @@
#endif
#include <istream>
#include <simgear/misc/sgstream.hxx>
#include <simgear/structure/exception.hxx>
#include <simgear/misc/strutils.hxx>
#include <simgear/debug/logstream.hxx>
#include "Navaids/navrecord.hxx"
#include "Airports/simple.hxx"
#include "Airports/runways.hxx"
#include "Main/fg_props.hxx"
FGNavRecord::FGNavRecord(void) :
type(0),
pos(SGGeod::fromDeg(0, 0)),
cart(0, 0, 0),
freq(0),
range(0),
multiuse(0.0),
ident(""),
name(""),
apt_id(""),
serviceable(true),
trans_ident("")
{
}
FGNavRecord::FGNavRecord(int aTy, const std::string& aIdent,
const std::string& aName, const std::string& aAirport,
double lat, double lon, int aFreq, int aRange, double aMultiuse) :
type(aTy),
FGNavRecord::FGNavRecord(Type aTy, const std::string& aIdent,
const std::string& aName,
double lat, double lon, double aElevFt,
int aFreq, int aRange, double aMultiuse) :
FGPositioned(aTy, aIdent, lat, lon, aElevFt),
freq(aFreq),
range(aRange),
multiuse(aMultiuse),
ident(aIdent),
name(aName),
apt_id(aAirport),
serviceable(true),
trans_ident(aIdent)
{
pos = SGGeod::fromDeg(lon, lat);
cart = SGVec3d::fromGeod(pos);
}
fg_nav_types FGNavRecord::get_fg_type() const {
switch(type) {
case 2: return(FG_NAV_NDB);
case 3: return(FG_NAV_VOR);
case 4: return(FG_NAV_ILS);
default: return(FG_NAV_ANY);
}
}
std::istream& operator>>( std::istream& in, FGNavRecord& n )
{
in >> n.type;
if ( n.type == 99 ) {
return in >> skipeol;
}
double lat, lon, elev_ft;
in >> lat >> lon >> elev_ft >> n.freq >> n.range >> n.multiuse
>> n.ident;
n.pos.setLatitudeDeg(lat);
n.pos.setLongitudeDeg(lon);
n.pos.setElevationFt(elev_ft);
getline( in, n.name );
// silently multiply adf frequencies by 100 so that adf
// vs. nav/loc frequency lookups can use the same code.
if ( n.type == 2 ) {
n.freq *= 100;
}
// Remove any leading spaces before the name
while ( n.name.substr(0,1) == " " ) {
n.name = n.name.erase(0,1);
}
if ( n.type >= 4 && n.type <= 9 ) {
// these types are always associated with an airport id
std::string::size_type pos = n.name.find(" ");
n.apt_id = n.name.substr(0, pos);
}
initAirportRelation();
// Ranges are included with the latest data format, no need to
// assign our own defaults, unless the range is not set for some
// reason.
if (range < 0.1) {
SG_LOG(SG_GENERAL, SG_WARN, "navaid " << ident() << " has no range set, using defaults");
switch (type()) {
case NDB:
case VOR:
range = FG_NAV_DEFAULT_RANGE;
break;
if ( n.range < 0.1 ) {
// assign default ranges
case LOC:
case ILS:
case GS:
range = FG_LOC_DEFAULT_RANGE;
break;
if ( n.type == 2 || n.type == 3 ) {
n.range = FG_NAV_DEFAULT_RANGE;
} else if ( n.type == 4 || n.type == 5 || n.type == 6 ) {
n.range = FG_LOC_DEFAULT_RANGE;
} else if ( n.type == 12 ) {
n.range = FG_DME_DEFAULT_RANGE;
} else {
n.range = FG_LOC_DEFAULT_RANGE;
case DME:
range = FG_DME_DEFAULT_RANGE;
break;
default:
range = FG_LOC_DEFAULT_RANGE;
}
}
// transmitted ident (same as ident unless modeling a fault)
n.trans_ident = n.ident;
// generate cartesian coordinates
n.cart = SGVec3d::fromGeod(n.pos);
return in;
}
SGVec3d FGNavRecord::get_cart() const
{
return SGVec3d::fromGeod(geod());
}
static FGPositioned::Type
mapRobinTypeToFGPType(int aTy)
{
switch (aTy) {
// case 1:
case 2: return FGPositioned::NDB;
case 3: return FGPositioned::VOR;
case 4: return FGPositioned::LOC;
case 5: return FGPositioned::ILS;
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 recgonize", "FGNavRecord::createFromStream");
}
}
FGNavRecord* FGNavRecord::createFromStream(std::istream& aStream)
{
int rawType;
aStream >> rawType;
if (aStream.eof()) {
return NULL; // happens with, eg, carrier_nav.dat
}
Type type = mapRobinTypeToFGPType(rawType);
if (type == INVALID) return NULL;
double lat, lon, elev_ft, multiuse;
int freq, range;
std::string apt_id, name, ident;
aStream >> lat >> lon >> elev_ft >> freq >> range >> multiuse >> ident;
getline(aStream, name);
// silently multiply adf frequencies by 100 so that adf
// vs. nav/loc frequency lookups can use the same code.
if (type == NDB) {
freq *= 100;
}
FGNavRecord* result = new FGNavRecord(type, ident,
simgear::strutils::strip(name),
lat, lon, elev_ft, freq, range, multiuse);
return result;
}
void FGNavRecord::initAirportRelation()
{
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);
if (!apt) {
SG_LOG(SG_GENERAL, SG_WARN, "navaid " << ident() << " associated with bogus airport ID:" << apt_id);
return;
}
// fudge elevation to the field elevation if it's not specified
if (fabs(elevation()) < 0.01) {
mPosition.setElevationFt(apt->getElevation());
}
// align localizers with their runway
if ((type() == ILS) || (type() == LOC)) {
if (!fgGetBool("/sim/navdb/localizers/auto-align", true)) {
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]);
alignLocaliserWithRunway(runway, threshold);
}
}
void FGNavRecord::alignLocaliserWithRunway(FGRunway* aRunway, double aThreshold)
{
// find the distance from the threshold to the localizer
SGGeod runwayThreshold(aRunway->threshold());
double dist, az1, az2;
SGGeodesy::inverse(mPosition, runwayThreshold, az1, az2, dist);
// back project that distance along the runway center line
SGGeod newPos = aRunway->pointOnCenterline(dist);
double hdg_diff = get_multiuse() - aRunway->headingDeg();
// 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) <= aThreshold ) {
mPosition = newPos;
set_multiuse( aRunway->headingDeg() );
} else {
SG_LOG(SG_GENERAL, SG_WARN, "localizer:" << ident() << ", aligning with runway "
<< aRunway->_rwy_no << " exceeded heading threshold");
}
}
FGTACANRecord::FGTACANRecord(void) :
channel(""),

View file

@ -26,36 +26,33 @@
#include <iosfwd>
#include <simgear/math/SGMath.hxx>
#include <simgear/structure/SGReferenced.hxx>
#include "positioned.hxx"
#define FG_NAV_DEFAULT_RANGE 50 // nm
#define FG_LOC_DEFAULT_RANGE 18 // nm
#define FG_DME_DEFAULT_RANGE 50 // nm
#define FG_NAV_MAX_RANGE 300 // nm
// Shield the rest of FG from possibly changing details of Robins navaid type numbering system.
// Currently only the GPS code uses this - extra types (LOC, GS etc) may need to be added
// should other FG code choose to use this.
enum fg_nav_types {
FG_NAV_VOR,
FG_NAV_NDB,
FG_NAV_ILS,
FG_NAV_ANY
};
// FIXME - get rid of these, and use the real enum directly
#define FG_NAV_VOR FGPositioned::VOR
#define FG_NAV_NDB FGPositioned::NDB
#define FG_NAV_ILS FGPositioned::ILS
#define FG_NAV_ANY FGPositioned::INVALID
class FGNavRecord : public SGReferenced {
typedef FGPositioned::Type fg_nav_types;
// forward decls
class FGRunway;
class FGNavRecord : public FGPositioned
{
int type;
SGGeod pos; // location in geodetic coords (degrees)
SGVec3d cart; // location in cartesian coords (earth centered)
int freq;
int range;
double multiuse; // can be slaved variation of VOR
// (degrees) or localizer heading
// (degrees) or dme bias (nm)
std::string ident; // navaid ident
std::string name; // verbose name in nav database
std::string apt_id; // corresponding airport id
@ -63,36 +60,41 @@ class FGNavRecord : public SGReferenced {
bool serviceable; // for failure modeling
std::string trans_ident; // for failure modeling
/**
* Helper to init data when a navrecord is associated with an airport
*/
void initAirportRelation();
void alignLocaliserWithRunway(FGRunway* aRunway, double aThreshold);
public:
FGNavRecord(void);
inline ~FGNavRecord(void) {}
FGNavRecord(int type, const std::string& ident, const std::string& name, const std::string& airport,
double lat, double lon, int freq, int range, double multiuse);
static FGNavRecord* createFromStream(std::istream& aStream);
inline int get_type() const { return type; }
FGNavRecord(Type type, const std::string& ident, const std::string& name,
double lat, double lon, double aElevFt,
int freq, int range, double multiuse);
fg_nav_types get_fg_type() const;
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 double get_lon() const { return pos.getLongitudeDeg(); } // degrees
inline void set_lon( double l ) { pos.setLongitudeDeg(l); } // degrees
inline double get_lat() const { return pos.getLatitudeDeg(); } // degrees
inline void set_lat( double l ) { pos.setLatitudeDeg(l); } // degrees
inline double get_elev_ft() const { return pos.getElevationFt(); }
inline void set_elev_ft( double e ) { pos.setElevationFt(e); }
const SGGeod& get_pos() const { return pos; }
const SGVec3d& get_cart() const { return cart; }
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 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(); }
friend std::istream& operator>> ( std::istream&, FGNavRecord& );
};
class FGTACANRecord : public SGReferenced {