Skip to content
Permalink
Browse files

[FEATURE] Preview for WMTS + added XYZ tile layers

This is a port of the functionality from master (to be QGIS 3.0) to 2.x that keeps backward API compatibility.

- added support for XYZ tile layers to WMS provider
- rendering of raster layers can be interrupted, support in WMS provider
- temporary preview of tiled layers (WMTS / XYZ) in WMS provider

WMTS improvements funded by Land Information New Zealand.

XYZ tile layer funded by Lutra Consulting.
  • Loading branch information
wonder-sk committed Sep 16, 2016
1 parent 85b6cba commit f5b657db19eda7e72e6ed34eb7fe333c156acad0
Showing with 2,046 additions and 669 deletions.
  1. +1 −0 python/core/core.sip
  2. +43 −0 python/core/qgsfeedback.sip
  3. +4 −0 python/core/qgsmaplayerrenderer.sip
  4. +2 −1 python/core/qgsmapsettings.sip
  5. +1 −0 python/core/qgsrendercontext.sip
  6. +2 −1 python/core/raster/qgsbrightnesscontrastfilter.sip
  7. +1 −0 python/core/raster/qgshillshaderenderer.sip
  8. +2 −1 python/core/raster/qgshuesaturationfilter.sip
  9. +1 −0 python/core/raster/qgsmultibandcolorrenderer.sip
  10. +1 −0 python/core/raster/qgspalettedrasterrenderer.sip
  11. +2 −1 python/core/raster/qgsrasterdataprovider.sip
  12. +2 −1 python/core/raster/qgsrasterdrawer.sip
  13. +51 −0 python/core/raster/qgsrasterinterface.sip
  14. +2 −1 python/core/raster/qgsrasteriterator.sip
  15. +1 −0 python/core/raster/qgsrasternuller.sip
  16. +15 −13 python/core/raster/qgsrasterprojector.sip
  17. +0 −2 python/core/raster/qgsrasterrenderer.sip
  18. +1 −0 python/core/raster/qgsrasterresamplefilter.sip
  19. +1 −0 python/core/raster/qgssinglebandcolordatarenderer.sip
  20. +1 −0 python/core/raster/qgssinglebandgrayrenderer.sip
  21. +1 −0 python/core/raster/qgssinglebandpseudocolorrenderer.sip
  22. +8 −0 src/app/main.cpp
  23. +25 −17 src/app/qgslayerstylingwidget.cpp
  24. +1 −0 src/core/CMakeLists.txt
  25. +13 −0 src/core/qgsdataitemproviderregistry.cpp
  26. +73 −0 src/core/qgsfeedback.h
  27. +3 −1 src/core/qgsmaplayer.cpp
  28. +6 −0 src/core/qgsmaplayerrenderer.h
  29. +9 −0 src/core/qgsmaprenderercustompainterjob.cpp
  30. +3 −0 src/core/qgsmaprendererparalleljob.cpp
  31. +2 −1 src/core/qgsmapsettings.h
  32. +1 −0 src/core/qgsrendercontext.cpp
  33. +1 −0 src/core/qgsrendercontext.h
  34. +6 −1 src/core/raster/qgsbrightnesscontrastfilter.cpp
  35. +1 −0 src/core/raster/qgsbrightnesscontrastfilter.h
  36. +7 −2 src/core/raster/qgshillshaderenderer.cpp
  37. +1 −0 src/core/raster/qgshillshaderenderer.h
  38. +6 −1 src/core/raster/qgshuesaturationfilter.cpp
  39. +1 −0 src/core/raster/qgshuesaturationfilter.h
  40. +6 −1 src/core/raster/qgsmultibandcolorrenderer.cpp
  41. +1 −0 src/core/raster/qgsmultibandcolorrenderer.h
  42. +7 −2 src/core/raster/qgspalettedrasterrenderer.cpp
  43. +1 −0 src/core/raster/qgspalettedrasterrenderer.h
  44. +7 −2 src/core/raster/qgsrasterdataprovider.cpp
  45. +3 −2 src/core/raster/qgsrasterdataprovider.h
  46. +20 −2 src/core/raster/qgsrasterdrawer.cpp
  47. +3 −1 src/core/raster/qgsrasterdrawer.h
  48. +59 −0 src/core/raster/qgsrasterinterface.h
  49. +4 −2 src/core/raster/qgsrasteriterator.cpp
  50. +4 −1 src/core/raster/qgsrasteriterator.h
  51. +41 −2 src/core/raster/qgsrasterlayerrenderer.cpp
  52. +31 −0 src/core/raster/qgsrasterlayerrenderer.h
  53. +6 −1 src/core/raster/qgsrasternuller.cpp
  54. +1 −0 src/core/raster/qgsrasternuller.h
  55. +1 −0 src/core/raster/qgsrasterpipe.h
  56. +105 −151 src/core/raster/qgsrasterprojector.cpp
  57. +60 −47 src/core/raster/qgsrasterprojector.h
  58. +0 −2 src/core/raster/qgsrasterrenderer.h
  59. +7 −2 src/core/raster/qgsrasterresamplefilter.cpp
  60. +1 −0 src/core/raster/qgsrasterresamplefilter.h
  61. +6 −1 src/core/raster/qgssinglebandcolordatarenderer.cpp
  62. +1 −0 src/core/raster/qgssinglebandcolordatarenderer.h
  63. +7 −2 src/core/raster/qgssinglebandgrayrenderer.cpp
  64. +1 −0 src/core/raster/qgssinglebandgrayrenderer.h
  65. +7 −2 src/core/raster/qgssinglebandpseudocolorrenderer.cpp
  66. +1 −0 src/core/raster/qgssinglebandpseudocolorrenderer.h
  67. +1 −0 src/gui/qgsmapcanvas.cpp
  68. +7 −0 src/gui/raster/qgsrastertransparencywidget.cpp
  69. +3 −1 src/providers/arcgisrest/qgsamsprovider.cpp
  70. +1 −1 src/providers/arcgisrest/qgsamsprovider.h
  71. +9 −3 src/providers/gdal/qgsgdalprovider.cpp
  72. +2 −1 src/providers/gdal/qgsgdalprovider.h
  73. +28 −1 src/providers/gdal/qgsgdalproviderbase.cpp
  74. +1 −1 src/providers/gdal/qgsgdalproviderbase.h
  75. +2 −1 src/providers/grass/qgsgrassrasterprovider.cpp
  76. +1 −1 src/providers/grass/qgsgrassrasterprovider.h
  77. +42 −26 src/providers/wcs/qgswcsprovider.cpp
  78. +4 −3 src/providers/wcs/qgswcsprovider.h
  79. +2 −0 src/providers/wms/CMakeLists.txt
  80. +57 −0 src/providers/wms/qgstilecache.cpp
  81. +56 −0 src/providers/wms/qgstilecache.h
  82. +133 −3 src/providers/wms/qgswmscapabilities.cpp
  83. +54 −19 src/providers/wms/qgswmscapabilities.h
  84. +89 −5 src/providers/wms/qgswmsdataitems.cpp
  85. +60 −0 src/providers/wms/qgswmsdataitems.h
  86. +640 −302 src/providers/wms/qgswmsprovider.cpp
  87. +55 −34 src/providers/wms/qgswmsprovider.h
  88. +59 −0 src/providers/wms/qgsxyzconnection.cpp
  89. +47 −0 src/providers/wms/qgsxyzconnection.h
