~ubuntu-branches/ubuntu/wily/qgis/wily

« back to all changes in this revision

Viewing changes to src/providers/gpx/qgsgpxprovider.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Johan Van de Wauw
  • Date: 2010-07-11 20:23:24 UTC
  • mfrom: (3.1.4 squeeze)
  • Revision ID: james.westby@ubuntu.com-20100711202324-5ktghxa7hracohmr
Tags: 1.4.0+12730-3ubuntu1
* Merge from Debian unstable (LP: #540941).
* Fix compilation issues with QT 4.7
* Add build-depends on libqt4-webkit-dev 

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 *   (at your option) any later version.                                   *
17
17
 *                                                                         *
18
18
 ***************************************************************************/
19
 
/* $Id: qgsgpxprovider.cpp 5802 2006-09-10 02:08:13Z g_j_m $ */
 
19
/* $Id$ */
20
20
 
21
21
#include <algorithm>
22
 
#include <cfloat>
23
22
#include <iostream>
24
23
#include <limits>
 
24
#include <cstring>
25
25
#include <cmath>
26
26
 
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>
31
 
 
32
31
#include <QFile>
 
32
#include <QTextCodec>
33
33
#include <QTextStream>
34
34
#include <QObject>
35
35
 
36
36
#include "qgis.h"
 
37
#include "qgsapplication.h"
37
38
#include "qgsdataprovider.h"
38
39
#include "qgsfeature.h"
39
40
#include "qgsfield.h"
40
 
#include "qgsrect.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>
44
 
 
45
 
#ifdef WIN32
46
 
#define QGISEXTERN extern "C" __declspec( dllexport )
47
 
#else
48
 
#define QGISEXTERN extern "C"
49
 
#endif
50
 
 
 
46
#include "qgslogger.h"
51
47
 
52
48
const char* QgsGPXProvider::attr[] = { "name", "elevation", "symbol", "number",
53
 
                                       "comment", "description", "source", 
54
 
                                       "url", "url name" };
 
49
                                       "comment", "description", "source",
 
50
                                       "url", "url name"
 
51
                                     };
55
52
 
56
53
 
57
54
const QString GPX_KEY = "gpx";
58
55
 
59
 
const QString GPX_DESCRIPTION = QObject::tr("GPS eXchange format provider");
60
 
 
61
 
 
62
 
QgsGPXProvider::QgsGPXProvider(QString const & uri) : 
63
 
        QgsVectorDataProvider(uri),
64
 
        mEditable(false),
65
 
        mMinMaxCacheDirty(true)
 
56
const QString GPX_DESCRIPTION = QObject::tr( "GPS eXchange format provider" );
 
57
 
 
58
 
 
59
QgsGPXProvider::QgsGPXProvider( QString uri ) :
 
60
    QgsVectorDataProvider( uri )
66
61
{
67
62
  // assume that it won't work
68
63
  mValid = false;
69
 
  
 
64
 
70
65
  // we always use UTF-8
71
 
  mEncoding = QTextCodec::codecForName("utf8");
72
 
  
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" );
 
67
 
 
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=" )
 
71
  {
 
72
    QgsLogger::warning( tr( "Bad URI - you need to specify the feature type." ) );
77
73
    return;
78
74
  }
79
 
  QString typeStr = uri.mid(fileNameEnd + 6);
80
 
  mFeatureType = (typeStr == "waypoint" ? WaypointType :
81
 
                  (typeStr == "route" ? RouteType : TrackType));
82
 
  
 
75
  QString typeStr = uri.mid( fileNameEnd + 6 );
 
76
  mFeatureType = ( typeStr == "waypoint" ? WaypointType :
 
77
                   ( typeStr == "route" ? RouteType : TrackType ) );
 
78
 
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) {
86
 
    mGeomType = 1;
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"));
91
 
  }
92
 
  else if (mFeatureType == RouteType || mFeatureType == TrackType) {
93
 
    mGeomType = 2;
94
 
    for (int i = 0; i < 8; ++i)
95
 
      mAllAttributes.push_back(i);
96
 
    attributeFields.push_back(QgsField(attr[NumAttr], "text"));
97
 
  }
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 )
 
82
  {
 
83
    attributeFields[EleAttr] = QgsField( attr[EleAttr], QVariant::Double, "double" );
 
84
    attributeFields[SymAttr] = QgsField( attr[SymAttr], QVariant::String, "text" );
 
85
  }
 
86
  else if ( mFeatureType == RouteType || mFeatureType == TrackType )
 
87
  {
 
88
    attributeFields[NumAttr] = QgsField( attr[NumAttr], QVariant::Int, "int" );
 
89
  }
 
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 );
104
96
 
105
97
  // set the selection rectangle to null
106
98
  mSelectionRectangle = 0;
107
 
  
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];
112
 
  }
113
99
 
114
100
  // parse the file
115
 
  data = GPSData::getData(mFileName);
116
 
  if (data == 0) {
 
101
  data = QgsGPSData::getData( mFileName );
 
102
  if ( data == 0 )
 
103
  {
117
104
    return;
118
105
  }
119
106
 
121
108
}
122
109
 
123
110
 
124
 
QgsGPXProvider::~QgsGPXProvider() {
125
 
  for(int i=0;i<fieldCount();i++) {
126
 
    delete mMinMaxCache[i];
127
 
  }
128
 
  delete[] mMinMaxCache;
129
 
  GPSData::releaseData(mFileName);
130
 
}
131
 
 
132
 
 
133
 
QString QgsGPXProvider::storageType()
134
 
{
135
 
  return tr("GPS eXchange file");
136
 
}
137
 
 
138
 
 
139
 
QString QgsGPXProvider::getProjectionWKT() {
140
 
  return 
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]]";
152
 
}
153
 
 
154
 
 
155
 
/**
156
 
 * Get the first feature resulting from a select operation
157
 
 * @return QgsFeature
158
 
 */
159
 
QgsFeature *QgsGPXProvider::getFirstFeature(bool fetchAttributes) {
160
 
  reset();
161
 
  return getNextFeature(fetchAttributes);
162
 
}
163
 
 
164
 
 
165
 
