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

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :                          qgsmeshlayerutils.cpp
       3                 :            :                          --------------------------
       4                 :            :     begin                : August 2018
       5                 :            :     copyright            : (C) 2018 by Martin Dobias
       6                 :            :     email                : wonder dot sk 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 <limits>
      19                 :            : #include <QTime>
      20                 :            : #include <QDateTime>
      21                 :            : 
      22                 :            : #include "qgsmeshlayerutils.h"
      23                 :            : #include "qgsmeshtimesettings.h"
      24                 :            : #include "qgstriangularmesh.h"
      25                 :            : #include "qgslogger.h"
      26                 :            : #include "qgsmeshdataprovider.h"
      27                 :            : #include "qgsmesh3daveraging.h"
      28                 :            : #include "qgsmeshlayer.h"
      29                 :            : 
      30                 :            : 
      31                 :            : ///@cond PRIVATE
      32                 :            : 
      33                 :          0 : int QgsMeshLayerUtils::datasetValuesCount( const QgsMesh *mesh, QgsMeshDatasetGroupMetadata::DataType dataType )
      34                 :            : {
      35                 :          0 :   if ( !mesh )
      36                 :          0 :     return 0;
      37                 :            : 
      38                 :          0 :   switch ( dataType )
      39                 :            :   {
      40                 :            :     case QgsMeshDatasetGroupMetadata::DataType::DataOnEdges:
      41                 :          0 :       return mesh->edgeCount();
      42                 :            :     case QgsMeshDatasetGroupMetadata::DataType::DataOnFaces:
      43                 :          0 :       return mesh->faceCount();
      44                 :            :     case QgsMeshDatasetGroupMetadata::DataType::DataOnVertices:
      45                 :          0 :       return mesh->vertexCount();
      46                 :            :     case QgsMeshDatasetGroupMetadata::DataType::DataOnVolumes:
      47                 :          0 :       return mesh->faceCount(); // because they are averaged to faces
      48                 :            :   }
      49                 :          0 :   return 0;
      50                 :          0 : }
      51                 :            : 
      52                 :          0 : QgsMeshDatasetGroupMetadata::DataType QgsMeshLayerUtils::datasetValuesType( const QgsMeshDatasetGroupMetadata::DataType &type )
      53                 :            : {
      54                 :            :   // data on volumes are averaged to 2D data on faces
      55                 :          0 :   if ( type == QgsMeshDatasetGroupMetadata::DataType::DataOnVolumes )
      56                 :          0 :     return QgsMeshDatasetGroupMetadata::DataType::DataOnFaces;
      57                 :            : 
      58                 :          0 :   return type;
      59                 :          0 : }
      60                 :            : 
      61                 :          0 : QgsMeshDataBlock QgsMeshLayerUtils::datasetValues(
      62                 :            :   const QgsMeshLayer *meshLayer,
      63                 :            :   QgsMeshDatasetIndex index,
      64                 :            :   int valueIndex,
      65                 :            :   int count )
      66                 :            : {
      67                 :          0 :   QgsMeshDataBlock block;
      68                 :          0 :   if ( !meshLayer )
      69                 :          0 :     return block;
      70                 :            : 
      71                 :            : 
      72                 :          0 :   if ( !meshLayer->datasetCount( index ) )
      73                 :          0 :     return block;
      74                 :            : 
      75                 :          0 :   if ( !index.isValid() )
      76                 :          0 :     return block;
      77                 :            : 
      78                 :          0 :   const QgsMeshDatasetGroupMetadata meta = meshLayer->datasetGroupMetadata( index.group() );
      79                 :          0 :   if ( meta.dataType() != QgsMeshDatasetGroupMetadata::DataType::DataOnVolumes )
      80                 :            :   {
      81                 :          0 :     block = meshLayer->datasetValues( index, valueIndex, count );
      82                 :          0 :     if ( block.isValid() )
      83                 :          0 :       return block;
      84                 :          0 :   }
      85                 :            :   else
      86                 :            :   {
      87                 :          0 :     const QgsMesh3dAveragingMethod *averagingMethod = meshLayer->rendererSettings().averagingMethod();
      88                 :          0 :     if ( !averagingMethod )
      89                 :          0 :       return block;
      90                 :            : 
      91                 :          0 :     QgsMesh3dDataBlock block3d = meshLayer->dataset3dValues( index, valueIndex, count );
      92                 :          0 :     if ( !block3d.isValid() )
      93                 :          0 :       return block;
      94                 :            : 
      95                 :          0 :     block = averagingMethod->calculate( block3d );
      96                 :          0 :   }
      97                 :          0 :   return block;
      98                 :          0 : }
      99                 :            : 
     100                 :          0 : QVector<QgsVector> QgsMeshLayerUtils::griddedVectorValues( const QgsMeshLayer *meshLayer,
     101                 :            :     const QgsMeshDatasetIndex index,
     102                 :            :     double xSpacing,
     103                 :            :     double ySpacing,
     104                 :            :     const QSize &size,
     105                 :            :     const QgsPointXY &minCorner )
     106                 :            : {
     107                 :          0 :   QVector<QgsVector> vectors;
     108                 :            : 
     109                 :          0 :   if ( !meshLayer || !index.isValid() )
     110                 :          0 :     return vectors;
     111                 :            : 
     112                 :          0 :   const QgsTriangularMesh *triangularMesh = meshLayer->triangularMesh();
     113                 :          0 :   const QgsMesh *nativeMesh = meshLayer->nativeMesh();
     114                 :            : 
     115                 :          0 :   if ( !triangularMesh || !nativeMesh )
     116                 :          0 :     return vectors;
     117                 :            : 
     118                 :          0 :   QgsMeshDatasetGroupMetadata meta = meshLayer->datasetGroupMetadata( index );
     119                 :          0 :   if ( !meta.isVector() )
     120                 :          0 :     return vectors;
     121                 :            : 
     122                 :            :   // extract vector dataset
     123                 :          0 :   bool vectorDataOnVertices = meta.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices;
     124                 :          0 :   int datacount = vectorDataOnVertices ? nativeMesh->vertices.count() : nativeMesh->faces.count();
     125                 :          0 :   const QgsMeshDataBlock vals = QgsMeshLayerUtils::datasetValues( meshLayer, index, 0, datacount );
     126                 :            : 
     127                 :          0 :   const QgsMeshDataBlock isFacesActive = meshLayer->areFacesActive( index, 0, nativeMesh->faceCount() );
     128                 :          0 :   const QgsMeshDatasetGroupMetadata::DataType dataType = meta.dataType();
     129                 :            : 
     130                 :          0 :   if ( dataType == QgsMeshDatasetGroupMetadata::DataOnEdges )
     131                 :          0 :     return vectors;
     132                 :            : 
     133                 :            :   try
     134                 :            :   {
     135                 :          0 :     vectors.reserve( size.height()*size.width() );
     136                 :          0 :   }
     137                 :            :   catch ( ... )
     138                 :            :   {
     139                 :          0 :     QgsDebugMsgLevel( "Unable to store the arrow grid in memory", 1 );
     140                 :          0 :     return QVector<QgsVector>();
     141                 :          0 :   }
     142                 :            : 
     143                 :          0 :   for ( int iy = 0; iy < size.height(); ++iy )
     144                 :            :   {
     145                 :          0 :     double y = minCorner.y() + iy * ySpacing;
     146                 :          0 :     for ( int ix = 0; ix < size.width(); ++ix )
     147                 :            :     {
     148                 :          0 :       double x = minCorner.x() + ix * xSpacing;
     149                 :          0 :       QgsPoint point( x, y );
     150                 :          0 :       int faceIndex = triangularMesh->faceIndexForPoint_v2( point );
     151                 :          0 :       int nativeFaceIndex = -1;
     152                 :          0 :       if ( faceIndex != -1 )
     153                 :          0 :         nativeFaceIndex = triangularMesh->trianglesToNativeFaces().at( faceIndex );
     154                 :          0 :       QgsMeshDatasetValue value;
     155                 :          0 :       if ( nativeFaceIndex != -1 && isFacesActive.active( nativeFaceIndex ) )
     156                 :            :       {
     157                 :          0 :         switch ( dataType )
     158                 :            :         {
     159                 :            :           case QgsMeshDatasetGroupMetadata::DataOnFaces:
     160                 :            :           case QgsMeshDatasetGroupMetadata::DataOnVolumes:
     161                 :          0 :             value = vals.value( nativeFaceIndex );
     162                 :          0 :             break;
     163                 :            :           case QgsMeshDatasetGroupMetadata::DataOnVertices:
     164                 :            :           {
     165                 :          0 :             const QgsMeshFace &face = triangularMesh->triangles()[faceIndex];
     166                 :          0 :             const int v1 = face[0], v2 = face[1], v3 = face[2];
     167                 :          0 :             const QgsPoint p1 = triangularMesh->vertices()[v1], p2 = triangularMesh->vertices()[v2], p3 = triangularMesh->vertices()[v3];
     168                 :          0 :             const QgsMeshDatasetValue val1 = vals.value( v1 );
     169                 :          0 :             const QgsMeshDatasetValue val2 = vals.value( v2 );
     170                 :          0 :             const QgsMeshDatasetValue val3 = vals.value( v3 );
     171                 :          0 :             const double x = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.x(), val2.x(), val3.x(), point );
     172                 :          0 :             const double y = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.y(), val2.y(), val3.y(), point );
     173                 :          0 :             value = QgsMeshDatasetValue( x, y );
     174                 :          0 :           }
     175                 :          0 :           break;
     176                 :            :           case QgsMeshDatasetGroupMetadata::DataOnEdges:
     177                 :          0 :             break;
     178                 :            :         }
     179                 :          0 :       }
     180                 :          0 :       vectors.append( QgsVector( value.x(), value.y() ) );
     181                 :          0 :     }
     182                 :          0 :   }
     183                 :          0 :   return vectors;
     184                 :          0 : }
     185                 :            : 
     186                 :          0 : QVector<double> QgsMeshLayerUtils::calculateMagnitudes( const QgsMeshDataBlock &block )
     187                 :            : {
     188                 :            :   Q_ASSERT( QgsMeshDataBlock::ActiveFlagInteger != block.type() );
     189                 :          0 :   int count = block.count();
     190                 :          0 :   QVector<double> ret( count );
     191                 :            : 
     192                 :          0 :   for ( int i = 0; i < count; ++i )
     193                 :            :   {
     194                 :          0 :     double mag = block.value( i ).scalar();
     195                 :          0 :     ret[i] = mag;
     196                 :          0 :   }
     197                 :          0 :   return ret;
     198                 :          0 : }
     199                 :            : 
     200                 :          0 : QgsRectangle QgsMeshLayerUtils::boundingBoxToScreenRectangle(
     201                 :            :   const QgsMapToPixel &mtp,
     202                 :            :   const QgsRectangle &bbox
     203                 :            : )
     204                 :            : {
     205                 :          0 :   const QgsPointXY topLeft = mtp.transform( bbox.xMinimum(), bbox.yMaximum() );
     206                 :          0 :   const QgsPointXY topRight = mtp.transform( bbox.xMaximum(), bbox.yMaximum() );
     207                 :          0 :   const QgsPointXY bottomLeft = mtp.transform( bbox.xMinimum(), bbox.yMinimum() );
     208                 :          0 :   const QgsPointXY bottomRight = mtp.transform( bbox.xMaximum(), bbox.yMinimum() );
     209                 :            : 
     210                 :          0 :   double xMin = std::min( {topLeft.x(), topRight.x(), bottomLeft.x(), bottomRight.x()} );
     211                 :          0 :   double xMax = std::max( {topLeft.x(), topRight.x(), bottomLeft.x(), bottomRight.x()} );
     212                 :          0 :   double yMin = std::min( {topLeft.y(), topRight.y(), bottomLeft.y(), bottomRight.y()} );
     213                 :          0 :   double yMax = std::max( {topLeft.y(), topRight.y(), bottomLeft.y(), bottomRight.y()} );
     214                 :            : 
     215                 :          0 :   QgsRectangle ret( xMin, yMin, xMax, yMax );
     216                 :          0 :   return ret;
     217                 :            : }
     218                 :            : 
     219                 :          0 : void QgsMeshLayerUtils::boundingBoxToScreenRectangle(
     220                 :            :   const QgsMapToPixel &mtp,
     221                 :            :   const QSize &outputSize,
     222                 :            :   const QgsRectangle &bbox,
     223                 :            :   int &leftLim,
     224                 :            :   int &rightLim,
     225                 :            :   int &bottomLim,
     226                 :            :   int &topLim )
     227                 :            : {
     228                 :          0 :   const QgsRectangle screenBBox = boundingBoxToScreenRectangle( mtp, bbox );
     229                 :            : 
     230                 :          0 :   bottomLim = std::max( int( screenBBox.yMinimum() ), 0 );
     231                 :          0 :   topLim = std::min( int( screenBBox.yMaximum() ), outputSize.height() - 1 );
     232                 :          0 :   leftLim = std::max( int( screenBBox.xMinimum() ), 0 );
     233                 :          0 :   rightLim = std::min( int( screenBBox.xMaximum() ), outputSize.width() - 1 );
     234                 :          0 : }
     235                 :            : 
     236                 :          0 : static void lamTol( double &lam )
     237                 :            : {
     238                 :            :   const static double eps = 1e-6;
     239                 :          0 :   if ( ( lam < 0.0 ) && ( lam > -eps ) )
     240                 :            :   {
     241                 :          0 :     lam = 0.0;
     242                 :          0 :   }
     243                 :          0 : }
     244                 :            : 
     245                 :          0 : static bool E3T_physicalToBarycentric( const QgsPointXY &pA, const QgsPointXY &pB, const QgsPointXY &pC, const QgsPointXY &pP,
     246                 :            :                                        double &lam1, double &lam2, double &lam3 )
     247                 :            : {
     248                 :            :   // Compute vectors
     249                 :          0 :   double xa = pA.x();
     250                 :          0 :   double ya = pA.y();
     251                 :          0 :   double v0x = pC.x() - xa ;
     252                 :          0 :   double v0y = pC.y() - ya ;
     253                 :          0 :   double v1x = pB.x() - xa ;
     254                 :          0 :   double v1y = pB.y() - ya ;
     255                 :          0 :   double v2x = pP.x() - xa ;
     256                 :          0 :   double v2y = pP.y() - ya ;
     257                 :            : 
     258                 :            :   // Compute dot products
     259                 :          0 :   double dot00 = v0x * v0x + v0y * v0y;
     260                 :          0 :   double dot01 = v0x * v1x + v0y * v1y;
     261                 :          0 :   double dot02 = v0x * v2x + v0y * v2y;
     262                 :          0 :   double dot11 = v1x * v1x + v1y * v1y;
     263                 :          0 :   double dot12 = v1x * v2x + v1y * v2y;
     264                 :            : 
     265                 :            :   // Compute barycentric coordinates
     266                 :          0 :   double invDenom =  dot00 * dot11 - dot01 * dot01;
     267                 :          0 :   if ( invDenom == 0 )
     268                 :          0 :     return false;
     269                 :          0 :   invDenom = 1.0 / invDenom;
     270                 :          0 :   lam1 = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
     271                 :          0 :   lam2 = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
     272                 :          0 :   lam3 = 1.0 - lam1 - lam2;
     273                 :            : 
     274                 :            :   // Apply some tolerance to lam so we can detect correctly border points
     275                 :          0 :   lamTol( lam1 );
     276                 :          0 :   lamTol( lam2 );
     277                 :          0 :   lamTol( lam3 );
     278                 :            : 
     279                 :            :   // Return if POI is outside triangle
     280                 :          0 :   if ( ( lam1 < 0 ) || ( lam2 < 0 ) || ( lam3 < 0 ) )
     281                 :            :   {
     282                 :          0 :     return false;
     283                 :            :   }
     284                 :            : 
     285                 :          0 :   return true;
     286                 :          0 : }
     287                 :            : 
     288                 :          0 : double QgsMeshLayerUtils::interpolateFromVerticesData( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3,
     289                 :            :     double val1, double val2, double val3, const QgsPointXY &pt )
     290                 :            : {
     291                 :            :   double lam1, lam2, lam3;
     292                 :          0 :   if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
     293                 :          0 :     return std::numeric_limits<double>::quiet_NaN();
     294                 :            : 
     295                 :          0 :   return lam1 * val3 + lam2 * val2 + lam3 * val1;
     296                 :          0 : }
     297                 :            : 
     298                 :          0 : double QgsMeshLayerUtils::interpolateFromVerticesData( double fraction, double val1, double val2 )
     299                 :            : {
     300                 :          0 :   if ( std::isnan( val1 ) || std::isnan( val2 ) || ( fraction < 0 ) || ( fraction > 1 ) )
     301                 :            :   {
     302                 :          0 :     return std::numeric_limits<double>::quiet_NaN();
     303                 :            :   }
     304                 :          0 :   return val1 + ( val2 - val1 ) * fraction;
     305                 :          0 : }
     306                 :            : 
     307                 :          0 : QgsMeshDatasetValue QgsMeshLayerUtils::interpolateFromVerticesData( double fraction, const QgsMeshDatasetValue &val1, const QgsMeshDatasetValue &val2 )
     308                 :            : {
     309                 :          0 :   return QgsMeshDatasetValue( interpolateFromVerticesData( fraction, val1.x(), val2.x() ),
     310                 :          0 :                               interpolateFromVerticesData( fraction, val1.y(), val2.y() ) );
     311                 :            : }
     312                 :            : 
     313                 :            : 
     314                 :          0 : QgsVector QgsMeshLayerUtils::interpolateVectorFromVerticesData( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3, QgsVector vect1, QgsVector vect2, QgsVector vect3, const QgsPointXY &pt )
     315                 :            : {
     316                 :            :   double lam1, lam2, lam3;
     317                 :          0 :   if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
     318                 :          0 :     return QgsVector( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() );
     319                 :            : 
     320                 :          0 :   return vect3 * lam1 + vect2 * lam2 + vect1 * lam3;
     321                 :          0 : }
     322                 :            : 
     323                 :          0 : double QgsMeshLayerUtils::interpolateFromFacesData( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3,
     324                 :            :     double val, const QgsPointXY &pt )
     325                 :            : {
     326                 :            :   double lam1, lam2, lam3;
     327                 :          0 :   if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
     328                 :          0 :     return std::numeric_limits<double>::quiet_NaN();
     329                 :            : 
     330                 :          0 :   return val;
     331                 :          0 : }
     332                 :            : 
     333                 :          0 : QgsVector QgsMeshLayerUtils::interpolateVectorFromFacesData( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3,
     334                 :            :     QgsVector vect, const QgsPointXY &pt )
     335                 :            : {
     336                 :            :   double lam1, lam2, lam3;
     337                 :          0 :   if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
     338                 :          0 :     return QgsVector( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() );
     339                 :            : 
     340                 :          0 :   return vect;
     341                 :          0 : }
     342                 :            : 
     343                 :            : 
     344                 :          0 : QVector<double> QgsMeshLayerUtils::interpolateFromFacesData(
     345                 :            :   QVector<double> valuesOnFaces,
     346                 :            :   const QgsMesh *nativeMesh,
     347                 :            :   const QgsTriangularMesh *triangularMesh,
     348                 :            :   QgsMeshDataBlock *active,
     349                 :            :   QgsMeshRendererScalarSettings::DataResamplingMethod method )
     350                 :            : {
     351                 :          0 :   assert( nativeMesh );
     352                 :            :   Q_UNUSED( method );
     353                 :            :   Q_UNUSED( triangularMesh );
     354                 :            : 
     355                 :            :   // assuming that native vertex count = triangular vertex count
     356                 :          0 :   assert( nativeMesh->vertices.size() == triangularMesh->vertices().size() );
     357                 :            : 
     358                 :          0 :   return interpolateFromFacesData( valuesOnFaces, *nativeMesh, active, method );
     359                 :            : }
     360                 :            : 
     361                 :          0 : QVector<double> QgsMeshLayerUtils::interpolateFromFacesData( const QVector<double> &valuesOnFaces,
     362                 :            :     const QgsMesh &nativeMesh,
     363                 :            :     QgsMeshDataBlock *active,
     364                 :            :     QgsMeshRendererScalarSettings::DataResamplingMethod method )
     365                 :            : {
     366                 :            : 
     367                 :          0 :   QgsMeshDataBlock activeFace;
     368                 :          0 :   if ( active )
     369                 :          0 :     activeFace = *active;
     370                 :            :   else
     371                 :            :   {
     372                 :          0 :     activeFace = QgsMeshDataBlock( QgsMeshDataBlock::ActiveFlagInteger, nativeMesh.faceCount() );
     373                 :          0 :     activeFace.setValid( true );
     374                 :            :   }
     375                 :            : 
     376                 :          0 :   return interpolateFromFacesData( valuesOnFaces, nativeMesh, activeFace, method );
     377                 :            : 
     378                 :          0 : }
     379                 :            : 
     380                 :          0 : QVector<double> QgsMeshLayerUtils::interpolateFromFacesData( const QVector<double> &valuesOnFaces, const QgsMesh &nativeMesh, const QgsMeshDataBlock &active, QgsMeshRendererScalarSettings::DataResamplingMethod method )
     381                 :            : {
     382                 :          0 :   int vertexCount = nativeMesh.vertexCount();
     383                 :            :   Q_UNUSED( method );
     384                 :          0 :   assert( method == QgsMeshRendererScalarSettings::NeighbourAverage );
     385                 :            : 
     386                 :          0 :   QVector<double> res( vertexCount, 0.0 );
     387                 :            :   // for face datasets do simple average of the valid values of all faces that contains this vertex
     388                 :          0 :   QVector<int> count( vertexCount, 0 );
     389                 :            : 
     390                 :          0 :   for ( int i = 0; i < nativeMesh.faceCount(); ++i )
     391                 :            :   {
     392                 :          0 :     if ( active.active( i ) )
     393                 :            :     {
     394                 :          0 :       double val = valuesOnFaces[ i ];
     395                 :          0 :       if ( !std::isnan( val ) )
     396                 :            :       {
     397                 :            :         // assign for all vertices
     398                 :          0 :         const QgsMeshFace &face = nativeMesh.faces.at( i );
     399                 :          0 :         for ( int j = 0; j < face.size(); ++j )
     400                 :            :         {
     401                 :          0 :           int vertexIndex = face[j];
     402                 :          0 :           res[vertexIndex] += val;
     403                 :          0 :           count[vertexIndex] += 1;
     404                 :          0 :         }
     405                 :          0 :       }
     406                 :          0 :     }
     407                 :          0 :   }
     408                 :            : 
     409                 :          0 :   for ( int i = 0; i < vertexCount; ++i )
     410                 :            :   {
     411                 :          0 :     if ( count.at( i ) > 0 )
     412                 :            :     {
     413                 :          0 :       res[i] = res[i] / double( count.at( i ) );
     414                 :          0 :     }
     415                 :            :     else
     416                 :            :     {
     417                 :          0 :       res[i] = std::numeric_limits<double>::quiet_NaN();
     418                 :            :     }
     419                 :          0 :   }
     420                 :            : 
     421                 :          0 :   return res;
     422                 :          0 : }
     423                 :            : 
     424                 :          0 : QVector<double> QgsMeshLayerUtils::resampleFromVerticesToFaces(
     425                 :            :   const QVector<double> valuesOnVertices,
     426                 :            :   const QgsMesh *nativeMesh,
     427                 :            :   const QgsTriangularMesh *triangularMesh,
     428                 :            :   const QgsMeshDataBlock *active,
     429                 :            :   QgsMeshRendererScalarSettings::DataResamplingMethod method )
     430                 :            : {
     431                 :          0 :   assert( nativeMesh );
     432                 :            :   Q_UNUSED( method );
     433                 :          0 :   assert( method == QgsMeshRendererScalarSettings::NeighbourAverage );
     434                 :            : 
     435                 :            :   // assuming that native vertex count = triangular vertex count
     436                 :            :   Q_UNUSED( triangularMesh );
     437                 :          0 :   assert( nativeMesh->vertices.size() == triangularMesh->vertices().size() );
     438                 :            : 
     439                 :          0 :   QVector<double> ret( nativeMesh->faceCount(), std::numeric_limits<double>::quiet_NaN() );
     440                 :            : 
     441                 :          0 :   for ( int i = 0; i < nativeMesh->faces.size(); ++i )
     442                 :            :   {
     443                 :          0 :     const QgsMeshFace face = nativeMesh->face( i );
     444                 :          0 :     if ( active->active( i ) && face.count() > 2 )
     445                 :            :     {
     446                 :          0 :       double value = 0;
     447                 :          0 :       for ( int j = 0; j < face.count(); ++j )
     448                 :            :       {
     449                 :          0 :         value += valuesOnVertices.at( face.at( j ) );
     450                 :          0 :       }
     451                 :          0 :       ret[i] = value / face.count();
     452                 :          0 :     }
     453                 :          0 :   }
     454                 :            : 
     455                 :          0 :   return ret;
     456                 :          0 : }
     457                 :            : 
     458                 :          0 : QVector<double> QgsMeshLayerUtils::calculateMagnitudeOnVertices( const QgsMeshLayer *meshLayer,
     459                 :            :     const QgsMeshDatasetIndex index,
     460                 :            :     QgsMeshDataBlock *activeFaceFlagValues,
     461                 :            :     const QgsMeshRendererScalarSettings::DataResamplingMethod method )
     462                 :            : {
     463                 :          0 :   QVector<double> ret;
     464                 :            : 
     465                 :          0 :   if ( !meshLayer && !index.isValid() )
     466                 :          0 :     return ret;
     467                 :            : 
     468                 :          0 :   const QgsTriangularMesh *triangularMesh = meshLayer->triangularMesh();
     469                 :          0 :   const QgsMesh *nativeMesh = meshLayer->nativeMesh();
     470                 :          0 :   if ( !triangularMesh || !nativeMesh )
     471                 :          0 :     return ret;
     472                 :            : 
     473                 :          0 :   const QgsMeshDatasetGroupMetadata metadata = meshLayer->datasetGroupMetadata( index );
     474                 :          0 :   bool scalarDataOnVertices = metadata.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices;
     475                 :            : 
     476                 :            :   // populate scalar values
     477                 :          0 :   int datacount = scalarDataOnVertices ? nativeMesh->vertices.count() : nativeMesh->faces.count();
     478                 :          0 :   QgsMeshDataBlock vals = QgsMeshLayerUtils::datasetValues(
     479                 :          0 :                             meshLayer,
     480                 :          0 :                             index,
     481                 :            :                             0,
     482                 :          0 :                             datacount );
     483                 :            : 
     484                 :          0 :   QgsMeshDataBlock activeFace;
     485                 :          0 :   if ( !activeFaceFlagValues )
     486                 :            :   {
     487                 :          0 :     activeFace = QgsMeshDataBlock( QgsMeshDataBlock::ActiveFlagInteger, 0 );
     488                 :          0 :     activeFace.setValid( true );
     489                 :          0 :   }
     490                 :            :   else
     491                 :          0 :     activeFace = *activeFaceFlagValues;
     492                 :            : 
     493                 :          0 :   return calculateMagnitudeOnVertices( *nativeMesh, metadata, vals, activeFace, method );
     494                 :          0 : }
     495                 :            : 
     496                 :          0 : QVector<double> QgsMeshLayerUtils::calculateMagnitudeOnVertices( const QgsMesh &nativeMesh,
     497                 :            :     const QgsMeshDatasetGroupMetadata &groupMetadata,
     498                 :            :     const QgsMeshDataBlock &datasetValues,
     499                 :            :     const QgsMeshDataBlock &activeFaceFlagValues,
     500                 :            :     const QgsMeshRendererScalarSettings::DataResamplingMethod method )
     501                 :            : {
     502                 :          0 :   QVector<double> ret;
     503                 :          0 :   bool scalarDataOnVertices = groupMetadata.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices;
     504                 :            : 
     505                 :          0 :   if ( datasetValues.isValid() )
     506                 :            :   {
     507                 :          0 :     ret = QgsMeshLayerUtils::calculateMagnitudes( datasetValues );
     508                 :            : 
     509                 :          0 :     if ( !scalarDataOnVertices )
     510                 :            :     {
     511                 :            :       //Need to interpolate data on vertices
     512                 :          0 :       ret = QgsMeshLayerUtils::interpolateFromFacesData(
     513                 :            :               ret,
     514                 :          0 :               nativeMesh,
     515                 :          0 :               activeFaceFlagValues,
     516                 :          0 :               method );
     517                 :          0 :     }
     518                 :          0 :   }
     519                 :          0 :   return ret;
     520                 :          0 : }
     521                 :            : 
     522                 :          0 : QgsRectangle QgsMeshLayerUtils::triangleBoundingBox( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3 )
     523                 :            : {
     524                 :            :   // p1
     525                 :          0 :   double xMin = p1.x();
     526                 :          0 :   double xMax = p1.x();
     527                 :          0 :   double yMin = p1.y();
     528                 :          0 :   double yMax = p1.y();
     529                 :            : 
     530                 :            :   //p2
     531                 :          0 :   xMin = ( ( xMin < p2.x() ) ? xMin : p2.x() );
     532                 :          0 :   xMax = ( ( xMax > p2.x() ) ? xMax : p2.x() );
     533                 :          0 :   yMin = ( ( yMin < p2.y() ) ? yMin : p2.y() );
     534                 :          0 :   yMax = ( ( yMax > p2.y() ) ? yMax : p2.y() );
     535                 :            : 
     536                 :            :   // p3
     537                 :          0 :   xMin = ( ( xMin < p3.x() ) ? xMin : p3.x() );
     538                 :          0 :   xMax = ( ( xMax > p3.x() ) ? xMax : p3.x() );
     539                 :          0 :   yMin = ( ( yMin < p3.y() ) ? yMin : p3.y() );
     540                 :          0 :   yMax = ( ( yMax > p3.y() ) ? yMax : p3.y() );
     541                 :            : 
     542                 :          0 :   QgsRectangle bbox( xMin,  yMin,  xMax,  yMax );
     543                 :          0 :   return bbox;
     544                 :            : }
     545                 :            : 
     546                 :          0 : QString QgsMeshLayerUtils::formatTime( double hours, const QDateTime &referenceTime, const QgsMeshTimeSettings &settings )
     547                 :            : {
     548                 :          0 :   QString ret;
     549                 :            : 
     550                 :          0 :   if ( referenceTime.isValid() )
     551                 :            :   {
     552                 :          0 :     QString format( settings.absoluteTimeFormat() );
     553                 :          0 :     QDateTime dateTime( referenceTime );
     554                 :          0 :     qint64 seconds = static_cast<qint64>( hours * 3600.0 );
     555                 :          0 :     dateTime = dateTime.addSecs( seconds );
     556                 :          0 :     ret = dateTime.toString( format );
     557                 :          0 :     if ( ret.isEmpty() ) // error
     558                 :          0 :       ret = dateTime.toString();
     559                 :          0 :   }
     560                 :            :   else
     561                 :            :   {
     562                 :          0 :     QString format( settings.relativeTimeFormat() );
     563                 :          0 :     format = format.trimmed();
     564                 :          0 :     int totalHours = static_cast<int>( hours );
     565                 :            : 
     566                 :          0 :     if ( format == QLatin1String( "hh:mm:ss.zzz" ) )
     567                 :            :     {
     568                 :          0 :       int ms = static_cast<int>( hours * 3600.0 * 1000 );
     569                 :          0 :       int seconds = ms / 1000;
     570                 :          0 :       int z = ms % 1000;
     571                 :          0 :       int m = seconds / 60;
     572                 :          0 :       int s = seconds % 60;
     573                 :          0 :       int h = m / 60;
     574                 :          0 :       m = m % 60;
     575                 :          0 :       ret = QStringLiteral( "%1:%2:%3.%4" ).
     576                 :          0 :             arg( h, 2, 10, QLatin1Char( '0' ) ).
     577                 :          0 :             arg( m, 2, 10, QLatin1Char( '0' ) ).
     578                 :          0 :             arg( s, 2, 10, QLatin1Char( '0' ) ).
     579                 :          0 :             arg( z, 3, 10, QLatin1Char( '0' ) );
     580                 :          0 :     }
     581                 :          0 :     else if ( format == QLatin1String( "hh:mm:ss" ) )
     582                 :            :     {
     583                 :          0 :       int seconds = static_cast<int>( hours * 3600.0 );
     584                 :          0 :       int m = seconds / 60;
     585                 :          0 :       int s = seconds % 60;
     586                 :          0 :       int h = m / 60;
     587                 :          0 :       m = m % 60;
     588                 :          0 :       ret = QStringLiteral( "%1:%2:%3" ).
     589                 :          0 :             arg( h, 2, 10, QLatin1Char( '0' ) ).
     590                 :          0 :             arg( m, 2, 10, QLatin1Char( '0' ) ).
     591                 :          0 :             arg( s, 2, 10, QLatin1Char( '0' ) );
     592                 :            : 
     593                 :          0 :     }
     594                 :          0 :     else if ( format == QLatin1String( "d hh:mm:ss" ) )
     595                 :            :     {
     596                 :          0 :       int seconds = static_cast<int>( hours * 3600.0 );
     597                 :          0 :       int m = seconds / 60;
     598                 :          0 :       int s = seconds % 60;
     599                 :          0 :       int h = m / 60;
     600                 :          0 :       m = m % 60;
     601                 :          0 :       int d = totalHours / 24;
     602                 :          0 :       h = totalHours % 24;
     603                 :          0 :       ret = QStringLiteral( "%1 d %2:%3:%4" ).
     604                 :          0 :             arg( d ).
     605                 :          0 :             arg( h, 2, 10, QLatin1Char( '0' ) ).
     606                 :          0 :             arg( m, 2, 10, QLatin1Char( '0' ) ).
     607                 :          0 :             arg( s, 2, 10, QLatin1Char( '0' ) );
     608                 :          0 :     }
     609                 :          0 :     else if ( format == QLatin1String( "d hh" ) )
     610                 :            :     {
     611                 :          0 :       int d = totalHours / 24;
     612                 :          0 :       int h = totalHours % 24;
     613                 :          0 :       ret = QStringLiteral( "%1 d %2" ).
     614                 :          0 :             arg( d ).
     615                 :          0 :             arg( h );
     616                 :          0 :     }
     617                 :          0 :     else if ( format == QLatin1String( "d" ) )
     618                 :            :     {
     619                 :          0 :       int d = totalHours / 24;
     620                 :          0 :       ret = QString::number( d );
     621                 :          0 :     }
     622                 :          0 :     else if ( format == QLatin1String( "ss" ) )
     623                 :            :     {
     624                 :          0 :       int seconds = static_cast<int>( hours * 3600.0 );
     625                 :          0 :       ret = QString::number( seconds );
     626                 :          0 :     }
     627                 :            :     else     // "hh"
     628                 :            :     {
     629                 :          0 :       ret = QString::number( hours );
     630                 :            :     }
     631                 :          0 :   }
     632                 :          0 :   return ret;
     633                 :          0 : }
     634                 :            : 
     635                 :          0 : QVector<QVector3D> QgsMeshLayerUtils::calculateNormals( const QgsTriangularMesh &triangularMesh, const QVector<double> &verticalMagnitude, bool isRelative )
     636                 :            : {
     637                 :          0 :   QVector<QVector3D> normals( triangularMesh.vertices().count() );
     638                 :          0 :   for ( const auto &face : triangularMesh.triangles() )
     639                 :            :   {
     640                 :          0 :     for ( int i = 0; i < 3; i++ )
     641                 :            :     {
     642                 :          0 :       int index( face.at( i ) );
     643                 :          0 :       int index1( face.at( ( i + 1 ) % 3 ) );
     644                 :          0 :       int index2( face.at( ( i + 2 ) % 3 ) );
     645                 :            : 
     646                 :          0 :       const QgsMeshVertex &vert( triangularMesh.vertices().at( index ) );
     647                 :          0 :       const QgsMeshVertex &otherVert1( triangularMesh.vertices().at( index1 ) );
     648                 :          0 :       const QgsMeshVertex &otherVert2( triangularMesh.vertices().at( index2 ) );
     649                 :            : 
     650                 :          0 :       float adjustRelative = 0;
     651                 :          0 :       float adjustRelative1 = 0;
     652                 :          0 :       float adjustRelative2 = 0;
     653                 :            : 
     654                 :          0 :       if ( isRelative )
     655                 :            :       {
     656                 :          0 :         adjustRelative = vert.z();
     657                 :          0 :         adjustRelative1 = otherVert1.z();
     658                 :          0 :         adjustRelative2 = otherVert2.z();
     659                 :          0 :       }
     660                 :            : 
     661                 :          0 :       QVector3D v1( float( otherVert1.x() - vert.x() ),
     662                 :          0 :                     float( otherVert1.y() - vert.y() ),
     663                 :          0 :                     float( verticalMagnitude[index1] - verticalMagnitude[index] + adjustRelative1 - adjustRelative ) );
     664                 :          0 :       QVector3D v2( float( otherVert2.x() - vert.x() ),
     665                 :          0 :                     float( otherVert2.y() - vert.y() ),
     666                 :          0 :                     float( verticalMagnitude[index2] - verticalMagnitude[index] + adjustRelative2 - adjustRelative ) );
     667                 :            : 
     668                 :          0 :       normals[index] += QVector3D::crossProduct( v1, v2 );
     669                 :          0 :     }
     670                 :            :   }
     671                 :            : 
     672                 :          0 :   return normals;
     673                 :          0 : }
     674                 :            : 
     675                 :            : ///@endcond

Generated by: LCOV version 1.14