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