raster creation moved from QgsGdalProvider::create() to GDAL provider extern C function

This commit is contained in:
Radim Blazek 2012-12-20 14:43:42 +01:00
parent c2aca4f268
commit d58d3476c0
7 changed files with 127 additions and 61 deletions

View File

@ -249,7 +249,9 @@ class QgsRasterDataProvider : QgsDataProvider, QgsRasterInterface
/** Creates a new dataset with mDataSourceURI /** Creates a new dataset with mDataSourceURI
@return true in case of success*/ @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, QGis::DataType type,
int width, int height, double* geoTransform, int width, int height, double* geoTransform,
const QgsCoordinateReferenceSystem& crs, const QgsCoordinateReferenceSystem& crs,

View File

@ -15,6 +15,7 @@
* * * *
***************************************************************************/ ***************************************************************************/
#include "qgsproviderregistry.h"
#include "qgsrasterdataprovider.h" #include "qgsrasterdataprovider.h"
#include "qgsrasterprojector.h" #include "qgsrasterprojector.h"
#include "qgslogger.h" #include "qgslogger.h"
@ -475,4 +476,30 @@ void QgsRasterDataProvider::setUserNoDataValue( int bandNo, QList<QgsRasterBlock
} }
} }
typedef QgsRasterDataProvider * createFunction_t( const QString&,
const QString&, int,
QGis::DataType,
int, int, double*,
const QgsCoordinateReferenceSystem&,
QStringList );
QgsRasterDataProvider* 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 )
{
createFunction_t *createFn = ( createFunction_t* ) cast_to_fptr( QgsProviderRegistry::instance()->function( 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 // ENDS

View File

@ -403,6 +403,7 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
/** Creates a new dataset with mDataSourceURI /** Creates a new dataset with mDataSourceURI
@return true in case of success*/ @return true in case of success*/
#if 0
virtual bool create( const QString& format, int nBands, virtual bool create( const QString& format, int nBands,
QGis::DataType type, QGis::DataType type,
int width, int height, double* geoTransform, int width, int height, double* geoTransform,
@ -419,6 +420,16 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
Q_UNUSED( createOptions ); Q_UNUSED( createOptions );
return false; 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 /** Set no data value on created dataset
* @param bandNo band number * @param bandNo band number

View File

@ -873,11 +873,11 @@ QgsRasterDataProvider* QgsRasterFileWriter::createPartProvider( const QgsRectang
QString outputFile = outputUrl + "/" + partFileName( fileIndex ); QString outputFile = outputUrl + "/" + partFileName( fileIndex );
//QgsRasterDataProvider* destProvider = QgsRasterLayer::loadProvider( mOutputProviderKey, outputFile ); //QgsRasterDataProvider* destProvider = QgsRasterLayer::loadProvider( mOutputProviderKey, outputFile );
QgsRasterDataProvider* destProvider = ( QgsRasterDataProvider* ) QgsProviderRegistry::instance()->provider( mOutputProviderKey, outputFile ); //QgsRasterDataProvider* destProvider = ( QgsRasterDataProvider* ) QgsProviderRegistry::instance()->provider( mOutputProviderKey, outputFile );
if ( !destProvider ) //if ( !destProvider )
{ //{
return 0; // return 0;
} //}
//geotransform //geotransform
double geoTransform[6]; double geoTransform[6];
@ -889,12 +889,29 @@ QgsRasterDataProvider* QgsRasterFileWriter::createPartProvider( const QgsRectang
geoTransform[5] = -mup; geoTransform[5] = -mup;
// perhaps we need a separate createOptions for tiles ? // 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; delete destProvider;
return 0; return 0;
} }
return destProvider; return destProvider;
} }
@ -909,24 +926,35 @@ QgsRasterDataProvider* QgsRasterFileWriter::initOutput( int nCols, int nRows, co
} }
else 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 // 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 // should this belong in provider? should also test that source provider is gdal
// if ( mBuildPyramidsFlag == -4 && mOutputProviderKey == "gdal" && mOutputFormat.toLower() == "gtiff" ) // if ( mBuildPyramidsFlag == -4 && mOutputProviderKey == "gdal" && mOutputFormat.toLower() == "gtiff" )
// mCreateOptions << "COPY_SRC_OVERVIEWS=YES"; // mCreateOptions << "COPY_SRC_OVERVIEWS=YES";
if ( !destProvider->create( mOutputFormat, nBands, type, nCols, nRows, geoTransform, //QgsRasterDataProvider* destProvider = QgsRasterLayer::loadProvider( mOutputProviderKey, mOutputUrl );
crs, mCreateOptions ) ) //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; delete destProvider;
return 0; return 0;
} }
/*
if ( !destProvider->create( mOutputFormat, nBands, type, nCols, nRows, geoTransform,
crs, mCreateOptions ) )
{
delete destProvider;
return 0;
}
*/
return destProvider; return destProvider;
} }
} }

View File

@ -92,10 +92,17 @@ int CPL_STDCALL progressCallback( double dfComplete,
return true; 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 ) : QgsRasterDataProvider( uri )
, QgsGdalProviderBase() , QgsGdalProviderBase()
, mUpdate( update )
, mValid( true ) , mValid( true )
{ {
QgsDebugMsg( "QgsGdalProvider: constructing with uri '" + uri + "'." ); QgsDebugMsg( "QgsGdalProvider: constructing with uri '" + uri + "'." );
@ -126,28 +133,11 @@ QgsGdalProvider::QgsGdalProvider( QString const & uri )
setDataSourceUri( vsiPrefix + uri ); setDataSourceUri( vsiPrefix + uri );
QgsDebugMsg( QString( "Trying %1 syntax, uri= %2" ).arg( vsiPrefix ).arg( dataSourceUri() ) ); 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(); QString gdalUri = dataSourceUri();
CPLErrorReset(); CPLErrorReset();
mGdalBaseDataset = GDALOpen( TO8F( gdalUri ), GA_ReadOnly ); mGdalBaseDataset = GDALOpen( TO8F( gdalUri ), mUpdate ? GA_Update : GA_ReadOnly );
if ( !mGdalBaseDataset ) if ( !mGdalBaseDataset )
{ {
@ -1481,7 +1471,7 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste
//something bad happenend //something bad happenend
//QString myString = QString (CPLGetLastError()); //QString myString = QString (CPLGetLastError());
GDALClose( mGdalBaseDataset ); 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 //Since we are not a virtual warped dataset, mGdalDataSet and mGdalBaseDataset are supposed to be the same
mGdalDataset = mGdalBaseDataset; mGdalDataset = mGdalBaseDataset;
@ -1523,7 +1513,7 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste
QgsDebugMsg( "Reopening dataset ..." ); QgsDebugMsg( "Reopening dataset ..." );
//close the gdal dataset and reopen it in read only mode //close the gdal dataset and reopen it in read only mode
GDALClose( mGdalBaseDataset ); 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 //Since we are not a virtual warped dataset, mGdalDataSet and mGdalBaseDataset are supposed to be the same
mGdalDataset = mGdalBaseDataset; mGdalDataset = mGdalBaseDataset;
} }
@ -2401,17 +2391,27 @@ char** papszFromStringList( const QStringList& list )
return papszRetList; return papszRetList;
} }
#if 0
bool QgsGdalProvider::create( const QString& format, int nBands, bool QgsGdalProvider::create( const QString& format, int nBands,
QGis::DataType type, QGis::DataType type,
int width, int height, double* geoTransform, int width, int height, double* geoTransform,
const QgsCoordinateReferenceSystem& crs, const QgsCoordinateReferenceSystem& crs,
QStringList createOptions ) 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 //get driver
GDALDriverH driver = GDALGetDriverByName( format.toLocal8Bit().data() ); GDALDriverH driver = GDALGetDriverByName( format.toLocal8Bit().data() );
if ( !driver ) if ( !driver )
{ {
return false; QgsError error( "Cannot load GDAL driver " + format, "GDAL provider" );
return new QgsGdalProvider( uri, error );
} }
QString tmpStr = "create options:"; QString tmpStr = "create options:";
@ -2420,27 +2420,21 @@ bool QgsGdalProvider::create( const QString& format, int nBands,
QgsDebugMsg( tmpStr ); QgsDebugMsg( tmpStr );
//create dataset //create dataset
CPLErrorReset();
char **papszOptions = papszFromStringList( createOptions ); 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 ); CSLDestroy( papszOptions );
if ( dataset == NULL ) 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]; GDALSetGeoTransform( dataset, geoTransform );
mGeoTransform[1] = geoTransform[1];
mGeoTransform[2] = geoTransform[2];
mGeoTransform[3] = geoTransform[3];
mGeoTransform[4] = geoTransform[4];
mGeoTransform[5] = geoTransform[5];
GDALSetGeoTransform( dataset, mGeoTransform );
GDALSetProjection( dataset, crs.toWkt().toLocal8Bit().data() ); GDALSetProjection( dataset, crs.toWkt().toLocal8Bit().data() );
GDALClose( dataset );
mGdalBaseDataset = dataset; return new QgsGdalProvider( uri, true );
initBaseDataset();
return mValid;
} }
bool QgsGdalProvider::write( void* data, int band, int width, int height, int xOffset, int yOffset ) bool QgsGdalProvider::write( void* data, int band, int width, int height, int xOffset, int yOffset )