/**
166
 
 * Get the next feature resulting from a select operation
167
 
 * Return 0 if there are no features in the selection set
168
 
 * @return QgsFeature
169
 
 */
170
 
bool QgsGPXProvider::getNextFeature(QgsFeature &feature, bool fetchAttributes){
171
 
  return false;
172
 
}
173
 
 
174
 
 
175
 
/**
176
 
 * Get the next feature resulting from a select operation
177
 
 * Return 0 if there are no features in the selection set
178
 
 * @return QgsFeature
179
 
 */
180
 
QgsFeature *QgsGPXProvider::getNextFeature(bool fetchAttributes) {
181
 
  QgsFeature* feature = new QgsFeature(-1);
182
 
  bool success;
183
 
  if (fetchAttributes)
184
 
    success = getNextFeature(feature, mAllAttributes);
185
 
  else {
186
 
    std::list<int> emptyList;
187
 
    success = getNextFeature(feature, emptyList);
188
 
  }
189
 
  if (success)
190
 
    return feature;
191
 
  delete feature;
192
 
  return NULL;
193
 
}
194
 
 
195
 
 
196
 
QgsFeature * QgsGPXProvider::getNextFeature(std::list<int> const & attlist, int featureQueueSize) {
197
 
  QgsFeature* feature = new QgsFeature(-1);
198
 
  bool success = getNextFeature(feature, attlist);
199
 
  if (success)
200
 
    return feature;
201
 
  delete feature;
202
 
  return NULL;
203
 
}
204
 
 
205
 
 
206
 
bool QgsGPXProvider::getNextFeature(QgsFeature* feature, 
207
 
                                    std::list<int> const & attlist) {
 
111
QgsGPXProvider::~QgsGPXProvider()
 
112
{
 
113
  QgsGPSData::releaseData( mFileName );
 
114
  delete mSelectionRectangle;
 
115
}
 
116
 
 
117
 
 
118
QString QgsGPXProvider::storageType() const
 
119
{
 
120
  return tr( "GPS eXchange file" );
 
121
}
 
122
 
 
123
int QgsGPXProvider::capabilities() const
 
124
{
 
125
  return QgsVectorDataProvider::AddFeatures |
 
126
         QgsVectorDataProvider::DeleteFeatures |
 
127
         QgsVectorDataProvider::ChangeAttributeValues;
 
128
}
 
129
 
 
130
bool QgsGPXProvider::nextFeature( QgsFeature& feature )
 
131
{
 
132
  feature.setValid( false );
208
133
  bool result = false;
209
 
  
210
 
  std::list<int>::const_iterator iter;
211
 
  
212
 
  if (mFeatureType == WaypointType) {
 
134
 
 
135
  QgsAttributeList::const_iterator iter;
 
136
 
 
137
  if ( mFeatureType == WaypointType )
 
138
  {
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) {
216
 
      const Waypoint* wpt;
217
 
      wpt = &(*mWptIter);
218
 
      if (boundsCheck(wpt->lon, wpt->lat)) {
219
 
        feature->setFeatureId(wpt->id);
220
 
        result = true;
221
 
        
222
 
        // some wkb voodoo
223
 
        char* geo = new char[21];
224
 
        std::memset(geo, 0, 21);
225
 
        geo[0] = endian();
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);
231
 
        
232
 
        // add attributes if they are wanted
233
 
        for (iter = attlist.begin(); iter != attlist.end(); ++iter) {
234
 
          switch (*iter) {
235
 
          case 0:
236
 
            feature->addAttribute(attr[NameAttr], wpt->name);
237
 
            break;
238
 
          case 1:
239
 
            if (wpt->ele == -std::numeric_limits<double>::max())
240
 
              feature->addAttribute(attr[EleAttr], "");
241
 
            else
242
 
              feature->addAttribute(attr[EleAttr], QString("%1").arg(wpt->ele));
243
 
            break;
244
 
          case 2:
245
 
            feature->addAttribute(attr[SymAttr], wpt->sym);
246
 
            break;
247
 
          case 3:
248
 
            feature->addAttribute(attr[CmtAttr], wpt->cmt);
249
 
            break;
250
 
          case 4:
251
 
            feature->addAttribute(attr[DscAttr], wpt->desc);
252
 
            break;
253
 
          case 5:
254
 
            feature->addAttribute(attr[SrcAttr], wpt->src);
255
 
            break;
256
 
          case 6:
257
 
            feature->addAttribute(attr[URLAttr], wpt->url);
258
 
            break;
259
 
          case 7:
260
 
            feature->addAttribute(attr[URLNameAttr], wpt->urlname);
261
 
            break;
262
 
          }
263
 
        }
264
 
        
265
 
        ++mWptIter;
266
 
        break;
 
141
    for ( ; mWptIter != data->waypointsEnd(); ++mWptIter )
 
142
    {
 
143
      const QgsWaypoint* wpt;
 
144
      wpt = &( *mWptIter );
 
145
      if ( boundsCheck( wpt->lon, wpt->lat ) )
 
146
      {
 
147
        feature.setFeatureId( wpt->id );
 
148
        result = true;
 
149
 
 
150
        // some wkb voodoo
 
151
        if ( mFetchGeom )
 
152
        {
 
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 ) );
 
160
        }
 
161
        feature.setValid( true );
 
162
 
 
163
        // add attributes if they are wanted
 
164
        for ( iter = mAttributesToFetch.begin(); iter != mAttributesToFetch.end(); ++iter )
 
165
        {
 
166
          switch ( *iter )
 
167
          {
 
168
            case NameAttr:
 
169
              feature.addAttribute( NameAttr, QVariant( wpt->name ) );
 
170
              break;
 
171
            case EleAttr:
 
172
              if ( wpt->ele != -std::numeric_limits<double>::max() )
 
173
                feature.addAttribute( EleAttr, QVariant( wpt->ele ) );
 
174
              break;
 
175
            case SymAttr:
 
176
              feature.addAttribute( SymAttr, QVariant( wpt->sym ) );
 
177
              break;
 
178
            case CmtAttr:
 
179
              feature.addAttribute( CmtAttr, QVariant( wpt->cmt ) );
 
180
              break;
 
181
            case DscAttr:
 
182
              feature.addAttribute( DscAttr, QVariant( wpt->desc ) );
 
183
              break;
 
184
            case SrcAttr:
 
185
              feature.addAttribute( SrcAttr, QVariant( wpt->src ) );
 
186
              break;
 
187
            case URLAttr:
 
188
              feature.addAttribute( URLAttr, QVariant( wpt->url ) );
 
189
              break;
 
190
            case URLNameAttr:
 
191
              feature.addAttribute( URLNameAttr, QVariant( wpt->urlname ) );
 
192
              break;
 
193
          }
 
194
        }
 
195
 
 
196
        ++mWptIter;
 
197
        break;
267
198
      }
268
199
    }
269
200
  }
270
 
  
271
 
  else if (mFeatureType == RouteType) {
 
201
 
 
202
  else if ( mFeatureType == RouteType )
 
203
  {
272
204
    // go through the routes and return the first one that is in the bounds
273
205
    // rectangle
274
 
    for (; mRteIter != data->routesEnd(); ++mRteIter) {
275
 
      const Route* rte;
276
 
      rte = &(*mRteIter);
277
 
      
278
 
      if (rte->points.size() == 0)
279
 
        continue;
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);
284
 
        result = true;
285
 
        
286
 
        // some wkb voodoo
287
 
        int nPoints = rte->points.size();
288
 
        char* geo = new char[9 + 16 * nPoints];
289
 
        std::memset(geo, 0, 9 + 16 * nPoints);
290
 
        geo[0] = endian();
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));
296
 
        }
