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) :
41 if (aPos.getElevationFt() > -999.0) {
42 setAltitude(aPos.getElevationFt(), RESTRICT_AT);
46 BasicWaypt::BasicWaypt(RouteBase* aOwner) :
51 void BasicWaypt::initFromProperties(SGPropertyNode_ptr aProp)
53 if (!aProp->hasChild("lon") || !aProp->hasChild("lat")) {
54 throw sg_io_exception("missing lon/lat properties",
55 "BasicWaypt::initFromProperties");
58 Waypt::initFromProperties(aProp);
60 _pos = SGGeod::fromDeg(aProp->getDoubleValue("lon"),
61 aProp->getDoubleValue("lat"));
62 _ident = aProp->getStringValue("ident");
65 void BasicWaypt::writeToProperties(SGPropertyNode_ptr aProp) const
67 Waypt::writeToProperties(aProp);
69 aProp->setStringValue("ident", _ident);
70 aProp->setDoubleValue("lon", _pos.getLongitudeDeg());
71 aProp->setDoubleValue("lat", _pos.getLatitudeDeg());
74 //////////////////////////////////////////////////////////////////////////////
76 NavaidWaypoint::NavaidWaypoint(FGPositioned* aPos, RouteBase* aOwner) :
80 if (aPos->type() == FGPositioned::RUNWAY) {
81 SG_LOG(SG_NAVAID, SG_WARN, "sure you don't want to be building a runway waypt here?");
85 NavaidWaypoint::NavaidWaypoint(RouteBase* aOwner) :
91 SGGeod NavaidWaypoint::position() const
93 return SGGeod::fromGeodFt(_navaid->geod(), _altitudeFt);
96 std::string NavaidWaypoint::ident() const
98 return _navaid->ident();
101 void NavaidWaypoint::initFromProperties(SGPropertyNode_ptr aProp)
103 if (!aProp->hasChild("ident")) {
104 throw sg_io_exception("missing navaid value",
105 "NavaidWaypoint::initFromProperties");
108 Waypt::initFromProperties(aProp);
110 std::string idn(aProp->getStringValue("ident"));
112 if (aProp->hasChild("lon")) {
113 p = SGGeod::fromDeg(aProp->getDoubleValue("lon"), aProp->getDoubleValue("lat"));
116 // FIXME - resolve co-located DME, etc
117 // is it sufficent just to ignore DMEs, actually?
118 FGPositionedRef nav = FGPositioned::findClosestWithIdent(idn, p, NULL);
120 throw sg_io_exception("unknown navaid ident:" + idn,
121 "NavaidWaypoint::initFromProperties");
127 void NavaidWaypoint::writeToProperties(SGPropertyNode_ptr aProp) const
129 Waypt::writeToProperties(aProp);
131 aProp->setStringValue("ident", _navaid->ident());
132 // write lon/lat to disambiguate
133 aProp->setDoubleValue("lon", _navaid->geod().getLongitudeDeg());
134 aProp->setDoubleValue("lat", _navaid->geod().getLatitudeDeg());
137 OffsetNavaidWaypoint::OffsetNavaidWaypoint(FGPositioned* aPos, RouteBase* aOwner,
138 double aRadial, double aDistNm) :
139 NavaidWaypoint(aPos, aOwner),
146 OffsetNavaidWaypoint::OffsetNavaidWaypoint(RouteBase* aOwner) :
147 NavaidWaypoint(aOwner)
151 void OffsetNavaidWaypoint::init()
155 SGGeodesy::direct(_navaid->geod(), _radial, _distanceNm * SG_NM_TO_METER, offset, az2);
156 _geod = SGGeod::fromGeodFt(offset, _altitudeFt);
159 void OffsetNavaidWaypoint::initFromProperties(SGPropertyNode_ptr aProp)
161 if (!aProp->hasChild("radial-deg") || !aProp->hasChild("distance-nm")) {
162 throw sg_io_exception("missing radial/offset distance",
163 "OffsetNavaidWaypoint::initFromProperties");
166 NavaidWaypoint::initFromProperties(aProp);
167 _radial = aProp->getDoubleValue("radial-deg");
168 _distanceNm = aProp->getDoubleValue("distance-nm");
172 void OffsetNavaidWaypoint::writeToProperties(SGPropertyNode_ptr aProp) const
174 NavaidWaypoint::writeToProperties(aProp);
175 aProp->setDoubleValue("radial-deg", _radial);
176 aProp->setDoubleValue("distance-nm", _distanceNm);
179 /////////////////////////////////////////////////////////////////////////////
181 RunwayWaypt::RunwayWaypt(FGRunway* aPos, RouteBase* aOwner) :
187 RunwayWaypt::RunwayWaypt(RouteBase* aOwner) :
192 SGGeod RunwayWaypt::position() const
194 return _runway->threshold();
197 std::string RunwayWaypt::ident() const
199 return _runway->airport()->ident() + "-" + _runway->ident();
202 FGPositioned* RunwayWaypt::source() const
207 double RunwayWaypt::headingRadialDeg() const
209 return _runway->headingDeg();
212 void RunwayWaypt::initFromProperties(SGPropertyNode_ptr aProp)
214 if (!aProp->hasChild("icao") || !aProp->hasChild("ident")) {
215 throw sg_io_exception("missing values: icao or ident",
216 "RunwayWaypoint::initFromProperties");
219 Waypt::initFromProperties(aProp);
220 std::string idn(aProp->getStringValue("ident"));
221 const FGAirport* apt = FGAirport::getByIdent(aProp->getStringValue("icao"));
222 _runway = apt->getRunwayByIdent(aProp->getStringValue("ident"));
225 void RunwayWaypt::writeToProperties(SGPropertyNode_ptr aProp) const
227 Waypt::writeToProperties(aProp);
228 aProp->setStringValue("ident", _runway->ident());
229 aProp->setStringValue("icao", _runway->airport()->ident());
232 /////////////////////////////////////////////////////////////////////////////
234 Hold::Hold(const SGGeod& aPos, const string& aIdent, RouteBase* aOwner) :
235 BasicWaypt(aPos, aIdent, aOwner),
239 setFlag(WPT_DYNAMIC);
242 Hold::Hold(RouteBase* aOwner) :
249 void Hold::setHoldRadial(double aInboundRadial)
251 _bearing = aInboundRadial;
254 void Hold::setHoldDistance(double aDistanceNm)
257 _holdTD = aDistanceNm;
260 void Hold::setHoldTime(double aTimeSec)
266 void Hold::setRightHanded()
271 void Hold::setLeftHanded()
273 _righthanded = false;
276 void Hold::initFromProperties(SGPropertyNode_ptr aProp)
278 BasicWaypt::initFromProperties(aProp);
280 if (!aProp->hasChild("lon") || !aProp->hasChild("lat")) {
281 throw sg_io_exception("missing lon/lat properties",
282 "Hold::initFromProperties");
285 _righthanded = aProp->getBoolValue("right-handed");
286 _isDistance = aProp->getBoolValue("is-distance");
287 _bearing = aProp->getDoubleValue("inbound-radial-deg");
288 _holdTD = aProp->getDoubleValue("td");
291 void Hold::writeToProperties(SGPropertyNode_ptr aProp) const
293 BasicWaypt::writeToProperties(aProp);
295 aProp->setBoolValue("right-handed", _righthanded);
296 aProp->setBoolValue("is-distance", _isDistance);
297 aProp->setDoubleValue("inbound-radial-deg", _bearing);
298 aProp->setDoubleValue("td", _holdTD);
301 /////////////////////////////////////////////////////////////////////////////
303 HeadingToAltitude::HeadingToAltitude(RouteBase* aOwner, const string& aIdent,
309 setFlag(WPT_DYNAMIC);
312 HeadingToAltitude::HeadingToAltitude(RouteBase* aOwner) :
317 void HeadingToAltitude::initFromProperties(SGPropertyNode_ptr aProp)
319 if (!aProp->hasChild("heading-deg")) {
320 throw sg_io_exception("missing heading/alt properties",
321 "HeadingToAltitude::initFromProperties");
324 Waypt::initFromProperties(aProp);
325 _magHeading = aProp->getDoubleValue("heading-deg");
326 _ident = aProp->getStringValue("ident");
329 void HeadingToAltitude::writeToProperties(SGPropertyNode_ptr aProp) const
331 Waypt::writeToProperties(aProp);
332 aProp->setStringValue("ident", _ident);
333 aProp->setDoubleValue("heading-deg", _magHeading);
336 /////////////////////////////////////////////////////////////////////////////
338 DMEIntercept::DMEIntercept(RouteBase* aOwner, const string& aIdent, const SGGeod& aPos,
339 double aCourseDeg, double aDistanceNm) :
343 _magCourse(aCourseDeg),
344 _dmeDistanceNm(aDistanceNm)
346 setFlag(WPT_DYNAMIC);
349 DMEIntercept::DMEIntercept(RouteBase* aOwner) :
354 void DMEIntercept::initFromProperties(SGPropertyNode_ptr aProp)
356 if (!aProp->hasChild("lon") || !aProp->hasChild("lat")) {
357 throw sg_io_exception("missing lon/lat properties",
358 "DMEIntercept::initFromProperties");
361 Waypt::initFromProperties(aProp);
362 _pos = SGGeod::fromDeg(aProp->getDoubleValue("lon"), aProp->getDoubleValue("lat"));
363 _ident = aProp->getStringValue("ident");
364 // check it's a real DME?
365 _magCourse = aProp->getDoubleValue("course-deg");
366 _dmeDistanceNm = aProp->getDoubleValue("dme-distance-nm");
370 void DMEIntercept::writeToProperties(SGPropertyNode_ptr aProp) const
372 Waypt::writeToProperties(aProp);
374 aProp->setStringValue("ident", _ident);
375 aProp->setDoubleValue("lon", _pos.getLongitudeDeg());
376 aProp->setDoubleValue("lat", _pos.getLatitudeDeg());
377 aProp->setDoubleValue("course-deg", _magCourse);
378 aProp->setDoubleValue("dme-distance-nm", _dmeDistanceNm);
381 /////////////////////////////////////////////////////////////////////////////
383 RadialIntercept::RadialIntercept(RouteBase* aOwner, const string& aIdent, const SGGeod& aPos,
384 double aCourseDeg, double aRadial) :
388 _magCourse(aCourseDeg),
391 setFlag(WPT_DYNAMIC);
394 RadialIntercept::RadialIntercept(RouteBase* aOwner) :
399 void RadialIntercept::initFromProperties(SGPropertyNode_ptr aProp)
401 if (!aProp->hasChild("lon") || !aProp->hasChild("lat")) {
402 throw sg_io_exception("missing lon/lat properties",
403 "RadialIntercept::initFromProperties");
406 Waypt::initFromProperties(aProp);
407 _pos = SGGeod::fromDeg(aProp->getDoubleValue("lon"), aProp->getDoubleValue("lat"));
408 _ident = aProp->getStringValue("ident");
409 // check it's a real VOR?
410 _magCourse = aProp->getDoubleValue("course-deg");
411 _radial = aProp->getDoubleValue("radial-deg");
415 void RadialIntercept::writeToProperties(SGPropertyNode_ptr aProp) const
417 Waypt::writeToProperties(aProp);
419 aProp->setStringValue("ident", _ident);
420 aProp->setDoubleValue("lon", _pos.getLongitudeDeg());
421 aProp->setDoubleValue("lat", _pos.getLatitudeDeg());
422 aProp->setDoubleValue("course-deg", _magCourse);
423 aProp->setDoubleValue("radial-deg", _radial);
426 /////////////////////////////////////////////////////////////////////////////
428 ATCVectors::ATCVectors(RouteBase* aOwner, FGAirport* aFacility) :
432 setFlag(WPT_DYNAMIC);
435 ATCVectors::~ATCVectors()
439 ATCVectors::ATCVectors(RouteBase* aOwner) :
444 SGGeod ATCVectors::position() const
446 return _facility->geod();
449 string ATCVectors::ident() const
451 return "VECTORS-" + _facility->ident();
454 void ATCVectors::initFromProperties(SGPropertyNode_ptr aProp)
456 if (!aProp->hasChild("icao")) {
457 throw sg_io_exception("missing icao propertie",
458 "ATCVectors::initFromProperties");
461 Waypt::initFromProperties(aProp);
462 _facility = FGAirport::getByIdent(aProp->getStringValue("icao"));
465 void ATCVectors::writeToProperties(SGPropertyNode_ptr aProp) const
467 Waypt::writeToProperties(aProp);
468 aProp->setStringValue("icao", _facility->ident());