QGIS API Documentation 3.39.0-Master (3783037d301)
Loading...
Searching...
No Matches
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 "qgsreadwritecontext.h"
19#include "qgssymbollayerutils.h"
21#include "qgslinesymbol.h"
22
23#include <gdal_alg.h>
24
26 : QgsRasterRenderer( input, QStringLiteral( "contour" ) )
27{
28 mContourSymbol.reset( static_cast<QgsLineSymbol *>( QgsLineSymbol::defaultSymbol( Qgis::GeometryType::Line ) ) );
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
50
52{
53 if ( elem.isNull() )
54 {
55 return nullptr;
56 }
57
59 r->readXml( elem );
60
61 const int inputBand = elem.attribute( QStringLiteral( "band" ), QStringLiteral( "-1" ) ).toInt();
62 const double contourInterval = elem.attribute( QStringLiteral( "contour-interval" ), QStringLiteral( "100" ) ).toDouble();
63 const double contourIndexInterval = elem.attribute( QStringLiteral( "contour-index-interval" ), QStringLiteral( "0" ) ).toDouble();
64 const double downscale = elem.attribute( QStringLiteral( "downscale" ), QStringLiteral( "4" ) ).toDouble();
65
70
71 QDomElement symbolsElem = elem.firstChildElement( QStringLiteral( "symbols" ) );
72 if ( !symbolsElem.isNull() )
73 {
75 if ( symbolMap.contains( QStringLiteral( "contour" ) ) )
76 {
77 QgsSymbol *symbol = symbolMap.take( QStringLiteral( "contour" ) );
78 if ( symbol->type() == Qgis::SymbolType::Line )
79 r->setContourSymbol( static_cast<QgsLineSymbol *>( symbol ) );
80 }
81 if ( symbolMap.contains( QStringLiteral( "index-contour" ) ) )
82 {
83 QgsSymbol *symbol = symbolMap.take( QStringLiteral( "index-contour" ) );
84 if ( symbol->type() == Qgis::SymbolType::Line )
85 r->setContourIndexSymbol( static_cast<QgsLineSymbol *>( symbol ) );
86 }
87 }
88 return r;
89}
90
91void QgsRasterContourRenderer::writeXml( QDomDocument &doc, QDomElement &parentElem ) const
92{
93 if ( parentElem.isNull() )
94 {
95 return;
96 }
97
98 QDomElement rasterRendererElem = doc.createElement( QStringLiteral( "rasterrenderer" ) );
99 _writeXml( doc, rasterRendererElem );
100
101 rasterRendererElem.setAttribute( QStringLiteral( "band" ), mInputBand );
102 rasterRendererElem.setAttribute( QStringLiteral( "contour-interval" ), mContourInterval );
103 rasterRendererElem.setAttribute( QStringLiteral( "contour-index-interval" ), mContourIndexInterval );
104 rasterRendererElem.setAttribute( QStringLiteral( "downscale" ), mDownscale );
105
106 QgsSymbolMap symbols;
107 symbols[QStringLiteral( "contour" )] = mContourSymbol.get();
108 if ( mContourIndexSymbol )
109 symbols[QStringLiteral( "index-contour" )] = mContourIndexSymbol.get();
110 const QDomElement symbolsElem = QgsSymbolLayerUtils::saveSymbols( symbols, QStringLiteral( "symbols" ), doc, QgsReadWriteContext() );
111 rasterRendererElem.appendChild( symbolsElem );
112
113 parentElem.appendChild( rasterRendererElem );
114}
115
125
126CPLErr _rasterContourWriter( double dfLevel, int nPoints, double *padfX, double *padfY, void *ptr )
127{
128 Q_UNUSED( dfLevel )
129 ContourWriterData *crData = static_cast<ContourWriterData *>( ptr );
130 QPolygonF polygon( nPoints );
131 QPointF *d = polygon.data();
132 for ( int i = 0; i < nPoints; ++i )
133 {
134 d[i] = QPointF( padfX[i] * crData->scaleX, padfY[i] * crData->scaleY );
135 }
136
137 if ( crData->indexSymbol && !qgsDoubleNear( crData->indexInterval, 0 ) && qgsDoubleNear( fmod( dfLevel, crData->indexInterval ), 0 ) )
138 crData->indexSymbol->renderPolyline( polygon, nullptr, *crData->context );
139 else
140 crData->symbol->renderPolyline( polygon, nullptr, *crData->context );
141 return CE_None;
142}
143
144QgsRasterBlock *QgsRasterContourRenderer::block( int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback )
145{
146 Q_UNUSED( bandNo )
147
148 std::unique_ptr< QgsRasterBlock > outputBlock( new QgsRasterBlock() );
149 if ( !mInput || !mContourSymbol )
150 {
151 return outputBlock.release();
152 }
153
154 const int inputWidth = static_cast<int>( round( width / mDownscale ) );
155 const int inputHeight = static_cast<int>( round( height / mDownscale ) );
156
157 std::unique_ptr< QgsRasterBlock > inputBlock( mInput->block( mInputBand, extent, inputWidth, inputHeight, feedback ) );
158 if ( !inputBlock || inputBlock->isEmpty() )
159 {
160 QgsDebugError( QStringLiteral( "No raster data!" ) );
161 return outputBlock.release();
162 }
163
164 if ( !inputBlock->convert( Qgis::DataType::Float64 ) ) // contouring algorithm requires double
165 return outputBlock.release();
166 double *scanline = reinterpret_cast<double *>( inputBlock->bits() );
167
168 QImage img( width, height, QImage::Format_ARGB32_Premultiplied );
169 img.fill( Qt::transparent );
170
171 QPainter p( &img );
172 p.setRenderHint( QPainter::Antialiasing );
173
175
176 ContourWriterData crData;
177 crData.painter = &p;
178 crData.scaleX = width / double( inputWidth );
179 crData.scaleY = height / double( inputHeight );
180 crData.symbol = mContourSymbol.get();
181 crData.indexSymbol = mContourIndexSymbol.get();
182 crData.indexInterval = mContourIndexInterval;
183 crData.context = &context;
184
185 crData.symbol->startRender( context );
186 if ( crData.indexSymbol )
187 crData.indexSymbol->startRender( context );
188
189 const double contourBase = 0.;
190 GDALContourGeneratorH cg = GDAL_CG_Create( inputBlock->width(), inputBlock->height(),
191 inputBlock->hasNoDataValue(), inputBlock->noDataValue(),
192 mContourInterval, contourBase,
193 _rasterContourWriter, static_cast<void *>( &crData ) );
194 for ( int i = 0; i < inputHeight; ++i )
195 {
196 if ( feedback && feedback->isCanceled() )
197 break;
198
199 GDAL_CG_FeedLine( cg, scanline );
200 scanline += inputWidth;
201 }
202 GDAL_CG_Destroy( cg );
203
204 crData.symbol->stopRender( context );
205 if ( crData.indexSymbol )
206 crData.indexSymbol->stopRender( context );
207
208 p.end();
209
210 outputBlock->setImage( &img );
211 return outputBlock.release();
212}
213
215{
216 QList<int> bandList;
217 if ( mInputBand != -1 )
218 {
219 bandList << mInputBand;
220 }
221 return bandList;
222}
223
224QList<QgsLayerTreeModelLegendNode *> QgsRasterContourRenderer::createLegendNodes( QgsLayerTreeLayer *nodeLayer )
225{
226 QList<QgsLayerTreeModelLegendNode *> nodes;
227
228 const QgsLegendSymbolItem contourItem( mContourSymbol.get(), QString::number( mContourInterval ), QStringLiteral( "contour" ) );
229 nodes << new QgsSymbolLegendNode( nodeLayer, contourItem );
230
231 if ( mContourIndexInterval > 0 )
232 {
233 const QgsLegendSymbolItem indexItem( mContourIndexSymbol.get(), QString::number( mContourIndexInterval ), QStringLiteral( "index" ) );
234 nodes << new QgsSymbolLegendNode( nodeLayer, indexItem );
235 }
236
237 return nodes;
238}
239
241{
242 return mInputBand;
243}
244
246{
247 if ( !mInput )
248 {
249 mInputBand = band;
250 return true;
251 }
252 else if ( band > 0 && band <= mInput->bandCount() )
253 {
254 mInputBand = band;
255 return true;
256 }
257 return false;
258}
259
261{
262 mContourSymbol.reset( symbol );
263}
264
266{
267 mContourIndexSymbol.reset( symbol );
268}
QFlags< RasterRendererFlag > RasterRendererFlags
Flags which control behavior of raster renderers.
Definition qgis.h:1404
@ UseNoDataForOutOfRangePixels
Out of range pixels (eg those values outside of the rendered map's z range filter) should be set usin...
@ Float64
Sixty four bit floating point (double)
@ Line
Line symbol.
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:53
Layer tree node points to a map layer.
The class stores information about one class/rule of a vector layer renderer in a unified way that ca...
A line symbol type, for rendering LineString and MultiLineString geometries.
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.
Feedback object tailored for raster block reading.
Raster data container.
Raster renderer that generates contours on the fly for a source raster band.
int inputBand() const override
Returns the input band for the renderer, or -1 if no input band is available.
static QgsRasterRenderer * create(const QDomElement &elem, QgsRasterInterface *input)
Creates an instance of the renderer based on definition from XML (used by renderer registry)
QgsRasterContourRenderer * clone() const override
Clone itself, create deep copy.
void setDownscale(double scale)
Sets by how much the renderer will scale down the request to the data provider.
QgsRasterContourRenderer(QgsRasterInterface *input)
Creates a contour renderer.
void setContourIndexSymbol(QgsLineSymbol *symbol)
Sets the symbol of index contour lines.
void setContourInterval(double interval)
Sets the interval of contour lines generation.
QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr) override
Read block of data using given extent and size.
Qgis::RasterRendererFlags flags() const override
Returns flags which dictate renderer behavior.
void writeXml(QDomDocument &doc, QDomElement &parentElem) const override
Write base class members to xml.
QList< QgsLayerTreeModelLegendNode * > createLegendNodes(QgsLayerTreeLayer *nodeLayer) override
Creates a set of legend nodes representing the renderer.
~QgsRasterContourRenderer() override
double downscale() const
Returns by how much the renderer will scale down the request to the data provider.
void setContourIndexInterval(double interval)
Sets the interval of index contour lines (index contour lines are typical further apart and with a wi...
bool setInputBand(int band) override
Attempts to set the input band for the renderer.
double contourInterval() const
Returns the interval of contour lines generation.
double contourIndexInterval() const
Returns the interval of index contour lines (index contour lines are typical further apart and with a...
void setContourSymbol(QgsLineSymbol *symbol)
Sets the symbol used for contour lines. Takes ownership of the passed symbol.
QList< int > usesBands() const override
Returns a list of band numbers used by the renderer.
Base class for processing filters like renderers, reprojector, resampler etc.
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.
QgsRasterInterface * mInput
virtual QgsRectangle extent() const
Gets the extent of the interface.
virtual QgsRasterInterface * input() const
Current input.
Raster renderer pipe that applies colors to a raster.
void _writeXml(QDomDocument &doc, QDomElement &rasterRendererElem) const
Write upper class info into rasterrenderer element (called by writeXml method of subclasses)
int bandCount() const override
Gets number of bands.
void copyCommonProperties(const QgsRasterRenderer *other, bool copyMinMaxOrigin=true)
Copies common properties like opacity / transparency data from other renderer.
void readXml(const QDomElement &rendererElem) override
Sets base class members from xml. Usually called from create() methods of subclasses.
The class is used as a container of context for various read/write operations on other objects.
A rectangle specified with double values.
Contains information about the context of a rendering operation.
static QgsRenderContext fromQPainter(QPainter *painter)
Creates a default render context given a pixel based QPainter destination.
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 ...
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.
Implementation of legend node interface for displaying preview of vector symbols and their labels and...
Abstract base class for all rendered symbols.
Definition qgssymbol.h:231
void stopRender(QgsRenderContext &context)
Ends the rendering process.
Qgis::SymbolType type() const
Returns the symbol's type.
Definition qgssymbol.h:293
void startRender(QgsRenderContext &context, const QgsFields &fields=QgsFields())
Begins the rendering process for the symbol.
static QgsSymbol * defaultSymbol(Qgis::GeometryType geomType)
Returns a new default symbol for the specified geometry type.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:5904
#define QgsDebugError(str)
Definition qgslogger.h:38
CPLErr _rasterContourWriter(double dfLevel, int nPoints, double *padfX, double *padfY, void *ptr)
QMap< QString, QgsSymbol * > QgsSymbolMap
Definition qgsrenderer.h:48