297
 
        feature->setGeometryAndOwnership((unsigned char *)geo, 9 + 16 * nPoints);
298
 
        feature->setValid(true);
299
 
        
300
 
        // add attributes if they are wanted
301
 
        for (iter = attlist.begin(); iter != attlist.end(); ++iter) {
302
 
          if (*iter == 0)
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], "");
307
 
            else
308
 
              feature->addAttribute(attr[NumAttr], QString("%1").arg(rte->number));
309
 
          }
310
 
          else if (*iter == 2)
311
 
            feature->addAttribute(attr[CmtAttr], rte->cmt);
312
 
          else if (*iter == 3)
313
 
            feature->addAttribute(attr[DscAttr], rte->desc);
314
 
          else if (*iter == 4)
315
 
            feature->addAttribute(attr[SrcAttr], rte->src);
316
 
          else if (*iter == 5)
317
 
            feature->addAttribute(attr[URLAttr], rte->url);
318
 
          else if (*iter == 6)
319
 
            feature->addAttribute(attr[URLNameAttr], rte->urlname);
320
 
        }
321
 
        
322
 
        ++mRteIter;
323
 
        break;
 
206
    for ( ; mRteIter != data->routesEnd(); ++mRteIter )
 
207
    {
 
208
      const QgsRoute* rte;
 
209
      rte = &( *mRteIter );
 
210
 
 
211
      if ( rte->points.size() == 0 )
 
212
        continue;
 
213
      const QgsRectangle& b( *mSelectionRectangle );
 
214
      if (( rte->xMax >= b.xMinimum() ) && ( rte->xMin <= b.xMaximum() ) &&
 
215
          ( rte->yMax >= b.yMinimum() ) && ( rte->yMin <= b.yMaximum() ) )
 
216
      {
 
217
        // some wkb voodoo
 
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 )
 
225
        {
 
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 ) );
 
228
        }
 
229
 
 
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
 
235
 
 
236
        if ( !intersection )
 
237
        {
 
238
          delete theGeometry;
 
239
        }
 
240
        else
 
241
        {
 
242
          if ( mFetchGeom )
 
243
          {
 
244
            feature.setGeometry( theGeometry );
 
245
          }
 
246
          else
 
247
          {
 
248
            delete theGeometry;
 
249
          }
 
250
          feature.setFeatureId( rte->id );
 
251
          result = true;
 
252
          feature.setValid( true );
 
253
 
 
254
          // add attributes if they are wanted
 
255
          for ( iter = mAttributesToFetch.begin(); iter != mAttributesToFetch.end(); ++iter )
 
256
          {
 
257
            switch ( *iter )
 
258
            {
 
259
              case NameAttr:
 
260
                feature.addAttribute( NameAttr, QVariant( rte->name ) );
 
261
                break;
 
262
              case NumAttr:
 
263
                if ( rte->number != std::numeric_limits<int>::max() )
 
264
                  feature.addAttribute( NumAttr, QVariant( rte->number ) );
 
265
                break;
 
266
              case CmtAttr:
 
267
                feature.addAttribute( CmtAttr, QVariant( rte->cmt ) );
 
268
                break;
 
269
              case DscAttr:
 
270
                feature.addAttribute( DscAttr, QVariant( rte->desc ) );
 
271
                break;
 
272
              case SrcAttr:
 
273
                feature.addAttribute( SrcAttr, QVariant( rte->src ) );
 
274
                break;
 
275
              case URLAttr:
 
276
                feature.addAttribute( URLAttr, QVariant( rte->url ) );
 
277
                break;
 
278
              case URLNameAttr:
 
279
                feature.addAttribute( URLNameAttr, QVariant( rte->urlname ) );
 
280
                break;
 
281
            }
 
282
          }
 
283
 
 
284
          ++mRteIter;
 
285
          break;
 
286
 
 
287
        }
 
288
 
 
289
        //++mRteIter;
 
290
        //xbreak;
324
291
      }
325
292
    }
326
293
  }
327
 
  
328
 
  else if (mFeatureType == TrackType) {
 
294
 
 
295
  else if ( mFeatureType == TrackType )
 
296
  {
329
297
    // go through the tracks and return the first one that is in the bounds
330
298
    // rectangle
331
 
    for (; mTrkIter != data->tracksEnd(); ++mTrkIter) {
332
 
      const Track* trk;
333
 
      trk = &(*mTrkIter);
334
 
      
335
 
      if (trk->segments.size() == 0)
336
 
        continue;
337
 
      if (trk->segments[0].points.size() == 0)
338
 
        continue;
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);
343
 
        result = true;
344
 
        
345
 
        // some wkb voodoo
346
 
        int nPoints = trk->segments[0].points.size();
347
 
        char* geo = new char[9 + 16 * nPoints];
348
 
        std::memset(geo, 0, 9 + 16 * nPoints);
349
 
        geo[0] = endian();
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));
355
 
        }
