]> git.mxchange.org Git - flightgear.git/blob - src/Navaids/navlist.cxx
Merge branch 'tat/configure'
[flightgear.git] / src / Navaids / navlist.cxx
1 // navlist.cxx -- navaids management class
2 //
3 // Written by Curtis Olson, started April 2000.
4 //
5 // Copyright (C) 2000  Curtis L. Olson - http://www.flightgear.org/~curt
6 //
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.
11 //
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.
16 //
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.
20 //
21 // $Id$
22
23
24 #ifdef HAVE_CONFIG_H
25 #  include <config.h>
26 #endif
27
28 #include <simgear/debug/logstream.hxx>
29 #include <simgear/math/sg_geodesy.hxx>
30 #include <simgear/sg_inlines.h>
31
32 #include "navlist.hxx"
33
34 #include <Airports/runways.hxx>
35
36 using std::string;
37
38 // FGNavList ------------------------------------------------------------------
39
40 FGNavList::FGNavList( void )
41 {
42 }
43
44
45 FGNavList::~FGNavList( void )
46 {
47     nav_list_type navlist = navaids.begin()->second;
48     navaids.erase( navaids.begin(), navaids.end() );
49 }
50
51
52 // load the navaids and build the map
53 bool FGNavList::init()
54 {
55     // No need to delete the original navaid structures
56     // since we're using an SGSharedPointer
57     nav_list_type navlist = navaids.begin()->second;
58     navaids.erase( navaids.begin(), navaids.end() );
59     return true;
60 }
61
62 // add an entry to the lists
63 bool FGNavList::add( FGNavRecord *n )
64 {
65     navaids[n->get_freq()].push_back(n);
66     return true;
67 }
68
69 FGNavRecord *FGNavList::findByFreq( double freq, const SGGeod& position)
70 {
71     const nav_list_type& stations = navaids[(int)(freq*100.0 + 0.5)];
72     SG_LOG( SG_INSTR, SG_DEBUG, "findbyFreq " << freq << " size " << stations.size()  );
73     return findNavFromList( position, stations );
74 }
75
76 class VORNDBFilter : public FGPositioned::Filter
77 {
78 public:
79   virtual FGPositioned::Type minType() const {
80     return FGPositioned::VOR;
81   }
82
83   virtual FGPositioned::Type maxType()  const {
84     return FGPositioned::NDB;
85   }
86 };
87
88 // Given an Ident and optional freqency, return the first matching
89 // station.
90 FGNavRecord *FGNavList::findByIdentAndFreq(const string& ident, const double freq )
91 {
92   FGPositionedRef cur;
93   VORNDBFilter filter;
94   cur = FGPositioned::findNextWithPartialId(cur, ident, &filter);
95   
96   if (freq <= 0.0) {
97     return static_cast<FGNavRecord*>(cur.ptr()); // might be null
98   }
99   
100   int f = (int)(freq*100.0 + 0.5);
101   while (cur) {
102     FGNavRecord* nav = static_cast<FGNavRecord*>(cur.ptr());
103     if (nav->get_freq() == f) {
104       return nav;
105     }
106     
107     cur = FGPositioned::findNextWithPartialId(cur, ident, &filter);
108   }
109
110   return NULL;
111 }
112
113 // discount navids if they conflict with another on the same frequency
114 // this only applies to navids associated with opposite ends of a runway,
115 // with matching frequencies.
116 static bool navidUsable(FGNavRecord* aNav, const SGGeod &aircraft)
117 {
118   FGRunway* r(aNav->runway());
119   if (!r || !r->reciprocalRunway()) {
120     return true;
121   }
122   
123 // check if the runway frequency is paired
124   FGNavRecord* locA = r->ILS();
125   FGNavRecord* locB = r->reciprocalRunway()->ILS();
126   
127   if (!locA || !locB || (locA->get_freq() != locB->get_freq())) {
128     return true; // not paired, ok
129   }
130   
131 // okay, both ends have an ILS, and they're paired. We need to select based on
132 // aircraft position. What we're going to use is *runway* (not navid) position,
133 // ie whichever runway end we are closer too. This makes back-course / missed
134 // approach behaviour incorrect, but that's the price we accept.
135   double crs = SGGeodesy::courseDeg(aircraft, r->geod());
136   double hdgDiff = crs - r->headingDeg();
137   SG_NORMALIZE_RANGE(hdgDiff, -180.0, 180.0);  
138   return (fabs(hdgDiff) < 90.0);
139 }
140
141 // Given a point and a list of stations, return the closest one to
142 // the specified point.
143 FGNavRecord* FGNavList::findNavFromList( const SGGeod &aircraft,
144                                   const nav_list_type &stations )
145 {
146     FGNavRecord *nav = NULL;
147     double d2;                  // in meters squared
148     double min_dist
149         = FG_NAV_MAX_RANGE*SG_NM_TO_METER*FG_NAV_MAX_RANGE*SG_NM_TO_METER;
150     SGVec3d aircraftCart = SGVec3d::fromGeod(aircraft);
151     
152     nav_list_const_iterator it;
153     nav_list_const_iterator end = stations.end();
154     // find the closest station within a sensible range (FG_NAV_MAX_RANGE)
155     for ( it = stations.begin(); it != end; ++it ) {
156         FGNavRecord *station = *it;
157         d2 = distSqr(station->cart(), aircraftCart);
158         if ( d2 > min_dist || !navidUsable(station, aircraft)) {
159           continue;
160         }
161         
162         min_dist = d2;
163         nav = station;
164     }
165
166     return nav;
167 }
168
169 // Given a frequency, return the first matching station.
170 FGNavRecord *FGNavList::findStationByFreq( double freq )
171 {
172     const nav_list_type& stations = navaids[(int)(freq*100.0 + 0.5)];
173
174     SG_LOG( SG_INSTR, SG_DEBUG, "findStationByFreq " << freq << " size " << stations.size()  );
175
176     if (!stations.empty()) {
177         return stations[0];
178     }
179     return NULL;
180 }
181
182
183
184 // FGTACANList ----------------------------------------------------------------
185
186 FGTACANList::FGTACANList( void )
187 {
188 }
189
190
191 FGTACANList::~FGTACANList( void )
192 {
193 }
194
195
196 bool FGTACANList::init()
197 {
198     return true;
199 }
200
201
202 // add an entry to the lists
203 bool FGTACANList::add( FGTACANRecord *c )
204 {
205     ident_channels[c->get_channel()].push_back(c);
206     return true;
207 }
208
209
210 // Given a TACAN Channel return the first matching frequency
211 FGTACANRecord *FGTACANList::findByChannel( const string& channel )
212 {
213     const tacan_list_type& stations = ident_channels[channel];
214     SG_LOG( SG_INSTR, SG_DEBUG, "findByChannel " << channel<< " size " << stations.size() );
215
216     if (!stations.empty()) {
217         return stations[0];
218     }
219     return NULL;
220 }
221
222