QGIS API Documentation 3.99.0-Master (d270888f95f)
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 <gdal_alg.h>
19
21#include "qgslinesymbol.h"
22#include "qgsreadwritecontext.h"
23#include "qgssymbollayerutils.h"
24
25#include <QString>
26
27using namespace Qt::StringLiterals;
28
34
36
38{
39 QgsRasterContourRenderer *renderer = new QgsRasterContourRenderer( nullptr );
40 renderer->copyCommonProperties( this );
41 renderer->mContourSymbol.reset( mContourSymbol ? mContourSymbol->clone() : nullptr );
42 renderer->mContourIndexSymbol.reset( mContourIndexSymbol ? mContourIndexSymbol->clone() : nullptr );
43 renderer->mContourInterval = mContourInterval;
44 renderer->mContourIndexInterval = mContourIndexInterval;
45 renderer->mInputBand = mInputBand;
46 renderer->mDownscale = mDownscale;
47 return renderer;
48}
49
54
56{
57 if ( elem.isNull() )
58 {
59 return nullptr;
60 }
61
63 r->readXml( elem );
64
65 const int inputBand = elem.attribute( u"band"_s, u"-1"_s ).toInt();
66 const double contourInterval = elem.attribute( u"contour-interval"_s, u"100"_s ).toDouble();
67 const double contourIndexInterval = elem.attribute( u"contour-index-interval"_s, u"0"_s ).toDouble();
68 const double downscale = elem.attribute( u"downscale"_s, u"4"_s ).toDouble();
69
74
75 QDomElement symbolsElem = elem.firstChildElement( u"symbols"_s );
76 if ( !symbolsElem.isNull() )
77 {
79 if ( symbolMap.contains( u"contour"_s ) )
80 {
81 QgsSymbol *symbol = symbolMap.take( u"contour"_s );
82 if ( symbol->type() == Qgis::SymbolType::Line )
83 r->setContourSymbol( static_cast<QgsLineSymbol *>( symbol ) );
84 }
85 if ( symbolMap.contains( u"index-contour"_s ) )
86 {
87 QgsSymbol *symbol = symbolMap.take( u"index-contour"_s );
88 if ( symbol->type() == Qgis::SymbolType::Line )
89 r->setContourIndexSymbol( static_cast<QgsLineSymbol *>( symbol ) );
90 }
91 }
92 return r;
93}
94
95void QgsRasterContourRenderer::writeXml( QDomDocument &doc, QDomElement &parentElem ) const
96{
97 if ( parentElem.isNull() )
98 {
99 return;
100 }
101
102 QDomElement rasterRendererElem = doc.createElement( u"rasterrenderer"_s );
103 _writeXml( doc, rasterRendererElem );
104
105 rasterRendererElem.setAttribute( u"band"_s, mInputBand );
106 rasterRendererElem.setAttribute( u"contour-interval"_s, mContourInterval );
107 rasterRendererElem.setAttribute( u"contour-index-interval"_s, mContourIndexInterval );
108 rasterRendererElem.setAttribute( u"downscale"_s, mDownscale );
109
110 QgsSymbolMap symbols;
111 symbols[u"contour"_s] = mContourSymbol.get();
112 if ( mContourIndexSymbol )
113 symbols[u"index-contour"_s] = mContourIndexSymbol.get();
114 const QDomElement symbolsElem = QgsSymbolLayerUtils::saveSymbols( symbols, u"symbols"_s, doc, QgsReadWriteContext() );
115 rasterRendererElem.appendChild( symbolsElem );
116
117 parentElem.appendChild( rasterRendererElem );
118}
119
129
130CPLErr _rasterContourWriter( double dfLevel, int nPoints, double *padfX, double *padfY, void *ptr )
131{
132 Q_UNUSED( dfLevel )
133 ContourWriterData *crData = static_cast<ContourWriterData *>( ptr );
134 QPolygonF polygon( nPoints );
135 QPointF *d = polygon.data();
136 for ( int i = 0; i < nPoints; ++i )
137 {
138 d[i] = QPointF( padfX[i] * crData->scaleX, padfY[i] * crData->scaleY );
139 }
140
141 if ( crData->indexSymbol && !qgsDoubleNear( crData->indexInterval, 0 ) && qgsDoubleNear( fmod( dfLevel, crData->indexInterval ), 0 ) )
142 crData->indexSymbol->renderPolyline( polygon, nullptr, *crData->context );
143 else
144 crData->symbol->renderPolyline( polygon, nullptr, *crData->context );
145 return CE_None;
146}
147
148QgsRasterBlock *QgsRasterContourRenderer::block( int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback )
149{
150 Q_UNUSED( bandNo )
151
152 auto outputBlock = std::make_unique<QgsRasterBlock>();
153 if ( !mInput || !mContourSymbol )
154 {
155 return outputBlock.release();
156 }
157
158 const int inputWidth = static_cast<int>( round( width / mDownscale ) );
159 const int inputHeight = static_cast<int>( round( height / mDownscale ) );
160
161 std::unique_ptr< QgsRasterBlock > inputBlock( mInput->block( mInputBand, extent, inputWidth, inputHeight, feedback ) );
162 if ( !inputBlock || inputBlock->isEmpty() )
163 {
164 QgsDebugError( u"No raster data!"_s );
165 return outputBlock.release();
166 }
167
168 if ( !inputBlock->convert( Qgis::DataType::Float64 ) ) // contouring algorithm requires double
169 return outputBlock.release();
170 double *scanline = reinterpret_cast<double *>( inputBlock->bits() );
171
172 QImage img( width, height, QImage::Format_ARGB32_Premultiplied );
173 img.fill( Qt::transparent );
174
175 QPainter p( &img );
176 p.setRenderHint( QPainter::Antialiasing );
177
179
180 ContourWriterData crData;
181 crData.painter = &p;
182 crData.scaleX = width / double( inputWidth );
183 crData.scaleY = height / double( inputHeight );
184 crData.symbol = mContourSymbol.get();
185 crData.indexSymbol = mContourIndexSymbol.get();
186 crData.indexInterval = mContourIndexInterval;
187 crData.context = &context;
188
189 crData.symbol->startRender( context );
190 if ( crData.indexSymbol )
191 crData.indexSymbol->startRender( context );
192
193 const double contourBase = 0.;
194 GDALContourGeneratorH cg = GDAL_CG_Create( inputBlock->width(), inputBlock->height(),
195 inputBlock->hasNoDataValue(), inputBlock->noDataValue(),
196 mContourInterval, contourBase,
197 _rasterContourWriter, static_cast<void *>( &crData ) );
198 for ( int i = 0; i < inputHeight; ++i )
199 {
200 if ( feedback && feedback->isCanceled() )
201 break;
202
203 GDAL_CG_FeedLine( cg, scanline );
204 scanline += inputWidth;
205 }
206 GDAL_CG_Destroy( cg );
207
208 crData.symbol->stopRender( context );
209 if ( crData.indexSymbol )
210 crData.indexSymbol->stopRender( context );
211
212 p.end();
213
214 outputBlock->setImage( &img );
215 return outputBlock.release();
216}
217
219{
220 QList<int> bandList;
221 if ( mInputBand != -1 )
222 {
223 bandList << mInputBand;
224 }
225 return bandList;
226}
227
228QList<QgsLayerTreeModelLegendNode *> QgsRasterContourRenderer::createLegendNodes( QgsLayerTreeLayer *nodeLayer )
229{
230 QList<QgsLayerTreeModelLegendNode *> nodes;
231
232 const QgsLegendSymbolItem contourItem( mContourSymbol.get(), QString::number( mContourInterval ), u"contour"_s );
233 nodes << new QgsSymbolLegendNode( nodeLayer, contourItem );
234
235 if ( mContourIndexInterval > 0 )
236 {
237 const QgsLegendSymbolItem indexItem( mContourIndexSymbol.get(), QString::number( mContourIndexInterval ), u"index"_s );
238 nodes << new QgsSymbolLegendNode( nodeLayer, indexItem );
239 }
240
241 return nodes;
242}
243
245{
246 return mInputBand;
247}
248
250{
251 if ( !mInput )
252 {
253 mInputBand = band;
254 return true;
255 }
256 else if ( band > 0 && band <= mInput->bandCount() )
257 {
258 mInputBand = band;
259 return true;
260 }
261 return false;
262}
263
265{
266 mContourSymbol.reset( symbol );
267}
268
270{
271 mContourIndexSymbol.reset( symbol );
272}
QFlags< RasterRendererFlag > RasterRendererFlags
Flags which control behavior of raster renderers.
Definition qgis.h:1570
@ UseNoDataForOutOfRangePixels
Out of range pixels (eg those values outside of the rendered map's z range filter) should be set usin...
Definition qgis.h:1562
@ Line
Lines.
Definition qgis.h:367
@ Float64
Sixty four bit floating point (double).
Definition qgis.h:388
@ Line
Line symbol.
Definition qgis.h:631
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:55
Layer tree node points to a map layer.
Stores information about one class/rule of a vector layer renderer in a unified way that can be used ...
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.
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.
QgsRasterInterface(QgsRasterInterface *input=nullptr)
QgsRasterInterface * mInput
virtual QgsRectangle extent() const
Gets the extent of the interface.
virtual QgsRasterInterface * input() const
Current input.
QgsRasterRenderer(QgsRasterInterface *input=nullptr, const QString &type=QString())
Constructor for QgsRasterRenderer.
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.
A container for the context for various read/write operations on 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:294
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:6900
#define QgsDebugError(str)
Definition qgslogger.h:59
CPLErr _rasterContourWriter(double dfLevel, int nPoints, double *padfX, double *padfY, void *ptr)
QMap< QString, QgsSymbol * > QgsSymbolMap
Definition qgsrenderer.h:52