2002-06-07 21:03:27 +00:00
|
|
|
// navlist.cxx -- navaids management class
|
2000-04-21 04:19:22 +00:00
|
|
|
//
|
|
|
|
// Written by Curtis Olson, started April 2000.
|
|
|
|
//
|
2004-11-19 22:10:41 +00:00
|
|
|
// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
|
2000-04-21 04:19:22 +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.
|
2000-04-21 04:19:22 +00:00
|
|
|
//
|
|
|
|
// $Id$
|
|
|
|
|
|
|
|
|
2001-05-15 22:30:39 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include <config.h>
|
|
|
|
#endif
|
|
|
|
|
2000-04-21 04:19:22 +00:00
|
|
|
#include <simgear/debug/logstream.hxx>
|
2000-09-27 20:16:22 +00:00
|
|
|
#include <simgear/math/sg_geodesy.hxx>
|
2008-12-25 23:11:43 +00:00
|
|
|
#include <simgear/sg_inlines.h>
|
2000-04-21 04:19:22 +00:00
|
|
|
|
2000-04-21 16:03:36 +00:00
|
|
|
#include "navlist.hxx"
|
2000-04-21 04:19:22 +00:00
|
|
|
|
2008-12-25 23:11:43 +00:00
|
|
|
using std::string;
|
2000-04-21 04:19:22 +00:00
|
|
|
|
2006-07-10 07:59:20 +00:00
|
|
|
// FGNavList ------------------------------------------------------------------
|
|
|
|
|
|
|
|
FGNavList::FGNavList( void )
|
|
|
|
{
|
2005-10-01 09:56:53 +00:00
|
|
|
}
|
|
|
|
|
2000-04-21 04:19:22 +00:00
|
|
|
|
2006-07-10 07:59:20 +00:00
|
|
|
FGNavList::~FGNavList( void )
|
|
|
|
{
|
2007-10-20 08:36:21 +00:00
|
|
|
nav_list_type navlist = navaids.begin()->second;
|
|
|
|
navaids.erase( navaids.begin(), navaids.end() );
|
2000-04-21 04:19:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// load the navaids and build the map
|
2006-07-10 07:59:20 +00:00
|
|
|
bool FGNavList::init()
|
|
|
|
{
|
2007-10-20 08:36:21 +00:00
|
|
|
// No need to delete the original navaid structures
|
|
|
|
// since we're using an SGSharedPointer
|
|
|
|
nav_list_type navlist = navaids.begin()->second;
|
2000-04-21 04:19:22 +00:00
|
|
|
navaids.erase( navaids.begin(), navaids.end() );
|
2004-05-28 05:24:54 +00:00
|
|
|
return true;
|
|
|
|
}
|
2000-04-21 04:19:22 +00:00
|
|
|
|
2004-05-28 05:24:54 +00:00
|
|
|
// add an entry to the lists
|
2006-07-10 07:59:20 +00:00
|
|
|
bool FGNavList::add( FGNavRecord *n )
|
|
|
|
{
|
2004-05-28 05:24:54 +00:00
|
|
|
navaids[n->get_freq()].push_back(n);
|
2000-04-21 04:19:22 +00:00
|
|
|
return true;
|
|
|
|
}
|
2000-04-21 05:26:24 +00:00
|
|
|
|
2008-12-25 23:11:43 +00:00
|
|
|
FGNavRecord *FGNavList::findByFreq( double freq, const SGGeod& position)
|
2000-04-21 05:26:24 +00:00
|
|
|
{
|
2006-06-15 19:16:21 +00:00
|
|
|
const nav_list_type& stations = navaids[(int)(freq*100.0 + 0.5)];
|
2005-10-01 09:56:53 +00:00
|
|
|
SG_LOG( SG_INSTR, SG_DEBUG, "findbyFreq " << freq << " size " << stations.size() );
|
2008-12-25 23:11:43 +00:00
|
|
|
return findNavFromList( position, stations );
|
2002-06-07 21:03:27 +00:00
|
|
|
}
|
|
|
|
|
2008-12-25 23:11:43 +00:00
|
|
|
class VORNDBFilter : public FGPositioned::Filter
|
2002-06-07 21:03:27 +00:00
|
|
|
{
|
2008-12-25 23:11:43 +00:00
|
|
|
public:
|
2009-01-08 21:11:53 +00:00
|
|
|
virtual FGPositioned::Type minType() const {
|
|
|
|
return FGPositioned::VOR;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual FGPositioned::Type maxType() const {
|
|
|
|
return FGPositioned::NDB;
|
2008-12-25 23:11:43 +00:00
|
|
|
}
|
|
|
|
};
|
2005-11-28 22:42:23 +00:00
|
|
|
|
2003-01-25 20:45:39 +00:00
|
|
|
// Given an Ident and optional freqency, return the first matching
|
|
|
|
// station.
|
2008-12-25 23:11:43 +00:00
|
|
|
FGNavRecord *FGNavList::findByIdentAndFreq(const string& ident, const double freq )
|
2003-01-05 00:10:36 +00:00
|
|
|
{
|
2008-12-25 23:11:43 +00:00
|
|
|
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;
|
2003-01-05 00:10:36 +00:00
|
|
|
}
|
2008-12-25 23:11:43 +00:00
|
|
|
|
|
|
|
cur = FGPositioned::findNextWithPartialId(cur, ident, &filter);
|
|
|
|
}
|
2003-01-05 00:10:36 +00:00
|
|
|
|
2008-12-25 23:11:43 +00:00
|
|
|
return NULL;
|
2003-01-05 00:10:36 +00:00
|
|
|
}
|
|
|
|
|
2008-09-12 08:46:15 +00:00
|
|
|
// 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.)
|
|
|
|
|
2008-12-25 23:11:43 +00:00
|
|
|
static bool penaltyForNav(FGNavRecord* aNav, const SGGeod &aGeod)
|
2008-09-12 08:46:15 +00:00
|
|
|
{
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2008-12-25 23:11:43 +00:00
|
|
|
double az1, az2, s;
|
|
|
|
SGGeodesy::inverse(aGeod, aNav->geod(), az1, az2, s);
|
2008-09-12 08:46:15 +00:00
|
|
|
az1 = az1 - hdg_deg;
|
2008-12-25 23:11:43 +00:00
|
|
|
SG_NORMALIZE_RANGE(az1, -180.0, 180.0);
|
2008-09-13 09:20:47 +00:00
|
|
|
return fabs(az1) > 90.0;
|
2008-09-12 08:46:15 +00:00
|
|
|
}
|
2003-01-05 00:10:36 +00:00
|
|
|
|
2003-01-25 20:45:39 +00:00
|
|
|
// Given a point and a list of stations, return the closest one to the
|
|
|
|
// specified point.
|
2008-12-25 23:11:43 +00:00
|
|
|
FGNavRecord *FGNavList::findNavFromList( const SGGeod &aircraft,
|
2004-05-28 05:24:54 +00:00
|
|
|
const nav_list_type &stations )
|
2002-06-07 21:03:27 +00:00
|
|
|
{
|
2004-05-28 05:24:54 +00:00
|
|
|
FGNavRecord *nav = NULL;
|
2004-07-19 18:02:00 +00:00
|
|
|
double d2; // in meters squared
|
|
|
|
double min_dist
|
|
|
|
= FG_NAV_MAX_RANGE*SG_NM_TO_METER*FG_NAV_MAX_RANGE*SG_NM_TO_METER;
|
2008-12-25 23:11:43 +00:00
|
|
|
SGVec3d aircraftCart = SGVec3d::fromGeod(aircraft);
|
|
|
|
|
2007-10-11 15:33:24 +00:00
|
|
|
nav_list_const_iterator it;
|
|
|
|
nav_list_const_iterator end = stations.end();
|
2004-06-20 18:58:44 +00:00
|
|
|
// find the closest station within a sensible range (FG_NAV_MAX_RANGE)
|
2007-10-11 15:33:24 +00:00
|
|
|
for ( it = stations.begin(); it != end; ++it ) {
|
|
|
|
FGNavRecord *station = *it;
|
2006-07-10 07:59:20 +00:00
|
|
|
// cout << "testing " << current->get_ident() << endl;
|
2008-12-25 23:11:43 +00:00
|
|
|
d2 = distSqr(station->cart(), aircraftCart);
|
2008-09-12 08:46:15 +00:00
|
|
|
if ( d2 < min_dist && penaltyForNav(station, aircraft))
|
2004-07-19 18:02:00 +00:00
|
|
|
{
|
2008-09-12 08:46:15 +00:00
|
|
|
double dist = sqrt(d2);
|
|
|
|
d2 = (dist + 5000) * (dist + 5000);
|
2004-07-19 18:02:00 +00:00
|
|
|
}
|
2008-09-12 08:46:15 +00:00
|
|
|
|
2004-07-19 18:02:00 +00:00
|
|
|
if ( d2 < min_dist ) {
|
|
|
|
min_dist = d2;
|
2007-10-11 15:33:24 +00:00
|
|
|
nav = station;
|
2003-01-25 20:45:39 +00:00
|
|
|
}
|
2000-04-21 05:26:24 +00:00
|
|
|
}
|
|
|
|
|
2003-01-25 20:45:39 +00:00
|
|
|
return nav;
|
2000-04-21 05:26:24 +00:00
|
|
|
}
|
2004-05-28 05:24:54 +00:00
|
|
|
|
2006-07-10 07:59:20 +00:00
|
|
|
// Given a frequency, return the first matching station.
|
|
|
|
FGNavRecord *FGNavList::findStationByFreq( double freq )
|
2005-10-01 09:56:53 +00:00
|
|
|
{
|
2006-07-10 07:59:20 +00:00
|
|
|
const nav_list_type& stations = navaids[(int)(freq*100.0 + 0.5)];
|
|
|
|
|
|
|
|
SG_LOG( SG_INSTR, SG_DEBUG, "findStationByFreq " << freq << " size " << stations.size() );
|
|
|
|
|
2007-10-11 15:33:24 +00:00
|
|
|
if (!stations.empty()) {
|
2005-10-01 09:56:53 +00:00
|
|
|
return stations[0];
|
2006-07-10 07:59:20 +00:00
|
|
|
}
|
2005-10-01 09:56:53 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-07-10 07:59:20 +00:00
|
|
|
|
|
|
|
|
|
|
|
// FGTACANList ----------------------------------------------------------------
|
|
|
|
|
|
|
|
FGTACANList::FGTACANList( void )
|
2005-10-01 09:56:53 +00:00
|
|
|
{
|
2006-07-10 07:59:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FGTACANList::~FGTACANList( void )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool FGTACANList::init()
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// add an entry to the lists
|
|
|
|
bool FGTACANList::add( FGTACANRecord *c )
|
|
|
|
{
|
|
|
|
ident_channels[c->get_channel()].push_back(c);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Given a TACAN Channel return the first matching frequency
|
|
|
|
FGTACANRecord *FGTACANList::findByChannel( const string& channel )
|
|
|
|
{
|
|
|
|
const tacan_list_type& stations = ident_channels[channel];
|
|
|
|
SG_LOG( SG_INSTR, SG_DEBUG, "findByChannel " << channel<< " size " << stations.size() );
|
|
|
|
|
2007-10-11 15:33:24 +00:00
|
|
|
if (!stations.empty()) {
|
2005-10-01 09:56:53 +00:00
|
|
|
return stations[0];
|
2006-07-10 07:59:20 +00:00
|
|
|
}
|
2005-10-01 09:56:53 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2006-07-10 07:59:20 +00:00
|
|
|
|
|
|
|
|