]> git.mxchange.org Git - flightgear.git/blob - src/Navaids/waypoint.cxx
Give the FGAirport class a sane filename.
[flightgear.git] / src / Navaids / waypoint.cxx
1 // waypoint.cxx - waypoints that can occur in routes/procedures
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 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23
24 #include "waypoint.hxx"
25
26 #include <simgear/structure/exception.hxx>
27
28 #include <Airports/airport.hxx>
29 #include <Airports/runways.hxx>
30
31 using std::string;
32
33 namespace flightgear
34 {
35
36 BasicWaypt::BasicWaypt(const SGGeod& aPos, const string& aIdent, RouteBase* aOwner) :
37   Waypt(aOwner),
38   _pos(aPos),
39   _ident(aIdent)
40 {
41   if (aPos.getElevationFt() > -999.0) {
42     setAltitude(aPos.getElevationFt(), RESTRICT_AT);
43   }
44 }
45
46 BasicWaypt::BasicWaypt(RouteBase* aOwner) :
47   Waypt(aOwner)
48 {
49 }
50
51 void BasicWaypt::initFromProperties(SGPropertyNode_ptr aProp)
52 {
53   if (!aProp->hasChild("lon") || !aProp->hasChild("lat")) {
54     throw sg_io_exception("missing lon/lat properties", 
55       "BasicWaypt::initFromProperties");
56   }
57
58   Waypt::initFromProperties(aProp);
59
60   _pos = SGGeod::fromDeg(aProp->getDoubleValue("lon"), 
61     aProp->getDoubleValue("lat"));
62   _ident = aProp->getStringValue("ident");
63 }
64
65 void BasicWaypt::writeToProperties(SGPropertyNode_ptr aProp) const
66 {
67   Waypt::writeToProperties(aProp);
68   
69   aProp->setStringValue("ident", _ident);
70   aProp->setDoubleValue("lon", _pos.getLongitudeDeg());
71   aProp->setDoubleValue("lat", _pos.getLatitudeDeg());
72 }
73
74 //////////////////////////////////////////////////////////////////////////////
75
76 NavaidWaypoint::NavaidWaypoint(FGPositioned* aPos, RouteBase* aOwner) :
77   Waypt(aOwner),
78   _navaid(aPos)
79 {
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?");
82   }
83 }
84
85 NavaidWaypoint::NavaidWaypoint(RouteBase* aOwner) :
86   Waypt(aOwner)
87 {
88 }
89
90
91 SGGeod NavaidWaypoint::position() const
92 {
93   return SGGeod::fromGeodFt(_navaid->geod(), _altitudeFt);
94 }  
95  
96 std::string NavaidWaypoint::ident() const
97 {
98   return _navaid->ident();
99 }
100
101 void NavaidWaypoint::initFromProperties(SGPropertyNode_ptr aProp)
102 {
103   if (!aProp->hasChild("ident")) {
104     throw sg_io_exception("missing navaid value", 
105       "NavaidWaypoint::initFromProperties");
106   }
107   
108   Waypt::initFromProperties(aProp);
109   
110   std::string idn(aProp->getStringValue("ident"));
111   SGGeod p;
112   if (aProp->hasChild("lon")) {
113     p = SGGeod::fromDeg(aProp->getDoubleValue("lon"), aProp->getDoubleValue("lat"));
114   }
115   
116   // FIXME - resolve co-located DME, etc
117   // is it sufficent just to ignore DMEs, actually?
118   FGPositionedRef nav = FGPositioned::findClosestWithIdent(idn, p, NULL);
119   if (!nav) {
120     throw sg_io_exception("unknown navaid ident:" + idn, 
121       "NavaidWaypoint::initFromProperties");
122   }
123   
124   _navaid = nav;
125 }
126
127 void NavaidWaypoint::writeToProperties(SGPropertyNode_ptr aProp) const
128 {
129   Waypt::writeToProperties(aProp);
130   
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());
135 }
136
137 OffsetNavaidWaypoint::OffsetNavaidWaypoint(FGPositioned* aPos, RouteBase* aOwner,
138   double aRadial, double aDistNm) :
139   NavaidWaypoint(aPos, aOwner),
140   _radial(aRadial),
141   _distanceNm(aDistNm)
142 {
143   init();
144 }
145
146 OffsetNavaidWaypoint::OffsetNavaidWaypoint(RouteBase* aOwner) :
147   NavaidWaypoint(aOwner)
148 {
149 }
150
151 void OffsetNavaidWaypoint::init()
152 {
153   SGGeod offset;
154   double az2;
155   SGGeodesy::direct(_navaid->geod(), _radial, _distanceNm * SG_NM_TO_METER, offset, az2);
156   _geod = SGGeod::fromGeodFt(offset, _altitudeFt);
157 }
158
159 void OffsetNavaidWaypoint::initFromProperties(SGPropertyNode_ptr aProp)
160 {
161   if (!aProp->hasChild("radial-deg") || !aProp->hasChild("distance-nm")) {
162     throw sg_io_exception("missing radial/offset distance",
163       "OffsetNavaidWaypoint::initFromProperties");
164   }
165   
166   NavaidWaypoint::initFromProperties(aProp);
167   _radial = aProp->getDoubleValue("radial-deg");
168   _distanceNm = aProp->getDoubleValue("distance-nm");
169   init();
170 }
171
172 void OffsetNavaidWaypoint::writeToProperties(SGPropertyNode_ptr aProp) const
173 {
174   NavaidWaypoint::writeToProperties(aProp);
175   aProp->setDoubleValue("radial-deg", _radial);
176   aProp->setDoubleValue("distance-nm", _distanceNm);
177 }
178
179 /////////////////////////////////////////////////////////////////////////////
180
181 RunwayWaypt::RunwayWaypt(FGRunway* aPos, RouteBase* aOwner) :
182   Waypt(aOwner),
183   _runway(aPos)
184 {
185 }
186
187 RunwayWaypt::RunwayWaypt(RouteBase* aOwner) :
188   Waypt(aOwner)
189 {
190 }
191
192 SGGeod RunwayWaypt::position() const
193 {
194   return _runway->threshold();
195 }
196   
197 std::string RunwayWaypt::ident() const
198 {
199   return _runway->airport()->ident() + "-" + _runway->ident();
200 }
201
202 FGPositioned* RunwayWaypt::source() const
203 {
204   return _runway;
205 }
206   
207 double RunwayWaypt::headingRadialDeg() const
208 {
209   return _runway->headingDeg();
210 }
211
212 void RunwayWaypt::initFromProperties(SGPropertyNode_ptr aProp)
213 {
214   if (!aProp->hasChild("icao") || !aProp->hasChild("ident")) {
215     throw sg_io_exception("missing values: icao or ident", 
216       "RunwayWaypoint::initFromProperties");
217   }
218   
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"));
223 }
224
225 void RunwayWaypt::writeToProperties(SGPropertyNode_ptr aProp) const
226 {
227   Waypt::writeToProperties(aProp);
228   aProp->setStringValue("ident", _runway->ident());
229   aProp->setStringValue("icao", _runway->airport()->ident());
230 }
231
232 /////////////////////////////////////////////////////////////////////////////
233
234 Hold::Hold(const SGGeod& aPos, const string& aIdent, RouteBase* aOwner) :
235   BasicWaypt(aPos, aIdent, aOwner),
236   _righthanded(true),
237   _isDistance(false)
238 {
239   setFlag(WPT_DYNAMIC);
240 }
241
242 Hold::Hold(RouteBase* aOwner) :
243   BasicWaypt(aOwner),
244   _righthanded(true),
245   _isDistance(false)
246 {
247 }
248
249 void Hold::setHoldRadial(double aInboundRadial)
250 {
251   _bearing = aInboundRadial;
252 }
253
254 void Hold::setHoldDistance(double aDistanceNm)
255 {
256   _isDistance = true;
257   _holdTD = aDistanceNm;
258 }
259
260 void Hold::setHoldTime(double aTimeSec)
261 {
262   _isDistance = false;
263   _holdTD = aTimeSec;
264 }
265
266 void Hold::setRightHanded()
267 {
268   _righthanded = true;
269 }
270
271 void Hold::setLeftHanded()
272 {
273   _righthanded = false;
274 }
275   
276 void Hold::initFromProperties(SGPropertyNode_ptr aProp)
277 {
278   BasicWaypt::initFromProperties(aProp);
279   
280   if (!aProp->hasChild("lon") || !aProp->hasChild("lat")) {
281     throw sg_io_exception("missing lon/lat properties", 
282       "Hold::initFromProperties");
283   }
284
285   _righthanded = aProp->getBoolValue("right-handed");
286   _isDistance = aProp->getBoolValue("is-distance");
287   _bearing = aProp->getDoubleValue("inbound-radial-deg");
288   _holdTD = aProp->getDoubleValue("td");
289 }
290
291 void Hold::writeToProperties(SGPropertyNode_ptr aProp) const
292 {
293   BasicWaypt::writeToProperties(aProp);
294
295   aProp->setBoolValue("right-handed", _righthanded);
296   aProp->setBoolValue("is-distance", _isDistance);
297   aProp->setDoubleValue("inbound-radial-deg", _bearing);
298   aProp->setDoubleValue("td", _holdTD);
299 }
300
301 /////////////////////////////////////////////////////////////////////////////
302
303 HeadingToAltitude::HeadingToAltitude(RouteBase* aOwner, const string& aIdent, 
304   double aMagHdg) :
305   Waypt(aOwner),
306   _ident(aIdent),
307   _magHeading(aMagHdg)
308 {
309   setFlag(WPT_DYNAMIC);
310 }
311
312 HeadingToAltitude::HeadingToAltitude(RouteBase* aOwner) :
313   Waypt(aOwner)
314 {
315 }
316
317 void HeadingToAltitude::initFromProperties(SGPropertyNode_ptr aProp)
318 {
319   if (!aProp->hasChild("heading-deg")) {
320     throw sg_io_exception("missing heading/alt properties", 
321       "HeadingToAltitude::initFromProperties");
322   }
323
324   Waypt::initFromProperties(aProp);
325   _magHeading = aProp->getDoubleValue("heading-deg");
326   _ident = aProp->getStringValue("ident");
327 }
328
329 void HeadingToAltitude::writeToProperties(SGPropertyNode_ptr aProp) const
330 {
331   Waypt::writeToProperties(aProp);
332   aProp->setStringValue("ident", _ident);
333   aProp->setDoubleValue("heading-deg", _magHeading);
334 }
335
336 /////////////////////////////////////////////////////////////////////////////
337
338 DMEIntercept::DMEIntercept(RouteBase* aOwner, const string& aIdent, const SGGeod& aPos,
339     double aCourseDeg, double aDistanceNm) :
340   Waypt(aOwner),
341   _ident(aIdent),
342   _pos(aPos),
343   _magCourse(aCourseDeg),
344   _dmeDistanceNm(aDistanceNm)
345 {
346   setFlag(WPT_DYNAMIC);
347 }
348
349 DMEIntercept::DMEIntercept(RouteBase* aOwner) :
350   Waypt(aOwner)
351 {
352 }
353
354 void DMEIntercept::initFromProperties(SGPropertyNode_ptr aProp)
355 {
356   if (!aProp->hasChild("lon") || !aProp->hasChild("lat")) {
357     throw sg_io_exception("missing lon/lat properties", 
358       "DMEIntercept::initFromProperties");
359   }
360
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");
367   
368 }
369
370 void DMEIntercept::writeToProperties(SGPropertyNode_ptr aProp) const
371 {
372   Waypt::writeToProperties(aProp);
373   
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);
379 }
380
381 /////////////////////////////////////////////////////////////////////////////
382
383 RadialIntercept::RadialIntercept(RouteBase* aOwner, const string& aIdent, const SGGeod& aPos,
384     double aCourseDeg, double aRadial) :
385   Waypt(aOwner),
386   _ident(aIdent),
387   _pos(aPos),
388   _magCourse(aCourseDeg),
389   _radial(aRadial)
390 {
391   setFlag(WPT_DYNAMIC);
392 }
393
394 RadialIntercept::RadialIntercept(RouteBase* aOwner) :
395   Waypt(aOwner)
396 {
397 }
398   
399 void RadialIntercept::initFromProperties(SGPropertyNode_ptr aProp)
400 {
401   if (!aProp->hasChild("lon") || !aProp->hasChild("lat")) {
402     throw sg_io_exception("missing lon/lat properties", 
403       "RadialIntercept::initFromProperties");
404   }
405
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");
412   
413 }
414
415 void RadialIntercept::writeToProperties(SGPropertyNode_ptr aProp) const
416 {
417   Waypt::writeToProperties(aProp);
418   
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);
424 }
425
426 /////////////////////////////////////////////////////////////////////////////
427
428 ATCVectors::ATCVectors(RouteBase* aOwner, FGAirport* aFacility) :
429   Waypt(aOwner),
430   _facility(aFacility)
431 {
432   setFlag(WPT_DYNAMIC);
433 }
434
435 ATCVectors::~ATCVectors()
436 {
437 }
438
439 ATCVectors::ATCVectors(RouteBase* aOwner) :
440   Waypt(aOwner)
441 {
442 }
443
444 SGGeod ATCVectors::position() const
445 {
446   return _facility->geod();
447 }
448     
449 string ATCVectors::ident() const
450 {
451   return "VECTORS-" + _facility->ident();
452 }
453
454 void ATCVectors::initFromProperties(SGPropertyNode_ptr aProp)
455 {  
456   if (!aProp->hasChild("icao")) {
457     throw sg_io_exception("missing icao propertie", 
458       "ATCVectors::initFromProperties");
459   }
460
461   Waypt::initFromProperties(aProp);
462   _facility = FGAirport::getByIdent(aProp->getStringValue("icao"));
463 }
464
465 void ATCVectors::writeToProperties(SGPropertyNode_ptr aProp) const
466 {
467   Waypt::writeToProperties(aProp);
468   aProp->setStringValue("icao", _facility->ident());
469 }
470
471 } // of namespace