@@ -54,6 +54,7 @@
%Include qgsfeaturefilterprovider.sip
%Include qgsfeatureiterator.sip
%Include qgsfeaturerequest.sip
%Include qgsfeedback.sip
%Include qgsfield.sip
%Include qgsgeometrysimplifier.sip
%Include qgsgeometryvalidator.sip
@@ -0,0 +1,43 @@

/** \ingroup core
* Base class for feedback objects to be used for cancellation of something running in a worker thread.
* The class may be used as is or it may be subclassed for extended functionality
* for a particular operation (e.g. report progress or pass some data for preview).
*
* When cancel() is called, the internal code has two options to check for cancellation state:
* - if the worker thread uses an event loop (e.g. for network communication), the code can
* make a queued connection to cancelled() signal and handle the cancellation in its slot.
* - if the worker thread does not use an event loop, it can poll isCancelled() method regularly
* to see if the operation should be cancelled.
*
* The class is meant to be created and destroyed in the main thread.
*
* For map rendering, the object may be created in constructor of a QgsMapLayerRenderer
* subclass and available with QgsMapLayerRenderer::feedback() method. When a map rendering job
* gets cancelled, the cancel() method is called on the feedback object of all layers.
*
* @note added in QGIS 2.18
*/
class QgsFeedback : QObject
{
%TypeHeaderCode
#include <qgsfeedback.h>
%End

public:
//! Construct a feedback object
QgsFeedback( QObject* parent /TransferThis/ = nullptr );

virtual ~QgsFeedback();

//! Tells the internal routines that the current operation should be cancelled. This should be run by the main thread
void cancel();

//! Tells whether the operation has been cancelled already
bool isCancelled() const;

signals:
//! Internal routines can connect to this signal if they use event loop
void cancelled();

};
@@ -12,6 +12,10 @@ class QgsMapLayerRenderer
//! Do the rendering (based on data stored in the class)
virtual bool render() = 0;

