From d58d3476c095d0753465b772efbc17b1b24dfd5c Mon Sep 17 00:00:00 2001 From: Radim Blazek Date: Thu, 20 Dec 2012 14:43:42 +0100 Subject: [PATCH] raster creation moved from QgsGdalProvider::create() to GDAL provider extern C function --- python/core/raster/qgsrasterdataprovider.sip | 4 +- src/core/raster/qgsrasterdataprovider.cpp | 27 +++++++++ src/core/raster/qgsrasterdataprovider.h | 11 ++++ src/core/raster/qgsrasterfilewriter.cpp | 60 +++++++++++++----- src/providers/gdal/qgsgdalprovider.cpp | 64 +++++++++----------- src/providers/gdal/qgsgdalprovider.h | 10 ++- src/providers/grass/qgsgrassgislib.cpp | 12 ++-- 7 files changed, 127 insertions(+), 61 deletions(-) diff --git a/python/core/raster/qgsrasterdataprovider.sip b/python/core/raster/qgsrasterdataprovider.sip index 65626d467de..7ffac6ed7a3 100644 --- a/python/core/raster/qgsrasterdataprovider.sip +++ b/python/core/raster/qgsrasterdataprovider.sip @@ -249,7 +249,9 @@ class QgsRasterDataProvider : QgsDataProvider, QgsRasterInterface /** Creates a new dataset with mDataSourceURI @return true in case of success*/ - virtual bool create( const QString& format, int nBands, + static QgsRasterDataProvider* create( const QString &providerKey, + const QString &uri, + const QString& format, int nBands, QGis::DataType type, int width, int height, double* geoTransform, const QgsCoordinateReferenceSystem& crs, diff --git a/src/core/raster/qgsrasterdataprovider.cpp b/src/core/raster/qgsrasterdataprovider.cpp index b6eaa18d3c8..6c682e0686a 100644 --- a/src/core/raster/qgsrasterdataprovider.cpp +++ b/src/core/raster/qgsrasterdataprovider.cpp @@ -15,6 +15,7 @@ * * ***************************************************************************/ +#include "qgsproviderregistry.h" #include "qgsrasterdataprovider.h" #include "qgsrasterprojector.h" #include "qgslogger.h" @@ -475,4 +476,30 @@ void QgsRasterDataProvider::setUserNoDataValue( int bandNo, QListfunction( providerKey, "create" ) ); + if ( !createFn ) + { + QgsDebugMsg( "Cannot resolve 'create' function in " + providerKey + " provider" ); + // TODO: it would be good to return invalid QgsRasterDataProvider + // with QgsError set, but QgsRasterDataProvider has pure virtual methods + return 0; + } + return createFn( uri, format, nBands, type, width, height, geoTransform, crs, createOptions ); +} + // ENDS diff --git a/src/core/raster/qgsrasterdataprovider.h b/src/core/raster/qgsrasterdataprovider.h index fe4a6aab370..2791d4cc5b6 100644 --- a/src/core/raster/qgsrasterdataprovider.h +++ b/src/core/raster/qgsrasterdataprovider.h @@ -403,6 +403,7 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast /** Creates a new dataset with mDataSourceURI @return true in case of success*/ +#if 0 virtual bool create( const QString& format, int nBands, QGis::DataType type, int width, int height, double* geoTransform, @@ -419,6 +420,16 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast Q_UNUSED( createOptions ); return false; } +#endif + + static QgsRasterDataProvider* create( const QString &providerKey, + const QString &uri, + const QString& format, int nBands, + QGis::DataType type, + int width, int height, double* geoTransform, + const QgsCoordinateReferenceSystem& crs, + QStringList createOptions = QStringList() ); + /** Set no data value on created dataset * @param bandNo band number diff --git a/src/core/raster/qgsrasterfilewriter.cpp b/src/core/raster/qgsrasterfilewriter.cpp index e83b1f6d223..66ad3a66757 100644 --- a/src/core/raster/qgsrasterfilewriter.cpp +++ b/src/core/raster/qgsrasterfilewriter.cpp @@ -873,11 +873,11 @@ QgsRasterDataProvider* QgsRasterFileWriter::createPartProvider( const QgsRectang QString outputFile = outputUrl + "/" + partFileName( fileIndex ); //QgsRasterDataProvider* destProvider = QgsRasterLayer::loadProvider( mOutputProviderKey, outputFile ); - QgsRasterDataProvider* destProvider = ( QgsRasterDataProvider* ) QgsProviderRegistry::instance()->provider( mOutputProviderKey, outputFile ); - if ( !destProvider ) - { - return 0; - } + //QgsRasterDataProvider* destProvider = ( QgsRasterDataProvider* ) QgsProviderRegistry::instance()->provider( mOutputProviderKey, outputFile ); + //if ( !destProvider ) + //{ + // return 0; + //} //geotransform double geoTransform[6]; @@ -889,12 +889,29 @@ QgsRasterDataProvider* QgsRasterFileWriter::createPartProvider( const QgsRectang geoTransform[5] = -mup; // perhaps we need a separate createOptions for tiles ? - if ( !destProvider->create( mOutputFormat, nBands, type, iterCols, iterRows, geoTransform, - crs ) ) + /* + if ( !destProvider->create( mOutputFormat, nBands, type, iterCols, iterRows, geoTransform, + crs ) ) + { + delete destProvider; + return 0; + } + */ + + QgsRasterDataProvider* destProvider = QgsRasterDataProvider::create( mOutputProviderKey, mOutputUrl, mOutputFormat, nBands, type, iterCols, iterRows, geoTransform, crs, mCreateOptions ) ; + + if ( !destProvider ) + { + return 0; + } + + // TODO: return provider and report error + if ( !destProvider->isValid() ) { delete destProvider; return 0; } + return destProvider; } @@ -909,24 +926,35 @@ QgsRasterDataProvider* QgsRasterFileWriter::initOutput( int nCols, int nRows, co } else { - //QgsRasterDataProvider* destProvider = QgsRasterLayer::loadProvider( mOutputProviderKey, mOutputUrl ); - QgsRasterDataProvider* destProvider = ( QgsRasterDataProvider* ) QgsProviderRegistry::instance()->provider( mOutputProviderKey, mOutputUrl ); - if ( !destProvider ) - { - return 0; - } - // TODO enable "use existing", has no effect for now, because using Create() in gdal provider // should this belong in provider? should also test that source provider is gdal // if ( mBuildPyramidsFlag == -4 && mOutputProviderKey == "gdal" && mOutputFormat.toLower() == "gtiff" ) // mCreateOptions << "COPY_SRC_OVERVIEWS=YES"; - if ( !destProvider->create( mOutputFormat, nBands, type, nCols, nRows, geoTransform, - crs, mCreateOptions ) ) + //QgsRasterDataProvider* destProvider = QgsRasterLayer::loadProvider( mOutputProviderKey, mOutputUrl ); + //QgsRasterDataProvider* destProvider = ( QgsRasterDataProvider* ) QgsProviderRegistry::instance()->provider( mOutputProviderKey, mOutputUrl ); + QgsRasterDataProvider* destProvider = QgsRasterDataProvider::create( mOutputProviderKey, mOutputUrl, mOutputFormat, nBands, type, nCols, nRows, geoTransform, crs, mCreateOptions ) ; + + if ( !destProvider ) + { + return 0; + } + + // TODO: return provider and report error + if ( !destProvider->isValid() ) { delete destProvider; return 0; } + + /* + if ( !destProvider->create( mOutputFormat, nBands, type, nCols, nRows, geoTransform, + crs, mCreateOptions ) ) + { + delete destProvider; + return 0; + } + */ return destProvider; } } diff --git a/src/providers/gdal/qgsgdalprovider.cpp b/src/providers/gdal/qgsgdalprovider.cpp index c0118ed3155..8a2ffb159c7 100644 --- a/src/providers/gdal/qgsgdalprovider.cpp +++ b/src/providers/gdal/qgsgdalprovider.cpp @@ -92,10 +92,17 @@ int CPL_STDCALL progressCallback( double dfComplete, return true; } +QgsGdalProvider::QgsGdalProvider( QString const & uri, QgsError error ) + : QgsRasterDataProvider( uri ) + , mValid( false ) +{ + setError( error ); +} -QgsGdalProvider::QgsGdalProvider( QString const & uri ) +QgsGdalProvider::QgsGdalProvider( QString const & uri, bool update ) : QgsRasterDataProvider( uri ) , QgsGdalProviderBase() + , mUpdate( update ) , mValid( true ) { QgsDebugMsg( "QgsGdalProvider: constructing with uri '" + uri + "'." ); @@ -126,28 +133,11 @@ QgsGdalProvider::QgsGdalProvider( QString const & uri ) setDataSourceUri( vsiPrefix + uri ); QgsDebugMsg( QString( "Trying %1 syntax, uri= %2" ).arg( vsiPrefix ).arg( dataSourceUri() ) ); } - else - { - // TODO: this constructor is also called for new rasters, in that case GDAL prints error: - // "ERROR 4: `pok.tif' does not exist in the file system, and is not recognised as a supported dataset name." - // To avoid this message, we test first if the file exists at all. - // This should be done better adding static create() method or something like that - // TODO: Cannot test for file existence, for example NetCDF with sublayers - // is using URI: NETCDF:"/path/to/file.cdf":layer1 - /* - if ( !QFile::exists( uri ) ) - { - QString msg = QString( "File does not exist: %1" ).arg( dataSourceUri() ); - appendError( ERR( msg ) ); - return; - } - */ - } QString gdalUri = dataSourceUri(); CPLErrorReset(); - mGdalBaseDataset = GDALOpen( TO8F( gdalUri ), GA_ReadOnly ); + mGdalBaseDataset = GDALOpen( TO8F( gdalUri ), mUpdate ? GA_Update : GA_ReadOnly ); if ( !mGdalBaseDataset ) { @@ -1481,7 +1471,7 @@ QString QgsGdalProvider::buildPyramids( QList const & theRaste //something bad happenend //QString myString = QString (CPLGetLastError()); GDALClose( mGdalBaseDataset ); - mGdalBaseDataset = GDALOpen( TO8F( dataSourceUri() ), GA_ReadOnly ); + mGdalBaseDataset = GDALOpen( TO8F( dataSourceUri() ), mUpdate ? GA_Update : GA_ReadOnly ); //Since we are not a virtual warped dataset, mGdalDataSet and mGdalBaseDataset are supposed to be the same mGdalDataset = mGdalBaseDataset; @@ -1523,7 +1513,7 @@ QString QgsGdalProvider::buildPyramids( QList const & theRaste QgsDebugMsg( "Reopening dataset ..." ); //close the gdal dataset and reopen it in read only mode GDALClose( mGdalBaseDataset ); - mGdalBaseDataset = GDALOpen( TO8F( dataSourceUri() ), GA_ReadOnly ); + mGdalBaseDataset = GDALOpen( TO8F( dataSourceUri() ), mUpdate ? GA_Update : GA_ReadOnly ); //Since we are not a virtual warped dataset, mGdalDataSet and mGdalBaseDataset are supposed to be the same mGdalDataset = mGdalBaseDataset; } @@ -2401,17 +2391,27 @@ char** papszFromStringList( const QStringList& list ) return papszRetList; } +#if 0 bool QgsGdalProvider::create( const QString& format, int nBands, QGis::DataType type, int width, int height, double* geoTransform, const QgsCoordinateReferenceSystem& crs, QStringList createOptions ) +#endif +QGISEXTERN QgsGdalProvider * create( + const QString &uri, + const QString& format, int nBands, + QGis::DataType type, + int width, int height, double* geoTransform, + const QgsCoordinateReferenceSystem& crs, + QStringList createOptions ) { //get driver GDALDriverH driver = GDALGetDriverByName( format.toLocal8Bit().data() ); if ( !driver ) { - return false; + QgsError error( "Cannot load GDAL driver " + format, "GDAL provider" ); + return new QgsGdalProvider( uri, error ); } QString tmpStr = "create options:"; @@ -2420,27 +2420,21 @@ bool QgsGdalProvider::create( const QString& format, int nBands, QgsDebugMsg( tmpStr ); //create dataset + CPLErrorReset(); char **papszOptions = papszFromStringList( createOptions ); - GDALDatasetH dataset = GDALCreate( driver, dataSourceUri().toLocal8Bit().data(), width, height, nBands, ( GDALDataType )type, papszOptions ); + GDALDatasetH dataset = GDALCreate( driver, uri.toLocal8Bit().data(), width, height, nBands, ( GDALDataType )type, papszOptions ); CSLDestroy( papszOptions ); if ( dataset == NULL ) { - return false; + QgsError error( QString( "Cannot create new dataset %1:\n%2" ).arg( uri ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ), "GDAL provider" ); + return new QgsGdalProvider( uri, error ); } - mGeoTransform[0] = geoTransform[0]; - mGeoTransform[1] = geoTransform[1]; - mGeoTransform[2] = geoTransform[2]; - mGeoTransform[3] = geoTransform[3]; - mGeoTransform[4] = geoTransform[4]; - mGeoTransform[5] = geoTransform[5]; - - GDALSetGeoTransform( dataset, mGeoTransform ); + GDALSetGeoTransform( dataset, geoTransform ); GDALSetProjection( dataset, crs.toWkt().toLocal8Bit().data() ); + GDALClose( dataset ); - mGdalBaseDataset = dataset; - initBaseDataset(); - return mValid; + return new QgsGdalProvider( uri, true ); } bool QgsGdalProvider::write( void* data, int band, int width, int height, int xOffset, int yOffset ) diff --git a/src/providers/gdal/qgsgdalprovider.h b/src/providers/gdal/qgsgdalprovider.h index 58e5000ec19..1efa02f2913 100644 --- a/src/providers/gdal/qgsgdalprovider.h +++ b/src/providers/gdal/qgsgdalprovider.h @@ -65,7 +65,10 @@ class QgsGdalProvider : public QgsRasterDataProvider, QgsGdalProviderBase * otherwise we contact the host directly. * */ - QgsGdalProvider( QString const & uri = 0 ); + QgsGdalProvider( QString const & uri = 0, bool update = false ); + + /** Create invalid provider with error */ + QgsGdalProvider( QString const & uri, QgsError error ); //! Destructor ~QgsGdalProvider(); @@ -234,11 +237,13 @@ class QgsGdalProvider : public QgsRasterDataProvider, QgsGdalProviderBase /** Creates a new dataset with mDataSourceURI @return true in case of success*/ + /* bool create( const QString& format, int nBands, QGis::DataType type, int width, int height, double* geoTransform, const QgsCoordinateReferenceSystem& crs, QStringList createOptions = QStringList() ); + */ /**Writes into the provider datasource*/ bool write( void* data, int band, int width, int height, int xOffset, int yOffset ); @@ -257,6 +262,9 @@ class QgsGdalProvider : public QgsRasterDataProvider, QgsGdalProviderBase void statusChanged( QString ); private: + // update mode + bool mUpdate; + // initialize CRS from wkt bool crsFromWkt( const char *wkt ); diff --git a/src/providers/grass/qgsgrassgislib.cpp b/src/providers/grass/qgsgrassgislib.cpp index 1421cd9fb83..067c9b8bc7b 100644 --- a/src/providers/grass/qgsgrassgislib.cpp +++ b/src/providers/grass/qgsgrassgislib.cpp @@ -573,12 +573,6 @@ int QgsGrassGisLib::G_open_raster_new( const char *name, RASTER_MAP_TYPE wr_type raster.name = name; //raster.writer = new QgsRasterFileWriter( dataSource ); - raster.provider = ( QgsRasterDataProvider* )QgsProviderRegistry::instance()->provider( providerKey, dataSource ); - if ( !raster.provider ) - { - fatal( "Cannot load raster provider with data source: " + dataSource ); - } - QString outputFormat = "GTiff"; int nBands = 1; QGis::DataType type = qgisRasterType( wr_type ); @@ -591,11 +585,13 @@ int QgsGrassGisLib::G_open_raster_new( const char *name, RASTER_MAP_TYPE wr_type geoTransform[4] = 0.0; geoTransform[5] = -1. * mExtent.height() / mRows; - if ( !raster.provider->create( outputFormat, nBands, type, mColumns, mRows, geoTransform, mCrs ) ) + raster.provider = QgsRasterDataProvider::create( providerKey, dataSource, outputFormat, nBands, type, mColumns, mRows, geoTransform, mCrs ); + if ( !raster.provider || !raster.provider->isValid() ) { - delete raster.provider; + if ( raster.provider ) delete raster.provider; fatal( "Cannot create output data source: " + dataSource ); } + raster.band = 1; double noDataValue = std::numeric_limits::quiet_NaN(); switch ( wr_type )