/*************************************************************************** qgsgpxprovider.cpp - Data provider for GPS eXchange files ------------------- begin : 2004-04-14 copyright : (C) 2004 by Lars Luthman email : larsl@users.sourceforge.net Partly based on qgsdelimitedtextprovider.cpp, (C) 2004 Gary E. Sherman ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include "../../src/qgsdataprovider.h" #include "../../src/qgsfeature.h" #include "../../src/qgsfield.h" #include "../../src/qgsrect.h" #include "qgsgpxprovider.h" #include "gpsdata.h" QgsGPXProvider::QgsGPXProvider(QString uri) : mFileName(uri), mMinMaxCacheDirty(true) { attributeFields.push_back(QgsField("name", "text")); attributeFields.push_back(QgsField("type", "text")); // set the selection rectangle to null mSelectionRectangle = 0; // parse the file mFile = new QFile(mFileName); QDomDocument qdd; if (!(mValid = (qdd.setContent(mFile) && data.parseDom(qdd)))) { std::cerr<close(); // resize the cache matrix mMinMaxCache=new double*[attributeFields.size()]; for(int i=0;iclose(); delete mFile; for(int i=0;isetGeometry((unsigned char *)geo, sizeof(wkbPoint)); result->setValid(true); // add attributes if they are wanted if (fetchAttributes) { result->addAttribute("name", wpt.name); result->addAttribute("type", "0"); } ++mFid; break; } } if (result != 0) return result; // go through the routes and return the first one that is in the bounds // rectangle int offset = data.getNumberOfWaypoints(); for (; mFid < offset + data.getNumberOfRoutes(); ++mFid) { const Route& rte(data.getRoute(mFid - offset)); if (rte.points.size() == 0) continue; const Routepoint& rtept(rte.points[0]); const QgsRect& b(*mSelectionRectangle); if ((rte.xMax >= b.xMin()) && (rte.xMin <= b.xMax()) && (rte.yMax >= b.yMin()) && (rte.yMin <= b.yMax())) { result = new QgsFeature(mFid); // some wkb voodoo int nPoints = rte.points.size(); char* geo = new char[9 + 16 * nPoints]; std::memset(geo, 0, 9 + 16 * nPoints); geo[0] = endian(); geo[1] = 2; std::memcpy(geo + 5, &nPoints, 4); for (int i = 0; i < rte.points.size(); ++i) { std::memcpy(geo + 9 + 16 * i, &rte.points[i].lon, sizeof(double)); std::memcpy(geo + 9 + 16 * i + 8, &rte.points[i].lat, sizeof(double)); } result->setGeometry((unsigned char *)geo, 9 + 16 * nPoints); result->setValid(true); // add attributes if they are wanted if (fetchAttributes) { result->addAttribute("name", rte.name); result->addAttribute("type", "1"); } ++mFid; break; } } if (result != 0) return result; // go through the tracks and return the first one that is in the bounds // rectangle offset = data.getNumberOfWaypoints() + data.getNumberOfRoutes(); for (; mFid < offset + data.getNumberOfTracks(); ++mFid) { const Track& trk(data.getTrack(mFid - offset)); if (trk.segments.size() == 0) continue; if (trk.segments[0].points.size() == 0) continue; const Trackpoint& trkpt(trk.segments[0].points[0]); const QgsRect& b(*mSelectionRectangle); if ((trk.xMax >= b.xMin()) && (trk.xMin <= b.xMax()) && (trk.yMax >= b.yMin()) && (trk.yMin <= b.yMax())) { result = new QgsFeature(mFid); // some wkb voodoo int nPoints = trk.segments[0].points.size(); char* geo = new char[9 + 16 * nPoints]; std::memset(geo, 0, 9 + 16 * nPoints); geo[0] = endian(); geo[1] = 2; std::memcpy(geo + 5, &nPoints, 4); for (int i = 0; i < nPoints; ++i) { std::memcpy(geo + 9 + 16 * i, &trk.segments[0].points[i].lon, sizeof(double)); std::memcpy(geo + 9 + 16 * i + 8, &trk.segments[0].points[i].lat, sizeof(double)); } result->setGeometry((unsigned char *)geo, 9 + 16 * nPoints); result->setValid(true); // add attributes if they are wanted if (fetchAttributes) { result->addAttribute("name", trk.name); result->addAttribute("type", "2"); } ++mFid; break; } } return result; } /** * Select features based on a bounding rectangle. Features can be retrieved * with calls to getFirstFeature and getNextFeature. * @param mbr QgsRect containing the extent to use in selecting features */ void QgsGPXProvider::select(QgsRect *rect, bool useIntersect) { // Setting a spatial filter doesn't make much sense since we have to // compare each point against the rectangle. // We store the rect and use it in getNextFeature to determine if the // feature falls in the selection area mSelectionRectangle = new QgsRect(*rect); // Select implies an upcoming feature read so we reset the data source reset(); // Reset the feature id to 0 mFid = 0; } /** * Identify features within the search radius specified by rect * @param rect Bounding rectangle of search radius * @return std::vector containing QgsFeature objects that intersect rect */ std::vector& QgsGPXProvider::identify(QgsRect * rect) { // reset the data source since we need to be able to read through // all features reset(); std::cerr<<"Attempting to identify features falling within " <stringRep()<exportToWkb((OGRwkbByteOrder) endian(), gPtr); return gPtr; } */ int QgsGPXProvider::endian() { char *chkEndian = new char[4]; memset(chkEndian, '\0', 4); chkEndian[0] = 0xE8; int *ce = (int *) chkEndian; int retVal; if (232 == *ce) retVal = NDR; else retVal = XDR; delete[]chkEndian; return retVal; } // Return the extent of the layer QgsRect *QgsGPXProvider::extent() { return data.getExtent(); } /** * Return the feature type */ int QgsGPXProvider::geometryType() { return 1; // WKBPoint } /** * Return the feature type */ long QgsGPXProvider::featureCount() { return data.getNumberOfWaypoints() + data.getNumberOfRoutes() + data.getNumberOfTracks(); } /** * Return the number of fields */ int QgsGPXProvider::fieldCount() { return attributeFields.size(); } std::vector& QgsGPXProvider::fields(){ return attributeFields; } void QgsGPXProvider::reset() { // Reset feature id to 0 mFid = 0; } QString QgsGPXProvider::minValue(int position) { if (position >= fieldCount()) { std::cerr<<"Warning: access requested to invalid position " <<"in QgsGPXProvider::minValue(..)"<= fieldCount()) { std::cerr<<"Warning: access requested to invalid position " <<"in QgsGPXProvider::maxValue(..)"<mMinMaxCache[i][1]) { mMinMaxCache[i][1]=value; } } } while(getNextFeature(f, true)); mMinMaxCacheDirty=false; } void QgsGPXProvider::setDataSourceUri(QString uri) { mFileName = uri; } QString QgsGPXProvider::getDataSourceUri() { return mFileName; } bool QgsGPXProvider::isValid(){ return mValid; } /** * Check to see if the point is within the selection rectangle */ bool QgsGPXProvider::boundsCheck(double x, double y) { bool inBounds = (((x < mSelectionRectangle->xMax()) && (x > mSelectionRectangle->xMin())) && ((y < mSelectionRectangle->yMax()) && (y > mSelectionRectangle->yMin()))); QString hit = inBounds?"true":"false"; return inBounds; } /** * Class factory to return a pointer to a newly created * QgsGPXProvider object */ extern "C" QgsGPXProvider * classFactory(const char *uri) { return new QgsGPXProvider(uri); } /** Required key function (used to map the plugin to a data store type) */ extern "C" QString providerKey(){ return QString("gpx"); } /** * Required description function */ extern "C" QString description(){ return QString("GPS eXchange format and LOC provider"); } /** * Required isProvider function. Used to determine if this shared library * is a data provider plugin */ extern "C" bool isProvider(){ return true; }