// Boost
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/algorithm/string.hpp>
+#include <boost/foreach.hpp>
// SimGear
#include <simgear/structure/exception.hxx>
-#include <simgear/xml/easyxml.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/magvar/magvar.hxx>
#include <simgear/timing/sg_time.hxx>
+#include <simgear/misc/sgstream.hxx>
+#include <simgear/misc/strutils.hxx>
+#include <simgear/props/props_io.hxx>
// FlightGear
#include <Main/globals.hxx>
+#include "Main/fg_props.hxx"
#include <Navaids/procedure.hxx>
#include <Navaids/waypoint.hxx>
+#include <Navaids/LevelDXML.hxx>
#include <Airports/simple.hxx>
using std::string;
const double NO_MAG_VAR = -1000.0; // an impossible mag-var value
-Waypt::Waypt(Route* aOwner) :
+bool isMachRestrict(RouteRestriction rr)
+{
+ return (rr == SPEED_RESTRICT_MACH) || (rr == SPEED_COMPUTED_MACH);
+}
+
+Waypt::Waypt(RouteBase* aOwner) :
_altitudeFt(0.0),
_speed(0.0),
_altRestrict(RESTRICT_NONE),
{
}
+Waypt::~Waypt()
+{
+}
+
std::string Waypt::ident() const
{
return "";
assert(!(position() == SGGeod()));
double jd = globals->get_time_params()->getJD();
- _magVarDeg = sgGetMagVar(position(), jd);
+ _magVarDeg = sgGetMagVar(position(), jd) * SG_RADIANS_TO_DEGREES;
}
return _magVarDeg;
}
+double Waypt::headingRadialDeg() const
+{
+ return 0.0;
+}
+
///////////////////////////////////////////////////////////////////////////
// persistence
}
}
-Waypt* Waypt::createInstance(Route* aOwner, const std::string& aTypeName)
+Waypt* Waypt::createInstance(RouteBase* aOwner, const std::string& aTypeName)
{
Waypt* r = NULL;
if (aTypeName == "basic") {
return r;
}
-WayptRef Waypt::createFromProperties(Route* aOwner, SGPropertyNode_ptr aProp)
+WayptRef Waypt::createFromProperties(RouteBase* aOwner, SGPropertyNode_ptr aProp)
{
if (!aProp->hasChild("type")) {
throw sg_io_exception("bad props node, no type provided",
"Waypt::createFromProperties");
}
- WayptRef nd(createInstance(aOwner, aProp->getStringValue("type")));
+ try {
+ WayptRef nd(createInstance(aOwner, aProp->getStringValue("type")));
+ nd->initFromProperties(aProp);
+ return nd;
+ } catch (sg_exception& e) {
+ SG_LOG(SG_GENERAL, SG_WARN, "failed to create waypoint, trying basic:" << e.getMessage());
+ }
+
+// if we failed to make the waypoint, try again making a basic waypoint.
+// this handles the case where a navaid waypoint is missing, for example
+ WayptRef nd(new BasicWaypt(aOwner));
nd->initFromProperties(aProp);
return nd;
}
setFlag(WPT_ARRIVAL, aProp->getBoolValue("arrival"));
}
+ if (aProp->hasChild("approach")) {
+ setFlag(WPT_APPROACH, aProp->getBoolValue("approach"));
+ }
+
if (aProp->hasChild("departure")) {
setFlag(WPT_DEPARTURE, aProp->getBoolValue("departure"));
}
aProp->setBoolValue("arrival", true);
}
+ if (flag(WPT_APPROACH)) {
+ aProp->setBoolValue("approach", true);
+ }
+
if (flag(WPT_MISS)) {
aProp->setBoolValue("miss", true);
}
}
}
-void Route::dumpRouteToFile(const WayptVec& aRoute, const std::string& aName)
+void RouteBase::dumpRouteToKML(const WayptVec& aRoute, const std::string& aName)
{
SGPath p = "/Users/jmt/Desktop/" + aName + ".kml";
std::fstream f;
f.open(p.str().c_str(), fstream::out | fstream::app);
if (!f.is_open()) {
- SG_LOG(SG_GENERAL, SG_WARN, "unable to open:" << p.str());
+ SG_LOG(SG_NAVAID, SG_WARN, "unable to open:" << p.str());
return;
}
"<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n"
"<Document>\n";
- dumpRouteToLineString(aName, aRoute, f);
+ dumpRouteToKMLLineString(aName, aRoute, f);
// post-amble
f << "</Document>\n"
f.close();
}
-void Route::dumpRouteToLineString(const std::string& aIdent,
+void RouteBase::dumpRouteToKMLLineString(const std::string& aIdent,
const WayptVec& aRoute, std::ostream& aStream)
{
// preamble
"</Placemark>\n" << endl;
}
-///////////////////////////////////////////////////////////////////////////
-
-class NavdataVisitor : public XMLVisitor {
-public:
- NavdataVisitor(FGAirport* aApt, const SGPath& aPath);
-
-protected:
- virtual void startXML ();
- virtual void endXML ();
- virtual void startElement (const char * name, const XMLAttributes &atts);
- virtual void endElement (const char * name);
- virtual void data (const char * s, int len);
- virtual void pi (const char * target, const char * data);
- virtual void warning (const char * message, int line, int column);
- virtual void error (const char * message, int line, int column);
-
-private:
- Waypt* buildWaypoint();
- void processRunways(ArrivalDeparture* aProc, const XMLAttributes &atts);
-
- void finishApproach();
- void finishSid();
- void finishStar();
-
- FGAirport* _airport;
- SGPath _path;
- string _text; ///< last element text value
-
- SID* _sid;
- STAR* _star;
- Approach* _approach;
-
- WayptVec _waypoints; ///< waypoint list for current approach/sid/star
- WayptVec _transWaypts; ///< waypoint list for current transition
-
- string _wayptName;
- string _wayptType;
- string _ident; // id of segment under construction
- string _transIdent;
- double _longitude, _latitude, _altitude, _speed;
- RouteRestriction _altRestrict;
-
- double _holdRadial; // inbound hold radial, or -1 if radial is 'inbound'
- double _holdTD; ///< hold time (seconds) or distance (nm), based on flag below
- bool _holdRighthanded;
- bool _holdDistance; // true, TD is distance in nm; false, TD is time in seconds
-
- double _course, _radial, _dmeDistance;
-};
-
-void Route::loadAirportProcedures(const SGPath& aPath, FGAirport* aApt)
+void RouteBase::loadAirportProcedures(const SGPath& aPath, FGAirport* aApt)
{
assert(aApt);
try {
NavdataVisitor visitor(aApt, aPath);
readXML(aPath.str(), visitor);
} catch (sg_io_exception& ex) {
- SG_LOG(SG_GENERAL, SG_WARN, "failured parsing procedures: " << aPath.str() <<
+ SG_LOG(SG_NAVAID, SG_WARN, "failure parsing procedures: " << aPath.str() <<
"\n\t" << ex.getMessage() << "\n\tat:" << ex.getLocation().asString());
} catch (sg_exception& ex) {
- SG_LOG(SG_GENERAL, SG_WARN, "failured parsing procedures: " << aPath.str() <<
+ SG_LOG(SG_NAVAID, SG_WARN, "failure parsing procedures: " << aPath.str() <<
"\n\t" << ex.getMessage());
}
}
-
-NavdataVisitor::NavdataVisitor(FGAirport* aApt, const SGPath& aPath):
- _airport(aApt),
- _path(aPath),
- _sid(NULL),
- _star(NULL),
- _approach(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.str());
- }
- } else if (tag == "Sid") {
- string ident(atts.getValue("Name"));
- _sid = new SID(ident);
- _waypoints.clear();
- processRunways(_sid, atts);
- } else if (tag == "Star") {
- string ident(atts.getValue("Name"));
- _star = new STAR(ident);
- _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;
- } else if (tag == "Approach") {
- _ident = atts.getValue("Name");
- _waypoints.clear();
- _approach = new Approach(_ident);
- } else if ((tag == "Sid_Transition") ||
- (tag == "App_Transition") ||
- (tag == "Star_Transition")) {
- _transIdent = atts.getValue("Name");
- _transWaypts.clear();
- } else if (tag == "RunwayTransition") {
- _transIdent = atts.getValue("Runway");
- _transWaypts.clear();
- } else {
-
- }
-}
-
-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());
- } else if ((tag == "AppTr_Waypoint") ||
- (tag == "SidTr_Waypoint") ||
- (tag == "RwyTr_Waypoint") ||
- (tag == "StarTr_Waypoint"))
- {
- _transWaypts.push_back(buildWaypoint());
- } else if (tag == "Sid_Transition") {
- assert(_sid);
- // SID waypoints are stored backwards, to share code with STARs
- std::reverse(_transWaypts.begin(), _transWaypts.end());
- Transition* t = new Transition(_transIdent, _sid, _transWaypts);
- _sid->addTransition(t);
- } else if (tag == "Star_Transition") {
- assert(_star);
- Transition* t = new Transition(_transIdent, _star, _transWaypts);
- _star->addTransition(t);
- } else if (tag == "App_Transition") {
- assert(_approach);
- Transition* t = new Transition(_transIdent, _approach, _transWaypts);
- _approach->addTransition(t);
- } 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* t = new Transition(_transIdent, ad, _transWaypts);
- FGRunwayRef rwy = _airport->getRunwayByIdent(_transIdent);
- ad->addRunwayTransition(rwy, t);
- } 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_value") {
- _course = atof(_text.c_str());
- } else if (tag == "DMEtoIntercept") {
- _dmeDistance = atof(_text.c_str());
- } else if (tag == "RadialtoIntercept") {
- _radial = atof(_text.c_str());
- } else {
-
- }
-}
-
-Waypt* NavdataVisitor::buildWaypoint()
-{
- Waypt* wp = NULL;
- if (_wayptType == "Normal") {
- // new LatLonWaypoint
- SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
- wp = new BasicWaypt(pos, _wayptName, NULL);
- } else if (_wayptType == "Runway") {
- string ident = _wayptName.substr(2);
- FGRunwayRef rwy = _airport->getRunwayByIdent(ident);
- wp = new RunwayWaypt(rwy, NULL);
- } else if (_wayptType == "Hold") {
- SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
- Hold* h = new Hold(pos, _wayptName, NULL);
- 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(NULL, _airport);
- } else if ((_wayptType == "Intc") || (_wayptType == "VorRadialIntc")) {
- SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
- wp = new RadialIntercept(NULL, _wayptName, pos, _course, _radial);
- } else if (_wayptType == "DmeIntc") {
- SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
- wp = new DMEIntercept(NULL, _wayptName, pos, _course, _dmeDistance);
- } else if (_wayptType == "ConstHdgtoAlt") {
- wp = new HeadingToAltitude(NULL, _wayptName, _course);
- } else {
- SG_LOG(SG_GENERAL, 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?
- }
-
- 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_IO, SG_WARN, "Warning: " << message << " (" << line << ',' << column << ')');
-}
-
-void NavdataVisitor::error (const char * message, int line, int column) {
- SG_LOG(SG_IO, SG_ALERT, "Error: " << message << " (" << line << ',' << column << ')');
-}
-
} // of namespace flightgear