356
 
        feature->setGeometryAndOwnership((unsigned char *)geo, 9 + 16 * nPoints);
357
 
        feature->setValid(true);
358
 
        
359
 
        // add attributes if they are wanted
360
 
        for (iter = attlist.begin(); iter != attlist.end(); ++iter) {
361
 
          if (*iter == 0)
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], "");
366
 
            else
367
 
              feature->addAttribute(attr[NumAttr], QString("%1").arg(trk->number));
368
 
          }
369
 
          else if (*iter == 2)
370
 
            feature->addAttribute(attr[CmtAttr], trk->cmt);
371
 
          else if (*iter == 3)
372
 
            feature->addAttribute(attr[DscAttr], trk->desc);
373
 
          else if (*iter == 4)
374
 
            feature->addAttribute(attr[SrcAttr], trk->src);
375
 
          else if (*iter == 5)
376
 
            feature->addAttribute(attr[URLAttr], trk->url);
377
 
          else if (*iter == 6)
378
 
            feature->addAttribute(attr[URLNameAttr], trk->urlname);
379
 
        }
380
 
        
381
 
        ++mTrkIter;
382
 
        break;
383
 
      }
 
299
    for ( ; mTrkIter != data->tracksEnd(); ++mTrkIter )
 
300
    {
 
301
      const QgsTrack* trk;
 
302
      trk = &( *mTrkIter );
 
303
 
 
304
      QgsDebugMsg( QString( "GPX feature track segments: %1" ).arg( trk->segments.size() ) );
 
305
      if ( trk->segments.size() == 0 )
 
306
        continue;
 
307
 
 
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 ++ )
 
311
      {
 
312
        totalPoints += trk->segments[i].points.size();
 
313
      }
 
314
      if ( totalPoints == 0 )
 
315
        continue;
 
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() ) )
 
320
      {
 
321
        // some wkb voodoo
 
322
        char* geo = new char[9 + 16 * totalPoints];
 
323
        if ( !geo )
 
324
        {
 
325
          QgsDebugMsg( "Too large track!!!" );
 
326
          return false;
 
327
        }
 
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 );
 
332
 
 
333
        int thisPoint = 0;
 
334
        for ( std::vector<QgsTrackSegment>::size_type k = 0; k < trk->segments.size(); k++ )
 
335
        {
 
336
          int nPoints = trk->segments[k].points.size();
 
337
          for ( int i = 0; i < nPoints; ++i )
 
338
          {
 
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 ) );
 
341
            thisPoint++;
 
342
          }
 
343
        }
 
344
 
 
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
 
350
 
 
351
        if ( !intersection ) //no intersection, delete geometry and move on
 
352
        {
 
353
          delete theGeometry;
 
354
        }
 
355
        else //intersection
 
356
        {
 
357
          if ( mFetchGeom )
 
358
          {
 
359
            feature.setGeometry( theGeometry );
 
360
          }
 
361
          else
 
362
          {
 
363
            delete theGeometry;
 
364
          }
 
365
          feature.setFeatureId( trk->id );
 
366
          result = true;
 
367
 
 
368
          feature.setValid( true );
 
369
 
 
370
          // add attributes if they are wanted
 
371
          for ( iter = mAttributesToFetch.begin(); iter != mAttributesToFetch.end(); ++iter )
 
372
          {
 
373
            switch ( *iter )
 
374
            {
 
375
              case NameAttr:
 
376
                feature.addAttribute( NameAttr, QVariant( trk->name ) );
 
377
                break;
 
378
              case NumAttr:
 
379
                if ( trk->number != std::numeric_limits<int>::max() )
 
380
                  feature.addAttribute( NumAttr, QVariant( trk->number ) );
 
381
                break;
 
382
              case CmtAttr:
 
383
                feature.addAttribute( CmtAttr, QVariant( trk->cmt ) );
 
384
                break;
 
385
              case DscAttr:
 
386
                feature.addAttribute( DscAttr, QVariant( trk->desc ) );
 
387
                break;
 
388
              case SrcAttr:
 
389
                feature.addAttribute( SrcAttr, QVariant( trk->src ) );
 
390
                break;
 
391
              case URLAttr:
 
392
                feature.addAttribute( URLAttr, QVariant( trk->url ) );
 
393
                break;
 
394
              case URLNameAttr:
 
395
                feature.addAttribute( URLNameAttr, QVariant( trk->urlname ) );
 
396
                break;
 
397
            }
 
398
          }
 
399
 
 
400
          ++mTrkIter;
 
401
          break;
 
402
        }
 
403
      }
 
404
 
384
405
    }
385
406
  }
 
407
  if ( result )
 
408
  {
 
409
    feature.setValid( true );
 
410
  }
386
411
  return result;
387
412
}
388
413
 
389
 
 
390
 
/**
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
394
 
 */
395
 
void QgsGPXProvider::select(QgsRect *rect, bool useIntersect) {
396
 
  
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
403
 
  reset();
404
 
}
405
 
 
406
 
 
407
 
/**
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
411
 
 */
412
 
std::vector<QgsFeature>& QgsGPXProvider::identify(QgsRect * rect) {
413
 
  // reset the data source since we need to be able to read through
414
 
  // all features
415
 
  reset();
416
 
  QgsLogger::debug("Attempting to identify features falling within " +
417
 
                   rect->stringRep()); 
418
 
  // select the features
419
 
  select(rect);
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;
423
 
  return features;
424
 
}
425
 
 
426
 
 
427
 
/*
428
 
   unsigned char * QgsGPXProvider::getGeometryPointer(OGRFeature *fet){
429
 
   unsigned char *gPtr=0;
430
 
// get the wkb representation
431
 
 
432
 
//geom->exportToWkb((OGRwkbByteOrder) endian(), gPtr);
433
 
return gPtr;
434
 
 
435
 
}
436
 
*/
 
414
void QgsGPXProvider::select( QgsAttributeList fetchAttributes,
 
415
                             QgsRectangle rect,
 
416
                             bool fetchGeometry,
 
417
                             bool useIntersect )
 
