Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgsrasterdataprovider.cpp - DataProvider Interface for raster layers
3 : : --------------------------------------
4 : : Date : Mar 11, 2005
5 : : Copyright : (C) 2005 by Brendan Morley
6 : : email : morb at ozemail dot com dot au
7 : : ***************************************************************************/
8 : :
9 : : /***************************************************************************
10 : : * *
11 : : * This program is free software; you can redistribute it and/or modify *
12 : : * it under the terms of the GNU General Public License as published by *
13 : : * the Free Software Foundation; either version 2 of the License, or *
14 : : * (at your option) any later version. *
15 : : * *
16 : : ***************************************************************************/
17 : :
18 : : #include "qgsproviderregistry.h"
19 : : #include "qgsrasterdataprovider.h"
20 : : #include "qgsrasteridentifyresult.h"
21 : : #include "qgsprovidermetadata.h"
22 : : #include "qgsrasterprojector.h"
23 : : #include "qgslogger.h"
24 : : #include "qgsmessagelog.h"
25 : : #include "qgsapplication.h"
26 : :
27 : : #include <QTime>
28 : : #include <QMap>
29 : : #include <QByteArray>
30 : : #include <QVariant>
31 : :
32 : : #define ERR(message) QgsError(message, "Raster provider")
33 : :
34 : 0 : void QgsRasterDataProvider::setUseSourceNoDataValue( int bandNo, bool use )
35 : : {
36 : 0 : if ( mUseSrcNoDataValue.size() < bandNo )
37 : : {
38 : 0 : for ( int i = mUseSrcNoDataValue.size(); i < bandNo; i++ )
39 : : {
40 : 0 : mUseSrcNoDataValue.append( false );
41 : 0 : }
42 : 0 : }
43 : 0 : mUseSrcNoDataValue[bandNo - 1] = use;
44 : 0 : }
45 : :
46 : 0 : QgsRasterBlock *QgsRasterDataProvider::block( int bandNo, QgsRectangle const &boundingBox, int width, int height, QgsRasterBlockFeedback *feedback )
47 : : {
48 : 0 : QgsDebugMsgLevel( QStringLiteral( "bandNo = %1 width = %2 height = %3" ).arg( bandNo ).arg( width ).arg( height ), 4 );
49 : 0 : QgsDebugMsgLevel( QStringLiteral( "boundingBox = %1" ).arg( boundingBox.toString() ), 4 );
50 : :
51 : 0 : std::unique_ptr< QgsRasterBlock > block = std::make_unique< QgsRasterBlock >( dataType( bandNo ), width, height );
52 : 0 : if ( sourceHasNoDataValue( bandNo ) && useSourceNoDataValue( bandNo ) )
53 : : {
54 : 0 : block->setNoDataValue( sourceNoDataValue( bandNo ) );
55 : 0 : }
56 : :
57 : 0 : if ( block->isEmpty() )
58 : : {
59 : 0 : QgsDebugMsg( QStringLiteral( "Couldn't create raster block" ) );
60 : 0 : block->setError( { tr( "Couldn't create raster block." ), QStringLiteral( "Raster" ) } );
61 : 0 : block->setValid( false );
62 : 0 : return block.release();
63 : : }
64 : :
65 : : // Read necessary extent only
66 : 0 : QgsRectangle tmpExtent = boundingBox;
67 : :
68 : 0 : if ( tmpExtent.isEmpty() )
69 : : {
70 : 0 : QgsDebugMsg( QStringLiteral( "Extent outside provider extent" ) );
71 : 0 : block->setError( { tr( "Extent outside provider extent." ), QStringLiteral( "Raster" ) } );
72 : 0 : block->setValid( false );
73 : 0 : block->setIsNoData();
74 : 0 : return block.release();
75 : : }
76 : :
77 : 0 : double xRes = boundingBox.width() / width;
78 : 0 : double yRes = boundingBox.height() / height;
79 : : double tmpXRes, tmpYRes;
80 : 0 : double providerXRes = 0;
81 : 0 : double providerYRes = 0;
82 : 0 : if ( capabilities() & Size )
83 : : {
84 : 0 : providerXRes = extent().width() / xSize();
85 : 0 : providerYRes = extent().height() / ySize();
86 : 0 : tmpXRes = std::max( providerXRes, xRes );
87 : 0 : tmpYRes = std::max( providerYRes, yRes );
88 : 0 : if ( qgsDoubleNear( tmpXRes, xRes ) ) tmpXRes = xRes;
89 : 0 : if ( qgsDoubleNear( tmpYRes, yRes ) ) tmpYRes = yRes;
90 : 0 : }
91 : : else
92 : : {
93 : 0 : tmpXRes = xRes;
94 : 0 : tmpYRes = yRes;
95 : : }
96 : :
97 : 0 : if ( tmpExtent != boundingBox ||
98 : 0 : tmpXRes > xRes || tmpYRes > yRes )
99 : : {
100 : : // Read smaller extent or lower resolution
101 : :
102 : 0 : if ( !extent().contains( boundingBox ) )
103 : : {
104 : 0 : QRect subRect = QgsRasterBlock::subRect( boundingBox, width, height, extent() );
105 : 0 : block->setIsNoDataExcept( subRect );
106 : 0 : }
107 : :
108 : : // Calculate row/col limits (before tmpExtent is aligned)
109 : 0 : int fromRow = std::round( ( boundingBox.yMaximum() - tmpExtent.yMaximum() ) / yRes );
110 : 0 : int toRow = std::round( ( boundingBox.yMaximum() - tmpExtent.yMinimum() ) / yRes ) - 1;
111 : 0 : int fromCol = std::round( ( tmpExtent.xMinimum() - boundingBox.xMinimum() ) / xRes );
112 : 0 : int toCol = std::round( ( tmpExtent.xMaximum() - boundingBox.xMinimum() ) / xRes ) - 1;
113 : :
114 : 0 : QgsDebugMsgLevel( QStringLiteral( "fromRow = %1 toRow = %2 fromCol = %3 toCol = %4" ).arg( fromRow ).arg( toRow ).arg( fromCol ).arg( toCol ), 4 );
115 : :
116 : 0 : if ( fromRow < 0 || fromRow >= height || toRow < 0 || toRow >= height ||
117 : 0 : fromCol < 0 || fromCol >= width || toCol < 0 || toCol >= width )
118 : : {
119 : : // Should not happen
120 : 0 : QgsDebugMsg( QStringLiteral( "Row or column limits out of range" ) );
121 : 0 : block->setError( { tr( "Row or column limits out of range" ), QStringLiteral( "Raster" ) } );
122 : 0 : block->setValid( false );
123 : 0 : return block.release();
124 : : }
125 : :
126 : : // If lower source resolution is used, the extent must be aligned to original
127 : : // resolution to avoid possible shift due to resampling
128 : 0 : if ( tmpXRes > xRes )
129 : : {
130 : 0 : int col = std::floor( ( tmpExtent.xMinimum() - extent().xMinimum() ) / providerXRes );
131 : 0 : tmpExtent.setXMinimum( extent().xMinimum() + col * providerXRes );
132 : 0 : col = std::ceil( ( tmpExtent.xMaximum() - extent().xMinimum() ) / providerXRes );
133 : 0 : tmpExtent.setXMaximum( extent().xMinimum() + col * providerXRes );
134 : 0 : }
135 : 0 : if ( tmpYRes > yRes )
136 : : {
137 : 0 : int row = std::floor( ( extent().yMaximum() - tmpExtent.yMaximum() ) / providerYRes );
138 : 0 : tmpExtent.setYMaximum( extent().yMaximum() - row * providerYRes );
139 : 0 : row = std::ceil( ( extent().yMaximum() - tmpExtent.yMinimum() ) / providerYRes );
140 : 0 : tmpExtent.setYMinimum( extent().yMaximum() - row * providerYRes );
141 : 0 : }
142 : 0 : int tmpWidth = std::round( tmpExtent.width() / tmpXRes );
143 : 0 : int tmpHeight = std::round( tmpExtent.height() / tmpYRes );
144 : 0 : tmpXRes = tmpExtent.width() / tmpWidth;
145 : 0 : tmpYRes = tmpExtent.height() / tmpHeight;
146 : :
147 : 0 : QgsDebugMsgLevel( QStringLiteral( "Reading smaller block tmpWidth = %1 height = %2" ).arg( tmpWidth ).arg( tmpHeight ), 4 );
148 : 0 : QgsDebugMsgLevel( QStringLiteral( "tmpExtent = %1" ).arg( tmpExtent.toString() ), 4 );
149 : :
150 : 0 : std::unique_ptr< QgsRasterBlock > tmpBlock = std::make_unique< QgsRasterBlock >( dataType( bandNo ), tmpWidth, tmpHeight );
151 : 0 : if ( sourceHasNoDataValue( bandNo ) && useSourceNoDataValue( bandNo ) )
152 : : {
153 : 0 : tmpBlock->setNoDataValue( sourceNoDataValue( bandNo ) );
154 : 0 : }
155 : :
156 : 0 : if ( !readBlock( bandNo, tmpExtent, tmpWidth, tmpHeight, tmpBlock->bits(), feedback ) )
157 : : {
158 : 0 : QgsDebugMsg( QStringLiteral( "Error occurred while reading block" ) );
159 : 0 : block->setError( { tr( "Error occurred while reading block." ), QStringLiteral( "Raster" ) } );
160 : 0 : block->setValid( false );
161 : 0 : block->setIsNoData();
162 : 0 : return block.release();
163 : : }
164 : :
165 : 0 : int pixelSize = dataTypeSize( bandNo );
166 : :
167 : 0 : double xMin = boundingBox.xMinimum();
168 : 0 : double yMax = boundingBox.yMaximum();
169 : 0 : double tmpXMin = tmpExtent.xMinimum();
170 : 0 : double tmpYMax = tmpExtent.yMaximum();
171 : :
172 : 0 : for ( int row = fromRow; row <= toRow; row++ )
173 : : {
174 : 0 : double y = yMax - ( row + 0.5 ) * yRes;
175 : 0 : int tmpRow = std::floor( ( tmpYMax - y ) / tmpYRes );
176 : :
177 : 0 : for ( int col = fromCol; col <= toCol; col++ )
178 : : {
179 : 0 : double x = xMin + ( col + 0.5 ) * xRes;
180 : 0 : int tmpCol = std::floor( ( x - tmpXMin ) / tmpXRes );
181 : :
182 : 0 : if ( tmpRow < 0 || tmpRow >= tmpHeight || tmpCol < 0 || tmpCol >= tmpWidth )
183 : : {
184 : 0 : QgsDebugMsg( QStringLiteral( "Source row or column limits out of range" ) );
185 : 0 : block->setIsNoData(); // so that the problem becomes obvious and fixed
186 : 0 : block->setError( { tr( "Source row or column limits out of range." ), QStringLiteral( "Raster" ) } );
187 : 0 : block->setValid( false );
188 : 0 : return block.release();
189 : : }
190 : :
191 : 0 : qgssize tmpIndex = static_cast< qgssize >( tmpRow ) * static_cast< qgssize >( tmpWidth ) + tmpCol;
192 : 0 : qgssize index = row * static_cast< qgssize >( width ) + col;
193 : :
194 : 0 : char *tmpBits = tmpBlock->bits( tmpIndex );
195 : 0 : char *bits = block->bits( index );
196 : 0 : if ( !tmpBits )
197 : : {
198 : 0 : QgsDebugMsg( QStringLiteral( "Cannot get input block data tmpRow = %1 tmpCol = %2 tmpIndex = %3." ).arg( tmpRow ).arg( tmpCol ).arg( tmpIndex ) );
199 : 0 : continue;
200 : : }
201 : 0 : if ( !bits )
202 : : {
203 : 0 : QgsDebugMsg( QStringLiteral( "Cannot set output block data." ) );
204 : 0 : continue;
205 : : }
206 : 0 : memcpy( bits, tmpBits, pixelSize );
207 : 0 : }
208 : 0 : }
209 : 0 : }
210 : : else
211 : : {
212 : 0 : if ( !readBlock( bandNo, boundingBox, width, height, block->bits(), feedback ) )
213 : : {
214 : 0 : QgsDebugMsg( QStringLiteral( "Error occurred while reading block" ) );
215 : 0 : block->setIsNoData();
216 : 0 : block->setError( { tr( "Error occurred while reading block." ), QStringLiteral( "Raster" ) } );
217 : 0 : block->setValid( false );
218 : 0 : return block.release();
219 : : }
220 : : }
221 : :
222 : : // apply scale and offset
223 : 0 : block->applyScaleOffset( bandScale( bandNo ), bandOffset( bandNo ) );
224 : : // apply user no data values
225 : 0 : block->applyNoDataValues( userNoDataValues( bandNo ) );
226 : 0 : return block.release();
227 : 0 : }
228 : :
229 : 0 : QgsRasterDataProvider::QgsRasterDataProvider()
230 : 0 : : QgsDataProvider( QString(), QgsDataProvider::ProviderOptions(), QgsDataProvider::ReadFlags() )
231 : 0 : , QgsRasterInterface( nullptr )
232 : 0 : , mTemporalCapabilities( std::make_unique< QgsRasterDataProviderTemporalCapabilities >() )
233 : 0 : {
234 : :
235 : 0 : }
236 : :
237 : 0 : QgsRasterDataProvider::QgsRasterDataProvider( const QString &uri, const ProviderOptions &options,
238 : : QgsDataProvider::ReadFlags flags )
239 : 0 : : QgsDataProvider( uri, options, flags )
240 : 0 : , QgsRasterInterface( nullptr )
241 : 0 : , mTemporalCapabilities( std::make_unique< QgsRasterDataProviderTemporalCapabilities >() )
242 : 0 : {
243 : 0 : }
244 : :
245 : 0 : QgsRasterDataProvider::ProviderCapabilities QgsRasterDataProvider::providerCapabilities() const
246 : : {
247 : 0 : return QgsRasterDataProvider::NoProviderCapabilities;
248 : : }
249 : :
250 : 0 : int QgsRasterDataProvider::colorInterpretation( int bandNo ) const
251 : : {
252 : : Q_UNUSED( bandNo )
253 : 0 : return QgsRaster::UndefinedColorInterpretation;
254 : : }
255 : :
256 : : //
257 : : //Random Static convenience function
258 : : //
259 : : /////////////////////////////////////////////////////////
260 : :
261 : : // TODO
262 : : // (WMS) IdentifyFormatFeature is not consistent with QgsRaster::IdentifyFormatValue.
263 : : // IdentifyFormatHtml: better error reporting
264 : 0 : QgsRasterIdentifyResult QgsRasterDataProvider::identify( const QgsPointXY &point, QgsRaster::IdentifyFormat format, const QgsRectangle &boundingBox, int width, int height, int /*dpi*/ )
265 : : {
266 : 0 : QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
267 : 0 : QMap<int, QVariant> results;
268 : :
269 : 0 : if ( format != QgsRaster::IdentifyFormatValue || !( capabilities() & IdentifyValue ) )
270 : : {
271 : 0 : QgsDebugMsg( QStringLiteral( "Format not supported" ) );
272 : 0 : return QgsRasterIdentifyResult( ERR( tr( "Format not supported" ) ) );
273 : : }
274 : :
275 : 0 : if ( !extent().contains( point ) )
276 : : {
277 : : // Outside the raster
278 : 0 : for ( int bandNo = 1; bandNo <= bandCount(); bandNo++ )
279 : : {
280 : 0 : results.insert( bandNo, QVariant() );
281 : 0 : }
282 : 0 : return QgsRasterIdentifyResult( QgsRaster::IdentifyFormatValue, results );
283 : : }
284 : :
285 : 0 : QgsRectangle finalExtent = boundingBox;
286 : 0 : if ( finalExtent.isEmpty() )
287 : 0 : finalExtent = extent();
288 : :
289 : 0 : if ( width == 0 )
290 : : {
291 : 0 : width = capabilities() & Size ? xSize() : 1000;
292 : 0 : }
293 : 0 : if ( height == 0 )
294 : : {
295 : 0 : height = capabilities() & Size ? ySize() : 1000;
296 : 0 : }
297 : :
298 : : // Calculate the row / column where the point falls
299 : 0 : double xres = ( finalExtent.width() ) / width;
300 : 0 : double yres = ( finalExtent.height() ) / height;
301 : :
302 : 0 : int col = static_cast< int >( std::floor( ( point.x() - finalExtent.xMinimum() ) / xres ) );
303 : 0 : int row = static_cast< int >( std::floor( ( finalExtent.yMaximum() - point.y() ) / yres ) );
304 : :
305 : 0 : double xMin = finalExtent.xMinimum() + col * xres;
306 : 0 : double xMax = xMin + xres;
307 : 0 : double yMax = finalExtent.yMaximum() - row * yres;
308 : 0 : double yMin = yMax - yres;
309 : 0 : QgsRectangle pixelExtent( xMin, yMin, xMax, yMax );
310 : :
311 : 0 : for ( int i = 1; i <= bandCount(); i++ )
312 : : {
313 : 0 : std::unique_ptr< QgsRasterBlock > bandBlock( block( i, pixelExtent, 1, 1 ) );
314 : :
315 : 0 : if ( bandBlock )
316 : : {
317 : 0 : double value = bandBlock->value( 0 );
318 : :
319 : 0 : results.insert( i, value );
320 : 0 : }
321 : : else
322 : : {
323 : 0 : results.insert( i, QVariant() );
324 : : }
325 : 0 : }
326 : 0 : return QgsRasterIdentifyResult( QgsRaster::IdentifyFormatValue, results );
327 : 0 : }
328 : :
329 : 0 : double QgsRasterDataProvider::sample( const QgsPointXY &point, int band,
330 : : bool *ok, const QgsRectangle &boundingBox, int width, int height, int dpi )
331 : : {
332 : 0 : if ( ok )
333 : 0 : *ok = false;
334 : :
335 : 0 : const auto res = identify( point, QgsRaster::IdentifyFormatValue, boundingBox, width, height, dpi );
336 : 0 : const QVariant value = res.results().value( band );
337 : :
338 : 0 : if ( !value.isValid() )
339 : 0 : return std::numeric_limits<double>::quiet_NaN();
340 : :
341 : 0 : if ( ok )
342 : 0 : *ok = true;
343 : :
344 : 0 : return value.toDouble( ok );
345 : 0 : }
346 : :
347 : 0 : QString QgsRasterDataProvider::lastErrorFormat()
348 : : {
349 : 0 : return QStringLiteral( "text/plain" );
350 : : }
351 : :
352 : 0 : bool QgsRasterDataProvider::writeBlock( QgsRasterBlock *block, int band, int xOffset, int yOffset )
353 : : {
354 : 0 : if ( !block )
355 : 0 : return false;
356 : 0 : if ( !isEditable() )
357 : : {
358 : 0 : QgsDebugMsg( QStringLiteral( "writeBlock() called on read-only provider." ) );
359 : 0 : return false;
360 : : }
361 : 0 : return write( block->bits(), band, block->width(), block->height(), xOffset, yOffset );
362 : 0 : }
363 : :
364 : : // typedef QList<QPair<QString, QString> > *pyramidResamplingMethods_t();
365 : 0 : QList<QPair<QString, QString> > QgsRasterDataProvider::pyramidResamplingMethods( const QString &providerKey )
366 : : {
367 : 0 : QList<QPair<QString, QString> > methods = QgsProviderRegistry::instance()->pyramidResamplingMethods( providerKey );
368 : 0 : if ( methods.isEmpty() )
369 : : {
370 : 0 : QgsDebugMsg( QStringLiteral( "provider pyramidResamplingMethods returned no methods" ) );
371 : 0 : }
372 : 0 : return methods;
373 : 0 : }
374 : :
375 : 0 : bool QgsRasterDataProvider::hasPyramids()
376 : : {
377 : 0 : QList<QgsRasterPyramid> myPyramidList = buildPyramidList();
378 : :
379 : 0 : if ( myPyramidList.isEmpty() )
380 : 0 : return false;
381 : :
382 : 0 : QList<QgsRasterPyramid>::iterator myRasterPyramidIterator;
383 : 0 : for ( myRasterPyramidIterator = myPyramidList.begin();
384 : 0 : myRasterPyramidIterator != myPyramidList.end();
385 : 0 : ++myRasterPyramidIterator )
386 : : {
387 : 0 : if ( myRasterPyramidIterator->exists )
388 : : {
389 : 0 : return true;
390 : : }
391 : 0 : }
392 : 0 : return false;
393 : 0 : }
394 : :
395 : 0 : void QgsRasterDataProvider::setUserNoDataValue( int bandNo, const QgsRasterRangeList &noData )
396 : : {
397 : 0 : if ( bandNo >= mUserNoDataValue.size() )
398 : : {
399 : 0 : for ( int i = mUserNoDataValue.size(); i < bandNo; i++ )
400 : : {
401 : 0 : mUserNoDataValue.append( QgsRasterRangeList() );
402 : 0 : }
403 : 0 : }
404 : 0 : QgsDebugMsgLevel( QStringLiteral( "set %1 band %1 no data ranges" ).arg( noData.size() ), 4 );
405 : :
406 : 0 : if ( mUserNoDataValue[bandNo - 1] != noData )
407 : : {
408 : : // Clear statistics
409 : 0 : int i = 0;
410 : 0 : while ( i < mStatistics.size() )
411 : : {
412 : 0 : if ( mStatistics.value( i ).bandNumber == bandNo )
413 : : {
414 : 0 : mStatistics.removeAt( i );
415 : 0 : mHistograms.removeAt( i );
416 : 0 : }
417 : : else
418 : : {
419 : 0 : i++;
420 : : }
421 : : }
422 : 0 : mUserNoDataValue[bandNo - 1] = noData;
423 : 0 : }
424 : 0 : }
425 : :
426 : 0 : QgsRasterDataProviderTemporalCapabilities *QgsRasterDataProvider::temporalCapabilities()
427 : : {
428 : 0 : return mTemporalCapabilities.get();
429 : : }
430 : :
431 : 0 : const QgsRasterDataProviderTemporalCapabilities *QgsRasterDataProvider::temporalCapabilities() const
432 : : {
433 : 0 : return mTemporalCapabilities.get();
434 : : }
435 : :
436 : 0 : QgsRasterDataProvider *QgsRasterDataProvider::create( const QString &providerKey,
437 : : const QString &uri,
438 : : const QString &format, int nBands,
439 : : Qgis::DataType type,
440 : : int width, int height, double *geoTransform,
441 : : const QgsCoordinateReferenceSystem &crs,
442 : : const QStringList &createOptions )
443 : : {
444 : 0 : QgsRasterDataProvider *ret = QgsProviderRegistry::instance()->createRasterDataProvider(
445 : 0 : providerKey,
446 : 0 : uri, format,
447 : 0 : nBands, type, width,
448 : 0 : height, geoTransform, crs, createOptions );
449 : 0 : if ( !ret )
450 : : {
451 : 0 : QgsDebugMsg( "Cannot resolve 'createRasterDataProviderFunction' function in " + providerKey + " provider" );
452 : 0 : }
453 : :
454 : : // TODO: it would be good to return invalid QgsRasterDataProvider
455 : : // with QgsError set, but QgsRasterDataProvider has pure virtual methods
456 : :
457 : 0 : return ret;
458 : 0 : }
459 : :
460 : 0 : QString QgsRasterDataProvider::identifyFormatName( QgsRaster::IdentifyFormat format )
461 : : {
462 : 0 : switch ( format )
463 : : {
464 : : case QgsRaster::IdentifyFormatValue:
465 : 0 : return QStringLiteral( "Value" );
466 : : case QgsRaster::IdentifyFormatText:
467 : 0 : return QStringLiteral( "Text" );
468 : : case QgsRaster::IdentifyFormatHtml:
469 : 0 : return QStringLiteral( "Html" );
470 : : case QgsRaster::IdentifyFormatFeature:
471 : 0 : return QStringLiteral( "Feature" );
472 : : default:
473 : 0 : return QStringLiteral( "Undefined" );
474 : : }
475 : 0 : }
476 : :
477 : 0 : QString QgsRasterDataProvider::identifyFormatLabel( QgsRaster::IdentifyFormat format )
478 : : {
479 : 0 : switch ( format )
480 : : {
481 : : case QgsRaster::IdentifyFormatValue:
482 : 0 : return tr( "Value" );
483 : : case QgsRaster::IdentifyFormatText:
484 : 0 : return tr( "Text" );
485 : : case QgsRaster::IdentifyFormatHtml:
486 : 0 : return tr( "Html" );
487 : : case QgsRaster::IdentifyFormatFeature:
488 : 0 : return tr( "Feature" );
489 : : default:
490 : 0 : return QStringLiteral( "Undefined" );
491 : : }
492 : 0 : }
493 : :
494 : 0 : QgsRaster::IdentifyFormat QgsRasterDataProvider::identifyFormatFromName( const QString &formatName )
495 : : {
496 : 0 : if ( formatName == QLatin1String( "Value" ) ) return QgsRaster::IdentifyFormatValue;
497 : 0 : if ( formatName == QLatin1String( "Text" ) ) return QgsRaster::IdentifyFormatText;
498 : 0 : if ( formatName == QLatin1String( "Html" ) ) return QgsRaster::IdentifyFormatHtml;
499 : 0 : if ( formatName == QLatin1String( "Feature" ) ) return QgsRaster::IdentifyFormatFeature;
500 : 0 : return QgsRaster::IdentifyFormatUndefined;
501 : 0 : }
502 : :
503 : 0 : QgsRasterInterface::Capability QgsRasterDataProvider::identifyFormatToCapability( QgsRaster::IdentifyFormat format )
504 : : {
505 : 0 : switch ( format )
506 : : {
507 : : case QgsRaster::IdentifyFormatValue:
508 : 0 : return IdentifyValue;
509 : : case QgsRaster::IdentifyFormatText:
510 : 0 : return IdentifyText;
511 : : case QgsRaster::IdentifyFormatHtml:
512 : 0 : return IdentifyHtml;
513 : : case QgsRaster::IdentifyFormatFeature:
514 : 0 : return IdentifyFeature;
515 : : default:
516 : 0 : return NoCapabilities;
517 : : }
518 : 0 : }
519 : :
520 : 0 : QList<double> QgsRasterDataProvider::nativeResolutions() const
521 : : {
522 : 0 : return QList< double >();
523 : : }
524 : :
525 : 0 : bool QgsRasterDataProvider::ignoreExtents() const
526 : : {
527 : 0 : return false;
528 : : }
529 : :
530 : 0 : QgsPoint QgsRasterDataProvider::transformCoordinates( const QgsPoint &point, QgsRasterDataProvider::TransformType type )
531 : : {
532 : 0 : Q_UNUSED( point )
533 : : Q_UNUSED( type )
534 : 0 : return QgsPoint();
535 : : }
536 : :
537 : 0 : bool QgsRasterDataProvider::userNoDataValuesContains( int bandNo, double value ) const
538 : : {
539 : 0 : QgsRasterRangeList rangeList = mUserNoDataValue.value( bandNo - 1 );
540 : 0 : return QgsRasterRange::contains( value, rangeList );
541 : 0 : }
542 : :
543 : 0 : void QgsRasterDataProvider::copyBaseSettings( const QgsRasterDataProvider &other )
544 : : {
545 : 0 : mDpi = other.mDpi;
546 : 0 : mSrcNoDataValue = other.mSrcNoDataValue;
547 : 0 : mSrcHasNoDataValue = other.mSrcHasNoDataValue;
548 : 0 : mUseSrcNoDataValue = other.mUseSrcNoDataValue;
549 : 0 : mUserNoDataValue = other.mUserNoDataValue;
550 : 0 : mExtent = other.mExtent;
551 : 0 : mProviderResamplingEnabled = other.mProviderResamplingEnabled;
552 : 0 : mZoomedInResamplingMethod = other.mZoomedInResamplingMethod;
553 : 0 : mZoomedOutResamplingMethod = other.mZoomedOutResamplingMethod;
554 : 0 : mMaxOversampling = other.mMaxOversampling;
555 : :
556 : : // copy temporal properties
557 : 0 : if ( mTemporalCapabilities && other.mTemporalCapabilities )
558 : : {
559 : 0 : *mTemporalCapabilities = *other.mTemporalCapabilities;
560 : 0 : }
561 : 0 : }
562 : :
563 : 0 : static QgsRasterDataProvider::ResamplingMethod resamplingMethodFromString( const QString &str )
564 : : {
565 : 0 : if ( str == QLatin1String( "bilinear" ) )
566 : : {
567 : 0 : return QgsRasterDataProvider::ResamplingMethod::Bilinear;
568 : : }
569 : 0 : else if ( str == QLatin1String( "cubic" ) )
570 : : {
571 : 0 : return QgsRasterDataProvider::ResamplingMethod::Cubic;
572 : : }
573 : 0 : else if ( str == QLatin1String( "cubicSpline" ) )
574 : : {
575 : 0 : return QgsRasterDataProvider::ResamplingMethod::CubicSpline;
576 : : }
577 : 0 : else if ( str == QLatin1String( "lanczos" ) )
578 : : {
579 : 0 : return QgsRasterDataProvider::ResamplingMethod::Lanczos;
580 : : }
581 : 0 : else if ( str == QLatin1String( "average" ) )
582 : : {
583 : 0 : return QgsRasterDataProvider::ResamplingMethod::Average;
584 : : }
585 : 0 : else if ( str == QLatin1String( "mode" ) )
586 : : {
587 : 0 : return QgsRasterDataProvider::ResamplingMethod::Mode;
588 : : }
589 : 0 : else if ( str == QLatin1String( "gauss" ) )
590 : : {
591 : 0 : return QgsRasterDataProvider::ResamplingMethod::Gauss;
592 : : }
593 : 0 : return QgsRasterDataProvider::ResamplingMethod::Nearest;
594 : 0 : }
595 : :
596 : 0 : void QgsRasterDataProvider::readXml( const QDomElement &filterElem )
597 : : {
598 : 0 : if ( filterElem.isNull() )
599 : : {
600 : 0 : return;
601 : : }
602 : :
603 : 0 : QDomElement resamplingElement = filterElem.firstChildElement( QStringLiteral( "resampling" ) );
604 : 0 : if ( !resamplingElement.isNull() )
605 : : {
606 : 0 : setMaxOversampling( resamplingElement.attribute( QStringLiteral( "maxOversampling" ), QStringLiteral( "2.0" ) ).toDouble() );
607 : 0 : setZoomedInResamplingMethod( resamplingMethodFromString( resamplingElement.attribute( QStringLiteral( "zoomedInResamplingMethod" ) ) ) );
608 : 0 : setZoomedOutResamplingMethod( resamplingMethodFromString( resamplingElement.attribute( QStringLiteral( "zoomedOutResamplingMethod" ) ) ) );
609 : 0 : enableProviderResampling( resamplingElement.attribute( QStringLiteral( "enabled" ) ) == QLatin1String( "true" ) );
610 : 0 : }
611 : 0 : }
612 : :
613 : 0 : static QString resamplingMethodToString( QgsRasterDataProvider::ResamplingMethod method )
614 : : {
615 : 0 : switch ( method )
616 : : {
617 : : case QgsRasterDataProvider::ResamplingMethod::Nearest:
618 : 0 : return QStringLiteral( "nearestNeighbour" );
619 : : case QgsRasterDataProvider::ResamplingMethod::Bilinear:
620 : 0 : return QStringLiteral( "bilinear" );
621 : : case QgsRasterDataProvider::ResamplingMethod::Cubic:
622 : 0 : return QStringLiteral( "cubic" );
623 : : case QgsRasterDataProvider::ResamplingMethod::CubicSpline:
624 : 0 : return QStringLiteral( "cubicSpline" );
625 : : case QgsRasterDataProvider::ResamplingMethod::Lanczos:
626 : 0 : return QStringLiteral( "lanczos" );
627 : : case QgsRasterDataProvider::ResamplingMethod::Average:
628 : 0 : return QStringLiteral( "average" );
629 : : case QgsRasterDataProvider::ResamplingMethod::Mode:
630 : 0 : return QStringLiteral( "mode" );
631 : : case QgsRasterDataProvider::ResamplingMethod::Gauss:
632 : 0 : return QStringLiteral( "gauss" );
633 : : }
634 : : // should not happen
635 : 0 : return QStringLiteral( "nearestNeighbour" );
636 : 0 : }
637 : :
638 : 0 : void QgsRasterDataProvider::writeXml( QDomDocument &doc, QDomElement &parentElem ) const
639 : : {
640 : 0 : QDomElement providerElement = doc.createElement( QStringLiteral( "provider" ) );
641 : 0 : parentElem.appendChild( providerElement );
642 : :
643 : 0 : QDomElement resamplingElement = doc.createElement( QStringLiteral( "resampling" ) );
644 : 0 : providerElement.appendChild( resamplingElement );
645 : :
646 : 0 : resamplingElement.setAttribute( QStringLiteral( "enabled" ),
647 : 0 : mProviderResamplingEnabled ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
648 : :
649 : 0 : resamplingElement.setAttribute( QStringLiteral( "zoomedInResamplingMethod" ),
650 : 0 : resamplingMethodToString( mZoomedInResamplingMethod ) );
651 : :
652 : 0 : resamplingElement.setAttribute( QStringLiteral( "zoomedOutResamplingMethod" ),
653 : 0 : resamplingMethodToString( mZoomedOutResamplingMethod ) );
654 : :
655 : 0 : resamplingElement.setAttribute( QStringLiteral( "maxOversampling" ),
656 : 0 : QString::number( mMaxOversampling ) );
657 : 0 : }
658 : :
659 : 0 : QString QgsRasterDataProvider::colorInterpretationName( int bandNo ) const
660 : : {
661 : 0 : return colorName( colorInterpretation( bandNo ) );
662 : : }
|