From 2659556af1e875074b83e1ad8ba81a4d9f24feee Mon Sep 17 00:00:00 2001 From: timlinux Date: Mon, 15 Sep 2008 20:51:01 +0000 Subject: [PATCH] zoomToActiveLayer instead of zoomActiveLayer. Also applied patch from Magnus Homann to correct issue where save as shapefile does not allow using CRS of project projection. git-svn-id: http://svn.osgeo.org/qgis/trunk@9334 c8812cc2-4d05-0410-92ff-de0c093fc19c --- python/core/qgsvectorfilewriter.sip | 1 + python/gui/qgisinterface.sip | 2 +- src/app/legend/qgslegendlayerfile.cpp | 34 ++++- src/app/qgisappinterface.cpp | 2 +- src/app/qgisappinterface.h | 2 +- src/core/qgsgeometry.cpp | 151 ++++++++++++++++++++++ src/core/qgsgeometry.h | 12 ++ src/core/qgsvectorfilewriter.cpp | 42 +++++- src/core/qgsvectorfilewriter.h | 1 + src/core/qgsvectorlayer.cpp | 3 +- src/gui/qgisinterface.h | 2 +- src/plugins/gps_importer/qgsgpsplugin.cpp | 2 + 12 files changed, 246 insertions(+), 8 deletions(-) diff --git a/python/core/qgsvectorfilewriter.sip b/python/core/qgsvectorfilewriter.sip index 5d98007c257..dff34977d84 100644 --- a/python/core/qgsvectorfilewriter.sip +++ b/python/core/qgsvectorfilewriter.sip @@ -28,6 +28,7 @@ public: static WriterError writeAsShapefile(QgsVectorLayer* layer, const QString& shapefileName, const QString& fileEncoding, + const QgsCoordinateReferenceSystem*, bool onlySelected = FALSE); diff --git a/python/gui/qgisinterface.sip b/python/gui/qgisinterface.sip index 161e746b599..495172cbb34 100644 --- a/python/gui/qgisinterface.sip +++ b/python/gui/qgisinterface.sip @@ -33,7 +33,7 @@ class QgisInterface : QObject //! Zoom to previous view extent virtual void zoomToPrevious()=0; //! Zoome to extent of the active layer - virtual void zoomActiveLayer()=0; + virtual void zoomToActiveLayer()=0; //! Add a vector layer virtual QgsVectorLayer* addVectorLayer(QString vectorLayerPath, QString baseName, QString providerKey)=0; diff --git a/src/app/legend/qgslegendlayerfile.cpp b/src/app/legend/qgslegendlayerfile.cpp index 1bc8618173a..04606732e90 100644 --- a/src/app/legend/qgslegendlayerfile.cpp +++ b/src/app/legend/qgslegendlayerfile.cpp @@ -24,10 +24,12 @@ #include "qgslegendlayer.h" #include "qgslegendlayerfile.h" #include "qgsmaplayer.h" +#include "qgsmaprenderer.h" #include "qgsrasterlayer.h" #include "qgsvectorfilewriter.h" #include "qgsvectorlayer.h" #include "qgsvectordataprovider.h" +#include "qgsgenericprojectionselector.h" // attribute table #include "qgsattributetable.h" @@ -225,6 +227,8 @@ void QgsLegendLayerFile::saveSelectionAsShapefile() void QgsLegendLayerFile::saveAsShapefileGeneral( bool saveOnlySelection ) { + QgsCoordinateReferenceSystem destCRS; + if ( mLyr.layer()->type() != QgsMapLayer::VECTOR ) return; @@ -264,6 +268,33 @@ void QgsLegendLayerFile::saveAsShapefileGeneral( bool saveOnlySelection ) shapefileName += ".shp"; } + destCRS = vlayer->srs(); + // Find out if we have projections enabled or not + if ( QgisApp::instance()->mapCanvas()->mapRenderer()->projectionsEnabled() ) + { + destCRS = QgisApp::instance()->mapCanvas()->mapRenderer()->destinationSrs(); + } + + QgsGenericProjectionSelector * mySelector = new QgsGenericProjectionSelector(); + mySelector->setSelectedCrsId( destCRS.srsid() ); + mySelector->setMessage(tr("Select the coordinate reference system for the saved shapefile.") + + tr("The data points will be transformed from the layer coordinate reference system.")); + + if ( mySelector->exec() ) + { + QgsCoordinateReferenceSystem srs( mySelector->selectedCrsId(), QgsCoordinateReferenceSystem::QGIS_CRSID ); + destCRS = srs; + // destCRS->createFromId(mySelector->selectedCrsId(), QgsCoordinateReferenceSystem::QGIS_CRSID) + } + else + { + // Aborted CS selection, don't save. + delete mySelector; + return; + } + + delete mySelector; + // overwrite the file - user will already have been prompted // to verify they want to overwrite by the file dialog above if ( QFile::exists( shapefileName ) ) @@ -273,11 +304,12 @@ void QgsLegendLayerFile::saveAsShapefileGeneral( bool saveOnlySelection ) return; } } + // ok if the file existed it should be deleted now so we can continue... QApplication::setOverrideCursor( Qt::WaitCursor ); QgsVectorFileWriter::WriterError error; - error = QgsVectorFileWriter::writeAsShapefile( vlayer, shapefileName, encoding, saveOnlySelection ); + error = QgsVectorFileWriter::writeAsShapefile( vlayer, shapefileName, encoding, &destCRS, saveOnlySelection ); QApplication::restoreOverrideCursor(); diff --git a/src/app/qgisappinterface.cpp b/src/app/qgisappinterface.cpp index 276baf5ef68..80a58ed4c97 100644 --- a/src/app/qgisappinterface.cpp +++ b/src/app/qgisappinterface.cpp @@ -52,7 +52,7 @@ void QgisAppInterface::zoomToPrevious() qgis->zoomToPrevious(); } -void QgisAppInterface::zoomActiveLayer() +void QgisAppInterface::zoomToActiveLayer() { qgis->zoomToLayerExtent(); } diff --git a/src/app/qgisappinterface.h b/src/app/qgisappinterface.h index 6d813868835..3df6dece469 100644 --- a/src/app/qgisappinterface.h +++ b/src/app/qgisappinterface.h @@ -48,7 +48,7 @@ class QgisAppInterface : public QgisInterface //! Zoom map to previous extent void zoomToPrevious(); //! Zoom to active layer - void zoomActiveLayer(); + void zoomToActiveLayer(); //! Add a vector layer QgsVectorLayer* addVectorLayer( QString vectorLayerPath, QString baseName, QString providerKey ); diff --git a/src/core/qgsgeometry.cpp b/src/core/qgsgeometry.cpp index f1773033561..b2511e50dae 100644 --- a/src/core/qgsgeometry.cpp +++ b/src/core/qgsgeometry.cpp @@ -2993,6 +2993,132 @@ int QgsGeometry::translate( double dx, double dy ) return 0; } +int QgsGeometry::transform( QgsCoordinateTransform& ct ) +{ + if ( mDirtyWkb ) + { + exportGeosToWkb(); + } + + if ( !mGeometry ) + { + QgsDebugMsg( "WKB geometry not available!" ); + return 1; + } + + QGis::WKBTYPE wkbType; + memcpy( &wkbType, &( mGeometry[1] ), sizeof( int ) ); + bool hasZValue = false; + int wkbPosition = 5; + + switch ( wkbType ) + { + case QGis::WKBPoint25D: + case QGis::WKBPoint: + { + transformVertex( wkbPosition, ct, hasZValue ); + } + break; + + case QGis::WKBLineString25D: + hasZValue = true; + case QGis::WKBLineString: + { + int* npoints = ( int* )( &mGeometry[wkbPosition] ); + wkbPosition += sizeof( int ); + for ( int index = 0;index < *npoints;++index ) + { + transformVertex( wkbPosition, ct, hasZValue ); + } + break; + } + + case QGis::WKBPolygon25D: + hasZValue = true; + case QGis::WKBPolygon: + { + int* nrings = ( int* )( &( mGeometry[wkbPosition] ) ); + wkbPosition += sizeof( int ); + int* npoints; + + for ( int index = 0;index < *nrings;++index ) + { + npoints = ( int* )( &( mGeometry[wkbPosition] ) ); + wkbPosition += sizeof( int ); + for ( int index2 = 0;index2 < *npoints;++index2 ) + { + transformVertex( wkbPosition, ct, hasZValue ); + } + } + break; + } + + case QGis::WKBMultiPoint25D: + hasZValue = true; + case QGis::WKBMultiPoint: + { + int* npoints = ( int* )( &( mGeometry[wkbPosition] ) ); + wkbPosition += sizeof( int ); + for ( int index = 0;index < *npoints;++index ) + { + wkbPosition += ( sizeof( int ) + 1 ); + transformVertex( wkbPosition, ct, hasZValue ); + } + break; + } + + case QGis::WKBMultiLineString25D: + hasZValue = true; + case QGis::WKBMultiLineString: + { + int* nlines = ( int* )( &( mGeometry[wkbPosition] ) ); + int* npoints = 0; + wkbPosition += sizeof( int ); + for ( int index = 0;index < *nlines;++index ) + { + wkbPosition += ( sizeof( int ) + 1 ); + npoints = ( int* )( &( mGeometry[wkbPosition] ) ); + wkbPosition += sizeof( int ); + for ( int index2 = 0; index2 < *npoints; ++index2 ) + { + transformVertex( wkbPosition, ct, hasZValue ); + } + } + break; + } + + case QGis::WKBMultiPolygon25D: + hasZValue = true; + case QGis::WKBMultiPolygon: + { + int* npolys = ( int* )( &( mGeometry[wkbPosition] ) ); + int* nrings; + int* npoints; + wkbPosition += sizeof( int ); + for ( int index = 0;index < *npolys;++index ) + { + wkbPosition += ( 1 + sizeof( int ) ); //skip endian and polygon type + nrings = ( int* )( &( mGeometry[wkbPosition] ) ); + wkbPosition += sizeof( int ); + for ( int index2 = 0;index2 < *nrings;++index2 ) + { + npoints = ( int* )( &( mGeometry[wkbPosition] ) ); + wkbPosition += sizeof( int ); + for ( int index3 = 0;index3 < *npoints;++index3 ) + { + transformVertex( wkbPosition, ct, hasZValue ); + } + } + } + } + + default: + break; + } + mDirtyGeos = true; + return 0; +} + int QgsGeometry::splitGeometry( const QList& splitLine, QList& newGeometries ) { int returnCode = 0; @@ -4569,6 +4695,31 @@ void QgsGeometry::translateVertex( int& wkbPosition, double dx, double dy, bool } } +void QgsGeometry::transformVertex( int& wkbPosition, QgsCoordinateTransform& ct, bool hasZValue ) +{ + double x, y, z; + + + x = *(( double * )( &( mGeometry[wkbPosition] ) ) ); + y = *(( double * )( &( mGeometry[wkbPosition + sizeof( double )] ) ) ); + z = 0.0; // Ignore Z for now. + + ct.transformInPlace( x, y, z); + + // new x-coordinate + memcpy( &( mGeometry[wkbPosition] ), &x, sizeof( double ) ); + wkbPosition += sizeof( double ); + + // new y-coordinate + memcpy( &( mGeometry[wkbPosition] ), &y, sizeof( double ) ); + wkbPosition += sizeof( double ); + + if ( hasZValue ) + { + wkbPosition += sizeof( double ); + } +} + int QgsGeometry::splitLinearGeometry( GEOSGeometry *splitLine, QList& newGeometries ) { if ( !splitLine ) diff --git a/src/core/qgsgeometry.h b/src/core/qgsgeometry.h index 0144b1969eb..6c27e89620c 100644 --- a/src/core/qgsgeometry.h +++ b/src/core/qgsgeometry.h @@ -30,6 +30,7 @@ email : morb at ozemail dot com dot au #endif #include "qgspoint.h" +#include "qgscoordinatetransform.h" /** polyline is represented as a vector of points */ typedef QVector QgsPolyline; @@ -233,6 +234,10 @@ class CORE_EXPORT QgsGeometry @return 0 in case of success*/ int translate( double dx, double dy ); + /**Transform this geometry as described by CoordinateTranasform ct + @return 0 in case of success*/ + int transform( QgsCoordinateTransform& ct ); + /**Splits this geometry according to a given line. Note that the geometry is only splitted once. If there are several intersections between geometry and splitLine, only the first one is considered. @param splitLine the line that splits the geometry @@ -380,6 +385,13 @@ class CORE_EXPORT QgsGeometry @param hasZValue 25D type?*/ void translateVertex( int& wkbPosition, double dx, double dy, bool hasZValue ); + /**Transforms a single vertex by ct. + @param ptr pointer to the wkb fragment containing the vertex + @param wkbPosition position in wkb array. Is increased automatically by the function + @param ct the QgsCoordinateTransform + @param hasZValue 25D type?*/ + void transformVertex( int& wkbPosition, QgsCoordinateTransform& ct, bool hasZValue ); + //helper functions for geometry splitting /**Splits line/multiline geometries diff --git a/src/core/qgsvectorfilewriter.cpp b/src/core/qgsvectorfilewriter.cpp index 8db3bf6b87c..38e565c0643 100644 --- a/src/core/qgsvectorfilewriter.cpp +++ b/src/core/qgsvectorfilewriter.cpp @@ -294,18 +294,36 @@ QgsVectorFileWriter::WriterError QgsVectorFileWriter::writeAsShapefile( QgsVectorLayer* layer, const QString& shapefileName, const QString& fileEncoding, + const QgsCoordinateReferenceSystem* destCRS, bool onlySelected ) { - QgsVectorDataProvider* provider = layer->dataProvider(); + const QgsCoordinateReferenceSystem* outputCRS; + QgsCoordinateTransform* ct; + QgsVectorDataProvider* provider = layer->dataProvider(); + int shallTransform = false; + + if ( destCRS && destCRS->isValid() ) + { + // This means we should transform + outputCRS = destCRS; + shallTransform = true; + } else { + // This means we shouldn't transform, use source CRS as output (if defined) + outputCRS = &layer->srs(); + } QgsVectorFileWriter* writer = new QgsVectorFileWriter( shapefileName, - fileEncoding, provider->fields(), provider->geometryType(), &layer->srs() ); + fileEncoding, provider->fields(), provider->geometryType(), outputCRS ); // check whether file creation was successful WriterError err = writer->hasError(); if ( err != NoError ) { + if (ct != NULL) + { + delete ct; + } delete writer; return err; } @@ -317,17 +335,37 @@ QgsVectorFileWriter::writeAsShapefile( QgsVectorLayer* layer, const QgsFeatureIds& ids = layer->selectedFeaturesIds(); + // Create our transform + if (destCRS) + { + ct = new QgsCoordinateTransform(layer->srs(), *destCRS); + } + + // Check for failure + if (ct == NULL) + { + shallTransform = false; + } + // write all features while ( provider->getNextFeature( fet ) ) { if ( onlySelected && !ids.contains( fet.featureId() ) ) continue; + if ( shallTransform ) + { + fet.geometry()->transform(*ct); + } writer->addFeature( fet ); } delete writer; + if (shallTransform) + { + delete ct; + } return NoError; } diff --git a/src/core/qgsvectorfilewriter.h b/src/core/qgsvectorfilewriter.h index 9378fb8ccaf..abf9c18ce21 100644 --- a/src/core/qgsvectorfilewriter.h +++ b/src/core/qgsvectorfilewriter.h @@ -55,6 +55,7 @@ class CORE_EXPORT QgsVectorFileWriter static WriterError writeAsShapefile( QgsVectorLayer* layer, const QString& shapefileName, const QString& fileEncoding, + const QgsCoordinateReferenceSystem *destCRS, bool onlySelected = FALSE ); diff --git a/src/core/qgsvectorlayer.cpp b/src/core/qgsvectorlayer.cpp index 598582db430..4729d7829a8 100644 --- a/src/core/qgsvectorlayer.cpp +++ b/src/core/qgsvectorlayer.cpp @@ -3301,7 +3301,8 @@ void QgsVectorLayer::drawFeature( QPainter* p, transformPoint( x, y, theMapToPixelTransform, ct ); //QPointF pt(x - (marker->width()/2), y - (marker->height()/2)); //QPointF pt(x/markerScaleFactor - (marker->width()/2), y/markerScaleFactor - (marker->height()/2)); - QPointF pt( x, y ); + QPointF pt( x*rasterScaleFactor - ( marker->width() / 2 ), y*rasterScaleFactor - ( marker->height() / 2 ) ); + //QPointF pt( x, y ); #if defined(Q_WS_X11) // Work around a +/- 32768 limitation on coordinates in X11 diff --git a/src/gui/qgisinterface.h b/src/gui/qgisinterface.h index a58cad61f3c..08f905bbd33 100644 --- a/src/gui/qgisinterface.h +++ b/src/gui/qgisinterface.h @@ -66,7 +66,7 @@ class GUI_EXPORT QgisInterface : public QObject //! Zoom to previous view extent virtual void zoomToPrevious() = 0; //! Zoome to extent of the active layer - virtual void zoomActiveLayer() = 0; + virtual void zoomToActiveLayer() = 0; //! Add a vector layer virtual QgsVectorLayer* addVectorLayer( QString vectorLayerPath, QString baseName, QString providerKey ) = 0; diff --git a/src/plugins/gps_importer/qgsgpsplugin.cpp b/src/plugins/gps_importer/qgsgpsplugin.cpp index cca82f5b696..d93a07144a8 100644 --- a/src/plugins/gps_importer/qgsgpsplugin.cpp +++ b/src/plugins/gps_importer/qgsgpsplugin.cpp @@ -556,6 +556,8 @@ void QgsGPSPlugin::setupBabel() if ( mBabelPath.isEmpty() ) mBabelPath = "gpsbabel"; // the importable formats + mImporters["Shapefile"] = + new QgsSimpleBabelFormat( "shape", true, true, true ); mImporters["Geocaching.com .loc"] = new QgsSimpleBabelFormat( "geo", true, false, false ); mImporters["Magellan Mapsend"] =