2004-05-28 05:24:54 +00:00
|
|
|
// navdb.cxx -- top level navaids management routines
|
|
|
|
//
|
|
|
|
// Written by Curtis Olson, started May 2004.
|
|
|
|
//
|
2004-11-19 22:10:41 +00:00
|
|
|
// Copyright (C) 2004 Curtis L. Olson - http://www.flightgear.org/~curt
|
2004-05-28 05:24:54 +00:00
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU General Public License as
|
|
|
|
// published by the Free Software Foundation; either version 2 of the
|
|
|
|
// License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful, but
|
|
|
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
// General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program; if not, write to the Free Software
|
2006-02-21 01:16:04 +00:00
|
|
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2004-05-28 05:24:54 +00:00
|
|
|
//
|
|
|
|
// $Id$
|
|
|
|
|
2006-02-18 13:58:09 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
2004-05-28 05:24:54 +00:00
|
|
|
|
2004-05-28 16:24:43 +00:00
|
|
|
#include <simgear/compiler.h>
|
|
|
|
|
2008-07-25 18:38:29 +00:00
|
|
|
#include <string>
|
2004-05-28 16:24:43 +00:00
|
|
|
|
2004-05-28 05:24:54 +00:00
|
|
|
#include <simgear/debug/logstream.hxx>
|
2008-09-10 08:54:49 +00:00
|
|
|
#include <simgear/misc/sgstream.hxx>
|
|
|
|
|
2008-08-03 14:34:42 +00:00
|
|
|
#include <simgear/math/sg_geodesy.hxx>
|
2008-08-14 18:13:39 +00:00
|
|
|
#include <simgear/misc/strutils.hxx>
|
2004-05-28 05:24:54 +00:00
|
|
|
|
2004-05-28 16:24:43 +00:00
|
|
|
#include <Airports/runways.hxx>
|
2004-06-09 03:13:13 +00:00
|
|
|
#include <Airports/simple.hxx>
|
2004-05-28 05:24:54 +00:00
|
|
|
#include <Main/globals.hxx>
|
|
|
|
|
|
|
|
#include "navrecord.hxx"
|
|
|
|
#include "navdb.hxx"
|
|
|
|
|
2008-07-29 08:27:48 +00:00
|
|
|
using std::string;
|
2004-05-28 16:24:43 +00:00
|
|
|
|
2004-05-28 05:24:54 +00:00
|
|
|
|
|
|
|
// load and initialize the navigational databases
|
2004-06-09 03:13:13 +00:00
|
|
|
bool fgNavDBInit( FGAirportList *airports,
|
|
|
|
FGNavList *navlist, FGNavList *loclist, FGNavList *gslist,
|
2005-10-01 09:56:53 +00:00
|
|
|
FGNavList *dmelist, FGNavList *mkrlist,
|
|
|
|
FGNavList *tacanlist, FGNavList *carrierlist,
|
|
|
|
FGTACANList *channellist)
|
2004-05-28 05:24:54 +00:00
|
|
|
{
|
|
|
|
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" );
|
|
|
|
|
|
|
|
sg_gzifstream in( path.str() );
|
|
|
|
if ( !in.is_open() ) {
|
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << path.str() );
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// skip first two lines
|
|
|
|
in >> skipeol;
|
|
|
|
in >> skipeol;
|
|
|
|
|
|
|
|
while ( ! in.eof() ) {
|
|
|
|
FGNavRecord *r = new FGNavRecord;
|
|
|
|
in >> (*r);
|
|
|
|
if ( r->get_type() > 95 ) {
|
2007-02-09 05:35:10 +00:00
|
|
|
delete r;
|
2004-05-28 05:24:54 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2005-10-01 09:56:53 +00:00
|
|
|
/*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; */
|
2004-05-28 05:24:54 +00:00
|
|
|
|
2004-06-09 03:13:13 +00:00
|
|
|
// 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;
|
2005-09-20 20:26:57 +00:00
|
|
|
const FGAirport* a = airports->search( r->get_apt_id() );
|
|
|
|
if ( a ) {
|
|
|
|
r->set_elev_ft( a->getElevation() );
|
2004-06-09 03:13:13 +00:00
|
|
|
// cout << " setting to " << a.elevation << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-05-28 05:24:54 +00:00
|
|
|
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 );
|
2006-03-10 03:46:50 +00:00
|
|
|
} else if ( r->get_type() == 12 || r->get_type() == 13) {
|
|
|
|
// DME with ILS=12; standalone DME=13
|
2005-10-01 09:56:53 +00:00
|
|
|
string str1( r->get_name() );
|
2006-10-17 21:21:26 +00:00
|
|
|
string::size_type loc1= str1.find( "TACAN", 0 );
|
|
|
|
string::size_type loc2 = str1.find( "VORTAC", 0 );
|
2005-10-01 09:56:53 +00:00
|
|
|
|
|
|
|
if( loc1 != string::npos || loc2 != string::npos ){
|
|
|
|
//cout << " name = " << r->get_name() ;
|
|
|
|
//cout << " freq = " << r->get_freq() ;
|
|
|
|
tacanlist->add( r );
|
|
|
|
}
|
|
|
|
|
2004-05-28 05:24:54 +00:00
|
|
|
dmelist->add( r );
|
2005-10-01 09:56:53 +00:00
|
|
|
|
2004-05-28 05:24:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
in >> skipcomment;
|
|
|
|
}
|
|
|
|
|
2005-10-01 09:56:53 +00:00
|
|
|
// load the carrier navaids file
|
|
|
|
|
|
|
|
string file, name;
|
|
|
|
path = "";
|
|
|
|
path = globals->get_fg_root() ;
|
|
|
|
path.append( "Navaids/carrier_nav.dat" );
|
|
|
|
|
|
|
|
file = path.str();
|
2005-12-06 18:48:56 +00:00
|
|
|
SG_LOG( SG_GENERAL, SG_INFO, "opening file: " << path.str() );
|
2005-10-01 09:56:53 +00:00
|
|
|
|
|
|
|
sg_gzifstream incarrier( path.str() );
|
|
|
|
|
|
|
|
if ( !incarrier.is_open() ) {
|
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << path.str() );
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// skip first two lines
|
|
|
|
//incarrier >> skipeol;
|
|
|
|
//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;*/
|
|
|
|
|
|
|
|
//if ( r->get_type() > 95 ) {
|
|
|
|
// break;}
|
|
|
|
} // end while
|
|
|
|
|
|
|
|
// end loading the carrier navaids file
|
|
|
|
|
|
|
|
// load the channel/freqency file
|
|
|
|
string channel, freq;
|
|
|
|
path="";
|
|
|
|
path = globals->get_fg_root();
|
|
|
|
path.append( "Navaids/TACAN_freq.dat" );
|
|
|
|
|
2005-12-06 18:48:56 +00:00
|
|
|
SG_LOG( SG_GENERAL, SG_INFO, "opening file: " << path.str() );
|
|
|
|
|
2005-10-01 09:56:53 +00:00
|
|
|
sg_gzifstream inchannel( path.str() );
|
|
|
|
|
|
|
|
if ( !inchannel.is_open() ) {
|
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << path.str() );
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
2005-10-02 17:57:16 +00:00
|
|
|
// skip first line
|
2005-10-01 09:56:53 +00:00
|
|
|
inchannel >> skipeol;
|
|
|
|
while ( ! inchannel.eof() ) {
|
|
|
|
FGTACANRecord *r = new FGTACANRecord;
|
|
|
|
inchannel >> (*r);
|
|
|
|
channellist->add ( r );
|
|
|
|
//cout << "channel = " << r->get_channel() ;
|
|
|
|
//cout << " freq = " << r->get_freq() << endl;
|
|
|
|
|
|
|
|
} // end while
|
|
|
|
|
|
|
|
|
|
|
|
// end ReadChanFile
|
|
|
|
|
2004-05-28 05:24:54 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2004-05-28 16:24:43 +00:00
|
|
|
|
|
|
|
|
|
|
|
// Given a localizer record and it's corresponding runway record,
|
|
|
|
// adjust the localizer position so it is in perfect alignment with
|
|
|
|
// the runway.
|
2004-05-28 20:57:05 +00:00
|
|
|
static void update_loc_position( FGNavRecord *loc, FGRunway *rwy,
|
|
|
|
double threshold )
|
|
|
|
{
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
double hdg = rwy->headingDeg();
|
2004-05-28 16:24:43 +00:00
|
|
|
hdg += 180.0;
|
|
|
|
if ( hdg > 360.0 ) {
|
|
|
|
hdg -= 360.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// calculate runway threshold point
|
|
|
|
double thresh_lat, thresh_lon, return_az;
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
geo_direct_wgs_84 ( 0.0, rwy->latitude(), rwy->longitude(), hdg,
|
|
|
|
rwy->lengthM() * 0.5,
|
2004-05-28 16:24:43 +00:00
|
|
|
&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;
|
2004-12-22 23:57:07 +00:00
|
|
|
// cout << "new heading = " << rwy->_heading << endl;
|
2004-05-28 20:57:05 +00:00
|
|
|
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
double hdg_diff = loc->get_multiuse() - rwy->headingDeg();
|
2004-05-28 20:57:05 +00:00
|
|
|
|
|
|
|
// 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 );
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
loc->set_multiuse( rwy->headingDeg() );
|
2004-05-28 20:57:05 +00:00
|
|
|
}
|
2004-05-28 16:24:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 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.
|
2008-08-14 18:13:39 +00:00
|
|
|
void fgNavDBAlignLOCwithRunway( FGAirportList *airports, FGNavList *loclist,
|
2004-05-28 20:57:05 +00:00
|
|
|
double threshold ) {
|
2004-05-28 16:24:43 +00:00
|
|
|
nav_map_type navmap = loclist->get_navaids();
|
|
|
|
|
2005-10-26 09:03:49 +00:00
|
|
|
nav_map_const_iterator freq = navmap.begin();
|
2004-05-28 16:24:43 +00:00
|
|
|
while ( freq != navmap.end() ) {
|
|
|
|
nav_list_type locs = freq->second;
|
2005-10-26 09:03:49 +00:00
|
|
|
nav_list_const_iterator loc = locs.begin();
|
2004-05-28 16:24:43 +00:00
|
|
|
while ( loc != locs.end() ) {
|
2008-08-14 18:13:39 +00:00
|
|
|
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
|
|
|
|
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
FGRunway* r = airport->getRunwayByIdent(parts[1]);
|
|
|
|
update_loc_position( (*loc), r, threshold );
|
2008-08-14 18:13:39 +00:00
|
|
|
++loc;
|
2004-05-28 16:24:43 +00:00
|
|
|
}
|
|
|
|
++freq;
|
|
|
|
}
|
|
|
|
}
|
2005-10-01 09:56:53 +00:00
|
|
|
|