1 // navlist.cxx -- navaids management class
3 // Written by Curtis Olson, started April 2000.
5 // Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
28 #include <simgear/debug/logstream.hxx>
29 #include <simgear/math/sg_geodesy.hxx>
30 #include <simgear/sg_inlines.h>
32 #include "navlist.hxx"
36 // FGNavList ------------------------------------------------------------------
38 FGNavList::FGNavList( void )
43 FGNavList::~FGNavList( void )
45 nav_list_type navlist = navaids.begin()->second;
46 navaids.erase( navaids.begin(), navaids.end() );
50 // load the navaids and build the map
51 bool FGNavList::init()
53 // No need to delete the original navaid structures
54 // since we're using an SGSharedPointer
55 nav_list_type navlist = navaids.begin()->second;
56 navaids.erase( navaids.begin(), navaids.end() );
60 // add an entry to the lists
61 bool FGNavList::add( FGNavRecord *n )
63 navaids[n->get_freq()].push_back(n);
67 FGNavRecord *FGNavList::findByFreq( double freq, const SGGeod& position)
69 const nav_list_type& stations = navaids[(int)(freq*100.0 + 0.5)];
70 SG_LOG( SG_INSTR, SG_DEBUG, "findbyFreq " << freq << " size " << stations.size() );
71 return findNavFromList( position, stations );
74 class VORNDBFilter : public FGPositioned::Filter
77 virtual bool pass(FGPositioned* aPos) const
79 return (aPos->type() == FGPositioned::VOR) || (aPos->type() == FGPositioned::NDB);
83 // Given an Ident and optional freqency, return the first matching
85 FGNavRecord *FGNavList::findByIdentAndFreq(const string& ident, const double freq )
89 cur = FGPositioned::findNextWithPartialId(cur, ident, &filter);
92 return static_cast<FGNavRecord*>(cur.ptr()); // might be null
95 int f = (int)(freq*100.0 + 0.5);
97 FGNavRecord* nav = static_cast<FGNavRecord*>(cur.ptr());
98 if (nav->get_freq() == f) {
102 cur = FGPositioned::findNextWithPartialId(cur, ident, &filter);
108 // LOC, ILS, GS, and DME antenna's could potentially be
109 // installed at the opposite end of the runway. So it's not
110 // enough to simply find the closest antenna with the right
111 // frequency. We need the closest antenna with the right
112 // frequency that is most oriented towards us. (We penalize
113 // stations that are facing away from us by adding 5000 meters
114 // which is further than matching stations would ever be
115 // placed from each other. (Do the expensive check only for
116 // directional atennas and only when there is a chance it is
117 // the closest station.)
119 static bool penaltyForNav(FGNavRecord* aNav, const SGGeod &aGeod)
121 switch (aNav->type()) {
122 case FGPositioned::ILS:
123 case FGPositioned::LOC:
124 case FGPositioned::GS:
126 // case FGPositioned::DME: we can't get the heading for a DME transmitter, oops
132 double hdg_deg = 0.0;
133 if (aNav->type() == FGPositioned::GS) {
134 int tmp = (int)(aNav->get_multiuse() / 1000.0);
135 hdg_deg = aNav->get_multiuse() - (tmp * 1000);
137 hdg_deg = aNav->get_multiuse();
141 SGGeodesy::inverse(aGeod, aNav->geod(), az1, az2, s);
143 SG_NORMALIZE_RANGE(az1, -180.0, 180.0);
144 return fabs(az1) > 90.0;
147 // Given a point and a list of stations, return the closest one to the
149 FGNavRecord *FGNavList::findNavFromList( const SGGeod &aircraft,
150 const nav_list_type &stations )
152 FGNavRecord *nav = NULL;
153 double d2; // in meters squared
155 = FG_NAV_MAX_RANGE*SG_NM_TO_METER*FG_NAV_MAX_RANGE*SG_NM_TO_METER;
156 SGVec3d aircraftCart = SGVec3d::fromGeod(aircraft);
158 nav_list_const_iterator it;
159 nav_list_const_iterator end = stations.end();
160 // find the closest station within a sensible range (FG_NAV_MAX_RANGE)
161 for ( it = stations.begin(); it != end; ++it ) {
162 FGNavRecord *station = *it;
163 // cout << "testing " << current->get_ident() << endl;
164 d2 = distSqr(station->cart(), aircraftCart);
165 if ( d2 < min_dist && penaltyForNav(station, aircraft))
167 double dist = sqrt(d2);
168 d2 = (dist + 5000) * (dist + 5000);
171 if ( d2 < min_dist ) {
180 // Given a frequency, return the first matching station.
181 FGNavRecord *FGNavList::findStationByFreq( double freq )
183 const nav_list_type& stations = navaids[(int)(freq*100.0 + 0.5)];
185 SG_LOG( SG_INSTR, SG_DEBUG, "findStationByFreq " << freq << " size " << stations.size() );
187 if (!stations.empty()) {
195 // FGTACANList ----------------------------------------------------------------
197 FGTACANList::FGTACANList( void )
202 FGTACANList::~FGTACANList( void )
207 bool FGTACANList::init()
213 // add an entry to the lists
214 bool FGTACANList::add( FGTACANRecord *c )
216 ident_channels[c->get_channel()].push_back(c);
221 // Given a TACAN Channel return the first matching frequency
222 FGTACANRecord *FGTACANList::findByChannel( const string& channel )
224 const tacan_list_type& stations = ident_channels[channel];
225 SG_LOG( SG_INSTR, SG_DEBUG, "findByChannel " << channel<< " size " << stations.size() );
227 if (!stations.empty()) {