//! Access to feedback object of the layer renderer (may be null)
//! @note added in QGIS 2.18
virtual QgsFeedback* feedback() const;

//! Return list of errors (problems) that happened during the rendering
QStringList errors() const;

@@ -116,7 +116,8 @@ class QgsMapSettings
UseRenderingOptimization, //!< Enable vector simplification and other rendering optimizations
DrawSelection, //!< Whether vector selections should be shown in the rendered map
DrawSymbolBounds, //!< Draw bounds of symbols (for debugging/testing)
RenderMapTile //!< Draw map such that there are no problems between adjacent tiles
RenderMapTile, //!< Draw map such that there are no problems between adjacent tiles
RenderPartialOutput, //!< Whether to make extra effort to update map image with partially rendered layers (better for interactive map canvas). Added in QGIS 2.18
};
typedef QFlags<QgsMapSettings::Flag> Flags;

@@ -23,6 +23,7 @@ class QgsRenderContext
DrawSymbolBounds, //!< Draw bounds of symbols (for debugging/testing)
RenderMapTile, //!< Draw map such that there are no problems between adjacent tiles
Antialiasing, //!< Use antialiasing while drawing
RenderPartialOutput, //!< Whether to make extra effort to update map image with partially rendered layers (better for interactive map canvas). Added in QGIS 2.18
};
typedef QFlags<QgsRenderContext::Flag> Flags;

@@ -15,7 +15,8 @@ class QgsBrightnessContrastFilter : QgsRasterInterface

bool setInput( QgsRasterInterface* input );

QgsRasterBlock *block( int bandNo, const QgsRectangle &extent, int width, int height );
QgsRasterBlock *block( int bandNo, const QgsRectangle &extent, int width, int height ) /Factory/;
QgsRasterBlock *block2( int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback* feedback = nullptr ) /Factory/;

void setBrightness( int brightness );
int brightness() const;
@@ -32,6 +32,7 @@ class QgsHillshadeRenderer : QgsRasterRenderer
static QgsRasterRenderer* create( const QDomElement& elem, QgsRasterInterface* input ) /Factory/;

QgsRasterBlock *block( int bandNo, const QgsRectangle & extent, int width, int height ) /Factory/;
QgsRasterBlock *block2( int bandNo, const QgsRectangle & extent, int width, int height, QgsRasterBlockFeedback* feedback = nullptr ) /Factory/;

void writeXML( QDomDocument& doc, QDomElement& parentElem ) const;

@@ -25,7 +25,8 @@ class QgsHueSaturationFilter : QgsRasterInterface

bool setInput( QgsRasterInterface* input );

QgsRasterBlock *block( int bandNo, const QgsRectangle &extent, int width, int height );
QgsRasterBlock *block( int bandNo, const QgsRectangle &extent, int width, int height ) /Factory/;
QgsRasterBlock *block2( int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback* feedback = nullptr ) /Factory/;