418
{
 
419
  delete mSelectionRectangle;
 
420
  mSelectionRectangle = 0;
 
421
 
 
422
  if ( rect.isEmpty() )
 
423
  {
 
424
    mSelectionRectangle = new QgsRectangle( extent() );
 
425
  }
 
426
  else
 
427
  {
 
428
    mSelectionRectangle = new QgsRectangle( rect );
 
429
  }
 
430
  mAttributesToFetch = fetchAttributes;
 
431
  mFetchGeom = fetchGeometry;
 
432
 
 
433
  rewind();
 
434
}
437
435
 
438
436
 
439
437
 
440
438
// Return the extent of the layer
441
 
QgsRect *QgsGPXProvider::extent() {
 
439
QgsRectangle QgsGPXProvider::extent()
 
440
{
442
441
  return data->getExtent();
443
442
}
444
443
 
445
444
 
446
 
/** 
 
445
/**
447
446
 * Return the feature type
448
447
 */
449
 
int QgsGPXProvider::geometryType() const
 
448
QGis::WkbType QgsGPXProvider::geometryType() const
450
449
{
451
 
  return mGeomType;
 
450
  if ( mFeatureType == WaypointType )
 
451
    return QGis::WKBPoint;
 
452
 
 
453
  if ( mFeatureType == RouteType || mFeatureType == TrackType )
 
454
    return QGis::WKBLineString;
 
455
 
 
456
  return QGis::WKBUnknown;
452
457
}
453
458
 
454
459
 
455
 
/** 
 
460
/**
456
461
 * Return the feature type
457
462
 */
458
463
long QgsGPXProvider::featureCount() const
459
464
{
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();
466
471
  return 0;
467
472
}
470
475
/**
471
476
 * Return the number of fields
472
477
 */
473
 
int QgsGPXProvider::fieldCount() const
 
478
uint QgsGPXProvider::fieldCount() const
474
479
{
475
480
  return attributeFields.size();
476
481
}
477
482
 
478
483
 
479
 
std::vector<QgsField> const & QgsGPXProvider::fields() const
 
484
const QgsFieldMap& QgsGPXProvider::fields() const
480
485
{
481
486
  return attributeFields;
482
487
}
483
488
 
484
489
 
485
 
void QgsGPXProvider::reset() {
486
 
  if (mFeatureType == WaypointType)
 
490
void QgsGPXProvider::rewind()
 
491
{
 
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();
492
498
}
493
499
 
494
500
 
495
 
QString QgsGPXProvider::minValue(int position) {
496
 
  if (position >= fieldCount()) {
497
 
    QgsLogger::warning(tr("Warning: access requested to invalid position "
498
 
                       "in QgsGPXProvider::minValue(..)"));
499
 
  }
500
 
  if (mMinMaxCacheDirty) {
501
 
    fillMinMaxCash();
502
 
  }
503
 
  return QString::number(mMinMaxCache[position][0],'f',2);
504
 
}
505
 
 
506
 
 
507
 
QString QgsGPXProvider::maxValue(int position) {
508
 
  if (position >= fieldCount()) {
509
 
    QgsLogger::warning(tr("Warning: access requested to invalid position "
510
 
                       "in QgsGPXProvider::maxValue(..)"));
511
 
  }
512
 
  if (mMinMaxCacheDirty) {
513
 
    fillMinMaxCash();
514
 
  }
515
 
  return QString::number(mMinMaxCache[position][1],'f',2);
516
 
}
517
 
 
518
 
 
519
 
void QgsGPXProvider::fillMinMaxCash() {
520
 
  for(int i=0;i<fieldCount();i++) {
521
 
    mMinMaxCache[i][0]=DBL_MAX;
522
 
    mMinMaxCache[i][1]=-DBL_MAX;
523
 
  }
524
 
 
525
 
  QgsFeature f;
526
 
  reset();
527
 
 
528
 
  getNextFeature(f, true);
529
 
  do {
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;  
534
 
      }  
535
 
      if(value>mMinMaxCache[i][1]) {
536
 
        mMinMaxCache[i][1]=value;  
537
 
      }
538
 
    }
539
 
  } while(getNextFeature(f, true));
540
 
 
541
 
  mMinMaxCacheDirty=false;
542
 
}
543
 
 
544
 
 
545
 
 
546
 
bool QgsGPXProvider::isValid(){
 
501
bool QgsGPXProvider::isValid()
 
502
{
547
503
  return mValid;
548
504
}
549
505
 
550
506
 
551
 
bool QgsGPXProvider::addFeatures(std::list<QgsFeature*> flist) {
552
 
  
 
507
bool QgsGPXProvider::addFeatures( QgsFeatureList & flist )
 
508
{
 
509
 
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 )
 
513
  {
 
514
    if ( !addFeature( *iter ) )
557
515
      return false;
558
516
  }
559
 
  
 
517
 
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 ) )
563
521
    return false;
564
 
  QTextStream ostr(&file);
565
 
  data->writeXML(ostr);
 
522
  QTextStream ostr( &file );
 
523
  data->writeXML( ostr );
566
524
  return true;
567
525
}
568
526
 
569
527
 
570
 
