1 /***************************************************************************
2     qgsrasterface.h - Internal raster processing modules interface
3      --------------------------------------
4     Date                 : Jun 21, 2012
5     Copyright            : (C) 2012 by Radim Blazek
6     email                : radim dot blazek at gmail dot com
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 #ifndef QGSRASTERINTERFACE_H
19 #define QGSRASTERINTERFACE_H
20 
21 #include "qgis_core.h"
22 #include "qgis_sip.h"
23 #include <limits>
24 
25 #include <QCoreApplication> // for tr()
26 #include <QImage>
27 
28 #include "qgsfeedback.h"
29 #include "qgsrasterbandstats.h"
30 #include "qgsrasterblock.h"
31 #include "qgsrasterhistogram.h"
32 #include "qgsrectangle.h"
33 
34 /**
35  * \ingroup core
36  * \brief Feedback object tailored for raster block reading.
37  *
38  * \since QGIS 3.0
39  */
40 class CORE_EXPORT QgsRasterBlockFeedback : public QgsFeedback
41 {
42     Q_OBJECT
43 
44   public:
45     //! Construct a new raster block feedback object
QgsFeedback(parent)46     QgsRasterBlockFeedback( QObject *parent = nullptr ) : QgsFeedback( parent ) {}
47 
48     /**
49      * May be emitted by raster data provider to indicate that some partial data are available
50      * and a new preview image may be produced
51      */
onNewData()52     virtual void onNewData() {}
53 
54     /**
55      * Whether the raster provider should return only data that are already available
56      * without waiting for full result. By default this flag is not enabled.
57      * \see setPreviewOnly()
58      */
isPreviewOnly()59     bool isPreviewOnly() const { return mPreviewOnly; }
60 
61     /**
62      * set flag whether the block request is for preview purposes only
63      * \see isPreviewOnly()
64      */
setPreviewOnly(bool preview)65     void setPreviewOnly( bool preview ) { mPreviewOnly = preview; }
66 
67     /**
68      * Whether our painter is drawing to a temporary image used just by this layer
69      * \see setRenderPartialOutput()
70      */
renderPartialOutput()71     bool renderPartialOutput() const { return mRenderPartialOutput; }
72 
73     /**
74      * Set whether our painter is drawing to a temporary image used just by this layer
75      * \see renderPartialOutput()
76      */
setRenderPartialOutput(bool enable)77     void setRenderPartialOutput( bool enable ) { mRenderPartialOutput = enable; }
78 
79     /**
80      * Appends an error message to the stored list of errors. Should be called
81      * whenever an error is encountered while retrieving a raster block.
82      *
83      * \see errors()
84      * \since QGIS 3.8.0
85      */
appendError(const QString & error)86     void appendError( const QString &error ) { mErrors.append( error ); }
87 
88     /**
89      * Returns a list of any errors encountered while retrieving the raster block.
90      *
91      * \see appendError()
92      * \since QGIS 3.8.0
93      */
errors()94     QStringList errors() const { return mErrors; }
95 
96   private:
97 
98     /**
99      * Whether the raster provider should return only data that are already available
100      * without waiting for full result
101      */
102     bool mPreviewOnly = false;
103 
104     //! Whether our painter is drawing to a temporary image used just by this layer
105     bool mRenderPartialOutput = false;
106 
107     //! List of errors encountered while retrieving block
108     QStringList mErrors;
109 };
110 
111 
112 /**
113  * \ingroup core
114  * \brief Base class for processing filters like renderers, reprojector, resampler etc.
115  */
116 class CORE_EXPORT QgsRasterInterface
117 {
118 #ifdef SIP_RUN
119 // QgsRasterInterface subclasses
120 #include <qgsbrightnesscontrastfilter.h>
121 #include <qgshuesaturationfilter.h>
122 #include <qgsrasterdataprovider.h>
123 #include <qgsrasternuller.h>
124 #include <qgsrasterprojector.h>
125 #include <qgsrasterrenderer.h>
126 #include <qgsrasterresamplefilter.h>
127 
128 // QgsRasterRenderer subclasses
129 #include <qgshillshaderenderer.h>
130 #include <qgsmultibandcolorrenderer.h>
131 #include <qgspalettedrasterrenderer.h>
132 #include <qgssinglebandcolordatarenderer.h>
133 #include <qgssinglebandgrayrenderer.h>
134 #include <qgssinglebandpseudocolorrenderer.h>
135 #endif
136 
137 
138 #ifdef SIP_RUN
139     SIP_CONVERT_TO_SUBCLASS_CODE
140     if ( dynamic_cast<QgsBrightnessContrastFilter *>( sipCpp ) )
141       sipType = sipType_QgsBrightnessContrastFilter;
142     else if ( dynamic_cast<QgsHueSaturationFilter *>( sipCpp ) )
143       sipType = sipType_QgsHueSaturationFilter;
144     else if ( dynamic_cast<QgsRasterDataProvider *>( sipCpp ) )
145     {
146       sipType = sipType_QgsRasterDataProvider;
147       // use static cast because QgsRasterDataProvider has multiple inheritance
148       // and we would end up with bad pointer otherwise!
149       *sipCppRet = static_cast<QgsRasterDataProvider *>( sipCpp );
150     }
151     else if ( dynamic_cast<QgsRasterNuller *>( sipCpp ) )
152       sipType = sipType_QgsRasterNuller;
153     else if ( dynamic_cast<QgsRasterProjector *>( sipCpp ) )
154       sipType = sipType_QgsRasterProjector;
155     else if ( dynamic_cast<QgsRasterRenderer *>( sipCpp ) )
156     {
157       if ( dynamic_cast<QgsHillshadeRenderer *>( sipCpp ) )
158         sipType = sipType_QgsHillshadeRenderer;
159       else if ( dynamic_cast<QgsMultiBandColorRenderer *>( sipCpp ) )
160         sipType = sipType_QgsMultiBandColorRenderer;
161       else if ( dynamic_cast<QgsPalettedRasterRenderer *>( sipCpp ) )
162         sipType = sipType_QgsPalettedRasterRenderer;
163       else if ( dynamic_cast<QgsSingleBandColorDataRenderer *>( sipCpp ) )
164         sipType = sipType_QgsSingleBandColorDataRenderer;
165       else if ( dynamic_cast<QgsSingleBandGrayRenderer *>( sipCpp ) )
166         sipType = sipType_QgsSingleBandGrayRenderer;
167       else if ( dynamic_cast<QgsSingleBandPseudoColorRenderer *>( sipCpp ) )
168         sipType = sipType_QgsSingleBandPseudoColorRenderer;
169       else
170         sipType = sipType_QgsRasterRenderer;
171     }
172     else if ( dynamic_cast<QgsRasterResampleFilter *>( sipCpp ) )
173       sipType = sipType_QgsRasterResampleFilter;
174     else
175       sipType = 0;
176     SIP_END
177 #endif
178 
179     Q_DECLARE_TR_FUNCTIONS( QgsRasterInterface )
180 
181   public:
182     //! If you add to this, please also add to capabilitiesString()
183     enum Capability
184     {
185       NoCapabilities   = 0,
186       Size             = 1 << 1, //!< Original data source size (and thus resolution) is known, it is not always available, for example for WMS
187       Create           = 1 << 2, //!< Create new datasets
188       Remove           = 1 << 3, //!< Delete datasets
189       BuildPyramids    = 1 << 4, //!< Supports building of pyramids (overviews)
190       Identify         = 1 << 5, //!< At least one identify format supported
191       IdentifyValue    = 1 << 6, //!< Numerical values
192       IdentifyText     = 1 << 7, //!< WMS text
193       IdentifyHtml     = 1 << 8, //!< WMS HTML
194       IdentifyFeature  = 1 << 9, //!< WMS GML -> feature
195       Prefetch         = 1 << 10, //!< Allow prefetching of out-of-view images
196     };
197 
198     QgsRasterInterface( QgsRasterInterface *input = nullptr );
199 
200     virtual ~QgsRasterInterface() = default;
201 
202     //! Clone itself, create deep copy
203     virtual QgsRasterInterface *clone() const = 0 SIP_FACTORY;
204 
205     //! Returns a bitmask containing the supported capabilities
capabilities()206     virtual int capabilities() const
207     {
208       return QgsRasterInterface::NoCapabilities;
209     }
210 
211     /**
212      *  Returns the raster interface capabilities in friendly format.
213      */
214     QString capabilitiesString() const;
215 
216     //! Returns data type for the band specified by number
217     virtual Qgis::DataType dataType( int bandNo ) const = 0;
218 
219     /**
220      * Returns source data type for the band specified by number,
221      *  source data type may be shorter than dataType
222     */
sourceDataType(int bandNo)223     virtual Qgis::DataType sourceDataType( int bandNo ) const { return mInput ? mInput->sourceDataType( bandNo ) : Qgis::DataType::UnknownDataType; }
224 
225     /**
226      * Gets the extent of the interface.
227      * \returns QgsRectangle containing the extent of the layer
228      */
extent()229     virtual QgsRectangle extent() const { return mInput ? mInput->extent() : QgsRectangle(); }
230 
231     /**
232      * Returns the size (in bytes) for the data type for the specified band.
233      */
dataTypeSize(int bandNo)234     int dataTypeSize( int bandNo ) const { return QgsRasterBlock::typeSize( dataType( bandNo ) ); }
235 
236     //! Gets number of bands
237     virtual int bandCount() const = 0;
238 
239     //! Gets block size
xBlockSize()240     virtual int xBlockSize() const { return mInput ? mInput->xBlockSize() : 0; }
yBlockSize()241     virtual int yBlockSize() const { return mInput ? mInput->yBlockSize() : 0; }
242 
243     //! Gets raster size
xSize()244     virtual int xSize() const { return mInput ? mInput->xSize() : 0; }
ySize()245     virtual int ySize() const { return mInput ? mInput->ySize() : 0; }
246 
247     //! \brief helper function to create zero padded band names
248     virtual QString generateBandName( int bandNumber ) const;
249 
250     /**
251      * Returns the name of the color interpretation for the specified \a bandNumber.
252      *
253      * \since QGIS 3.18
254      */
255     virtual QString colorInterpretationName( int bandNumber ) const;
256 
257     /**
258      * Generates a friendly, descriptive name for the specified \a bandNumber.
259      *
260      * \since QGIS 3.18
261      */
262     QString displayBandName( int bandNumber ) const;
263 
264     /**
265      * Read block of data using given extent and size.
266      *  Returns pointer to data.
267      *  Caller is responsible to free the memory returned.
268      * \param bandNo band number
269      * \param extent extent of block
270      * \param width pixel width of block
271      * \param height pixel height of block
272      * \param feedback optional raster feedback object for cancellation/preview. Added in QGIS 3.0.
273      */
274     virtual QgsRasterBlock *block( int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback = nullptr ) = 0 SIP_FACTORY;
275 
276     /**
277      * Set input.
278       * Returns TRUE if set correctly, FALSE if cannot use that input
279     */
setInput(QgsRasterInterface * input)280     virtual bool setInput( QgsRasterInterface *input ) { mInput = input; return true; }
281 
282     //! Current input
input()283     virtual QgsRasterInterface *input() const { return mInput; }
284 
285     //! Returns whether the interface is on or off
on()286     virtual bool on() const { return mOn; }
287 
288     //! Sets whether the interface is on or off
setOn(bool on)289     virtual void setOn( bool on ) { mOn = on; }
290 
291     /**
292      * Gets source / raw input, the first in pipe, usually provider.
293      *  It may be used to get info about original data, e.g. resolution to decide
294      *  resampling etc.
295      * \note not available in Python bindings.
296      */
sourceInput()297     virtual const QgsRasterInterface *sourceInput() const SIP_SKIP
298     {
299       QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
300       return mInput ? mInput->sourceInput() : this;
301     }
302 
303     /**
304      * Gets source / raw input, the first in pipe, usually provider.
305      *  It may be used to get info about original data, e.g. resolution to decide
306      *  resampling etc.
307      */
sourceInput()308     virtual QgsRasterInterface *sourceInput()
309     {
310       QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
311       return mInput ? mInput->sourceInput() : this;
312     }
313 
314     /**
315      * Returns the band statistics.
316      * \param bandNo The band (number).
317      * \param stats Requested statistics
318      * \param extent Extent used to calc statistics, if empty, whole raster extent is used.
319      * \param sampleSize Approximate number of cells in sample. If 0, all cells (whole raster will be used). If raster does not have exact size (WCS without exact size for example), provider decides size of sample.
320      * \param feedback optional feedback object
321      */
322     virtual QgsRasterBandStats bandStatistics( int bandNo,
323         int stats = QgsRasterBandStats::All,
324         const QgsRectangle &extent = QgsRectangle(),
325         int sampleSize = 0, QgsRasterBlockFeedback *feedback = nullptr );
326 
327     /**
328      * \brief Returns TRUE if histogram is available (cached, already calculated).     *   The parameters are the same as in bandStatistics()
329      * \returns TRUE if statistics are available (ready to use)
330      */
331     virtual bool hasStatistics( int bandNo,
332                                 int stats = QgsRasterBandStats::All,
333                                 const QgsRectangle &extent = QgsRectangle(),
334                                 int sampleSize = 0 );
335 
336 
337     /**
338      * Returns a band histogram. Histograms are cached in providers.
339      * \param bandNo The band (number).
340      * \param binCount Number of bins (intervals,buckets). If 0, the number of bins is decided automatically according to data type, raster size etc.
341      * \param minimum Minimum value, if NaN (None for Python), raster minimum value will be used.
342      * \param maximum Maximum value, if NaN (None for Python), raster maximum value will be used.
343      * \param extent Extent used to calc histogram, if empty, whole raster extent is used.
344      * \param sampleSize Approximate number of cells in sample. If 0, all cells (whole raster will be used). If raster does not have exact size (WCS without exact size for example), provider decides size of sample.
345      * \param includeOutOfRange include out of range values
346      * \param feedback optional feedback object
347      * \returns Vector of non NULL cell counts for each bin.
348      * \note binCount, minimum and maximum not optional in Python bindings
349      */
350 #ifndef SIP_RUN
351     virtual QgsRasterHistogram histogram( int bandNo,
352                                           int binCount = 0,
353                                           double minimum = std::numeric_limits<double>::quiet_NaN(),
354                                           double maximum = std::numeric_limits<double>::quiet_NaN(),
355                                           const QgsRectangle &extent = QgsRectangle(),
356                                           int sampleSize = 0,
357                                           bool includeOutOfRange = false,
358                                           QgsRasterBlockFeedback *feedback = nullptr );
359 #else
360     virtual QgsRasterHistogram histogram( int bandNo,
361                                           int binCount = 0,
362                                           SIP_PYOBJECT minimum = Py_None,
363                                           SIP_PYOBJECT maximum = Py_None,
364                                           const QgsRectangle &extent = QgsRectangle(),
365                                           int sampleSize = 0,
366                                           bool includeOutOfRange = false,
367                                           QgsRasterBlockFeedback *feedback = nullptr )
368     [QgsRasterHistogram( int bandNo,
369                          int binCount = 0,
370                          double minimum = 0.0,
371                          double maximum = 0.0,
372                          const QgsRectangle &extent = QgsRectangle(),
373                          int sampleSize = 0,
374                          bool includeOutOfRange = false,
375                          QgsRasterBlockFeedback *feedback = nullptr )];
376     % MethodCode
377     double minimum;
378     double maximum;
379     if ( a2 == Py_None )
380     {
381       minimum = std::numeric_limits<double>::quiet_NaN();
382     }
383     else
384     {
385       minimum = PyFloat_AsDouble( a2 );
386     }
387 
388     if ( a3 == Py_None )
389     {
390       maximum = std::numeric_limits<double>::quiet_NaN();
391     }
392     else
393     {
394       maximum = PyFloat_AsDouble( a3 );
395     }
396 
397     QgsRasterHistogram *h = new QgsRasterHistogram( sipCpp->histogram( a0, a1, minimum, maximum, *a4, a5, a6, a7 ) );
398     return sipConvertFromType( h, sipType_QgsRasterHistogram, Py_None );
399     % End
400 #endif
401 
402 
403     /**
404      * \brief Returns TRUE if histogram is available (cached, already calculated)
405      * \note the parameters are the same as in \see histogram()
406      */
407 #ifndef SIP_RUN
408     virtual bool hasHistogram( int bandNo,
409                                int binCount,
410                                double minimum = std::numeric_limits<double>::quiet_NaN(),
411                                double maximum = std::numeric_limits<double>::quiet_NaN(),
412                                const QgsRectangle &extent = QgsRectangle(),
413                                int sampleSize = 0,
414                                bool includeOutOfRange = false );
415 #else
416     virtual bool hasHistogram( int bandNo,
417                                int binCount,
418                                SIP_PYOBJECT minimum = Py_None,
419                                SIP_PYOBJECT maximum = Py_None,
420                                const QgsRectangle &extent = QgsRectangle(),
421                                int sampleSize = 0,
422                                bool includeOutOfRange = false )
423     [bool( int bandNo,
424            int binCount,
425            double minimum = 0.0,
426            double maximum = 0.0,
427            const QgsRectangle &extent = QgsRectangle(),
428            int sampleSize = 0,
429            bool includeOutOfRange = false )];
430     % MethodCode
431     double minimum;
432     double maximum;
433     if ( a2 == Py_None )
434     {
435       minimum = std::numeric_limits<double>::quiet_NaN();
436     }
437     else
438     {
439       minimum = PyFloat_AsDouble( a2 );
440     }
441 
442     if ( a3 == Py_None )
443     {
444       maximum = std::numeric_limits<double>::quiet_NaN();
445     }
446     else
447     {
448       maximum = PyFloat_AsDouble( a3 );
449     }
450 
451     sipRes = sipCpp->hasHistogram( a0, a1, minimum, maximum, *a4, a5, a6 );
452     % End
453 #endif
454 
455 
456     /**
457      * \brief Find values for cumulative pixel count cut.
458      * \param bandNo The band (number).
459      * \param lowerCount The lower count as fraction of 1, e.g. 0.02 = 2%
460      * \param upperCount The upper count as fraction of 1, e.g. 0.98 = 98%
461      * \param lowerValue Location into which the lower value will be set.
462      * \param upperValue  Location into which the upper value will be set.
463      * \param extent Extent used to calc histogram, if empty, whole raster extent is used.
464      * \param sampleSize Approximate number of cells in sample. If 0, all cells (whole raster will be used). If raster does not have exact size (WCS without exact size for example), provider decides size of sample.
465      */
466     virtual void cumulativeCut( int bandNo,
467                                 double lowerCount,
468                                 double upperCount,
469                                 double &lowerValue,
470                                 double &upperValue,
471                                 const QgsRectangle &extent = QgsRectangle(),
472                                 int sampleSize = 0 );
473 
474     //! Write base class members to xml.
writeXml(QDomDocument & doc,QDomElement & parentElem)475     virtual void writeXml( QDomDocument &doc, QDomElement &parentElem ) const { Q_UNUSED( doc ) Q_UNUSED( parentElem ); }
476     //! Sets base class members from xml. Usually called from create() methods of subclasses
readXml(const QDomElement & filterElem)477     virtual void readXml( const QDomElement &filterElem ) { Q_UNUSED( filterElem ) }
478 
479   protected:
480     // QgsRasterInterface used as input
481     QgsRasterInterface *mInput = nullptr;
482 
483     //! \brief List  of cached statistics, all bands mixed
484     QList<QgsRasterBandStats> mStatistics;
485 
486     //! \brief List  of cached histograms, all bands mixed
487     QList<QgsRasterHistogram> mHistograms;
488 
489     // On/off state, if off, it does not do anything, replicates input
490     bool mOn = true;
491 
492     /**
493      * Fill in histogram defaults if not specified
494      * \note the parameters are the same as in \see histogram()
495      */
496 #ifndef SIP_RUN
497     void initHistogram( QgsRasterHistogram &histogram,
498                         int bandNo,
499                         int binCount,
500                         double minimum = std::numeric_limits<double>::quiet_NaN(),
501                         double maximum = std::numeric_limits<double>::quiet_NaN(),
502                         const QgsRectangle &boundingBox = QgsRectangle(),
503                         int sampleSize = 0,
504                         bool includeOutOfRange = false );
505 #else
506     void initHistogram( QgsRasterHistogram &histogram,
507                         int bandNo,
508                         int binCount,
509                         SIP_PYOBJECT minimum = Py_None,
510                         SIP_PYOBJECT maximum = Py_None,
511                         const QgsRectangle &boundingBox = QgsRectangle(),
512                         int sampleSize = 0,
513                         bool includeOutOfRange = false )
514     [void ( QgsRasterHistogram & histogram,
515             int bandNo,
516             int binCount,
517             double minimum = 0.0,
518             double maximum = 0.0,
519             const QgsRectangle &boundingBox = QgsRectangle(),
520             int sampleSize = 0,
521             bool includeOutOfRange = false )];
522     % MethodCode
523     double minimum;
524     double maximum;
525     if ( a3 == Py_None )
526     {
527       minimum = std::numeric_limits<double>::quiet_NaN();
528     }
529     else
530     {
531       minimum = PyFloat_AsDouble( a3 );
532     }
533 
534     if ( a4 == Py_None )
535     {
536       maximum = std::numeric_limits<double>::quiet_NaN();
537     }
538     else
539     {
540       maximum = PyFloat_AsDouble( a4 );
541     }
542 
543 #if defined(SIP_PROTECTED_IS_PUBLIC) || (SIP_VERSION >= 0x050000 && !defined(_MSC_VER))
544     sipCpp->initHistogram( *a0, a1, a2, minimum, maximum, *a5, a6, a7 );
545 #else
546     sipCpp->sipProtect_initHistogram( *a0, a1, a2, minimum, maximum, *a5, a6, a7 );
547 #endif
548     % End
549 #endif
550 
551     //! Fill in statistics defaults if not specified
552     void initStatistics( QgsRasterBandStats &statistics, int bandNo,
553                          int stats = QgsRasterBandStats::All,
554                          const QgsRectangle &boundingBox = QgsRectangle(),
555                          int binCount = 0 );
556 
557   private:
558 #ifdef SIP_RUN
559     QgsRasterInterface( const QgsRasterInterface & );
560     QgsRasterInterface &operator=( const QgsRasterInterface & );
561 #endif
562 
563     Q_DISABLE_COPY( QgsRasterInterface )   // there is clone() for copying
564 };
565 
566 #endif
567 
568 
569