/*************************************************************************** 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 #include #include #include "gpsdata.h" bool GPSObject::parseNode(const QDomNode& node) { QDomNode node2; // name is optional node2 = node.namedItem("name"); if (!node2.isNull()) name = (const char*)node2.firstChild().nodeValue(); // cmt is optional node2 = node.namedItem("cmt"); if (!node2.isNull()) cmt = (const char*)node2.firstChild().nodeValue(); // desc is optional node2 = node.namedItem("desc"); if (!node2.isNull()) desc = (const char*)node2.firstChild().nodeValue(); // src is optional node2 = node.namedItem("src"); if (!node2.isNull()) src = (const char*)node2.firstChild().nodeValue(); // url is optional node2 = node.namedItem("url"); if (!node2.isNull()) url = (const char*)node2.firstChild().nodeValue(); // urlname is optional node2 = node.namedItem("urlname"); if (!node2.isNull()) urlname = (const char*)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::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::max(); // sym is optional node2 = node.namedItem("sym"); if (!node2.isNull()) sym = (const char*)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::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::max(); return true; } void GPSExtended::fillElement(QDomElement& elt) { GPSObject::fillElement(elt); QDomDocument qdd = elt.ownerDocument(); if (number != std::numeric_limits::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::max(); xMax = -std::numeric_limits::max(); yMin = std::numeric_limits::max(); yMax = -std::numeric_limits::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::max(); xMax = -std::numeric_limits::max(); yMin = std::numeric_limits::max(); yMax = -std::numeric_limits::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); } } GPSData::GPSData() { xMin = std::numeric_limits::max(); xMax = -std::numeric_limits::max(); yMin = std::numeric_limits::max(); yMax = -std::numeric_limits::max(); } QgsRect* GPSData::getExtent() const { return new QgsRect(xMin, yMin, xMax, yMax); } int GPSData::getNumberOfWaypoints() const { return waypoints.size(); } int GPSData::getNumberOfRoutes() const { return routes.size(); } int GPSData::getNumberOfTracks() const { return tracks.size(); } 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]; } 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]; } 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]; } 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; 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; } int GPSData::addRoute(QString name) { Route rte; rte.name = name; routes.push_back(rte); return routes.size() - 1; } int GPSData::addTrack(QString name) { Track trk; trk.name = name; tracks.push_back(trk); return tracks.size() - 1; } 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; } 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); } 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); } std::ostream& operator<<(std::ostream& os, const GPSData& d) { os<<" Waypoints:"<::max(); xMax = -std::numeric_limits::max(); yMin = std::numeric_limits::max(); yMax = -std::numeric_limits::max(); // reset the data waypoints.clear(); routes.clear(); tracks.clear(); // ignore the 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; } 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 "<parseDom(qdd))) { std::cerr<(data, 0); } else std::cerr<second.second); return (GPSData*)(iter->second.first); } 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 "<second.second) == 0) { std::cerr<<"No one's using "<second.first; dataObjects.erase(iter); } } } // we have to initialize the static member GPSData::DataMap GPSData::dataObjects;