bool QgsGPXProvider::addFeature(QgsFeature* f) {
571
 
  unsigned char* geo = f->getGeometry();
 
528
bool QgsGPXProvider::addFeature( QgsFeature& f )
 
529
{
 
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());
575
 
  
 
533
  QgsGPSObject* obj = NULL;
 
534
  const QgsAttributeMap& attrs( f.attributeMap() );
 
535
  QgsAttributeMap::const_iterator it;
 
536
 
576
537
  // is it a waypoint?
577
 
  if (mFeatureType == WaypointType && geo != NULL && geo[geo[0] == NDR ? 1 : 4] == QGis::WKBPoint) {
578
 
    
 
538
  if ( mFeatureType == WaypointType && geo != NULL && wkbType == QGis::WKBPoint )
 
539
  {
 
540
 
579
541
    // add geometry
580
 
    Waypoint wpt;
581
 
    std::memcpy(&wpt.lon, geo+5, sizeof(double));
582
 
    std::memcpy(&wpt.lat, geo+13, sizeof(double));
583
 
    
 
542
    QgsWaypoint wpt;
 
543
    std::memcpy( &wpt.lon, geo + 5, sizeof( double ) );
 
544
    std::memcpy( &wpt.lat, geo + 13, sizeof( double ) );
 
545
 
584
546
    // add waypoint-specific attributes
585
 
    for (int i = 0; i < attrs.size(); ++i) {
586
 
      if (attrs[i].fieldName() == attr[EleAttr]) {
587
 
        bool eleIsOK;
588
 
        double ele = attrs[i].fieldValue().toDouble(&eleIsOK);
589
 
        if (eleIsOK)
590
 
          wpt.ele = ele;
 
547
    for ( it = attrs.begin(); it != attrs.end(); ++it )
 
548
    {
 
549
      if ( it.key() == EleAttr )
 
550
      {
 
551
        bool eleIsOK;
 
552
        double ele = it->toDouble( &eleIsOK );
 
553
        if ( eleIsOK )
 
554
          wpt.ele = ele;
591
555
      }
592
 
      else if (attrs[i].fieldName() == attr[SymAttr]) {
593
 
        wpt.sym = attrs[i].fieldValue();
 
556
      else if ( it.key() == SymAttr )
 
557
      {
 
558
        wpt.sym = it->toString();
594
559
      }
595
560
    }
596
 
    
597
 
    GPSData::WaypointIterator iter = data->addWaypoint(wpt);
 
561
 
 
562
    QgsGPSData::WaypointIterator iter = data->addWaypoint( wpt );
598
563
    success = true;
599
 
    obj = &(*iter);
 
564
    obj = &( *iter );
600
565
  }
601
 
  
 
566
 
602
567
  // is it a route?
603
 
  if (mFeatureType == RouteType && geo != NULL && geo[geo[0] == NDR ? 1 : 4] == QGis::WKBLineString) {
604
 
 
605
 
    Route rte;
606
 
    
 
568
  if ( mFeatureType == RouteType && geo != NULL && wkbType == QGis::WKBLineString )
 
569
  {
 
570
 
 
571
    QgsRoute rte;
 
572
 
607
573
    // reset bounds
608
574
    rte.xMin = std::numeric_limits<double>::max();
609
575
    rte.xMax = -std::numeric_limits<double>::max();
612
578
 
613
579
    // add geometry
614
580
    int nPoints;
615
 
    std::memcpy(&nPoints, geo + 5, 4);
616
 
    for (int i = 0; i < nPoints; ++i) {
 
581
    std::memcpy( &nPoints, geo + 5, 4 );
 
582
    for ( int i = 0; i < nPoints; ++i )
 
583
    {
617
584
      double lat, lon;
618
 
      std::memcpy(&lon, geo + 9 + 16 * i, sizeof(double));
619
 
      std::memcpy(&lat, geo + 9 + 16 * i + 8, sizeof(double));
620
 
      Routepoint rtept;
 
585
      std::memcpy( &lon, geo + 9 + 16 * i, sizeof( double ) );
 
586
      std::memcpy( &lat, geo + 9 + 16 * i + 8, sizeof( double ) );
 
587
      QgsRoutepoint rtept;
621
588
      rtept.lat = lat;
622
589
      rtept.lon = lon;
623
 
      rte.points.push_back(rtept);
 
590
      rte.points.push_back( rtept );
624
591
      rte.xMin = rte.xMin < lon ? rte.xMin : lon;
625
592
      rte.xMax = rte.xMax > lon ? rte.xMax : lon;
626
593
      rte.yMin = rte.yMin < lat ? rte.yMin : lat;
627
594
      rte.yMax = rte.yMax > lat ? rte.yMax : lat;
628
595
    }
629
 
    
 
596
 
630
597
    // add route-specific attributes
631
 
    for (int i = 0; i < attrs.size(); ++i) {
632
 
      if (attrs[i].fieldName() == attr[NumAttr]) {
633
 
        bool numIsOK;
634
 
        long num = attrs[i].fieldValue().toLong(&numIsOK);
635
 
        if (numIsOK)
636
 
          rte.number = num;
 
598
    for ( it = attrs.begin(); it != attrs.end(); ++it )
 
599
    {
 
600
      if ( it.key() == NumAttr )
 
601
      {
 
602
        bool numIsOK;
 
603
        long num = it->toInt( &numIsOK );
 
604
        if ( numIsOK )
 
605
          rte.number = num;
637
606
      }
638
607
    }
639
 
    
640
 
    GPSData::RouteIterator iter = data->addRoute(rte);
 
608
 
 
609
    QgsGPSData::RouteIterator iter = data->addRoute( rte );
641
610
    success = true;
642
 
    obj = &(*iter);
 
611
    obj = &( *iter );
643
612
  }
644
 
  
 
613
 
645
614
  // is it a track?
646
 
  if (mFeatureType == TrackType && geo != NULL && geo[geo[0] == NDR ? 1 : 4] == QGis::WKBLineString) {
647
 
 
648
 
    Track trk;
649
 
    TrackSegment trkseg;
650
 
    
 
615
  if ( mFeatureType == TrackType && geo != NULL && wkbType == QGis::WKBLineString )
 
616
  {
 
617
 
 
618
    QgsTrack trk;
 
619
    QgsTrackSegment trkseg;
 
620
 
651
621
    // reset bounds
652
622
    trk.xMin = std::numeric_limits<double>::max();
653
623
    trk.xMax = -std::numeric_limits<double>::max();
656
626
 
657
627
    // add geometry
658
628
    int nPoints;
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 )
 
631
    {
661
632
      double lat, lon;
662
 
      std::memcpy(&lon, geo + 9 + 16 * i, sizeof(double));
663
 
      std::memcpy(&lat, geo + 9 + 16 * i + 8, sizeof(double));
664
 
      Trackpoint trkpt;
 
633
      std::memcpy( &lon, geo + 9 + 16 * i, sizeof( double ) );
 
634
      std::memcpy( &lat, geo + 9 + 16 * i + 8, sizeof( double ) );
 
635
      QgsTrackpoint trkpt;
665
636
      trkpt.lat = lat;
666
637
      trkpt.lon = lon;
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;
672
643
    }
673
 
    
 
644
 
674
645
    // add track-specific attributes
675
 
    for (int i = 0; i < attrs.size(); ++i) {
676
 
      if (attrs[i].fieldName() == attr[NumAttr]) {
677
 
        bool numIsOK;
678
 
        long num = attrs[i].fieldValue().toLong(&numIsOK);
679
 
        if (numIsOK)
680
 
          trk.number = num;
 
646
    for ( it = attrs.begin(); it != attrs.end(); ++it )
 
647
    {
 
648
      if ( it.key() == NumAttr )
 
649
      {
 
650
        bool numIsOK;
 
651
        long num = it->toInt( &numIsOK );
 
652
        if ( numIsOK )
 
653
          trk.number = num;
681
654
      }
682
655
    }
683
 
    
684
 
    trk.segments.push_back(trkseg);
685
 
    GPSData::TrackIterator iter = data->addTrack(trk);
 
656
 
 
657
    trk.segments.push_back( trkseg );
 
658
    QgsGPSData::TrackIterator iter = data->addTrack( trk );
686
659
    success = true;
687
 
    obj = &(*iter);
 
660
    obj = &( *iter );
688
661
  }
689
 
  
690
 
  
 
662
 
 
663
 
691
664
  // add common attributes
692
 
  if (obj) {
693
 
    for (int i = 0; i < attrs.size(); ++i) {
694
 
      if (attrs[i].fieldName() == attr[NameAttr]) {
695
 
        obj->name = attrs[i].fieldValue();
696
 
      }
697
 
      else if (attrs[i].fieldName() == attr[CmtAttr]) {
698
 
        obj->cmt = attrs[i].fieldValue();
699
 
      }
700
 
      else if (attrs[i].fieldName() == attr[DscAttr]) {
701
 
        obj->desc = attrs[i].fieldValue();
702
 
      }
703
 
      else if (attrs[i].fieldName() == attr[SrcAttr]) {
704
 
        obj->src = attrs[i].fieldValue();
705
 
      }
706
 
      else if (attrs[i].fieldName() == attr[URLAttr]) {
707
 
        obj->url = attrs[i].fieldValue();
708
 
      }
709
 
      else if (attrs[i].fieldName() == attr[URLNameAttr]) {
710
 
        obj->urlname = attrs[i].fieldValue();
 
665
  if ( obj )
 
666
  {
 
667
    for ( it = attrs.begin(); it != attrs.end(); ++it )
 
668
    {
 
669
      if ( it.key() == NameAttr )
 
670
      {
 
671
        obj->name = it->toString();
 
672
      }
 
673
      else if ( it.key() == CmtAttr )
 
674
      {
 
675
        obj->cmt = it->toString();
 
676
      }
 
677
      else if ( it.key() == DscAttr )
 
678
      {
 
679
        obj->desc = it->toString();
 
680
      }
 
681
      else if ( it.key() == SrcAttr )
 
682
      {
 
683
        obj->src = it->toString();
 
684
      }
 
685
      else if ( it.key() == URLAttr )
 
686
      {
 
687
        obj->url = it->toString();
 
688
      }
 
689
      else if ( it.key() == URLNameAttr )
 
690
      {
 
691
        obj->urlname = it->toString();
711
692
      }
712
693
    }
713
694
  }
714
 
    
 
695
 
715
696
  return success;
716
697
}
717
698
 
718
699
 
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);
726
 
 
727
 
  // write back to file
728
 
  QFile file(mFileName);
729
 
  if (!file.open(QIODevice::WriteOnly))
730
 
    return false;
731
 
  QTextStream ostr(&file);
732
 
  data->writeXML(ostr);
733
 
  return true;
734
 
}
735
 
 
736
 
 
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 =
739
 
    attr_map.begin();
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);
745
 
        ++aIter;
746
 
      }
747
 
    }
748
 
  }
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);
754
 
        ++aIter;
755
 
      }
756
 
    }
757
 
  }
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);
763
 
        ++aIter;
764
 
      }
765
 
    }
