]> git.mxchange.org Git - flightgear.git/blob - src/Navaids/procedure.cxx
Avoid compiler warning.
[flightgear.git] / src / Navaids / procedure.cxx
1 // procedure.cxx - define route storing an approach, arrival or departure procedure
2 // Written by James Turner, started 2009.
3 //
4 // Copyright (C) 2009  Curtis L. Olson
5 //
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License as
8 // published by the Free Software Foundation; either version 2 of the
9 // License, or (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful, but
12 // WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19
20 #include "procedure.hxx"
21
22 #include <cassert>
23 #include <algorithm> // for reverse_copy
24
25 #include <simgear/structure/exception.hxx>
26
27 #include <Navaids/waypoint.hxx>
28
29 using std::string;
30
31 namespace flightgear
32 {
33   
34 static void markWaypoints(WayptVec& wps, WayptFlag f)
35 {
36   for (unsigned int i=0; i<wps.size(); ++i) {
37     wps[i]->setFlag(f, true);
38   }
39 }
40
41 Procedure::Procedure(const string& aIdent) :
42   _ident(aIdent)
43 {
44 }
45
46 Approach::Approach(const string& aIdent, ProcedureType ty) : 
47   Procedure(aIdent),
48   _type(ty)
49 {
50
51 }
52
53 void Approach::setRunway(FGRunwayRef aRwy)
54 {
55   _runway = aRwy;
56 }
57
58 FGAirport* Approach::airport() const
59 {
60   return _runway->airport();
61 }
62
63 RunwayVec Approach::runways() const
64 {
65   RunwayVec r;
66   r.push_back(_runway);
67   return r;
68 }
69   
70 void Approach::setPrimaryAndMissed(const WayptVec& aPrimary, const WayptVec& aMissed)
71 {
72   _primary = aPrimary;
73   _primary[0]->setFlag(WPT_IAF, true);
74   _primary[_primary.size()-1]->setFlag(WPT_FAF, true);
75   markWaypoints(_primary, WPT_APPROACH);
76   
77   _missed = aMissed;
78   
79   if (!_missed.empty()) {
80     // mark the first point as the published missed-approach point
81     _missed[0]->setFlag(WPT_MAP, true);
82     markWaypoints(_missed, WPT_MISS);
83     markWaypoints(_missed, WPT_APPROACH);
84   }
85 }
86
87 void Approach::addTransition(Transition* aTrans)
88 {
89   WayptRef entry = aTrans->enroute();
90   _transitions[entry] = aTrans;
91   aTrans->mark(WPT_APPROACH);
92 }
93
94 bool Approach::route(WayptRef aIAF, WayptVec& aWps)
95 {
96   if (aIAF.valid()) {
97     WptTransitionMap::iterator it;
98     bool haveTrans = false;
99     for (it = _transitions.begin(); it != _transitions.end(); ++it) {
100       Transition* t= it->second;
101       if (t->enroute()->matches(aIAF)) {
102         t->route(aWps);
103         haveTrans = true;
104         break;
105       }
106     } // of transitions iteration
107     
108     if (!haveTrans) {
109       SG_LOG(SG_GENERAL, SG_INFO, "approach " << ident() << " has no transition " <<
110         "for IAF: " << aIAF->ident());
111       return false;
112     }
113   }
114   
115   return routeFromVectors(aWps);
116 }
117
118 bool Approach::routeFromVectors(WayptVec& aWps)
119 {
120   aWps.insert(aWps.end(), _primary.begin(), _primary.end());
121   RunwayWaypt* rwy = new RunwayWaypt(_runway, NULL);
122   rwy->setFlag(WPT_APPROACH);
123   aWps.push_back(rwy);
124   aWps.insert(aWps.end(), _missed.begin(), _missed.end());
125   return true;
126 }
127
128 bool Approach::isApproach(ProcedureType ty)
129 {
130   return (ty >= PROCEDURE_APPROACH_ILS) && (ty <= PROCEDURE_APPROACH_RNAV);
131 }
132   
133 //////////////////////////////////////////////////////////////////////////////
134
135 ArrivalDeparture::ArrivalDeparture(const string& aIdent, FGAirport* apt) :
136   Procedure(aIdent),
137   _airport(apt)
138 {
139 }
140
141 void ArrivalDeparture::addRunway(FGRunwayRef aWay)
142 {
143   assert(aWay->airport() == _airport);
144   _runways[aWay] = NULL;
145 }
146
147 bool ArrivalDeparture::isForRunway(const FGRunway* aWay) const
148 {
149   // null runway always passes
150   if (!aWay) {
151     return true;
152   }
153   
154   FGRunwayRef r(const_cast<FGRunway*>(aWay));
155   return (_runways.count(r));
156 }
157
158 RunwayVec ArrivalDeparture::runways() const
159 {
160   RunwayVec r;
161   RunwayTransitionMap::const_iterator it = _runways.begin();
162   for (; it != _runways.end(); ++it) {
163     r.push_back(it->first);
164   }
165   
166   return r;
167 }
168     
169 void ArrivalDeparture::addTransition(Transition* aTrans)
170 {
171   WayptRef entry = aTrans->enroute();
172   aTrans->mark(flagType());
173   _enrouteTransitions[entry] = aTrans;
174 }
175
176 string_list ArrivalDeparture::transitionIdents() const
177 {
178   string_list r;
179   WptTransitionMap::const_iterator eit;
180   for (eit = _enrouteTransitions.begin(); eit != _enrouteTransitions.end(); ++eit) {
181     r.push_back(eit->second->ident());
182   }
183   return r;
184 }
185   
186 void ArrivalDeparture::addRunwayTransition(FGRunwayRef aWay, Transition* aTrans)
187 {
188   assert(aWay->ident() == aTrans->ident());
189   if (!isForRunway(aWay)) {
190     throw sg_io_exception("adding transition for unspecified runway:" + aWay->ident(), ident());
191   }
192   
193   aTrans->mark(flagType());
194   _runways[aWay] = aTrans;
195 }
196
197 void ArrivalDeparture::setCommon(const WayptVec& aWps)
198 {
199   _common = aWps;
200   markWaypoints(_common, flagType());
201 }
202
203 bool ArrivalDeparture::commonRoute(Transition* t, WayptVec& aPath, FGRunwayRef aRwy)
204 {
205   // assume we're routing from enroute, to the runway.
206   // for departures, we'll flip the result points
207
208   WayptVec::iterator firstCommon = _common.begin();
209   if (t) {
210     t->route(aPath);
211
212     Waypt* transEnd = t->procedureEnd();
213     for (; firstCommon != _common.end(); ++firstCommon) {
214       if ((*firstCommon)->matches(transEnd)) {
215         // found transition->common point, stop search
216         break;
217       }
218     } // of common points
219     
220     // if we hit this point, the transition doesn't end (start, for a SID) on
221     // a common point. We assume this means we should just append the entire
222     // common section after the transition.
223     firstCommon = _common.begin();
224   } else {
225     // no tranasition
226   } // of not using a transition
227   
228   // append (some) common points
229   aPath.insert(aPath.end(), firstCommon, _common.end());
230   
231   if (!aRwy) {
232     // no runway specified, we're done
233     return true;
234   }
235   
236   RunwayTransitionMap::iterator r = _runways.find(aRwy);
237   assert(r != _runways.end());
238   if (!r->second) {
239     // no transitions specified. Not great, but not
240     // much we can do about it. Calling code will insert VECTORS to the approach
241     // if required, or maybe there's an approach transition defined.
242     return true;
243   }
244   
245   SG_LOG(SG_GENERAL, SG_INFO, ident() << " using runway transition for " << r->first->ident());
246   r->second->route(aPath);
247   return true;
248 }
249
250 Transition* ArrivalDeparture::findTransitionByEnroute(Waypt* aEnroute) const
251 {
252   if (!aEnroute) {
253     return NULL;
254   }
255   
256   WptTransitionMap::const_iterator eit;
257   for (eit = _enrouteTransitions.begin(); eit != _enrouteTransitions.end(); ++eit) {
258     if (eit->second->enroute()->matches(aEnroute)) {
259       SG_LOG(SG_GENERAL, SG_INFO, ident() << " using enroute transition " << eit->second->ident());
260       return eit->second;
261     }
262   } // of enroute transition iteration
263   
264   return NULL;
265 }
266
267 WayptRef ArrivalDeparture::findBestTransition(const SGGeod& aPos) const
268 {
269   // no transitions, that's easy
270   if (_enrouteTransitions.empty()) {
271     SG_LOG(SG_GENERAL, SG_INFO, "no enroute transitions for " << ident());
272     return _common.front();
273   }
274   
275   double d = 1e9;
276   WayptRef w;
277   WptTransitionMap::const_iterator eit;
278   for (eit = _enrouteTransitions.begin(); eit != _enrouteTransitions.end(); ++eit) {
279     WayptRef c = eit->second->enroute();
280     SG_LOG(SG_GENERAL, SG_INFO, "findBestTransition for " << ident() << ", looking at " << c->ident());
281     // assert(c->hasFixedPosition());
282     double cd = SGGeodesy::distanceM(aPos, c->position());
283     
284     if (cd < d) { // distance to 'c' is less, new best match
285       d = cd;
286       w = c;
287     }
288   } // of transitions iteration
289   
290   assert(w);
291   return w;
292 }
293
294 Transition* ArrivalDeparture::findTransitionByName(const string& aIdent) const
295 {
296   WptTransitionMap::const_iterator eit;
297   for (eit = _enrouteTransitions.begin(); eit != _enrouteTransitions.end(); ++eit) {
298     if (eit->second->ident() == aIdent) {
299       return eit->second;
300     }
301   }
302   
303   return NULL;
304 }
305
306 ////////////////////////////////////////////////////////////////////////////
307
308 SID::SID(const string& aIdent, FGAirport* apt) :
309     ArrivalDeparture(aIdent, apt)
310 {
311 }
312
313 bool SID::route(FGRunwayRef aWay, Transition* trans, WayptVec& aPath)
314 {
315   if (!isForRunway(aWay)) {
316     SG_LOG(SG_GENERAL, SG_WARN, "SID " << ident() << " not for runway " << aWay->ident());
317     return false;
318   }
319   
320   WayptVec path;
321   if (!commonRoute(trans, path, aWay)) {
322     return false;
323   }
324   
325   // SID waypoints (including transitions) are stored reversed, so we can
326   // re-use the routing code. This is where we fix the ordering for client code
327   std::back_insert_iterator<WayptVec> bi(aPath);
328   std::reverse_copy(path.begin(), path.end(), bi);
329
330   return true;
331 }
332
333 ////////////////////////////////////////////////////////////////////////////
334
335 STAR::STAR(const string& aIdent, FGAirport* apt) :
336     ArrivalDeparture(aIdent, apt)
337 {
338 }
339
340 bool STAR::route(FGRunwayRef aWay, Transition* trans, WayptVec& aPath)
341 {
342   if (aWay && !isForRunway(aWay)) {
343     return false;
344   }
345     
346   return commonRoute(trans, aPath, aWay);
347 }
348
349 /////////////////////////////////////////////////////////////////////////////
350
351 Transition::Transition(const std::string& aIdent, ProcedureType ty, Procedure* aPr) :
352   Procedure(aIdent),
353   _type(ty),
354   _parent(aPr)
355 {
356   assert(aPr);
357 }
358   
359 void Transition::setPrimary(const WayptVec& aWps)
360 {
361   _primary = aWps;
362   assert(!_primary.empty());
363   _primary[0]->setFlag(WPT_TRANSITION, true);
364 }
365
366 WayptRef Transition::enroute() const
367 {
368   assert(!_primary.empty());
369   return _primary[0];
370 }
371
372 WayptRef Transition::procedureEnd() const
373 {
374   assert(!_primary.empty());
375   return _primary[_primary.size() - 1];
376 }
377
378 bool Transition::route(WayptVec& aPath)
379 {
380   aPath.insert(aPath.end(), _primary.begin(), _primary.end());
381   return true;
382 }
383
384 FGAirport* Transition::airport() const
385 {
386   return _parent->airport();
387 }
388   
389 void Transition::mark(WayptFlag f)
390 {
391   markWaypoints(_primary, f);
392 }
393   
394 } // of namespace