QGIS API Documentation  3.17.0-Master (a84647cf30)
qgsrastercontourrenderer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrastercontourrenderer.cpp
3  --------------------------------------
4  Date : March 2020
5  Copyright : (C) 2020 by Martin Dobias
6  Email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
17 
18 #include "qgslinesymbollayer.h"
19 #include "qgsreadwritecontext.h"
20 #include "qgssymbollayerutils.h"
22 
23 #include <gdal_alg.h>
24 
26  : QgsRasterRenderer( input, QStringLiteral( "contour" ) )
27 {
28  mContourSymbol.reset( static_cast<QgsLineSymbol *>( QgsLineSymbol::defaultSymbol( QgsWkbTypes::LineGeometry ) ) );
29 }
30 
32 
34 {
35  QgsRasterContourRenderer *renderer = new QgsRasterContourRenderer( nullptr );
36  renderer->copyCommonProperties( this );
37  renderer->mContourSymbol.reset( mContourSymbol ? mContourSymbol->clone() : nullptr );
38  renderer->mContourIndexSymbol.reset( mContourIndexSymbol ? mContourIndexSymbol->clone() : nullptr );
39  renderer->mContourInterval = mContourInterval;
40  renderer->mContourIndexInterval = mContourIndexInterval;
41  renderer->mInputBand = mInputBand;
42  renderer->mDownscale = mDownscale;
43  return renderer;
44 }
45 
47 {
48  if ( elem.isNull() )
49  {
50  return nullptr;
51  }
52 
54  r->readXml( elem );
55 
56  int inputBand = elem.attribute( QStringLiteral( "band" ), QStringLiteral( "-1" ) ).toInt();
57  double contourInterval = elem.attribute( QStringLiteral( "contour-interval" ), QStringLiteral( "100" ) ).toDouble();
58  double contourIndexInterval = elem.attribute( QStringLiteral( "contour-index-interval" ), QStringLiteral( "0" ) ).toDouble();
59  double downscale = elem.attribute( QStringLiteral( "downscale" ), QStringLiteral( "4" ) ).toDouble();
60 
61  r->setInputBand( inputBand );
62  r->setContourInterval( contourInterval );
63  r->setContourIndexInterval( contourIndexInterval );
64  r->setDownscale( downscale );
65 
66  QDomElement symbolsElem = elem.firstChildElement( QStringLiteral( "symbols" ) );
67  if ( !symbolsElem.isNull() )
68  {
70  if ( symbolMap.contains( QStringLiteral( "contour" ) ) )
71  {
72  QgsSymbol *symbol = symbolMap.take( QStringLiteral( "contour" ) );
73  if ( symbol->type() == QgsSymbol::Line )
74  r->setContourSymbol( static_cast<QgsLineSymbol *>( symbol ) );
75  }
76  if ( symbolMap.contains( QStringLiteral( "index-contour" ) ) )
77  {
78  QgsSymbol *symbol = symbolMap.take( QStringLiteral( "index-contour" ) );
79  if ( symbol->type() == QgsSymbol::Line )
80  r->setContourIndexSymbol( static_cast<QgsLineSymbol *>( symbol ) );
81  }
82  }
83  return r;
84 }
85 
86 void QgsRasterContourRenderer::writeXml( QDomDocument &doc, QDomElement &parentElem ) const
87 {
88  if ( parentElem.isNull() )
89  {
90  return;
91  }
92 
93  QDomElement rasterRendererElem = doc.createElement( QStringLiteral( "rasterrenderer" ) );
94  _writeXml( doc, rasterRendererElem );
95 
96  rasterRendererElem.setAttribute( QStringLiteral( "band" ), mInputBand );
97  rasterRendererElem.setAttribute( QStringLiteral( "contour-interval" ), mContourInterval );
98  rasterRendererElem.setAttribute( QStringLiteral( "contour-index-interval" ), mContourIndexInterval );
99  rasterRendererElem.setAttribute( QStringLiteral( "downscale" ), mDownscale );
100 
101  QgsSymbolMap symbols;
102  symbols[QStringLiteral( "contour" )] = mContourSymbol.get();
103  if ( mContourIndexSymbol )
104  symbols[QStringLiteral( "index-contour" )] = mContourIndexSymbol.get();
105  QDomElement symbolsElem = QgsSymbolLayerUtils::saveSymbols( symbols, QStringLiteral( "symbols" ), doc, QgsReadWriteContext() );
106  rasterRendererElem.appendChild( symbolsElem );
107 
108  parentElem.appendChild( rasterRendererElem );
109 }
110 
112 {
113  QPainter *painter;
114  double scaleX, scaleY;
119 };
120 
121 CPLErr _rasterContourWriter( double dfLevel, int nPoints, double *padfX, double *padfY, void *ptr )
122 {
123  Q_UNUSED( dfLevel )
124  ContourWriterData *crData = static_cast<ContourWriterData *>( ptr );
125  QPolygonF polygon( nPoints );
126  QPointF *d = polygon.data();
127  for ( int i = 0; i < nPoints; ++i )
128  {
129  d[i] = QPointF( padfX[i] * crData->scaleX, padfY[i] * crData->scaleY );
130  }
131 
132  if ( crData->indexSymbol && !qgsDoubleNear( crData->indexInterval, 0 ) && qgsDoubleNear( fmod( dfLevel, crData->indexInterval ), 0 ) )
133  crData->indexSymbol->renderPolyline( polygon, nullptr, *crData->context );
134  else
135  crData->symbol->renderPolyline( polygon, nullptr, *crData->context );
136  return CE_None;
137 }
138 
139 QgsRasterBlock *QgsRasterContourRenderer::block( int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback )
140 {
141  Q_UNUSED( bandNo )
142 
143  std::unique_ptr< QgsRasterBlock > outputBlock( new QgsRasterBlock() );
144  if ( !mInput || !mContourSymbol )
145  {
146  return outputBlock.release();
147  }
148 
149  int inputWidth = static_cast<int>( round( width / mDownscale ) );
150  int inputHeight = static_cast<int>( round( height / mDownscale ) );
151 
152  std::unique_ptr< QgsRasterBlock > inputBlock( mInput->block( mInputBand, extent, inputWidth, inputHeight, feedback ) );
153  if ( !inputBlock || inputBlock->isEmpty() )
154  {
155  QgsDebugMsg( QStringLiteral( "No raster data!" ) );
156  return outputBlock.release();
157  }
158 
159  if ( !inputBlock->convert( Qgis::Float64 ) ) // contouring algorithm requires double
160  return outputBlock.release();
161  double *scanline = reinterpret_cast<double *>( inputBlock->bits() );
162 
163  QImage img( width, height, QImage::Format_ARGB32_Premultiplied );
164  img.fill( Qt::transparent );
165 
166  QPainter p( &img );
167  p.setRenderHint( QPainter::Antialiasing );
168 
170 
171  ContourWriterData crData;
172  crData.painter = &p;
173  crData.scaleX = width / double( inputWidth );
174  crData.scaleY = height / double( inputHeight );
175  crData.symbol = mContourSymbol.get();
176  crData.indexSymbol = mContourIndexSymbol.get();
177  crData.indexInterval = mContourIndexInterval;
178  crData.context = &context;
179 
180  crData.symbol->startRender( context );
181  if ( crData.indexSymbol )
182  crData.indexSymbol->startRender( context );
183 
184  double contourBase = 0.;
185  GDALContourGeneratorH cg = GDAL_CG_Create( inputBlock->width(), inputBlock->height(),
186  inputBlock->hasNoDataValue(), inputBlock->noDataValue(),
187  mContourInterval, contourBase,
188  _rasterContourWriter, static_cast<void *>( &crData ) );
189  for ( int i = 0; i < inputHeight; ++i )
190  {
191  if ( feedback && feedback->isCanceled() )
192  break;
193 
194  GDAL_CG_FeedLine( cg, scanline );
195  scanline += inputWidth;
196  }
197  GDAL_CG_Destroy( cg );
198 
199  crData.symbol->stopRender( context );
200  if ( crData.indexSymbol )
201  crData.indexSymbol->stopRender( context );
202 
203  p.end();
204 
205  outputBlock->setImage( &img );
206  return outputBlock.release();
207 }
208 
210 {
211  QList<int> bandList;
212  if ( mInputBand != -1 )
213  {
214  bandList << mInputBand;
215  }
216  return bandList;
217 }
218 
219 QList<QgsLayerTreeModelLegendNode *> QgsRasterContourRenderer::createLegendNodes( QgsLayerTreeLayer *nodeLayer )
220 {
221  QList<QgsLayerTreeModelLegendNode *> nodes;
222 
223  QgsLegendSymbolItem contourItem( mContourSymbol.get(), QString::number( mContourInterval ), QStringLiteral( "contour" ) );
224  nodes << new QgsSymbolLegendNode( nodeLayer, contourItem );
225 
226  if ( mContourIndexInterval > 0 )
227  {
228  QgsLegendSymbolItem indexItem( mContourIndexSymbol.get(), QString::number( mContourIndexInterval ), QStringLiteral( "index" ) );
229  nodes << new QgsSymbolLegendNode( nodeLayer, indexItem );
230  }
231 
232  return nodes;
233 }
234 
236 {
237  mContourSymbol.reset( symbol );
238 }
239 
241 {
242  mContourIndexSymbol.reset( symbol );
243 }
The class is used as a container of context for various read/write operations on other objects...
A rectangle specified with double values.
Definition: qgsrectangle.h:41
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:64
virtual QgsRectangle extent() const
Gets the extent of the interface.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:316
virtual QgsRasterInterface * input() const
Current input.
void renderPolyline(const QPolygonF &points, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
Renders the symbol along the line joining points, using the given render context. ...
Definition: qgssymbol.cpp:2206
Implementation of legend node interface for displaying preview of vector symbols and their labels and...
void setContourIndexSymbol(QgsLineSymbol *symbol)
Sets the symbol of index contour lines.
Line symbol.
Definition: qgssymbol.h:89
void setContourInterval(double interval)
Sets the interval of contour lines generation.
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgssymbol.h:1192
void startRender(QgsRenderContext &context, const QgsFields &fields=QgsFields())
Begins the rendering process for the symbol.
Definition: qgssymbol.cpp:480
Sixty four bit floating point (double)
Definition: qgis.h:110
static QgsSymbol * defaultSymbol(QgsWkbTypes::GeometryType geomType)
Returns a new default symbol for the specified geometry type.
Definition: qgssymbol.cpp:346
Raster data container.
QList< int > usesBands() const override
Returns a list of band numbers used by the renderer.
virtual QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr)=0
Read block of data using given extent and size.
static QDomElement saveSymbols(QgsSymbolMap &symbols, const QString &tagName, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a collection of symbols to XML with specified tagName for the top-level element.
void _writeXml(QDomDocument &doc, QDomElement &rasterRendererElem) const
Write upper class info into rasterrenderer element (called by writeXml method of subclasses) ...
void copyCommonProperties(const QgsRasterRenderer *other, bool copyMinMaxOrigin=true)
Copies common properties like opacity / transparency data from other renderer.
static QgsRenderContext fromQPainter(QPainter *painter)
Creates a default render context given a pixel based QPainter destination.
void writeXml(QDomDocument &doc, QDomElement &parentElem) const override
Write base class members to xml.
QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr) override
Read block of data using given extent and size.
Raster renderer that generates contours on the fly for a source raster band.
QList< QgsLayerTreeModelLegendNode * > createLegendNodes(QgsLayerTreeLayer *nodeLayer) override
Creates a set of legend nodes representing the renderer.
void readXml(const QDomElement &rendererElem) override
Sets base class members from xml. Usually called from create() methods of subclasses.
void setDownscale(double scale)
Sets by how much the renderer will scale down the request to the data provider.
static QgsSymbolMap loadSymbols(QDomElement &element, const QgsReadWriteContext &context)
Reads a collection of symbols from XML and returns them in a map. Caller is responsible for deleting ...
Base class for processing filters like renderers, reprojector, resampler etc.
void setContourIndexInterval(double interval)
Sets the interval of index contour lines (index contour lines are typical further apart and with a wi...
The class stores information about one class/rule of a vector layer renderer in a unified way that ca...
Contains information about the context of a rendering operation.
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:53
SymbolType type() const
Returns the symbol&#39;s type.
Definition: qgssymbol.h:138
double contourInterval() const
Returns the interval of contour lines generation.
QgsRasterContourRenderer * clone() const override
Clone itself, create deep copy.
static QgsRasterRenderer * create(const QDomElement &elem, QgsRasterInterface *input)
Creates an instance of the renderer based on definition from XML (used by renderer registry) ...
QgsRasterContourRenderer(QgsRasterInterface *input)
Creates a contour renderer.
QMap< QString, QgsSymbol *> QgsSymbolMap
Definition: qgsrenderer.h:46
double contourIndexInterval() const
Returns the interval of index contour lines (index contour lines are typical further apart and with a...
int inputBand() const
Returns the number of the input raster band.
double downscale() const
Returns by how much the renderer will scale down the request to the data provider.
QgsRasterInterface * mInput
~QgsRasterContourRenderer() override
Feedback object tailored for raster block reading.
void stopRender(QgsRenderContext &context)
Ends the rendering process.
Definition: qgssymbol.cpp:507
void setInputBand(int band)
Sets the number of the input raster band.
Raster renderer pipe that applies colors to a raster.
Layer tree node points to a map layer.
void setContourSymbol(QgsLineSymbol *symbol)
Sets the symbol used for contour lines. Takes ownership of the passed symbol.
CPLErr _rasterContourWriter(double dfLevel, int nPoints, double *padfX, double *padfY, void *ptr)