766
 
  }
767
 
 
768
 
  // write back to file
769
 
  QFile file(mFileName);
770
 
  if (!file.open(QIODevice::WriteOnly))
771
 
    return false;
772
 
  QTextStream ostr(&file);
773
 
  data->writeXML(ostr);
774
 
  return true;
775
 
}
776
 
 
777
 
 
778
 
void QgsGPXProvider::changeAttributeValues(GPSObject& obj, 
779
 
                                           const std::map<QString, QString>& attrs) {
780
 
  std::map<QString, QString>::const_iterator aIter;
781
 
  
782
 
  // common attributes
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;
795
 
  
 
700
bool QgsGPXProvider::deleteFeatures( const QgsFeatureIds & id )
 
701
{
 
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 );
 
708
 
 
709
  // write back to file
 
710
  QFile file( mFileName );
 
711
  if ( !file.open( QIODevice::WriteOnly ) )
 
712
    return false;
 
713
  QTextStream ostr( &file );
 
714
  data->writeXML( ostr );
 
715
  return true;
 
716
}
 
717
 
 
718
 
 
719
bool QgsGPXProvider::changeAttributeValues( const QgsChangedAttributesMap & attr_map )
 
720
{
 
721
  QgsChangedAttributesMap::const_iterator aIter = attr_map.begin();
 
722
  if ( mFeatureType == WaypointType )
 
723
  {
 
724
    QgsGPSData::WaypointIterator wIter = data->waypointsBegin();
 
725
    for ( ; wIter != data->waypointsEnd() && aIter != attr_map.end(); ++wIter )
 
726
    {
 
727
      if ( wIter->id == aIter.key() )
 
728
      {
 
729
        changeAttributeValues( *wIter, aIter.value() );
 
730
        ++aIter;
 
731
      }
 
732
    }
 
733
  }
 
734
  else if ( mFeatureType == RouteType )
 
735
  {
 
736
    QgsGPSData::RouteIterator rIter = data->routesBegin();
 
737
    for ( ; rIter != data->routesEnd() && aIter != attr_map.end(); ++rIter )
 
738
    {
 
739
      if ( rIter->id == aIter.key() )
 
740
      {
 
741
        changeAttributeValues( *rIter, aIter.value() );
 
742
        ++aIter;
 
743
      }
 
744
    }
 
745
  }
 
746
  if ( mFeatureType == TrackType )
 
747
  {
 
748
    QgsGPSData::TrackIterator tIter = data->tracksBegin();
 
749
    for ( ; tIter != data->tracksEnd() && aIter != attr_map.end(); ++tIter )
 
750
    {
 
751
      if ( tIter->id == aIter.key() )
 
752
      {
 
753
        changeAttributeValues( *tIter, aIter.value() );
 
754
        ++aIter;
 
755
      }
 
756
    }
 
757
  }
 
758
 
 
759
  // write back to file
 
760
  QFile file( mFileName );
 
761
  if ( !file.open( QIODevice::WriteOnly ) )
 
762
    return false;
 
763
  QTextStream ostr( &file );
 
764
  data->writeXML( ostr );
 
765
  return true;
 
766
}
 