View File

@ -65,7 +65,10 @@ class QgsGdalProvider : public QgsRasterDataProvider, QgsGdalProviderBase
* otherwise we contact the host directly. * 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 //! Destructor
~QgsGdalProvider(); ~QgsGdalProvider();
@ -234,11 +237,13 @@ class QgsGdalProvider : public QgsRasterDataProvider, QgsGdalProviderBase
/** Creates a new dataset with mDataSourceURI /** Creates a new dataset with mDataSourceURI
@return true in case of success*/ @return true in case of success*/
/*
bool create( const QString& format, int nBands, bool create( const QString& format, int nBands,
QGis::DataType type, QGis::DataType type,
int width, int height, double* geoTransform, int width, int height, double* geoTransform,
const QgsCoordinateReferenceSystem& crs, const QgsCoordinateReferenceSystem& crs,
QStringList createOptions = QStringList() ); QStringList createOptions = QStringList() );
*/
/**Writes into the provider datasource*/ /**Writes into the provider datasource*/
bool write( void* data, int band, int width, int height, int xOffset, int yOffset ); 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 ); void statusChanged( QString );
private: private:
// update mode
bool mUpdate;
// initialize CRS from wkt // initialize CRS from wkt
bool crsFromWkt( const char *wkt ); bool crsFromWkt( const char *wkt );

View File

@ -573,12 +573,6 @@ int QgsGrassGisLib::G_open_raster_new( const char *name, RASTER_MAP_TYPE wr_type
raster.name = name; raster.name = name;
//raster.writer = new QgsRasterFileWriter( dataSource ); //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"; QString outputFormat = "GTiff";
int nBands = 1; int nBands = 1;
QGis::DataType type = qgisRasterType( wr_type ); 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[4] = 0.0;
geoTransform[5] = -1. * mExtent.height() / mRows; 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 ); fatal( "Cannot create output data source: " + dataSource );
} }
raster.band = 1; raster.band = 1;
double noDataValue = std::numeric_limits<double>::quiet_NaN(); double noDataValue = std::numeric_limits<double>::quiet_NaN();
switch ( wr_type ) switch ( wr_type )