void setSaturation( int saturation );
int saturation() const;
@@ -13,6 +13,7 @@ class QgsMultiBandColorRenderer: QgsRasterRenderer
static QgsRasterRenderer* create( const QDomElement& elem, QgsRasterDataProvider* provider ) /Factory/;

QgsRasterBlock* block( int bandNo, const QgsRectangle & extent, int width, int height ) /Factory/;
QgsRasterBlock* block2( int bandNo, const QgsRectangle & extent, int width, int height, QgsRasterBlockFeedback* feedback = nullptr ) /Factory/;

int redBand() const;
void setRedBand( int band );
@@ -11,6 +11,7 @@ class QgsPalettedRasterRenderer : QgsRasterRenderer
static QgsRasterRenderer* create( const QDomElement& elem, QgsRasterInterface* input ) /Factory/;

QgsRasterBlock *block( int bandNo, const QgsRectangle & extent, int width, int height ) /Factory/;
QgsRasterBlock *block2( int bandNo, const QgsRectangle & extent, int width, int height, QgsRasterBlockFeedback* feedback = nullptr ) /Factory/;

/** Returns number of colors*/
int nColors() const;
@@ -103,6 +103,7 @@ class QgsRasterDataProvider : QgsDataProvider, QgsRasterInterface

/** Read block of data using given extent and size. */
virtual QgsRasterBlock *block( int theBandNo, const QgsRectangle &theExtent, int theWidth, int theHeight ) / Factory /;
virtual QgsRasterBlock *block2( int theBandNo, const QgsRectangle &theExtent, int theWidth, int theHeight, QgsRasterBlockFeedback* feedback = nullptr ) / Factory /;

/** Return true if source band has no data value */
virtual bool srcHasNoDataValue( int bandNo ) const;
@@ -306,7 +307,7 @@ class QgsRasterDataProvider : QgsDataProvider, QgsRasterInterface
/** Read block of data using give extent and size
* @note not available in python bindings
*/
//virtual void readBlock( int bandNo, QgsRectangle const & viewExtent, int width, int height, void *data );
//virtual void readBlock( int bandNo, QgsRectangle const & viewExtent, int width, int height, void *data, QgsRasterBlockFeedback* feedback = nullptr );

/** Returns true if user no data contains value */
bool userNoDataValuesContains( int bandNo, double value ) const;
@@ -14,8 +14,9 @@ class QgsRasterDrawer
* @param viewPort viewport to render
* @param theQgsMapToPixel map to pixel convertor
* @param ctx render context
* @param feedback optional raster feedback object for cancellation/preview. Added in QGIS 2.18.
*/
void draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel, const QgsRenderContext *ctx = nullptr );
void draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel, const QgsRenderContext *ctx = nullptr, QgsRasterBlockFeedback* feedback = nullptr );

protected:
/** Draws raster part
@@ -1,4 +1,41 @@

/** \ingroup core
* Feedback object tailored for raster block reading.
*
* @note added in QGIS 2.18
*/
class QgsRasterBlockFeedback : QgsFeedback
{
%TypeHeaderCode
#include <qgsrasterinterface.h>
%End

public:
//! Construct a new raster block feedback object
QgsRasterBlockFeedback( QObject* parent = nullptr );

//! May be emitted by raster data provider to indicate that some partial data are available
//! and a new preview image may be produced
virtual void onNewData();

//! Whether the raster provider should return only data that are already available
//! without waiting for full result. By default this flag is not enabled.
//! @see setPreviewOnly()
bool isPreviewOnly() const;
//! set flag whether the block request is for preview purposes only
//! @see isPreviewOnly()
void setPreviewOnly( bool preview );

//! Whether our painter is drawing to a temporary image used just by this layer
//! @see setRenderPartialOutput()
bool renderPartialOutput() const;
//! Set whether our painter is drawing to a temporary image used just by this layer
//! @see renderPartialOutput()
void setRenderPartialOutput( bool enable );

};


/** Base class for processing modules.
*
*/
@@ -132,6 +169,19 @@ class QgsRasterInterface
*/
virtual QgsRasterBlock *block( int bandNo, const QgsRectangle &extent, int width, int height ) = 0 /Factory/;

