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>
27 #include <simgear/route/waypoint.hxx>
29 #include <Airports/simple.hxx>
30 #include <Airports/runways.hxx>
37 BasicWaypt::BasicWaypt(const SGGeod& aPos, const string& aIdent, RouteBase* aOwner) :
42 if (aPos.getElevationFt() > -999.0) {
43 setAltitude(aPos.getElevationFt(), RESTRICT_AT);
47 BasicWaypt::BasicWaypt(const SGWayPoint& aWP, RouteBase* aOwner) :
49 _pos(aWP.get_target()),
54 BasicWaypt::BasicWaypt(RouteBase* aOwner) :
59 void BasicWaypt::initFromProperties(SGPropertyNode_ptr aProp)
61 if (!aProp->hasChild("lon") || !aProp->hasChild("lat")) {
62 throw sg_io_exception("missing lon/lat properties",
63 "BasicWaypt::initFromProperties");
66 Waypt::initFromProperties(aProp);
68 _pos = SGGeod::fromDeg(aProp->getDoubleValue("lon"),
69 aProp->getDoubleValue("lat"));
70 _ident = aProp->getStringValue("ident");
73 void BasicWaypt::writeToProperties(SGPropertyNode_ptr aProp) const
75 Waypt::writeToProperties(aProp);
77 aProp->setStringValue("ident", _ident);
78 aProp->setDoubleValue("lon", _pos.getLongitudeDeg());
79 aProp->setDoubleValue("lat", _pos.getLatitudeDeg());
82 //////////////////////////////////////////////////////////////////////////////
84 NavaidWaypoint::NavaidWaypoint(FGPositioned* aPos, RouteBase* aOwner) :
88 if (aPos->type() == FGPositioned::RUNWAY) {
89 SG_LOG(SG_GENERAL, SG_WARN, "sure you don't want to be building a runway waypt here?");
93 NavaidWaypoint::NavaidWaypoint(RouteBase* aOwner) :
99 SGGeod NavaidWaypoint::position() const
101 return SGGeod::fromGeodFt(_navaid->geod(), _altitudeFt);
104 std::string NavaidWaypoint::ident() const
106 return _navaid->ident();
109 void NavaidWaypoint::initFromProperties(SGPropertyNode_ptr aProp)
111 if (!aProp->hasChild("ident")) {
112 throw sg_io_exception("missing navaid value",
113 "NavaidWaypoint::initFromProperties");
116 Waypt::initFromProperties(aProp);
118 std::string idn(aProp->getStringValue("ident"));
120 if (aProp->hasChild("lon")) {
121 p = SGGeod::fromDeg(aProp->getDoubleValue("lon"), aProp->getDoubleValue("lat"));
124 // FIXME - resolve co-located DME, etc
125 // is it sufficent just to ignore DMEs, actually?
126 FGPositionedRef nav = FGPositioned::findClosestWithIdent(idn, p, NULL);
128 throw sg_io_exception("unknown navaid ident:" + idn,
129 "NavaidWaypoint::initFromProperties");
135 void NavaidWaypoint::writeToProperties(SGPropertyNode_ptr aProp) const
137 Waypt::writeToProperties(aProp);
139 aProp->setStringValue("ident", _navaid->ident());
140 // write lon/lat to disambiguate
141 aProp->setDoubleValue("lon", _navaid->geod().getLongitudeDeg());
142 aProp->setDoubleValue("lat", _navaid->geod().getLatitudeDeg());
145 OffsetNavaidWaypoint::OffsetNavaidWaypoint(FGPositioned* aPos, RouteBase* aOwner,
146 double aRadial, double aDistNm) :
147 NavaidWaypoint(aPos, aOwner),
154 OffsetNavaidWaypoint::OffsetNavaidWaypoint(RouteBase* aOwner) :
155 NavaidWaypoint(aOwner)
159 void OffsetNavaidWaypoint::init()
163 SGGeodesy::direct(_navaid->geod(), _radial, _distanceNm * SG_NM_TO_METER, offset, az2);
164 _geod = SGGeod::fromGeodFt(offset, _altitudeFt);
167 void OffsetNavaidWaypoint::initFromProperties(SGPropertyNode_ptr aProp)
169 if (!aProp->hasChild("radial-deg") || !aProp->hasChild("distance-nm")) {
170 throw sg_io_exception("missing radial/offset distance",
171 "OffsetNavaidWaypoint::initFromProperties");
174 NavaidWaypoint::initFromProperties(aProp);
175 _radial = aProp->getDoubleValue("radial-deg");
176 _distanceNm = aProp->getDoubleValue("distance-nm");
180 void OffsetNavaidWaypoint::writeToProperties(SGPropertyNode_ptr aProp) const
182 NavaidWaypoint::writeToProperties(aProp);
183 aProp->setDoubleValue("radial-deg", _radial);
184 aProp->setDoubleValue("distance-nm", _distanceNm);
187 /////////////////////////////////////////////////////////////////////////////
189 RunwayWaypt::RunwayWaypt(FGRunway* aPos, RouteBase* aOwner) :
195 RunwayWaypt::RunwayWaypt(RouteBase* aOwner) :
200 SGGeod RunwayWaypt::position() const
202 return _runway->threshold();
205 std::string RunwayWaypt::ident() const
207 return _runway->airport()->ident() + "-" + _runway->ident();
210 FGPositioned* RunwayWaypt::source() const
215 double RunwayWaypt::headingRadialDeg() const
217 return _runway->headingDeg();
220 void RunwayWaypt::initFromProperties(SGPropertyNode_ptr aProp)
222 if (!aProp->hasChild("icao") || !aProp->hasChild("ident")) {
223 throw sg_io_exception("missing values: icao or ident",
224 "RunwayWaypoint::initFromProperties");
227 Waypt::initFromProperties(aProp);
228 std::string idn(aProp->getStringValue("ident"));
229 const FGAirport* apt = FGAirport::getByIdent(aProp->getStringValue("icao"));
230 _runway = apt->getRunwayByIdent(aProp->getStringValue("ident"));
233 void RunwayWaypt::writeToProperties(SGPropertyNode_ptr aProp) const
235 Waypt::writeToProperties(aProp);
236 aProp->setStringValue("ident", _runway->ident());
237 aProp->setStringValue("icao", _runway->airport()->ident());
240 /////////////////////////////////////////////////////////////////////////////
242 Hold::Hold(const SGGeod& aPos, const string& aIdent, RouteBase* aOwner) :
243 BasicWaypt(aPos, aIdent, aOwner),
247 setFlag(WPT_DYNAMIC);
250 Hold::Hold(RouteBase* aOwner) :
257 void Hold::setHoldRadial(double aInboundRadial)
259 _bearing = aInboundRadial;
262 void Hold::setHoldDistance(double aDistanceNm)
265 _holdTD = aDistanceNm;
268 void Hold::setHoldTime(double aTimeSec)
274 void Hold::setRightHanded()
279 void Hold::setLeftHanded()
281 _righthanded = false;
284 void Hold::initFromProperties(SGPropertyNode_ptr aProp)
286 BasicWaypt::initFromProperties(aProp);
288 if (!aProp->hasChild("lon") || !aProp->hasChild("lat")) {
289 throw sg_io_exception("missing lon/lat properties",
290 "Hold::initFromProperties");
293 _righthanded = aProp->getBoolValue("right-handed");
294 _isDistance = aProp->getBoolValue("is-distance");
295 _bearing = aProp->getDoubleValue("inbound-radial-deg");
296 _holdTD = aProp->getDoubleValue("td");
299 void Hold::writeToProperties(SGPropertyNode_ptr aProp) const
301 BasicWaypt::writeToProperties(aProp);
303 aProp->setBoolValue("right-handed", _righthanded);
304 aProp->setBoolValue("is-distance", _isDistance);
305 aProp->setDoubleValue("inbound-radial-deg", _bearing);
306 aProp->setDoubleValue("td", _holdTD);
309 /////////////////////////////////////////////////////////////////////////////
311 HeadingToAltitude::HeadingToAltitude(RouteBase* aOwner, const string& aIdent,
317 setFlag(WPT_DYNAMIC);
320 HeadingToAltitude::HeadingToAltitude(RouteBase* aOwner) :
325 void HeadingToAltitude::initFromProperties(SGPropertyNode_ptr aProp)
327 if (!aProp->hasChild("heading-deg")) {
328 throw sg_io_exception("missing heading/alt properties",
329 "HeadingToAltitude::initFromProperties");
332 Waypt::initFromProperties(aProp);
333 _magHeading = aProp->getDoubleValue("heading-deg");
334 _ident = aProp->getStringValue("ident");
337 void HeadingToAltitude::writeToProperties(SGPropertyNode_ptr aProp) const
339 Waypt::writeToProperties(aProp);
340 aProp->setStringValue("ident", _ident);
341 aProp->setDoubleValue("heading-deg", _magHeading);
344 /////////////////////////////////////////////////////////////////////////////
346 DMEIntercept::DMEIntercept(RouteBase* aOwner, const string& aIdent, const SGGeod& aPos,
347 double aCourseDeg, double aDistanceNm) :
351 _magCourse(aCourseDeg),
352 _dmeDistanceNm(aDistanceNm)
354 setFlag(WPT_DYNAMIC);
357 DMEIntercept::DMEIntercept(RouteBase* aOwner) :
362 void DMEIntercept::initFromProperties(SGPropertyNode_ptr aProp)
364 if (!aProp->hasChild("lon") || !aProp->hasChild("lat")) {
365 throw sg_io_exception("missing lon/lat properties",
366 "DMEIntercept::initFromProperties");
369 Waypt::initFromProperties(aProp);
370 _pos = SGGeod::fromDeg(aProp->getDoubleValue("lon"), aProp->getDoubleValue("lat"));
371 _ident = aProp->getStringValue("ident");
372 // check it's a real DME?
373 _magCourse = aProp->getDoubleValue("course-deg");
374 _dmeDistanceNm = aProp->getDoubleValue("dme-distance-nm");
378 void DMEIntercept::writeToProperties(SGPropertyNode_ptr aProp) const
380 Waypt::writeToProperties(aProp);
382 aProp->setStringValue("ident", _ident);
383 aProp->setDoubleValue("lon", _pos.getLongitudeDeg());
384 aProp->setDoubleValue("lat", _pos.getLatitudeDeg());
385 aProp->setDoubleValue("course-deg", _magCourse);
386 aProp->setDoubleValue("dme-distance-nm", _dmeDistanceNm);
389 /////////////////////////////////////////////////////////////////////////////
391 RadialIntercept::RadialIntercept(RouteBase* aOwner, const string& aIdent, const SGGeod& aPos,
392 double aCourseDeg, double aRadial) :
396 _magCourse(aCourseDeg),
399 setFlag(WPT_DYNAMIC);
402 RadialIntercept::RadialIntercept(RouteBase* aOwner) :
407 void RadialIntercept::initFromProperties(SGPropertyNode_ptr aProp)
409 if (!aProp->hasChild("lon") || !aProp->hasChild("lat")) {
410 throw sg_io_exception("missing lon/lat properties",
411 "RadialIntercept::initFromProperties");
414 Waypt::initFromProperties(aProp);
415 _pos = SGGeod::fromDeg(aProp->getDoubleValue("lon"), aProp->getDoubleValue("lat"));
416 _ident = aProp->getStringValue("ident");
417 // check it's a real VOR?
418 _magCourse = aProp->getDoubleValue("course-deg");
419 _radial = aProp->getDoubleValue("radial-deg");
423 void RadialIntercept::writeToProperties(SGPropertyNode_ptr aProp) const
425 Waypt::writeToProperties(aProp);
427 aProp->setStringValue("ident", _ident);
428 aProp->setDoubleValue("lon", _pos.getLongitudeDeg());
429 aProp->setDoubleValue("lat", _pos.getLatitudeDeg());
430 aProp->setDoubleValue("course-deg", _magCourse);
431 aProp->setDoubleValue("radial-deg", _radial);
434 /////////////////////////////////////////////////////////////////////////////
436 ATCVectors::ATCVectors(RouteBase* aOwner, FGAirport* aFacility) :
440 setFlag(WPT_DYNAMIC);
443 ATCVectors::~ATCVectors()
447 ATCVectors::ATCVectors(RouteBase* aOwner) :
452 SGGeod ATCVectors::position() const
454 return _facility->geod();
457 string ATCVectors::ident() const
459 return "VECTORS-" + _facility->ident();
462 void ATCVectors::initFromProperties(SGPropertyNode_ptr aProp)
464 if (!aProp->hasChild("icao")) {
465 throw sg_io_exception("missing icao propertie",
466 "ATCVectors::initFromProperties");
469 Waypt::initFromProperties(aProp);
470 _facility = FGAirport::getByIdent(aProp->getStringValue("icao"));
473 void ATCVectors::writeToProperties(SGPropertyNode_ptr aProp) const
475 Waypt::writeToProperties(aProp);
476 aProp->setStringValue("icao", _facility->ident());