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