/** Read block of data using given extent and size.
* Returns pointer to data.
* Caller is responsible to free the memory returned.
* @param bandNo band number
* @param extent extent of block
* @param width pixel width of block
* @param height pixel height of block
* @param feedback optional raster feedback object for cancellation/preview
* @note This is extended version of block() method. Default implementation falls back to calling block().
* @note Added in QGIS 2.18
*/
virtual QgsRasterBlock *block2( int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback* feedback = nullptr ) /Factory/;

/** Set input.
* Returns true if set correctly, false if cannot use that input */
virtual bool setInput( QgsRasterInterface* input );
@@ -241,5 +291,6 @@ class QgsRasterInterface
int theStats = QgsRasterBandStats::All,
const QgsRectangle & theExtent = QgsRectangle(),
int theBinCount = 0 );

};

@@ -12,8 +12,9 @@ class QgsRasterIterator
@param nCols number of columns
@param nRows number of rows
@param extent area to read
@param feedback optional raster feedback object for cancellation/preview. Added in QGIS 2.18
*/
void startRasterRead( int bandNumber, int nCols, int nRows, const QgsRectangle& extent );
void startRasterRead( int bandNumber, int nCols, int nRows, const QgsRectangle& extent, QgsRasterBlockFeedback* feedback = nullptr );

/** Fetches next part of raster data, caller takes ownership of the block and
caller should delete the block.
@@ -20,6 +20,7 @@ class QgsRasterNuller : QgsRasterInterface
QGis::DataType dataType( int bandNo ) const;

QgsRasterBlock *block( int bandNo, const QgsRectangle &extent, int width, int height ) / Factory /;
QgsRasterBlock *block2( int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback* feedback = nullptr ) / Factory /;

void setNoData( int bandNo, const QgsRasterRangeList& noData );

@@ -1,6 +1,10 @@

/** Raster projector */

/** \ingroup core
* \brief QgsRasterProjector implements approximate projection support for
* it calculates grid of points in source CRS for target CRS + extent
* which are used to calculate affine transformation matrices.
* \class QgsRasterProjector
*/
class QgsRasterProjector : QgsRasterInterface
{
%TypeHeaderCode
@@ -18,11 +22,7 @@ class QgsRasterProjector : QgsRasterInterface
Exact, //!< Exact, precise but slow
};

/** \brief QgsRasterProjector implements approximate projection support for
* it calculates grid of points in source CRS for target CRS + extent
* which are used to calculate affine transformation matrices.
*/

//! @deprecated since 2.18: use default constructor
QgsRasterProjector( const QgsCoordinateReferenceSystem& theSrcCRS,
const QgsCoordinateReferenceSystem& theDestCRS,
int theSrcDatumTransform,
@@ -31,20 +31,21 @@ class QgsRasterProjector : QgsRasterInterface
int theDestRows, int theDestCols,
double theMaxSrcXRes, double theMaxSrcYRes,
const QgsRectangle& theExtent
);

) /Deprecated/;
//! @deprecated since 2.18: use default constructor
QgsRasterProjector( const QgsCoordinateReferenceSystem& theSrcCRS,
const QgsCoordinateReferenceSystem& theDestCRS,
const QgsRectangle& theDestExtent,
int theDestRows, int theDestCols,
double theMaxSrcXRes, double theMaxSrcYRes,
const QgsRectangle& theExtent
);
) /Deprecated/;
//! @deprecated since 2.18: use default constructor
QgsRasterProjector( const QgsCoordinateReferenceSystem& theSrcCRS,
const QgsCoordinateReferenceSystem& theDestCRS,
double theMaxSrcXRes, double theMaxSrcYRes,
const QgsRectangle& theExtent
);
) /Deprecated/;
QgsRasterProjector();

/** \brief The destructor */
@@ -66,15 +67,16 @@ class QgsRasterProjector : QgsRasterInterface
/** \brief Get destination CRS */
QgsCoordinateReferenceSystem destCrs() const;

