]> git.mxchange.org Git - flightgear.git/blob - src/Navaids/waypoint.cxx
fix trx and rx heights and improve calculations
[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, Route* 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, Route* aOwner) :
48   Waypt(aOwner),
49   _pos(aWP.get_target()),
50   _ident(aWP.get_id())
51 {
52 }
53
54 BasicWaypt::BasicWaypt(Route* 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, Route* 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(Route* 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, Route* aOwner,
146   double aRadial, double aDistNm) :
147   NavaidWaypoint(aPos, aOwner),
148   _radial(aRadial),
149   _distanceNm(aDistNm)
150 {
151   init();
152 }
153
154 OffsetNavaidWaypoint::OffsetNavaidWaypoint(Route* 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, Route* aOwner) :
190   Waypt(aOwner),
191   _runway(aPos)
192 {
193 }
194
195 RunwayWaypt::RunwayWaypt(Route* 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 void RunwayWaypt::initFromProperties(SGPropertyNode_ptr aProp)
216 {
217   if (!aProp->hasChild("icao") || !aProp->hasChild("ident")) {
218     throw sg_io_exception("missing values: icao or ident", 
219       "RunwayWaypoint::initFromProperties");
220   }
221   
222   Waypt::initFromProperties(aProp);
223   std::string idn(aProp->getStringValue("ident"));
224   const FGAirport* apt = FGAirport::getByIdent(aProp->getStringValue("icao"));
225   _runway = apt->getRunwayByIdent(aProp->getStringValue("ident"));
226 }
227
228 void RunwayWaypt::writeToProperties(SGPropertyNode_ptr aProp) const
229 {
230   Waypt::writeToProperties(aProp);
231   aProp->setStringValue("ident", _runway->ident());
232   aProp->setStringValue("icao", _runway->airport()->ident());
233 }
234
235 /////////////////////////////////////////////////////////////////////////////
236
237 Hold::Hold(const SGGeod& aPos, const string& aIdent, Route* aOwner) :
238   BasicWaypt(aPos, aIdent, aOwner),
239   _righthanded(true),
240   _isDistance(false)
241 {
242   setFlag(WPT_DYNAMIC);
243 }
244
245 Hold::Hold(Route* aOwner) :
246   BasicWaypt(aOwner),
247   _righthanded(true),
248   _isDistance(false)
249 {
250 }
251
252 void Hold::setHoldRadial(double aInboundRadial)
253 {
254   _bearing = aInboundRadial;
255 }
256
257 void Hold::setHoldDistance(double aDistanceNm)
258 {
259   _isDistance = true;
260   _holdTD = aDistanceNm;
261 }
262
263 void Hold::setHoldTime(double aTimeSec)
264 {
265   _isDistance = false;
266   _holdTD = aTimeSec;
267 }
268
269 void Hold::setRightHanded()
270 {
271   _righthanded = true;
272 }
273
274 void Hold::setLeftHanded()
275 {
276   _righthanded = false;
277 }
278   
279 void Hold::initFromProperties(SGPropertyNode_ptr aProp)
280 {
281   BasicWaypt::initFromProperties(aProp);
282   
283   if (!aProp->hasChild("lon") || !aProp->hasChild("lat")) {
284     throw sg_io_exception("missing lon/lat properties", 
285       "Hold::initFromProperties");
286   }
287
288   _righthanded = aProp->getBoolValue("right-handed");
289   _isDistance = aProp->getBoolValue("is-distance");
290   _bearing = aProp->getDoubleValue("inbound-radial-deg");
291   _holdTD = aProp->getDoubleValue("td");
292 }
293
294 void Hold::writeToProperties(SGPropertyNode_ptr aProp) const
295 {
296   BasicWaypt::writeToProperties(aProp);
297
298   aProp->setBoolValue("right-handed", _righthanded);
299   aProp->setBoolValue("is-distance", _isDistance);
300   aProp->setDoubleValue("inbound-radial-deg", _bearing);
301   aProp->setDoubleValue("td", _holdTD);
302 }
303
304 /////////////////////////////////////////////////////////////////////////////
305
306 HeadingToAltitude::HeadingToAltitude(Route* aOwner, const string& aIdent, 
307   double aMagHdg) :
308   Waypt(aOwner),
309   _ident(aIdent),
310   _magHeading(aMagHdg)
311 {
312   setFlag(WPT_DYNAMIC);
313 }
314
315 HeadingToAltitude::HeadingToAltitude(Route* aOwner) :
316   Waypt(aOwner)
317 {
318 }
319
320 void HeadingToAltitude::initFromProperties(SGPropertyNode_ptr aProp)
321 {
322   if (!aProp->hasChild("heading-deg")) {
323     throw sg_io_exception("missing heading/alt properties", 
324       "HeadingToAltitude::initFromProperties");
325   }
326
327   Waypt::initFromProperties(aProp);
328   _magHeading = aProp->getDoubleValue("heading-deg");
329   _ident = aProp->getStringValue("ident");
330 }
331
332 void HeadingToAltitude::writeToProperties(SGPropertyNode_ptr aProp) const
333 {
334   Waypt::writeToProperties(aProp);
335   aProp->setStringValue("ident", _ident);
336   aProp->setDoubleValue("heading-deg", _magHeading);
337 }
338
339 /////////////////////////////////////////////////////////////////////////////
340
341 DMEIntercept::DMEIntercept(Route* aOwner, const string& aIdent, const SGGeod& aPos,
342     double aCourseDeg, double aDistanceNm) :
343   Waypt(aOwner),
344   _ident(aIdent),
345   _pos(aPos),
346   _magCourse(aCourseDeg),
347   _dmeDistanceNm(aDistanceNm)
348 {
349   setFlag(WPT_DYNAMIC);
350 }
351
352 DMEIntercept::DMEIntercept(Route* aOwner) :
353   Waypt(aOwner)
354 {
355 }
356
357 void DMEIntercept::initFromProperties(SGPropertyNode_ptr aProp)
358 {
359   if (!aProp->hasChild("lon") || !aProp->hasChild("lat")) {
360     throw sg_io_exception("missing lon/lat properties", 
361       "DMEIntercept::initFromProperties");
362   }
363
364   Waypt::initFromProperties(aProp);
365   _pos = SGGeod::fromDeg(aProp->getDoubleValue("lon"), aProp->getDoubleValue("lat"));
366   _ident = aProp->getStringValue("ident");
367 // check it's a real DME?
368   _magCourse = aProp->getDoubleValue("course-deg");
369   _dmeDistanceNm = aProp->getDoubleValue("dme-distance-nm");
370   
371 }
372
373 void DMEIntercept::writeToProperties(SGPropertyNode_ptr aProp) const
374 {
375   Waypt::writeToProperties(aProp);
376   
377   aProp->setStringValue("ident", _ident);
378   aProp->setDoubleValue("lon", _pos.getLongitudeDeg());
379   aProp->setDoubleValue("lat", _pos.getLatitudeDeg());
380   aProp->setDoubleValue("course-deg", _magCourse);
381   aProp->setDoubleValue("dme-distance-nm", _dmeDistanceNm);
382 }
383
384 /////////////////////////////////////////////////////////////////////////////
385
386 RadialIntercept::RadialIntercept(Route* aOwner, const string& aIdent, const SGGeod& aPos,
387     double aCourseDeg, double aRadial) :
388   Waypt(aOwner),
389   _ident(aIdent),
390   _pos(aPos),
391   _magCourse(aCourseDeg),
392   _radial(aRadial)
393 {
394   setFlag(WPT_DYNAMIC);
395 }
396
397 RadialIntercept::RadialIntercept(Route* aOwner) :
398   Waypt(aOwner)
399 {
400 }
401   
402 void RadialIntercept::initFromProperties(SGPropertyNode_ptr aProp)
403 {
404   if (!aProp->hasChild("lon") || !aProp->hasChild("lat")) {
405     throw sg_io_exception("missing lon/lat properties", 
406       "RadialIntercept::initFromProperties");
407   }
408
409   Waypt::initFromProperties(aProp);
410   _pos = SGGeod::fromDeg(aProp->getDoubleValue("lon"), aProp->getDoubleValue("lat"));
411   _ident = aProp->getStringValue("ident");
412 // check it's a real VOR?
413   _magCourse = aProp->getDoubleValue("course-deg");
414   _radial = aProp->getDoubleValue("radial-deg");
415   
416 }
417
418 void RadialIntercept::writeToProperties(SGPropertyNode_ptr aProp) const
419 {
420   Waypt::writeToProperties(aProp);
421   
422   aProp->setStringValue("ident", _ident);
423   aProp->setDoubleValue("lon", _pos.getLongitudeDeg());
424   aProp->setDoubleValue("lat", _pos.getLatitudeDeg());
425   aProp->setDoubleValue("course-deg", _magCourse);
426   aProp->setDoubleValue("radial-deg", _radial);
427 }
428
429 /////////////////////////////////////////////////////////////////////////////
430
431 ATCVectors::ATCVectors(Route* aOwner, FGAirport* aFacility) :
432   Waypt(aOwner),
433   _facility(aFacility)
434 {
435   setFlag(WPT_DYNAMIC);
436 }
437
438 ATCVectors::~ATCVectors()
439 {
440 }
441
442 ATCVectors::ATCVectors(Route* aOwner) :
443   Waypt(aOwner)
444 {
445 }
446
447 SGGeod ATCVectors::position() const
448 {
449   return _facility->geod();
450 }
451     
452 string ATCVectors::ident() const
453 {
454   return "VECTORS-" + _facility->ident();
455 }
456
457 void ATCVectors::initFromProperties(SGPropertyNode_ptr aProp)
458 {  
459   if (!aProp->hasChild("icao")) {
460     throw sg_io_exception("missing icao propertie", 
461       "ATCVectors::initFromProperties");
462   }
463
464   Waypt::initFromProperties(aProp);
465   _facility = FGAirport::getByIdent(aProp->getStringValue("icao"));
466 }
467
468 void ATCVectors::writeToProperties(SGPropertyNode_ptr aProp) const
469 {
470   Waypt::writeToProperties(aProp);
471   aProp->setStringValue("icao", _facility->ident());
472 }
473
474 } // of namespace