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

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :                          qgsmeshvectorrenderer.cpp
       3                 :            :                          -------------------------
       4                 :            :     begin                : May 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 "qgsmeshvectorrenderer.h"
      19                 :            : #include "qgsrendercontext.h"
      20                 :            : #include "qgscoordinatetransform.h"
      21                 :            : #include "qgsmaptopixel.h"
      22                 :            : #include "qgsunittypes.h"
      23                 :            : #include "qgsmeshlayerutils.h"
      24                 :            : #include "qgsmeshtracerenderer.h"
      25                 :            : 
      26                 :            : #include <cstdlib>
      27                 :            : #include <ctime>
      28                 :            : #include <algorithm>
      29                 :            : #include <QPen>
      30                 :            : #include <QPainter>
      31                 :            : #include <cmath>
      32                 :            : 
      33                 :            : ///@cond PRIVATE
      34                 :            : 
      35                 :            : #ifndef M_DEG2RAD
      36                 :            : #define M_DEG2RAD 0.0174532925
      37                 :            : #endif
      38                 :            : 
      39                 :          0 : inline double mag( double input )
      40                 :            : {
      41                 :          0 :   if ( input < 0.0 )
      42                 :            :   {
      43                 :          0 :     return -1.0;
      44                 :            :   }
      45                 :          0 :   return 1.0;
      46                 :          0 : }
      47                 :            : 
      48                 :          0 : inline bool nodataValue( double x, double y )
      49                 :            : {
      50                 :          0 :   return ( std::isnan( x ) || std::isnan( y ) );
      51                 :            : }
      52                 :            : 
      53                 :          0 : QgsMeshVectorArrowRenderer::QgsMeshVectorArrowRenderer(
      54                 :            :   const QgsTriangularMesh &m,
      55                 :            :   const QgsMeshDataBlock &datasetValues,
      56                 :            :   const QVector<double> &datasetValuesMag,
      57                 :            :   double datasetMagMaximumValue, double datasetMagMinimumValue,
      58                 :            :   QgsMeshDatasetGroupMetadata::DataType dataType,
      59                 :            :   const QgsMeshRendererVectorSettings &settings,
      60                 :            :   QgsRenderContext &context,
      61                 :            :   QSize size )  :
      62                 :          0 :   mTriangularMesh( m )
      63                 :          0 :   , mDatasetValues( datasetValues )
      64                 :          0 :   , mDatasetValuesMag( datasetValuesMag )
      65                 :          0 :   , mMinMag( datasetMagMinimumValue )
      66                 :          0 :   , mMaxMag( datasetMagMaximumValue )
      67                 :          0 :   , mContext( context )
      68                 :          0 :   , mCfg( settings )
      69                 :          0 :   , mDataType( dataType )
      70                 :          0 :   , mOutputSize( size )
      71                 :          0 :   , mBufferedExtent( context.mapExtent() )
      72                 :          0 : {
      73                 :            :   // should be checked in caller
      74                 :            :   Q_ASSERT( !mDatasetValuesMag.empty() );
      75                 :            :   Q_ASSERT( !std::isnan( mMinMag ) );
      76                 :            :   Q_ASSERT( !std::isnan( mMaxMag ) );
      77                 :            :   Q_ASSERT( mDatasetValues.isValid() );
      78                 :            :   Q_ASSERT( QgsMeshDataBlock::Vector2DDouble == mDatasetValues.type() );
      79                 :            : 
      80                 :            :   // we need to expand out the extent so that it includes
      81                 :            :   // arrows which start or end up outside of the
      82                 :            :   // actual visible extent
      83                 :          0 :   double extension = context.convertToMapUnits( calcExtentBufferSize(), QgsUnitTypes::RenderPixels );
      84                 :          0 :   mBufferedExtent.setXMinimum( mBufferedExtent.xMinimum() - extension );
      85                 :          0 :   mBufferedExtent.setXMaximum( mBufferedExtent.xMaximum() + extension );
      86                 :          0 :   mBufferedExtent.setYMinimum( mBufferedExtent.yMinimum() - extension );
      87                 :          0 :   mBufferedExtent.setYMaximum( mBufferedExtent.yMaximum() + extension );
      88                 :            : 
      89                 :          0 :   mVectorColoring = settings.vectorStrokeColoring();
      90                 :          0 : }
      91                 :            : 
      92                 :          0 : QgsMeshVectorArrowRenderer::~QgsMeshVectorArrowRenderer() = default;
      93                 :            : 
      94                 :          0 : void QgsMeshVectorArrowRenderer::draw()
      95                 :            : {
      96                 :            :   // Set up the render configuration options
      97                 :          0 :   QPainter *painter = mContext.painter();
      98                 :            : 
      99                 :          0 :   QgsScopedQPainterState painterState( painter );
     100                 :          0 :   mContext.setPainterFlagsUsingContext( painter );
     101                 :            : 
     102                 :          0 :   QPen pen = painter->pen();
     103                 :          0 :   pen.setCapStyle( Qt::FlatCap );
     104                 :          0 :   pen.setJoinStyle( Qt::MiterJoin );
     105                 :            : 
     106                 :          0 :   double penWidth = mContext.convertToPainterUnits( mCfg.lineWidth(),
     107                 :            :                     QgsUnitTypes::RenderUnit::RenderMillimeters );
     108                 :          0 :   pen.setWidthF( penWidth );
     109                 :          0 :   painter->setPen( pen );
     110                 :            : 
     111                 :          0 :   if ( mCfg.isOnUserDefinedGrid() )
     112                 :            :   {
     113                 :          0 :     drawVectorDataOnGrid( );
     114                 :          0 :   }
     115                 :          0 :   else if ( mDataType == QgsMeshDatasetGroupMetadata::DataType::DataOnVertices )
     116                 :            :   {
     117                 :          0 :     drawVectorDataOnVertices( );
     118                 :          0 :   }
     119                 :          0 :   else if ( mDataType == QgsMeshDatasetGroupMetadata::DataType::DataOnFaces )
     120                 :            :   {
     121                 :          0 :     drawVectorDataOnFaces( );
     122                 :          0 :   }
     123                 :          0 :   else if ( mDataType == QgsMeshDatasetGroupMetadata::DataType::DataOnEdges )
     124                 :            :   {
     125                 :          0 :     drawVectorDataOnEdges( );
     126                 :          0 :   }
     127                 :          0 : }
     128                 :            : 
     129                 :          0 : bool QgsMeshVectorArrowRenderer::calcVectorLineEnd(
     130                 :            :   QgsPointXY &lineEnd,
     131                 :            :   double &vectorLength,
     132                 :            :   double &cosAlpha,
     133                 :            :   double &sinAlpha, //out
     134                 :            :   const QgsPointXY &lineStart,
     135                 :            :   double xVal,
     136                 :            :   double yVal,
     137                 :            :   double magnitude //in
     138                 :            : )
     139                 :            : {
     140                 :            :   // return true on error
     141                 :            : 
     142                 :          0 :   if ( xVal == 0.0 && yVal == 0.0 )
     143                 :          0 :     return true;
     144                 :            : 
     145                 :            :   // do not render if magnitude is outside of the filtered range (if filtering is enabled)
     146                 :          0 :   if ( mCfg.filterMin() >= 0 && magnitude < mCfg.filterMin() )
     147                 :          0 :     return true;
     148                 :          0 :   if ( mCfg.filterMax() >= 0 && magnitude > mCfg.filterMax() )
     149                 :          0 :     return true;
     150                 :            : 
     151                 :            :   // Determine the angle of the vector, counter-clockwise, from east
     152                 :            :   // (and associated trigs)
     153                 :          0 :   double vectorAngle = -1.0 * atan( ( -1.0 * yVal ) / xVal ) - mContext.mapToPixel().mapRotation() * M_DEG2RAD;
     154                 :            : 
     155                 :          0 :   cosAlpha = cos( vectorAngle ) * mag( xVal );
     156                 :          0 :   sinAlpha = sin( vectorAngle ) * mag( xVal );
     157                 :            : 
     158                 :            :   // Now determine the X and Y distances of the end of the line from the start
     159                 :          0 :   double xDist = 0.0;
     160                 :          0 :   double yDist = 0.0;
     161                 :          0 :   switch ( mCfg.arrowSettings().shaftLengthMethod() )
     162                 :            :   {
     163                 :            :     case QgsMeshRendererVectorArrowSettings::ArrowScalingMethod::MinMax:
     164                 :            :     {
     165                 :          0 :       double minShaftLength = mContext.convertToPainterUnits( mCfg.arrowSettings().minShaftLength(),
     166                 :            :                               QgsUnitTypes::RenderUnit::RenderMillimeters );
     167                 :          0 :       double maxShaftLength = mContext.convertToPainterUnits( mCfg.arrowSettings().maxShaftLength(),
     168                 :            :                               QgsUnitTypes::RenderUnit::RenderMillimeters );
     169                 :          0 :       double minVal = mMinMag;
     170                 :          0 :       double maxVal = mMaxMag;
     171                 :          0 :       double k = ( magnitude - minVal ) / ( maxVal - minVal );
     172                 :          0 :       double L = minShaftLength + k * ( maxShaftLength - minShaftLength );
     173                 :          0 :       xDist = cosAlpha * L;
     174                 :          0 :       yDist = sinAlpha * L;
     175                 :          0 :       break;
     176                 :            :     }
     177                 :            :     case QgsMeshRendererVectorArrowSettings::ArrowScalingMethod::Scaled:
     178                 :            :     {
     179                 :          0 :       double scaleFactor = mCfg.arrowSettings().scaleFactor();
     180                 :          0 :       xDist = scaleFactor * xVal;
     181                 :          0 :       yDist = scaleFactor * yVal;
     182                 :          0 :       break;
     183                 :            :     }
     184                 :            :     case QgsMeshRendererVectorArrowSettings::ArrowScalingMethod::Fixed:
     185                 :            :     {
     186                 :            :       // We must be using a fixed length
     187                 :          0 :       double fixedShaftLength = mContext.convertToPainterUnits( mCfg.arrowSettings().fixedShaftLength(),
     188                 :            :                                 QgsUnitTypes::RenderUnit::RenderMillimeters );
     189                 :          0 :       xDist = cosAlpha * fixedShaftLength;
     190                 :          0 :       yDist = sinAlpha * fixedShaftLength;
     191                 :          0 :       break;
     192                 :            :     }
     193                 :            :   }
     194                 :            : 
     195                 :            :   // Flip the Y axis (pixel vs real-world axis)
     196                 :          0 :   yDist *= -1.0;
     197                 :            : 
     198                 :          0 :   if ( std::abs( xDist ) < 1 && std::abs( yDist ) < 1 )
     199                 :          0 :     return true;
     200                 :            : 
     201                 :            :   // Determine the line coords
     202                 :          0 :   lineEnd = QgsPointXY( lineStart.x() + xDist,
     203                 :          0 :                         lineStart.y() + yDist );
     204                 :            : 
     205                 :          0 :   vectorLength = sqrt( xDist * xDist + yDist * yDist );
     206                 :            : 
     207                 :            :   // Check to see if both of the coords are outside the QImage area, if so, skip the whole vector
     208                 :          0 :   if ( ( lineStart.x() < 0 || lineStart.x() > mOutputSize.width() ||
     209                 :          0 :          lineStart.y() < 0 || lineStart.y() > mOutputSize.height() ) &&
     210                 :          0 :        ( lineEnd.x() < 0   || lineEnd.x() > mOutputSize.width() ||
     211                 :          0 :          lineEnd.y() < 0   || lineEnd.y() > mOutputSize.height() ) )
     212                 :          0 :     return true;
     213                 :            : 
     214                 :          0 :   return false; //success
     215                 :          0 : }
     216                 :            : 
     217                 :          0 : double QgsMeshVectorArrowRenderer::calcExtentBufferSize() const
     218                 :            : {
     219                 :          0 :   double buffer = 0;
     220                 :          0 :   switch ( mCfg.arrowSettings().shaftLengthMethod() )
     221                 :            :   {
     222                 :            :     case QgsMeshRendererVectorArrowSettings::ArrowScalingMethod::MinMax:
     223                 :            :     {
     224                 :          0 :       buffer = mContext.convertToPainterUnits( mCfg.arrowSettings().maxShaftLength(),
     225                 :            :                QgsUnitTypes::RenderUnit::RenderMillimeters );
     226                 :          0 :       break;
     227                 :            :     }
     228                 :            :     case QgsMeshRendererVectorArrowSettings::ArrowScalingMethod::Scaled:
     229                 :            :     {
     230                 :          0 :       buffer = mCfg.arrowSettings().scaleFactor() * mMaxMag;
     231                 :          0 :       break;
     232                 :            :     }
     233                 :            :     case QgsMeshRendererVectorArrowSettings::ArrowScalingMethod::Fixed:
     234                 :            :     {
     235                 :          0 :       buffer = mContext.convertToPainterUnits( mCfg.arrowSettings().fixedShaftLength(),
     236                 :            :                QgsUnitTypes::RenderUnit::RenderMillimeters );
     237                 :          0 :       break;
     238                 :            :     }
     239                 :            :   }
     240                 :            : 
     241                 :          0 :   if ( mCfg.filterMax() >= 0 && buffer > mCfg.filterMax() )
     242                 :          0 :     buffer = mCfg.filterMax();
     243                 :            : 
     244                 :          0 :   if ( buffer < 0.0 )
     245                 :          0 :     buffer = 0.0;
     246                 :            : 
     247                 :          0 :   return buffer;
     248                 :            : }
     249                 :            : 
     250                 :            : 
     251                 :          0 : void QgsMeshVectorArrowRenderer::drawVectorDataOnVertices()
     252                 :            : {
     253                 :          0 :   const QVector<QgsMeshVertex> &vertices = mTriangularMesh.vertices();
     254                 :          0 :   QSet<int> verticesToDraw;
     255                 :            : 
     256                 :            :   // currently expecting that triangulation does not add any new extra vertices on the way
     257                 :            :   Q_ASSERT( mDatasetValuesMag.count() == vertices.count() );
     258                 :            : 
     259                 :            :   // find all vertices from faces to render
     260                 :            :   {
     261                 :          0 :     const QList<int> trianglesInExtent = mTriangularMesh.faceIndexesForRectangle( mBufferedExtent );
     262                 :          0 :     const QVector<QgsMeshFace> &triangles = mTriangularMesh.triangles();
     263                 :          0 :     verticesToDraw.unite( QgsMeshUtils::nativeVerticesFromTriangles( trianglesInExtent, triangles ) );
     264                 :          0 :   }
     265                 :            : 
     266                 :            :   // find all vertices from edges to render
     267                 :            :   {
     268                 :          0 :     const QList<int> edgesInExtent = mTriangularMesh.edgeIndexesForRectangle( mBufferedExtent );
     269                 :          0 :     const QVector<QgsMeshEdge> &edges = mTriangularMesh.edges();
     270                 :          0 :     verticesToDraw.unite( QgsMeshUtils::nativeVerticesFromEdges( edgesInExtent, edges ) );
     271                 :          0 :   }
     272                 :            : 
     273                 :            :   // render
     274                 :          0 :   drawVectorDataOnPoints( verticesToDraw, vertices );
     275                 :          0 : }
     276                 :            : 
     277                 :          0 : void QgsMeshVectorArrowRenderer::drawVectorDataOnPoints( const QSet<int> indexesToRender, const QVector<QgsMeshVertex> &points )
     278                 :            : {
     279                 :          0 :   for ( int i : indexesToRender )
     280                 :            :   {
     281                 :          0 :     if ( mContext.renderingStopped() )
     282                 :          0 :       break;
     283                 :            : 
     284                 :          0 :     QgsPointXY center = points.at( i );
     285                 :          0 :     if ( !mBufferedExtent.contains( center ) )
     286                 :          0 :       continue;
     287                 :            : 
     288                 :          0 :     const QgsMeshDatasetValue val = mDatasetValues.value( i );
     289                 :          0 :     double xVal = val.x();
     290                 :          0 :     double yVal = val.y();
     291                 :          0 :     if ( nodataValue( xVal, yVal ) )
     292                 :          0 :       continue;
     293                 :            : 
     294                 :          0 :     double V = mDatasetValuesMag[i];  // pre-calculated magnitude
     295                 :          0 :     QgsPointXY lineStart = mContext.mapToPixel().transform( center.x(), center.y() );
     296                 :            : 
     297                 :          0 :     drawVectorArrow( lineStart, xVal, yVal, V );
     298                 :            :   }
     299                 :          0 : }
     300                 :            : 
     301                 :          0 : void QgsMeshVectorArrowRenderer::drawVectorDataOnFaces( )
     302                 :            : {
     303                 :          0 :   const QList<int> trianglesInExtent = mTriangularMesh.faceIndexesForRectangle( mBufferedExtent );
     304                 :          0 :   const QVector<QgsMeshVertex> &centroids = mTriangularMesh.faceCentroids();
     305                 :          0 :   const QSet<int> nativeFacesInExtent = QgsMeshUtils::nativeFacesFromTriangles( trianglesInExtent,
     306                 :          0 :                                         mTriangularMesh.trianglesToNativeFaces() );
     307                 :          0 :   drawVectorDataOnPoints( nativeFacesInExtent, centroids );
     308                 :          0 : }
     309                 :            : 
     310                 :          0 : void QgsMeshVectorArrowRenderer::drawVectorDataOnEdges()
     311                 :            : {
     312                 :          0 :   const QList<int> egdesInExtent = mTriangularMesh.edgeIndexesForRectangle( mBufferedExtent );
     313                 :          0 :   const QVector<QgsMeshVertex> &centroids = mTriangularMesh.edgeCentroids();
     314                 :          0 :   const QSet<int> nativeEdgesInExtent = QgsMeshUtils::nativeEdgesFromEdges( egdesInExtent,
     315                 :          0 :                                         mTriangularMesh.edgesToNativeEdges() );
     316                 :          0 :   drawVectorDataOnPoints( nativeEdgesInExtent, centroids );
     317                 :          0 : }
     318                 :            : 
     319                 :          0 : void QgsMeshVectorArrowRenderer::drawVectorDataOnGrid( )
     320                 :            : {
     321                 :          0 :   if ( mDataType == QgsMeshDatasetGroupMetadata::DataType::DataOnEdges ||
     322                 :          0 :        mDataType == QgsMeshDatasetGroupMetadata::DataType::DataOnVolumes )
     323                 :          0 :     return;
     324                 :            : 
     325                 :          0 :   const QList<int> trianglesInExtent = mTriangularMesh.faceIndexesForRectangle( mBufferedExtent );
     326                 :          0 :   int cellx = mCfg.userGridCellWidth();
     327                 :          0 :   int celly = mCfg.userGridCellHeight();
     328                 :            : 
     329                 :          0 :   const QVector<QgsMeshFace> &triangles = mTriangularMesh.triangles();
     330                 :          0 :   const QVector<QgsMeshVertex> &vertices = mTriangularMesh.vertices();
     331                 :            : 
     332                 :          0 :   for ( const int i : trianglesInExtent )
     333                 :            :   {
     334                 :          0 :     if ( mContext.renderingStopped() )
     335                 :          0 :       break;
     336                 :            : 
     337                 :          0 :     const QgsMeshFace &face = triangles[i];
     338                 :            : 
     339                 :          0 :     const int v1 = face[0], v2 = face[1], v3 = face[2];
     340                 :          0 :     const QgsPoint p1 = vertices[v1], p2 = vertices[v2], p3 = vertices[v3];
     341                 :            : 
     342                 :          0 :     const int nativeFaceIndex = mTriangularMesh.trianglesToNativeFaces()[i];
     343                 :            : 
     344                 :            :     // Get the BBox of the element in pixels
     345                 :          0 :     QgsRectangle bbox = QgsMeshLayerUtils::triangleBoundingBox( p1, p2, p3 );
     346                 :            :     int left, right, top, bottom;
     347                 :          0 :     QgsMeshLayerUtils::boundingBoxToScreenRectangle( mContext.mapToPixel(), mOutputSize, bbox, left, right, top, bottom );
     348                 :            : 
     349                 :            :     // Align rect to the grid (e.g. interval <13, 36> with grid cell 10 will be trimmed to <20,30>
     350                 :          0 :     if ( left % cellx != 0 )
     351                 :          0 :       left += cellx - ( left % cellx );
     352                 :          0 :     if ( right % cellx != 0 )
     353                 :          0 :       right -= ( right % cellx );
     354                 :          0 :     if ( top % celly != 0 )
     355                 :          0 :       top += celly - ( top % celly );
     356                 :          0 :     if ( bottom % celly != 0 )
     357                 :          0 :       bottom -= ( bottom % celly );
     358                 :            : 
     359                 :          0 :     for ( int y = top; y <= bottom; y += celly )
     360                 :            :     {
     361                 :          0 :       for ( int x = left; x <= right; x += cellx )
     362                 :            :       {
     363                 :          0 :         QgsMeshDatasetValue val;
     364                 :          0 :         const QgsPointXY p = mContext.mapToPixel().toMapCoordinates( x, y );
     365                 :            : 
     366                 :          0 :         if ( mDataType == QgsMeshDatasetGroupMetadata::DataType::DataOnVertices )
     367                 :            :         {
     368                 :          0 :           const auto val1 = mDatasetValues.value( v1 );
     369                 :          0 :           const auto val2 = mDatasetValues.value( v2 );
     370                 :          0 :           const auto val3 = mDatasetValues.value( v3 );
     371                 :          0 :           val.setX(
     372                 :          0 :             QgsMeshLayerUtils::interpolateFromVerticesData(
     373                 :          0 :               p1, p2, p3,
     374                 :          0 :               val1.x(),
     375                 :          0 :               val2.x(),
     376                 :          0 :               val3.x(),
     377                 :            :               p )
     378                 :            :           );
     379                 :          0 :           val.setY(
     380                 :          0 :             QgsMeshLayerUtils::interpolateFromVerticesData(
     381                 :          0 :               p1, p2, p3,
     382                 :          0 :               val1.y(),
     383                 :          0 :               val2.y(),
     384                 :          0 :               val3.y(),
     385                 :            :               p )
     386                 :            :           );
     387                 :          0 :         }
     388                 :          0 :         else if ( mDataType == QgsMeshDatasetGroupMetadata::DataType::DataOnFaces )
     389                 :            :         {
     390                 :          0 :           const auto val1 = mDatasetValues.value( nativeFaceIndex );
     391                 :          0 :           val.setX(
     392                 :          0 :             QgsMeshLayerUtils::interpolateFromFacesData(
     393                 :          0 :               p1, p2, p3,
     394                 :          0 :               val1.x(),
     395                 :            :               p
     396                 :            :             )
     397                 :            :           );
     398                 :          0 :           val.setY(
     399                 :          0 :             QgsMeshLayerUtils::interpolateFromFacesData(
     400                 :          0 :               p1, p2, p3,
     401                 :          0 :               val1.y(),
     402                 :            :               p
     403                 :            :             )
     404                 :            :           );
     405                 :          0 :         }
     406                 :          0 :         if ( nodataValue( val.x(), val.y() ) )
     407                 :          0 :           continue;
     408                 :            : 
     409                 :          0 :         QgsPointXY lineStart( x, y );
     410                 :          0 :         drawVectorArrow( lineStart, val.x(), val.y(), val.scalar() );
     411                 :          0 :       }
     412                 :          0 :     }
     413                 :          0 :   }
     414                 :          0 : }
     415                 :            : 
     416                 :          0 : void QgsMeshVectorArrowRenderer::drawVectorArrow( const QgsPointXY &lineStart, double xVal, double yVal, double magnitude )
     417                 :            : {
     418                 :          0 :   QgsPointXY lineEnd;
     419                 :            :   double vectorLength;
     420                 :            :   double cosAlpha, sinAlpha;
     421                 :          0 :   if ( calcVectorLineEnd( lineEnd, vectorLength, cosAlpha, sinAlpha,
     422                 :          0 :                           lineStart, xVal, yVal, magnitude ) )
     423                 :          0 :     return;
     424                 :            : 
     425                 :            :   // Make a set of vector head coordinates that we will place at the end of each vector,
     426                 :            :   // scale, translate and rotate.
     427                 :          0 :   QgsPointXY vectorHeadPoints[3];
     428                 :          0 :   QVector<QPointF> finalVectorHeadPoints( 3 );
     429                 :            : 
     430                 :          0 :   double vectorHeadWidthRatio  = mCfg.arrowSettings().arrowHeadWidthRatio();
     431                 :          0 :   double vectorHeadLengthRatio = mCfg.arrowSettings().arrowHeadLengthRatio();
     432                 :            : 
     433                 :            :   // First head point:  top of ->
     434                 :          0 :   vectorHeadPoints[0].setX( -1.0 * vectorHeadLengthRatio );
     435                 :          0 :   vectorHeadPoints[0].setY( vectorHeadWidthRatio * 0.5 );
     436                 :            : 
     437                 :            :   // Second head point:  right of ->
     438                 :          0 :   vectorHeadPoints[1].setX( 0.0 );
     439                 :          0 :   vectorHeadPoints[1].setY( 0.0 );
     440                 :            : 
     441                 :            :   // Third head point:  bottom of ->
     442                 :          0 :   vectorHeadPoints[2].setX( -1.0 * vectorHeadLengthRatio );
     443                 :          0 :   vectorHeadPoints[2].setY( -1.0 * vectorHeadWidthRatio * 0.5 );
     444                 :            : 
     445                 :            :   // Determine the arrow head coords
     446                 :          0 :   for ( int j = 0; j < 3; j++ )
     447                 :            :   {
     448                 :          0 :     finalVectorHeadPoints[j].setX( lineEnd.x()
     449                 :          0 :                                    + ( vectorHeadPoints[j].x() * cosAlpha * vectorLength )
     450                 :          0 :                                    - ( vectorHeadPoints[j].y() * sinAlpha * vectorLength )
     451                 :            :                                  );
     452                 :            : 
     453                 :          0 :     finalVectorHeadPoints[j].setY( lineEnd.y()
     454                 :          0 :                                    - ( vectorHeadPoints[j].x() * sinAlpha * vectorLength )
     455                 :          0 :                                    - ( vectorHeadPoints[j].y() * cosAlpha * vectorLength )
     456                 :            :                                  );
     457                 :          0 :   }
     458                 :            : 
     459                 :            :   // Now actually draw the vector
     460                 :          0 :   QPen pen( mContext.painter()->pen() );
     461                 :          0 :   pen.setColor( mVectorColoring.color( magnitude ) );
     462                 :          0 :   mContext.painter()->setPen( pen );
     463                 :          0 :   mContext.painter()->drawLine( lineStart.toQPointF(), lineEnd.toQPointF() );
     464                 :          0 :   mContext.painter()->drawPolygon( finalVectorHeadPoints );
     465                 :          0 : }
     466                 :            : 
     467                 :          0 : QgsMeshVectorRenderer::~QgsMeshVectorRenderer() = default;
     468                 :            : 
     469                 :          0 : QgsMeshVectorRenderer *QgsMeshVectorRenderer::makeVectorRenderer(
     470                 :            :   const QgsTriangularMesh &m,
     471                 :            :   const QgsMeshDataBlock &datasetVectorValues,
     472                 :            :   const QgsMeshDataBlock &scalarActiveFaceFlagValues,
     473                 :            :   const QVector<double> &datasetValuesMag,
     474                 :            :   double datasetMagMaximumValue,
     475                 :            :   double datasetMagMinimumValue,
     476                 :            :   QgsMeshDatasetGroupMetadata::DataType dataType,
     477                 :            :   const QgsMeshRendererVectorSettings &settings,
     478                 :            :   QgsRenderContext &context,
     479                 :            :   const QgsRectangle &layerExtent,
     480                 :            :   QSize size )
     481                 :            : {
     482                 :          0 :   QgsMeshVectorRenderer *renderer = nullptr;
     483                 :            : 
     484                 :          0 :   switch ( settings.symbology() )
     485                 :            :   {
     486                 :            :     case QgsMeshRendererVectorSettings::Arrows:
     487                 :          0 :       renderer = new QgsMeshVectorArrowRenderer(
     488                 :          0 :         m,
     489                 :          0 :         datasetVectorValues,
     490                 :          0 :         datasetValuesMag,
     491                 :          0 :         datasetMagMaximumValue,
     492                 :          0 :         datasetMagMinimumValue,
     493                 :          0 :         dataType,
     494                 :          0 :         settings,
     495                 :          0 :         context,
     496                 :          0 :         size );
     497                 :          0 :       break;
     498                 :            :     case QgsMeshRendererVectorSettings::Streamlines:
     499                 :          0 :       renderer = new QgsMeshVectorStreamlineRenderer(
     500                 :          0 :         m,
     501                 :          0 :         datasetVectorValues,
     502                 :          0 :         scalarActiveFaceFlagValues,
     503                 :          0 :         dataType == QgsMeshDatasetGroupMetadata::DataType::DataOnVertices,
     504                 :          0 :         settings,
     505                 :          0 :         context,
     506                 :          0 :         layerExtent,
     507                 :          0 :         datasetMagMaximumValue );
     508                 :          0 :       break;
     509                 :            :     case QgsMeshRendererVectorSettings::Traces:
     510                 :          0 :       renderer = new QgsMeshVectorTraceRenderer(
     511                 :          0 :         m,
     512                 :          0 :         datasetVectorValues,
     513                 :          0 :         scalarActiveFaceFlagValues,
     514                 :          0 :         dataType == QgsMeshDatasetGroupMetadata::DataType::DataOnVertices,
     515                 :          0 :         settings,
     516                 :          0 :         context,
     517                 :          0 :         layerExtent,
     518                 :          0 :         datasetMagMaximumValue );
     519                 :          0 :       break;
     520                 :            :   }
     521                 :            : 
     522                 :          0 :   return renderer;
     523                 :          0 : }
     524                 :            : 
     525                 :            : 
     526                 :            : ///@endcond

Generated by: LCOV version 1.14