FlightGear next
route.cxx
Go to the documentation of this file.
1// route.cxx - classes supporting waypoints and route structures
2
3// Written by James Turner, started 2009.
4//
5// Copyright (C) 2009 Curtis L. Olson
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#include "config.h"
22
23#include "route.hxx"
24
25// std
26#include <map>
27#include <fstream>
28
29
30// SimGear
31#include <simgear/structure/exception.hxx>
32#include <simgear/misc/sg_path.hxx>
33#include <simgear/magvar/magvar.hxx>
34#include <simgear/timing/sg_time.hxx>
35#include <simgear/io/iostreams/sgstream.hxx>
36#include <simgear/misc/strutils.hxx>
37#include <simgear/props/props_io.hxx>
38
39// FlightGear
40#include <Main/globals.hxx>
41#include "Main/fg_props.hxx"
42#include <Navaids/procedure.hxx>
43#include <Navaids/waypoint.hxx>
44#include <Navaids/LevelDXML.hxx>
45#include <Airports/airport.hxx>
46#include <Navaids/airways.hxx>
47#include <Environment/atmosphere.hxx> // for Mach conversions
48
49using std::string;
50using std::vector;
51using std::endl;
52using std::fstream;
53
54
55namespace flightgear {
56
57const double NO_MAG_VAR = -1000.0; // an impossible mag-var value
58
60{
61 return (rr == SPEED_RESTRICT_MACH) || (rr == SPEED_COMPUTED_MACH);
62}
63
64namespace {
65
66double magvarDegAt(const SGGeod& pos)
67{
68 double jd = globals->get_time_params()->getJD();
69 return sgGetMagVar(pos, jd) * SG_RADIANS_TO_DEGREES;
70}
71
72WayptRef intersectionFromString(FGPositionedRef p1,
73 const SGGeod& basePosition,
74 const double magvar,
75 const string_list& pieces)
76{
77 assert(pieces.size() == 4);
78 // navid/radial/navid/radial notation
79 FGPositionedRef p2 = FGPositioned::findClosestWithIdent(pieces[2], basePosition);
80 if (!p2) {
81 SG_LOG(SG_NAVAID, SG_INFO, "Unable to find FGPositioned with ident:" << pieces[2]);
82 return {};
83 }
84
85 double r1 = atof(pieces[1].c_str()),
86 r2 = atof(pieces[3].c_str());
87 r1 += magvar;
88 r2 += magvar;
89
90 SGGeod intersection;
91 bool ok = SGGeodesy::radialIntersection(p1->geod(), r1, p2->geod(), r2, intersection);
92 if (!ok) {
93 SG_LOG(SG_NAVAID, SG_INFO, "no valid intersection for:" << pieces[0] << "/" << pieces[2]);
94 return {};
95 }
96
97 std::string name = p1->ident() + "-" + p2->ident();
98 return new BasicWaypt(intersection, name, nullptr);
99}
100
101WayptRef viaFromString(const SGGeod& basePosition, const std::string& target)
102{
103 assert(target.find("VIA-") == 0);
104 string_list pieces(simgear::strutils::split(target.substr(4), "/"));
105 if (pieces.size() != 2) {
106 SG_LOG(SG_NAVAID, SG_WARN, "Malformed VIA specification string:" << target);
107 return {};
108 }
109
110 // TO navaid is pieces[1]
111 FGPositionedRef nav = FGPositioned::findClosestWithIdent(pieces[1], basePosition, nullptr);
112 if (!nav) {
113 SG_LOG(SG_NAVAID, SG_WARN, "TO navaid:" << pieces[3] << " unknown");
114 return {};
115 }
116
117 // airway ident is pieces[1]
118 AirwayRef airway = Airway::findByIdentAndNavaid(pieces[0], nav);
119 if (!airway) {
120 SG_LOG(SG_NAVAID, SG_WARN, "Unknown airway:" << pieces[0]);
121 return {};
122 }
123
124 return new Via(nullptr, airway, nav);
125}
126
127static double convertSpeedToKnots(RouteUnits aUnits, double aAltitudeFt, double aValue)
128{
129 switch (aUnits) {
130 case SPEED_KNOTS: return aValue;
131 case SPEED_KPH: return aValue * SG_KMH_TO_MPS * SG_MPS_TO_KT;
132 case SPEED_MACH: return FGAtmo::knotsFromMachAtAltitudeFt(aValue, aAltitudeFt);
133
134 default:
135 throw sg_format_exception("Can't convert unit to Knots", "convertSpeedToKnots");
136 }
137}
138
139static double convertSpeedFromKnots(RouteUnits aUnits, double aAltitudeFt, double aValue)
140{
141 if (aUnits == DEFAULT_UNITS) {
142 // TODO : use KPH is simulator is in metric
143 aUnits = SPEED_KNOTS;
144 }
145
146 switch (aUnits) {
147 case SPEED_KNOTS: return aValue;
148 case SPEED_KPH: return aValue * SG_KT_TO_MPS * SG_MPS_TO_KMH;
149 case SPEED_MACH: return FGAtmo::machFromKnotsAtAltitudeFt(aValue, aAltitudeFt);
150
151 default:
152 throw sg_format_exception("Can't convert to unit", "convertSpeedFromKnots");
153 }
154}
155
156} // anonymous namespace
157
158double convertSpeedUnits(RouteUnits aSrc, RouteUnits aDest, double aAltitudeFt, double aValue)
159{
160 const double valueKnots = convertSpeedToKnots(aSrc, aAltitudeFt, aValue);
161 return convertSpeedFromKnots(aDest, aAltitudeFt, valueKnots);
162}
163
164double convertAltitudeUnits(RouteUnits aSrc, RouteUnits aDest, double aValue)
165{
166 if (aDest == DEFAULT_UNITS) {
167 // TODO : use meters if sim is in metric
168 aDest = ALTITUDE_FEET;
169 }
170
171 double altFt = 0.0;
172 switch (aSrc) {
173 case ALTITUDE_FEET: altFt = aValue; break;
174 case ALTITUDE_METER: altFt = aValue * SG_METER_TO_FEET; break;
175 case ALTITUDE_FLIGHTLEVEL: altFt = aValue * 100; break;
176 default:
177 throw sg_format_exception("Unsupported source altitude units", "convertAltitudeUnits");
178 }
179
180 switch (aDest) {
181 case ALTITUDE_FEET: return altFt;
182 case ALTITUDE_METER: return altFt * SG_FEET_TO_METER;
183 case ALTITUDE_FLIGHTLEVEL: return round(altFt / 100);
184 default:
185 throw sg_format_exception("Unsupported destination altitude units", "convertAltitudeUnits");
186 }
187}
188
190 _owner(aOwner),
191 _magVarDeg(NO_MAG_VAR)
192{
193}
194
196{
197}
198
199std::string Waypt::ident() const
200{
201 return {};
202}
203
204bool Waypt::flag(WayptFlag aFlag) const
205{
206 return ((_flags & aFlag) != 0);
207}
208
209void Waypt::setFlag(WayptFlag aFlag, bool aV)
210{
211 if (aFlag == 0) {
212 throw sg_range_exception("invalid waypoint flag set");
213 }
214
215 _flags = (_flags & ~aFlag);
216 if (aV) _flags |= aFlag;
217}
218
219bool Waypt::matches(Waypt* aOther) const
220{
221 assert(aOther);
222 if (ident() != aOther->ident()) { // cheap check first
223 return false;
224 }
225
226 return matches(aOther->position());
227}
228
230{
231 if (!aPos)
232 return false;
233
234 // if w ehave no source, match on position and ident
235 if (!source()) {
236 return (ident() == aPos->ident()) && matches(aPos->geod());
237 }
238
239 return (aPos == source());
240}
241
242bool Waypt::matches(const SGGeod& aPos) const
243{
244 double d = SGGeodesy::distanceM(position(), aPos);
245 return (d < 100.0); // 100 metres seems plenty
246}
247
248void Waypt::setAltitude(double aAlt, RouteRestriction aRestrict, RouteUnits aUnit)
249{
250 if (aUnit == DEFAULT_UNITS) {
251 aUnit = ALTITUDE_FEET;
252 }
253
254 _altitude = aAlt;
255 _altitudeUnits = aUnit;
256 _altRestrict = aRestrict;
257}
258
260{
261 _constraintAltitude = aAlt;
262}
263
264void Waypt::setSpeed(double aSpeed, RouteRestriction aRestrict, RouteUnits aUnit)
265{
266 if (aUnit == DEFAULT_UNITS) {
267 if ((aRestrict == SPEED_RESTRICT_MACH) || (aRestrict == SPEED_RESTRICT_MACH)) {
268 aUnit = SPEED_MACH;
269 } else {
270 aUnit = SPEED_KNOTS;
271 }
272 }
273
274 _speed = aSpeed;
275 _speedUnits = aUnit;
276 _speedRestrict = aRestrict;
277}
278
279double Waypt::speedKts() const
280{
281 return speed(SPEED_KNOTS);
282}
283
284double Waypt::speedMach() const
285{
286 return speed(SPEED_MACH);
287}
288
289double Waypt::altitudeFt() const
290{
291 return altitude(ALTITUDE_FEET);
292}
293
294double Waypt::speed(RouteUnits aUnits) const
295{
296 if (aUnits == _speedUnits) {
297 return _speed;
298 }
299
301}
302
303double Waypt::altitude(RouteUnits aUnits) const
304{
305 if (aUnits == _altitudeUnits) {
306 return _altitude;
307 }
308
310}
311
313{
314 if (!_constraintAltitude.has_value())
315 return 0.0;
316
317 if (aUnits == _altitudeUnits) {
318 return _constraintAltitude.value_or(0.0);
319 }
320
321 return convertAltitudeUnits(_altitudeUnits, aUnits, _constraintAltitude.value_or(0.0));
322}
323
324double Waypt::magvarDeg() const
325{
326 if (_magVarDeg == NO_MAG_VAR) {
327 // derived classes with a default pos must override this method
328 assert(!(position() == SGGeod()));
329
330 double jd = globals->get_time_params()->getJD();
331 _magVarDeg = sgGetMagVar(position(), jd) * SG_RADIANS_TO_DEGREES;
332 }
333
334 return _magVarDeg;
335}
336
338{
339 return 0.0;
340}
341
342std::string Waypt::icaoDescription() const
343{
344 return ident();
345}
346
348// persistence
349
351{
352 std::string l = simgear::strutils::lowercase(aStr);
353
354 if (l == "at") return RESTRICT_AT;
355 if (l == "above") return RESTRICT_ABOVE;
356 if (l == "below") return RESTRICT_BELOW;
357 if (l == "between") return RESTRICT_BETWEEN;
358 if (l == "none") return RESTRICT_NONE;
359 if (l == "mach") return SPEED_RESTRICT_MACH;
360
361 if (l.empty()) return RESTRICT_NONE;
362 throw sg_io_exception("unknown restriction specification:" + l,
363 "Route restrictFromString");
364}
365
367{
368 switch (aRestrict) {
369 case RESTRICT_AT: return "at";
370 case RESTRICT_BELOW: return "below";
371 case RESTRICT_ABOVE: return "above";
372 case RESTRICT_NONE: return "none";
373 case RESTRICT_BETWEEN: return "between";
374 case SPEED_RESTRICT_MACH: return "mach";
375
376 default:
377 throw sg_exception("invalid route restriction",
378 "Route restrictToString");
379 }
380}
381
382WayptRef Waypt::createInstance(RouteBase* aOwner, const std::string& aTypeName)
383{
384 WayptRef r;
385 if (aTypeName == "basic") {
386 r = new BasicWaypt(aOwner);
387 } else if (aTypeName == "navaid") {
388 r = new NavaidWaypoint(aOwner);
389 } else if (aTypeName == "offset-navaid") {
390 r = new OffsetNavaidWaypoint(aOwner);
391 } else if (aTypeName == "hold") {
392 r = new Hold(aOwner);
393 } else if (aTypeName == "runway") {
394 r = new RunwayWaypt(aOwner);
395 } else if (aTypeName == "hdgToAlt") {
396 r = new HeadingToAltitude(aOwner);
397 } else if (aTypeName == "dmeIntercept") {
398 r = new DMEIntercept(aOwner);
399 } else if (aTypeName == "radialIntercept") {
400 r = new RadialIntercept(aOwner);
401 } else if (aTypeName == "vectors") {
402 r = new ATCVectors(aOwner);
403 } else if (aTypeName == "discontinuity") {
404 r = new Discontinuity(aOwner);
405 } else if (aTypeName == "via") {
406 r = new Via(aOwner);
407 }
408
409 if (!r || (r->type() != aTypeName)) {
410 throw sg_exception("broken factory method for type:" + aTypeName,
411 "Waypt::createInstance");
412 }
413
414 return r;
415}
416
417WayptRef Waypt::createFromProperties(RouteBase* aOwner, SGPropertyNode_ptr aProp)
418{
419 if (!aProp->hasChild("type")) {
420 SG_LOG(SG_GENERAL, SG_WARN, "Bad waypoint node: missing type");
421 return {};
422 }
423
425 if (aProp->hasChild("airway")) {
426 auto level = Airway::Both;
427 if (aProp->hasValue("network")) {
428 level = static_cast<flightgear::Airway::Level>(aProp->getIntValue("network"));
429 }
430
431 via = flightgear::Airway::findByIdent(aProp->getStringValue("airway"), level);
432 if (via) {
433 // override owner if we are from an airway
434 aOwner = via.get();
435 }
436 }
437
438 WayptRef nd(createInstance(aOwner, aProp->getStringValue("type")));
439 if (nd->initFromProperties(aProp)) {
440 return nd;
441 }
442 SG_LOG(SG_GENERAL, SG_WARN, "failed to create waypoint, trying basic");
443
444
445 // if we failed to make the waypoint, try again making a basic waypoint.
446 // this handles the case where a navaid waypoint is missing, for example
447 // we also reject navaids that don't look correct (too far form the specified
448 // lat-lon, eg see https://sourceforge.net/p/flightgear/codetickets/1814/ )
449 // and again fallback to here.
450 WayptRef bw(new BasicWaypt(aOwner));
451 if (bw->initFromProperties(aProp)) {
452 return bw;
453 }
454
455 return {}; // total failure
456}
457
458WayptRef Waypt::fromLatLonString(RouteBase* aOwner, const std::string& target)
459{
460 // permit lat,lon/radial/offset format
461 string_list pieces(simgear::strutils::split(target, "/"));
462 if ((pieces.size() != 1) && (pieces.size() != 3)) {
463 return {};
464 }
465
466 SGGeod g;
467 const bool defaultToLonLat = true; // parseStringAsGeod would otherwise default to lat,lon
468 if (!simgear::strutils::parseStringAsGeod(pieces[0], &g, defaultToLonLat)) {
469 return {};
470 }
471
472 if (pieces.size() == 3) {
473 // process offset
474 const double bearing = std::stod(pieces[1]);
475 const double distanceNm = std::stod(pieces[2]);
476 g = SGGeodesy::direct(g, bearing, distanceNm * SG_NM_TO_METER);
477 }
478
479 // build a short name
480 const int lonDeg = static_cast<int>(g.getLongitudeDeg());
481 const int latDeg = static_cast<int>(g.getLatitudeDeg());
482
483 char buf[32];
484 char ew = (lonDeg < 0) ? 'W' : 'E';
485 char ns = (latDeg < 0) ? 'S' : 'N';
486 snprintf(buf, 32, "%c%03d%c%03d", ew, std::abs(lonDeg), ns, std::abs(latDeg));
487
488 return new BasicWaypt(g, buf, aOwner);
489}
490
491WayptRef Waypt::createFromString(RouteBase* aOwner, const std::string& s, const SGGeod& aVicinity)
492{
493 auto vicinity = aVicinity;
494 if (!vicinity.isValid()) {
495 vicinity = globals->get_aircraft_position();
496 }
497
498 auto target = simgear::strutils::uppercase(s);
499 // extract altitude
500 double alt = 0.0;
501 RouteRestriction altSetting = RESTRICT_NONE;
502 RouteUnits altitudeUnits = ALTITUDE_FEET;
503
504 size_t pos = target.find('@');
505 if (pos != string::npos) {
506 auto altStr = simgear::strutils::uppercase(target.substr(pos + 1));
507 if (simgear::strutils::starts_with(altStr, "FL")) {
508 altitudeUnits = ALTITUDE_FLIGHTLEVEL;
509 altStr = altStr.substr(2); // trim leading 'FL'
510 } else if (fgGetString("/sim/startup/units") == "meter") {
511 altitudeUnits = ALTITUDE_METER;
512 }
513
514 alt = std::stof(altStr);
515 target = target.substr(0, pos);
516 altSetting = RESTRICT_AT;
517 }
518
519 // check for lon,lat
520 WayptRef wpt = fromLatLonString(aOwner, target);
521
522 const double magvar = magvarDegAt(vicinity);
523
524 if (wpt) {
525 // already handled in the lat/lon test above
526 } else if (target.find("VIA-") == 0) {
527 wpt = viaFromString(vicinity, target);
528 } else {
532 string_list pieces(simgear::strutils::split(target, "/"));
533 FGPositionedRef p = FGPositioned::findClosestWithIdent(pieces.front(), vicinity, &filter);
534 if (!p) {
535 SG_LOG(SG_NAVAID, SG_INFO, "Unable to find FGPositioned with ident:" << pieces.front());
536 return {};
537 }
538
539 if (pieces.size() == 1) {
540 wpt = new NavaidWaypoint(p, aOwner);
541 } else if (pieces.size() == 3) {
542 // navaid/radial/distance-nm notation
543 double radial = atof(pieces[1].c_str()),
544 distanceNm = atof(pieces[2].c_str());
545 radial += magvar;
546 wpt = new OffsetNavaidWaypoint(p, aOwner, radial, distanceNm);
547 } else if (pieces.size() == 2) {
548 FGAirport* apt = dynamic_cast<FGAirport*>(p.ptr());
549 if (!apt) {
550 SG_LOG(SG_NAVAID, SG_INFO, "Waypoint is not an airport:" << pieces.front());
551 return {};
552 }
553
554 if (!apt->hasRunwayWithIdent(pieces[1])) {
555 SG_LOG(SG_NAVAID, SG_INFO, "No runway: " << pieces[1] << " at " << pieces[0]);
556 return {};
557 }
558
559 FGRunway* runway = apt->getRunwayByIdent(pieces[1]);
560 wpt = new NavaidWaypoint(runway, aOwner);
561 } else if (pieces.size() == 4) {
562 wpt = intersectionFromString(p, vicinity, magvar, pieces);
563 }
564 }
565
566 if (!wpt) {
567 SG_LOG(SG_NAVAID, SG_INFO, "Unable to parse waypoint:" << target);
568 return {};
569 }
570
571 if (altSetting != RESTRICT_NONE) {
572 wpt->setAltitude(alt, altSetting, altitudeUnits);
573 }
574 return wpt;
575}
576
577
578void Waypt::saveAsNode(SGPropertyNode* n) const
579{
580 n->setStringValue("type", type());
582}
583
584bool Waypt::initFromProperties(SGPropertyNode_ptr aProp)
585{
586 if (aProp->hasChild("generated")) {
587 setFlag(WPT_GENERATED, aProp->getBoolValue("generated"));
588 }
589
590 if (aProp->hasChild("overflight")) {
591 setFlag(WPT_OVERFLIGHT, aProp->getBoolValue("overflight"));
592 }
593
594 if (aProp->hasChild("arrival")) {
595 setFlag(WPT_ARRIVAL, aProp->getBoolValue("arrival"));
596 }
597
598 if (aProp->hasChild("approach")) {
599 setFlag(WPT_APPROACH, aProp->getBoolValue("approach"));
600 }
601
602 if (aProp->hasChild("departure")) {
603 setFlag(WPT_DEPARTURE, aProp->getBoolValue("departure"));
604 }
605
606 if (aProp->hasChild("miss")) {
607 setFlag(WPT_MISS, aProp->getBoolValue("miss"));
608 }
609
610 if (aProp->hasChild("airway")) {
611 setFlag(WPT_VIA, true);
612 }
613
614 if (aProp->hasChild("alt-restrict")) {
615 _altRestrict = restrictionFromString(aProp->getStringValue("alt-restrict"));
616 if (aProp->hasChild("altitude-ft")) {
617 _altitude = aProp->getDoubleValue("altitude-ft");
619 } else if (aProp->hasChild("altitude-m")) {
620 _altitude = aProp->getDoubleValue("altitude-m");
622 } else if (aProp->hasChild("flight-level")) {
623 _altitude = aProp->getIntValue("flight-level");
625 }
626
627 if (aProp->hasChild("constraint-altitude")) {
628 _constraintAltitude = aProp->getDoubleValue("constraint-altitude");
629 }
630 }
631
632 if (aProp->hasChild("speed-restrict")) {
633 _speedRestrict = restrictionFromString(aProp->getStringValue("speed-restrict"));
634 RouteUnits units = SPEED_KNOTS;
636 units = SPEED_MACH;
637 }
638
639 if (aProp->hasChild("speed-mach")) {
640 units = SPEED_MACH;
641 _speed = aProp->getDoubleValue("speed-mach");
642 } else if (aProp->hasChild("speed-kph")) {
643 units = SPEED_KPH;
644 _speed = aProp->getDoubleValue("speed-kph");
645 } else {
646 _speed = aProp->getDoubleValue("speed");
647 }
648
649 _speedUnits = units;
650 }
651
652 return true;
653}
654
655void Waypt::writeToProperties(SGPropertyNode_ptr aProp) const
656{
657 if (flag(WPT_OVERFLIGHT)) {
658 aProp->setBoolValue("overflight", true);
659 }
660
661 if (flag(WPT_DEPARTURE)) {
662 aProp->setBoolValue("departure", true);
663 }
664
665 if (flag(WPT_ARRIVAL)) {
666 aProp->setBoolValue("arrival", true);
667 }
668
669 if (flag(WPT_APPROACH)) {
670 aProp->setBoolValue("approach", true);
671 }
672
673 if (flag(WPT_VIA) && _owner) {
675 aProp->setStringValue("airway", awy->ident());
676 aProp->setIntValue("network", awy->level());
677 }
678
679 if (flag(WPT_MISS)) {
680 aProp->setBoolValue("miss", true);
681 }
682
683 if (flag(WPT_GENERATED)) {
684 aProp->setBoolValue("generated", true);
685 }
686
688 aProp->setStringValue("alt-restrict", restrictionToString(_altRestrict));
690 aProp->setDoubleValue("altitude-m", _altitude);
691 } else if (_altitudeUnits == ALTITUDE_FLIGHTLEVEL) {
692 aProp->setDoubleValue("flight-level", _altitude);
693
694 } else {
695 aProp->setDoubleValue("altitude-ft", _altitude);
696 }
697 }
698
699 if (_constraintAltitude.has_value()) {
700 aProp->setDoubleValue("constraint-altitude", _constraintAltitude.value_or(0.0));
701 }
702
704 aProp->setStringValue("speed-restrict", restrictionToString(_speedRestrict));
705 aProp->setDoubleValue("speed", _speed);
706 }
707}
708
712
713void RouteBase::dumpRouteToKML(const WayptVec& aRoute, const std::string& aName)
714{
715 SGPath p = SGPath::desktop() / (aName + ".kml");
716 sg_ofstream f(p);
717 if (!f.is_open()) {
718 SG_LOG(SG_NAVAID, SG_WARN, "unable to open:" << p);
719 return;
720 }
721
722// pre-amble
723 f << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
724 "<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n"
725 "<Document>\n";
726
727 dumpRouteToKMLLineString(aName, aRoute, f);
728
729// post-amble
730 f << "</Document>\n"
731 "</kml>" << endl;
732 f.close();
733}
734
735void RouteBase::dumpRouteToKMLLineString(const std::string& aIdent,
736 const WayptVec& aRoute, std::ostream& aStream)
737{
738 // preamble
739 aStream << "<Placemark>\n";
740 aStream << "<name>" << aIdent << "</name>\n";
741 aStream << "<LineString>\n";
742 aStream << "<tessellate>1</tessellate>\n";
743 aStream << "<coordinates>\n";
744
745 // waypoints
746 for (unsigned int i=0; i<aRoute.size(); ++i) {
747 SGGeod pos = aRoute[i]->position();
748 aStream << pos.getLongitudeDeg() << "," << pos.getLatitudeDeg() << " " << endl;
749 }
750
751 // postable
752 aStream << "</coordinates>\n"
753 "</LineString>\n"
754 "</Placemark>\n" << endl;
755}
756
757void RouteBase::loadAirportProcedures(const SGPath& aPath, FGAirport* aApt)
758{
759 assert(aApt);
760 try {
761 NavdataVisitor visitor(aApt, aPath);
762 readXML(aPath, visitor);
763 } catch (sg_io_exception& ex) {
764 SG_LOG(SG_NAVAID, SG_WARN, "failure parsing procedures: " << aPath <<
765 "\n\t" << ex.getMessage() << "\n\tat:" << ex.getLocation().asString());
766 } catch (sg_exception& ex) {
767 SG_LOG(SG_NAVAID, SG_WARN, "failure parsing procedures: " << aPath <<
768 "\n\t" << ex.getMessage());
769 }
770}
771
772} // of namespace flightgear
double altitude
Definition ADA.cxx:46
#define p2(x, y)
#define p(x)
#define i(x)
FGRunwayRef getRunwayByIdent(const std::string &aIdent) const
Definition airport.cxx:182
bool hasRunwayWithIdent(const std::string &aIdent) const
Definition airport.cxx:162
static double knotsFromMachAtAltitudeFt(const double mach, const double altFt, const double Tsl=atmodel::ISA::T0)
static double machFromKnotsAtAltitudeFt(const double knots, const double altFt, const double Tsl=atmodel::ISA::T0)
static FGPositionedRef findClosestWithIdent(const std::string &aIdent, const SGGeod &aPos, Filter *aFilter=NULL)
virtual const SGGeod & geod() const
const std::string & ident() const
@ Both
Jet airways.
Definition airways.hxx:49
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 AirwayRef findByIdent(const std::string &aIdent, Level level)
Definition airways.cxx:294
Waypoint based upon a navaid.
Definition waypoint.hxx:63
static void dumpRouteToKML(const WayptVec &aRoute, const std::string &aName)
Definition route.cxx:713
static void loadAirportProcedures(const SGPath &aPath, FGAirport *aApt)
Definition route.cxx:757
static void dumpRouteToKMLLineString(const std::string &aIdent, const WayptVec &aRoute, std::ostream &aStream)
Definition route.cxx:735
virtual ~RouteBase()
Definition route.cxx:709
virtual std::string icaoDescription() const
icaoDescription - description of the waypoint in ICAO route plan format
Definition route.cxx:342
RouteUnits _altitudeUnits
Definition route.hxx:242
double speed(RouteUnits aUnits=DEFAULT_UNITS) const
Definition route.cxx:294
double altitude(RouteUnits aUnits=DEFAULT_UNITS) const
Definition route.cxx:303
Waypt(RouteBase *aOwner)
Definition route.cxx:189
double altitudeFt() const
Definition route.cxx:289
RouteRestriction _altRestrict
Definition route.hxx:247
std::optional< double > _constraintAltitude
some restriction types specify two altitudes, in which case this is the second value,...
Definition route.hxx:240
virtual FGPositioned * source() const
The Positioned associated with this element, if one exists.
Definition route.hxx:117
virtual std::string type() const =0
static WayptRef createFromString(RouteBase *aOwner, const std::string &s, const SGGeod &vicinity)
Create a waypoint from the route manager's standard string format:
Definition route.cxx:491
void setAltitude(double aAlt, RouteRestriction aRestrict, RouteUnits aUnits=DEFAULT_UNITS)
Definition route.cxx:248
void setConstraintAltitude(double aAlt)
Definition route.cxx:259
RouteRestriction _speedRestrict
Definition route.hxx:248
void setFlag(WayptFlag aFlag, bool aV=true)
Definition route.cxx:209
virtual ~Waypt()
Definition route.cxx:195
bool matches(Waypt *aOther) const
Test if this element and another are 'the same', i.e matching ident and lat/lon are approximately equ...
Definition route.cxx:219
static WayptRef createFromProperties(RouteBase *aOwner, SGPropertyNode_ptr aProp)
Factory method.
Definition route.cxx:417
virtual bool initFromProperties(SGPropertyNode_ptr aProp)
Persistence helper - read node properties from a file.
Definition route.cxx:584
virtual bool flag(WayptFlag aFlag) const
Test if the specified flag is set for this element.
Definition route.cxx:204
virtual double headingRadialDeg() const
return the assoicated heading or radial for this waypoint.
Definition route.cxx:337
virtual void writeToProperties(SGPropertyNode_ptr aProp) const
Persistence helper - save this element to a node.
Definition route.cxx:655
void saveAsNode(SGPropertyNode *node) const
Definition route.cxx:578
virtual std::string ident() const
Identifier assoicated with the waypoint.
Definition route.cxx:199
virtual SGGeod position() const =0
static WayptRef fromLatLonString(RouteBase *aOwner, const std::string &target)
Definition route.cxx:458
RouteUnits _speedUnits
Definition route.hxx:245
double speedMach() const
Definition route.cxx:284
virtual double magvarDeg() const
Magentic variation at/in the vicinity of the waypoint.
Definition route.cxx:324
void setSpeed(double aSpeed, RouteRestriction aRestrict, RouteUnits aUnits=DEFAULT_UNITS)
Definition route.cxx:264
double constraintAltitude(RouteUnits aUnits=DEFAULT_UNITS) const
Definition route.cxx:312
double speedKts() const
Definition route.cxx:279
std::string fgGetString(const char *name, const char *defaultValue)
Get a string value for a property.
Definition fg_props.cxx:556
FGGlobals * globals
Definition globals.cxx:142
std::vector< std::string > string_list
Definition globals.hxx:36
FlightPlan.hxx - defines a full flight-plan object, including departure, cruise, arrival information ...
Definition Addon.cxx:53
double convertAltitudeUnits(RouteUnits aSrc, RouteUnits aDest, double aValue)
Definition route.cxx:164
const double NO_MAG_VAR
Definition route.cxx:57
RouteRestriction restrictionFromString(const std::string &aStr)
Definition route.cxx:350
@ SPEED_KPH
Definition route.hxx:89
@ ALTITUDE_FLIGHTLEVEL
Definition route.hxx:86
@ DEFAULT_UNITS
Definition route.hxx:83
@ ALTITUDE_METER
Definition route.hxx:85
@ SPEED_KNOTS
Definition route.hxx:87
@ SPEED_MACH
Definition route.hxx:88
@ ALTITUDE_FEET
Definition route.hxx:84
SGSharedPtr< FGPositioned > FGPositionedRef
Definition airways.cxx:49
SGSharedPtr< Waypt > WayptRef
SGSharedPtr< Airway > AirwayRef
Definition airways.hxx:40
const char * name
double convertSpeedUnits(RouteUnits aSrc, RouteUnits aDest, double aAltitudeFt, double aValue)
Definition route.cxx:158
const char * restrictionToString(RouteRestriction aRestrict)
Definition route.cxx:366
bool isMachRestrict(RouteRestriction rr)
Definition route.cxx:59
@ WPT_DEPARTURE
Definition route.hxx:54
@ WPT_MISS
segment is part of missed approach
Definition route.hxx:46
@ WPT_APPROACH
Definition route.hxx:60
@ WPT_ARRIVAL
Definition route.hxx:55
@ WPT_GENERATED
waypoint was created automatically (not manually entered/loaded) for example waypoints from airway ro...
Definition route.hxx:52
@ WPT_OVERFLIGHT
must overfly the point directly
Definition route.hxx:44
@ WPT_VIA
waypoint prodcued by expanding a VIA segment
Definition route.hxx:63
std::vector< WayptRef > WayptVec
RouteRestriction
Definition route.hxx:70
@ RESTRICT_NONE
Definition route.hxx:71
@ RESTRICT_AT
Definition route.hxx:72
@ RESTRICT_BELOW
Definition route.hxx:74
@ SPEED_COMPUTED_MACH
variant on above to encode a Mach value
Definition route.hxx:79
@ RESTRICT_ABOVE
Definition route.hxx:73
@ SPEED_RESTRICT_MACH
encode an 'AT' restriction in Mach, not IAS
Definition route.hxx:76
@ RESTRICT_BETWEEN
Definition route.hxx:75
static double atof(const string &str)
Definition options.cxx:107