LCOV - code coverage report
Current view: top level - core/raster - qgsrastercontourrenderer.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 0 145 0.0 %
Date: 2021-04-10 08:29:14 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       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                 :            : 
      16                 :            : #include "qgsrastercontourrenderer.h"
      17                 :            : 
      18                 :            : #include "qgslinesymbollayer.h"
      19                 :            : #include "qgsreadwritecontext.h"
      20                 :            : #include "qgssymbollayerutils.h"
      21                 :            : #include "qgslayertreemodellegendnode.h"
      22                 :            : 
      23                 :            : #include <gdal_alg.h>
      24                 :            : 
      25                 :          0 : QgsRasterContourRenderer::QgsRasterContourRenderer( QgsRasterInterface *input )
      26                 :          0 :   : QgsRasterRenderer( input, QStringLiteral( "contour" ) )
      27                 :          0 : {
      28                 :          0 :   mContourSymbol.reset( static_cast<QgsLineSymbol *>( QgsLineSymbol::defaultSymbol( QgsWkbTypes::LineGeometry ) ) );
      29                 :          0 : }
      30                 :            : 
      31                 :          0 : QgsRasterContourRenderer::~QgsRasterContourRenderer() = default;
      32                 :            : 
      33                 :          0 : QgsRasterContourRenderer *QgsRasterContourRenderer::clone() const
      34                 :            : {
      35                 :          0 :   QgsRasterContourRenderer *renderer = new QgsRasterContourRenderer( nullptr );
      36                 :          0 :   renderer->copyCommonProperties( this );
      37                 :          0 :   renderer->mContourSymbol.reset( mContourSymbol ? mContourSymbol->clone() : nullptr );
      38                 :          0 :   renderer->mContourIndexSymbol.reset( mContourIndexSymbol ? mContourIndexSymbol->clone() : nullptr );
      39                 :          0 :   renderer->mContourInterval = mContourInterval;
      40                 :          0 :   renderer->mContourIndexInterval = mContourIndexInterval;
      41                 :          0 :   renderer->mInputBand = mInputBand;
      42                 :          0 :   renderer->mDownscale = mDownscale;
      43                 :          0 :   return renderer;
      44                 :          0 : }
      45                 :            : 
      46                 :          0 : QgsRasterRenderer *QgsRasterContourRenderer::create( const QDomElement &elem, QgsRasterInterface *input )
      47                 :            : {
      48                 :          0 :   if ( elem.isNull() )
      49                 :            :   {
      50                 :          0 :     return nullptr;
      51                 :            :   }
      52                 :            : 
      53                 :          0 :   QgsRasterContourRenderer *r = new QgsRasterContourRenderer( input );
      54                 :          0 :   r->readXml( elem );
      55                 :            : 
      56                 :          0 :   int inputBand = elem.attribute( QStringLiteral( "band" ), QStringLiteral( "-1" ) ).toInt();
      57                 :          0 :   double contourInterval = elem.attribute( QStringLiteral( "contour-interval" ), QStringLiteral( "100" ) ).toDouble();
      58                 :          0 :   double contourIndexInterval = elem.attribute( QStringLiteral( "contour-index-interval" ), QStringLiteral( "0" ) ).toDouble();
      59                 :          0 :   double downscale = elem.attribute( QStringLiteral( "downscale" ), QStringLiteral( "4" ) ).toDouble();
      60                 :            : 
      61                 :          0 :   r->setInputBand( inputBand );
      62                 :          0 :   r->setContourInterval( contourInterval );
      63                 :          0 :   r->setContourIndexInterval( contourIndexInterval );
      64                 :          0 :   r->setDownscale( downscale );
      65                 :            : 
      66                 :          0 :   QDomElement symbolsElem = elem.firstChildElement( QStringLiteral( "symbols" ) );
      67                 :          0 :   if ( !symbolsElem.isNull() )
      68                 :            :   {
      69                 :          0 :     QgsSymbolMap symbolMap = QgsSymbolLayerUtils::loadSymbols( symbolsElem, QgsReadWriteContext() );
      70                 :          0 :     if ( symbolMap.contains( QStringLiteral( "contour" ) ) )
      71                 :            :     {
      72                 :          0 :       QgsSymbol *symbol = symbolMap.take( QStringLiteral( "contour" ) );
      73                 :          0 :       if ( symbol->type() == QgsSymbol::Line )
      74                 :          0 :         r->setContourSymbol( static_cast<QgsLineSymbol *>( symbol ) );
      75                 :          0 :     }
      76                 :          0 :     if ( symbolMap.contains( QStringLiteral( "index-contour" ) ) )
      77                 :            :     {
      78                 :          0 :       QgsSymbol *symbol = symbolMap.take( QStringLiteral( "index-contour" ) );
      79                 :          0 :       if ( symbol->type() == QgsSymbol::Line )
      80                 :          0 :         r->setContourIndexSymbol( static_cast<QgsLineSymbol *>( symbol ) );
      81                 :          0 :     }
      82                 :          0 :   }
      83                 :          0 :   return r;
      84                 :          0 : }
      85                 :            : 
      86                 :          0 : void QgsRasterContourRenderer::writeXml( QDomDocument &doc, QDomElement &parentElem ) const
      87                 :            : {
      88                 :          0 :   if ( parentElem.isNull() )
      89                 :            :   {
      90                 :          0 :     return;
      91                 :            :   }
      92                 :            : 
      93                 :          0 :   QDomElement rasterRendererElem = doc.createElement( QStringLiteral( "rasterrenderer" ) );
      94                 :          0 :   _writeXml( doc, rasterRendererElem );
      95                 :            : 
      96                 :          0 :   rasterRendererElem.setAttribute( QStringLiteral( "band" ), mInputBand );
      97                 :          0 :   rasterRendererElem.setAttribute( QStringLiteral( "contour-interval" ), mContourInterval );
      98                 :          0 :   rasterRendererElem.setAttribute( QStringLiteral( "contour-index-interval" ), mContourIndexInterval );
      99                 :          0 :   rasterRendererElem.setAttribute( QStringLiteral( "downscale" ), mDownscale );
     100                 :            : 
     101                 :          0 :   QgsSymbolMap symbols;
     102                 :          0 :   symbols[QStringLiteral( "contour" )] = mContourSymbol.get();
     103                 :          0 :   if ( mContourIndexSymbol )
     104                 :          0 :     symbols[QStringLiteral( "index-contour" )] = mContourIndexSymbol.get();
     105                 :          0 :   QDomElement symbolsElem = QgsSymbolLayerUtils::saveSymbols( symbols, QStringLiteral( "symbols" ), doc, QgsReadWriteContext() );
     106                 :          0 :   rasterRendererElem.appendChild( symbolsElem );
     107                 :          0 : 
     108                 :          0 :   parentElem.appendChild( rasterRendererElem );
     109                 :          0 : }
     110                 :            : 
     111                 :            : struct ContourWriterData
     112                 :            : {
     113                 :            :   QPainter *painter;
     114                 :            :   double scaleX, scaleY;
     115                 :            :   QgsLineSymbol *symbol;
     116                 :            :   QgsLineSymbol *indexSymbol;
     117                 :            :   double indexInterval;
     118                 :            :   QgsRenderContext *context;
     119                 :            : };
     120                 :            : 
     121                 :          0 : CPLErr _rasterContourWriter( double dfLevel, int nPoints, double *padfX, double *padfY, void *ptr )
     122                 :            : {
     123                 :            :   Q_UNUSED( dfLevel )
     124                 :          0 :   ContourWriterData *crData = static_cast<ContourWriterData *>( ptr );
     125                 :          0 :   QPolygonF polygon( nPoints );
     126                 :          0 :   QPointF *d = polygon.data();
     127                 :          0 :   for ( int i = 0; i < nPoints; ++i )
     128                 :            :   {
     129                 :          0 :     d[i] = QPointF( padfX[i] * crData->scaleX, padfY[i] * crData->scaleY );
     130                 :          0 :   }
     131                 :            : 
     132                 :          0 :   if ( crData->indexSymbol && !qgsDoubleNear( crData->indexInterval, 0 ) && qgsDoubleNear( fmod( dfLevel, crData->indexInterval ), 0 ) )
     133                 :          0 :     crData->indexSymbol->renderPolyline( polygon, nullptr, *crData->context );
     134                 :            :   else
     135                 :          0 :     crData->symbol->renderPolyline( polygon, nullptr, *crData->context );
     136                 :            :   return CE_None;
     137                 :          0 : }
     138                 :            : 
     139                 :          0 : QgsRasterBlock *QgsRasterContourRenderer::block( int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback )
     140                 :            : {
     141                 :            :   Q_UNUSED( bandNo )
     142                 :            : 
     143                 :          0 :   std::unique_ptr< QgsRasterBlock > outputBlock( new QgsRasterBlock() );
     144                 :          0 :   if ( !mInput || !mContourSymbol )
     145                 :            :   {
     146                 :          0 :     return outputBlock.release();
     147                 :            :   }
     148                 :            : 
     149                 :          0 :   int inputWidth = static_cast<int>( round( width / mDownscale ) );
     150                 :          0 :   int inputHeight = static_cast<int>( round( height / mDownscale ) );
     151                 :            : 
     152                 :          0 :   std::unique_ptr< QgsRasterBlock > inputBlock( mInput->block( mInputBand, extent, inputWidth, inputHeight, feedback ) );
     153                 :          0 :   if ( !inputBlock || inputBlock->isEmpty() )
     154                 :            :   {
     155                 :          0 :     QgsDebugMsg( QStringLiteral( "No raster data!" ) );
     156                 :          0 :     return outputBlock.release();
     157                 :            :   }
     158                 :            : 
     159                 :          0 :   if ( !inputBlock->convert( Qgis::Float64 ) ) // contouring algorithm requires double
     160                 :          0 :     return outputBlock.release();
     161                 :          0 :   double *scanline = reinterpret_cast<double *>( inputBlock->bits() );
     162                 :            : 
     163                 :          0 :   QImage img( width, height, QImage::Format_ARGB32_Premultiplied );
     164                 :          0 :   img.fill( Qt::transparent );
     165                 :            : 
     166                 :          0 :   QPainter p( &img );
     167                 :          0 :   p.setRenderHint( QPainter::Antialiasing );
     168                 :            : 
     169                 :          0 :   QgsRenderContext context = QgsRenderContext::fromQPainter( &p );
     170                 :            : 
     171                 :            :   ContourWriterData crData;
     172                 :          0 :   crData.painter = &p;
     173                 :          0 :   crData.scaleX = width / double( inputWidth );
     174                 :          0 :   crData.scaleY = height / double( inputHeight );
     175                 :          0 :   crData.symbol = mContourSymbol.get();
     176                 :          0 :   crData.indexSymbol = mContourIndexSymbol.get();
     177                 :          0 :   crData.indexInterval = mContourIndexInterval;
     178                 :          0 :   crData.context = &context;
     179                 :            : 
     180                 :          0 :   crData.symbol->startRender( context );
     181                 :          0 :   if ( crData.indexSymbol )
     182                 :          0 :     crData.indexSymbol->startRender( context );
     183                 :            : 
     184                 :          0 :   double contourBase = 0.;
     185                 :          0 :   GDALContourGeneratorH cg = GDAL_CG_Create( inputBlock->width(), inputBlock->height(),
     186                 :          0 :                              inputBlock->hasNoDataValue(), inputBlock->noDataValue(),
     187                 :          0 :                              mContourInterval, contourBase,
     188                 :          0 :                              _rasterContourWriter, static_cast<void *>( &crData ) );
     189                 :          0 :   for ( int i = 0; i < inputHeight; ++i )
     190                 :            :   {
     191                 :          0 :     if ( feedback && feedback->isCanceled() )
     192                 :          0 :       break;
     193                 :            : 
     194                 :          0 :     GDAL_CG_FeedLine( cg, scanline );
     195                 :          0 :     scanline += inputWidth;
     196                 :          0 :   }
     197                 :          0 :   GDAL_CG_Destroy( cg );
     198                 :            : 
     199                 :          0 :   crData.symbol->stopRender( context );
     200                 :          0 :   if ( crData.indexSymbol )
     201                 :          0 :     crData.indexSymbol->stopRender( context );
     202                 :            : 
     203                 :          0 :   p.end();
     204                 :            : 
     205                 :          0 :   outputBlock->setImage( &img );
     206                 :          0 :   return outputBlock.release();
     207                 :          0 : }
     208                 :            : 
     209                 :          0 : QList<int> QgsRasterContourRenderer::usesBands() const
     210                 :            : {
     211                 :          0 :   QList<int> bandList;
     212                 :          0 :   if ( mInputBand != -1 )
     213                 :            :   {
     214                 :          0 :     bandList << mInputBand;
     215                 :          0 :   }
     216                 :          0 :   return bandList;
     217                 :          0 : }
     218                 :            : 
     219                 :          0 : QList<QgsLayerTreeModelLegendNode *> QgsRasterContourRenderer::createLegendNodes( QgsLayerTreeLayer *nodeLayer )
     220                 :            : {
     221                 :          0 :   QList<QgsLayerTreeModelLegendNode *> nodes;
     222                 :            : 
     223                 :          0 :   QgsLegendSymbolItem contourItem( mContourSymbol.get(), QString::number( mContourInterval ), QStringLiteral( "contour" ) );
     224                 :          0 :   nodes << new QgsSymbolLegendNode( nodeLayer, contourItem );
     225                 :            : 
     226                 :          0 :   if ( mContourIndexInterval > 0 )
     227                 :            :   {
     228                 :          0 :     QgsLegendSymbolItem indexItem( mContourIndexSymbol.get(), QString::number( mContourIndexInterval ), QStringLiteral( "index" ) );
     229                 :          0 :     nodes << new QgsSymbolLegendNode( nodeLayer, indexItem );
     230                 :          0 :   }
     231                 :            : 
     232                 :          0 :   return nodes;
     233                 :          0 : }
     234                 :            : 
     235                 :          0 : void QgsRasterContourRenderer::setContourSymbol( QgsLineSymbol *symbol )
     236                 :            : {
     237                 :          0 :   mContourSymbol.reset( symbol );
     238                 :          0 : }
     239                 :            : 
     240                 :          0 : void QgsRasterContourRenderer::setContourIndexSymbol( QgsLineSymbol *symbol )
     241                 :            : {
     242                 :          0 :   mContourIndexSymbol.reset( symbol );
     243                 :          0 : }

Generated by: LCOV version 1.14