/** \brief set maximum source resolution */
void setMaxSrcRes( double theMaxSrcXRes, double theMaxSrcYRes );
/** @deprecated since 2.18, does nothing */
void setMaxSrcRes( double theMaxSrcXRes, double theMaxSrcYRes ) /Deprecated/;

Precision precision() const;
void setPrecision( Precision precision );
// Translated precision mode, for use in ComboBox etc.
static QString precisionLabel( Precision precision );

QgsRasterBlock *block( int bandNo, const QgsRectangle & extent, int width, int height ) / Factory /;
QgsRasterBlock *block2( int bandNo, const QgsRectangle & extent, int width, int height, QgsRasterBlockFeedback* feedback = nullptr ) / Factory /;

/** Calculate destination extent and size from source extent and size */
bool destExtentSize( const QgsRectangle& theSrcExtent, int theSrcXSize, int theSrcYSize,
@@ -38,8 +38,6 @@ class QgsRasterRenderer : QgsRasterInterface

virtual bool setInput( QgsRasterInterface* input );

virtual QgsRasterBlock *block( int bandNo, const QgsRectangle &extent, int width, int height ) = 0 / Factory /;

bool usesTransparency() const;

void setOpacity( double opacity );
@@ -20,6 +20,7 @@ class QgsRasterResampleFilter : QgsRasterInterface
bool setInput( QgsRasterInterface* input );

QgsRasterBlock *block( int bandNo, const QgsRectangle &extent, int width, int height ) /Factory/;
QgsRasterBlock *block2( int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback* feedback = nullptr ) /Factory/;

/** Set resampler for zoomed in scales. Takes ownership of the object*/
void setZoomedInResampler( QgsRasterResampler* r /Transfer/ );
@@ -13,6 +13,7 @@ class QgsSingleBandColorDataRenderer: QgsRasterRenderer
bool setInput( QgsRasterInterface* input );

QgsRasterBlock* block( int bandNo, const QgsRectangle & extent, int width, int height ) / Factory /;
QgsRasterBlock* block2( int bandNo, const QgsRectangle & extent, int width, int height, QgsRasterBlockFeedback* feedback = nullptr ) / Factory /;

void writeXML( QDomDocument& doc, QDomElement& parentElem ) const;

@@ -17,6 +17,7 @@ class QgsSingleBandGrayRenderer: QgsRasterRenderer
static QgsRasterRenderer* create( const QDomElement& elem, QgsRasterDataProvider* provider ) /Factory/;

QgsRasterBlock *block( int bandNo, const QgsRectangle & extent, int width, int height ) / Factory /;
QgsRasterBlock *block2( int bandNo, const QgsRectangle & extent, int width, int height, QgsRasterBlockFeedback* feedback = nullptr ) / Factory /;

int grayBand() const;
void setGrayBand( int band );
@@ -12,6 +12,7 @@ class QgsSingleBandPseudoColorRenderer: QgsRasterRenderer
static QgsRasterRenderer* create( const QDomElement& elem, QgsRasterDataProvider* provider ) /Factory/;

QgsRasterBlock* block( int bandNo, const QgsRectangle & extent, int width, int height ) / Factory /;
QgsRasterBlock* block2( int bandNo, const QgsRectangle & extent, int width, int height, QgsRasterBlockFeedback* feedback = nullptr ) / Factory /;

/** Takes ownership of the shader*/
void setShader( QgsRasterShader* shader /Transfer/ );
@@ -194,6 +194,14 @@ static void dumpBacktrace( unsigned int depth )
depth = 20;

#if ((defined(linux) || defined(__linux__)) && !defined(ANDROID)) || defined(__FreeBSD__)
// Below there is a bunch of operations that are not safe in multi-threaded
// environment (dup()+close() combo, wait(), juggling with file descriptors).
// Maybe some problems could be resolved with dup2() and waitpid(), but it seems
// that if the operations on descriptors are not serialized, things will get nasty.
// That's why there's this lovely mutex here...
static QMutex mutex;
QMutexLocker locker( &mutex );

int stderr_fd = -1;
if ( access( "/usr/bin/c++filt", X_OK ) < 0 )
{

0 comments on commit f5b657d

Please sign in to comment.
You can’t perform that action at this time.