767
 
 
768
 
 
769
void QgsGPXProvider::changeAttributeValues( QgsGPSObject& obj, const QgsAttributeMap& attrs )
 
770
{
 
771
  QgsAttributeMap::const_iterator aIter;
 
772
 
 
773
  // TODO:
 
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();
 
786
 
796
787
  // waypoint-specific attributes
797
 
  Waypoint* wpt = dynamic_cast<Waypoint*>(&obj);
798
 
  if (wpt != NULL) {
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 );
 
789
  if ( wpt != NULL )
 
790
  {
 
791
    if ( attrs.contains( SymAttr ) )
 
792
      wpt->sym = attrs[SymAttr].toString();
 
793
    if ( attrs.contains( EleAttr ) )
 
794
    {
802
795
      bool eleIsOK;
803
 
      double ele = aIter->second.toDouble(&eleIsOK);
804
 
      if (eleIsOK)
805
 
        wpt->ele = ele;
 
796
      double ele = attrs[EleAttr].toDouble( &eleIsOK );
 
797
      if ( eleIsOK )
 
798
        wpt->ele = ele;
806
799
    }
807
800
  }
808
 
  
 
801
 
809
802
  // route- and track-specific attributes
810
 
  GPSExtended* ext = dynamic_cast<GPSExtended*>(&obj);
811
 
  if (ext != NULL) {
812
 
    if ((aIter = attrs.find(attr[NumAttr])) != attrs.end()) {
 
803
  QgsGPSExtended* ext = dynamic_cast<QgsGPSExtended*>( &obj );
 
804
  if ( ext != NULL )
 
805
  {
 
806
    if ( attrs.contains( NumAttr ) )
 
807
    {
813
808
      bool eleIsOK;
814
 
      int number = aIter->second.toInt(&eleIsOK);
815
 
      if (eleIsOK)
816
 
        ext->number = number;
 
809
      double ele = attrs[NumAttr].toDouble( &eleIsOK );
 
810
      if ( eleIsOK )
 
811
        wpt->ele = ele;
817
812
    }
818
813
  }
819
814
}
820
815
 
821
816
 
822
 
size_t QgsGPXProvider::layerCount() const
 
817
QVariant QgsGPXProvider::defaultValue( int fieldId )
823
818
{
824
 
    return 1;                   // XXX need to calculate actual number of layers
825
 
} // QgsGPXProvider::layerCount()
826
 
 
827
 
 
828
 
 
829
 
QString QgsGPXProvider::getDefaultValue(const QString& attr, QgsFeature* f) {
830
 
  if (attr == "source")
831
 
    return tr("Digitized in QGIS");
832
 
  return "";
 
819
  if ( fieldId == SrcAttr )
 
820
    return tr( "Digitized in QGIS" );
 
821
  return QVariant();
833
822
}
834
823
 
835
824
 
836
 
/** 
 
825
/**
837
826
 * Check to see if the point is within the selection rectangle
838
827
 */
839
 
bool QgsGPXProvider::boundsCheck(double x, double y)
 
828
bool QgsGPXProvider::boundsCheck( double x, double y )
840
829
{
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";
846
835
  return inBounds;
847
836
}
848
837
 
849
838
 
850
839
QString QgsGPXProvider::name() const
851
840
{
852
 
    return GPX_KEY;
 
841
  return GPX_KEY;
853
842
} // QgsGPXProvider::name()
854
843
 
855
844
 
856
845
 
857
846
QString QgsGPXProvider::description() const
858
847
{
859
 
    return GPX_DESCRIPTION;
 
848
  return GPX_DESCRIPTION;
860
849
} // QgsGPXProvider::description()
861
850
 
 
851
QgsCoordinateReferenceSystem QgsGPXProvider::crs()
 
852
{
 
853
  return QgsCoordinateReferenceSystem(); // use default CRS - it's WGS84
 
854
}
862
855
 
863
856
 
864
857
 
866
859
 
867
860
 
868
861
/**
869
 
 * Class factory to return a pointer to a newly created 
 
862
 * Class factory to return a pointer to a newly created
870
863
 * QgsGPXProvider object
871
864
 */
872
 
QGISEXTERN QgsGPXProvider * classFactory(const QString *uri) {
873
 
  return new QgsGPXProvider(*uri);
 
865
QGISEXTERN QgsGPXProvider * classFactory( const QString *uri )
 
866
{
 
867
  return new QgsGPXProvider( *uri );
874
868
}
875
869
 
876
870
 
877
871
/** Required key function (used to map the plugin to a data store type)
878
872
*/
879
 
QGISEXTERN QString providerKey(){
880
 
    return GPX_KEY;
 
873
QGISEXTERN QString providerKey()
 
874
{
 
875
  return GPX_KEY;
881
876
}
882
877
 
883
878
 
884
879
/**
885
 
 * Required description function 
 
880
 * Required description function
886
881
 */
887
 
QGISEXTERN QString description(){
888
 
    return GPX_DESCRIPTION;
889
 
 
882
QGISEXTERN QString description()
 
883
{
 
884
  return GPX_DESCRIPTION;
 
885
}
890
886
 
891
887
 
892
888
/**
893
889
 * Required isProvider function. Used to determine if this shared library
894
890
 * is a data provider plugin
895
891
 */
896
 
QGISEXTERN bool isProvider(){
 
892
QGISEXTERN bool isProvider()
 
893
{
897
894
  return true;
898
895
}
899
896