Logo Search packages:      
Sourcecode: qgis version File versions

gpsdata.cpp

/***************************************************************************
      gpsdata.cpp  -  Data structures for GPS data
                             -------------------
    begin                : 2004-04-14
    copyright            : (C) 2004 by Lars Luthman
    email                : larsl@users.sourceforge.net
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include <limits>
#include <stdexcept>

#include <qfile.h>

#include "gpsdata.h"


bool GPSObject::parseNode(const QDomNode& node) {
  
  QDomNode node2;
  
  // name is optional
  node2 = node.namedItem("name");
  if (!node2.isNull())
    name = node2.firstChild().nodeValue();
  
  // cmt is optional
  node2 = node.namedItem("cmt");
  if (!node2.isNull())
    cmt = node2.firstChild().nodeValue();
  
  // desc is optional
  node2 = node.namedItem("desc");
  if (!node2.isNull())
    desc = node2.firstChild().nodeValue();
  
  // src is optional
  node2 = node.namedItem("src");
  if (!node2.isNull())
    src = node2.firstChild().nodeValue();
  
  // url is optional
  node2 = node.namedItem("url");
  if (!node2.isNull())
    url = node2.firstChild().nodeValue();
  
  // urlname is optional
  node2 = node.namedItem("urlname");
  if (!node2.isNull())
    urlname = node2.firstChild().nodeValue();
  
  return true;
}


void GPSObject::fillElement(QDomElement& elt) {
  QDomDocument qdd = elt.ownerDocument();
  if (!name.isEmpty()) {
    QDomElement nameElt = qdd.createElement("name");
    nameElt.appendChild(qdd.createTextNode(name));
    elt.appendChild(nameElt);
  }
  if (!cmt.isEmpty()) {
    QDomElement cmtElt = qdd.createElement("cmt");
    cmtElt.appendChild(qdd.createTextNode(cmt));
    elt.appendChild(cmtElt);
  }
  if (!desc.isEmpty()) {
    QDomElement descElt = qdd.createElement("desc");
    descElt.appendChild(qdd.createTextNode(desc));
    elt.appendChild(descElt);
  }
  if (!src.isEmpty()) {
    QDomElement srcElt = qdd.createElement("src");
    srcElt.appendChild(qdd.createTextNode(src));
    elt.appendChild(srcElt);
  }
  if (!url.isEmpty()) {
    QDomElement urlElt = qdd.createElement("url");
    urlElt.appendChild(qdd.createTextNode(url));
    elt.appendChild(urlElt);
  }
  if (!urlname.isEmpty()) {
    QDomElement urlnameElt = qdd.createElement("urlname");
    urlnameElt.appendChild(qdd.createTextNode(urlname));
    elt.appendChild(urlnameElt);
  }
}


GPSPoint::GPSPoint() {
  ele = -std::numeric_limits<double>::max();
}


bool GPSPoint::parseNode(const QDomNode& node) {
  GPSObject::parseNode(node);

  QDomNode node2;
  
  // lat and lon are required
  node2 = node.attributes().namedItem("lat");
  if (node2.isNull())
    return false;
  lat = node2.nodeValue().toDouble();
  node2 = node.attributes().namedItem("lon");
  if (node2.isNull())
    return false;
  lon = node2.nodeValue().toDouble();
  
  // ele is optional
  node2 = node.namedItem("ele");
  if (!node2.isNull())
    ele = std::atof((const char*)node2.firstChild().nodeValue());
  else
    ele = -std::numeric_limits<double>::max();
  
  // sym is optional
  node2 = node.namedItem("sym");
  if (!node2.isNull())
    sym = node2.firstChild().nodeValue();
  
  return true;
}


void GPSPoint::fillElement(QDomElement& elt) {
  GPSObject::fillElement(elt);
  QDomDocument qdd = elt.ownerDocument();
  elt.setAttribute("lat", QString("%1").arg(lat, 0, 'f'));
  elt.setAttribute("lon", QString("%1").arg(lon, 0, 'f'));
  if (ele != -std::numeric_limits<double>::max()) {
    QDomElement eleElt = qdd.createElement("ele");
    eleElt.appendChild(qdd.createTextNode(QString("%1").arg(ele, 0, 'f')));
    elt.appendChild(eleElt);
  }
  if (!sym.isEmpty()) {
    QDomElement symElt = qdd.createElement("sym");
    symElt.appendChild(qdd.createTextNode(sym));
    elt.appendChild(symElt);
  }
}


bool GPSExtended::parseNode(const QDomNode& node) {
  GPSObject::parseNode(node);

  // number is optional
  QDomNode node2 = node.namedItem("number");
  if (!node2.isNull())
    number = std::atoi((const char*)node2.firstChild().nodeValue());
  else
    number = std::numeric_limits<int>::max();
  return true;
}


void GPSExtended::fillElement(QDomElement& elt) {
  GPSObject::fillElement(elt);
  QDomDocument qdd = elt.ownerDocument();
  if (number != std::numeric_limits<int>::max()) {
    QDomElement numberElt = qdd.createElement("number");
    numberElt.appendChild(qdd.createTextNode(QString("%1").arg(number)));
    elt.appendChild(numberElt);
  }
}


bool Route::parseNode(const QDomNode& node) {
  GPSExtended::parseNode(node);
  
  QDomNode node2;
  
  // reset extent
  xMin = std::numeric_limits<double>::max();
  xMax = -std::numeric_limits<double>::max();
  yMin = std::numeric_limits<double>::max();
  yMax = -std::numeric_limits<double>::max();
  
  // routepoints are optional, empty routes are allowed
  node2 = node.namedItem("rtept");
  while (!node2.isNull()) {
    if (node2.nodeName() == "rtept") {
      Routepoint rtept;
      if (!rtept.parseNode(node2))
      return false;
      points.push_back(rtept);
      
      // update the route bounds
      xMin = (xMin < rtept.lon ? xMin : rtept.lon);
      xMax = (xMax > rtept.lon ? xMax : rtept.lon);
      yMin = (yMin < rtept.lat ? yMin : rtept.lat);
      yMax = (yMax > rtept.lat ? yMax : rtept.lat);
    }
    node2 = node2.nextSibling();
  }
  
  return true;
}


void Route::fillElement(QDomElement& elt) {
  GPSExtended::fillElement(elt);
  
  QDomDocument qdd = elt.ownerDocument();
  
  for (int i = 0; i < points.size(); ++i) {
    QDomElement ptElt = qdd.createElement("rtept");
    points[i].fillElement(ptElt);
    elt.appendChild(ptElt);
  }
}


bool Track::parseNode(const QDomNode& node) {
  GPSExtended::parseNode(node);
  
  QDomNode node2, node3;

  // reset track bounds
  xMin = std::numeric_limits<double>::max();
  xMax = -std::numeric_limits<double>::max();
  yMin = std::numeric_limits<double>::max();
  yMax = -std::numeric_limits<double>::max();
  
  // track segments are optional - empty tracks are allowed
  node2 = node.namedItem("trkseg");
  while (!node2.isNull()) {
    if (node2.nodeName() == "trkseg") {
      TrackSegment trkseg;
      node3 = node2.namedItem("trkpt");
      while (!node3.isNull()) {
      if (node3.nodeName() == "trkpt") {
        Trackpoint trkpt;
        if (!trkpt.parseNode(node3))
          return false;
        trkseg.points.push_back(trkpt);
        
        // update the track bounds
        xMin = (xMin < trkpt.lon ? xMin : trkpt.lon);
        xMax = (xMax > trkpt.lon ? xMax : trkpt.lon);
        yMin = (yMin < trkpt.lat ? yMin : trkpt.lat);
        yMax = (yMax > trkpt.lat ? yMax : trkpt.lat);
      }
      node3 = node3.nextSibling();
      }
      
      segments.push_back(trkseg);
    }
    node2 = node2.nextSibling();
  }
  
  return true;
}


void Track::fillElement(QDomElement& elt) {
  GPSExtended::fillElement(elt);
  QDomDocument qdd = elt.ownerDocument();
  
  for (int i = 0; i < segments.size(); ++i) {
    QDomElement sgmElt = qdd.createElement("trkseg");
    for (int j = 0; j < segments[i].points.size(); ++j) {
      QDomElement ptElt = qdd.createElement("trkpt");
      segments[i].points[j].fillElement(ptElt);
      sgmElt.appendChild(ptElt);
    }
    elt.appendChild(sgmElt);
  }
}


00281 GPSData::GPSData() {
  xMin = std::numeric_limits<double>::max();
  xMax = -std::numeric_limits<double>::max();
  yMin = std::numeric_limits<double>::max();
  yMax = -std::numeric_limits<double>::max();
}


00289 QgsRect* GPSData::getExtent() const {
  return new QgsRect(xMin, yMin, xMax, yMax);
}


00294 int GPSData::getNumberOfWaypoints() const {
  return waypoints.size();
}


00299 int GPSData::getNumberOfRoutes() const {
  return routes.size();
}


00304 int GPSData::getNumberOfTracks() const {
  return tracks.size();
}


00309 Waypoint& GPSData::getWaypoint(int index) {
  if (index < 0 || index >= waypoints.size())
    throw std::out_of_range("Waypoint index is out of range");
  return waypoints[index];
}


00316 Route& GPSData::getRoute(int index) {
  if (index < 0 || index >= routes.size())
    throw std::out_of_range("Route index is out of range");
  return routes[index];
}


00323 Track& GPSData::getTrack(int index) {
  if (index < 0 || index >= tracks.size())
    throw std::out_of_range("Track index is out of range");
  return tracks[index];
}


00330 int GPSData::addWaypoint(double lat, double lon, QString name, 
                   double ele) {
  Waypoint wpt;
  wpt.lat = lat;
  wpt.lon = lon;
  wpt.name = name;
  wpt.ele = ele;
  return addWaypoint(wpt);
}


00341 int GPSData::addWaypoint(const Waypoint& wpt) {
  xMax = xMax > wpt.lon ? xMax : wpt.lon;
  xMin = xMin < wpt.lon ? xMin : wpt.lon;
  yMax = yMax > wpt.lat ? yMax : wpt.lat;
  yMin = yMin < wpt.lat ? yMin : wpt.lat;
  waypoints.push_back(wpt);
  return waypoints.size() - 1;
}


00351 int GPSData::addRoute(QString name) {
  Route rte;
  rte.name = name;
  return addRoute(rte);
}


00358 int GPSData::addRoute(const Route& rte) {
  xMax = xMax > rte.xMax ? xMax : rte.xMax;
  xMin = xMin < rte.xMin ? xMin : rte.xMin;
  yMax = yMax > rte.yMax ? yMax : rte.yMax;
  yMin = yMin < rte.yMin ? yMin : rte.yMin;
  routes.push_back(rte);
  return routes.size() - 1;
}


00368 int GPSData::addTrack(QString name) {
  Track trk;
  trk.name = name;
  return addTrack(trk);
}
  

00375 int GPSData::addTrack(const Track& trk) {
  xMax = xMax > trk.xMax ? xMax : trk.xMax;
  xMin = xMin < trk.xMin ? xMin : trk.xMin;
  yMax = yMax > trk.yMax ? yMax : trk.yMax;
  yMin = yMin < trk.yMin ? yMin : trk.yMin;
  tracks.push_back(trk);
  return tracks.size() - 1;
}


00385 bool GPSData::removeWaypoint(int index, bool checkRoutes) {
  if (checkRoutes)
    throw std::logic_error("Not implemented");
  if (index < 0 || index >= waypoints.size())
    throw std::out_of_range("Waypoint index is out of range");
  waypoints.erase(waypoints.begin() + index);
  return true;
}


00395 void GPSData::removeRoute(int index) {
  if (index < 0 || index >= routes.size())
    throw std::out_of_range("Route index is out of range");
  routes.erase(routes.begin() + index);
}


00402 void GPSData::removeTrack(int index) {
  if (index < 0 || index >= tracks.size())
    throw std::out_of_range("Track index is out of range");
  tracks.erase(tracks.begin() + index);
}
  

00409 std::ostream& operator<<(std::ostream& os, const GPSData& d) {
  os<<"  Waypoints:"<<std::endl;
  for (int i = 0; i < d.waypoints.size(); ++i)
    os<<"    "<<d.waypoints[i].name<<": "
      <<d.waypoints[i].lat<<", "<<d.waypoints[i].lon<<std::endl;

  os<<"  Routes:"<<std::endl;
  for (int i = 0; i < d.routes.size(); ++i)
    os<<"    "<<d.routes[i].name<<std::endl;

  os<<"  Tracks:"<<std::endl;
  for (int i = 0; i < d.tracks.size(); ++i)
    os<<"    "<<d.tracks[i].name<<std::endl;

  return os;
}


00427 bool GPSData::parseDom(QDomDocument& qdd) {
  
  // reset the extent
  xMin = std::numeric_limits<double>::max();
  xMax = -std::numeric_limits<double>::max();
  yMin = std::numeric_limits<double>::max();
  yMax = -std::numeric_limits<double>::max();
  
  // reset the data
  waypoints.clear();
  routes.clear();
  tracks.clear();
  
  // ignore the <?xml... tags
  QDomNode node, node2, node3, node4;
  node = qdd.firstChild();
  while (node.nodeName() != "gpx")
    node = node.nextSibling();
  
  // there must be a gpx element
  if (node.isNull())
    return false;
  
  return parseGPX(node);
}


00454 void GPSData::fillDom(QDomDocument& qdd) {
  QDomElement gpxElt = qdd.createElement("gpx");
  qdd.appendChild(gpxElt);
  gpxElt.setAttribute("version", "1.0");
  
  // add waypoints
  for (int i = 0; i < waypoints.size(); ++i) {
    QDomElement wptElt = qdd.createElement("wpt");
    waypoints[i].fillElement(wptElt);
    gpxElt.appendChild(wptElt);
  }

  // add routes
  for (int i = 0; i < routes.size(); ++i) {
    QDomElement rteElt = qdd.createElement("rte");
    routes[i].fillElement(rteElt);
    gpxElt.appendChild(rteElt);
  }

  // add tracks
  for (int i = 0; i < tracks.size(); ++i) {
    QDomElement trkElt = qdd.createElement("trk");
    tracks[i].fillElement(trkElt);
    gpxElt.appendChild(trkElt);
  }
}


00482 bool GPSData::parseGPX(QDomNode& node) {
  // start parsing child nodes
  node = node.firstChild();
  QDomNode node2, node3, node4;
  while (!node.isNull()) {

    // waypoint
    if (node.nodeName() == "wpt") {
      Waypoint wpt;
      if (!wpt.parseNode(node))
      return false;
      waypoints.push_back(wpt);
      
      // update the extent
      xMin = xMin < wpt.lon ? xMin : wpt.lon;
      xMax = xMax > wpt.lon ? xMax : wpt.lon;
      yMin = yMin < wpt.lat ? yMin : wpt.lat;
      yMax = yMax > wpt.lat ? yMax : wpt.lat;
    }
    
    // route
    else if (node.nodeName() == "rte") {
      Route rte;
      if (!rte.parseNode(node))
      return false;
      routes.push_back(rte);

      // update the extent
      xMin = xMin < rte.xMin ? xMin : rte.xMin;
      xMax = xMax > rte.xMax ? xMax : rte.xMax;
      yMin = yMin < rte.yMin ? yMin : rte.yMin;
      yMax = yMax > rte.yMax ? yMax : rte.yMax;
    }
    
    // track
    else if (node.nodeName() == "trk") {
      Track trk;
      if (!trk.parseNode(node))
      return false;
      tracks.push_back(trk);
      
      // update the extent
      xMin = xMin < trk.xMin ? xMin : trk.xMin;
      xMax = xMax > trk.xMax ? xMax : trk.xMax;
      yMin = yMin < trk.yMin ? yMin : trk.yMin;
      yMax = yMax > trk.yMax ? yMax : trk.yMax;
    }
      
    node = node.nextSibling();
  } 
  
  return true;
}


00537 GPSData* GPSData::getData(const QString& filename) {
  
  // if the data isn't there already, try to load it
  if (dataObjects.find(filename) == dataObjects.end()) {
    QDomDocument qdd;
    QFile file(filename);
    GPSData* data = new GPSData;
    std::cerr<<"Loading file "<<filename<<std::endl;
    if (!(qdd.setContent(&file) && data->parseDom(qdd))) {
      std::cerr<<filename<<"is not valid GPX!"<<std::endl;
      return 0;
    }
    dataObjects[filename] = std::pair<GPSData*, unsigned>(data, 0);
  }
  else
    std::cerr<<filename<<" is already loaded"<<std::endl;
  
  // return a pointer and increase the reference count for that filename
  DataMap::iterator iter = dataObjects.find(filename);
  ++(iter->second.second);
  return (GPSData*)(iter->second.first);
}


00561 void GPSData::releaseData(const QString& filename) {
  
  /* decrease the reference count for the filename (if it is used), and erase
     it if the reference count becomes 0 */
  DataMap::iterator iter = dataObjects.find(filename);
  if (iter != dataObjects.end()) {
    std::cerr<<"unrefing "<<filename<<std::endl;
    if (--(iter->second.second) == 0) {
      std::cerr<<"No one's using "<<filename<<", I'll erase it"<<std::endl;
      delete iter->second.first;
      dataObjects.erase(iter);
    }
  }
}


// we have to initialize the static member
GPSData::DataMap GPSData::dataObjects;

Generated by  Doxygen 1.6.0   Back to index