QGIS API Documentation 3.30.0-'s-Hertogenbosch (f186b8efe0)
qgsrasterdataprovider.cpp
Go to the documentation of this file.
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"
21#include "qgslogger.h"
22#include "qgspoint.h"
23#include "qgsthreadingutils.h"
24
25#include <QTime>
26#include <QMap>
27#include <QByteArray>
28#include <QVariant>
29
30#include <QUrl>
31#include <QUrlQuery>
32#include <QSet>
33
34#define ERR(message) QgsError(message, "Raster provider")
35
37{
39
40 if ( mUseSrcNoDataValue.size() < bandNo )
41 {
42 for ( int i = mUseSrcNoDataValue.size(); i < bandNo; i++ )
43 {
44 mUseSrcNoDataValue.append( false );
45 }
46 }
47 mUseSrcNoDataValue[bandNo - 1] = use;
48}
49
50QgsRasterBlock *QgsRasterDataProvider::block( int bandNo, QgsRectangle const &boundingBox, int width, int height, QgsRasterBlockFeedback *feedback )
51{
53
54 QgsDebugMsgLevel( QStringLiteral( "bandNo = %1 width = %2 height = %3" ).arg( bandNo ).arg( width ).arg( height ), 4 );
55 QgsDebugMsgLevel( QStringLiteral( "boundingBox = %1" ).arg( boundingBox.toString() ), 4 );
56
57 std::unique_ptr< QgsRasterBlock > block = std::make_unique< QgsRasterBlock >( dataType( bandNo ), width, height );
58 if ( sourceHasNoDataValue( bandNo ) && useSourceNoDataValue( bandNo ) )
59 {
61 }
62
63 if ( block->isEmpty() )
64 {
65 QgsDebugMsg( QStringLiteral( "Couldn't create raster block" ) );
66 block->setError( { tr( "Couldn't create raster block." ), QStringLiteral( "Raster" ) } );
67 block->setValid( false );
68 return block.release();
69 }
70
71 // Read necessary extent only
72 QgsRectangle tmpExtent = boundingBox;
73
74 if ( tmpExtent.isEmpty() )
75 {
76 QgsDebugMsg( QStringLiteral( "Extent outside provider extent" ) );
77 block->setError( { tr( "Extent outside provider extent." ), QStringLiteral( "Raster" ) } );
78 block->setValid( false );
80 return block.release();
81 }
82
83 const double xRes = boundingBox.width() / width;
84 const double yRes = boundingBox.height() / height;
85 double tmpXRes, tmpYRes;
86 double providerXRes = 0;
87 double providerYRes = 0;
88 if ( capabilities() & Size )
89 {
90 providerXRes = extent().width() / xSize();
91 providerYRes = extent().height() / ySize();
92 tmpXRes = std::max( providerXRes, xRes );
93 tmpYRes = std::max( providerYRes, yRes );
94 if ( qgsDoubleNear( tmpXRes, xRes ) ) tmpXRes = xRes;
95 if ( qgsDoubleNear( tmpYRes, yRes ) ) tmpYRes = yRes;
96 }
97 else
98 {
99 tmpXRes = xRes;
100 tmpYRes = yRes;
101 }
102
103 if ( tmpExtent != boundingBox ||
104 tmpXRes > xRes || tmpYRes > yRes )
105 {
106 // Read smaller extent or lower resolution
107
108 if ( !extent().contains( boundingBox ) )
109 {
110 const QRect subRect = QgsRasterBlock::subRect( boundingBox, width, height, extent() );
111 block->setIsNoDataExcept( subRect );
112 }
113
114 // Calculate row/col limits (before tmpExtent is aligned)
115 const int fromRow = std::round( ( boundingBox.yMaximum() - tmpExtent.yMaximum() ) / yRes );
116 const int toRow = std::round( ( boundingBox.yMaximum() - tmpExtent.yMinimum() ) / yRes ) - 1;
117 const int fromCol = std::round( ( tmpExtent.xMinimum() - boundingBox.xMinimum() ) / xRes );
118 const int toCol = std::round( ( tmpExtent.xMaximum() - boundingBox.xMinimum() ) / xRes ) - 1;
119
120 QgsDebugMsgLevel( QStringLiteral( "fromRow = %1 toRow = %2 fromCol = %3 toCol = %4" ).arg( fromRow ).arg( toRow ).arg( fromCol ).arg( toCol ), 4 );
121
122 if ( fromRow < 0 || fromRow >= height || toRow < 0 || toRow >= height ||
123 fromCol < 0 || fromCol >= width || toCol < 0 || toCol >= width )
124 {
125 // Should not happen
126 QgsDebugMsg( QStringLiteral( "Row or column limits out of range" ) );
127 block->setError( { tr( "Row or column limits out of range" ), QStringLiteral( "Raster" ) } );
128 block->setValid( false );
129 return block.release();
130 }
131
132 // If lower source resolution is used, the extent must be aligned to original
133 // resolution to avoid possible shift due to resampling
134 if ( tmpXRes > xRes )
135 {
136 int col = std::floor( ( tmpExtent.xMinimum() - extent().xMinimum() ) / providerXRes );
137 tmpExtent.setXMinimum( extent().xMinimum() + col * providerXRes );
138 col = std::ceil( ( tmpExtent.xMaximum() - extent().xMinimum() ) / providerXRes );
139 tmpExtent.setXMaximum( extent().xMinimum() + col * providerXRes );
140 }
141 if ( tmpYRes > yRes )
142 {
143 int row = std::floor( ( extent().yMaximum() - tmpExtent.yMaximum() ) / providerYRes );
144 tmpExtent.setYMaximum( extent().yMaximum() - row * providerYRes );
145 row = std::ceil( ( extent().yMaximum() - tmpExtent.yMinimum() ) / providerYRes );
146 tmpExtent.setYMinimum( extent().yMaximum() - row * providerYRes );
147 }
148 const int tmpWidth = std::round( tmpExtent.width() / tmpXRes );
149 const int tmpHeight = std::round( tmpExtent.height() / tmpYRes );
150 tmpXRes = tmpExtent.width() / tmpWidth;
151 tmpYRes = tmpExtent.height() / tmpHeight;
152
153 QgsDebugMsgLevel( QStringLiteral( "Reading smaller block tmpWidth = %1 height = %2" ).arg( tmpWidth ).arg( tmpHeight ), 4 );
154 QgsDebugMsgLevel( QStringLiteral( "tmpExtent = %1" ).arg( tmpExtent.toString() ), 4 );
155
156 std::unique_ptr< QgsRasterBlock > tmpBlock = std::make_unique< QgsRasterBlock >( dataType( bandNo ), tmpWidth, tmpHeight );
157 if ( sourceHasNoDataValue( bandNo ) && useSourceNoDataValue( bandNo ) )
158 {
159 tmpBlock->setNoDataValue( sourceNoDataValue( bandNo ) );
160 }
161
162 if ( !readBlock( bandNo, tmpExtent, tmpWidth, tmpHeight, tmpBlock->bits(), feedback ) )
163 {
164 QgsDebugMsg( QStringLiteral( "Error occurred while reading block" ) );
165 block->setError( { tr( "Error occurred while reading block." ), QStringLiteral( "Raster" ) } );
166 block->setValid( false );
168 return block.release();
169 }
170
171 const int pixelSize = dataTypeSize( bandNo );
172
173 const double xMin = boundingBox.xMinimum();
174 const double yMax = boundingBox.yMaximum();
175 const double tmpXMin = tmpExtent.xMinimum();
176 const double tmpYMax = tmpExtent.yMaximum();
177
178 for ( int row = fromRow; row <= toRow; row++ )
179 {
180 const double y = yMax - ( row + 0.5 ) * yRes;
181 const int tmpRow = std::floor( ( tmpYMax - y ) / tmpYRes );
182
183 for ( int col = fromCol; col <= toCol; col++ )
184 {
185 const double x = xMin + ( col + 0.5 ) * xRes;
186 const int tmpCol = std::floor( ( x - tmpXMin ) / tmpXRes );
187
188 if ( tmpRow < 0 || tmpRow >= tmpHeight || tmpCol < 0 || tmpCol >= tmpWidth )
189 {
190 QgsDebugMsg( QStringLiteral( "Source row or column limits out of range" ) );
191 block->setIsNoData(); // so that the problem becomes obvious and fixed
192 block->setError( { tr( "Source row or column limits out of range." ), QStringLiteral( "Raster" ) } );
193 block->setValid( false );
194 return block.release();
195 }
196
197 const qgssize tmpIndex = static_cast< qgssize >( tmpRow ) * static_cast< qgssize >( tmpWidth ) + tmpCol;
198 const qgssize index = row * static_cast< qgssize >( width ) + col;
199
200 char *tmpBits = tmpBlock->bits( tmpIndex );
201 char *bits = block->bits( index );
202 if ( !tmpBits )
203 {
204 QgsDebugMsg( QStringLiteral( "Cannot get input block data tmpRow = %1 tmpCol = %2 tmpIndex = %3." ).arg( tmpRow ).arg( tmpCol ).arg( tmpIndex ) );
205 continue;
206 }
207 if ( !bits )
208 {
209 QgsDebugMsg( QStringLiteral( "Cannot set output block data." ) );
210 continue;
211 }
212 memcpy( bits, tmpBits, pixelSize );
213 }
214 }
215 }
216 else
217 {
218 if ( !readBlock( bandNo, boundingBox, width, height, block->bits(), feedback ) )
219 {
220 QgsDebugMsg( QStringLiteral( "Error occurred while reading block" ) );
222 block->setError( { tr( "Error occurred while reading block." ), QStringLiteral( "Raster" ) } );
223 block->setValid( false );
224 return block.release();
225 }
226 }
227
228 // apply scale and offset
229 block->applyScaleOffset( bandScale( bandNo ), bandOffset( bandNo ) );
230 // apply user no data values
232 return block.release();
233}
234
236 : QgsDataProvider( QString(), QgsDataProvider::ProviderOptions(), QgsDataProvider::ReadFlags() )
237 , QgsRasterInterface( nullptr )
238 , mTemporalCapabilities( std::make_unique< QgsRasterDataProviderTemporalCapabilities >() )
239{
240
241}
242
244 QgsDataProvider::ReadFlags flags )
245 : QgsDataProvider( uri, options, flags )
246 , QgsRasterInterface( nullptr )
247 , mTemporalCapabilities( std::make_unique< QgsRasterDataProviderTemporalCapabilities >() )
248{
249}
250
251QgsRasterDataProvider::ProviderCapabilities QgsRasterDataProvider::providerCapabilities() const
252{
254
256}
257
259{
261
262 Q_UNUSED( bandNo )
263 return Qgis::RasterColorInterpretation::Undefined;
264}
265
266// TODO
267// (WMS) IdentifyFormatFeature is not consistent with QgsRaster::IdentifyFormatValue.
268// IdentifyFormatHtml: better error reporting
269QgsRasterIdentifyResult QgsRasterDataProvider::identify( const QgsPointXY &point, Qgis::RasterIdentifyFormat format, const QgsRectangle &boundingBox, int width, int height, int /*dpi*/ )
270{
272
273 QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
274 QMap<int, QVariant> results;
275
276 if ( format != Qgis::RasterIdentifyFormat::Value || !( capabilities() & IdentifyValue ) )
277 {
278 QgsDebugMsg( QStringLiteral( "Format not supported" ) );
279 return QgsRasterIdentifyResult( ERR( tr( "Format not supported" ) ) );
280 }
281
282 if ( !extent().contains( point ) )
283 {
284 // Outside the raster
285 for ( int bandNo = 1; bandNo <= bandCount(); bandNo++ )
286 {
287 results.insert( bandNo, QVariant() );
288 }
289 return QgsRasterIdentifyResult( Qgis::RasterIdentifyFormat::Value, results );
290 }
291
292 QgsRectangle finalExtent = boundingBox;
293 if ( finalExtent.isEmpty() )
294 finalExtent = extent();
295
296 if ( width == 0 )
297 {
298 width = capabilities() & Size ? xSize() : 1000;
299 }
300 if ( height == 0 )
301 {
302 height = capabilities() & Size ? ySize() : 1000;
303 }
304
305 // Calculate the row / column where the point falls
306 const double xres = ( finalExtent.width() ) / width;
307 const double yres = ( finalExtent.height() ) / height;
308
309 const int col = static_cast< int >( std::floor( ( point.x() - finalExtent.xMinimum() ) / xres ) );
310 const int row = static_cast< int >( std::floor( ( finalExtent.yMaximum() - point.y() ) / yres ) );
311
312 const double xMin = finalExtent.xMinimum() + col * xres;
313 const double xMax = xMin + xres;
314 const double yMax = finalExtent.yMaximum() - row * yres;
315 const double yMin = yMax - yres;
316 const QgsRectangle pixelExtent( xMin, yMin, xMax, yMax );
317
318 for ( int bandNumber = 1; bandNumber <= bandCount(); bandNumber++ )
319 {
320 std::unique_ptr< QgsRasterBlock > bandBlock( block( bandNumber, pixelExtent, 1, 1 ) );
321
322 if ( bandBlock )
323 {
324 const double value = bandBlock->value( 0 );
325 results.insert( bandNumber, value );
326 }
327 else
328 {
329 results.insert( bandNumber, QVariant() );
330 }
331 }
332 return QgsRasterIdentifyResult( Qgis::RasterIdentifyFormat::Value, results );
333}
334
335double QgsRasterDataProvider::sample( const QgsPointXY &point, int band,
336 bool *ok, const QgsRectangle &boundingBox, int width, int height, int dpi )
337{
339
340 if ( ok )
341 *ok = false;
342
343 const auto res = identify( point, Qgis::RasterIdentifyFormat::Value, boundingBox, width, height, dpi );
344 const QVariant value = res.results().value( band );
345
346 if ( !value.isValid() )
347 return std::numeric_limits<double>::quiet_NaN();
348
349 if ( ok )
350 *ok = true;
351
352 return value.toDouble( ok );
353}
354
356{
358
359 return QStringLiteral( "text/plain" );
360}
361
362bool QgsRasterDataProvider::writeBlock( QgsRasterBlock *block, int band, int xOffset, int yOffset )
363{
365
366 if ( !block )
367 return false;
368 if ( !isEditable() )
369 {
370 QgsDebugMsg( QStringLiteral( "writeBlock() called on read-only provider." ) );
371 return false;
372 }
373 return write( block->bits(), band, block->width(), block->height(), xOffset, yOffset );
374}
375
376// typedef QList<QPair<QString, QString> > *pyramidResamplingMethods_t();
377QList<QPair<QString, QString> > QgsRasterDataProvider::pyramidResamplingMethods( const QString &providerKey )
378{
379 QList<QPair<QString, QString> > methods = QgsProviderRegistry::instance()->pyramidResamplingMethods( providerKey );
380 if ( methods.isEmpty() )
381 {
382 QgsDebugMsg( QStringLiteral( "provider pyramidResamplingMethods returned no methods" ) );
383 }
384 return methods;
385}
386
388{
390
391 const QList<QgsRasterPyramid> pyramidList = buildPyramidList();
392 return std::any_of( pyramidList.constBegin(), pyramidList.constEnd(), []( QgsRasterPyramid pyramid ) { return pyramid.getExists(); } );
393}
394
396{
398
399 if ( bandNo >= mUserNoDataValue.size() )
400 {
401 for ( int i = mUserNoDataValue.size(); i < bandNo; i++ )
402 {
404 }
405 }
406 QgsDebugMsgLevel( QStringLiteral( "set %1 band %1 no data ranges" ).arg( noData.size() ), 4 );
407
408 if ( mUserNoDataValue[bandNo - 1] != noData )
409 {
410 // Clear statistics
411 mStatistics.erase( std::remove_if( mStatistics.begin(), mStatistics.end(), [bandNo]( const QgsRasterBandStats & stats )
412 {
413 return stats.bandNumber == bandNo;
414 } ), mStatistics.end() );
415 mHistograms.erase( std::remove_if( mHistograms.begin(), mHistograms.end(), [bandNo]( const QgsRasterHistogram & histogram )
416 {
417 return histogram.bandNumber == bandNo;
418 } ), mHistograms.end() );
419 mUserNoDataValue[bandNo - 1] = noData;
420 }
421}
422
424{
426
427 return mTemporalCapabilities.get();
428}
429
431{
433
434 return mTemporalCapabilities.get();
435}
436
438 const QString &uri,
439 const QString &format, int nBands,
440 Qgis::DataType type,
441 int width, int height, double *geoTransform,
443 const QStringList &createOptions )
444{
446 providerKey,
447 uri, format,
448 nBands, type, width,
449 height, geoTransform, crs, createOptions );
450 if ( !ret )
451 {
452 QgsDebugMsg( "Cannot resolve 'createRasterDataProviderFunction' function in " + providerKey + " provider" );
453 }
454
455 // TODO: it would be good to return invalid QgsRasterDataProvider
456 // with QgsError set, but QgsRasterDataProvider has pure virtual methods
457
458 return ret;
459}
460
462{
463 switch ( format )
464 {
465 case Qgis::RasterIdentifyFormat::Value:
466 return QStringLiteral( "Value" );
467 case Qgis::RasterIdentifyFormat::Text:
468 return QStringLiteral( "Text" );
469 case Qgis::RasterIdentifyFormat::Html:
470 return QStringLiteral( "Html" );
471 case Qgis::RasterIdentifyFormat::Feature:
472 return QStringLiteral( "Feature" );
473 case Qgis::RasterIdentifyFormat::Undefined:
474 break;
475 }
476 return QStringLiteral( "Undefined" );
477}
478
480{
481 switch ( format )
482 {
483 case Qgis::RasterIdentifyFormat::Value:
484 return tr( "Value" );
485 case Qgis::RasterIdentifyFormat::Text:
486 return tr( "Text" );
487 case Qgis::RasterIdentifyFormat::Html:
488 return tr( "HTML" );
489 case Qgis::RasterIdentifyFormat::Feature:
490 return tr( "Feature" );
491 case Qgis::RasterIdentifyFormat::Undefined:
492 break;
493 }
494 return QStringLiteral( "Undefined" );
495}
496
498{
499 if ( formatName == QLatin1String( "Value" ) )
500 return Qgis::RasterIdentifyFormat::Value;
501 if ( formatName == QLatin1String( "Text" ) )
502 return Qgis::RasterIdentifyFormat::Text;
503 if ( formatName == QLatin1String( "Html" ) )
504 return Qgis::RasterIdentifyFormat::Html;
505 if ( formatName == QLatin1String( "Feature" ) )
506 return Qgis::RasterIdentifyFormat::Feature;
507 return Qgis::RasterIdentifyFormat::Undefined;
508}
509
511{
512 switch ( format )
513 {
514 case Qgis::RasterIdentifyFormat::Value:
515 return IdentifyValue;
516 case Qgis::RasterIdentifyFormat::Text:
517 return IdentifyText;
518 case Qgis::RasterIdentifyFormat::Html:
519 return IdentifyHtml;
520 case Qgis::RasterIdentifyFormat::Feature:
521 return IdentifyFeature;
522 case Qgis::RasterIdentifyFormat::Undefined:
523 break;
524 }
525 return NoCapabilities;
526}
527
529{
531
532 return QList< double >();
533}
534
536{
538
539 return false;
540}
541
543{
545
546 Q_UNUSED( point )
547 Q_UNUSED( type )
548 return QgsPoint();
549}
550
551bool QgsRasterDataProvider::userNoDataValuesContains( int bandNo, double value ) const
552{
554
555 const QgsRasterRangeList rangeList = mUserNoDataValue.value( bandNo - 1 );
556 return QgsRasterRange::contains( value, rangeList );
557}
558
560{
562
563 mDpi = other.mDpi;
568 mExtent = other.mExtent;
573
574 // copy temporal properties
575 if ( mTemporalCapabilities && other.mTemporalCapabilities )
576 {
577 *mTemporalCapabilities = *other.mTemporalCapabilities;
578 }
579}
580
581static QgsRasterDataProvider::ResamplingMethod resamplingMethodFromString( const QString &str )
582{
583 if ( str == QLatin1String( "bilinear" ) )
584 {
586 }
587 else if ( str == QLatin1String( "cubic" ) )
588 {
590 }
591 else if ( str == QLatin1String( "cubicSpline" ) )
592 {
594 }
595 else if ( str == QLatin1String( "lanczos" ) )
596 {
598 }
599 else if ( str == QLatin1String( "average" ) )
600 {
602 }
603 else if ( str == QLatin1String( "mode" ) )
604 {
606 }
607 else if ( str == QLatin1String( "gauss" ) )
608 {
610 }
612}
613
614void QgsRasterDataProvider::readXml( const QDomElement &filterElem )
615{
617
618 if ( filterElem.isNull() )
619 {
620 return;
621 }
622
623 const QDomElement resamplingElement = filterElem.firstChildElement( QStringLiteral( "resampling" ) );
624 if ( !resamplingElement.isNull() )
625 {
626 setMaxOversampling( resamplingElement.attribute( QStringLiteral( "maxOversampling" ), QStringLiteral( "2.0" ) ).toDouble() );
627 setZoomedInResamplingMethod( resamplingMethodFromString( resamplingElement.attribute( QStringLiteral( "zoomedInResamplingMethod" ) ) ) );
628 setZoomedOutResamplingMethod( resamplingMethodFromString( resamplingElement.attribute( QStringLiteral( "zoomedOutResamplingMethod" ) ) ) );
629 enableProviderResampling( resamplingElement.attribute( QStringLiteral( "enabled" ) ) == QLatin1String( "true" ) );
630 }
631}
632
633static QString resamplingMethodToString( QgsRasterDataProvider::ResamplingMethod method )
634{
635 switch ( method )
636 {
638 return QStringLiteral( "nearestNeighbour" );
640 return QStringLiteral( "bilinear" );
642 return QStringLiteral( "cubic" );
644 return QStringLiteral( "cubicSpline" );
646 return QStringLiteral( "lanczos" );
648 return QStringLiteral( "average" );
650 return QStringLiteral( "mode" );
652 return QStringLiteral( "gauss" );
653 }
654 // should not happen
655 return QStringLiteral( "nearestNeighbour" );
656}
657
658void QgsRasterDataProvider::writeXml( QDomDocument &doc, QDomElement &parentElem ) const
659{
661
662 QDomElement providerElement = doc.createElement( QStringLiteral( "provider" ) );
663 parentElem.appendChild( providerElement );
664
665 QDomElement resamplingElement = doc.createElement( QStringLiteral( "resampling" ) );
666 providerElement.appendChild( resamplingElement );
667
668 resamplingElement.setAttribute( QStringLiteral( "enabled" ),
669 mProviderResamplingEnabled ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
670
671 resamplingElement.setAttribute( QStringLiteral( "zoomedInResamplingMethod" ),
672 resamplingMethodToString( mZoomedInResamplingMethod ) );
673
674 resamplingElement.setAttribute( QStringLiteral( "zoomedOutResamplingMethod" ),
675 resamplingMethodToString( mZoomedOutResamplingMethod ) );
676
677 resamplingElement.setAttribute( QStringLiteral( "maxOversampling" ),
678 QString::number( mMaxOversampling ) );
679}
680
682{
684
685 try
686 {
687 return mAttributeTables.at( bandNumber ).get();
688 }
689 catch ( std::out_of_range const & )
690 {
691 return nullptr;
692 }
693}
694
696{
698
699 if ( attributeTable )
700 {
701 mAttributeTables[ bandNumber ] = std::unique_ptr<QgsRasterAttributeTable>( attributeTable );
702 }
703 else
704 {
705 removeAttributeTable( bandNumber );
706 }
707}
708
710{
712
713 if ( mAttributeTables.find( bandNumber ) != std::end( mAttributeTables ) )
714 {
715 mAttributeTables.erase( bandNumber );
716 }
717}
718
719bool QgsRasterDataProvider::writeFileBasedAttributeTable( int bandNumber, const QString &path, QString *errorMessage ) const
720{
722
723 QgsRasterAttributeTable *rat { attributeTable( bandNumber ) };
724 if ( ! rat )
725 {
726 if ( errorMessage )
727 {
728 *errorMessage = QObject::tr( "Raster has no Raster Attribute Table for band %1" ).arg( bandNumber );
729 }
730 return false;
731 }
732
733 return rat->writeToFile( path, errorMessage );
734}
735
737{
739
740 if ( errorMessage )
741 {
742 *errorMessage = QObject::tr( "Raster data provider has no native Raster Attribute Table support." );
743 }
744 return false;
745}
746
747bool QgsRasterDataProvider::readFileBasedAttributeTable( int bandNumber, const QString &path, QString *errorMessage )
748{
750
751 std::unique_ptr<QgsRasterAttributeTable> rat = std::make_unique<QgsRasterAttributeTable>();
752 if ( rat->readFromFile( path, errorMessage ) )
753 {
754 setAttributeTable( bandNumber, rat.release() );
755 return true;
756 }
757 else
758 {
759 return false;
760 }
761}
762
763bool QgsRasterDataProvider::writeNativeAttributeTable( QString *errorMessage ) //#spellok
764{
766
767 Q_UNUSED( errorMessage );
768 return false;
769}
770
772{
774
775 return colorName( colorInterpretation( bandNo ) );
776}
777
779{
780 QUrl url = QUrl::fromPercentEncoding( uri.toUtf8() );
781 const QUrlQuery query( url.query() );
782 VirtualRasterParameters components;
783
784 if ( ! query.hasQueryItem( QStringLiteral( "crs" ) ) )
785 {
786 QgsDebugMsg( "crs is missing" );
787 if ( ok ) *ok = false;
788 return components;
789 }
790 if ( ! components.crs.createFromString( query.queryItemValue( QStringLiteral( "crs" ) ) ) )
791 {
792 QgsDebugMsg( "failed to create crs" );
793 if ( ok ) *ok = false;
794 return components;
795 }
796
797
798 if ( ! query.hasQueryItem( QStringLiteral( "extent" ) ) )
799 {
800 QgsDebugMsg( "extent is missing" );
801 if ( ok ) *ok = false;
802 return components;
803 }
804 QStringList pointValuesList = query.queryItemValue( QStringLiteral( "extent" ) ).split( ',' );
805 if ( pointValuesList.size() != 4 )
806 {
807 QgsDebugMsg( "the extent is not correct" );
808 if ( ok ) *ok = false;
809 return components;
810 }
811 components.extent = QgsRectangle( pointValuesList.at( 0 ).toDouble(), pointValuesList.at( 1 ).toDouble(),
812 pointValuesList.at( 2 ).toDouble(), pointValuesList.at( 3 ).toDouble() );
813
814 if ( ! query.hasQueryItem( QStringLiteral( "width" ) ) )
815 {
816 QgsDebugMsg( "width is missing" );
817 if ( ok ) *ok = false;
818 return components;
819 }
820 bool flagW;
821 components.width = query.queryItemValue( QStringLiteral( "width" ) ).toInt( & flagW );
822 if ( !flagW || components.width < 0 )
823 {
824 QgsDebugMsg( "invalid or negative width input" );
825 if ( ok ) *ok = false;
826 return components;
827 }
828
829 if ( ! query.hasQueryItem( QStringLiteral( "height" ) ) )
830 {
831 QgsDebugMsg( "height is missing" );
832 if ( ok ) *ok = false;
833 return components;
834 }
835 bool flagH;
836 components.height = query.queryItemValue( QStringLiteral( "height" ) ).toInt( & flagH );
837 if ( !flagH || components.height < 0 )
838 {
839 QgsDebugMsg( "invalid or negative width input" );
840 if ( ok ) *ok = false;
841 return components;
842 }
843
844 if ( ! query.hasQueryItem( QStringLiteral( "formula" ) ) )
845 {
846 QgsDebugMsg( "formula is missing" );
847 if ( ok ) *ok = false;
848 return components;
849 }
850 components.formula = query.queryItemValue( QStringLiteral( "formula" ) );
851
852 for ( const auto &item : query.queryItems() )
853 {
854 if ( !( item.first.mid( item.first.indexOf( ':' ), -1 ) == QLatin1String( ":uri" ) ) )
855 {
856 continue;
857 }
858
860 rLayer.name = item.first.mid( 0, item.first.indexOf( ':' ) );
861 rLayer.uri = query.queryItemValue( item.first );
862 rLayer.provider = query.queryItemValue( item.first.mid( 0, item.first.indexOf( ':' ) ) + QStringLiteral( ":provider" ) );
863
864 if ( rLayer.uri.isNull() || rLayer.provider.isNull() )
865 {
866 QgsDebugMsg( "One or more raster information are missing" );
867 if ( ok ) *ok = false;
868 return components;
869 }
870
871 components.rInputLayers.append( rLayer ) ;
872
873 }
874
875 if ( ok ) *ok = true;
876 return components;
877}
878
880{
881 QUrl uri;
882 QUrlQuery query;
883
884 if ( parts.crs.isValid() )
885 {
886 query.addQueryItem( QStringLiteral( "crs" ), parts.crs.authid() );
887 }
888
889 if ( ! parts.extent.isNull() )
890 {
891 QString rect = QString( "%1,%2,%3,%4" ).arg( qgsDoubleToString( parts.extent.xMinimum() ), qgsDoubleToString( parts.extent.yMinimum() ),
893
894 query.addQueryItem( QStringLiteral( "extent" ), rect );
895 }
896
897 query.addQueryItem( QStringLiteral( "width" ), QString::number( parts.width ) );
898
899 query.addQueryItem( QStringLiteral( "height" ), QString::number( parts.height ) );
900
901 query.addQueryItem( QStringLiteral( "formula" ), parts.formula );
902
903 if ( ! parts.rInputLayers.isEmpty() )
904 {
905 for ( const auto &it : parts.rInputLayers )
906 {
907 query.addQueryItem( it.name + QStringLiteral( ":uri" ), it.uri );
908 query.addQueryItem( it.name + QStringLiteral( ":provider" ), it.provider );
909 }
910 }
911 uri.setQuery( query );
912 return QString( QUrl::toPercentEncoding( uri.toEncoded() ) );
913}
DataType
Raster data types.
Definition: qgis.h:242
RasterColorInterpretation
Raster color interpretation.
Definition: qgis.h:2849
RasterIdentifyFormat
Raster identify formats.
Definition: qgis.h:2948
This class represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
bool createFromString(const QString &definition)
Set up this CRS from a string definition.
Abstract base class for spatial data provider implementations.
virtual QgsCoordinateReferenceSystem crs() const =0
Returns the coordinate system for the data source.
QgsDataSourceUri uri() const
Gets the data source specification.
A class to represent a 2D point.
Definition: qgspointxy.h:59
double y
Definition: qgspointxy.h:63
Q_GADGET double x
Definition: qgspointxy.h:62
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:49
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
QgsRasterDataProvider * createRasterDataProvider(const QString &providerKey, const QString &uri, const QString &format, int nBands, Qgis::DataType type, int width, int height, double *geoTransform, const QgsCoordinateReferenceSystem &crs, const QStringList &createOptions=QStringList())
Creates new instance of raster data provider.
QList< QPair< QString, QString > > pyramidResamplingMethods(const QString &providerKey)
Returns list of raster pyramid resampling methods.
The QgsRasterAttributeTable class represents a Raster Attribute Table (RAT).
bool writeToFile(const QString &path, QString *errorMessage=nullptr)
Writes the Raster Attribute Table to a DBF file specified by path, optionally reporting any error in ...
The RasterBandStats struct is a container for statistics about a single raster band.
Feedback object tailored for raster block reading.
Raster data container.
bool isEmpty() const
Returns true if block is empty, i.e.
void setNoDataValue(double noDataValue) SIP_HOLDGIL
Sets cell value that will be considered as "no data".
void setValid(bool valid) SIP_HOLDGIL
Mark block as valid or invalid.
int width() const SIP_HOLDGIL
Returns the width (number of columns) of the raster block.
char * bits(int row, int column)
Returns a pointer to block data.
bool setIsNoDataExcept(QRect exceptRect)
Set the whole block to no data except specified rectangle.
void applyNoDataValues(const QgsRasterRangeList &rangeList)
void applyScaleOffset(double scale, double offset)
Apply band scale and offset to raster block values.
static QRect subRect(const QgsRectangle &extent, int width, int height, const QgsRectangle &subExtent)
For extent and width, height find rectangle covered by subextent.
void setError(const QgsError &error)
Sets the last error.
int height() const SIP_HOLDGIL
Returns the height (number of rows) of the raster block.
bool setIsNoData(int row, int column) SIP_HOLDGIL
Set no data on pixel.
Implementation of data provider temporal properties for QgsRasterDataProviders.
Base class for raster data providers.
double mMaxOversampling
Maximum boundary for oversampling (to avoid too much data traffic). Default: 2.0.
static Capability identifyFormatToCapability(Qgis::RasterIdentifyFormat format)
Converts a raster identify format to a capability.
QList< bool > mUseSrcNoDataValue
Use source nodata value.
TransformType
Types of transformation in transformCoordinates() function.
bool writeFileBasedAttributeTable(int bandNumber, const QString &path, QString *errorMessage=nullptr) const
Writes the filesystem-based attribute table for the specified bandNumber to path, optionally reportin...
virtual bool sourceHasNoDataValue(int bandNo) const
Returns true if source band has no data value.
static QString encodeVirtualRasterProviderUri(const VirtualRasterParameters &parts)
Encodes the URI starting from the struct .
virtual double bandOffset(int bandNo) const
Read band offset for raster value.
virtual QString lastErrorFormat()
Returns the format of the error text for the last error in this provider.
bool mProviderResamplingEnabled
Whether provider resampling is enabled.
virtual bool writeNativeAttributeTable(QString *errorMessage=nullptr)
Writes the native attribute table, optionally reporting any error in errorMessage,...
virtual bool useSourceNoDataValue(int bandNo) const
Returns the source nodata value usage.
bool readFileBasedAttributeTable(int bandNumber, const QString &path, QString *errorMessage=nullptr)
Loads the filesystem-based attribute table for the specified bandNumber from path,...
static QgsRasterDataProvider::VirtualRasterParameters decodeVirtualRasterProviderUri(const QString &uri, bool *ok=nullptr)
Decodes the URI returning a struct with all the parameters for QgsVirtualRasterProvider class.
virtual void setUseSourceNoDataValue(int bandNo, bool use)
Sets the source nodata value usage.
QgsRasterAttributeTable * attributeTable(int bandNumber) const
Returns the (possibly NULL) attribute table for the specified bandNumber.
void setAttributeTable(int bandNumber, QgsRasterAttributeTable *attributeTable)
Set the attribute table to attributeTable for the specified bandNumber, if the attributeTable is NULL...
virtual double sourceNoDataValue(int bandNo) const
Value representing no data value.
void readXml(const QDomElement &filterElem) override
Sets base class members from xml. Usually called from create() methods of subclasses.
QList< QgsRasterRangeList > mUserNoDataValue
List of lists of user defined additional no data values for each band, indexed from 0.
virtual QgsRasterDataProvider::ProviderCapabilities providerCapabilities() const
Returns flags containing the supported capabilities of the data provider.
virtual bool isEditable() const
Checks whether the provider is in editing mode, i.e.
QString colorName(Qgis::RasterColorInterpretation colorInterpretation) const
Returns a string color name representation of a color interpretation.
virtual bool readNativeAttributeTable(QString *errorMessage=nullptr)
Reads the native attribute table, optionally reporting any error in errorMessage, returns true on suc...
void copyBaseSettings(const QgsRasterDataProvider &other)
Copy member variables from other raster data provider. Useful for implementation of clone() method in...
bool userNoDataValuesContains(int bandNo, double value) const
Returns true if user no data contains value.
bool writeBlock(QgsRasterBlock *block, int band, int xOffset=0, int yOffset=0)
Writes pixel data from a raster block into the provider data source.
virtual bool enableProviderResampling(bool enable)
Enable or disable provider-level resampling.
QgsRectangle extent() const override=0
Returns the extent of the layer.
virtual bool ignoreExtents() const
Returns true if the extents reported by the data provider are not reliable and it's possible that the...
virtual bool setMaxOversampling(double factor)
Sets maximum oversampling factor for zoomed-out operations.
Qgis::DataType dataType(int bandNo) const override=0
Returns data type for the band specified by number.
ResamplingMethod mZoomedOutResamplingMethod
Resampling method for zoomed out pixel extraction.
bool hasPyramids()
Returns true if raster has at least one existing pyramid.
virtual QgsRasterIdentifyResult identify(const QgsPointXY &point, Qgis::RasterIdentifyFormat format, const QgsRectangle &boundingBox=QgsRectangle(), int width=0, int height=0, int dpi=96)
Identify raster value(s) found on the point position.
virtual double bandScale(int bandNo) const
Read band scale for raster value.
@ NoProviderCapabilities
Provider has no capabilities.
int dpi() const
Returns the dpi of the output device.
virtual Qgis::RasterColorInterpretation colorInterpretation(int bandNo) const
Returns data type for the band specified by number.
virtual double sample(const QgsPointXY &point, int band, bool *ok=nullptr, const QgsRectangle &boundingBox=QgsRectangle(), int width=0, int height=0, int dpi=96)
Samples a raster value from the specified band found at the point position.
QgsRasterBlock * block(int bandNo, const QgsRectangle &boundingBox, int width, int height, QgsRasterBlockFeedback *feedback=nullptr) override
Read block of data using given extent and size.
QList< double > mSrcNoDataValue
Source no data value is available and is set to be used or internal no data is available.
virtual bool readBlock(int bandNo, int xBlock, int yBlock, void *data)
Reads a block of raster data into data.
ResamplingMethod mZoomedInResamplingMethod
Resampling method for zoomed in pixel extraction.
QgsRasterDataProvider()
Provider capabilities.
QList< bool > mSrcHasNoDataValue
Source no data value exists.
void removeAttributeTable(int bandNumber)
Remove the attribute table for the specified bandNumber.
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, const QStringList &createOptions=QStringList())
Creates a new dataset with mDataSourceURI.
virtual QgsRasterRangeList userNoDataValues(int bandNo) const
Returns a list of user no data value ranges.
virtual bool setZoomedInResamplingMethod(ResamplingMethod method)
Set resampling method to apply for zoomed-in operations.
static QList< QPair< QString, QString > > pyramidResamplingMethods(const QString &providerKey)
Returns a list of pyramid resampling method name and label pairs for given provider.
void writeXml(QDomDocument &doc, QDomElement &parentElem) const override
Write base class members to xml.
virtual QList< double > nativeResolutions() const
Returns a list of native resolutions if available, i.e.
virtual QgsPoint transformCoordinates(const QgsPoint &point, TransformType type)
Transforms coordinates between source image coordinate space [0..width]x[0..height] and layer coordin...
static QString identifyFormatName(Qgis::RasterIdentifyFormat format)
Converts a raster identify format to a string name.
QgsRasterDataProviderTemporalCapabilities * temporalCapabilities() override
Returns the provider's temporal capabilities.
QString colorInterpretationName(int bandNo) const override
Returns the name of the color interpretation for the specified bandNumber.
ResamplingMethod
Resampling method for provider-level resampling.
@ Lanczos
Lanczos windowed sinc interpolation (6x6 kernel)
@ Nearest
Nearest-neighbour resampling.
@ Mode
Mode (selects the value which appears most often of all the sampled points)
@ Bilinear
Bilinear (2x2 kernel) resampling.
@ CubicSpline
Cubic B-Spline Approximation (4x4 kernel)
@ Cubic
Cubic Convolution Approximation (4x4 kernel) resampling.
virtual bool write(void *data, int band, int width, int height, int xOffset, int yOffset)
Writes into the provider datasource.
static Qgis::RasterIdentifyFormat identifyFormatFromName(const QString &formatName)
Converts a string formatName to a raster identify format.
static QString identifyFormatLabel(Qgis::RasterIdentifyFormat format)
Converts a raster identify format to a translated string label.
virtual void setUserNoDataValue(int bandNo, const QgsRasterRangeList &noData)
virtual bool setZoomedOutResamplingMethod(ResamplingMethod method)
Set resampling method to apply for zoomed-out operations.
virtual QList< QgsRasterPyramid > buildPyramidList(const QList< int > &overviewList=QList< int >())
Returns the raster layers pyramid list.
The QgsRasterHistogram is a container for histogram of a single raster band.
Raster identify results container.
Base class for processing filters like renderers, reprojector, resampler etc.
QList< QgsRasterBandStats > mStatistics
List of cached statistics, all bands mixed.
Capability
If you add to this, please also add to capabilitiesString()
@ IdentifyValue
Numerical values.
@ IdentifyFeature
WMS GML -> feature.
@ Size
Original data source size (and thus resolution) is known, it is not always available,...
virtual int xSize() const
Gets raster size.
virtual int bandCount() const =0
Gets number of bands.
int dataTypeSize(int bandNo) const
Returns the size (in bytes) for the data type for the specified band.
virtual int capabilities() const
Returns a bitmask containing the supported capabilities.
virtual int ySize() const
QList< QgsRasterHistogram > mHistograms
List of cached histograms, all bands mixed.
virtual QgsRasterHistogram histogram(int bandNo, int binCount=0, double minimum=std::numeric_limits< double >::quiet_NaN(), double maximum=std::numeric_limits< double >::quiet_NaN(), const QgsRectangle &extent=QgsRectangle(), int sampleSize=0, bool includeOutOfRange=false, QgsRasterBlockFeedback *feedback=nullptr)
Returns a band histogram.
This struct is used to store pyramid info for the raster layer.
bool contains(double value) const
Returns true if this range contains the specified value.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:193
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:183
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:188
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:198
void setYMinimum(double y) SIP_HOLDGIL
Set the minimum y value.
Definition: qgsrectangle.h:161
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:479
void setXMaximum(double x) SIP_HOLDGIL
Set the maximum x value.
Definition: qgsrectangle.h:156
void setXMinimum(double x) SIP_HOLDGIL
Set the minimum x value.
Definition: qgsrectangle.h:151
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:230
void setYMaximum(double y) SIP_HOLDGIL
Set the maximum y value.
Definition: qgsrectangle.h:166
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:223
bool isEmpty() const
Returns true if the rectangle is empty.
Definition: qgsrectangle.h:469
#define str(x)
Definition: qgis.cpp:37
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:3448
unsigned long long qgssize
Qgssize is used instead of size_t, because size_t is stdlib type, unknown by SIP, and it would be har...
Definition: qgis.h:4064
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:3509
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
#define ERR(message)
QList< QgsRasterRange > QgsRasterRangeList
#define QGIS_PROTECT_QOBJECT_THREAD_ACCESS
const QgsCoordinateReferenceSystem & crs
Setting options for creating vector data providers.
Struct that stores information of the raster used in QgsVirtualRasterProvider for the calculations,...
Struct that stores the information about the parameters that should be given to the QgsVirtualRasterP...
QList< QgsRasterDataProvider::VirtualRasterInputLayers > rInputLayers