#include <simgear/compiler.h>
-#include STL_STRING
+#include <string>
#include <simgear/debug/logstream.hxx>
-
-#include <Airports/runways.hxx>
-#include <Airports/simple.hxx>
-#include <Main/globals.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>
+#include <Navaids/markerbeacon.hxx>
+#include <Airports/simple.hxx>
+
+using std::string;
-SG_USING_STD( string );
+static FGPositioned::Type
+mapRobinTypeToFGPType(int aTy)
+{
+ switch (aTy) {
+ // case 1:
+ case 2: return FGPositioned::NDB;
+ case 3: return FGPositioned::VOR;
+ case 4: return FGPositioned::ILS;
+ case 5: return FGPositioned::LOC;
+ case 6: return FGPositioned::GS;
+ 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 recognize", "FGNavRecord::createFromStream");
+ }
+}
+static FGNavRecord* createNavFromStream(std::istream& aStream)
+{
+ int rawType;
+ aStream >> rawType;
+ if (aStream.eof() || (rawType == 99)) {
+ return NULL; // happens with, eg, carrier_nav.dat
+ }
+
+ double lat, lon, elev_ft, multiuse;
+ int freq, range;
+ std::string name, ident;
+ aStream >> lat >> lon >> elev_ft >> freq >> range >> multiuse >> ident;
+ getline(aStream, name);
+
+ SGGeod pos(SGGeod::fromDegFt(lon, lat, elev_ft));
+ name = simgear::strutils::strip(name);
+
+ if ((rawType >= 7) && (rawType <= 9)) {
+ // marker beacons use a different run-time class now
+ FGMarkerBeaconRecord::create(rawType, name, pos);
+ return NULL; // not a nav-record, but that's okay
+ }
+
+ FGPositioned::Type type = mapRobinTypeToFGPType(rawType);
+ if (type == FGPositioned::INVALID) {
+ return NULL;
+ }
+
+ // silently multiply adf frequencies by 100 so that adf
+ // vs. nav/loc frequency lookups can use the same code.
+ if (type == FGPositioned::NDB) {
+ freq *= 100;
+ }
+
+ return new FGNavRecord(type, ident, name, pos,
+ freq, range, multiuse);
+}
// load and initialize the navigational databases
-bool fgNavDBInit( FGAirportList *airports,
- FGNavList *navlist, FGNavList *loclist, FGNavList *gslist,
- FGNavList *dmelist, FGNavList *mkrlist,
+bool fgNavDBInit( FGNavList *navlist, FGNavList *loclist, FGNavList *gslist,
+ FGNavList *dmelist,
FGNavList *tacanlist, FGNavList *carrierlist,
FGTACANList *channellist)
{
SG_LOG(SG_GENERAL, SG_INFO, "Loading Navaid Databases");
- // SG_LOG(SG_GENERAL, SG_INFO, " VOR/NDB");
- // SGPath p_nav( globals->get_fg_root() );
- // p_nav.append( "Navaids/default.nav" );
- // navlist->init( p_nav );
-
- // SG_LOG(SG_GENERAL, SG_INFO, " ILS and Marker Beacons");
- // beacons->init();
- // SGPath p_ils( globals->get_fg_root() );
- // p_ils.append( "Navaids/default.ils" );
- // ilslist->init( p_ils );
-
SGPath path( globals->get_fg_root() );
path.append( "Navaids/nav.dat" );
in >> skipeol;
in >> skipeol;
-
-#ifdef __MWERKS__
- char c = 0;
- while ( in.get(c) && c != '\0' ) {
- in.putback(c);
-#else
- while ( ! in.eof() ) {
-#endif
-
- FGNavRecord *r = new FGNavRecord;
- in >> (*r);
- if ( r->get_type() > 95 ) {
- break;
+ while (!in.eof()) {
+ FGNavRecord *r = createNavFromStream(in);
+ if (!r) {
+ continue;
+ }
+
+ switch (r->type()) {
+ case FGPositioned::NDB:
+ case FGPositioned::VOR:
+ navlist->add(r);
+ break;
+
+ case FGPositioned::ILS:
+ case FGPositioned::LOC:
+ loclist->add(r);
+ break;
+
+ case FGPositioned::GS:
+ gslist->add(r);
+ break;
+
+ case FGPositioned::DME:
+ {
+ dmelist->add(r);
+ 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);
}
- /*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; */
+ break;
+ }
+
+ default:
+ throw sg_range_exception("got unsupported NavRecord type", "fgNavDBInit");
+ }
- // 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;
- }
- }
-
- 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 )
- {
- // 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 );
-
- if( loc1 != string::npos || loc2 != string::npos ){
- //cout << " name = " << r->get_name() ;
- //cout << " freq = " << r->get_freq() ;
- tacanlist->add( r );
- }
-
- dmelist->add( r );
-
- }
-
- in >> skipcomment;
- }
+ 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" );
//incarrier >> skipeol;
//incarrier >> skipeol;
-#ifdef __MWERKS__
- char c = 0;
- while ( incarrier.get(c) && c != '\0' ) {
- incarrier.putback(c);
-#else
while ( ! incarrier.eof() ) {
-#endif
-
- 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;*/
-
- //if ( r->get_type() > 95 ) {
- // break;}
+ FGNavRecord *r = createNavFromStream(incarrier);
+ if (!r) {
+ continue;
+ }
+
+ carrierlist->add (r);
} // end while
// end loading the carrier navaids file
// skip first line
inchannel >> skipeol;
-
-#ifdef __MWERKS__
- char c = 0;
- while ( inchannel.get(c) && c != '\0' ) {
- in.putback(c);
-#else
while ( ! inchannel.eof() ) {
-#endif
-
FGTACANRecord *r = new FGTACANRecord;
inchannel >> (*r);
channellist->add ( r );
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 )
+FGRunway* getRunwayFromName(const std::string& aName)
{
- double hdg = rwy->_heading;
- 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->_lat, rwy->_lon, hdg,
- rwy->_length/2.0 * SG_FEET_TO_METER,
- &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->_heading;
-
- // 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->_heading );
- }
-}
-
-
-// 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( FGRunwayList *runways, 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() ) {
- string name = (*loc)->get_name();
- string::size_type pos1 = name.find(" ");
- string id = name.substr(0, pos1);
- name = name.substr(pos1+1);
- string::size_type pos2 = name.find(" ");
- string rwy = name.substr(0, pos2);
-
- FGRunway r;
- if ( runways->search(id, rwy, &r) ) {
- update_loc_position( (*loc), &r, threshold );
- }
- ++loc;
- }
- ++freq;
- }
+ vector<string> parts = simgear::strutils::split(aName);
+ if (parts.size() < 2) {
+ SG_LOG(SG_GENERAL, SG_WARN, "getRunwayFromName: malformed name:" << aName);
+ return NULL;
+ }
+
+ const FGAirport* apt = fgFindAirportID(parts[0]);
+ if (!apt) {
+ SG_LOG(SG_GENERAL, SG_WARN, "navaid " << aName << " associated with bogus airport ID:" << parts[0]);
+ return NULL;
+ }
+
+ if (!apt->hasRunwayWithIdent(parts[1])) {
+ SG_LOG(SG_GENERAL, SG_WARN, "navaid " << aName << " associated with bogus runway ID:" << parts[1]);
+ return NULL;
+ }
+
+ return apt->getRunwayByIdent(parts[1]);
}
-