]> git.mxchange.org Git - flightgear.git/blobdiff - src/Navaids/route.cxx
Bug #927 - flightplan XML loading.
[flightgear.git] / src / Navaids / route.cxx
index 4afed518407f35bfe2068871aed173cc7adf8895..9123d24c3059b0cc3cb6698b0d928fead8b7219f 100644 (file)
 // 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;
@@ -54,7 +59,12 @@ namespace flightgear {
 
 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),
@@ -189,7 +199,7 @@ static const char* restrictionToString(RouteRestriction aRestrict)
   }
 }
 
-Waypt* Waypt::createInstance(Route* aOwner, const std::string& aTypeName)
+Waypt* Waypt::createInstance(RouteBase* aOwner, const std::string& aTypeName)
 {
   Waypt* r = NULL;
   if (aTypeName == "basic") {
@@ -220,14 +230,24 @@ Waypt* Waypt::createInstance(Route* aOwner, const std::string& aTypeName)
   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;
 }
@@ -252,6 +272,10 @@ void Waypt::initFromProperties(SGPropertyNode_ptr aProp)
     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")); 
   }
@@ -287,6 +311,10 @@ void Waypt::writeToProperties(SGPropertyNode_ptr aProp) const
     aProp->setBoolValue("arrival", true);
   }
   
+  if (flag(WPT_APPROACH)) {
+    aProp->setBoolValue("approach", true);
+  }
+  
   if (flag(WPT_MISS)) {
     aProp->setBoolValue("miss", true);
   }
@@ -306,13 +334,13 @@ void Waypt::writeToProperties(SGPropertyNode_ptr aProp) const
   }
 }
 
-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;
   }
   
@@ -321,7 +349,7 @@ void Route::dumpRouteToFile(const WayptVec& aRoute, const std::string& aName)
       "<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" 
@@ -329,7 +357,7 @@ void Route::dumpRouteToFile(const WayptVec& aRoute, const std::string& aName)
   f.close();
 }
 
-void Route::dumpRouteToLineString(const std::string& aIdent,
+void RouteBase::dumpRouteToKMLLineString(const std::string& aIdent,
   const WayptVec& aRoute, std::ostream& aStream)
 {
   // preamble
@@ -351,386 +379,19 @@ void Route::dumpRouteToLineString(const std::string& aIdent,
     "</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(Route* owner);
-  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;
-  Transition* _transition;
-  Procedure* _procedure;
-  
-  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, "failure 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, "failure 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),
-  _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.str());
-    }
-  } else if (tag == "Sid") {
-    string ident(atts.getValue("Name"));
-    _sid = new SID(ident);
-    _procedure = _sid;
-    _waypoints.clear();
-    processRunways(_sid, atts);
-  } else if (tag == "Star") {
-    string ident(atts.getValue("Name"));
-    _star = new STAR(ident);
-    _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;
-  } else if (tag == "Approach") {
-    _ident = atts.getValue("Name");
-    _waypoints.clear();
-    _approach = new Approach(_ident);
-    _procedure = _approach;
-  } else if ((tag == "Sid_Transition") || 
-             (tag == "App_Transition") ||
-             (tag == "Star_Transition")) {
-    _transIdent = atts.getValue("Name");
-    _transition = new Transition(_transIdent, _procedure);
-    _transWaypts.clear();
-  } else if (tag == "RunwayTransition") {
-    _transIdent = atts.getValue("Runway");
-    _transition = new Transition(_transIdent, _procedure);
-    _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(_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_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(Route* 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, _course, _radial);
-  } else if (_wayptType == "DmeIntc") {
-    SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
-    wp = new DMEIntercept(owner, _wayptName, pos, _course, _dmeDistance);
-  } else if (_wayptType == "ConstHdgtoAlt") {
-    wp = new HeadingToAltitude(owner, _wayptName, _course);
-  } else if (_wayptType == "PBD") {
-    SGGeod pos(SGGeod::fromDeg(_longitude, _latitude)), pos2;
-    double az2;
-    SGGeodesy::direct(pos, _course, _dmeDistance, pos2, az2);
-    wp = new BasicWaypt(pos2, _wayptName, owner);
-  } 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