16
16
* (at your option) any later version. *
18
18
***************************************************************************/
19
/* $Id: qgsgpxprovider.cpp 5802 2006-09-10 02:08:13Z g_j_m $ */
21
21
#include <algorithm>
23
22
#include <iostream>
27
27
// Changed #include <qapp.h> to <qapplication.h>. Apparently some
28
28
// debian distros do not include the qapp.h wrapper and the compilation
29
29
// fails. [gsherman]
30
30
#include <QApplication>
33
33
#include <QTextStream>
37
#include "qgsapplication.h"
37
38
#include "qgsdataprovider.h"
38
39
#include "qgsfeature.h"
39
40
#include "qgsfield.h"
41
#include "qgsgeometry.h"
42
#include "qgscoordinatereferencesystem.h"
43
#include "qgsrectangle.h"
41
44
#include "qgsgpxprovider.h"
42
45
#include "gpsdata.h"
43
#include <qgslogger.h>
46
#define QGISEXTERN extern "C" __declspec( dllexport )
48
#define QGISEXTERN extern "C"
46
#include "qgslogger.h"
52
48
const char* QgsGPXProvider::attr[] = { "name", "elevation", "symbol", "number",
53
"comment", "description", "source",
49
"comment", "description", "source",
57
54
const QString GPX_KEY = "gpx";
59
const QString GPX_DESCRIPTION = QObject::tr("GPS eXchange format provider");
62
QgsGPXProvider::QgsGPXProvider(QString const & uri) :
63
QgsVectorDataProvider(uri),
65
mMinMaxCacheDirty(true)
56
const QString GPX_DESCRIPTION = QObject::tr( "GPS eXchange format provider" );
59
QgsGPXProvider::QgsGPXProvider( QString uri ) :
60
QgsVectorDataProvider( uri )
67
62
// assume that it won't work
70
65
// we always use UTF-8
71
mEncoding = QTextCodec::codecForName("utf8");
73
// get the filename and the type parameter from the URI
74
int fileNameEnd = uri.find('?');
75
if (fileNameEnd == -1 || uri.mid(fileNameEnd + 1, 5) != "type=") {
76
QgsLogger::warning(tr("Bad URI - you need to specify the feature type."));
66
mEncoding = QTextCodec::codecForName( "utf8" );
68
// get the file name and the type parameter from the URI
69
int fileNameEnd = uri.indexOf( '?' );
70
if ( fileNameEnd == -1 || uri.mid( fileNameEnd + 1, 5 ) != "type=" )
72
QgsLogger::warning( tr( "Bad URI - you need to specify the feature type." ) );
79
QString typeStr = uri.mid(fileNameEnd + 6);
80
mFeatureType = (typeStr == "waypoint" ? WaypointType :
81
(typeStr == "route" ? RouteType : TrackType));
75
QString typeStr = uri.mid( fileNameEnd + 6 );
76
mFeatureType = ( typeStr == "waypoint" ? WaypointType :
77
( typeStr == "route" ? RouteType : TrackType ) );
83
79
// set up the attributes and the geometry type depending on the feature type
84
attributeFields.push_back(QgsField(attr[NameAttr], "text"));
85
if (mFeatureType == WaypointType) {
87
for (int i = 0; i < 8; ++i)
88
mAllAttributes.push_back(i);
89
attributeFields.push_back(QgsField(attr[EleAttr], "text"));
90
attributeFields.push_back(QgsField(attr[SymAttr], "text"));
92
else if (mFeatureType == RouteType || mFeatureType == TrackType) {
94
for (int i = 0; i < 8; ++i)
95
mAllAttributes.push_back(i);
96
attributeFields.push_back(QgsField(attr[NumAttr], "text"));
98
attributeFields.push_back(QgsField(attr[CmtAttr], "text"));
99
attributeFields.push_back(QgsField(attr[DscAttr], "text"));
100
attributeFields.push_back(QgsField(attr[SrcAttr], "text"));
101
attributeFields.push_back(QgsField(attr[URLAttr], "text"));
102
attributeFields.push_back(QgsField(attr[URLNameAttr], "text"));
103
mFileName = uri.left(fileNameEnd);
80
attributeFields[NameAttr] = QgsField( attr[NameAttr], QVariant::String, "text" );
81
if ( mFeatureType == WaypointType )
83
attributeFields[EleAttr] = QgsField( attr[EleAttr], QVariant::Double, "double" );
84
attributeFields[SymAttr] = QgsField( attr[SymAttr], QVariant::String, "text" );
86
else if ( mFeatureType == RouteType || mFeatureType == TrackType )
88
attributeFields[NumAttr] = QgsField( attr[NumAttr], QVariant::Int, "int" );
90
attributeFields[CmtAttr] = QgsField( attr[CmtAttr], QVariant::String, "text" );
91
attributeFields[DscAttr] = QgsField( attr[DscAttr], QVariant::String, "text" );
92
attributeFields[SrcAttr] = QgsField( attr[SrcAttr], QVariant::String, "text" );
93
attributeFields[URLAttr] = QgsField( attr[URLAttr], QVariant::String, "text" );
94
attributeFields[URLNameAttr] = QgsField( attr[URLNameAttr], QVariant::String, "text" );
95
mFileName = uri.left( fileNameEnd );
105
97
// set the selection rectangle to null
106
98
mSelectionRectangle = 0;
108
// resize the cache matrix
109
mMinMaxCache=new double*[attributeFields.size()];
110
for(int i=0;i<attributeFields.size();i++) {
111
mMinMaxCache[i]=new double[2];
114
100
// parse the file
115
data = GPSData::getData(mFileName);
101
data = QgsGPSData::getData( mFileName );
124
QgsGPXProvider::~QgsGPXProvider() {
125
for(int i=0;i<fieldCount();i++) {
126
delete mMinMaxCache[i];
128
delete[] mMinMaxCache;
129
GPSData::releaseData(mFileName);
133
QString QgsGPXProvider::storageType()
135
return tr("GPS eXchange file");
139
QString QgsGPXProvider::getProjectionWKT() {
141
"GEOGCS[\"WGS 84\", "
142
" DATUM[\"WGS_1984\", "
143
" SPHEROID[\"WGS 84\",6378137,298.257223563, "
144
" AUTHORITY[\"EPSG\",7030]], "
145
" TOWGS84[0,0,0,0,0,0,0], "
146
" AUTHORITY[\"EPSG\",6326]], "
147
" PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",8901]], "
148
" UNIT[\"DMSH\",0.0174532925199433,AUTHORITY[\"EPSG\",9108]], "
149
" AXIS[\"Lat\",NORTH], "
150
" AXIS[\"Long\",EAST], "
151
" AUTHORITY[\"EPSG\",4326]]";
156
* Get the first feature resulting from a select operation
159
QgsFeature *QgsGPXProvider::getFirstFeature(bool fetchAttributes) {
161
return getNextFeature(fetchAttributes);
166
* Get the next feature resulting from a select operation
167
* Return 0 if there are no features in the selection set
170
bool QgsGPXProvider::getNextFeature(QgsFeature &feature, bool fetchAttributes){
176
* Get the next feature resulting from a select operation
177
* Return 0 if there are no features in the selection set
180
QgsFeature *QgsGPXProvider::getNextFeature(bool fetchAttributes) {
181
QgsFeature* feature = new QgsFeature(-1);
184
success = getNextFeature(feature, mAllAttributes);
186
std::list<int> emptyList;
187
success = getNextFeature(feature, emptyList);
196
QgsFeature * QgsGPXProvider::getNextFeature(std::list<int> const & attlist, int featureQueueSize) {
197
QgsFeature* feature = new QgsFeature(-1);
198
bool success = getNextFeature(feature, attlist);
206
bool QgsGPXProvider::getNextFeature(QgsFeature* feature,
207
std::list<int> const & attlist) {
111
QgsGPXProvider::~QgsGPXProvider()
113
QgsGPSData::releaseData( mFileName );
114
delete mSelectionRectangle;
118
QString QgsGPXProvider::storageType() const
120
return tr( "GPS eXchange file" );
123
int QgsGPXProvider::capabilities() const
125
return QgsVectorDataProvider::AddFeatures |
126
QgsVectorDataProvider::DeleteFeatures |
127
QgsVectorDataProvider::ChangeAttributeValues;
130
bool QgsGPXProvider::nextFeature( QgsFeature& feature )
132
feature.setValid( false );
208
133
bool result = false;
210
std::list<int>::const_iterator iter;
212
if (mFeatureType == WaypointType) {
135
QgsAttributeList::const_iterator iter;
137
if ( mFeatureType == WaypointType )
213
139
// go through the list of waypoints and return the first one that is in
214
140
// the bounds rectangle
215
for (; mWptIter != data->waypointsEnd(); ++mWptIter) {
218
if (boundsCheck(wpt->lon, wpt->lat)) {
219
feature->setFeatureId(wpt->id);
223
char* geo = new char[21];
224
std::memset(geo, 0, 21);
226
geo[geo[0] == NDR ? 1 : 4] = QGis::WKBPoint;
227
std::memcpy(geo+5, &wpt->lon, sizeof(double));
228
std::memcpy(geo+13, &wpt->lat, sizeof(double));
229
feature->setGeometryAndOwnership((unsigned char *)geo, sizeof(wkbPoint));
230
feature->setValid(true);
232
// add attributes if they are wanted
233
for (iter = attlist.begin(); iter != attlist.end(); ++iter) {
236
feature->addAttribute(attr[NameAttr], wpt->name);
239
if (wpt->ele == -std::numeric_limits<double>::max())
240
feature->addAttribute(attr[EleAttr], "");
242
feature->addAttribute(attr[EleAttr], QString("%1").arg(wpt->ele));
245
feature->addAttribute(attr[SymAttr], wpt->sym);
248
feature->addAttribute(attr[CmtAttr], wpt->cmt);
251
feature->addAttribute(attr[DscAttr], wpt->desc);
254
feature->addAttribute(attr[SrcAttr], wpt->src);
257
feature->addAttribute(attr[URLAttr], wpt->url);
260
feature->addAttribute(attr[URLNameAttr], wpt->urlname);
141
for ( ; mWptIter != data->waypointsEnd(); ++mWptIter )
143
const QgsWaypoint* wpt;
144
wpt = &( *mWptIter );
145
if ( boundsCheck( wpt->lon, wpt->lat ) )
147
feature.setFeatureId( wpt->id );
153
char* geo = new char[21];
154
std::memset( geo, 0, 21 );
155
geo[0] = QgsApplication::endian();
156
geo[geo[0] == QgsApplication::NDR ? 1 : 4] = QGis::WKBPoint;
157
std::memcpy( geo + 5, &wpt->lon, sizeof( double ) );
158
std::memcpy( geo + 13, &wpt->lat, sizeof( double ) );
159
feature.setGeometryAndOwnership(( unsigned char * )geo, sizeof( wkbPoint ) );
161
feature.setValid( true );
163
// add attributes if they are wanted
164
for ( iter = mAttributesToFetch.begin(); iter != mAttributesToFetch.end(); ++iter )
169
feature.addAttribute( NameAttr, QVariant( wpt->name ) );
172
if ( wpt->ele != -std::numeric_limits<double>::max() )
173
feature.addAttribute( EleAttr, QVariant( wpt->ele ) );
176
feature.addAttribute( SymAttr, QVariant( wpt->sym ) );
179
feature.addAttribute( CmtAttr, QVariant( wpt->cmt ) );
182
feature.addAttribute( DscAttr, QVariant( wpt->desc ) );
185
feature.addAttribute( SrcAttr, QVariant( wpt->src ) );
188
feature.addAttribute( URLAttr, QVariant( wpt->url ) );
191
feature.addAttribute( URLNameAttr, QVariant( wpt->urlname ) );
271
else if (mFeatureType == RouteType) {
202
else if ( mFeatureType == RouteType )
272
204
// go through the routes and return the first one that is in the bounds
274
for (; mRteIter != data->routesEnd(); ++mRteIter) {
278
if (rte->points.size() == 0)
280
const QgsRect& b(*mSelectionRectangle);
281
if ((rte->xMax >= b.xMin()) && (rte->xMin <= b.xMax()) &&
282
(rte->yMax >= b.yMin()) && (rte->yMin <= b.yMax())) {
283
feature->setFeatureId(rte->id);
287
int nPoints = rte->points.size();
288
char* geo = new char[9 + 16 * nPoints];
289
std::memset(geo, 0, 9 + 16 * nPoints);
291
geo[geo[0] == NDR ? 1 : 4] = QGis::WKBLineString;
292
std::memcpy(geo + 5, &nPoints, 4);
293
for (int i = 0; i < rte->points.size(); ++i) {
294
std::memcpy(geo + 9 + 16 * i, &rte->points[i].lon, sizeof(double));
295
std::memcpy(geo + 9 + 16 * i + 8, &rte->points[i].lat, sizeof(double));
297
feature->setGeometryAndOwnership((unsigned char *)geo, 9 + 16 * nPoints);
298
feature->setValid(true);
300
// add attributes if they are wanted
301
for (iter = attlist.begin(); iter != attlist.end(); ++iter) {
303
feature->addAttribute(attr[NameAttr], rte->name);
304
else if (*iter == 1) {
305
if (rte->number == std::numeric_limits<int>::max())
306
feature->addAttribute(attr[NumAttr], "");
308
feature->addAttribute(attr[NumAttr], QString("%1").arg(rte->number));
311
feature->addAttribute(attr[CmtAttr], rte->cmt);
313
feature->addAttribute(attr[DscAttr], rte->desc);
315
feature->addAttribute(attr[SrcAttr], rte->src);
317
feature->addAttribute(attr[URLAttr], rte->url);
319
feature->addAttribute(attr[URLNameAttr], rte->urlname);
206
for ( ; mRteIter != data->routesEnd(); ++mRteIter )
209
rte = &( *mRteIter );
211
if ( rte->points.size() == 0 )
213
const QgsRectangle& b( *mSelectionRectangle );
214
if (( rte->xMax >= b.xMinimum() ) && ( rte->xMin <= b.xMaximum() ) &&
215
( rte->yMax >= b.yMinimum() ) && ( rte->yMin <= b.yMaximum() ) )
218
int nPoints = rte->points.size();
219
char* geo = new char[9 + 16 * nPoints];
220
std::memset( geo, 0, 9 + 16 * nPoints );
221
geo[0] = QgsApplication::endian();
222
geo[geo[0] == QgsApplication::NDR ? 1 : 4] = QGis::WKBLineString;
223
std::memcpy( geo + 5, &nPoints, 4 );
224
for ( uint i = 0; i < rte->points.size(); ++i )
226
std::memcpy( geo + 9 + 16 * i, &rte->points[i].lon, sizeof( double ) );
227
std::memcpy( geo + 9 + 16 * i + 8, &rte->points[i].lat, sizeof( double ) );
230
//create QgsGeometry and use it for intersection test
231
//if geometry is to be fetched, it is attached to the feature, otherwise we delete it
232
QgsGeometry* theGeometry = new QgsGeometry();
233
theGeometry->fromWkb(( unsigned char * )geo, 9 + 16 * nPoints );
234
bool intersection = theGeometry->intersects( b );//use geos for precise intersection test
244
feature.setGeometry( theGeometry );
250
feature.setFeatureId( rte->id );
252
feature.setValid( true );
254
// add attributes if they are wanted
255
for ( iter = mAttributesToFetch.begin(); iter != mAttributesToFetch.end(); ++iter )
260
feature.addAttribute( NameAttr, QVariant( rte->name ) );
263
if ( rte->number != std::numeric_limits<int>::max() )
264
feature.addAttribute( NumAttr, QVariant( rte->number ) );
267
feature.addAttribute( CmtAttr, QVariant( rte->cmt ) );
270
feature.addAttribute( DscAttr, QVariant( rte->desc ) );
273
feature.addAttribute( SrcAttr, QVariant( rte->src ) );
276
feature.addAttribute( URLAttr, QVariant( rte->url ) );
279
feature.addAttribute( URLNameAttr, QVariant( rte->urlname ) );
328
else if (mFeatureType == TrackType) {
295
else if ( mFeatureType == TrackType )
329
297
// go through the tracks and return the first one that is in the bounds
331
for (; mTrkIter != data->tracksEnd(); ++mTrkIter) {
335
if (trk->segments.size() == 0)
337
if (trk->segments[0].points.size() == 0)
339
const QgsRect& b(*mSelectionRectangle);
340
if ((trk->xMax >= b.xMin()) && (trk->xMin <= b.xMax()) &&
341
(trk->yMax >= b.yMin()) && (trk->yMin <= b.yMax())) {
342
feature->setFeatureId(trk->id);
346
int nPoints = trk->segments[0].points.size();
347
char* geo = new char[9 + 16 * nPoints];
348
std::memset(geo, 0, 9 + 16 * nPoints);
350
geo[geo[0] == NDR ? 1 : 4] = QGis::WKBLineString;
351
std::memcpy(geo + 5, &nPoints, 4);
352
for (int i = 0; i < nPoints; ++i) {
353
std::memcpy(geo + 9 + 16 * i, &trk->segments[0].points[i].lon, sizeof(double));
354
std::memcpy(geo + 9 + 16 * i + 8, &trk->segments[0].points[i].lat, sizeof(double));
356
feature->setGeometryAndOwnership((unsigned char *)geo, 9 + 16 * nPoints);
357
feature->setValid(true);
359
// add attributes if they are wanted
360
for (iter = attlist.begin(); iter != attlist.end(); ++iter) {
362
feature->addAttribute(attr[NameAttr], trk->name);
363
else if (*iter == 1) {
364
if (trk->number == std::numeric_limits<int>::max())
365
feature->addAttribute(attr[NumAttr], "");
367
feature->addAttribute(attr[NumAttr], QString("%1").arg(trk->number));
370
feature->addAttribute(attr[CmtAttr], trk->cmt);
372
feature->addAttribute(attr[DscAttr], trk->desc);
374
feature->addAttribute(attr[SrcAttr], trk->src);
376
feature->addAttribute(attr[URLAttr], trk->url);
378
feature->addAttribute(attr[URLNameAttr], trk->urlname);
299
for ( ; mTrkIter != data->tracksEnd(); ++mTrkIter )
302
trk = &( *mTrkIter );
304
QgsDebugMsg( QString( "GPX feature track segments: %1" ).arg( trk->segments.size() ) );
305
if ( trk->segments.size() == 0 )
308
// A track consists of several segments. Add all those segments into one.
309
int totalPoints = 0;;
310
for ( std::vector<QgsTrackSegment>::size_type i = 0; i < trk->segments.size(); i ++ )
312
totalPoints += trk->segments[i].points.size();
314
if ( totalPoints == 0 )
316
QgsDebugMsg( "GPX feature track total points: " + QString::number( totalPoints ) );
317
const QgsRectangle& b( *mSelectionRectangle );
318
if (( trk->xMax >= b.xMinimum() ) && ( trk->xMin <= b.xMaximum() ) &&
319
( trk->yMax >= b.yMinimum() ) && ( trk->yMin <= b.yMaximum() ) )
322
char* geo = new char[9 + 16 * totalPoints];
325
QgsDebugMsg( "Too large track!!!" );
328
std::memset( geo, 0, 9 + 16 * totalPoints );
329
geo[0] = QgsApplication::endian();
330
geo[geo[0] == QgsApplication::NDR ? 1 : 4] = QGis::WKBLineString;
331
std::memcpy( geo + 5, &totalPoints, 4 );
334
for ( std::vector<QgsTrackSegment>::size_type k = 0; k < trk->segments.size(); k++ )
336
int nPoints = trk->segments[k].points.size();
337
for ( int i = 0; i < nPoints; ++i )
339
std::memcpy( geo + 9 + 16 * thisPoint, &trk->segments[k].points[i].lon, sizeof( double ) );
340
std::memcpy( geo + 9 + 16 * thisPoint + 8, &trk->segments[k].points[i].lat, sizeof( double ) );
345
//create QgsGeometry and use it for intersection test
346
//if geometry is to be fetched, it is attached to the feature, otherwise we delete it
347
QgsGeometry* theGeometry = new QgsGeometry();
348
theGeometry->fromWkb(( unsigned char * )geo, 9 + 16 * totalPoints );
349
bool intersection = theGeometry->intersects( b );//use geos for precise intersection test
351
if ( !intersection ) //no intersection, delete geometry and move on
359
feature.setGeometry( theGeometry );
365
feature.setFeatureId( trk->id );
368
feature.setValid( true );
370
// add attributes if they are wanted
371
for ( iter = mAttributesToFetch.begin(); iter != mAttributesToFetch.end(); ++iter )
376
feature.addAttribute( NameAttr, QVariant( trk->name ) );
379
if ( trk->number != std::numeric_limits<int>::max() )
380
feature.addAttribute( NumAttr, QVariant( trk->number ) );
383
feature.addAttribute( CmtAttr, QVariant( trk->cmt ) );
386
feature.addAttribute( DscAttr, QVariant( trk->desc ) );
389
feature.addAttribute( SrcAttr, QVariant( trk->src ) );
392
feature.addAttribute( URLAttr, QVariant( trk->url ) );
395
feature.addAttribute( URLNameAttr, QVariant( trk->urlname ) );
409
feature.setValid( true );
391
* Select features based on a bounding rectangle. Features can be retrieved
392
* with calls to getFirstFeature and getNextFeature.
393
* @param mbr QgsRect containing the extent to use in selecting features
395
void QgsGPXProvider::select(QgsRect *rect, bool useIntersect) {
397
// Setting a spatial filter doesn't make much sense since we have to
398
// compare each point against the rectangle.
399
// We store the rect and use it in getNextFeature to determine if the
400
// feature falls in the selection area
401
mSelectionRectangle = new QgsRect(*rect);
402
// Select implies an upcoming feature read so we reset the data source
408
* Identify features within the search radius specified by rect
409
* @param rect Bounding rectangle of search radius
410
* @return std::vector containing QgsFeature objects that intersect rect
412
std::vector<QgsFeature>& QgsGPXProvider::identify(QgsRect * rect) {
413
// reset the data source since we need to be able to read through
416
QgsLogger::debug("Attempting to identify features falling within " +
418
// select the features
420
// temporary fix to get this to compile under windows
421
// XXX What the heck is going on here?
422
static std::vector<QgsFeature> features;
428
unsigned char * QgsGPXProvider::getGeometryPointer(OGRFeature *fet){
429
unsigned char *gPtr=0;
430
// get the wkb representation
432
//geom->exportToWkb((OGRwkbByteOrder) endian(), gPtr);
414
void QgsGPXProvider::select( QgsAttributeList fetchAttributes,
419
delete mSelectionRectangle;
420
mSelectionRectangle = 0;
422
if ( rect.isEmpty() )
424
mSelectionRectangle = new QgsRectangle( extent() );
428
mSelectionRectangle = new QgsRectangle( rect );
430
mAttributesToFetch = fetchAttributes;
431
mFetchGeom = fetchGeometry;
440
438
// Return the extent of the layer
441
QgsRect *QgsGPXProvider::extent() {
439
QgsRectangle QgsGPXProvider::extent()
442
441
return data->getExtent();
447
446
* Return the feature type
449
int QgsGPXProvider::geometryType() const
448
QGis::WkbType QgsGPXProvider::geometryType() const
450
if ( mFeatureType == WaypointType )
451
return QGis::WKBPoint;
453
if ( mFeatureType == RouteType || mFeatureType == TrackType )
454
return QGis::WKBLineString;
456
return QGis::WKBUnknown;
456
461
* Return the feature type
458
463
long QgsGPXProvider::featureCount() const
460
if (mFeatureType == WaypointType)
465
if ( mFeatureType == WaypointType )
461
466
return data->getNumberOfWaypoints();
462
if (mFeatureType == RouteType)
467
if ( mFeatureType == RouteType )
463
468
return data->getNumberOfRoutes();
464
if (mFeatureType == TrackType)
469
if ( mFeatureType == TrackType )
465
470
return data->getNumberOfTracks();
471
476
* Return the number of fields
473
int QgsGPXProvider::fieldCount() const
478
uint QgsGPXProvider::fieldCount() const
475
480
return attributeFields.size();
479
std::vector<QgsField> const & QgsGPXProvider::fields() const
484
const QgsFieldMap& QgsGPXProvider::fields() const
481
486
return attributeFields;
485
void QgsGPXProvider::reset() {
486
if (mFeatureType == WaypointType)
490
void QgsGPXProvider::rewind()
492
if ( mFeatureType == WaypointType )
487
493
mWptIter = data->waypointsBegin();
488
else if (mFeatureType == RouteType)
494
else if ( mFeatureType == RouteType )
489
495
mRteIter = data->routesBegin();
490
else if (mFeatureType == TrackType)
496
else if ( mFeatureType == TrackType )
491
497
mTrkIter = data->tracksBegin();
495
QString QgsGPXProvider::minValue(int position) {
496
if (position >= fieldCount()) {
497
QgsLogger::warning(tr("Warning: access requested to invalid position "
498
"in QgsGPXProvider::minValue(..)"));
500
if (mMinMaxCacheDirty) {
503
return QString::number(mMinMaxCache[position][0],'f',2);
507
QString QgsGPXProvider::maxValue(int position) {
508
if (position >= fieldCount()) {
509
QgsLogger::warning(tr("Warning: access requested to invalid position "
510
"in QgsGPXProvider::maxValue(..)"));
512
if (mMinMaxCacheDirty) {
515
return QString::number(mMinMaxCache[position][1],'f',2);
519
void QgsGPXProvider::fillMinMaxCash() {
520
for(int i=0;i<fieldCount();i++) {
521
mMinMaxCache[i][0]=DBL_MAX;
522
mMinMaxCache[i][1]=-DBL_MAX;
528
getNextFeature(f, true);
530
for(int i=0;i<fieldCount();i++) {
531
double value=(f.attributeMap())[i].fieldValue().toDouble();
532
if(value<mMinMaxCache[i][0]) {
533
mMinMaxCache[i][0]=value;
535
if(value>mMinMaxCache[i][1]) {
536
mMinMaxCache[i][1]=value;
539
} while(getNextFeature(f, true));
541
mMinMaxCacheDirty=false;
546
bool QgsGPXProvider::isValid(){
501
bool QgsGPXProvider::isValid()
551
bool QgsGPXProvider::addFeatures(std::list<QgsFeature*> flist) {
507
bool QgsGPXProvider::addFeatures( QgsFeatureList & flist )
553
510
// add all the features
554
for (std::list<QgsFeature*>::const_iterator iter = flist.begin();
555
iter != flist.end(); ++iter) {
556
if (!addFeature(*iter))
511
for ( QgsFeatureList::iterator iter = flist.begin();
512
iter != flist.end(); ++iter )
514
if ( !addFeature( *iter ) )
560
518
// write back to file
561
QFile file(mFileName);
562
if (!file.open(QIODevice::WriteOnly))
519
QFile file( mFileName );
520
if ( !file.open( QIODevice::WriteOnly ) )
564
QTextStream ostr(&file);
565
data->writeXML(ostr);
522
QTextStream ostr( &file );
523
data->writeXML( ostr );
570
bool QgsGPXProvider::addFeature(QgsFeature* f) {
571
unsigned char* geo = f->getGeometry();
528
bool QgsGPXProvider::addFeature( QgsFeature& f )
530
unsigned char* geo = f.geometry()->asWkb();
531
QGis::WkbType wkbType = f.geometry()->wkbType();
572
532
bool success = false;
573
GPSObject* obj = NULL;
574
const std::vector<QgsFeatureAttribute>& attrs(f->attributeMap());
533
QgsGPSObject* obj = NULL;
534
const QgsAttributeMap& attrs( f.attributeMap() );
535
QgsAttributeMap::const_iterator it;
576
537
// is it a waypoint?
577
if (mFeatureType == WaypointType && geo != NULL && geo[geo[0] == NDR ? 1 : 4] == QGis::WKBPoint) {
538
if ( mFeatureType == WaypointType && geo != NULL && wkbType == QGis::WKBPoint )
581
std::memcpy(&wpt.lon, geo+5, sizeof(double));
582
std::memcpy(&wpt.lat, geo+13, sizeof(double));
543
std::memcpy( &wpt.lon, geo + 5, sizeof( double ) );
544
std::memcpy( &wpt.lat, geo + 13, sizeof( double ) );
584
546
// add waypoint-specific attributes
585
for (int i = 0; i < attrs.size(); ++i) {
586
if (attrs[i].fieldName() == attr[EleAttr]) {
588
double ele = attrs[i].fieldValue().toDouble(&eleIsOK);
547
for ( it = attrs.begin(); it != attrs.end(); ++it )
549
if ( it.key() == EleAttr )
552
double ele = it->toDouble( &eleIsOK );
592
else if (attrs[i].fieldName() == attr[SymAttr]) {
593
wpt.sym = attrs[i].fieldValue();
556
else if ( it.key() == SymAttr )
558
wpt.sym = it->toString();
597
GPSData::WaypointIterator iter = data->addWaypoint(wpt);
562
QgsGPSData::WaypointIterator iter = data->addWaypoint( wpt );
602
567
// is it a route?
603
if (mFeatureType == RouteType && geo != NULL && geo[geo[0] == NDR ? 1 : 4] == QGis::WKBLineString) {
568
if ( mFeatureType == RouteType && geo != NULL && wkbType == QGis::WKBLineString )
608
574
rte.xMin = std::numeric_limits<double>::max();
609
575
rte.xMax = -std::numeric_limits<double>::max();
659
std::memcpy(&nPoints, geo + 5, 4);
660
for (int i = 0; i < nPoints; ++i) {
629
std::memcpy( &nPoints, geo + 5, 4 );
630
for ( int i = 0; i < nPoints; ++i )
662
std::memcpy(&lon, geo + 9 + 16 * i, sizeof(double));
663
std::memcpy(&lat, geo + 9 + 16 * i + 8, sizeof(double));
633
std::memcpy( &lon, geo + 9 + 16 * i, sizeof( double ) );
634
std::memcpy( &lat, geo + 9 + 16 * i + 8, sizeof( double ) );
667
trkseg.points.push_back(trkpt);
638
trkseg.points.push_back( trkpt );
668
639
trk.xMin = trk.xMin < lon ? trk.xMin : lon;
669
640
trk.xMax = trk.xMax > lon ? trk.xMax : lon;
670
641
trk.yMin = trk.yMin < lat ? trk.yMin : lat;
671
642
trk.yMax = trk.yMax > lat ? trk.yMax : lat;
674
645
// add track-specific attributes
675
for (int i = 0; i < attrs.size(); ++i) {
676
if (attrs[i].fieldName() == attr[NumAttr]) {
678
long num = attrs[i].fieldValue().toLong(&numIsOK);
646
for ( it = attrs.begin(); it != attrs.end(); ++it )
648
if ( it.key() == NumAttr )
651
long num = it->toInt( &numIsOK );
684
trk.segments.push_back(trkseg);
685
GPSData::TrackIterator iter = data->addTrack(trk);
657
trk.segments.push_back( trkseg );
658
QgsGPSData::TrackIterator iter = data->addTrack( trk );
691
664
// add common attributes
693
for (int i = 0; i < attrs.size(); ++i) {
694
if (attrs[i].fieldName() == attr[NameAttr]) {
695
obj->name = attrs[i].fieldValue();
697
else if (attrs[i].fieldName() == attr[CmtAttr]) {
698
obj->cmt = attrs[i].fieldValue();
700
else if (attrs[i].fieldName() == attr[DscAttr]) {
701
obj->desc = attrs[i].fieldValue();
703
else if (attrs[i].fieldName() == attr[SrcAttr]) {
704
obj->src = attrs[i].fieldValue();
706
else if (attrs[i].fieldName() == attr[URLAttr]) {
707
obj->url = attrs[i].fieldValue();
709
else if (attrs[i].fieldName() == attr[URLNameAttr]) {
710
obj->urlname = attrs[i].fieldValue();
667
for ( it = attrs.begin(); it != attrs.end(); ++it )
669
if ( it.key() == NameAttr )
671
obj->name = it->toString();
673
else if ( it.key() == CmtAttr )
675
obj->cmt = it->toString();
677
else if ( it.key() == DscAttr )
679
obj->desc = it->toString();
681
else if ( it.key() == SrcAttr )
683
obj->src = it->toString();
685
else if ( it.key() == URLAttr )
687
obj->url = it->toString();
689
else if ( it.key() == URLNameAttr )
691
obj->urlname = it->toString();
719
bool QgsGPXProvider::deleteFeatures(std::list<int> const & id) {
720
if (mFeatureType == WaypointType)
721
data->removeWaypoints(id);
722
else if (mFeatureType == RouteType)
723
data->removeRoutes(id);
724
else if (mFeatureType == TrackType)
725
data->removeTracks(id);
727
// write back to file
728
QFile file(mFileName);
729
if (!file.open(QIODevice::WriteOnly))
731
QTextStream ostr(&file);
732
data->writeXML(ostr);
737
bool QgsGPXProvider::changeAttributeValues(std::map<int,std::map<QString,QString> > const& attr_map) {
738
std::map<int, std::map<QString, QString> >::const_iterator aIter =
740
if (mFeatureType == WaypointType) {
741
GPSData::WaypointIterator wIter = data->waypointsBegin();
742
for (; wIter != data->waypointsEnd() && aIter != attr_map.end(); ++wIter) {
743
if (wIter->id == aIter->first) {
744
changeAttributeValues(*wIter, aIter->second);
749
else if (mFeatureType == RouteType) {
750
GPSData::RouteIterator rIter = data->routesBegin();
751
for (; rIter != data->routesEnd() && aIter != attr_map.end(); ++rIter) {
752
if (rIter->id == aIter->first) {
753
changeAttributeValues(*rIter, aIter->second);
758
if (mFeatureType == TrackType) {
759
GPSData::TrackIterator tIter = data->tracksBegin();
760
for (; tIter != data->tracksEnd() && aIter != attr_map.end(); ++tIter) {
761
if (tIter->id == aIter->first) {
762
changeAttributeValues(*tIter, aIter->second);
768
// write back to file
769
QFile file(mFileName);
770
if (!file.open(QIODevice::WriteOnly))
772
QTextStream ostr(&file);
773
data->writeXML(ostr);
778
void QgsGPXProvider::changeAttributeValues(GPSObject& obj,
779
const std::map<QString, QString>& attrs) {
780
std::map<QString, QString>::const_iterator aIter;
783
if ((aIter = attrs.find(attr[NameAttr])) != attrs.end())
784
obj.name = aIter->second;
785
if ((aIter = attrs.find(attr[CmtAttr])) != attrs.end())
786
obj.cmt = aIter->second;
787
if ((aIter = attrs.find(attr[DscAttr])) != attrs.end())
788
obj.desc = aIter->second;
789
if ((aIter = attrs.find(attr[SrcAttr])) != attrs.end())
790
obj.src = aIter->second;
791
if ((aIter = attrs.find(attr[URLAttr])) != attrs.end())
792
obj.url = aIter->second;
793
if ((aIter = attrs.find(attr[URLNameAttr])) != attrs.end())
794
obj.urlname = aIter->second;
700
bool QgsGPXProvider::deleteFeatures( const QgsFeatureIds & id )
702
if ( mFeatureType == WaypointType )
703
data->removeWaypoints( id );
704
else if ( mFeatureType == RouteType )
705
data->removeRoutes( id );
706
else if ( mFeatureType == TrackType )
707
data->removeTracks( id );
709
// write back to file
710
QFile file( mFileName );
711
if ( !file.open( QIODevice::WriteOnly ) )
713
QTextStream ostr( &file );
714
data->writeXML( ostr );
719
bool QgsGPXProvider::changeAttributeValues( const QgsChangedAttributesMap & attr_map )
721
QgsChangedAttributesMap::const_iterator aIter = attr_map.begin();
722
if ( mFeatureType == WaypointType )
724
QgsGPSData::WaypointIterator wIter = data->waypointsBegin();
725
for ( ; wIter != data->waypointsEnd() && aIter != attr_map.end(); ++wIter )
727
if ( wIter->id == aIter.key() )
729
changeAttributeValues( *wIter, aIter.value() );
734
else if ( mFeatureType == RouteType )
736
QgsGPSData::RouteIterator rIter = data->routesBegin();
737
for ( ; rIter != data->routesEnd() && aIter != attr_map.end(); ++rIter )
739
if ( rIter->id == aIter.key() )
741
changeAttributeValues( *rIter, aIter.value() );
746
if ( mFeatureType == TrackType )
748
QgsGPSData::TrackIterator tIter = data->tracksBegin();
749
for ( ; tIter != data->tracksEnd() && aIter != attr_map.end(); ++tIter )
751
if ( tIter->id == aIter.key() )
753
changeAttributeValues( *tIter, aIter.value() );
759
// write back to file
760
QFile file( mFileName );
761
if ( !file.open( QIODevice::WriteOnly ) )
763
QTextStream ostr( &file );
764
data->writeXML( ostr );
769
void QgsGPXProvider::changeAttributeValues( QgsGPSObject& obj, const QgsAttributeMap& attrs )
771
QgsAttributeMap::const_iterator aIter;
774
if ( attrs.contains( NameAttr ) )
775
obj.name = attrs[NameAttr].toString();
776
if ( attrs.contains( CmtAttr ) )
777
obj.cmt = attrs[CmtAttr].toString();
778
if ( attrs.contains( DscAttr ) )
779
obj.desc = attrs[DscAttr].toString();
780
if ( attrs.contains( SrcAttr ) )
781
obj.src = attrs[SrcAttr].toString();
782
if ( attrs.contains( URLAttr ) )
783
obj.url = attrs[URLAttr].toString();
784
if ( attrs.contains( URLNameAttr ) )
785
obj.urlname = attrs[URLNameAttr].toString();
796
787
// waypoint-specific attributes
797
Waypoint* wpt = dynamic_cast<Waypoint*>(&obj);
799
if ((aIter = attrs.find(attr[SymAttr])) != attrs.end())
800
wpt->sym = aIter->second;
801
if ((aIter = attrs.find(attr[EleAttr])) != attrs.end()) {
788
QgsWaypoint* wpt = dynamic_cast<QgsWaypoint*>( &obj );
791
if ( attrs.contains( SymAttr ) )
792
wpt->sym = attrs[SymAttr].toString();
793
if ( attrs.contains( EleAttr ) )
803
double ele = aIter->second.toDouble(&eleIsOK);
796
double ele = attrs[EleAttr].toDouble( &eleIsOK );
809
802
// route- and track-specific attributes
810
GPSExtended* ext = dynamic_cast<GPSExtended*>(&obj);
812
if ((aIter = attrs.find(attr[NumAttr])) != attrs.end()) {
803
QgsGPSExtended* ext = dynamic_cast<QgsGPSExtended*>( &obj );
806
if ( attrs.contains( NumAttr ) )
814
int number = aIter->second.toInt(&eleIsOK);
816
ext->number = number;
809
double ele = attrs[NumAttr].toDouble( &eleIsOK );
822
size_t QgsGPXProvider::layerCount() const
817
QVariant QgsGPXProvider::defaultValue( int fieldId )
824
return 1; // XXX need to calculate actual number of layers
825
} // QgsGPXProvider::layerCount()
829
QString QgsGPXProvider::getDefaultValue(const QString& attr, QgsFeature* f) {
830
if (attr == "source")
831
return tr("Digitized in QGIS");
819
if ( fieldId == SrcAttr )
820
return tr( "Digitized in QGIS" );
837
826
* Check to see if the point is within the selection rectangle
839
bool QgsGPXProvider::boundsCheck(double x, double y)
828
bool QgsGPXProvider::boundsCheck( double x, double y )
841
bool inBounds = (((x <= mSelectionRectangle->xMax()) &&
842
(x >= mSelectionRectangle->xMin())) &&
843
((y <= mSelectionRectangle->yMax()) &&
844
(y >= mSelectionRectangle->yMin())));
845
QString hit = inBounds?"true":"false";
830
bool inBounds = ((( x <= mSelectionRectangle->xMaximum() ) &&
831
( x >= mSelectionRectangle->xMinimum() ) ) &&
832
(( y <= mSelectionRectangle->yMaximum() ) &&
833
( y >= mSelectionRectangle->yMinimum() ) ) );
834
QString hit = inBounds ? "true" : "false";
850
839
QString QgsGPXProvider::name() const
853
842
} // QgsGPXProvider::name()
857
846
QString QgsGPXProvider::description() const
859
return GPX_DESCRIPTION;
848
return GPX_DESCRIPTION;
860
849
} // QgsGPXProvider::description()
851
QgsCoordinateReferenceSystem QgsGPXProvider::crs()
853
return QgsCoordinateReferenceSystem(); // use default CRS - it's WGS84