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/simple.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 } else if (tag == "Approach") {
73 _ident = atts.getValue("Name");
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);
84 } else if (tag == "RunwayTransition") {
85 _transIdent = atts.getValue("Runway");
86 _transition = new Transition(_transIdent, PROCEDURE_RUNWAY_TRANSITION, _procedure);
93 void NavdataVisitor::processRunways(ArrivalDeparture* aProc, const XMLAttributes &atts)
96 if (atts.hasAttribute("Runways")) {
97 v = atts.getValue("Runways");
101 for (unsigned int r=0; r<_airport->numRunways(); ++r) {
102 aProc->addRunway(_airport->getRunwayByIndex(r));
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);
115 void NavdataVisitor::endElement(const char* name)
118 if ((tag == "Sid_Waypoint") ||
119 (tag == "App_Waypoint") ||
120 (tag == "Star_Waypoint"))
122 _waypoints.push_back(buildWaypoint(_procedure));
123 } else if ((tag == "AppTr_Waypoint") ||
124 (tag == "SidTr_Waypoint") ||
125 (tag == "RwyTr_Waypoint") ||
126 (tag == "StarTr_Waypoint"))
128 _transWaypts.push_back(buildWaypoint(_transition));
129 } else if (tag == "Sid_Transition") {
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") {
137 _transition->setPrimary(_transWaypts);
138 _star->addTransition(_transition);
139 } else if (tag == "App_Transition") {
141 _transition->setPrimary(_transWaypts);
142 _approach->addTransition(_transition);
143 } else if (tag == "RunwayTransition") {
144 ArrivalDeparture* ad;
146 // SID waypoints are stored backwards, to share code with STARs
147 std::reverse(_transWaypts.begin(), _transWaypts.end());
153 _transition->setPrimary(_transWaypts);
154 FGRunwayRef rwy = _airport->getRunwayByIdent(_transIdent);
155 ad->addRunwayTransition(rwy, _transition);
156 } else if (tag == "Approach") {
158 } else if (tag == "Sid") {
160 } else if (tag == "Star") {
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") {
168 } else if (tag == "Type") {
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") {
176 _altRestrict = RESTRICT_AT;
177 } else if (_text == "above") {
178 _altRestrict = RESTRICT_ABOVE;
179 } else if (_text == "below") {
180 _altRestrict = RESTRICT_BELOW;
182 throw sg_format_exception("Unrecognized altitude restriction", _text);
184 } else if (tag == "Hld_Rad_or_Inbd") {
185 if (_text == "Inbd") {
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());
207 Waypt* NavdataVisitor::buildWaypoint(RouteBase* owner)
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);
222 if (_holdRighthanded) {
229 h->setHoldDistance(_holdTD);
231 h->setHoldTime(_holdTD * 60.0);
234 if (_holdRadial >= 0.0) {
235 h->setHoldRadial(_holdRadial);
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;
250 SGGeodesy::direct(pos, _course, _dmeDistance, pos2, az2);
251 wp = new BasicWaypt(pos2, _wayptName, owner);
253 SG_LOG(SG_GENERAL, SG_ALERT, "implement waypoint type:" << _wayptType);
254 throw sg_format_exception("Unrecognized waypt type", _wayptType);
258 if ((_altitude > 0.0) && (_altRestrict != RESTRICT_NONE)) {
259 wp->setAltitude(_altitude,_altRestrict);
263 wp->setSpeed(_speed, RESTRICT_AT); // or _BELOW?
269 void NavdataVisitor::finishApproach()
271 WayptVec::iterator it;
274 // find the runway node
275 for (it = _waypoints.begin(); it != _waypoints.end(); ++it) {
276 FGPositionedRef navid = (*it)->source();
281 if (navid->type() == FGPositioned::RUNWAY) {
282 rwy = (FGRunway*) navid.get();
288 throw sg_format_exception("Malformed approach, no runway waypt", _ident);
291 WayptVec primary(_waypoints.begin(), it);
292 // erase all points up to and including the runway, to leave only the
294 _waypoints.erase(_waypoints.begin(), ++it);
296 _approach->setRunway(rwy);
297 _approach->setPrimaryAndMissed(primary, _waypoints);
298 _airport->addApproach(_approach);
302 void NavdataVisitor::finishSid()
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);
312 void NavdataVisitor::finishStar()
314 _star->setCommon(_waypoints);
315 _airport->addSTAR(_star);
319 void NavdataVisitor::data (const char * s, int len)
321 _text += string(s, len);
325 void NavdataVisitor::pi (const char * target, const char * data) {
326 //cout << "Processing instruction " << target << ' ' << data << endl;
329 void NavdataVisitor::warning (const char * message, int line, int column) {
330 SG_LOG(SG_IO, SG_WARN, "Warning: " << message << " (" << line << ',' << column << ')');
333 void NavdataVisitor::error (const char * message, int line, int column) {
334 SG_LOG(SG_IO, SG_ALERT, "Error: " << message << " (" << line << ',' << column << ')');