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