5 #include "LevelDXML.hxx"
7 #include <boost/algorithm/string.hpp>
9 #include <simgear/structure/exception.hxx>
10 #include <simgear/misc/sg_path.hxx>
12 #include <Navaids/waypoint.hxx>
13 #include <Airports/airport.hxx>
21 NavdataVisitor::NavdataVisitor(FGAirport* aApt, const SGPath& aPath):
32 void NavdataVisitor::startXML()
36 void NavdataVisitor::endXML()
40 void NavdataVisitor::startElement(const char* name, const XMLAttributes &atts)
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());
49 } else if (tag == "Sid") {
50 string ident(atts.getValue("Name"));
51 _sid = new SID(ident, _airport);
54 processRunways(_sid, atts);
55 } else if (tag == "Star") {
56 string ident(atts.getValue("Name"));
57 _star = new STAR(ident, _airport);
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"))
68 // reset waypoint data
70 _altRestrict = RESTRICT_NONE;
72 _overflightWaypt = false; // default to Fly-by
73 _courseFlag = false; // default to heading
74 } else if (tag == "Approach") {
75 _ident = atts.getValue("Name");
77 ProcedureType ty = PROCEDURE_APPROACH_RNAV;
78 _approach = new Approach(_ident, ty);
79 _procedure = _approach;
80 } else if ((tag == "Sid_Transition") ||
81 (tag == "App_Transition") ||
82 (tag == "Star_Transition")) {
83 _transIdent = atts.getValue("Name");
84 _transition = new Transition(_transIdent, PROCEDURE_TRANSITION, _procedure);
86 } else if (tag == "RunwayTransition") {
87 _transIdent = atts.getValue("Runway");
88 _transition = new Transition(_transIdent, PROCEDURE_RUNWAY_TRANSITION, _procedure);
91 // nothing here, we warn on unrecognized in endElement
95 void NavdataVisitor::processRunways(ArrivalDeparture* aProc, const XMLAttributes &atts)
98 if (atts.hasAttribute("Runways")) {
99 v = atts.getValue("Runways");
103 for (unsigned int r=0; r<_airport->numRunways(); ++r) {
104 aProc->addRunway(_airport->getRunwayByIndex(r));
110 boost::split(rwys, v, boost::is_any_of(" ,"));
111 for (unsigned int r=0; r<rwys.size(); ++r) {
112 FGRunway* rwy = _airport->getRunwayByIdent(rwys[r]);
113 aProc->addRunway(rwy);
117 void NavdataVisitor::endElement(const char* name)
120 if ((tag == "Sid_Waypoint") ||
121 (tag == "App_Waypoint") ||
122 (tag == "Star_Waypoint"))
124 _waypoints.push_back(buildWaypoint(_procedure));
125 } else if ((tag == "AppTr_Waypoint") ||
126 (tag == "SidTr_Waypoint") ||
127 (tag == "RwyTr_Waypoint") ||
128 (tag == "StarTr_Waypoint"))
130 _transWaypts.push_back(buildWaypoint(_transition));
131 } else if (tag == "Sid_Transition") {
133 // SID waypoints are stored backwards, to share code with STARs
134 std::reverse(_transWaypts.begin(), _transWaypts.end());
135 _transition->setPrimary(_transWaypts);
136 _sid->addTransition(_transition);
137 } else if (tag == "Star_Transition") {
139 _transition->setPrimary(_transWaypts);
140 _star->addTransition(_transition);
141 } else if (tag == "App_Transition") {
143 _transition->setPrimary(_transWaypts);
144 _approach->addTransition(_transition);
145 } else if (tag == "RunwayTransition") {
146 ArrivalDeparture* ad;
148 // SID waypoints are stored backwards, to share code with STARs
149 std::reverse(_transWaypts.begin(), _transWaypts.end());
155 _transition->setPrimary(_transWaypts);
156 FGRunwayRef rwy = _airport->getRunwayByIdent(_transIdent);
157 ad->addRunwayTransition(rwy, _transition);
158 } else if (tag == "Approach") {
160 } else if (tag == "Sid") {
162 } else if (tag == "Star") {
164 } else if (tag == "Longitude") {
165 _longitude = atof(_text.c_str());
166 } else if (tag == "Latitude") {
167 _latitude = atof(_text.c_str());
168 } else if (tag == "Name") {
170 } else if (tag == "Type") {
172 } else if (tag == "Speed") {
173 _speed = atoi(_text.c_str());
174 } else if (tag == "Altitude") {
175 _altitude = atof(_text.c_str());
176 } else if (tag == "AltitudeRestriction") {
178 _altRestrict = RESTRICT_AT;
179 } else if (_text == "above") {
180 _altRestrict = RESTRICT_ABOVE;
181 } else if (_text == "below") {
182 _altRestrict = RESTRICT_BELOW;
184 throw sg_format_exception("Unrecognized altitude restriction", _text);
186 } else if (tag == "Hld_Rad_or_Inbd") {
187 if (_text == "Inbd") {
190 } else if (tag == "Hld_Time_or_Dist") {
191 _holdDistance = (_text == "Dist");
192 } else if (tag == "Hld_Rad_value") {
193 _holdRadial = atof(_text.c_str());
194 } else if (tag == "Hld_Turn") {
195 _holdRighthanded = (_text == "Right");
196 } else if (tag == "Hld_td_value") {
197 _holdTD = atof(_text.c_str());
198 } else if (tag == "Hdg_Crs") {
199 _courseFlag = atoi(_text.c_str());
200 } else if (tag == "Hdg_Crs_value") {
201 _courseOrHeading = atof(_text.c_str());
202 } else if (tag == "DMEtoIntercept") {
203 _dmeDistance = atof(_text.c_str());
204 } else if (tag == "RadialtoIntercept") {
205 _radial = atof(_text.c_str());
206 } else if (tag == "Flytype") {
207 // values are 'Fly-by' and 'Fly-over'
208 _overflightWaypt = (_text == "Fly-over");
209 } else if ((tag == "AltitudeCons") ||
210 (tag == "BankLimit") ||
213 // ignored but don't warn
215 SG_LOG(SG_IO, SG_INFO, "unrecognized Level-D XML element:" << tag);
219 Waypt* NavdataVisitor::buildWaypoint(RouteBase* owner)
222 if (_wayptType == "Normal") {
223 // new LatLonWaypoint
224 SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
225 wp = new BasicWaypt(pos, _wayptName, owner);
226 } else if (_wayptType == "Runway") {
227 string ident = _wayptName.substr(2);
228 FGRunwayRef rwy = _airport->getRunwayByIdent(ident);
229 wp = new RunwayWaypt(rwy, owner);
230 } else if (_wayptType == "Hold") {
231 SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
232 Hold* h = new Hold(pos, _wayptName, owner);
234 if (_holdRighthanded) {
241 h->setHoldDistance(_holdTD);
243 h->setHoldTime(_holdTD * 60.0);
246 if (_holdRadial >= 0.0) {
247 h->setHoldRadial(_holdRadial);
249 } else if (_wayptType == "Vectors") {
250 wp = new ATCVectors(owner, _airport);
251 } else if ((_wayptType == "Intc") || (_wayptType == "VorRadialIntc")) {
252 SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
253 wp = new RadialIntercept(owner, _wayptName, pos, _courseOrHeading, _radial);
254 } else if (_wayptType == "DmeIntc") {
255 SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
256 wp = new DMEIntercept(owner, _wayptName, pos, _courseOrHeading, _dmeDistance);
257 } else if (_wayptType == "ConstHdgtoAlt") {
258 wp = new HeadingToAltitude(owner, _wayptName, _courseOrHeading);
259 } else if (_wayptType == "PBD") {
260 SGGeod pos(SGGeod::fromDeg(_longitude, _latitude)), pos2;
262 SGGeodesy::direct(pos, _courseOrHeading, _dmeDistance, pos2, az2);
263 wp = new BasicWaypt(pos2, _wayptName, owner);
265 SG_LOG(SG_NAVAID, SG_ALERT, "implement waypoint type:" << _wayptType);
266 throw sg_format_exception("Unrecognized waypt type", _wayptType);
270 if ((_altitude > 0.0) && (_altRestrict != RESTRICT_NONE)) {
271 wp->setAltitude(_altitude,_altRestrict);
275 wp->setSpeed(_speed, RESTRICT_AT); // or _BELOW?
278 if (_overflightWaypt) {
279 wp->setFlag(WPT_OVERFLIGHT);
285 void NavdataVisitor::finishApproach()
287 WayptVec::iterator it;
290 // find the runway node
291 for (it = _waypoints.begin(); it != _waypoints.end(); ++it) {
292 FGPositionedRef navid = (*it)->source();
297 if (navid->type() == FGPositioned::RUNWAY) {
298 rwy = (FGRunway*) navid.get();
304 throw sg_format_exception("Malformed approach, no runway waypt", _ident);
307 WayptVec primary(_waypoints.begin(), it);
308 // erase all points up to and including the runway, to leave only the
310 _waypoints.erase(_waypoints.begin(), ++it);
312 _approach->setRunway(rwy);
313 _approach->setPrimaryAndMissed(primary, _waypoints);
314 _airport->addApproach(_approach);
318 void NavdataVisitor::finishSid()
320 // reverse order, because that's how we deal with commonality between
321 // STARs and SIDs. SID::route undoes this
322 std::reverse(_waypoints.begin(), _waypoints.end());
323 _sid->setCommon(_waypoints);
324 _airport->addSID(_sid);
328 void NavdataVisitor::finishStar()
330 _star->setCommon(_waypoints);
331 _airport->addSTAR(_star);
335 void NavdataVisitor::data (const char * s, int len)
337 _text += string(s, len);
341 void NavdataVisitor::pi (const char * target, const char * data) {
342 //cout << "Processing instruction " << target << ' ' << data << endl;
345 void NavdataVisitor::warning (const char * message, int line, int column) {
346 SG_LOG(SG_NAVAID, SG_WARN, "Warning: " << message << " (" << line << ',' << column << ')');
349 void NavdataVisitor::error (const char * message, int line, int column) {
350 SG_LOG(SG_NAVAID, SG_ALERT, "Error: " << message << " (" << line << ',' << column << ')');