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

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :                          qgsmeshlayerrenderer.cpp
       3                 :            :                          ------------------------
       4                 :            :     begin                : April 2018
       5                 :            :     copyright            : (C) 2018 by Peter Petrik
       6                 :            :     email                : zilolv at gmail dot com
       7                 :            :  ***************************************************************************/
       8                 :            : 
       9                 :            : /***************************************************************************
      10                 :            :  *                                                                         *
      11                 :            :  *   This program is free software; you can redistribute it and/or modify  *
      12                 :            :  *   it under the terms of the GNU General Public License as published by  *
      13                 :            :  *   the Free Software Foundation; either version 2 of the License, or     *
      14                 :            :  *   (at your option) any later version.                                   *
      15                 :            :  *                                                                         *
      16                 :            :  ***************************************************************************/
      17                 :            : 
      18                 :            : #include <memory>
      19                 :            : #include <QSet>
      20                 :            : #include <QPair>
      21                 :            : #include <QLinearGradient>
      22                 :            : #include <QBrush>
      23                 :            : #include <QPointer>
      24                 :            : #include <algorithm>
      25                 :            : 
      26                 :            : #include "qgsmeshlayerrenderer.h"
      27                 :            : 
      28                 :            : #include "qgsfield.h"
      29                 :            : #include "qgslogger.h"
      30                 :            : #include "qgsmeshlayer.h"
      31                 :            : #include "qgspointxy.h"
      32                 :            : #include "qgsrenderer.h"
      33                 :            : #include "qgssinglebandpseudocolorrenderer.h"
      34                 :            : #include "qgsrastershader.h"
      35                 :            : #include "qgsmeshlayerinterpolator.h"
      36                 :            : #include "qgsmeshlayerutils.h"
      37                 :            : #include "qgsmeshvectorrenderer.h"
      38                 :            : #include "qgsmeshtracerenderer.h"
      39                 :            : #include "qgsfillsymbollayer.h"
      40                 :            : #include "qgssettings.h"
      41                 :            : #include "qgsstyle.h"
      42                 :            : #include "qgsmeshdataprovidertemporalcapabilities.h"
      43                 :            : #include "qgsmapclippingutils.h"
      44                 :            : #include "qgscolorrampshader.h"
      45                 :            : 
      46                 :          0 : QgsMeshLayerRenderer::QgsMeshLayerRenderer(
      47                 :            :   QgsMeshLayer *layer,
      48                 :            :   QgsRenderContext &context )
      49                 :          0 :   : QgsMapLayerRenderer( layer->id(), &context )
      50                 :          0 :   , mFeedback( new QgsMeshLayerRendererFeedback )
      51                 :          0 :   , mRendererSettings( layer->rendererSettings() )
      52                 :          0 :   , mLayerOpacity( layer->opacity() )
      53                 :          0 : {
      54                 :            :   // make copies for mesh data
      55                 :            :   // cppcheck-suppress assertWithSideEffect
      56                 :            :   Q_ASSERT( layer->nativeMesh() );
      57                 :            :   // cppcheck-suppress assertWithSideEffect
      58                 :            :   Q_ASSERT( layer->triangularMesh() );
      59                 :            :   // cppcheck-suppress assertWithSideEffect
      60                 :            :   Q_ASSERT( layer->rendererCache() );
      61                 :            :   // cppcheck-suppress assertWithSideEffect
      62                 :            :   Q_ASSERT( layer->dataProvider() );
      63                 :            : 
      64                 :          0 :   mReadyToCompose = false;
      65                 :            : 
      66                 :            :   // copy native mesh
      67                 :          0 :   mNativeMesh = *( layer->nativeMesh() );
      68                 :          0 :   mLayerExtent = layer->extent();
      69                 :            : 
      70                 :            :   // copy triangular mesh
      71                 :          0 :   copyTriangularMeshes( layer, context );
      72                 :            : 
      73                 :            :   // copy datasets
      74                 :          0 :   copyScalarDatasetValues( layer );
      75                 :          0 :   copyVectorDatasetValues( layer );
      76                 :            : 
      77                 :          0 :   calculateOutputSize();
      78                 :            : 
      79                 :          0 :   mClippingRegions = QgsMapClippingUtils::collectClippingRegionsForLayer( *renderContext(), layer );
      80                 :          0 : }
      81                 :            : 
      82                 :          0 : void QgsMeshLayerRenderer::copyTriangularMeshes( QgsMeshLayer *layer, QgsRenderContext &context )
      83                 :            : {
      84                 :            :   // handle level of details of mesh
      85                 :          0 :   QgsMeshSimplificationSettings simplificationSettings = layer->meshSimplificationSettings();
      86                 :          0 :   if ( simplificationSettings.isEnabled() )
      87                 :            :   {
      88                 :          0 :     double triangleSize = simplificationSettings.meshResolution() * context.mapToPixel().mapUnitsPerPixel();
      89                 :          0 :     mTriangularMesh = *( layer->triangularMesh( triangleSize ) );
      90                 :          0 :     mIsMeshSimplificationActive = true;
      91                 :          0 :   }
      92                 :            :   else
      93                 :            :   {
      94                 :          0 :     mTriangularMesh = *( layer->triangularMesh() );
      95                 :            :   }
      96                 :          0 : }
      97                 :            : 
      98                 :          0 : QgsFeedback *QgsMeshLayerRenderer::feedback() const
      99                 :            : {
     100                 :          0 :   return mFeedback.get();
     101                 :            : }
     102                 :            : 
     103                 :          0 : void QgsMeshLayerRenderer::calculateOutputSize()
     104                 :            : {
     105                 :            :   // figure out image size
     106                 :          0 :   QgsRenderContext &context = *renderContext();
     107                 :          0 :   const QgsRectangle extent = context.mapExtent();
     108                 :          0 :   const QgsMapToPixel mapToPixel = context.mapToPixel();
     109                 :          0 :   const QgsRectangle screenBBox = QgsMeshLayerUtils::boundingBoxToScreenRectangle( mapToPixel, extent );
     110                 :          0 :   int width = int( screenBBox.width() );
     111                 :          0 :   int height = int( screenBBox.height() );
     112                 :          0 :   mOutputSize = QSize( width, height );
     113                 :          0 : }
     114                 :            : 
     115                 :          0 : void QgsMeshLayerRenderer::copyScalarDatasetValues( QgsMeshLayer *layer )
     116                 :          0 : {
     117                 :          0 :   QgsMeshDatasetIndex datasetIndex;
     118                 :          0 :   if ( renderContext()->isTemporal() )
     119                 :          0 :     datasetIndex = layer->activeScalarDatasetAtTime( renderContext()->temporalRange() );
     120                 :            :   else
     121                 :          0 :     datasetIndex = layer->staticScalarDatasetIndex();
     122                 :            : 
     123                 :            :   // Find out if we can use cache up to date. If yes, use it and return
     124                 :          0 :   const int datasetGroupCount = layer->datasetGroupCount();
     125                 :          0 :   const QgsMeshRendererScalarSettings::DataResamplingMethod method = mRendererSettings.scalarSettings( datasetIndex.group() ).dataResamplingMethod();
     126                 :          0 :   QgsMeshLayerRendererCache *cache = layer->rendererCache();
     127                 :          0 :   if ( ( cache->mDatasetGroupsCount == datasetGroupCount ) &&
     128                 :          0 :        ( cache->mActiveScalarDatasetIndex == datasetIndex ) &&
     129                 :          0 :        ( cache->mDataInterpolationMethod ==  method ) &&
     130                 :          0 :        ( QgsMesh3dAveragingMethod::equals( cache->mScalarAveragingMethod.get(), mRendererSettings.averagingMethod() ) )
     131                 :            :      )
     132                 :            :   {
     133                 :          0 :     mScalarDatasetValues = cache->mScalarDatasetValues;
     134                 :          0 :     mScalarActiveFaceFlagValues = cache->mScalarActiveFaceFlagValues;
     135                 :          0 :     mScalarDataType = cache->mScalarDataType;
     136                 :          0 :     mScalarDatasetMinimum = cache->mScalarDatasetMinimum;
     137                 :          0 :     mScalarDatasetMaximum = cache->mScalarDatasetMaximum;
     138                 :          0 :     return;
     139                 :            :   }
     140                 :            : 
     141                 :            :   // Cache is not up-to-date, gather data
     142                 :          0 :   if ( datasetIndex.isValid() )
     143                 :          0 :   {
     144                 :          0 :     const QgsMeshDatasetGroupMetadata metadata = layer->datasetGroupMetadata( datasetIndex.group() );
     145                 :          0 :     mScalarDataType = QgsMeshLayerUtils::datasetValuesType( metadata.dataType() );
     146                 :          0 : 
     147                 :            :     // populate scalar values
     148                 :          0 :     const int count = QgsMeshLayerUtils::datasetValuesCount( &mNativeMesh, mScalarDataType );
     149                 :          0 :     QgsMeshDataBlock vals = QgsMeshLayerUtils::datasetValues(
     150                 :          0 :                               layer,
     151                 :          0 :                               datasetIndex,
     152                 :            :                               0,
     153                 :          0 :                               count );
     154                 :            : 
     155                 :          0 :     if ( vals.isValid() )
     156                 :            :     {
     157                 :            :       // vals could be scalar or vectors, for contour rendering we want always magnitude
     158                 :          0 :       mScalarDatasetValues = QgsMeshLayerUtils::calculateMagnitudes( vals );
     159                 :          0 :     }
     160                 :            :     else
     161                 :            :     {
     162                 :          0 :       mScalarDatasetValues = QVector<double>( count, std::numeric_limits<double>::quiet_NaN() );
     163                 :            :     }
     164                 :            : 
     165                 :            :     // populate face active flag, always defined on faces
     166                 :          0 :     mScalarActiveFaceFlagValues = layer->areFacesActive(
     167                 :            :                                     datasetIndex,
     168                 :            :                                     0,
     169                 :          0 :                                     mNativeMesh.faces.count() );
     170                 :            : 
     171                 :            :     // for data on faces, there could be request to interpolate the data to vertices
     172                 :          0 :     if ( method != QgsMeshRendererScalarSettings::None )
     173                 :            :     {
     174                 :          0 :       if ( mScalarDataType == QgsMeshDatasetGroupMetadata::DataType::DataOnFaces )
     175                 :            :       {
     176                 :          0 :         mScalarDataType = QgsMeshDatasetGroupMetadata::DataType::DataOnVertices;
     177                 :          0 :         mScalarDatasetValues = QgsMeshLayerUtils::interpolateFromFacesData(
     178                 :          0 :                                  mScalarDatasetValues,
     179                 :          0 :                                  &mNativeMesh,
     180                 :          0 :                                  &mTriangularMesh,
     181                 :          0 :                                  &mScalarActiveFaceFlagValues,
     182                 :          0 :                                  method
     183                 :            :                                );
     184                 :          0 :       }
     185                 :          0 :       else if ( mScalarDataType == QgsMeshDatasetGroupMetadata::DataType::DataOnVertices )
     186                 :            :       {
     187                 :          0 :         mScalarDataType = QgsMeshDatasetGroupMetadata::DataType::DataOnFaces;
     188                 :          0 :         mScalarDatasetValues = QgsMeshLayerUtils::resampleFromVerticesToFaces(
     189                 :          0 :                                  mScalarDatasetValues,
     190                 :          0 :                                  &mNativeMesh,
     191                 :          0 :                                  &mTriangularMesh,
     192                 :          0 :                                  &mScalarActiveFaceFlagValues,
     193                 :          0 :                                  method
     194                 :            :                                );
     195                 :          0 :       }
     196                 :            : 
     197                 :          0 :     }
     198                 :            : 
     199                 :          0 :     const QgsMeshDatasetMetadata datasetMetadata = layer->datasetMetadata( datasetIndex );
     200                 :          0 :     mScalarDatasetMinimum = datasetMetadata.minimum();
     201                 :          0 :     mScalarDatasetMaximum = datasetMetadata.maximum();
     202                 :          0 :   }
     203                 :            : 
     204                 :            :   // update cache
     205                 :          0 :   cache->mDatasetGroupsCount = datasetGroupCount;
     206                 :          0 :   cache->mActiveScalarDatasetIndex = datasetIndex;
     207                 :          0 :   cache->mDataInterpolationMethod = method;
     208                 :          0 :   cache->mScalarDatasetValues = mScalarDatasetValues;
     209                 :          0 :   cache->mScalarActiveFaceFlagValues = mScalarActiveFaceFlagValues;
     210                 :          0 :   cache->mScalarDataType = mScalarDataType;
     211                 :          0 :   cache->mScalarDatasetMinimum = mScalarDatasetMinimum;
     212                 :          0 :   cache->mScalarDatasetMaximum = mScalarDatasetMaximum;
     213                 :          0 :   cache->mScalarAveragingMethod.reset( mRendererSettings.averagingMethod() ? mRendererSettings.averagingMethod()->clone() : nullptr );
     214                 :          0 : }
     215                 :            : 
     216                 :            : 
     217                 :          0 : void QgsMeshLayerRenderer::copyVectorDatasetValues( QgsMeshLayer *layer )
     218                 :            : {
     219                 :          0 :   QgsMeshDatasetIndex datasetIndex;
     220                 :          0 :   if ( renderContext()->isTemporal() )
     221                 :          0 :     datasetIndex = layer->activeVectorDatasetAtTime( renderContext()->temporalRange() );
     222                 :            :   else
     223                 :          0 :     datasetIndex = layer->staticVectorDatasetIndex();
     224                 :            : 
     225                 :            :   // Find out if we can use cache up to date. If yes, use it and return
     226                 :          0 :   const int datasetGroupCount = layer->datasetGroupCount();
     227                 :          0 :   QgsMeshLayerRendererCache *cache = layer->rendererCache();
     228                 :          0 :   if ( ( cache->mDatasetGroupsCount == datasetGroupCount ) &&
     229                 :          0 :        ( cache->mActiveVectorDatasetIndex == datasetIndex ) &&
     230                 :          0 :        ( QgsMesh3dAveragingMethod::equals( cache->mVectorAveragingMethod.get(), mRendererSettings.averagingMethod() ) )
     231                 :            :      )
     232                 :            :   {
     233                 :          0 :     mVectorDatasetValues = cache->mVectorDatasetValues;
     234                 :          0 :     mVectorDatasetValuesMag = cache->mVectorDatasetValuesMag;
     235                 :          0 :     mVectorDatasetMagMinimum = cache->mVectorDatasetMagMinimum;
     236                 :          0 :     mVectorDatasetMagMaximum = cache->mVectorDatasetMagMaximum;
     237                 :          0 :     mVectorDatasetGroupMagMinimum = cache->mVectorDatasetMagMinimum;
     238                 :          0 :     mVectorDatasetGroupMagMaximum = cache->mVectorDatasetMagMaximum;
     239                 :          0 :     mVectorDataType = cache->mVectorDataType;
     240                 :          0 :     return;
     241                 :            :   }
     242                 :            : 
     243                 :            :   // Cache is not up-to-date, gather data
     244                 :          0 :   if ( datasetIndex.isValid() )
     245                 :            :   {
     246                 :          0 :     const QgsMeshDatasetGroupMetadata metadata = layer->datasetGroupMetadata( datasetIndex );
     247                 :            : 
     248                 :          0 :     bool isScalar = metadata.isScalar();
     249                 :          0 :     if ( isScalar )
     250                 :            :     {
     251                 :          0 :       QgsDebugMsg( QStringLiteral( "Dataset has no vector values" ) );
     252                 :          0 :     }
     253                 :            :     else
     254                 :            :     {
     255                 :          0 :       mVectorDataType = QgsMeshLayerUtils::datasetValuesType( metadata.dataType() );
     256                 :            : 
     257                 :          0 :       mVectorDatasetGroupMagMinimum = metadata.minimum();
     258                 :          0 :       mVectorDatasetGroupMagMaximum = metadata.maximum();
     259                 :            : 
     260                 :          0 :       int count = QgsMeshLayerUtils::datasetValuesCount( &mNativeMesh, mVectorDataType );
     261                 :          0 :       mVectorDatasetValues = QgsMeshLayerUtils::datasetValues(
     262                 :          0 :                                layer,
     263                 :          0 :                                datasetIndex,
     264                 :            :                                0,
     265                 :          0 :                                count );
     266                 :            : 
     267                 :          0 :       if ( mVectorDatasetValues.isValid() )
     268                 :          0 :         mVectorDatasetValuesMag = QgsMeshLayerUtils::calculateMagnitudes( mVectorDatasetValues );
     269                 :            :       else
     270                 :          0 :         mVectorDatasetValuesMag = QVector<double>( count, std::numeric_limits<double>::quiet_NaN() );
     271                 :            : 
     272                 :          0 :       const QgsMeshDatasetMetadata datasetMetadata = layer->datasetMetadata( datasetIndex );
     273                 :          0 :       mVectorDatasetMagMinimum = datasetMetadata.minimum();
     274                 :          0 :       mVectorDatasetMagMaximum = datasetMetadata.maximum();
     275                 :            :     }
     276                 :          0 :   }
     277                 :            : 
     278                 :            :   // update cache
     279                 :          0 :   cache->mDatasetGroupsCount = datasetGroupCount;
     280                 :          0 :   cache->mActiveVectorDatasetIndex = datasetIndex;
     281                 :          0 :   cache->mVectorDatasetValues = mVectorDatasetValues;
     282                 :          0 :   cache->mVectorDatasetValuesMag = mVectorDatasetValuesMag;
     283                 :          0 :   cache->mVectorDatasetMagMinimum = mVectorDatasetMagMinimum;
     284                 :          0 :   cache->mVectorDatasetMagMaximum = mVectorDatasetMagMaximum;
     285                 :          0 :   cache->mVectorDatasetGroupMagMinimum = mVectorDatasetMagMinimum;
     286                 :          0 :   cache->mVectorDatasetGroupMagMaximum = mVectorDatasetMagMaximum;
     287                 :          0 :   cache->mVectorDataType = mVectorDataType;
     288                 :          0 :   cache->mVectorAveragingMethod.reset( mRendererSettings.averagingMethod() ? mRendererSettings.averagingMethod()->clone() : nullptr );
     289                 :          0 : }
     290                 :            : 
     291                 :          0 : bool QgsMeshLayerRenderer::render()
     292                 :            : {
     293                 :          0 :   mReadyToCompose = false;
     294                 :          0 :   QgsScopedQPainterState painterState( renderContext()->painter() );
     295                 :          0 :   if ( !mClippingRegions.empty() )
     296                 :            :   {
     297                 :          0 :     bool needsPainterClipPath = false;
     298                 :          0 :     const QPainterPath path = QgsMapClippingUtils::calculatePainterClipRegion( mClippingRegions, *renderContext(), QgsMapLayerType::MeshLayer, needsPainterClipPath );
     299                 :          0 :     if ( needsPainterClipPath )
     300                 :          0 :       renderContext()->painter()->setClipPath( path, Qt::IntersectClip );
     301                 :          0 :   }
     302                 :            : 
     303                 :          0 :   renderScalarDataset();
     304                 :          0 :   mReadyToCompose = true;
     305                 :          0 :   renderMesh();
     306                 :          0 :   renderVectorDataset();
     307                 :            : 
     308                 :          0 :   return !renderContext()->renderingStopped();
     309                 :          0 : }
     310                 :            : 
     311                 :          0 : bool QgsMeshLayerRenderer::forceRasterRender() const
     312                 :            : {
     313                 :          0 :   return renderContext()->testFlag( QgsRenderContext::UseAdvancedEffects ) && ( !qgsDoubleNear( mLayerOpacity, 1.0 ) );
     314                 :            : }
     315                 :            : 
     316                 :          0 : void QgsMeshLayerRenderer::renderMesh()
     317                 :            : {
     318                 :          0 :   if ( !mRendererSettings.nativeMeshSettings().isEnabled() &&
     319                 :          0 :        !mRendererSettings.edgeMeshSettings().isEnabled() &&
     320                 :          0 :        !mRendererSettings.triangularMeshSettings().isEnabled() )
     321                 :          0 :     return;
     322                 :            : 
     323                 :            :   // triangular mesh
     324                 :          0 :   const QList<int> trianglesInExtent = mTriangularMesh.faceIndexesForRectangle( renderContext()->mapExtent() );
     325                 :          0 :   if ( mRendererSettings.triangularMeshSettings().isEnabled() )
     326                 :            :   {
     327                 :          0 :     renderFaceMesh(
     328                 :          0 :       mRendererSettings.triangularMeshSettings(),
     329                 :          0 :       mTriangularMesh.triangles(),
     330                 :            :       trianglesInExtent );
     331                 :          0 :   }
     332                 :            : 
     333                 :            :   // native mesh
     334                 :          0 :   if ( mRendererSettings.nativeMeshSettings().isEnabled() && mTriangularMesh.levelOfDetail() == 0 )
     335                 :            :   {
     336                 :          0 :     const QSet<int> nativeFacesInExtent = QgsMeshUtils::nativeFacesFromTriangles( trianglesInExtent,
     337                 :          0 :                                           mTriangularMesh.trianglesToNativeFaces() );
     338                 :            : 
     339                 :          0 :     renderFaceMesh(
     340                 :          0 :       mRendererSettings.nativeMeshSettings(),
     341                 :          0 :       mNativeMesh.faces,
     342                 :          0 :       nativeFacesInExtent.values() );
     343                 :          0 :   }
     344                 :            : 
     345                 :            :   // edge mesh
     346                 :          0 :   if ( mRendererSettings.edgeMeshSettings().isEnabled() )
     347                 :            :   {
     348                 :          0 :     const QList<int> edgesInExtent = mTriangularMesh.edgeIndexesForRectangle( renderContext()->mapExtent() );
     349                 :          0 :     renderEdgeMesh( mRendererSettings.edgeMeshSettings(), edgesInExtent );
     350                 :          0 :   }
     351                 :          0 : }
     352                 :            : 
     353                 :          0 : static QPainter *_painterForMeshFrame( QgsRenderContext &context, const QgsMeshRendererMeshSettings &settings )
     354                 :            : {
     355                 :            :   // Set up the render configuration options
     356                 :          0 :   QPainter *painter = context.painter();
     357                 :            : 
     358                 :          0 :   painter->save();
     359                 :          0 :   context.setPainterFlagsUsingContext( painter );
     360                 :            : 
     361                 :          0 :   QPen pen = painter->pen();
     362                 :          0 :   pen.setCapStyle( Qt::FlatCap );
     363                 :          0 :   pen.setJoinStyle( Qt::MiterJoin );
     364                 :            : 
     365                 :          0 :   double penWidth = context.convertToPainterUnits( settings.lineWidth(), settings.lineWidthUnit() );
     366                 :          0 :   pen.setWidthF( penWidth );
     367                 :          0 :   pen.setColor( settings.color() );
     368                 :          0 :   painter->setPen( pen );
     369                 :          0 :   return painter;
     370                 :          0 : }
     371                 :            : 
     372                 :          0 : void QgsMeshLayerRenderer::renderEdgeMesh( const QgsMeshRendererMeshSettings &settings, const QList<int> &edgesInExtent )
     373                 :            : {
     374                 :            :   Q_ASSERT( settings.isEnabled() );
     375                 :            : 
     376                 :          0 :   if ( !mTriangularMesh.contains( QgsMesh::ElementType::Edge ) )
     377                 :          0 :     return;
     378                 :            : 
     379                 :          0 :   QgsRenderContext &context = *renderContext();
     380                 :          0 :   QPainter *painter = _painterForMeshFrame( context, settings );
     381                 :            : 
     382                 :          0 :   const QVector<QgsMeshEdge> edges = mTriangularMesh.edges();
     383                 :          0 :   const QVector<QgsMeshVertex> vertices = mTriangularMesh.vertices();
     384                 :            : 
     385                 :          0 :   for ( const int i : edgesInExtent )
     386                 :            :   {
     387                 :          0 :     if ( context.renderingStopped() )
     388                 :          0 :       break;
     389                 :            : 
     390                 :          0 :     if ( i >= edges.size() )
     391                 :          0 :       continue;
     392                 :            : 
     393                 :          0 :     const QgsMeshEdge &edge = edges[i];
     394                 :          0 :     const int startVertexIndex = edge.first;
     395                 :          0 :     const int endVertexIndex = edge.second;
     396                 :            : 
     397                 :          0 :     if ( ( startVertexIndex >= vertices.size() ) || endVertexIndex >= vertices.size() )
     398                 :          0 :       continue;
     399                 :            : 
     400                 :          0 :     const QgsMeshVertex &startVertex = vertices[startVertexIndex];
     401                 :          0 :     const QgsMeshVertex &endVertex = vertices[endVertexIndex];
     402                 :          0 :     const QgsPointXY lineStart = context.mapToPixel().transform( startVertex.x(), startVertex.y() );
     403                 :          0 :     const QgsPointXY lineEnd = context.mapToPixel().transform( endVertex.x(), endVertex.y() );
     404                 :          0 :     painter->drawLine( lineStart.toQPointF(), lineEnd.toQPointF() );
     405                 :            :   }
     406                 :          0 :   painter->restore();
     407                 :          0 : };
     408                 :            : 
     409                 :          0 : void QgsMeshLayerRenderer::renderFaceMesh(
     410                 :            :   const QgsMeshRendererMeshSettings &settings,
     411                 :            :   const QVector<QgsMeshFace> &faces,
     412                 :            :   const QList<int> &facesInExtent )
     413                 :            : {
     414                 :            :   Q_ASSERT( settings.isEnabled() );
     415                 :            : 
     416                 :          0 :   if ( !mTriangularMesh.contains( QgsMesh::ElementType::Face ) )
     417                 :          0 :     return;
     418                 :            : 
     419                 :          0 :   QgsRenderContext &context = *renderContext();
     420                 :          0 :   QPainter *painter = _painterForMeshFrame( context, settings );
     421                 :            : 
     422                 :          0 :   const QVector<QgsMeshVertex> &vertices = mTriangularMesh.vertices(); //Triangular mesh vertices contains also native mesh vertices
     423                 :          0 :   QSet<QPair<int, int>> drawnEdges;
     424                 :            : 
     425                 :          0 :   for ( const int i : facesInExtent )
     426                 :            :   {
     427                 :          0 :     if ( context.renderingStopped() )
     428                 :          0 :       break;
     429                 :            : 
     430                 :          0 :     const QgsMeshFace &face = faces[i];
     431                 :          0 :     if ( face.size() < 2 )
     432                 :          0 :       continue;
     433                 :            : 
     434                 :          0 :     for ( int j = 0; j < face.size(); ++j )
     435                 :            :     {
     436                 :          0 :       const int startVertexId = face[j];
     437                 :          0 :       const int endVertexId = face[( j + 1 ) % face.size()];
     438                 :          0 :       const QPair<int, int> thisEdge( startVertexId, endVertexId );
     439                 :          0 :       const QPair<int, int> thisEdgeReversed( endVertexId, startVertexId );
     440                 :          0 :       if ( drawnEdges.contains( thisEdge ) || drawnEdges.contains( thisEdgeReversed ) )
     441                 :          0 :         continue;
     442                 :          0 :       drawnEdges.insert( thisEdge );
     443                 :          0 :       drawnEdges.insert( thisEdgeReversed );
     444                 :            : 
     445                 :          0 :       const QgsMeshVertex &startVertex = vertices[startVertexId];
     446                 :          0 :       const QgsMeshVertex &endVertex = vertices[endVertexId];
     447                 :          0 :       const QgsPointXY lineStart = context.mapToPixel().transform( startVertex.x(), startVertex.y() );
     448                 :          0 :       const QgsPointXY lineEnd = context.mapToPixel().transform( endVertex.x(), endVertex.y() );
     449                 :          0 :       painter->drawLine( lineStart.toQPointF(), lineEnd.toQPointF() );
     450                 :          0 :     }
     451                 :            :   }
     452                 :            : 
     453                 :          0 :   painter->restore();
     454                 :          0 : }
     455                 :            : 
     456                 :          0 : void QgsMeshLayerRenderer::renderScalarDataset()
     457                 :            : {
     458                 :          0 :   if ( mScalarDatasetValues.isEmpty() )
     459                 :          0 :     return; // activeScalarDataset == NO_ACTIVE_MESH_DATASET
     460                 :            : 
     461                 :          0 :   if ( std::isnan( mScalarDatasetMinimum ) || std::isnan( mScalarDatasetMaximum ) )
     462                 :          0 :     return; // only NODATA values
     463                 :            : 
     464                 :          0 :   int groupIndex = mRendererSettings.activeScalarDatasetGroup();
     465                 :          0 :   if ( groupIndex < 0 )
     466                 :          0 :     return; // no shader
     467                 :            : 
     468                 :          0 :   const QgsMeshRendererScalarSettings scalarSettings = mRendererSettings.scalarSettings( groupIndex );
     469                 :            : 
     470                 :          0 :   if ( ( mTriangularMesh.contains( QgsMesh::ElementType::Face ) ) &&
     471                 :          0 :        ( mScalarDataType != QgsMeshDatasetGroupMetadata::DataType::DataOnEdges ) )
     472                 :            :   {
     473                 :          0 :     renderScalarDatasetOnFaces( scalarSettings );
     474                 :          0 :   }
     475                 :            : 
     476                 :          0 :   if ( ( mTriangularMesh.contains( QgsMesh::ElementType::Edge ) ) &&
     477                 :          0 :        ( mScalarDataType != QgsMeshDatasetGroupMetadata::DataType::DataOnFaces ) )
     478                 :            :   {
     479                 :          0 :     renderScalarDatasetOnEdges( scalarSettings );
     480                 :          0 :   }
     481                 :          0 : }
     482                 :            : 
     483                 :          0 : void QgsMeshLayerRenderer::renderScalarDatasetOnEdges( const QgsMeshRendererScalarSettings &scalarSettings )
     484                 :            : {
     485                 :          0 :   QgsRenderContext &context = *renderContext();
     486                 :          0 :   const QVector<QgsMeshEdge> edges = mTriangularMesh.edges();
     487                 :          0 :   const QVector<QgsMeshVertex> vertices = mTriangularMesh.vertices();
     488                 :          0 :   const QList<int> egdesInExtent = mTriangularMesh.edgeIndexesForRectangle( context.mapExtent() );
     489                 :          0 :   const QSet<int> nativeEdgesInExtent = QgsMeshUtils::nativeEdgesFromEdges( egdesInExtent,
     490                 :          0 :                                         mTriangularMesh.edgesToNativeEdges() );
     491                 :            : 
     492                 :          0 :   QgsInterpolatedLineRenderer edgePlotter;
     493                 :          0 :   edgePlotter.setInterpolatedColor( QgsInterpolatedLineColor( scalarSettings.colorRampShader() ) );
     494                 :          0 :   edgePlotter.setInterpolatedWidth( QgsInterpolatedLineWidth( scalarSettings.edgeStrokeWidth() ) );
     495                 :          0 :   edgePlotter.setWidthUnit( scalarSettings.edgeStrokeWidthUnit() );
     496                 :            : 
     497                 :          0 :   for ( const int i : egdesInExtent )
     498                 :            :   {
     499                 :          0 :     if ( context.renderingStopped() )
     500                 :          0 :       break;
     501                 :            : 
     502                 :          0 :     if ( i >= edges.size() )
     503                 :          0 :       continue;
     504                 :            : 
     505                 :          0 :     const QgsMeshEdge &edge = edges[i];
     506                 :          0 :     const int startVertexIndex = edge.first;
     507                 :          0 :     const int endVertexIndex = edge.second;
     508                 :            : 
     509                 :          0 :     if ( ( startVertexIndex >= vertices.size() ) || endVertexIndex >= vertices.size() )
     510                 :          0 :       continue;
     511                 :            : 
     512                 :          0 :     const QgsMeshVertex &startVertex = vertices[startVertexIndex];
     513                 :          0 :     const QgsMeshVertex &endVertex = vertices[endVertexIndex];
     514                 :            : 
     515                 :          0 :     if ( mScalarDataType == QgsMeshDatasetGroupMetadata::DataType::DataOnEdges )
     516                 :            :     {
     517                 :          0 :       edgePlotter.render( mScalarDatasetValues[i], mScalarDatasetValues[i], startVertex, endVertex, context );
     518                 :          0 :     }
     519                 :            :     else
     520                 :            :     {
     521                 :          0 :       edgePlotter.render( mScalarDatasetValues[startVertexIndex], mScalarDatasetValues[endVertexIndex], startVertex, endVertex, context );
     522                 :            :     }
     523                 :            :   }
     524                 :          0 : }
     525                 :            : 
     526                 :          0 : QColor QgsMeshLayerRenderer::colorAt( QgsColorRampShader *shader, double val ) const
     527                 :            : {
     528                 :            :   int r, g, b, a;
     529                 :          0 :   if ( shader->shade( val, &r, &g, &b, &a ) )
     530                 :            :   {
     531                 :          0 :     return QColor( r, g, b, a );
     532                 :            :   }
     533                 :          0 :   return QColor();
     534                 :          0 : }
     535                 :            : 
     536                 :          0 : QgsPointXY QgsMeshLayerRenderer::fractionPoint( const QgsPointXY &p1, const QgsPointXY &p2, double fraction ) const
     537                 :            : {
     538                 :          0 :   const QgsPointXY pt( p1.x() + fraction * ( p2.x() - p1.x() ),
     539                 :          0 :                        p1.y() + fraction * ( p2.y() - p1.y() ) );
     540                 :          0 :   return pt;
     541                 :            : }
     542                 :            : 
     543                 :          0 : void QgsMeshLayerRenderer::renderScalarDatasetOnFaces( const QgsMeshRendererScalarSettings &scalarSettings )
     544                 :            : {
     545                 :          0 :   QgsRenderContext &context = *renderContext();
     546                 :            : 
     547                 :          0 :   QgsColorRampShader *fcn = new QgsColorRampShader( scalarSettings.colorRampShader() );
     548                 :          0 :   QgsRasterShader *sh = new QgsRasterShader();
     549                 :          0 :   sh->setRasterShaderFunction( fcn );  // takes ownership of fcn
     550                 :          0 :   QgsMeshLayerInterpolator interpolator( mTriangularMesh,
     551                 :          0 :                                          mScalarDatasetValues,
     552                 :          0 :                                          mScalarActiveFaceFlagValues,
     553                 :          0 :                                          mScalarDataType,
     554                 :          0 :                                          context,
     555                 :          0 :                                          mOutputSize );
     556                 :          0 :   interpolator.setSpatialIndexActive( mIsMeshSimplificationActive );
     557                 :          0 :   QgsSingleBandPseudoColorRenderer renderer( &interpolator, 0, sh );  // takes ownership of sh
     558                 :          0 :   renderer.setClassificationMin( scalarSettings.classificationMinimum() );
     559                 :          0 :   renderer.setClassificationMax( scalarSettings.classificationMaximum() );
     560                 :          0 :   renderer.setOpacity( scalarSettings.opacity() );
     561                 :            : 
     562                 :          0 :   std::unique_ptr<QgsRasterBlock> bl( renderer.block( 0, context.mapExtent(), mOutputSize.width(), mOutputSize.height(), mFeedback.get() ) );
     563                 :          0 :   QImage img = bl->image();
     564                 :            : 
     565                 :          0 :   context.painter()->drawImage( 0, 0, img );
     566                 :          0 : }
     567                 :            : 
     568                 :          0 : void QgsMeshLayerRenderer::renderVectorDataset()
     569                 :            : {
     570                 :          0 :   int groupIndex = mRendererSettings.activeVectorDatasetGroup();
     571                 :          0 :   if ( groupIndex < 0 )
     572                 :          0 :     return;
     573                 :            : 
     574                 :          0 :   if ( !mVectorDatasetValues.isValid() )
     575                 :          0 :     return; // no data at all
     576                 :            : 
     577                 :          0 :   if ( std::isnan( mVectorDatasetMagMinimum ) || std::isnan( mVectorDatasetMagMaximum ) )
     578                 :          0 :     return; // only NODATA values
     579                 :            : 
     580                 :          0 :   if ( !( mVectorDatasetMagMaximum > 0 ) )
     581                 :          0 :     return; //all vector are null vector
     582                 :            : 
     583                 :          0 :   std::unique_ptr<QgsMeshVectorRenderer> renderer( QgsMeshVectorRenderer::makeVectorRenderer(
     584                 :          0 :         mTriangularMesh,
     585                 :          0 :         mVectorDatasetValues,
     586                 :          0 :         mScalarActiveFaceFlagValues,
     587                 :          0 :         mVectorDatasetValuesMag,
     588                 :          0 :         mVectorDatasetMagMaximum,
     589                 :          0 :         mVectorDatasetMagMinimum,
     590                 :          0 :         mVectorDataType,
     591                 :          0 :         mRendererSettings.vectorSettings( groupIndex ),
     592                 :          0 :         *renderContext(),
     593                 :          0 :         mLayerExtent,
     594                 :          0 :         mOutputSize ) );
     595                 :            : 
     596                 :          0 :   if ( renderer )
     597                 :          0 :     renderer->draw();
     598                 :          0 : }
     599                 :            : 

Generated by: LCOV version 1.14