1 // waypoint.cxx - waypoints that can occur in routes/procedures
2 // Written by James Turner, started 2009.
4 // Copyright (C) 2009 Curtis L. Olson
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.
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.
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.
24 #include "waypoint.hxx"
26 #include <simgear/structure/exception.hxx>
28 #include <Airports/airport.hxx>
29 #include <Airports/runways.hxx>
36 BasicWaypt::BasicWaypt(const SGGeod& aPos, const string& aIdent, RouteBase* aOwner) :
43 BasicWaypt::BasicWaypt(RouteBase* aOwner) :
48 void BasicWaypt::initFromProperties(SGPropertyNode_ptr aProp)
50 if (!aProp->hasChild("lon") || !aProp->hasChild("lat")) {
51 throw sg_io_exception("missing lon/lat properties",
52 "BasicWaypt::initFromProperties");
55 Waypt::initFromProperties(aProp);
57 _pos = SGGeod::fromDeg(aProp->getDoubleValue("lon"),
58 aProp->getDoubleValue("lat"));
59 _ident = aProp->getStringValue("ident");
62 void BasicWaypt::writeToProperties(SGPropertyNode_ptr aProp) const
64 Waypt::writeToProperties(aProp);
66 aProp->setStringValue("ident", _ident);
67 aProp->setDoubleValue("lon", _pos.getLongitudeDeg());
68 aProp->setDoubleValue("lat", _pos.getLatitudeDeg());
71 //////////////////////////////////////////////////////////////////////////////
73 NavaidWaypoint::NavaidWaypoint(FGPositioned* aPos, RouteBase* aOwner) :
77 if (aPos->type() == FGPositioned::RUNWAY) {
78 SG_LOG(SG_NAVAID, SG_WARN, "sure you don't want to be building a runway waypt here?");
82 NavaidWaypoint::NavaidWaypoint(RouteBase* aOwner) :
88 SGGeod NavaidWaypoint::position() const
90 return SGGeod::fromGeodFt(_navaid->geod(), _altitudeFt);
93 std::string NavaidWaypoint::ident() const
95 return _navaid->ident();
98 void NavaidWaypoint::initFromProperties(SGPropertyNode_ptr aProp)
100 if (!aProp->hasChild("ident")) {
101 throw sg_io_exception("missing navaid value",
102 "NavaidWaypoint::initFromProperties");
105 Waypt::initFromProperties(aProp);
107 std::string idn(aProp->getStringValue("ident"));
109 if (aProp->hasChild("lon")) {
110 p = SGGeod::fromDeg(aProp->getDoubleValue("lon"), aProp->getDoubleValue("lat"));
113 // FIXME - resolve co-located DME, etc
114 // is it sufficent just to ignore DMEs, actually?
115 FGPositionedRef nav = FGPositioned::findClosestWithIdent(idn, p, NULL);
117 throw sg_io_exception("unknown navaid ident:" + idn,
118 "NavaidWaypoint::initFromProperties");
124 void NavaidWaypoint::writeToProperties(SGPropertyNode_ptr aProp) const
126 Waypt::writeToProperties(aProp);
128 aProp->setStringValue("ident", _navaid->ident());
129 // write lon/lat to disambiguate
130 aProp->setDoubleValue("lon", _navaid->geod().getLongitudeDeg());
131 aProp->setDoubleValue("lat", _navaid->geod().getLatitudeDeg());
134 OffsetNavaidWaypoint::OffsetNavaidWaypoint(FGPositioned* aPos, RouteBase* aOwner,
135 double aRadial, double aDistNm) :
136 NavaidWaypoint(aPos, aOwner),
143 OffsetNavaidWaypoint::OffsetNavaidWaypoint(RouteBase* aOwner) :
144 NavaidWaypoint(aOwner)
148 void OffsetNavaidWaypoint::init()
152 SGGeodesy::direct(_navaid->geod(), _radial, _distanceNm * SG_NM_TO_METER, offset, az2);
153 _geod = SGGeod::fromGeodFt(offset, _altitudeFt);
156 void OffsetNavaidWaypoint::initFromProperties(SGPropertyNode_ptr aProp)
158 if (!aProp->hasChild("radial-deg") || !aProp->hasChild("distance-nm")) {
159 throw sg_io_exception("missing radial/offset distance",
160 "OffsetNavaidWaypoint::initFromProperties");
163 NavaidWaypoint::initFromProperties(aProp);
164 _radial = aProp->getDoubleValue("radial-deg");
165 _distanceNm = aProp->getDoubleValue("distance-nm");
169 void OffsetNavaidWaypoint::writeToProperties(SGPropertyNode_ptr aProp) const
171 NavaidWaypoint::writeToProperties(aProp);
172 aProp->setDoubleValue("radial-deg", _radial);
173 aProp->setDoubleValue("distance-nm", _distanceNm);
176 /////////////////////////////////////////////////////////////////////////////
178 RunwayWaypt::RunwayWaypt(FGRunway* aPos, RouteBase* aOwner) :
184 RunwayWaypt::RunwayWaypt(RouteBase* aOwner) :
189 SGGeod RunwayWaypt::position() const
191 return _runway->threshold();
194 std::string RunwayWaypt::ident() const
196 return _runway->airport()->ident() + "-" + _runway->ident();
199 FGPositioned* RunwayWaypt::source() const
204 double RunwayWaypt::headingRadialDeg() const
206 return _runway->headingDeg();
209 void RunwayWaypt::initFromProperties(SGPropertyNode_ptr aProp)
211 if (!aProp->hasChild("icao") || !aProp->hasChild("ident")) {
212 throw sg_io_exception("missing values: icao or ident",
213 "RunwayWaypoint::initFromProperties");
216 Waypt::initFromProperties(aProp);
217 std::string idn(aProp->getStringValue("ident"));
218 const FGAirport* apt = FGAirport::getByIdent(aProp->getStringValue("icao"));
219 _runway = apt->getRunwayByIdent(aProp->getStringValue("ident"));
222 void RunwayWaypt::writeToProperties(SGPropertyNode_ptr aProp) const
224 Waypt::writeToProperties(aProp);
225 aProp->setStringValue("ident", _runway->ident());
226 aProp->setStringValue("icao", _runway->airport()->ident());
229 /////////////////////////////////////////////////////////////////////////////
231 Hold::Hold(const SGGeod& aPos, const string& aIdent, RouteBase* aOwner) :
232 BasicWaypt(aPos, aIdent, aOwner),
236 setFlag(WPT_DYNAMIC);
239 Hold::Hold(RouteBase* aOwner) :
246 void Hold::setHoldRadial(double aInboundRadial)
248 _bearing = aInboundRadial;
251 void Hold::setHoldDistance(double aDistanceNm)
254 _holdTD = aDistanceNm;
257 void Hold::setHoldTime(double aTimeSec)
263 void Hold::setRightHanded()
268 void Hold::setLeftHanded()
270 _righthanded = false;
273 void Hold::initFromProperties(SGPropertyNode_ptr aProp)
275 BasicWaypt::initFromProperties(aProp);
277 if (!aProp->hasChild("lon") || !aProp->hasChild("lat")) {
278 throw sg_io_exception("missing lon/lat properties",
279 "Hold::initFromProperties");
282 _righthanded = aProp->getBoolValue("right-handed");
283 _isDistance = aProp->getBoolValue("is-distance");
284 _bearing = aProp->getDoubleValue("inbound-radial-deg");
285 _holdTD = aProp->getDoubleValue("td");
288 void Hold::writeToProperties(SGPropertyNode_ptr aProp) const
290 BasicWaypt::writeToProperties(aProp);
292 aProp->setBoolValue("right-handed", _righthanded);
293 aProp->setBoolValue("is-distance", _isDistance);
294 aProp->setDoubleValue("inbound-radial-deg", _bearing);
295 aProp->setDoubleValue("td", _holdTD);
298 /////////////////////////////////////////////////////////////////////////////
300 HeadingToAltitude::HeadingToAltitude(RouteBase* aOwner, const string& aIdent,
306 setFlag(WPT_DYNAMIC);
309 HeadingToAltitude::HeadingToAltitude(RouteBase* aOwner) :
314 void HeadingToAltitude::initFromProperties(SGPropertyNode_ptr aProp)
316 if (!aProp->hasChild("heading-deg")) {
317 throw sg_io_exception("missing heading/alt properties",
318 "HeadingToAltitude::initFromProperties");
321 Waypt::initFromProperties(aProp);
322 _magHeading = aProp->getDoubleValue("heading-deg");
323 _ident = aProp->getStringValue("ident");
326 void HeadingToAltitude::writeToProperties(SGPropertyNode_ptr aProp) const
328 Waypt::writeToProperties(aProp);
329 aProp->setStringValue("ident", _ident);
330 aProp->setDoubleValue("heading-deg", _magHeading);
333 /////////////////////////////////////////////////////////////////////////////
335 DMEIntercept::DMEIntercept(RouteBase* aOwner, const string& aIdent, const SGGeod& aPos,
336 double aCourseDeg, double aDistanceNm) :
340 _magCourse(aCourseDeg),
341 _dmeDistanceNm(aDistanceNm)
343 setFlag(WPT_DYNAMIC);
346 DMEIntercept::DMEIntercept(RouteBase* aOwner) :
351 void DMEIntercept::initFromProperties(SGPropertyNode_ptr aProp)
353 if (!aProp->hasChild("lon") || !aProp->hasChild("lat")) {
354 throw sg_io_exception("missing lon/lat properties",
355 "DMEIntercept::initFromProperties");
358 Waypt::initFromProperties(aProp);
359 _pos = SGGeod::fromDeg(aProp->getDoubleValue("lon"), aProp->getDoubleValue("lat"));
360 _ident = aProp->getStringValue("ident");
361 // check it's a real DME?
362 _magCourse = aProp->getDoubleValue("course-deg");
363 _dmeDistanceNm = aProp->getDoubleValue("dme-distance-nm");
367 void DMEIntercept::writeToProperties(SGPropertyNode_ptr aProp) const
369 Waypt::writeToProperties(aProp);
371 aProp->setStringValue("ident", _ident);
372 aProp->setDoubleValue("lon", _pos.getLongitudeDeg());
373 aProp->setDoubleValue("lat", _pos.getLatitudeDeg());
374 aProp->setDoubleValue("course-deg", _magCourse);
375 aProp->setDoubleValue("dme-distance-nm", _dmeDistanceNm);
378 /////////////////////////////////////////////////////////////////////////////
380 RadialIntercept::RadialIntercept(RouteBase* aOwner, const string& aIdent, const SGGeod& aPos,
381 double aCourseDeg, double aRadial) :
385 _magCourse(aCourseDeg),
388 setFlag(WPT_DYNAMIC);
391 RadialIntercept::RadialIntercept(RouteBase* aOwner) :
396 void RadialIntercept::initFromProperties(SGPropertyNode_ptr aProp)
398 if (!aProp->hasChild("lon") || !aProp->hasChild("lat")) {
399 throw sg_io_exception("missing lon/lat properties",
400 "RadialIntercept::initFromProperties");
403 Waypt::initFromProperties(aProp);
404 _pos = SGGeod::fromDeg(aProp->getDoubleValue("lon"), aProp->getDoubleValue("lat"));
405 _ident = aProp->getStringValue("ident");
406 // check it's a real VOR?
407 _magCourse = aProp->getDoubleValue("course-deg");
408 _radial = aProp->getDoubleValue("radial-deg");
412 void RadialIntercept::writeToProperties(SGPropertyNode_ptr aProp) const
414 Waypt::writeToProperties(aProp);
416 aProp->setStringValue("ident", _ident);
417 aProp->setDoubleValue("lon", _pos.getLongitudeDeg());
418 aProp->setDoubleValue("lat", _pos.getLatitudeDeg());
419 aProp->setDoubleValue("course-deg", _magCourse);
420 aProp->setDoubleValue("radial-deg", _radial);
423 /////////////////////////////////////////////////////////////////////////////
425 ATCVectors::ATCVectors(RouteBase* aOwner, FGAirport* aFacility) :
429 setFlag(WPT_DYNAMIC);
432 ATCVectors::~ATCVectors()
436 ATCVectors::ATCVectors(RouteBase* aOwner) :
441 SGGeod ATCVectors::position() const
443 return _facility->geod();
446 string ATCVectors::ident() const
448 return "VECTORS-" + _facility->ident();
451 void ATCVectors::initFromProperties(SGPropertyNode_ptr aProp)
453 if (!aProp->hasChild("icao")) {
454 throw sg_io_exception("missing icao propertie",
455 "ATCVectors::initFromProperties");
458 Waypt::initFromProperties(aProp);
459 _facility = FGAirport::getByIdent(aProp->getStringValue("icao"));
462 void ATCVectors::writeToProperties(SGPropertyNode_ptr aProp) const
464 Waypt::writeToProperties(aProp);
465 aProp->setStringValue("icao", _facility->ident());