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