1
0
Fork 0
flightgear/src/Navaids/LevelDXML.cxx
James Turner 6d0c2070fd Use future-proof SGPath APIs.
Remove uses of .str(), .c_str() and some other methods of SGPath.
Pass SGPath directly where possible, or explicitly convert to the
appropriate 8-bit encoding.
2016-06-28 10:08:38 +01:00

353 lines
10 KiB
C++

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "LevelDXML.hxx"
#include <boost/algorithm/string.hpp>
#include <simgear/structure/exception.hxx>
#include <simgear/misc/sg_path.hxx>
#include <Navaids/waypoint.hxx>
#include <Airports/airport.hxx>
using std::string;
using std::vector;
namespace flightgear
{
NavdataVisitor::NavdataVisitor(FGAirport* aApt, const SGPath& aPath):
_airport(aApt),
_path(aPath),
_sid(NULL),
_star(NULL),
_approach(NULL),
_transition(NULL),
_procedure(NULL)
{
}
void NavdataVisitor::startXML()
{
}
void NavdataVisitor::endXML()
{
}
void NavdataVisitor::startElement(const char* name, const XMLAttributes &atts)
{
_text.clear();
string tag(name);
if (tag == "Airport") {
string icao(atts.getValue("ICAOcode"));
if (_airport->ident() != icao) {
throw sg_format_exception("Airport and ICAO mismatch", icao, _path.utf8Str());
}
} else if (tag == "Sid") {
string ident(atts.getValue("Name"));
_sid = new SID(ident, _airport);
_procedure = _sid;
_waypoints.clear();
processRunways(_sid, atts);
} else if (tag == "Star") {
string ident(atts.getValue("Name"));
_star = new STAR(ident, _airport);
_procedure = _star;
_waypoints.clear();
processRunways(_star, atts);
} else if ((tag == "Sid_Waypoint") ||
(tag == "App_Waypoint") ||
(tag == "Star_Waypoint") ||
(tag == "AppTr_Waypoint") ||
(tag == "SidTr_Waypoint") ||
(tag == "RwyTr_Waypoint"))
{
// reset waypoint data
_speed = 0.0;
_altRestrict = RESTRICT_NONE;
_altitude = 0.0;
_overflightWaypt = false; // default to Fly-by
_courseFlag = false; // default to heading
} else if (tag == "Approach") {
_ident = atts.getValue("Name");
_waypoints.clear();
ProcedureType ty = PROCEDURE_APPROACH_RNAV;
_approach = new Approach(_ident, ty);
_procedure = _approach;
} else if ((tag == "Sid_Transition") ||
(tag == "App_Transition") ||
(tag == "Star_Transition")) {
_transIdent = atts.getValue("Name");
_transition = new Transition(_transIdent, PROCEDURE_TRANSITION, _procedure);
_transWaypts.clear();
} else if (tag == "RunwayTransition") {
_transIdent = atts.getValue("Runway");
_transition = new Transition(_transIdent, PROCEDURE_RUNWAY_TRANSITION, _procedure);
_transWaypts.clear();
} else {
// nothing here, we warn on unrecognized in endElement
}
}
void NavdataVisitor::processRunways(ArrivalDeparture* aProc, const XMLAttributes &atts)
{
string v("All");
if (atts.hasAttribute("Runways")) {
v = atts.getValue("Runways");
}
if (v == "All") {
for (unsigned int r=0; r<_airport->numRunways(); ++r) {
aProc->addRunway(_airport->getRunwayByIndex(r));
}
return;
}
vector<string> rwys;
boost::split(rwys, v, boost::is_any_of(" ,"));
for (unsigned int r=0; r<rwys.size(); ++r) {
FGRunway* rwy = _airport->getRunwayByIdent(rwys[r]);
aProc->addRunway(rwy);
}
}
void NavdataVisitor::endElement(const char* name)
{
string tag(name);
if ((tag == "Sid_Waypoint") ||
(tag == "App_Waypoint") ||
(tag == "Star_Waypoint"))
{
_waypoints.push_back(buildWaypoint(_procedure));
} else if ((tag == "AppTr_Waypoint") ||
(tag == "SidTr_Waypoint") ||
(tag == "RwyTr_Waypoint") ||
(tag == "StarTr_Waypoint"))
{
_transWaypts.push_back(buildWaypoint(_transition));
} else if (tag == "Sid_Transition") {
assert(_sid);
// SID waypoints are stored backwards, to share code with STARs
std::reverse(_transWaypts.begin(), _transWaypts.end());
_transition->setPrimary(_transWaypts);
_sid->addTransition(_transition);
} else if (tag == "Star_Transition") {
assert(_star);
_transition->setPrimary(_transWaypts);
_star->addTransition(_transition);
} else if (tag == "App_Transition") {
assert(_approach);
_transition->setPrimary(_transWaypts);
_approach->addTransition(_transition);
} else if (tag == "RunwayTransition") {
ArrivalDeparture* ad;
if (_sid) {
// SID waypoints are stored backwards, to share code with STARs
std::reverse(_transWaypts.begin(), _transWaypts.end());
ad = _sid;
} else {
ad = _star;
}
_transition->setPrimary(_transWaypts);
FGRunwayRef rwy = _airport->getRunwayByIdent(_transIdent);
ad->addRunwayTransition(rwy, _transition);
} else if (tag == "Approach") {
finishApproach();
} else if (tag == "Sid") {
finishSid();
} else if (tag == "Star") {
finishStar();
} else if (tag == "Longitude") {
_longitude = atof(_text.c_str());
} else if (tag == "Latitude") {
_latitude = atof(_text.c_str());
} else if (tag == "Name") {
_wayptName = _text;
} else if (tag == "Type") {
_wayptType = _text;
} else if (tag == "Speed") {
_speed = atoi(_text.c_str());
} else if (tag == "Altitude") {
_altitude = atof(_text.c_str());
} else if (tag == "AltitudeRestriction") {
if (_text == "at") {
_altRestrict = RESTRICT_AT;
} else if (_text == "above") {
_altRestrict = RESTRICT_ABOVE;
} else if (_text == "below") {
_altRestrict = RESTRICT_BELOW;
} else {
throw sg_format_exception("Unrecognized altitude restriction", _text);
}
} else if (tag == "Hld_Rad_or_Inbd") {
if (_text == "Inbd") {
_holdRadial = -1.0;
}
} else if (tag == "Hld_Time_or_Dist") {
_holdDistance = (_text == "Dist");
} else if (tag == "Hld_Rad_value") {
_holdRadial = atof(_text.c_str());
} else if (tag == "Hld_Turn") {
_holdRighthanded = (_text == "Right");
} else if (tag == "Hld_td_value") {
_holdTD = atof(_text.c_str());
} else if (tag == "Hdg_Crs") {
_courseFlag = atoi(_text.c_str());
} else if (tag == "Hdg_Crs_value") {
_courseOrHeading = atof(_text.c_str());
} else if (tag == "DMEtoIntercept") {
_dmeDistance = atof(_text.c_str());
} else if (tag == "RadialtoIntercept") {
_radial = atof(_text.c_str());
} else if (tag == "Flytype") {
// values are 'Fly-by' and 'Fly-over'
_overflightWaypt = (_text == "Fly-over");
} else if ((tag == "AltitudeCons") ||
(tag == "BankLimit") ||
(tag == "Sp_Turn"))
{
// ignored but don't warn
} else {
SG_LOG(SG_IO, SG_INFO, "unrecognized Level-D XML element:" << tag);
}
}
Waypt* NavdataVisitor::buildWaypoint(RouteBase* owner)
{
Waypt* wp = NULL;
if (_wayptType == "Normal") {
// new LatLonWaypoint
SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
wp = new BasicWaypt(pos, _wayptName, owner);
} else if (_wayptType == "Runway") {
string ident = _wayptName.substr(2);
FGRunwayRef rwy = _airport->getRunwayByIdent(ident);
wp = new RunwayWaypt(rwy, owner);
} else if (_wayptType == "Hold") {
SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
Hold* h = new Hold(pos, _wayptName, owner);
wp = h;
if (_holdRighthanded) {
h->setRightHanded();
} else {
h->setLeftHanded();
}
if (_holdDistance) {
h->setHoldDistance(_holdTD);
} else {
h->setHoldTime(_holdTD * 60.0);
}
if (_holdRadial >= 0.0) {
h->setHoldRadial(_holdRadial);
}
} else if (_wayptType == "Vectors") {
wp = new ATCVectors(owner, _airport);
} else if ((_wayptType == "Intc") || (_wayptType == "VorRadialIntc")) {
SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
wp = new RadialIntercept(owner, _wayptName, pos, _courseOrHeading, _radial);
} else if (_wayptType == "DmeIntc") {
SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
wp = new DMEIntercept(owner, _wayptName, pos, _courseOrHeading, _dmeDistance);
} else if (_wayptType == "ConstHdgtoAlt") {
wp = new HeadingToAltitude(owner, _wayptName, _courseOrHeading);
} else if (_wayptType == "PBD") {
SGGeod pos(SGGeod::fromDeg(_longitude, _latitude)), pos2;
double az2;
SGGeodesy::direct(pos, _courseOrHeading, _dmeDistance, pos2, az2);
wp = new BasicWaypt(pos2, _wayptName, owner);
} else {
SG_LOG(SG_NAVAID, SG_ALERT, "implement waypoint type:" << _wayptType);
throw sg_format_exception("Unrecognized waypt type", _wayptType);
}
assert(wp);
if ((_altitude > 0.0) && (_altRestrict != RESTRICT_NONE)) {
wp->setAltitude(_altitude,_altRestrict);
}
if (_speed > 0.0) {
wp->setSpeed(_speed, RESTRICT_AT); // or _BELOW?
}
if (_overflightWaypt) {
wp->setFlag(WPT_OVERFLIGHT);
}
return wp;
}
void NavdataVisitor::finishApproach()
{
WayptVec::iterator it;
FGRunwayRef rwy;
// find the runway node
for (it = _waypoints.begin(); it != _waypoints.end(); ++it) {
FGPositionedRef navid = (*it)->source();
if (!navid) {
continue;
}
if (navid->type() == FGPositioned::RUNWAY) {
rwy = (FGRunway*) navid.get();
break;
}
}
if (!rwy) {
throw sg_format_exception("Malformed approach, no runway waypt", _ident);
}
WayptVec primary(_waypoints.begin(), it);
// erase all points up to and including the runway, to leave only the
// missed segments
_waypoints.erase(_waypoints.begin(), ++it);
_approach->setRunway(rwy);
_approach->setPrimaryAndMissed(primary, _waypoints);
_airport->addApproach(_approach);
_approach = NULL;
}
void NavdataVisitor::finishSid()
{
// reverse order, because that's how we deal with commonality between
// STARs and SIDs. SID::route undoes this
std::reverse(_waypoints.begin(), _waypoints.end());
_sid->setCommon(_waypoints);
_airport->addSID(_sid);
_sid = NULL;
}
void NavdataVisitor::finishStar()
{
_star->setCommon(_waypoints);
_airport->addSTAR(_star);
_star = NULL;
}
void NavdataVisitor::data (const char * s, int len)
{
_text += string(s, len);
}
void NavdataVisitor::pi (const char * target, const char * data) {
//cout << "Processing instruction " << target << ' ' << data << endl;
}
void NavdataVisitor::warning (const char * message, int line, int column) {
SG_LOG(SG_NAVAID, SG_WARN, "Warning: " << message << " (" << line << ',' << column << ')');
}
void NavdataVisitor::error (const char * message, int line, int column) {
SG_LOG(SG_NAVAID, SG_ALERT, "Error: " << message << " (" << line << ',' << column << ')');
}
}