]> git.mxchange.org Git - flightgear.git/blob - src/Navaids/LevelDXML.cxx
Add support for helipads from apt.dat 850+
[flightgear.git] / src / Navaids / LevelDXML.cxx
1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4
5 #include "LevelDXML.hxx"
6
7 #include <boost/algorithm/string.hpp>
8
9 #include <simgear/structure/exception.hxx>
10 #include <simgear/misc/sg_path.hxx>
11
12 #include <Navaids/waypoint.hxx>
13 #include <Airports/simple.hxx>
14
15 using std::string;
16 using std::vector;
17
18 namespace flightgear
19 {
20
21 NavdataVisitor::NavdataVisitor(FGAirport* aApt, const SGPath& aPath):
22   _airport(aApt),
23   _path(aPath),
24   _sid(NULL),
25   _star(NULL),
26   _approach(NULL),
27   _transition(NULL),
28   _procedure(NULL)
29 {
30 }
31
32 void NavdataVisitor::startXML()
33 {
34 }
35
36 void NavdataVisitor::endXML()
37 {
38 }
39
40 void NavdataVisitor::startElement(const char* name, const XMLAttributes &atts)
41 {
42   _text.clear();
43   string tag(name);
44   if (tag == "Airport") {
45     string icao(atts.getValue("ICAOcode"));
46     if (_airport->ident() != icao) {
47       throw sg_format_exception("Airport and ICAO mismatch", icao, _path.str());
48     }
49   } else if (tag == "Sid") {
50     string ident(atts.getValue("Name"));
51     _sid = new SID(ident, _airport);
52     _procedure = _sid;
53     _waypoints.clear();
54     processRunways(_sid, atts);
55   } else if (tag == "Star") {
56     string ident(atts.getValue("Name"));
57     _star = new STAR(ident, _airport);
58     _procedure = _star;
59     _waypoints.clear();
60     processRunways(_star, atts);
61   } else if ((tag == "Sid_Waypoint") ||
62       (tag == "App_Waypoint") ||
63       (tag == "Star_Waypoint") ||
64       (tag == "AppTr_Waypoint") ||
65       (tag == "SidTr_Waypoint") ||
66       (tag == "RwyTr_Waypoint"))
67   {
68     // reset waypoint data
69     _speed = 0.0;
70     _altRestrict = RESTRICT_NONE;
71     _altitude = 0.0;
72   } else if (tag == "Approach") {
73     _ident = atts.getValue("Name");
74     _waypoints.clear();
75     ProcedureType ty = PROCEDURE_APPROACH_RNAV;
76     _approach = new Approach(_ident, ty);
77     _procedure = _approach;
78   } else if ((tag == "Sid_Transition") || 
79              (tag == "App_Transition") ||
80              (tag == "Star_Transition")) {
81     _transIdent = atts.getValue("Name");
82     _transition = new Transition(_transIdent, PROCEDURE_TRANSITION, _procedure);
83     _transWaypts.clear();
84   } else if (tag == "RunwayTransition") {
85     _transIdent = atts.getValue("Runway");
86     _transition = new Transition(_transIdent, PROCEDURE_RUNWAY_TRANSITION, _procedure);
87     _transWaypts.clear();
88   } else {
89     
90   }
91 }
92
93 void NavdataVisitor::processRunways(ArrivalDeparture* aProc, const XMLAttributes &atts)
94 {
95   string v("All");
96   if (atts.hasAttribute("Runways")) {
97     v = atts.getValue("Runways");
98   }
99   
100   if (v == "All") {
101     for (unsigned int r=0; r<_airport->numRunways(); ++r) {
102       aProc->addRunway(_airport->getRunwayByIndex(r));
103     }
104     return;
105   }
106   
107   vector<string> rwys;
108   boost::split(rwys, v, boost::is_any_of(" ,"));
109   for (unsigned int r=0; r<rwys.size(); ++r) {
110     FGRunway* rwy = _airport->getRunwayByIdent(rwys[r]);
111     aProc->addRunway(rwy);
112   }
113 }
114
115 void NavdataVisitor::endElement(const char* name)
116 {
117   string tag(name);
118   if ((tag == "Sid_Waypoint") ||
119       (tag == "App_Waypoint") ||
120       (tag == "Star_Waypoint"))
121   {
122     _waypoints.push_back(buildWaypoint(_procedure));
123   } else if ((tag == "AppTr_Waypoint") || 
124              (tag == "SidTr_Waypoint") ||
125              (tag == "RwyTr_Waypoint") ||
126              (tag == "StarTr_Waypoint")) 
127   {
128     _transWaypts.push_back(buildWaypoint(_transition));
129   } else if (tag == "Sid_Transition") {
130     assert(_sid);
131     // SID waypoints are stored backwards, to share code with STARs
132     std::reverse(_transWaypts.begin(), _transWaypts.end());
133     _transition->setPrimary(_transWaypts);
134     _sid->addTransition(_transition);
135   } else if (tag == "Star_Transition") {
136     assert(_star);
137     _transition->setPrimary(_transWaypts);
138     _star->addTransition(_transition);
139   } else if (tag == "App_Transition") {
140     assert(_approach);
141     _transition->setPrimary(_transWaypts);
142     _approach->addTransition(_transition);
143   } else if (tag == "RunwayTransition") {
144     ArrivalDeparture* ad;
145     if (_sid) {
146       // SID waypoints are stored backwards, to share code with STARs
147       std::reverse(_transWaypts.begin(), _transWaypts.end());
148       ad = _sid;
149     } else {
150       ad = _star;
151     }
152
153     _transition->setPrimary(_transWaypts);
154     FGRunwayRef rwy = _airport->getRunwayByIdent(_transIdent);
155     ad->addRunwayTransition(rwy, _transition);
156   } else if (tag == "Approach") {
157     finishApproach();
158   } else if (tag == "Sid") {
159     finishSid();
160   } else if (tag == "Star") {
161     finishStar();  
162   } else if (tag == "Longitude") {
163     _longitude = atof(_text.c_str());
164   } else if (tag == "Latitude") {
165     _latitude = atof(_text.c_str());
166   } else if (tag == "Name") {
167     _wayptName = _text;
168   } else if (tag == "Type") {
169     _wayptType = _text;
170   } else if (tag == "Speed") {
171     _speed = atoi(_text.c_str());
172   } else if (tag == "Altitude") {
173     _altitude = atof(_text.c_str());
174   } else if (tag == "AltitudeRestriction") {
175     if (_text == "at") {
176       _altRestrict = RESTRICT_AT;
177     } else if (_text == "above") {
178       _altRestrict = RESTRICT_ABOVE;
179     } else if (_text == "below") {
180       _altRestrict = RESTRICT_BELOW;
181     } else {
182       throw sg_format_exception("Unrecognized altitude restriction", _text);
183     }
184   } else if (tag == "Hld_Rad_or_Inbd") {
185     if (_text == "Inbd") {
186       _holdRadial = -1.0;
187     }
188   } else if (tag == "Hld_Time_or_Dist") {
189     _holdDistance = (_text == "Dist");
190   } else if (tag == "Hld_Rad_value") {
191     _holdRadial = atof(_text.c_str());
192   } else if (tag == "Hld_Turn") {
193     _holdRighthanded = (_text == "Right");
194   } else if (tag == "Hld_td_value") {
195     _holdTD = atof(_text.c_str());
196   } else if (tag == "Hdg_Crs_value") {
197     _course = atof(_text.c_str());
198   } else if (tag == "DMEtoIntercept") {
199     _dmeDistance = atof(_text.c_str());
200   } else if (tag == "RadialtoIntercept") {
201     _radial = atof(_text.c_str());
202   } else {
203     
204   }
205 }
206
207 Waypt* NavdataVisitor::buildWaypoint(RouteBase* owner)
208 {
209   Waypt* wp = NULL;
210   if (_wayptType == "Normal") {
211     // new LatLonWaypoint
212     SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
213     wp = new BasicWaypt(pos, _wayptName, owner);
214   } else if (_wayptType == "Runway") {
215     string ident = _wayptName.substr(2);
216     FGRunwayRef rwy = _airport->getRunwayByIdent(ident);
217     wp = new RunwayWaypt(rwy, owner);
218   } else if (_wayptType == "Hold") {
219     SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
220     Hold* h = new Hold(pos, _wayptName, owner);
221     wp = h;
222     if (_holdRighthanded) {
223       h->setRightHanded();
224     } else {
225       h->setLeftHanded();
226     }
227     
228     if (_holdDistance) {
229       h->setHoldDistance(_holdTD);
230     } else {
231       h->setHoldTime(_holdTD * 60.0);
232     }
233     
234     if (_holdRadial >= 0.0) {
235       h->setHoldRadial(_holdRadial);
236     }
237   } else if (_wayptType == "Vectors") {
238     wp = new ATCVectors(owner, _airport);
239   } else if ((_wayptType == "Intc") || (_wayptType == "VorRadialIntc")) {
240     SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
241     wp = new RadialIntercept(owner, _wayptName, pos, _course, _radial);
242   } else if (_wayptType == "DmeIntc") {
243     SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
244     wp = new DMEIntercept(owner, _wayptName, pos, _course, _dmeDistance);
245   } else if (_wayptType == "ConstHdgtoAlt") {
246     wp = new HeadingToAltitude(owner, _wayptName, _course);
247   } else if (_wayptType == "PBD") {
248     SGGeod pos(SGGeod::fromDeg(_longitude, _latitude)), pos2;
249     double az2;
250     SGGeodesy::direct(pos, _course, _dmeDistance, pos2, az2);
251     wp = new BasicWaypt(pos2, _wayptName, owner);
252   } else {
253     SG_LOG(SG_NAVAID, SG_ALERT, "implement waypoint type:" << _wayptType);
254     throw sg_format_exception("Unrecognized waypt type", _wayptType);
255   }
256   
257   assert(wp);
258   if ((_altitude > 0.0) && (_altRestrict != RESTRICT_NONE)) {
259     wp->setAltitude(_altitude,_altRestrict);
260   }
261   
262   if (_speed > 0.0) {
263     wp->setSpeed(_speed, RESTRICT_AT); // or _BELOW?
264   }
265   
266   return wp;
267 }
268
269 void NavdataVisitor::finishApproach()
270 {
271   WayptVec::iterator it;
272   FGRunwayRef rwy;
273   
274 // find the runway node
275   for (it = _waypoints.begin(); it != _waypoints.end(); ++it) {
276     FGPositionedRef navid = (*it)->source();
277     if (!navid) {
278       continue;
279     }
280     
281     if (navid->type() == FGPositioned::RUNWAY) {
282       rwy = (FGRunway*) navid.get();
283       break;
284     }
285   }
286   
287   if (!rwy) {
288     throw sg_format_exception("Malformed approach, no runway waypt", _ident);
289   }
290   
291   WayptVec primary(_waypoints.begin(), it);
292   // erase all points up to and including the runway, to leave only the
293   // missed segments
294   _waypoints.erase(_waypoints.begin(), ++it);
295   
296   _approach->setRunway(rwy);
297   _approach->setPrimaryAndMissed(primary, _waypoints);
298   _airport->addApproach(_approach);
299   _approach = NULL;
300 }
301
302 void NavdataVisitor::finishSid()
303 {
304   // reverse order, because that's how we deal with commonality between
305   // STARs and SIDs. SID::route undoes  this
306   std::reverse(_waypoints.begin(), _waypoints.end());
307   _sid->setCommon(_waypoints);
308   _airport->addSID(_sid);
309   _sid = NULL;
310 }
311
312 void NavdataVisitor::finishStar()
313 {
314   _star->setCommon(_waypoints);
315   _airport->addSTAR(_star);
316   _star = NULL;
317 }
318
319 void NavdataVisitor::data (const char * s, int len)
320 {
321   _text += string(s, len);
322 }
323
324
325 void NavdataVisitor::pi (const char * target, const char * data) {
326   //cout << "Processing instruction " << target << ' ' << data << endl;
327 }
328
329 void NavdataVisitor::warning (const char * message, int line, int column) {
330   SG_LOG(SG_NAVAID, SG_WARN, "Warning: " << message << " (" << line << ',' << column << ')');
331 }
332
333 void NavdataVisitor::error (const char * message, int line, int column) {
334   SG_LOG(SG_NAVAID, SG_ALERT, "Error: " << message << " (" << line << ',' << column << ')');
335 }
336
337 }