1
/***************************************************************************
2
gpsdata.cpp - Data structures for GPS data
5
copyright : (C) 2004 by Lars Luthman
6
email : larsl@users.sourceforge.net
7
***************************************************************************/
9
/***************************************************************************
11
* This program is free software; you can redistribute it and/or modify *
12
* it under the terms of the GNU General Public License as published by *
13
* the Free Software Foundation; either version 2 of the License, or *
14
* (at your option) any later version. *
16
***************************************************************************/
22
#include <QTextStream>
26
#include <qgslogger.h>
28
QString GPSObject::xmlify(const QString& str) {
30
tmp.replace("&", "&");
31
tmp.replace("<", "<");
32
tmp.replace(">", ">");
33
tmp.replace("\"", """);
34
tmp.replace("\'", "'");
39
void GPSObject::writeXML(QTextStream& stream) {
41
stream<<"<name>"<<xmlify(name)<<"</name>\n";
43
stream<<"<cmt>"<<xmlify(cmt)<<"</cmt>\n";
45
stream<<"<desc>"<<xmlify(desc)<<"</desc>\n";
47
stream<<"<src>"<<xmlify(src)<<"</src>\n";
49
stream<<"<url>"<<xmlify(url)<<"</url>\n";
50
if (!urlname.isEmpty())
51
stream<<"<urlname>"<<xmlify(urlname)<<"</urlname>\n";
55
GPSPoint::GPSPoint() {
56
ele = -std::numeric_limits<double>::max();
60
void GPSPoint::writeXML(QTextStream& stream) {
61
GPSObject::writeXML(stream);
62
if (ele != -std::numeric_limits<double>::max())
63
stream<<"<ele>"<<ele<<"</ele>\n";
65
stream<<"<sym>"<<xmlify(sym)<<"</sym>\n";
69
GPSExtended::GPSExtended()
70
: xMin(std::numeric_limits<double>::max()),
71
xMax(-std::numeric_limits<double>::max()),
72
yMin(std::numeric_limits<double>::max()),
73
yMax(-std::numeric_limits<double>::max()),
74
number(std::numeric_limits<int>::max()) {
79
void GPSExtended::writeXML(QTextStream& stream) {
80
GPSObject::writeXML(stream);
81
if (number != std::numeric_limits<int>::max())
82
stream<<"<number>"<<number<<"</number>\n";
86
void Waypoint::writeXML(QTextStream& stream) {
87
stream<<"<wpt lat=\""<<lat<<"\" lon=\""<<lon<<"\">\n";
88
GPSPoint::writeXML(stream);
93
void Route::writeXML(QTextStream& stream) {
95
GPSExtended::writeXML(stream);
96
for (int i = 0; i < points.size(); ++i) {
97
stream<<"<rtept lat=\""<<points[i].lat
98
<<"\" lon=\""<<points[i].lon<<"\">\n";
99
points[i].writeXML(stream);
100
stream<<"</rtept>\n";
106
void Track::writeXML(QTextStream& stream) {
108
GPSExtended::writeXML(stream);
109
for (int i = 0; i < segments.size(); ++i) {
110
stream<<"<trkseg>\n";
111
for (int j = 0; j < segments[i].points.size(); ++j) {
112
stream<<"<trkpt lat=\""<<segments[i].points[j].lat
113
<<"\" lon=\""<<segments[i].points[j].lon<<"\">\n";
114
segments[i].points[j].writeXML(stream);
115
stream<<"</trkpt>\n";
117
stream<<"</trkseg>\n";
124
xMin = std::numeric_limits<double>::max();
125
xMax = -std::numeric_limits<double>::max();
126
yMin = std::numeric_limits<double>::max();
127
yMax = -std::numeric_limits<double>::max();
134
QgsRect* GPSData::getExtent() const {
135
return new QgsRect(xMin, yMin, xMax, yMax);
138
void GPSData::setNoDataExtent() {
139
if (getNumberOfWaypoints() + getNumberOfRoutes() + getNumberOfTracks() == 0)
148
int GPSData::getNumberOfWaypoints() const {
149
return waypoints.size();
153
int GPSData::getNumberOfRoutes() const {
154
return routes.size();
158
int GPSData::getNumberOfTracks() const {
159
return tracks.size();
163
GPSData::WaypointIterator GPSData::waypointsBegin() {
164
return waypoints.begin();
168
GPSData::RouteIterator GPSData::routesBegin() {
169
return routes.begin();
173
GPSData::TrackIterator GPSData::tracksBegin() {
174
return tracks.begin();
178
GPSData::WaypointIterator GPSData::waypointsEnd() {
179
return waypoints.end();
183
GPSData::RouteIterator GPSData::routesEnd() {
188
GPSData::TrackIterator GPSData::tracksEnd() {
193
GPSData::WaypointIterator GPSData::addWaypoint(double lat, double lon,
194
QString name, double ele) {
200
return addWaypoint(wpt);
204
GPSData::WaypointIterator GPSData::addWaypoint(const Waypoint& wpt) {
205
xMax = xMax > wpt.lon ? xMax : wpt.lon;
206
xMin = xMin < wpt.lon ? xMin : wpt.lon;
207
yMax = yMax > wpt.lat ? yMax : wpt.lat;
208
yMin = yMin < wpt.lat ? yMin : wpt.lat;
209
WaypointIterator iter = waypoints.insert(waypoints.end(), wpt);
210
iter->id = nextWaypoint++;
215
GPSData::RouteIterator GPSData::addRoute(QString name) {
218
return addRoute(rte);
222
GPSData::RouteIterator GPSData::addRoute(const Route& rte) {
223
xMax = xMax > rte.xMax ? xMax : rte.xMax;
224
xMin = xMin < rte.xMin ? xMin : rte.xMin;
225
yMax = yMax > rte.yMax ? yMax : rte.yMax;
226
yMin = yMin < rte.yMin ? yMin : rte.yMin;
227
RouteIterator iter = routes.insert(routes.end(), rte);
228
iter->id = nextRoute++;
233
GPSData::TrackIterator GPSData::addTrack(QString name) {
236
return addTrack(trk);
240
GPSData::TrackIterator GPSData::addTrack(const Track& trk) {
241
xMax = xMax > trk.xMax ? xMax : trk.xMax;
242
xMin = xMin < trk.xMin ? xMin : trk.xMin;
243
yMax = yMax > trk.yMax ? yMax : trk.yMax;
244
yMin = yMin < trk.yMin ? yMin : trk.yMin;
245
TrackIterator iter = tracks.insert(tracks.end(), trk);
246
iter->id = nextTrack++;
251
void GPSData::removeWaypoints(std::list<int> const & ids) {
252
std::list<int> ids2 = ids;
254
std::list<int>::const_iterator iter = ids2.begin();
255
WaypointIterator wIter;
256
for (wIter = waypoints.begin();
257
wIter != waypoints.end() && iter != ids2.end(); ) {
258
WaypointIterator tmpIter = wIter;
260
if (wIter->id == *iter) {
261
waypoints.erase(wIter);
269
void GPSData::removeRoutes(std::list<int> const & ids) {
270
std::list<int> ids2 = ids;
272
std::list<int>::const_iterator iter = ids2.begin();
274
for (rIter = routes.begin(); rIter != routes.end() && iter != ids2.end(); ) {
275
RouteIterator tmpIter = rIter;
277
if (rIter->id == *iter) {
286
void GPSData::removeTracks(std::list<int> const & ids) {
287
std::list<int> ids2 = ids;
289
std::list<int>::const_iterator iter = ids2.begin();
291
for (tIter = tracks.begin(); tIter != tracks.end() && iter != ids2.end(); ) {
292
TrackIterator tmpIter = tIter;
294
if (tIter->id == *iter) {
303
void GPSData::writeXML(QTextStream& stream) {
304
stream.setEncoding(QTextStream::UnicodeUTF8);
305
stream<<"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
306
<<"<gpx version=\"1.0\" creator=\"Quantum GIS\">\n";
307
for (WaypointIterator wIter = waypoints.begin();
308
wIter != waypoints.end(); ++wIter)
309
wIter->writeXML(stream);
310
for (RouteIterator rIter = routes.begin(); rIter != routes.end(); ++rIter)
311
rIter->writeXML(stream);
312
for (TrackIterator tIter = tracks.begin(); tIter != tracks.end(); ++tIter)
313
tIter->writeXML(stream);
319
GPSData* GPSData::getData(const QString& filename) {
320
// if the data isn't there already, try to load it
321
if (dataObjects.find(filename) == dataObjects.end()) {
322
QFile file(filename);
323
if (!file.open(QIODevice::ReadOnly)) {
324
QgsLogger::warning(QObject::tr("Couldn't open the data source: ") + filename);
327
GPSData* data = new GPSData;
328
QgsLogger::debug("Loading file " + filename);
329
GPXHandler handler(*data);
333
XML_Parser p = XML_ParserCreate(NULL);
334
XML_SetUserData(p, &handler);
335
XML_SetElementHandler(p, GPXHandler::start, GPXHandler::end);
336
XML_SetCharacterDataHandler(p, GPXHandler::chars);
337
long int bufsize = 10*1024*1024;
338
char* buffer = new char[bufsize];
340
while (!file.atEnd()) {
341
long int readBytes = file.readBlock(buffer, bufsize);
344
if (!XML_Parse(p, buffer, readBytes, atEnd)) {
345
QgsLogger::warning(QObject::tr("Parse error at line ") +
346
QString("%1").arg(XML_GetCurrentLineNumber(p)) +
348
QString(XML_ErrorString(XML_GetErrorCode(p))));
358
data->setNoDataExtent();
360
dataObjects[filename] = std::pair<GPSData*, unsigned>(data, 0);
363
QgsLogger::debug(filename + " is already loaded");
365
// return a pointer and increase the reference count for that filename
366
DataMap::iterator iter = dataObjects.find(filename);
367
++(iter->second.second);
368
return (GPSData*)(iter->second.first);
372
void GPSData::releaseData(const QString& filename) {
374
/* decrease the reference count for the filename (if it is used), and erase
375
it if the reference count becomes 0 */
376
DataMap::iterator iter = dataObjects.find(filename);
377
if (iter != dataObjects.end()) {
378
QgsLogger::debug("unrefing " + filename);
379
if (--(iter->second.second) == 0) {
380
QgsLogger::debug("No one's using " + filename + ", I'll erase it");
381
delete iter->second.first;
382
dataObjects.erase(iter);
388
// we have to initialize the static member
389
GPSData::DataMap GPSData::dataObjects;
394
bool GPXHandler::startElement(const XML_Char* qName, const XML_Char** attr) {
396
if (!std::strcmp(qName, "gpx")) {
397
parseModes.push(ParsingDocument);
402
else if (!std::strcmp(qName, "wpt")) {
403
parseModes.push(ParsingWaypoint);
405
for (int i = 0; attr[2*i] != NULL; ++i) {
406
if (!std::strcmp(attr[2*i], "lat"))
407
mWpt.lat = QString(attr[2*i+1]).toDouble();
408
else if (!std::strcmp(attr[2*i], "lon"))
409
mWpt.lon = QString(attr[2*i+1]).toDouble();
413
else if (!std::strcmp(qName, "rte")) {
414
parseModes.push(ParsingRoute);
418
else if (!std::strcmp(qName, "trk")) {
419
parseModes.push(ParsingTrack);
425
else if (!std::strcmp(qName, "name")) {
426
if (parseModes.top() == ParsingWaypoint ||
427
parseModes.top() == ParsingRoute ||
428
parseModes.top() == ParsingTrack) {
429
mString = &mObj->name;
431
parseModes.push(ParsingString);
434
parseModes.push(ParsingUnknown);
436
else if (!std::strcmp(qName, "cmt")) {
437
if (parseModes.top() == ParsingWaypoint ||
438
parseModes.top() == ParsingRoute ||
439
parseModes.top() == ParsingTrack) {
440
mString = &mObj->cmt;
442
parseModes.push(ParsingString);
445
parseModes.push(ParsingUnknown);
447
else if (!std::strcmp(qName, "desc")) {
448
if (parseModes.top() == ParsingWaypoint ||
449
parseModes.top() == ParsingRoute ||
450
parseModes.top() == ParsingTrack) {
451
mString = &mObj->desc;
453
parseModes.push(ParsingString);
456
parseModes.push(ParsingUnknown);
458
else if (!std::strcmp(qName, "src")) {
459
if (parseModes.top() == ParsingWaypoint ||
460
parseModes.top() == ParsingRoute ||
461
parseModes.top() == ParsingTrack) {
462
mString = &mObj->src;
464
parseModes.push(ParsingString);
467
parseModes.push(ParsingUnknown);
469
else if (!std::strcmp(qName, "url")) {
470
if (parseModes.top() == ParsingWaypoint ||
471
parseModes.top() == ParsingRoute ||
472
parseModes.top() == ParsingTrack) {
473
mString = &mObj->url;
475
parseModes.push(ParsingString);
478
parseModes.push(ParsingUnknown);
480
else if (!std::strcmp(qName, "urlname")) {
481
if (parseModes.top() == ParsingWaypoint ||
482
parseModes.top() == ParsingRoute ||
483
parseModes.top() == ParsingTrack) {
484
mString = &mObj->urlname;
486
parseModes.push(ParsingString);
489
parseModes.push(ParsingUnknown);
492
// waypoint-specific attributes
493
else if (!std::strcmp(qName, "ele")) {
494
if (parseModes.top() == ParsingWaypoint) {
497
parseModes.push(ParsingDouble);
500
parseModes.push(ParsingUnknown);
502
else if (!std::strcmp(qName, "sym")) {
503
if (parseModes.top() == ParsingWaypoint) {
506
parseModes.push(ParsingString);
509
parseModes.push(ParsingUnknown);
512
// route/track-specific attributes
513
else if (!std::strcmp(qName, "number")) {
514
if (parseModes.top() == ParsingRoute) {
517
parseModes.push(ParsingInt);
519
else if (parseModes.top() == ParsingTrack) {
521
parseModes.push(ParsingInt);
524
parseModes.push(ParsingUnknown);
528
else if (!std::strcmp(qName, "rtept")) {
529
if (parseModes.top() == ParsingRoute) {
530
mRtept = Routepoint();
531
for (int i = 0; attr[2*i] != NULL; ++i) {
532
if (!std::strcmp(attr[2*i], "lat"))
533
mRtept.lat = QString(attr[2*i+1]).toDouble();
534
else if (!std::strcmp(attr[2*i], "lon"))
535
mRtept.lon = QString(attr[2*i+1]).toDouble();
537
parseModes.push(ParsingRoutepoint);
540
parseModes.push(ParsingUnknown);
543
// track segments and points
544
else if (!std::strcmp(qName, "trkseg")) {
545
if (parseModes.top() == ParsingTrack) {
546
mTrkseg = TrackSegment();
547
parseModes.push(ParsingTrackSegment);
550
parseModes.push(ParsingUnknown);
552
else if (!std::strcmp(qName, "trkpt")) {
553
if (parseModes.top() == ParsingTrackSegment) {
554
mTrkpt = Trackpoint();
555
for (int i = 0; attr[2*i] != NULL; ++i) {
556
if (!std::strcmp(attr[2*i], "lat"))
557
mTrkpt.lat = QString(attr[2*i+1]).toDouble();
558
else if (!std::strcmp(attr[2*i], "lon"))
559
mTrkpt.lon = QString(attr[2*i+1]).toDouble();
561
parseModes.push(ParsingTrackpoint);
564
parseModes.push(ParsingUnknown);
569
parseModes.push(ParsingUnknown);
575
void GPXHandler::characters(const XML_Char* chars, int len) {
578
for (int i = 0; i < len; ++i)
579
mCharBuffer += QChar(chars[i]);
581
mCharBuffer += QString::fromUtf8(chars, len);
586
bool GPXHandler::endElement(const std::string& qName) {
587
if (parseModes.top() == ParsingWaypoint) {
588
mData.addWaypoint(mWpt);
590
else if (parseModes.top() == ParsingRoute) {
591
mData.addRoute(mRte);
593
else if (parseModes.top() == ParsingTrack) {
594
mData.addTrack(mTrk);
596
else if (parseModes.top() == ParsingRoutepoint) {
597
mRte.points.push_back(mRtept);
598
mRte.xMin = (mRte.xMin < mRtept.lon ? mRte.xMin : mRtept.lon);
599
mRte.xMax = (mRte.xMax > mRtept.lon ? mRte.xMax : mRtept.lon);
600
mRte.yMin = (mRte.yMin < mRtept.lat ? mRte.yMin : mRtept.lat);
601
mRte.yMax = (mRte.yMax > mRtept.lat ? mRte.yMax : mRtept.lat);
603
else if (parseModes.top() == ParsingTrackSegment) {
604
mTrk.segments.push_back(mTrkseg);
606
else if (parseModes.top() == ParsingTrackpoint) {
607
mTrkseg.points.push_back(mTrkpt);
608
mTrk.xMin = (mTrk.xMin < mTrkpt.lon ? mTrk.xMin : mTrkpt.lon);
609
mTrk.xMax = (mTrk.xMax > mTrkpt.lon ? mTrk.xMax : mTrkpt.lon);
610
mTrk.yMin = (mTrk.yMin < mTrkpt.lat ? mTrk.yMin : mTrkpt.lat);
611
mTrk.yMax = (mTrk.yMax > mTrkpt.lat ? mTrk.yMax : mTrkpt.lat);
613
else if (parseModes.top() == ParsingDouble) {
614
*mDouble = QString(mCharBuffer).toDouble();
617
else if (parseModes.top() == ParsingInt) {
618
*mInt = QString(mCharBuffer).toInt();
621
else if (parseModes.top() == ParsingString) {
622
*mString = mCharBuffer;