FlightGear next
airways.cxx
Go to the documentation of this file.
1// airways.cxx - storage of airways network, and routing between nodes
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 "config.h"
21
22#include "airways.hxx"
23
24#include <tuple>
25#include <algorithm>
26#include <set>
27
28#include <simgear/sg_inlines.h>
29#include <simgear/structure/exception.hxx>
30#include <simgear/io/iostreams/sgstream.hxx>
31#include <simgear/misc/sg_path.hxx>
32
33#include <Main/globals.hxx>
35#include <Navaids/waypoint.hxx>
37
38using std::make_pair;
39using std::string;
40using std::set;
41using std::vector;
42
43//#define DEBUG_AWY_SEARCH 1
44
45namespace flightgear
46{
47
48static std::vector<AirwayRef> static_airwaysCache;
49typedef SGSharedPtr<FGPositioned> FGPositionedRef;
50
52
53class AStarOpenNode : public SGReferenced
54{
55public:
56 AStarOpenNode(FGPositionedRef aNode, double aLegDist,
57 int aAirway,
58 FGPositionedRef aDest, AStarOpenNode* aPrev) :
59 node(aNode),
60 previous(aPrev),
61 airway(aAirway)
62 {
63 distanceFromStart = aLegDist;
64 if (previous) {
65 distanceFromStart += previous->distanceFromStart;
66 }
67
68 directDistanceToDestination = SGGeodesy::distanceM(node->geod(), aDest->geod());
69 }
70
72 {
73 }
74
76 SGSharedPtr<AStarOpenNode> previous;
77 int airway;
78 double distanceFromStart; // aka 'g(x)'
79 double directDistanceToDestination; // aka 'h(x)'
80
84 double totalCost() const {
86 }
87};
88
89using AStarOpenNodeRef = SGSharedPtr<AStarOpenNode>;
90
92
94{
95 static Network* static_lowLevel = nullptr;
96
97 if (!static_lowLevel) {
98 static_lowLevel = new Network;
99 static_lowLevel->_networkID = Airway::LowLevel;
100 }
101
102 return static_lowLevel;
103}
104
106{
107 static Network* static_highLevel = nullptr;
108 if (!static_highLevel) {
109 static_highLevel = new Network;
110 static_highLevel->_networkID = Airway::HighLevel;
111 }
112
113 return static_highLevel;
114}
115
116Airway::Airway(const std::string& aIdent,
117 const Level level,
118 int dbId,
119 int aTop, int aBottom) :
120 _ident(aIdent),
121 _level(level),
122 _cacheId(dbId),
123 _topAltitudeFt(aTop),
124 _bottomAltitudeFt(aBottom)
125{
126 assert((level == HighLevel) || (level == LowLevel));
127 static_airwaysCache.push_back(this);
128}
129
130void Airway::loadAWYDat(const SGPath& path)
131{
132 std::string identStart, identEnd, name;
133 double latStart, lonStart, latEnd, lonEnd;
134 int type, base, top;
135
136 sg_gzifstream in( path );
137 if ( !in.is_open() ) {
138 SG_LOG( SG_NAVAID, SG_ALERT, "Cannot open file: " << path );
139 throw sg_io_exception("Could not open airways data", path);
140 }
141// toss the first two lines of the file
142 in >> skipeol;
143 in >> skipeol;
144
145// read in each remaining line of the file
146 while (!in.eof()) {
147 in >> identStart;
148
149 if (identStart == "99") {
150 break;
151 }
152
153 in >> latStart >> lonStart >> identEnd >> latEnd >> lonEnd >> type >> base >> top >> name;
154 in >> skipeol;
155
156 // type = 1; low-altitude (victor)
157 // type = 2; high-altitude (jet)
158 Network* net = (type == 1) ? lowLevel() : highLevel();
159
160 SGGeod startPos(SGGeod::fromDeg(lonStart, latStart)),
161 endPos(SGGeod::fromDeg(lonEnd, latEnd));
162
163 if (type == 1) {
164
165 } else if (type == 2) {
166
167 } else {
168 SG_LOG(SG_NAVAID, SG_DEV_WARN, "unknown airway type:" << type << " for " << name);
169 continue;
170 }
171
172 auto pieces = simgear::strutils::split(name, "-");
173 for (auto p : pieces) {
174 int awy = net->findAirway(p);
175 net->addEdge(awy, startPos, identStart, endPos, identEnd);
176 }
177 } // of file line iteration
178}
179
180WayptVec::const_iterator Airway::find(WayptRef wpt) const
181{
182 assert(!_elements.empty());
183 if (wpt->type() == "via") {
184 // map vias to their end navaid / fix, so chaining them
185 // together works. (Temporary waypoint is discarded after search)
186 wpt = new NavaidWaypoint(wpt->source(), wpt->owner());
187 }
188
189 return std::find_if(_elements.begin(), _elements.end(),
190 [wpt] (const WayptRef& w)
191 {
192 if (!w) return false;
193 return w->matches(wpt);
194 });
195}
196
197bool Airway::canVia(const WayptRef& from, const WayptRef& to) const
198{
199 loadWaypoints();
200
201 auto fit = find(from);
202 auto tit = find(to);
203
204 if ((fit == _elements.end()) || (tit == _elements.end())) {
205 return false;
206 }
207
208 if (fit < tit) {
209 // forward progression
210 for (++fit; fit != tit; ++fit) {
211 if (*fit == nullptr) {
212 // traversed an airway discontinuity
213 return false;
214 }
215 }
216 } else {
217 // reverse progression
218 for (--fit; fit != tit; --fit) {
219 if (*fit == nullptr) {
220 // traversed an airway discontinuity
221 return false;
222 }
223 }
224 }
225
226 return true;
227}
228
229WayptVec Airway::via(const WayptRef& from, const WayptRef& to) const
230{
231 loadWaypoints();
232
233 WayptVec v;
234 auto fit = find(from);
235 auto tit = find(to);
236
237 if ((fit == _elements.end()) || (tit == _elements.end())) {
238 throw sg_exception("bad VIA transition points");
239 }
240
241 if (fit == tit) {
242 // will cause duplicate point but that seems better than
243 // return an empty
244 v.push_back(*tit);
245 return v;
246 }
247
248 // establish the ordering of the transitions, i.e are we moving forward or
249 // backard along the airway.
250 if (fit < tit) {
251 // forward progression
252 for (++fit; fit != tit; ++fit) {
253 v.push_back(*fit);
254 }
255 } else {
256 // reverse progression
257 for (--fit; fit != tit; --fit) {
258 v.push_back(*fit);
259 }
260 }
261
262 v.push_back(*tit);
263 return v;
264}
265
267{
268 if (!navaid)
269 return false;
270
271 loadWaypoints();
272 auto it = std::find_if(_elements.begin(), _elements.end(),
273 [navaid](WayptRef w)
274 {
275 if (!w) return false;
276 return w->matches(navaid);
277 });
278 return (it != _elements.end());
279}
280
281int Airway::Network::findAirway(const std::string& aName)
282{
283 const Level level = _networkID;
284 auto it = std::find_if(static_airwaysCache.begin(), static_airwaysCache.end(),
285 [aName, level](const AirwayRef& awy)
286 { return (awy->_level == level) && (awy->ident() == aName); });
287 if (it != static_airwaysCache.end()) {
288 return (*it)->_cacheId;
289 }
290
291 return NavDataCache::instance()->findAirway(_networkID, aName, true);
292}
293
294AirwayRef Airway::findByIdent(const std::string& aIdent, Level level)
295{
296 auto it = std::find_if(static_airwaysCache.begin(), static_airwaysCache.end(),
297 [aIdent, level](const AirwayRef& awy)
298 {
299 if ((level != Both) && (awy->_level != level)) return false;
300 return (awy->ident() == aIdent);
301 });
302 if (it != static_airwaysCache.end()) {
303 return *it;
304 }
305
306 auto ndc = NavDataCache::instance();
307 int airwayId = 0;
308 if (level == Both) {
309 airwayId = ndc->findAirway(HighLevel, aIdent, false);
310 if (airwayId == 0) {
311 level = LowLevel; // not found in HighLevel, try LowLevel
312 } else {
313 level = HighLevel; // fix up, so Airway ctro see a valid value
314 }
315 }
316
317 if (airwayId == 0) {
318 airwayId = ndc->findAirway(level, aIdent, false);
319 if (airwayId == 0) {
320 return {};
321 }
322 }
323
324 return ndc->loadAirway(airwayId);
325}
326
328 {
329 auto it = std::find_if(static_airwaysCache.begin(), static_airwaysCache.end(),
330 [cacheId](const AirwayRef& awy)
331 { return (awy->_cacheId == cacheId); });
332 if (it != static_airwaysCache.end()) {
333 return *it;
334 }
335
337 ;
338 }
339
340void Airway::loadWaypoints() const
341{
343 for (auto id : ndc->airwayWaypts(_cacheId)) {
344 if (id == 0) {
345 _elements.push_back({});
346 } else {
347 FGPositionedRef pos = ndc->loadById(id);
348 auto wp = new NavaidWaypoint(pos, const_cast<Airway*>(this));
349 wp->setFlag(WPT_VIA);
350 wp->setFlag(WPT_GENERATED);
351 _elements.push_back(wp);
352 }
353 }
354}
355
356AirwayRef Airway::findByIdentAndVia(const std::string& aIdent, const WayptRef& from, const WayptRef& to)
357{
358 AirwayRef hi = findByIdent(aIdent, HighLevel);
359 if (hi && hi->canVia(from, to)) {
360 return hi;
361 }
362
363 AirwayRef low = findByIdent(aIdent, LowLevel);
364 if (low && low->canVia(from, to)) {
365 return low;
366 }
367
368 return nullptr;
369}
370
371AirwayRef Airway::findByIdentAndNavaid(const std::string& aIdent, const FGPositionedRef nav)
372{
373 AirwayRef hi = findByIdent(aIdent, HighLevel);
374 if (hi && hi->containsNavaid(nav)) {
375 return hi;
376 }
377
378 AirwayRef low = findByIdent(aIdent, LowLevel);
379 if (low && low->containsNavaid(nav)) {
380 return low;
381 }
382
383 return nullptr;
384}
385
386WayptRef Airway::findEnroute(const std::string &aIdent) const
387{
388 loadWaypoints();
389 auto it = std::find_if(_elements.begin(), _elements.end(),
390 [&aIdent](WayptRef w)
391 {
392 if (!w) return false;
393 return w->ident() == aIdent;
394 });
395
396 if (it != _elements.end())
397 return *it;
398 return {};
399}
400
402{
403 loadWaypoints();
404 auto it = std::find_if(_elements.begin(), _elements.end(),
405 [&nav](WayptRef w)
406 {
407 if (!w) return false;
408 return w->source() == nav;
409 });
410
411 if (it != _elements.end())
412 return *it;
413 return {};
414}
415
416void Airway::Network::addEdge(int aWay, const SGGeod& aStartPos,
417 const std::string& aStartIdent,
418 const SGGeod& aEndPos, const std::string& aEndIdent)
419{
420 FGPositionedRef start = FGPositioned::findClosestWithIdent(aStartIdent, aStartPos);
421 FGPositionedRef end = FGPositioned::findClosestWithIdent(aEndIdent, aEndPos);
422
423 if (!start) {
424 SG_LOG(SG_NAVAID, SG_DEBUG, "unknown airways start pt: '" << aStartIdent << "'");
425 start = FGPositioned::createWaypoint(FGPositioned::WAYPOINT, aStartIdent, aStartPos);
426 }
427
428 if (!end) {
429 SG_LOG(SG_NAVAID, SG_DEBUG, "unknown airways end pt: '" << aEndIdent << "'");
430 end = FGPositioned::createWaypoint(FGPositioned::WAYPOINT, aEndIdent, aEndPos);
431 }
432
433 NavDataCache::instance()->insertEdge(_networkID, aWay, start->guid(), end->guid());
434}
435
437
438static double headingDiffDeg(double a, double b)
439{
440 double rawDiff = b - a;
441 SG_NORMALIZE_RANGE(rawDiff, -180.0, 180.0);
442 return rawDiff;
443}
444
445bool Airway::Network::inNetwork(PositionedID posID) const
446{
447 NetworkMembershipDict::iterator it = _inNetworkCache.find(posID);
448 if (it != _inNetworkCache.end()) {
449 return it->second; // cached, easy
450 }
451
452 bool r = NavDataCache::instance()->isInAirwayNetwork(_networkID, posID);
453 _inNetworkCache.insert(it, std::make_pair(posID, r));
454 return r;
455}
456
458 WayptVec& aPath)
459{
460 if (!aFrom || !aTo) {
461 throw sg_exception("invalid waypoints to route between");
462 }
463
464// find closest nodes on the graph to from/to
465// if argument waypoints are directly on the graph (which is frequently the
466// case), note this so we don't duplicate them in the output.
467
468 FGPositionedRef from, to;
469 bool exactTo, exactFrom;
470 std::tie(from, exactFrom) = findClosestNode(aFrom);
471 std::tie(to, exactTo) = findClosestNode(aTo);
472
473#ifdef DEBUG_AWY_SEARCH
474 SG_LOG(SG_NAVAID, SG_INFO, "from:" << from->ident() << "/" << from->name());
475 SG_LOG(SG_NAVAID, SG_INFO, "to:" << to->ident() << "/" << to->name());
476#endif
477
478 bool ok = search2(from, to, aPath);
479 if (!ok) {
480 return false;
481 }
482
483 return cleanGeneratedPath(aFrom, aTo, aPath, exactTo, exactFrom);
484}
485
486bool Airway::Network::cleanGeneratedPath(WayptRef aFrom, WayptRef aTo, WayptVec& aPath,
487 bool exactTo, bool exactFrom)
488{
489 // path cleaning phase : various cases to handle here.
490 // if either the TO or FROM waypoints were 'exact', i.e part of the enroute
491 // structure, we don't want to duplicate them. This happens frequently with
492 // published SIDs and STARs.
493 // secondly, if the waypoints are NOT on the enroute structure, the course to
494 // them may be a significant dog-leg. Check how the leg course deviates
495 // from the direct course FROM->TO, and delete the first/last leg if it's more
496 // than 90 degrees out.
497 // note we delete a maximum of one leg, and no more. This is a heuristic - we
498 // could check the next (previous) legs, but at some point we'll end up
499 // deleting too much.
500
501 const double MAX_DOG_LEG = 90.0;
502 double enrouteCourse = SGGeodesy::courseDeg(aFrom->position(), aTo->position()),
503 finalLegCourse = SGGeodesy::courseDeg(aPath.back()->position(), aTo->position());
504
505 bool isDogLeg = fabs(headingDiffDeg(enrouteCourse, finalLegCourse)) > MAX_DOG_LEG;
506 if (exactTo || isDogLeg) {
507 aPath.pop_back();
508 }
509
510 // edge case - if from and to are equal, which can happen, don't
511 // crash here. This happens routing EGPH -> EGCC; 'DCS' is common
512 // to the EGPH departure and EGCC STAR.
513 if (aPath.empty()) {
514 return true;
515 }
516
517 double initialLegCourse = SGGeodesy::courseDeg(aFrom->position(), aPath.front()->position());
518 isDogLeg = fabs(headingDiffDeg(enrouteCourse, initialLegCourse)) > MAX_DOG_LEG;
519 if (exactFrom || isDogLeg) {
520 aPath.erase(aPath.begin());
521 }
522
523 return true;
524}
525
526std::pair<FGPositionedRef, bool>
528{
529 if (aRef->source()) {
530 // we can check directly
531 if (inNetwork(aRef->source()->guid())) {
532 return std::make_pair(aRef->source(), true);
533 }
534 }
535
536 return findClosestNode(aRef->position());
537}
538
540{
541public:
543 _net(aNet)
544 { ; }
545
546 virtual bool pass(FGPositioned* aPos) const
547 {
548 return _net->inNetwork(aPos->guid());
549 }
550
552 { return FGPositioned::WAYPOINT; }
553
555 { return FGPositioned::VOR; }
556
557private:
558 const Airway::Network* _net;
559};
560
561std::pair<FGPositionedRef, bool>
563{
564 InAirwayFilter f(this);
565 FGPositionedRef r = FGPositioned::findClosest(aGeod, 800.0, &f);
566 bool exact = false;
567
568 if (r && (SGGeodesy::distanceM(aGeod, r->geod()) < 100.0)) {
569 exact = true; // within 100 metres, let's call that exact
570 }
571
572 return make_pair(r, exact);
573}
574
576Airway::Network::findNodeByIdent(const std::string& ident, const SGGeod& near) const
577{
578 InAirwayFilter f(this);
580}
581
583
584typedef vector<AStarOpenNodeRef> OpenNodeHeap;
585
586static void buildWaypoints(AStarOpenNodeRef aNode, WayptVec& aRoute)
587{
588// count the route length, and hence pre-size aRoute
589 size_t count = 0;
590 AStarOpenNodeRef n = aNode;
591 for (; n != nullptr; ++count, n = n->previous) {;}
592 aRoute.resize(count);
593
594// run over the route, creating waypoints
595 for (n = aNode; n; n=n->previous) {
596 // get / create airway to be the owner for this waypoint
597 AirwayRef awy = Airway::loadByCacheId(n->airway);
598 auto wp = new NavaidWaypoint(n->node, awy);
599 if (awy) {
600 wp->setFlag(WPT_VIA);
601 }
602 wp->setFlag(WPT_GENERATED);
603 aRoute[--count] = wp;
604 }
605}
606
610static AStarOpenNodeRef
612{
613 for (unsigned int i=0; i<aHeap.size(); ++i) {
614 if (aHeap[i]->node == aPos) {
615 return aHeap[i];
616 }
617 }
618
619 return nullptr;
620}
621
623{
624public:
626 {
627 return a->totalCost() > b->totalCost();
628 }
629};
630
631bool Airway::Network::search2(FGPositionedRef aStart, FGPositionedRef aDest,
632 WayptVec& aRoute)
633{
634 typedef set<PositionedID> ClosedNodeSet;
635
636 OpenNodeHeap openNodes;
637 ClosedNodeSet closedNodes;
638 HeapOrder ordering;
639
640 openNodes.push_back(new AStarOpenNode(aStart, 0.0, 0, aDest, nullptr));
641
642// A* open node iteration
643 while (!openNodes.empty()) {
644 std::pop_heap(openNodes.begin(), openNodes.end(), ordering);
645 AStarOpenNodeRef x = openNodes.back();
646 FGPositioned* xp = x->node;
647 openNodes.pop_back();
648 closedNodes.insert(xp->guid());
649
650#ifdef DEBUG_AWY_SEARCH
651 SG_LOG(SG_NAVAID, SG_INFO, "x:" << xp->ident() << ", f(x)=" << x->totalCost());
652#endif
653
654 // check if xp is the goal; if so we're done, since there cannot be an open
655 // node with lower f(x) value.
656 if (xp == aDest) {
657 buildWaypoints(x, aRoute);
658 return true;
659 }
660
661 // adjacent (neighbour) iteration
663 for (auto other : cache->airwayEdgesFrom(_networkID, xp->guid())) {
664 if (closedNodes.count(other.second)) {
665 continue; // closed, ignore
666 }
667
668 FGPositioned* yp = cache->loadById(other.second);
669 double edgeDistanceM = SGGeodesy::distanceM(xp->geod(), yp->geod());
670 AStarOpenNodeRef y = findInOpen(openNodes, yp);
671 if (y) { // already open
672 double g = x->distanceFromStart + edgeDistanceM;
673 if (g > y->distanceFromStart) {
674 // worse path, ignore
675#ifdef DEBUG_AWY_SEARCH
676 SG_LOG(SG_NAVAID, SG_INFO, "\tabandoning " << yp->ident() <<
677 " path is worse: g(y)" << y->distanceFromStart << ", g'=" << g);
678#endif
679 continue;
680 }
681
682 // we need to update y. Unfortunately this means rebuilding the heap,
683 // since y's score can change arbitrarily
684#ifdef DEBUG_AWY_SEARCH
685 SG_LOG(SG_NAVAID, SG_INFO, "\tfixing up previous for new path to " << yp->ident() << ", d =" << g);
686#endif
687 y->previous = x;
688 y->distanceFromStart = g;
689 y->airway = other.first;
690 std::make_heap(openNodes.begin(), openNodes.end(), ordering);
691 } else { // not open, insert a new node for y into the heap
692 y = new AStarOpenNode(yp, edgeDistanceM, other.first, aDest, x);
693#ifdef DEBUG_AWY_SEARCH
694 SG_LOG(SG_NAVAID, SG_INFO, "\ty=" << yp->ident() << ", f(y)=" << y->totalCost());
695#endif
696 openNodes.push_back(y);
697 std::push_heap(openNodes.begin(), openNodes.end(), ordering);
698 }
699 } // of neighbour iteration
700 } // of open node iteration
701
702 SG_LOG(SG_NAVAID, SG_INFO, "A* failed to find route");
703 return false;
704}
705
706} // of namespace flightgear
#define p(x)
#define i(x)
SGSharedPtr< FGPositioned > FGPositionedRef
Definition airways.hxx:30
Predicate class to support custom filtering of FGPositioned queries Default implementation of this pa...
static FGPositionedRef createWaypoint(FGPositioned::Type aType, const std::string &aIdent, const SGGeod &aPos, bool isTemporary=false, const std::string &aName={})
PositionedID guid() const
static FGPositionedRef findClosestWithIdent(const std::string &aIdent, const SGGeod &aPos, Filter *aFilter=NULL)
virtual const SGGeod & geod() const
const std::string & ident() const
static FGPositionedRef findClosest(const SGGeod &aPos, double aCutoffNm, Filter *aFilter=NULL)
Find the closest item to a position, which pass the specified filter A cutoff range in NM must be spe...
SGSharedPtr< AStarOpenNode > previous
Definition airways.cxx:76
AStarOpenNode(FGPositionedRef aNode, double aLegDist, int aAirway, FGPositionedRef aDest, AStarOpenNode *aPrev)
Definition airways.cxx:56
double totalCost() const
aka 'f(x)'
Definition airways.cxx:84
FGPositionedRef node
Definition airways.cxx:75
Track a network of airways.
Definition airways.hxx:101
std::pair< FGPositionedRef, bool > findClosestNode(const SGGeod &aGeod)
Overloaded version working with a raw SGGeod.
Definition airways.cxx:562
FGPositionedRef findNodeByIdent(const std::string &ident, const SGGeod &near) const
Definition airways.cxx:576
bool route(WayptRef aFrom, WayptRef aTo, WayptVec &aPath)
Principal routing algorithm.
Definition airways.cxx:457
static Network * lowLevel()
Definition airways.cxx:93
WayptVec via(const WayptRef &from, const WayptRef &to) const
Definition airways.cxx:229
@ HighLevel
Victor airways.
Definition airways.hxx:48
@ Both
Jet airways.
Definition airways.hxx:49
bool containsNavaid(const FGPositionedRef &navaid) const
Definition airways.cxx:266
WayptRef findEnroute(const std::string &aIdent) const
Definition airways.cxx:386
bool canVia(const WayptRef &from, const WayptRef &to) const
Definition airways.cxx:197
static void loadAWYDat(const SGPath &path)
Definition airways.cxx:130
static AirwayRef findByIdentAndNavaid(const std::string &aIdent, const FGPositionedRef nav)
Find an airway by ident, and containing a particula rnavaid/fix.
Definition airways.cxx:371
static Network * highLevel()
Definition airways.cxx:105
std::string ident() const override
Definition airways.hxx:52
static AirwayRef findByIdent(const std::string &aIdent, Level level)
Definition airways.cxx:294
int cacheId() const
Definition airways.hxx:55
friend class NavDataCache
Definition airways.hxx:176
static AirwayRef loadByCacheId(int cacheId)
Definition airways.cxx:327
Level level() const
Definition airways.hxx:58
static AirwayRef findByIdentAndVia(const std::string &aIdent, const WayptRef &from, const WayptRef &to)
Find the airway based on its ident.
Definition airways.cxx:356
bool operator()(AStarOpenNode *a, AStarOpenNode *b)
Definition airways.cxx:625
virtual FGPositioned::Type minType() const
Definition airways.cxx:551
virtual FGPositioned::Type maxType() const
Definition airways.cxx:554
virtual bool pass(FGPositioned *aPos) const
Over-rideable filter method.
Definition airways.cxx:546
InAirwayFilter(const Airway::Network *aNet)
Definition airways.cxx:542
PositionedIDVec airwayWaypts(int id)
Waypoints on the airway.
AirwayRef loadAirway(int airwayID)
FGPositionedRef loadById(PositionedID guid)
retrieve an FGPositioned from the cache.
static NavDataCache * instance()
void insertEdge(int network, int airwayID, PositionedID from, PositionedID to)
insert an edge between two positioned nodes, into the network.
bool isInAirwayNetwork(int network, PositionedID pos)
is the specified positioned a node on the network?
int findAirway(int network, const std::string &aName, bool create)
Waypoint based upon a navaid.
Definition waypoint.hxx:63
const double g(9.80665)
FlightPlan.hxx - defines a full flight-plan object, including departure, cruise, arrival information ...
Definition Addon.cxx:53
SGSharedPtr< AStarOpenNode > AStarOpenNodeRef
Definition airways.cxx:89
vector< AStarOpenNodeRef > OpenNodeHeap
Definition airways.cxx:584
static double headingDiffDeg(double a, double b)
Definition airways.cxx:438
SGSharedPtr< FGPositioned > FGPositionedRef
Definition airways.cxx:49
SGSharedPtr< Waypt > WayptRef
SGSharedPtr< Airway > AirwayRef
Definition airways.hxx:40
const char * name
@ WPT_GENERATED
waypoint was created automatically (not manually entered/loaded) for example waypoints from airway ro...
Definition route.hxx:52
@ WPT_VIA
waypoint prodcued by expanding a VIA segment
Definition route.hxx:63
static void buildWaypoints(AStarOpenNodeRef aNode, WayptVec &aRoute)
Definition airways.cxx:586
std::vector< WayptRef > WayptVec
static std::vector< AirwayRef > static_airwaysCache
Definition airways.cxx:48
static AStarOpenNodeRef findInOpen(const OpenNodeHeap &aHeap, FGPositioned *aPos)
Inefficent (linear) helper to find an open node in the heap.
Definition airways.cxx:611
int64_t PositionedID