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

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :                          qgsalgorithmexportmesh.cpp
       3                 :            :                          ---------------------------
       4                 :            :     begin                : October 2020
       5                 :            :     copyright            : (C) 2020 by Vincent Cloarec
       6                 :            :     email                : vcloarec 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 "qgsalgorithmexportmesh.h"
      19                 :            : #include "qgsprocessingparametermeshdataset.h"
      20                 :            : #include "qgsmeshcontours.h"
      21                 :            : #include "qgsmeshdataset.h"
      22                 :            : #include "qgsmeshlayer.h"
      23                 :            : #include "qgsmeshlayerutils.h"
      24                 :            : #include "qgsmeshlayertemporalproperties.h"
      25                 :            : #include "qgsmeshlayerinterpolator.h"
      26                 :            : #include "qgspolygon.h"
      27                 :            : #include "qgsrasterfilewriter.h"
      28                 :            : #include "qgslinestring.h"
      29                 :            : 
      30                 :            : #include <QTextStream>
      31                 :            : 
      32                 :            : ///@cond PRIVATE
      33                 :            : 
      34                 :            : 
      35                 :          0 : static QgsFields createFields( const QList<QgsMeshDatasetGroupMetadata> &groupMetadataList, int vectorOption )
      36                 :            : {
      37                 :          0 :   QgsFields fields;
      38                 :          0 :   for ( const QgsMeshDatasetGroupMetadata &meta : groupMetadataList )
      39                 :            :   {
      40                 :          0 :     if ( meta.isVector() )
      41                 :            :     {
      42                 :          0 :       if ( vectorOption == 0 || vectorOption == 2 )
      43                 :            :       {
      44                 :          0 :         fields.append( QStringLiteral( "%1_x" ).arg( meta.name() ) );
      45                 :          0 :         fields.append( QStringLiteral( "%1_y" ).arg( meta.name() ) );
      46                 :          0 :       }
      47                 :            : 
      48                 :          0 :       if ( vectorOption == 1 || vectorOption == 2 )
      49                 :            :       {
      50                 :          0 :         fields.append( QStringLiteral( "%1_mag" ).arg( meta.name() ) );
      51                 :          0 :         fields.append( QStringLiteral( "%1_dir" ).arg( meta.name() ) );
      52                 :          0 :       }
      53                 :          0 :     }
      54                 :            :     else
      55                 :          0 :       fields.append( meta.name() );
      56                 :            :   }
      57                 :          0 :   return fields;
      58                 :          0 : }
      59                 :            : 
      60                 :          0 : static QVector<double> vectorValue( const QgsMeshDatasetValue &value, int exportOption )
      61                 :            : {
      62                 :          0 :   QVector<double> ret( exportOption == 2 ? 4 : 2 );
      63                 :            : 
      64                 :          0 :   if ( exportOption == 0 || exportOption == 2 )
      65                 :            :   {
      66                 :          0 :     ret[0] = value.x();
      67                 :          0 :     ret[1] = value.y();
      68                 :          0 :   }
      69                 :          0 :   if ( exportOption == 1 || exportOption == 2 )
      70                 :            :   {
      71                 :          0 :     double x = value.x();
      72                 :          0 :     double y = value.y();
      73                 :          0 :     double magnitude = sqrt( x * x + y * y );
      74                 :          0 :     double direction = ( asin( x / magnitude ) ) / M_PI * 180;
      75                 :          0 :     if ( y < 0 )
      76                 :          0 :       direction = 180 - direction;
      77                 :            : 
      78                 :          0 :     if ( exportOption == 1 )
      79                 :            :     {
      80                 :          0 :       ret[0] = magnitude;
      81                 :          0 :       ret[1] = direction;
      82                 :          0 :     }
      83                 :          0 :     if ( exportOption == 2 )
      84                 :            :     {
      85                 :          0 :       ret[2] = magnitude;
      86                 :          0 :       ret[3] = direction;
      87                 :          0 :     }
      88                 :          0 :   }
      89                 :          0 :   return ret;
      90                 :          0 : }
      91                 :            : 
      92                 :          0 : static void addAttributes( const QgsMeshDatasetValue &value, QgsAttributes &attributes, bool isVector, int vectorOption )
      93                 :            : {
      94                 :          0 :   if ( isVector )
      95                 :            :   {
      96                 :          0 :     QVector<double> vectorValues = vectorValue( value, vectorOption );
      97                 :          0 :     for ( double v : vectorValues )
      98                 :            :     {
      99                 :          0 :       if ( v == std::numeric_limits<double>::quiet_NaN() )
     100                 :          0 :         attributes.append( QVariant() );
     101                 :            :       else
     102                 :          0 :         attributes.append( v );
     103                 :            :     }
     104                 :          0 :   }
     105                 :            :   else
     106                 :            :   {
     107                 :          0 :     if ( value.scalar() == std::numeric_limits<double>::quiet_NaN() )
     108                 :          0 :       attributes.append( QVariant() );
     109                 :            :     else
     110                 :          0 :       attributes.append( value.scalar() );
     111                 :            :   }
     112                 :          0 : }
     113                 :            : 
     114                 :          0 : static QgsMeshDatasetValue extractDatasetValue(
     115                 :            :   const QgsPointXY &point,
     116                 :            :   int nativeFaceIndex,
     117                 :            :   int triangularFaceIndex,
     118                 :            :   const QgsTriangularMesh &triangularMesh,
     119                 :            :   const QgsMeshDataBlock &activeFaces,
     120                 :            :   const QgsMeshDataBlock &datasetValues,
     121                 :            :   const QgsMeshDatasetGroupMetadata &metadata )
     122                 :            : {
     123                 :          0 :   bool faceActive = activeFaces.active( nativeFaceIndex );
     124                 :          0 :   QgsMeshDatasetValue value;
     125                 :          0 :   if ( faceActive )
     126                 :            :   {
     127                 :          0 :     switch ( metadata.dataType() )
     128                 :            :     {
     129                 :            :       case QgsMeshDatasetGroupMetadata::DataOnEdges:
     130                 :            :         //not supported
     131                 :          0 :         break;
     132                 :            :       case QgsMeshDatasetGroupMetadata::DataOnVolumes:
     133                 :            :       case QgsMeshDatasetGroupMetadata::DataOnFaces:
     134                 :            :       {
     135                 :          0 :         value = datasetValues.value( nativeFaceIndex );
     136                 :            :       }
     137                 :          0 :       break;
     138                 :            : 
     139                 :            :       case QgsMeshDatasetGroupMetadata::DataOnVertices:
     140                 :            :       {
     141                 :          0 :         const QgsMeshFace &face = triangularMesh.triangles()[triangularFaceIndex];
     142                 :          0 :         const int v1 = face[0], v2 = face[1], v3 = face[2];
     143                 :          0 :         const QgsPoint p1 = triangularMesh.vertices()[v1], p2 = triangularMesh.vertices()[v2], p3 = triangularMesh.vertices()[v3];
     144                 :          0 :         const QgsMeshDatasetValue val1 = datasetValues.value( v1 );
     145                 :          0 :         const QgsMeshDatasetValue val2 = datasetValues.value( v2 );
     146                 :          0 :         const QgsMeshDatasetValue val3 = datasetValues.value( v3 );
     147                 :          0 :         const double x = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.x(), val2.x(), val3.x(), point );
     148                 :          0 :         double y = std::numeric_limits<double>::quiet_NaN();
     149                 :          0 :         bool isVector = metadata.isVector();
     150                 :          0 :         if ( isVector )
     151                 :          0 :           y = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.y(), val2.y(), val3.y(), point );
     152                 :            : 
     153                 :          0 :         value = QgsMeshDatasetValue( x, y );
     154                 :          0 :       }
     155                 :          0 :       break;
     156                 :            :     }
     157                 :          0 :   }
     158                 :            : 
     159                 :          0 :   return value;
     160                 :          0 : }
     161                 :            : 
     162                 :          0 : QString QgsExportMeshOnElement::group() const
     163                 :            : {
     164                 :          0 :   return QObject::tr( "Mesh" );
     165                 :            : }
     166                 :            : 
     167                 :          0 : QString QgsExportMeshOnElement::groupId() const
     168                 :            : {
     169                 :          0 :   return QStringLiteral( "mesh" );
     170                 :            : }
     171                 :            : 
     172                 :          0 : QString QgsExportMeshVerticesAlgorithm::shortHelpString() const
     173                 :            : {
     174                 :          0 :   return QObject::tr( "Exports mesh layer's vertices to a point vector layer, with the dataset values on vertices as attribute values" );
     175                 :            : }
     176                 :            : 
     177                 :          0 : QString QgsExportMeshVerticesAlgorithm::name() const
     178                 :            : {
     179                 :          0 :   return QStringLiteral( "exportmeshvertices" );
     180                 :            : }
     181                 :            : 
     182                 :          0 : QString QgsExportMeshVerticesAlgorithm::displayName() const
     183                 :            : {
     184                 :          0 :   return QObject::tr( "Export mesh vertices" );
     185                 :            : }
     186                 :            : 
     187                 :          0 : QgsProcessingAlgorithm *QgsExportMeshVerticesAlgorithm::createInstance() const
     188                 :            : {
     189                 :          0 :   return new QgsExportMeshVerticesAlgorithm();
     190                 :          0 : }
     191                 :            : 
     192                 :          0 : QgsGeometry QgsExportMeshVerticesAlgorithm::meshElement( int index ) const
     193                 :            : {
     194                 :          0 :   return QgsGeometry( new QgsPoint( mNativeMesh.vertex( index ) ) );
     195                 :          0 : }
     196                 :            : 
     197                 :          0 : void QgsExportMeshOnElement::initAlgorithm( const QVariantMap &configuration )
     198                 :            : {
     199                 :          0 :   Q_UNUSED( configuration );
     200                 :            : 
     201                 :          0 :   addParameter( new QgsProcessingParameterMeshLayer( QStringLiteral( "INPUT" ), QObject::tr( "Input mesh layer" ) ) );
     202                 :            : 
     203                 :            : 
     204                 :          0 :   addParameter( new QgsProcessingParameterMeshDatasetGroups(
     205                 :          0 :                   QStringLiteral( "DATASET_GROUPS" ),
     206                 :          0 :                   QObject::tr( "Dataset groups" ),
     207                 :          0 :                   QStringLiteral( "INPUT" ),
     208                 :          0 :                   supportedDataType(), true ) );
     209                 :            : 
     210                 :          0 :   addParameter( new QgsProcessingParameterMeshDatasetTime(
     211                 :          0 :                   QStringLiteral( "DATASET_TIME" ),
     212                 :          0 :                   QObject::tr( "Dataset time" ),
     213                 :          0 :                   QStringLiteral( "INPUT" ),
     214                 :          0 :                   QStringLiteral( "DATASET_GROUPS" ) ) );
     215                 :            : 
     216                 :          0 :   addParameter( new QgsProcessingParameterCrs( QStringLiteral( "CRS_OUTPUT" ), QObject::tr( "Output coordinate system" ), QVariant(), true ) );
     217                 :            : 
     218                 :          0 :   QStringList exportVectorOptions;
     219                 :          0 :   exportVectorOptions << QObject::tr( "Cartesian (x,y)" )
     220                 :          0 :                       << QObject::tr( "Polar (magnitude,degree)" )
     221                 :          0 :                       << QObject::tr( "Cartesian and Polar" );
     222                 :          0 :   addParameter( new QgsProcessingParameterEnum( QStringLiteral( "VECTOR_OPTION" ), QObject::tr( "Export vector option" ), exportVectorOptions, false, 0 ) );
     223                 :          0 :   addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Output vector layer" ), sinkType() ) );
     224                 :          0 : }
     225                 :            : 
     226                 :          0 : static QgsInterval datasetRelativetime( const QVariant parameterTimeVariant, QgsMeshLayer *meshLayer, const QgsProcessingContext &context )
     227                 :            : {
     228                 :          0 :   QgsInterval relativeTime( 0 );
     229                 :          0 :   QDateTime layerReferenceTime = static_cast<QgsMeshLayerTemporalProperties *>( meshLayer->temporalProperties() )->referenceTime();
     230                 :          0 :   QString timeType = QgsProcessingParameterMeshDatasetTime::valueAsTimeType( parameterTimeVariant );
     231                 :            : 
     232                 :          0 :   if ( timeType == QLatin1String( "dataset-time-step" ) )
     233                 :            :   {
     234                 :          0 :     QgsMeshDatasetIndex datasetIndex = QgsProcessingParameterMeshDatasetTime::timeValueAsDatasetIndex( parameterTimeVariant );
     235                 :          0 :     relativeTime = meshLayer->datasetRelativeTime( datasetIndex );
     236                 :          0 :   }
     237                 :          0 :   else if ( timeType == QLatin1String( "defined-date-time" ) )
     238                 :            :   {
     239                 :          0 :     QDateTime dateTime = QgsProcessingParameterMeshDatasetTime::timeValueAsDefinedDateTime( parameterTimeVariant );
     240                 :          0 :     if ( dateTime.isValid() )
     241                 :          0 :       relativeTime = QgsInterval( layerReferenceTime.secsTo( dateTime ) );
     242                 :          0 :   }
     243                 :          0 :   else if ( timeType == QLatin1String( "current-context-time" ) )
     244                 :            :   {
     245                 :          0 :     QDateTime dateTime = context.currentTimeRange().begin();
     246                 :          0 :     if ( dateTime.isValid() )
     247                 :          0 :       relativeTime = QgsInterval( layerReferenceTime.secsTo( dateTime ) );
     248                 :          0 :   }
     249                 :            : 
     250                 :            :   return relativeTime;
     251                 :          0 : }
     252                 :            : 
     253                 :            : 
     254                 :          0 : bool QgsExportMeshOnElement::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
     255                 :            : {
     256                 :          0 :   QgsMeshLayer *meshLayer = parameterAsMeshLayer( parameters, QStringLiteral( "INPUT" ), context );
     257                 :            : 
     258                 :          0 :   if ( !meshLayer || !meshLayer->isValid() )
     259                 :          0 :     return false;
     260                 :            : 
     261                 :          0 :   QgsCoordinateReferenceSystem outputCrs = parameterAsCrs( parameters, QStringLiteral( "CRS_OUTPUT" ), context );
     262                 :          0 :   if ( !outputCrs.isValid() )
     263                 :          0 :     outputCrs = meshLayer->crs();
     264                 :          0 :   mTransform = QgsCoordinateTransform( meshLayer->crs(), outputCrs, context.transformContext() );
     265                 :          0 :   if ( !meshLayer->nativeMesh() )
     266                 :          0 :     meshLayer->updateTriangularMesh( mTransform ); //necessary to load the native mesh
     267                 :            : 
     268                 :          0 :   mNativeMesh = *meshLayer->nativeMesh();
     269                 :            : 
     270                 :            :   QList<int> datasetGroups =
     271                 :          0 :     QgsProcessingParameterMeshDatasetGroups::valueAsDatasetGroup( parameters.value( QStringLiteral( "DATASET_GROUPS" ) ) );
     272                 :            : 
     273                 :          0 :   if ( feedback )
     274                 :            :   {
     275                 :          0 :     feedback->setProgressText( QObject::tr( "Preparing data" ) );
     276                 :          0 :   }
     277                 :            : 
     278                 :          0 :   QDateTime layerReferenceTime = static_cast<QgsMeshLayerTemporalProperties *>( meshLayer->temporalProperties() )->referenceTime();
     279                 :            : 
     280                 :            :   // Extract the date time used to export dataset values under a relative time
     281                 :          0 :   QVariant parameterTimeVariant = parameters.value( QStringLiteral( "DATASET_TIME" ) );
     282                 :          0 :   QgsInterval relativeTime = datasetRelativetime( parameterTimeVariant, meshLayer, context );
     283                 :            : 
     284                 :          0 :   switch ( meshElementType() )
     285                 :            :   {
     286                 :            :     case QgsMesh::Face:
     287                 :          0 :       mElementCount = mNativeMesh.faceCount();
     288                 :          0 :       break;
     289                 :            :     case QgsMesh::Vertex:
     290                 :          0 :       mElementCount = mNativeMesh.vertexCount();
     291                 :          0 :       break;
     292                 :            :     case QgsMesh::Edge:
     293                 :          0 :       mElementCount = mNativeMesh.edgeCount();
     294                 :          0 :       break;
     295                 :            :   }
     296                 :            : 
     297                 :          0 :   for ( int i = 0; i < datasetGroups.count(); ++i )
     298                 :            :   {
     299                 :          0 :     int  groupIndex = datasetGroups.at( i );
     300                 :          0 :     QgsMeshDatasetIndex datasetIndex = meshLayer->datasetIndexAtRelativeTime( relativeTime, groupIndex );
     301                 :            : 
     302                 :          0 :     DataGroup dataGroup;
     303                 :          0 :     dataGroup.metadata = meshLayer->datasetGroupMetadata( datasetIndex );
     304                 :          0 :     if ( supportedDataType().contains( dataGroup.metadata.dataType() ) )
     305                 :            :     {
     306                 :          0 :       dataGroup.datasetValues = meshLayer->datasetValues( datasetIndex, 0, mElementCount );
     307                 :          0 :       mDataPerGroup.append( dataGroup );
     308                 :          0 :     }
     309                 :          0 :     if ( feedback )
     310                 :          0 :       feedback->setProgress( 100 * i / datasetGroups.count() );
     311                 :          0 :   }
     312                 :            : 
     313                 :          0 :   mExportVectorOption = parameterAsInt( parameters, QStringLiteral( "VECTOR_OPTION" ), context );
     314                 :            : 
     315                 :          0 :   return true;
     316                 :          0 : }
     317                 :            : 
     318                 :          0 : QVariantMap QgsExportMeshOnElement::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
     319                 :            : {
     320                 :          0 :   if ( feedback )
     321                 :            :   {
     322                 :          0 :     if ( feedback->isCanceled() )
     323                 :          0 :       return QVariantMap();
     324                 :          0 :     feedback->setProgress( 0 );
     325                 :          0 :     feedback->setProgressText( QObject::tr( "Creating output vector layer" ) );
     326                 :          0 :   }
     327                 :            : 
     328                 :          0 :   QList<QgsMeshDatasetGroupMetadata> metaList;
     329                 :          0 :   metaList.reserve( mDataPerGroup.size() );
     330                 :          0 :   for ( const DataGroup &dataGroup : mDataPerGroup )
     331                 :          0 :     metaList.append( dataGroup.metadata );
     332                 :          0 :   QgsFields fields = createFields( metaList, mExportVectorOption );
     333                 :            : 
     334                 :          0 :   QgsCoordinateReferenceSystem outputCrs = parameterAsCrs( parameters, QStringLiteral( "CRS_OUTPUT" ), context );
     335                 :          0 :   QString identifier;
     336                 :          0 :   QgsFeatureSink *sink = parameterAsSink( parameters,
     337                 :          0 :                                           QStringLiteral( "OUTPUT" ),
     338                 :          0 :                                           context,
     339                 :            :                                           identifier,
     340                 :            :                                           fields,
     341                 :          0 :                                           sinkGeometryType(),
     342                 :            :                                           outputCrs );
     343                 :          0 :   if ( !sink )
     344                 :          0 :     return QVariantMap();
     345                 :            : 
     346                 :          0 :   if ( feedback )
     347                 :            :   {
     348                 :          0 :     if ( feedback->isCanceled() )
     349                 :          0 :       return QVariantMap();
     350                 :          0 :     feedback->setProgress( 0 );
     351                 :          0 :     feedback->setProgressText( QObject::tr( "Creating points for each vertices" ) );
     352                 :          0 :   }
     353                 :            : 
     354                 :          0 :   for ( int i = 0; i < mElementCount; ++i )
     355                 :            :   {
     356                 :          0 :     QgsAttributes attributes;
     357                 :          0 :     for ( const DataGroup &dataGroup : mDataPerGroup )
     358                 :            :     {
     359                 :          0 :       const QgsMeshDatasetValue &value = dataGroup.datasetValues.value( i );
     360                 :          0 :       addAttributes( value, attributes, dataGroup.metadata.isVector(), mExportVectorOption );
     361                 :            :     }
     362                 :            : 
     363                 :          0 :     QgsFeature feat;
     364                 :          0 :     QgsGeometry geom = meshElement( i );
     365                 :            :     try
     366                 :            :     {
     367                 :          0 :       geom.transform( mTransform );
     368                 :          0 :     }
     369                 :            :     catch ( QgsCsException & )
     370                 :            :     {
     371                 :          0 :       geom = meshElement( i );
     372                 :          0 :       feedback->reportError( QObject::tr( "Could not transform point to destination CRS" ) );
     373                 :          0 :     }
     374                 :          0 :     feat.setGeometry( geom );
     375                 :          0 :     feat.setAttributes( attributes );
     376                 :            : 
     377                 :          0 :     sink->addFeature( feat );
     378                 :            : 
     379                 :          0 :     if ( feedback )
     380                 :            :     {
     381                 :          0 :       if ( feedback->isCanceled() )
     382                 :          0 :         return QVariantMap();
     383                 :          0 :       feedback->setProgress( 100 * i / mElementCount );
     384                 :          0 :     }
     385                 :          0 :   }
     386                 :            : 
     387                 :          0 :   QVariantMap ret;
     388                 :          0 :   ret[QStringLiteral( "OUTPUT" )] = identifier;
     389                 :            : 
     390                 :          0 :   return ret;
     391                 :          0 : }
     392                 :            : 
     393                 :          0 : QString QgsExportMeshFacesAlgorithm::shortHelpString() const
     394                 :            : {
     395                 :          0 :   return QObject::tr( "Exports mesh layer's faces to a polygon vector layer, with the dataset values on faces as attribute values" );
     396                 :            : }
     397                 :            : 
     398                 :          0 : QString QgsExportMeshFacesAlgorithm::name() const
     399                 :            : {
     400                 :          0 :   return QStringLiteral( "exportmeshfaces" );
     401                 :            : }
     402                 :            : 
     403                 :          0 : QString QgsExportMeshFacesAlgorithm::displayName() const
     404                 :            : {
     405                 :          0 :   return QObject::tr( "Export mesh faces" );
     406                 :            : }
     407                 :            : 
     408                 :          0 : QgsProcessingAlgorithm *QgsExportMeshFacesAlgorithm::createInstance() const
     409                 :            : {
     410                 :          0 :   return new QgsExportMeshFacesAlgorithm();
     411                 :          0 : }
     412                 :            : 
     413                 :          0 : QgsGeometry QgsExportMeshFacesAlgorithm::meshElement( int index ) const
     414                 :            : {
     415                 :          0 :   const QgsMeshFace &face = mNativeMesh.face( index );
     416                 :          0 :   QVector<QgsPoint> vertices( face.size() );
     417                 :          0 :   for ( int i = 0; i < face.size(); ++i )
     418                 :          0 :     vertices[i] = mNativeMesh.vertex( face.at( i ) );
     419                 :          0 :   std::unique_ptr<QgsPolygon> polygon = std::make_unique<QgsPolygon>();
     420                 :          0 :   polygon->setExteriorRing( new QgsLineString( vertices ) );
     421                 :          0 :   return QgsGeometry( polygon.release() );
     422                 :          0 : }
     423                 :            : 
     424                 :          0 : QString QgsExportMeshEdgesAlgorithm::shortHelpString() const
     425                 :            : {
     426                 :          0 :   return QObject::tr( "Exports mesh layer's edges to a line vector layer, with the dataset values on edges as attribute values" );
     427                 :            : }
     428                 :            : 
     429                 :          0 : QString QgsExportMeshEdgesAlgorithm::name() const
     430                 :            : {
     431                 :          0 :   return QStringLiteral( "exportmeshedges" );
     432                 :            : }
     433                 :            : 
     434                 :          0 : QString QgsExportMeshEdgesAlgorithm::displayName() const
     435                 :            : {
     436                 :          0 :   return QObject::tr( "Export mesh edges" );
     437                 :            : }
     438                 :            : 
     439                 :          0 : QgsProcessingAlgorithm *QgsExportMeshEdgesAlgorithm::createInstance() const
     440                 :            : {
     441                 :          0 :   return new QgsExportMeshEdgesAlgorithm();
     442                 :          0 : }
     443                 :            : 
     444                 :          0 : QgsGeometry QgsExportMeshEdgesAlgorithm::meshElement( int index ) const
     445                 :            : {
     446                 :          0 :   const QgsMeshEdge &edge = mNativeMesh.edge( index );
     447                 :          0 :   QVector<QgsPoint> vertices( 2 );
     448                 :          0 :   vertices[0] = mNativeMesh.vertex( edge.first );
     449                 :          0 :   vertices[1] = mNativeMesh.vertex( edge.second );
     450                 :          0 :   return QgsGeometry( new QgsLineString( vertices ) );
     451                 :          0 : }
     452                 :            : 
     453                 :            : 
     454                 :          0 : QString QgsExportMeshOnGridAlgorithm::name() const {return QStringLiteral( "exportmeshongrid" );}
     455                 :            : 
     456                 :          0 : QString QgsExportMeshOnGridAlgorithm::displayName() const {return QObject::tr( "Export mesh on grid" );}
     457                 :            : 
     458                 :          0 : QString QgsExportMeshOnGridAlgorithm::group() const {return QObject::tr( "Mesh" );}
     459                 :            : 
     460                 :          0 : QString QgsExportMeshOnGridAlgorithm::groupId() const {return QStringLiteral( "mesh" );}
     461                 :            : 
     462                 :          0 : QString QgsExportMeshOnGridAlgorithm::shortHelpString() const
     463                 :            : {
     464                 :          0 :   return QObject::tr( "Exports mesh layer's dataset values to a gridded point vector layer, with the dataset values on this point as attribute values.\n"
     465                 :            :                       "For data on volume (3D stacked dataset values), the exported dataset values are averaged on faces using the method defined in the mesh layer properties (default is Multi level averaging method).\n"
     466                 :            :                       "1D meshes are not supported." );
     467                 :            : }
     468                 :            : 
     469                 :          0 : QgsProcessingAlgorithm *QgsExportMeshOnGridAlgorithm::createInstance() const
     470                 :            : {
     471                 :          0 :   return new QgsExportMeshOnGridAlgorithm();
     472                 :          0 : }
     473                 :            : 
     474                 :          0 : void QgsExportMeshOnGridAlgorithm::initAlgorithm( const QVariantMap &configuration )
     475                 :            : {
     476                 :          0 :   Q_UNUSED( configuration );
     477                 :            : 
     478                 :          0 :   addParameter( new QgsProcessingParameterMeshLayer( QStringLiteral( "INPUT" ), QObject::tr( "Input Mesh Layer" ) ) );
     479                 :            : 
     480                 :          0 :   addParameter( new QgsProcessingParameterMeshDatasetGroups(
     481                 :          0 :                   QStringLiteral( "DATASET_GROUPS" ),
     482                 :          0 :                   QObject::tr( "Dataset groups" ),
     483                 :          0 :                   QStringLiteral( "INPUT" ),
     484                 :          0 :                   supportedDataType() ) );
     485                 :            : 
     486                 :          0 :   addParameter( new QgsProcessingParameterMeshDatasetTime(
     487                 :          0 :                   QStringLiteral( "DATASET_TIME" ),
     488                 :          0 :                   QObject::tr( "Dataset time" ),
     489                 :          0 :                   QStringLiteral( "INPUT" ),
     490                 :          0 :                   QStringLiteral( "DATASET_GROUPS" ) ) );
     491                 :            : 
     492                 :          0 :   addParameter( new QgsProcessingParameterExtent( QStringLiteral( "EXTENT" ), QObject::tr( "Extent" ), QVariant(), true ) );
     493                 :            : 
     494                 :          0 :   addParameter( new QgsProcessingParameterDistance( QStringLiteral( "GRID_SPACING" ), QObject::tr( "Grid spacing" ), 10, QStringLiteral( "INPUT" ), false ) );
     495                 :            : 
     496                 :          0 :   addParameter( new QgsProcessingParameterCrs( QStringLiteral( "CRS_OUTPUT" ), QObject::tr( "Output coordinate system" ), QVariant(), true ) );
     497                 :            : 
     498                 :          0 :   QStringList exportVectorOptions;
     499                 :          0 :   exportVectorOptions << QObject::tr( "Cartesian (x,y)" )
     500                 :          0 :                       << QObject::tr( "Polar (magnitude,degree)" )
     501                 :          0 :                       << QObject::tr( "Cartesian and Polar" );
     502                 :          0 :   addParameter( new QgsProcessingParameterEnum( QStringLiteral( "VECTOR_OPTION" ), QObject::tr( "Export vector option" ), exportVectorOptions, false, 0 ) );
     503                 :          0 :   addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Output vector layer" ), QgsProcessing::TypeVectorPoint ) );
     504                 :          0 : }
     505                 :            : 
     506                 :          0 : static void extractDatasetValues( const QList<int> &datasetGroups,
     507                 :            :                                   QgsMeshLayer *meshLayer,
     508                 :            :                                   const QgsTriangularMesh &triangularMesh,
     509                 :            :                                   const QgsMesh &nativeMesh,
     510                 :            :                                   const QgsInterval &relativeTime,
     511                 :            :                                   const QSet<int> supportedDataType,
     512                 :            :                                   QList<DataGroup> &datasetPerGroup,
     513                 :            :                                   QgsProcessingFeedback *feedback )
     514                 :            : {
     515                 :          0 :   for ( int i = 0; i < datasetGroups.count(); ++i )
     516                 :            :   {
     517                 :          0 :     int  groupIndex = datasetGroups.at( i );
     518                 :          0 :     QgsMeshDatasetIndex datasetIndex = meshLayer->datasetIndexAtRelativeTime( relativeTime, groupIndex );
     519                 :            : 
     520                 :          0 :     DataGroup dataGroup;
     521                 :          0 :     dataGroup.metadata = meshLayer->datasetGroupMetadata( datasetIndex );
     522                 :          0 :     if ( supportedDataType.contains( dataGroup.metadata.dataType() ) )
     523                 :            :     {
     524                 :          0 :       int valueCount = dataGroup.metadata.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices ?
     525                 :          0 :                        triangularMesh.vertices().count() : nativeMesh.faceCount();
     526                 :          0 :       dataGroup.datasetValues = meshLayer->datasetValues( datasetIndex, 0, valueCount );
     527                 :          0 :       dataGroup.activeFaces = meshLayer->areFacesActive( datasetIndex, 0, nativeMesh.faceCount() );
     528                 :          0 :       if ( dataGroup.metadata.dataType() == QgsMeshDatasetGroupMetadata::DataOnVolumes )
     529                 :            :       {
     530                 :          0 :         dataGroup.dataset3dStakedValue = meshLayer->dataset3dValues( datasetIndex, 0, valueCount );
     531                 :          0 :       }
     532                 :          0 :       datasetPerGroup.append( dataGroup );
     533                 :          0 :     }
     534                 :          0 :     if ( feedback )
     535                 :          0 :       feedback->setProgress( 100 * i / datasetGroups.count() );
     536                 :          0 :   }
     537                 :          0 : }
     538                 :            : 
     539                 :          0 : bool QgsExportMeshOnGridAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
     540                 :            : {
     541                 :          0 :   QgsMeshLayer *meshLayer = parameterAsMeshLayer( parameters, QStringLiteral( "INPUT" ), context );
     542                 :            : 
     543                 :          0 :   if ( !meshLayer || !meshLayer->isValid() )
     544                 :          0 :     return false;
     545                 :            : 
     546                 :          0 :   QgsCoordinateReferenceSystem outputCrs = parameterAsCrs( parameters, QStringLiteral( "CRS_OUTPUT" ), context );
     547                 :          0 :   if ( !outputCrs.isValid() )
     548                 :          0 :     outputCrs = meshLayer->crs();
     549                 :          0 :   mTransform = QgsCoordinateTransform( meshLayer->crs(), outputCrs, context.transformContext() );
     550                 :          0 :   if ( !meshLayer->nativeMesh() )
     551                 :          0 :     meshLayer->updateTriangularMesh( mTransform ); //necessary to load the native mesh
     552                 :            : 
     553                 :          0 :   mTriangularMesh = *meshLayer->triangularMesh();
     554                 :          0 :   const QgsMesh &nativeMesh = *meshLayer->nativeMesh();
     555                 :            : 
     556                 :            :   QList<int> datasetGroups =
     557                 :          0 :     QgsProcessingParameterMeshDatasetGroups::valueAsDatasetGroup( parameters.value( QStringLiteral( "DATASET_GROUPS" ) ) );
     558                 :            : 
     559                 :          0 :   if ( feedback )
     560                 :            :   {
     561                 :          0 :     feedback->setProgressText( QObject::tr( "Preparing data" ) );
     562                 :          0 :   }
     563                 :            : 
     564                 :            :   // Extract the date time used to export dataset values under a relative time
     565                 :          0 :   QVariant parameterTimeVariant = parameters.value( QStringLiteral( "DATASET_TIME" ) );
     566                 :          0 :   QgsInterval relativeTime = datasetRelativetime( parameterTimeVariant, meshLayer, context );
     567                 :            : 
     568                 :          0 :   extractDatasetValues( datasetGroups, meshLayer, mTriangularMesh, nativeMesh, relativeTime, supportedDataType(), mDataPerGroup, feedback );
     569                 :            : 
     570                 :          0 :   mExportVectorOption = parameterAsInt( parameters, QStringLiteral( "VECTOR_OPTION" ), context );
     571                 :            : 
     572                 :          0 :   return true;
     573                 :          0 : }
     574                 :            : 
     575                 :          0 : QVariantMap QgsExportMeshOnGridAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
     576                 :            : {
     577                 :          0 :   if ( feedback )
     578                 :            :   {
     579                 :          0 :     if ( feedback->isCanceled() )
     580                 :          0 :       return QVariantMap();
     581                 :          0 :     feedback->setProgress( 0 );
     582                 :          0 :     feedback->setProgressText( QObject::tr( "Creating output vector layer" ) );
     583                 :          0 :   }
     584                 :            : 
     585                 :            :   //First, if present, average 3D staked dataset value to 2D face value
     586                 :          0 :   const QgsMesh3dAveragingMethod *avgMethod = mLayerRendererSettings.averagingMethod();
     587                 :          0 :   for ( DataGroup &dataGroup : mDataPerGroup )
     588                 :            :   {
     589                 :          0 :     if ( dataGroup.dataset3dStakedValue.isValid() )
     590                 :          0 :       dataGroup.datasetValues = avgMethod->calculate( dataGroup.dataset3dStakedValue );
     591                 :            :   }
     592                 :            : 
     593                 :          0 :   QList<QgsMeshDatasetGroupMetadata> metaList;
     594                 :          0 :   metaList.reserve( mDataPerGroup.size() );
     595                 :          0 :   for ( const DataGroup &dataGroup : mDataPerGroup )
     596                 :          0 :     metaList.append( dataGroup.metadata );
     597                 :          0 :   QgsFields fields = createFields( metaList, mExportVectorOption );
     598                 :            : 
     599                 :            :   //create sink
     600                 :          0 :   QgsCoordinateReferenceSystem outputCrs = parameterAsCrs( parameters, QStringLiteral( "CRS_OUTPUT" ), context );
     601                 :          0 :   QString identifier;
     602                 :          0 :   QgsFeatureSink *sink = parameterAsSink( parameters,
     603                 :          0 :                                           QStringLiteral( "OUTPUT" ),
     604                 :          0 :                                           context,
     605                 :            :                                           identifier,
     606                 :            :                                           fields,
     607                 :            :                                           QgsWkbTypes::Point,
     608                 :            :                                           outputCrs );
     609                 :          0 :   if ( !sink )
     610                 :          0 :     return QVariantMap();
     611                 :            : 
     612                 :          0 :   if ( feedback )
     613                 :            :   {
     614                 :          0 :     if ( feedback->isCanceled() )
     615                 :          0 :       return QVariantMap();
     616                 :          0 :     feedback->setProgress( 0 );
     617                 :          0 :     feedback->setProgressText( QObject::tr( "Creating gridded points" ) );
     618                 :          0 :   }
     619                 :            : 
     620                 :            :   // grid definition
     621                 :          0 :   double gridSpacing = parameterAsDouble( parameters, QStringLiteral( "GRID_SPACING" ), context );
     622                 :          0 :   QgsRectangle extent = parameterAsExtent( parameters, QStringLiteral( "EXTENT" ), context );
     623                 :          0 :   if ( extent.isEmpty() )
     624                 :          0 :     extent = mTriangularMesh.extent();
     625                 :          0 :   int pointXCount = int( extent.width() / gridSpacing ) + 1;
     626                 :          0 :   int pointYCount = int( extent.height() / gridSpacing ) + 1;
     627                 :            : 
     628                 :          0 :   for ( int ix = 0; ix < pointXCount; ++ix )
     629                 :            :   {
     630                 :          0 :     for ( int iy = 0; iy < pointYCount; ++iy )
     631                 :            :     {
     632                 :          0 :       QgsPoint point( extent.xMinimum() + ix * gridSpacing, extent.yMinimum() + iy * gridSpacing );
     633                 :          0 :       int triangularFaceIndex = mTriangularMesh.faceIndexForPoint_v2( point );
     634                 :          0 :       if ( triangularFaceIndex >= 0 )
     635                 :            :       {
     636                 :            :         //extract dataset values for the point
     637                 :          0 :         QgsAttributes attributes;
     638                 :          0 :         int nativeFaceIndex = mTriangularMesh.trianglesToNativeFaces().at( triangularFaceIndex );
     639                 :          0 :         for ( int i = 0; i < mDataPerGroup.count(); ++i )
     640                 :            :         {
     641                 :          0 :           const DataGroup &dataGroup = mDataPerGroup.at( i );
     642                 :          0 :           bool faceActive = dataGroup.activeFaces.active( nativeFaceIndex );
     643                 :          0 :           if ( !faceActive )
     644                 :          0 :             continue;
     645                 :          0 :           QgsMeshDatasetValue value = extractDatasetValue(
     646                 :          0 :                                         point,
     647                 :          0 :                                         nativeFaceIndex,
     648                 :          0 :                                         triangularFaceIndex,
     649                 :          0 :                                         mTriangularMesh,
     650                 :          0 :                                         dataGroup.activeFaces,
     651                 :          0 :                                         dataGroup.datasetValues,
     652                 :          0 :                                         dataGroup.metadata );
     653                 :            : 
     654                 :          0 :           if ( dataGroup.metadata.isVector() )
     655                 :            :           {
     656                 :          0 :             QVector<double> vector = vectorValue( dataGroup.datasetValues.value( i ), mExportVectorOption );
     657                 :          0 :             for ( double v : vector )
     658                 :            :             {
     659                 :          0 :               attributes.append( v );
     660                 :            :             }
     661                 :          0 :           }
     662                 :            :           else
     663                 :          0 :             attributes.append( value.scalar() );
     664                 :          0 :         }
     665                 :          0 :         QgsFeature feat;
     666                 :          0 :         QgsGeometry geom( point.clone() );
     667                 :            :         try
     668                 :            :         {
     669                 :          0 :           geom.transform( mTransform );
     670                 :          0 :         }
     671                 :            :         catch ( QgsCsException & )
     672                 :            :         {
     673                 :          0 :           geom = QgsGeometry( point.clone() );
     674                 :          0 :           feedback->reportError( QObject::tr( "Could not transform point to destination CRS" ) );
     675                 :          0 :         }
     676                 :          0 :         feat.setGeometry( geom );
     677                 :          0 :         feat.setAttributes( attributes );
     678                 :            : 
     679                 :          0 :         sink->addFeature( feat );
     680                 :          0 :       }
     681                 :          0 :     }
     682                 :          0 :   }
     683                 :            : 
     684                 :          0 :   QVariantMap ret;
     685                 :          0 :   ret[QStringLiteral( "OUTPUT" )] = identifier;
     686                 :            : 
     687                 :          0 :   return ret;
     688                 :          0 : }
     689                 :            : 
     690                 :          0 : QSet<int> QgsExportMeshOnGridAlgorithm::supportedDataType()
     691                 :            : {
     692                 :          0 :   return QSet<int>(
     693                 :          0 :   {
     694                 :            :     QgsMeshDatasetGroupMetadata::DataOnVertices,
     695                 :            :     QgsMeshDatasetGroupMetadata::DataOnFaces,
     696                 :            :     QgsMeshDatasetGroupMetadata::DataOnVolumes} );
     697                 :            : }
     698                 :            : 
     699                 :          0 : QString QgsMeshRasterizeAlgorithm::name() const
     700                 :            : {
     701                 :          0 :   return QStringLiteral( "meshrasterize" );
     702                 :            : }
     703                 :            : 
     704                 :          0 : QString QgsMeshRasterizeAlgorithm::displayName() const
     705                 :            : {
     706                 :          0 :   return QObject::tr( "Rasterize mesh dataset" );
     707                 :            : }
     708                 :            : 
     709                 :          0 : QString QgsMeshRasterizeAlgorithm::group() const
     710                 :            : {
     711                 :          0 :   return QObject::tr( "Mesh" );
     712                 :            : }
     713                 :            : 
     714                 :          0 : QString QgsMeshRasterizeAlgorithm::groupId() const
     715                 :            : {
     716                 :          0 :   return QStringLiteral( "mesh" );
     717                 :            : }
     718                 :            : 
     719                 :          0 : QString QgsMeshRasterizeAlgorithm::shortHelpString() const
     720                 :            : {
     721                 :          0 :   return QObject::tr( "Create a raster layer from a mesh dataset.\n"
     722                 :            :                       "For data on volume (3D stacked dataset values), the exported dataset values are averaged on faces using the method defined in the mesh layer properties (default is Multi level averaging method).\n"
     723                 :            :                       "1D meshes are not supported." );
     724                 :            : }
     725                 :            : 
     726                 :          0 : QgsProcessingAlgorithm *QgsMeshRasterizeAlgorithm::createInstance() const
     727                 :            : {
     728                 :          0 :   return new QgsMeshRasterizeAlgorithm();
     729                 :          0 : }
     730                 :            : 
     731                 :          0 : void QgsMeshRasterizeAlgorithm::initAlgorithm( const QVariantMap &configuration )
     732                 :            : {
     733                 :          0 :   Q_UNUSED( configuration );
     734                 :            : 
     735                 :          0 :   addParameter( new QgsProcessingParameterMeshLayer( QStringLiteral( "INPUT" ), QObject::tr( "Input Mesh Layer" ) ) );
     736                 :            : 
     737                 :          0 :   addParameter( new QgsProcessingParameterMeshDatasetGroups(
     738                 :          0 :                   QStringLiteral( "DATASET_GROUPS" ),
     739                 :          0 :                   QObject::tr( "Dataset groups" ),
     740                 :          0 :                   QStringLiteral( "INPUT" ),
     741                 :          0 :                   supportedDataType() ) );
     742                 :            : 
     743                 :          0 :   addParameter( new QgsProcessingParameterMeshDatasetTime(
     744                 :          0 :                   QStringLiteral( "DATASET_TIME" ),
     745                 :          0 :                   QObject::tr( "Dataset time" ),
     746                 :          0 :                   QStringLiteral( "INPUT" ),
     747                 :          0 :                   QStringLiteral( "DATASET_GROUPS" ) ) );
     748                 :            : 
     749                 :          0 :   addParameter( new QgsProcessingParameterExtent( QStringLiteral( "EXTENT" ), QObject::tr( "Extent" ), QVariant(), true ) );
     750                 :            : 
     751                 :          0 :   addParameter( new QgsProcessingParameterDistance( QStringLiteral( "PIXEL_SIZE" ), QObject::tr( "Pixel size" ), 1, QStringLiteral( "INPUT" ), false ) );
     752                 :            : 
     753                 :          0 :   addParameter( new QgsProcessingParameterCrs( QStringLiteral( "CRS_OUTPUT" ), QObject::tr( "Output coordinate system" ), QVariant(), true ) );
     754                 :            : 
     755                 :          0 :   addParameter( new QgsProcessingParameterRasterDestination( QStringLiteral( "OUTPUT" ), QObject::tr( "Output raster layer" ) ) );
     756                 :          0 : }
     757                 :            : 
     758                 :          0 : bool QgsMeshRasterizeAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
     759                 :            : {
     760                 :          0 :   QgsMeshLayer *meshLayer = parameterAsMeshLayer( parameters, QStringLiteral( "INPUT" ), context );
     761                 :            : 
     762                 :          0 :   if ( !meshLayer || !meshLayer->isValid() )
     763                 :          0 :     return false;
     764                 :            : 
     765                 :          0 :   QgsCoordinateReferenceSystem outputCrs = parameterAsCrs( parameters, QStringLiteral( "CRS_OUTPUT" ), context );
     766                 :          0 :   if ( !outputCrs.isValid() )
     767                 :          0 :     outputCrs = meshLayer->crs();
     768                 :          0 :   mTransform = QgsCoordinateTransform( meshLayer->crs(), outputCrs, context.transformContext() );
     769                 :          0 :   if ( !meshLayer->nativeMesh() )
     770                 :          0 :     meshLayer->updateTriangularMesh( mTransform ); //necessary to load the native mesh
     771                 :            : 
     772                 :          0 :   mTriangularMesh = *meshLayer->triangularMesh();
     773                 :            : 
     774                 :            :   QList<int> datasetGroups =
     775                 :          0 :     QgsProcessingParameterMeshDatasetGroups::valueAsDatasetGroup( parameters.value( QStringLiteral( "DATASET_GROUPS" ) ) );
     776                 :            : 
     777                 :          0 :   if ( feedback )
     778                 :            :   {
     779                 :          0 :     feedback->setProgressText( QObject::tr( "Preparing data" ) );
     780                 :          0 :   }
     781                 :            : 
     782                 :            :   // Extract the date time used to export dataset values under a relative time
     783                 :          0 :   QVariant parameterTimeVariant = parameters.value( QStringLiteral( "DATASET_TIME" ) );
     784                 :          0 :   QgsInterval relativeTime = datasetRelativetime( parameterTimeVariant, meshLayer, context );
     785                 :            : 
     786                 :          0 :   extractDatasetValues( datasetGroups, meshLayer, mTriangularMesh, *meshLayer->nativeMesh(), relativeTime, supportedDataType(), mDataPerGroup, feedback );
     787                 :            : 
     788                 :          0 :   mLayerRendererSettings = meshLayer->rendererSettings();
     789                 :            : 
     790                 :          0 :   return true;
     791                 :          0 : }
     792                 :            : 
     793                 :          0 : QVariantMap QgsMeshRasterizeAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
     794                 :            : {
     795                 :          0 :   if ( feedback )
     796                 :            :   {
     797                 :          0 :     if ( feedback->isCanceled() )
     798                 :          0 :       return QVariantMap();
     799                 :          0 :     feedback->setProgress( 0 );
     800                 :          0 :     feedback->setProgressText( QObject::tr( "Creating raster layer" ) );
     801                 :          0 :   }
     802                 :            : 
     803                 :            :   //First, if present, average 3D staked dataset value to 2D face value
     804                 :          0 :   const QgsMesh3dAveragingMethod *avgMethod = mLayerRendererSettings.averagingMethod();
     805                 :          0 :   for ( DataGroup &dataGroup : mDataPerGroup )
     806                 :            :   {
     807                 :          0 :     if ( dataGroup.dataset3dStakedValue.isValid() )
     808                 :          0 :       dataGroup.datasetValues = avgMethod->calculate( dataGroup.dataset3dStakedValue );
     809                 :            :   }
     810                 :            : 
     811                 :            :   // create raster
     812                 :          0 :   double pixelSize = parameterAsDouble( parameters, QStringLiteral( "PIXEL_SIZE" ), context );
     813                 :          0 :   QgsRectangle extent = parameterAsExtent( parameters, QStringLiteral( "EXTENT" ), context );
     814                 :          0 :   if ( extent.isEmpty() )
     815                 :          0 :     extent = mTriangularMesh.extent();
     816                 :            : 
     817                 :          0 :   int width = extent.width() / pixelSize;
     818                 :          0 :   int height = extent.height() / pixelSize;
     819                 :            : 
     820                 :          0 :   QString fileName = parameterAsOutputLayer( parameters, QStringLiteral( "OUTPUT" ), context );
     821                 :          0 :   QFileInfo fileInfo( fileName );
     822                 :          0 :   QString outputFormat = QgsRasterFileWriter::driverForExtension( fileInfo.suffix() );
     823                 :          0 :   QgsRasterFileWriter rasterFileWriter( fileName );
     824                 :          0 :   rasterFileWriter.setOutputProviderKey( QStringLiteral( "gdal" ) );
     825                 :          0 :   rasterFileWriter.setOutputFormat( outputFormat );
     826                 :            : 
     827                 :          0 :   std::unique_ptr<QgsRasterDataProvider> rasterDataProvider(
     828                 :          0 :     rasterFileWriter.createMultiBandRaster( Qgis::Float64, width, height, extent, mTransform.destinationCrs(), mDataPerGroup.count() ) );
     829                 :          0 :   rasterDataProvider->setEditable( true );
     830                 :            : 
     831                 :          0 :   for ( int i = 0; i < mDataPerGroup.count(); ++i )
     832                 :            :   {
     833                 :          0 :     const DataGroup &dataGroup = mDataPerGroup.at( i );
     834                 :          0 :     QgsRasterBlockFeedback rasterBlockFeedBack;
     835                 :          0 :     if ( feedback )
     836                 :          0 :       QObject::connect( &rasterBlockFeedBack, &QgsFeedback::canceled, feedback, &QgsFeedback::cancel );
     837                 :            : 
     838                 :          0 :     QgsRasterBlock *block = QgsMeshUtils::exportRasterBlock(
     839                 :          0 :                               mTriangularMesh,
     840                 :          0 :                               dataGroup.datasetValues,
     841                 :          0 :                               dataGroup.activeFaces,
     842                 :          0 :                               dataGroup.metadata.dataType(),
     843                 :          0 :                               mTransform,
     844                 :          0 :                               pixelSize,
     845                 :            :                               extent,
     846                 :            :                               &rasterBlockFeedBack );
     847                 :            : 
     848                 :            : 
     849                 :            : 
     850                 :          0 :     rasterDataProvider->writeBlock( block, i + 1 );
     851                 :          0 :     rasterDataProvider->setNoDataValue( i + 1, block->noDataValue() );
     852                 :          0 :     if ( feedback )
     853                 :            :     {
     854                 :          0 :       if ( feedback->isCanceled() )
     855                 :          0 :         return QVariantMap();
     856                 :          0 :       feedback->setProgress( 100 * i / mDataPerGroup.count() );
     857                 :          0 :     }
     858                 :          0 :   }
     859                 :            : 
     860                 :          0 :   rasterDataProvider->setEditable( false );
     861                 :            : 
     862                 :          0 :   if ( feedback )
     863                 :          0 :     feedback->setProgress( 100 );
     864                 :            : 
     865                 :          0 :   QVariantMap ret;
     866                 :          0 :   ret[QStringLiteral( "OUTPUT" )] = fileName;
     867                 :            : 
     868                 :          0 :   return ret;
     869                 :          0 : }
     870                 :            : 
     871                 :          0 : QSet<int> QgsMeshRasterizeAlgorithm::supportedDataType()
     872                 :            : {
     873                 :          0 :   return QSet<int>(
     874                 :          0 :   {
     875                 :            :     QgsMeshDatasetGroupMetadata::DataOnVertices,
     876                 :            :     QgsMeshDatasetGroupMetadata::DataOnFaces,
     877                 :            :     QgsMeshDatasetGroupMetadata::DataOnVolumes} );
     878                 :            : }
     879                 :            : 
     880                 :          0 : QString QgsMeshContoursAlgorithm::name() const
     881                 :            : {
     882                 :          0 :   return QStringLiteral( "meshcontours" );
     883                 :            : }
     884                 :            : 
     885                 :          0 : QString QgsMeshContoursAlgorithm::displayName() const
     886                 :            : {
     887                 :          0 :   return QObject::tr( "Export contours" );
     888                 :            : }
     889                 :            : 
     890                 :          0 : QString QgsMeshContoursAlgorithm::group() const
     891                 :            : {
     892                 :          0 :   return QObject::tr( "Mesh" );
     893                 :            : }
     894                 :            : 
     895                 :          0 : QString QgsMeshContoursAlgorithm::groupId() const
     896                 :            : {
     897                 :          0 :   return QStringLiteral( "mesh" );
     898                 :            : }
     899                 :            : 
     900                 :          0 : QString QgsMeshContoursAlgorithm::shortHelpString() const
     901                 :            : {
     902                 :          0 :   return QObject::tr( "Creates contours as vector layer from mesh scalar dataset" );
     903                 :            : }
     904                 :            : 
     905                 :          0 : QgsProcessingAlgorithm *QgsMeshContoursAlgorithm::createInstance() const
     906                 :            : {
     907                 :          0 :   return new QgsMeshContoursAlgorithm();
     908                 :          0 : }
     909                 :            : 
     910                 :          0 : void QgsMeshContoursAlgorithm::initAlgorithm( const QVariantMap &configuration )
     911                 :            : {
     912                 :          0 :   Q_UNUSED( configuration );
     913                 :            : 
     914                 :          0 :   addParameter( new QgsProcessingParameterMeshLayer( QStringLiteral( "INPUT" ), QObject::tr( "Input Mesh Layer" ) ) );
     915                 :            : 
     916                 :          0 :   addParameter( new QgsProcessingParameterMeshDatasetGroups(
     917                 :          0 :                   QStringLiteral( "DATASET_GROUPS" ),
     918                 :          0 :                   QObject::tr( "Dataset groups" ),
     919                 :          0 :                   QStringLiteral( "INPUT" ),
     920                 :          0 :                   supportedDataType() ) );
     921                 :            : 
     922                 :          0 :   addParameter( new QgsProcessingParameterMeshDatasetTime(
     923                 :          0 :                   QStringLiteral( "DATASET_TIME" ),
     924                 :          0 :                   QObject::tr( "Dataset time" ),
     925                 :          0 :                   QStringLiteral( "INPUT" ),
     926                 :          0 :                   QStringLiteral( "DATASET_GROUPS" ) ) );
     927                 :            : 
     928                 :          0 :   addParameter( new QgsProcessingParameterNumber(
     929                 :          0 :                   QStringLiteral( "INCREMENT" ), QObject::tr( "Increment between contour levels" ), QgsProcessingParameterNumber::Double, QVariant(), true ) );
     930                 :            : 
     931                 :          0 :   addParameter( new QgsProcessingParameterNumber(
     932                 :          0 :                   QStringLiteral( "MINIMUM" ), QObject::tr( "Minimum contour level" ), QgsProcessingParameterNumber::Double, QVariant(), true ) );
     933                 :          0 :   addParameter( new QgsProcessingParameterNumber(
     934                 :          0 :                   QStringLiteral( "MAXIMUM" ), QObject::tr( "Maximum contour level" ), QgsProcessingParameterNumber::Double, QVariant(), true ) );
     935                 :            : 
     936                 :          0 :   addParameter( new QgsProcessingParameterString(
     937                 :          0 :                   QStringLiteral( "CONTOUR_LEVEL_LIST" ), QObject::tr( "List of contours level" ), QVariant(), false, true ) );
     938                 :            : 
     939                 :          0 :   addParameter( new QgsProcessingParameterCrs( QStringLiteral( "CRS_OUTPUT" ), QObject::tr( "Output coordinate system" ), QVariant(), true ) );
     940                 :            : 
     941                 :            : 
     942                 :          0 :   addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT_LINES" ), QObject::tr( "Exported contour lines" ), QgsProcessing::TypeVectorLine ) );
     943                 :          0 :   addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT_POLYGONS" ), QObject::tr( "Exported contour polygons" ), QgsProcessing::TypeVectorPolygon ) );
     944                 :          0 : }
     945                 :            : 
     946                 :          0 : bool QgsMeshContoursAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
     947                 :            : {
     948                 :          0 :   QgsMeshLayer *meshLayer = parameterAsMeshLayer( parameters, QStringLiteral( "INPUT" ), context );
     949                 :            : 
     950                 :          0 :   if ( !meshLayer || !meshLayer->isValid() )
     951                 :          0 :     return false;
     952                 :            : 
     953                 :          0 :   QgsCoordinateReferenceSystem outputCrs = parameterAsCrs( parameters, QStringLiteral( "CRS_OUTPUT" ), context );
     954                 :          0 :   if ( !outputCrs.isValid() )
     955                 :          0 :     outputCrs = meshLayer->crs();
     956                 :          0 :   mTransform = QgsCoordinateTransform( meshLayer->crs(), outputCrs, context.transformContext() );
     957                 :          0 :   if ( !meshLayer->nativeMesh() )
     958                 :          0 :     meshLayer->updateTriangularMesh( mTransform ); //necessary to load the native mesh
     959                 :            : 
     960                 :          0 :   mTriangularMesh = *meshLayer->triangularMesh();
     961                 :          0 :   mNativeMesh = *meshLayer->nativeMesh();
     962                 :            : 
     963                 :            :   // Prepare levels
     964                 :          0 :   mLevels.clear();
     965                 :            :   // First, try with the levels list
     966                 :          0 :   QString levelsString = parameterAsString( parameters, QStringLiteral( "CONTOUR_LEVEL_LIST" ), context );
     967                 :          0 :   if ( ! levelsString.isEmpty() )
     968                 :            :   {
     969                 :          0 :     QStringList levelStringList = levelsString.split( ',' );
     970                 :          0 :     if ( !levelStringList.isEmpty() )
     971                 :            :     {
     972                 :          0 :       for ( const QString &stringVal : levelStringList )
     973                 :            :       {
     974                 :            :         bool ok;
     975                 :          0 :         double val = stringVal.toDouble( &ok );
     976                 :          0 :         if ( ok )
     977                 :          0 :           mLevels.append( val );
     978                 :            :         else
     979                 :          0 :           throw QgsProcessingException( QObject::tr( "Invalid format for level values, must be numbers separated with comma" ) );
     980                 :            : 
     981                 :          0 :         if ( mLevels.count() >= 2 )
     982                 :          0 :           if ( mLevels.last() <= mLevels.at( mLevels.count() - 2 ) )
     983                 :          0 :             throw QgsProcessingException( QObject::tr( "Invalid format for level values, must be different numbers and in increasing order" ) );
     984                 :            :       }
     985                 :          0 :     }
     986                 :          0 :   }
     987                 :            : 
     988                 :          0 :   if ( mLevels.isEmpty() )
     989                 :            :   {
     990                 :          0 :     double minimum = parameterAsDouble( parameters, QStringLiteral( "MINIMUM" ), context );
     991                 :          0 :     double maximum = parameterAsDouble( parameters, QStringLiteral( "MAXIMUM" ), context );
     992                 :          0 :     double interval = parameterAsDouble( parameters, QStringLiteral( "INCREMENT" ), context );
     993                 :            : 
     994                 :          0 :     if ( interval <= 0 )
     995                 :          0 :       throw QgsProcessingException( QObject::tr( "Invalid interval value, must be greater than zero" ) );
     996                 :            : 
     997                 :          0 :     if ( minimum >= maximum )
     998                 :          0 :       throw QgsProcessingException( QObject::tr( "Invalid minimum and maximum values, minimum must be lesser than maximum" ) );
     999                 :            : 
    1000                 :          0 :     if ( interval > ( maximum - minimum ) )
    1001                 :          0 :       throw QgsProcessingException( QObject::tr( "Invalid minimum, maximum and interval values, difference between minimum and maximum must be greater or equal than interval" ) );
    1002                 :            : 
    1003                 :          0 :     int intervalCount = ( maximum - minimum ) / interval;
    1004                 :            : 
    1005                 :          0 :     mLevels.reserve( intervalCount );
    1006                 :          0 :     for ( int i = 0; i < intervalCount; ++i )
    1007                 :            :     {
    1008                 :          0 :       mLevels.append( minimum + i * interval );
    1009                 :          0 :     }
    1010                 :          0 :   }
    1011                 :            : 
    1012                 :            :   // Prepare data
    1013                 :            :   QList<int> datasetGroups =
    1014                 :          0 :     QgsProcessingParameterMeshDatasetGroups::valueAsDatasetGroup( parameters.value( QStringLiteral( "DATASET_GROUPS" ) ) );
    1015                 :            : 
    1016                 :          0 :   if ( feedback )
    1017                 :            :   {
    1018                 :          0 :     feedback->setProgressText( QObject::tr( "Preparing data" ) );
    1019                 :          0 :   }
    1020                 :            : 
    1021                 :            :   // Extract the date time used to export dataset values under a relative time
    1022                 :          0 :   QVariant parameterTimeVariant = parameters.value( QStringLiteral( "DATASET_TIME" ) );
    1023                 :          0 :   QgsInterval relativeTime = datasetRelativetime( parameterTimeVariant, meshLayer, context );
    1024                 :            : 
    1025                 :          0 :   mDateTimeString = meshLayer->formatTime( relativeTime.hours() );
    1026                 :            : 
    1027                 :          0 :   extractDatasetValues( datasetGroups, meshLayer, mTriangularMesh, mNativeMesh, relativeTime, supportedDataType(), mDataPerGroup, feedback );
    1028                 :            : 
    1029                 :          0 :   mLayerRendererSettings = meshLayer->rendererSettings();
    1030                 :            : 
    1031                 :          0 :   return true;
    1032                 :          0 : }
    1033                 :            : 
    1034                 :          0 : QVariantMap QgsMeshContoursAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
    1035                 :            : {
    1036                 :            :   //First, if present, average 3D staked dataset value to 2D face value
    1037                 :          0 :   const QgsMesh3dAveragingMethod *avgMethod = mLayerRendererSettings.averagingMethod();
    1038                 :          0 :   for ( DataGroup &dataGroup : mDataPerGroup )
    1039                 :            :   {
    1040                 :          0 :     if ( dataGroup.dataset3dStakedValue.isValid() )
    1041                 :          0 :       dataGroup.datasetValues = avgMethod->calculate( dataGroup.dataset3dStakedValue );
    1042                 :            :   }
    1043                 :            : 
    1044                 :            :   // Create vector layers
    1045                 :          0 :   QgsFields polygonFields;
    1046                 :          0 :   QgsFields lineFields;
    1047                 :          0 :   polygonFields.append( QObject::tr( "group" ) );
    1048                 :          0 :   polygonFields.append( QObject::tr( "time" ) );
    1049                 :          0 :   polygonFields.append( QObject::tr( "min_value" ) );
    1050                 :          0 :   polygonFields.append( QObject::tr( "max_value" ) );
    1051                 :          0 :   lineFields.append( QObject::tr( "group" ) );
    1052                 :          0 :   lineFields.append( QObject::tr( "time" ) );
    1053                 :          0 :   lineFields.append( QObject::tr( "value" ) );
    1054                 :            : 
    1055                 :          0 :   QgsCoordinateReferenceSystem outputCrs = parameterAsCrs( parameters, QStringLiteral( "CRS_OUTPUT" ), context );
    1056                 :            : 
    1057                 :          0 :   QString lineIdentifier;
    1058                 :          0 :   QString polygonIdentifier;
    1059                 :          0 :   QgsFeatureSink *sinkPolygons = parameterAsSink( parameters,
    1060                 :          0 :                                  QStringLiteral( "OUTPUT_POLYGONS" ),
    1061                 :          0 :                                  context,
    1062                 :            :                                  polygonIdentifier,
    1063                 :            :                                  polygonFields,
    1064                 :            :                                  QgsWkbTypes::PolygonZ,
    1065                 :            :                                  outputCrs );
    1066                 :          0 :   QgsFeatureSink *sinkLines = parameterAsSink( parameters,
    1067                 :          0 :                               QStringLiteral( "OUTPUT_LINES" ),
    1068                 :          0 :                               context,
    1069                 :            :                               lineIdentifier,
    1070                 :            :                               lineFields,
    1071                 :            :                               QgsWkbTypes::LineStringZ,
    1072                 :            :                               outputCrs );
    1073                 :            : 
    1074                 :          0 :   if ( !sinkLines || !sinkPolygons )
    1075                 :          0 :     return QVariantMap();
    1076                 :            : 
    1077                 :            : 
    1078                 :          0 :   for ( int i = 0; i < mDataPerGroup.count(); ++i )
    1079                 :            :   {
    1080                 :          0 :     DataGroup dataGroup = mDataPerGroup.at( i );
    1081                 :          0 :     bool scalarDataOnVertices = dataGroup.metadata.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices;
    1082                 :          0 :     int count =  scalarDataOnVertices ? mNativeMesh.vertices.count() : mNativeMesh.faces.count();
    1083                 :            : 
    1084                 :          0 :     QVector<double> values;
    1085                 :          0 :     if ( dataGroup.datasetValues.isValid() )
    1086                 :            :     {
    1087                 :            :       // vals could be scalar or vectors, for contour rendering we want always magnitude
    1088                 :          0 :       values = QgsMeshLayerUtils::calculateMagnitudes( dataGroup.datasetValues );
    1089                 :          0 :     }
    1090                 :            :     else
    1091                 :            :     {
    1092                 :          0 :       values = QVector<double>( count, std::numeric_limits<double>::quiet_NaN() );
    1093                 :            :     }
    1094                 :            : 
    1095                 :          0 :     if ( ( !scalarDataOnVertices ) )
    1096                 :            :     {
    1097                 :          0 :       values = QgsMeshLayerUtils::interpolateFromFacesData(
    1098                 :            :                  values,
    1099                 :          0 :                  mNativeMesh,
    1100                 :          0 :                  &dataGroup.activeFaces,
    1101                 :            :                  QgsMeshRendererScalarSettings::NeighbourAverage
    1102                 :            :                );
    1103                 :          0 :     }
    1104                 :            : 
    1105                 :          0 :     QgsMeshContours contoursExported( mTriangularMesh, mNativeMesh, values, dataGroup.activeFaces );
    1106                 :            : 
    1107                 :          0 :     QgsAttributes firstAttributes;
    1108                 :          0 :     firstAttributes.append( dataGroup.metadata.name() );
    1109                 :          0 :     firstAttributes.append( mDateTimeString );
    1110                 :            : 
    1111                 :          0 :     for ( double level : mLevels )
    1112                 :            :     {
    1113                 :          0 :       QgsGeometry line = contoursExported.exportLines( level, feedback );
    1114                 :          0 :       if ( feedback->isCanceled() )
    1115                 :          0 :         return QVariantMap();
    1116                 :          0 :       if ( line.isEmpty() )
    1117                 :          0 :         continue;
    1118                 :          0 :       QgsAttributes lineAttributes = firstAttributes;
    1119                 :          0 :       lineAttributes.append( level );
    1120                 :            : 
    1121                 :          0 :       QgsFeature lineFeat;
    1122                 :          0 :       lineFeat.setGeometry( line );
    1123                 :          0 :       lineFeat.setAttributes( lineAttributes );
    1124                 :            : 
    1125                 :          0 :       sinkLines->addFeature( lineFeat );
    1126                 :            : 
    1127                 :          0 :     }
    1128                 :            : 
    1129                 :          0 :     for ( int l = 0; l < mLevels.count() - 1; ++l )
    1130                 :            :     {
    1131                 :          0 :       QgsGeometry polygon = contoursExported.exportPolygons( mLevels.at( l ), mLevels.at( l + 1 ), feedback );
    1132                 :          0 :       if ( feedback->isCanceled() )
    1133                 :          0 :         return QVariantMap();
    1134                 :            : 
    1135                 :          0 :       if ( polygon.isEmpty() )
    1136                 :          0 :         continue;
    1137                 :          0 :       QgsAttributes polygonAttributes = firstAttributes;
    1138                 :          0 :       polygonAttributes.append( mLevels.at( l ) );
    1139                 :          0 :       polygonAttributes.append( mLevels.at( l + 1 ) );
    1140                 :            : 
    1141                 :          0 :       QgsFeature polygonFeature;
    1142                 :          0 :       polygonFeature.setGeometry( polygon );
    1143                 :          0 :       polygonFeature.setAttributes( polygonAttributes );
    1144                 :          0 :       sinkPolygons->addFeature( polygonFeature );
    1145                 :          0 :     }
    1146                 :            : 
    1147                 :          0 :     if ( feedback )
    1148                 :            :     {
    1149                 :          0 :       feedback->setProgress( 100 * i / mDataPerGroup.count() );
    1150                 :          0 :     }
    1151                 :          0 :   }
    1152                 :            : 
    1153                 :          0 :   QVariantMap ret;
    1154                 :          0 :   ret[QStringLiteral( "OUTPUT_LINES" )] = lineIdentifier;
    1155                 :          0 :   ret[QStringLiteral( "OUTPUT_POLYGONS" )] = polygonIdentifier;
    1156                 :            : 
    1157                 :          0 :   return ret;
    1158                 :          0 : }
    1159                 :            : 
    1160                 :          0 : QString QgsMeshExportCrossSection::name() const
    1161                 :            : {
    1162                 :          0 :   return QStringLiteral( "meshexportcrosssection" );
    1163                 :            : }
    1164                 :            : 
    1165                 :          0 : QString QgsMeshExportCrossSection::displayName() const
    1166                 :            : {
    1167                 :          0 :   return QObject::tr( "Export cross section dataset values on lines from mesh" );
    1168                 :            : }
    1169                 :            : 
    1170                 :          0 : QString QgsMeshExportCrossSection::group() const
    1171                 :            : {
    1172                 :          0 :   return QObject::tr( "Mesh" );
    1173                 :            : }
    1174                 :            : 
    1175                 :          0 : QString QgsMeshExportCrossSection::groupId() const
    1176                 :            : {
    1177                 :          0 :   return QStringLiteral( "mesh" );
    1178                 :            : }
    1179                 :            : 
    1180                 :          0 : QString QgsMeshExportCrossSection::shortHelpString() const
    1181                 :            : {
    1182                 :          0 :   return QObject::tr( "This algorithm extracts mesh's dataset values from line contained in a vector layer.\n"
    1183                 :            :                       "Each line is discretized with a resolution distance parameter for extraction of values on its vertices." );
    1184                 :            : }
    1185                 :            : 
    1186                 :          0 : QgsProcessingAlgorithm *QgsMeshExportCrossSection::createInstance() const
    1187                 :            : {
    1188                 :          0 :   return new QgsMeshExportCrossSection();
    1189                 :          0 : }
    1190                 :            : 
    1191                 :          0 : void QgsMeshExportCrossSection::initAlgorithm( const QVariantMap &configuration )
    1192                 :            : {
    1193                 :          0 :   Q_UNUSED( configuration );
    1194                 :            : 
    1195                 :          0 :   addParameter( new QgsProcessingParameterMeshLayer( QStringLiteral( "INPUT" ), QObject::tr( "Input Mesh Layer" ) ) );
    1196                 :            : 
    1197                 :          0 :   addParameter( new QgsProcessingParameterMeshDatasetGroups(
    1198                 :          0 :                   QStringLiteral( "DATASET_GROUPS" ),
    1199                 :          0 :                   QObject::tr( "Dataset groups" ),
    1200                 :          0 :                   QStringLiteral( "INPUT" ),
    1201                 :          0 :                   supportedDataType() ) );
    1202                 :            : 
    1203                 :          0 :   addParameter( new QgsProcessingParameterMeshDatasetTime(
    1204                 :          0 :                   QStringLiteral( "DATASET_TIME" ),
    1205                 :          0 :                   QObject::tr( "Dataset time" ),
    1206                 :          0 :                   QStringLiteral( "INPUT" ),
    1207                 :          0 :                   QStringLiteral( "DATASET_GROUPS" ) ) );
    1208                 :            : 
    1209                 :          0 :   QList<int> datatype;
    1210                 :          0 :   datatype << QgsProcessing::TypeVectorLine;
    1211                 :          0 :   addParameter( new QgsProcessingParameterFeatureSource(
    1212                 :          0 :                   QStringLiteral( "INPUT_LINES" ), QObject::tr( "Lines for data export" ), datatype, QVariant(), false ) );
    1213                 :            : 
    1214                 :          0 :   addParameter( new QgsProcessingParameterDistance(
    1215                 :          0 :                   QStringLiteral( "RESOLUTION" ), QObject::tr( "Line segmentation resolution" ), 10.0, QStringLiteral( "INPUT_LINES" ), false, 0 ) );
    1216                 :            : 
    1217                 :          0 :   addParameter( new QgsProcessingParameterNumber(
    1218                 :          0 :                   QStringLiteral( "COORDINATES_DIGITS" ), QObject::tr( "Digits count for coordinates" ), QgsProcessingParameterNumber::Integer, 2 ) );
    1219                 :            : 
    1220                 :          0 :   addParameter( new QgsProcessingParameterNumber(
    1221                 :          0 :                   QStringLiteral( "DATASET_DIGITS" ), QObject::tr( "Digits count for dataset value" ), QgsProcessingParameterNumber::Integer, 2 ) );
    1222                 :            : 
    1223                 :          0 :   addParameter( new QgsProcessingParameterFileDestination(
    1224                 :          0 :                   QStringLiteral( "OUTPUT" ), QObject::tr( "Exported data CSV file" ), QObject::tr( "CSV file (*.csv)" ) ) );
    1225                 :          0 : }
    1226                 :            : 
    1227                 :          0 : bool QgsMeshExportCrossSection::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
    1228                 :            : {
    1229                 :          0 :   QgsMeshLayer *meshLayer = parameterAsMeshLayer( parameters, QStringLiteral( "INPUT" ), context );
    1230                 :            : 
    1231                 :          0 :   if ( !meshLayer || !meshLayer->isValid() )
    1232                 :          0 :     return false;
    1233                 :            : 
    1234                 :          0 :   mMeshLayerCrs = meshLayer->crs();
    1235                 :          0 :   mTriangularMesh = *meshLayer->triangularMesh();
    1236                 :            : 
    1237                 :            :   QList<int> datasetGroups =
    1238                 :          0 :     QgsProcessingParameterMeshDatasetGroups::valueAsDatasetGroup( parameters.value( QStringLiteral( "DATASET_GROUPS" ) ) );
    1239                 :            : 
    1240                 :          0 :   if ( feedback )
    1241                 :            :   {
    1242                 :          0 :     feedback->setProgressText( QObject::tr( "Preparing data" ) );
    1243                 :          0 :   }
    1244                 :            : 
    1245                 :            :   // Extract the date time used to export dataset values under a relative time
    1246                 :          0 :   QVariant parameterTimeVariant = parameters.value( QStringLiteral( "DATASET_TIME" ) );
    1247                 :          0 :   QgsInterval relativeTime = datasetRelativetime( parameterTimeVariant, meshLayer, context );
    1248                 :            : 
    1249                 :          0 :   extractDatasetValues( datasetGroups, meshLayer, mTriangularMesh, *meshLayer->nativeMesh(), relativeTime, supportedDataType(), mDataPerGroup, feedback );
    1250                 :            : 
    1251                 :          0 :   mLayerRendererSettings = meshLayer->rendererSettings();
    1252                 :            : 
    1253                 :          0 :   return true;
    1254                 :          0 : }
    1255                 :            : 
    1256                 :          0 : QVariantMap QgsMeshExportCrossSection::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
    1257                 :            : {
    1258                 :          0 :   if ( feedback )
    1259                 :          0 :     feedback->setProgress( 0 );
    1260                 :            :   //First, if present, average 3D staked dataset value to 2D face value
    1261                 :          0 :   const QgsMesh3dAveragingMethod *avgMethod = mLayerRendererSettings.averagingMethod();
    1262                 :          0 :   for ( DataGroup &dataGroup : mDataPerGroup )
    1263                 :            :   {
    1264                 :          0 :     if ( dataGroup.dataset3dStakedValue.isValid() )
    1265                 :          0 :       dataGroup.datasetValues = avgMethod->calculate( dataGroup.dataset3dStakedValue );
    1266                 :            :   }
    1267                 :          0 :   double resolution = parameterAsDouble( parameters, QStringLiteral( "RESOLUTION" ), context );
    1268                 :          0 :   int datasetDigits = parameterAsInt( parameters, QStringLiteral( "DATASET_DIGITS" ), context );
    1269                 :          0 :   int coordDigits = parameterAsInt( parameters, QStringLiteral( "COORDINATES_DIGITS" ), context );
    1270                 :            : 
    1271                 :          0 :   QgsProcessingFeatureSource *featureSource = parameterAsSource( parameters, QStringLiteral( "INPUT_LINES" ), context );
    1272                 :          0 :   if ( !featureSource )
    1273                 :          0 :     throw QgsProcessingException( QObject::tr( "Input lines vector layer required" ) );
    1274                 :            : 
    1275                 :          0 :   QgsCoordinateTransform transform( featureSource->sourceCrs(), mMeshLayerCrs, context.transformContext() );
    1276                 :            : 
    1277                 :          0 :   QString outputFileName = parameterAsFileOutput( parameters, QStringLiteral( "OUTPUT" ), context );
    1278                 :          0 :   QFile file( outputFileName );
    1279                 :          0 :   if ( ! file.open( QIODevice::WriteOnly ) )
    1280                 :          0 :     throw QgsProcessingException( QObject::tr( "Unable to create the outputfile" ) );
    1281                 :            : 
    1282                 :          0 :   QTextStream textStream( &file );
    1283                 :          0 :   QStringList header;
    1284                 :          0 :   header << QStringLiteral( "fid" ) << QStringLiteral( "x" ) << QStringLiteral( "y" ) << QObject::tr( "offset" );
    1285                 :          0 :   for ( const DataGroup &datagroup : mDataPerGroup )
    1286                 :          0 :     header << datagroup.metadata.name();
    1287                 :          0 :   textStream << header.join( ',' ) << QStringLiteral( "\n" );
    1288                 :            : 
    1289                 :          0 :   int featCount = featureSource->featureCount();
    1290                 :          0 :   int featCounter = 0;
    1291                 :          0 :   QgsFeatureIterator featIt = featureSource->getFeatures();
    1292                 :          0 :   QgsFeature feat;
    1293                 :          0 :   while ( featIt.nextFeature( feat ) )
    1294                 :            :   {
    1295                 :          0 :     int fid = feat.id();
    1296                 :          0 :     QgsGeometry line = feat.geometry();
    1297                 :            :     try
    1298                 :            :     {
    1299                 :          0 :       line.transform( transform );
    1300                 :          0 :     }
    1301                 :            :     catch ( QgsCsException & )
    1302                 :            :     {
    1303                 :          0 :       line = feat.geometry();
    1304                 :          0 :       feedback->reportError( QObject::tr( "Could not transform line to mesh CRS" ) );
    1305                 :          0 :     }
    1306                 :            : 
    1307                 :          0 :     if ( line.isEmpty() )
    1308                 :          0 :       continue;
    1309                 :          0 :     double offset = 0;
    1310                 :          0 :     while ( offset <= line.length() )
    1311                 :            :     {
    1312                 :          0 :       if ( feedback->isCanceled() )
    1313                 :          0 :         return QVariantMap();
    1314                 :            : 
    1315                 :          0 :       QStringList textLine;
    1316                 :          0 :       QgsPointXY point = line.interpolate( offset ).asPoint();
    1317                 :          0 :       int triangularFaceIndex = mTriangularMesh.faceIndexForPoint_v2( point );
    1318                 :          0 :       textLine << QString::number( fid ) << QString::number( point.x(), 'f', coordDigits ) << QString::number( point.y(), 'f', coordDigits ) << QString::number( offset, 'f', coordDigits );
    1319                 :          0 :       if ( triangularFaceIndex >= 0 )
    1320                 :            :       {
    1321                 :            :         //extract dataset values for the point
    1322                 :          0 :         QgsAttributes attributes;
    1323                 :          0 :         int nativeFaceIndex = mTriangularMesh.trianglesToNativeFaces().at( triangularFaceIndex );
    1324                 :          0 :         for ( int i = 0; i < mDataPerGroup.count(); ++i )
    1325                 :            :         {
    1326                 :          0 :           const DataGroup &dataGroup = mDataPerGroup.at( i );
    1327                 :          0 :           bool faceActive = dataGroup.activeFaces.active( nativeFaceIndex );
    1328                 :          0 :           if ( !faceActive )
    1329                 :          0 :             continue;
    1330                 :          0 :           QgsMeshDatasetValue value = extractDatasetValue(
    1331                 :            :                                         point,
    1332                 :          0 :                                         nativeFaceIndex,
    1333                 :          0 :                                         triangularFaceIndex,
    1334                 :          0 :                                         mTriangularMesh,
    1335                 :          0 :                                         dataGroup.activeFaces,
    1336                 :          0 :                                         dataGroup.datasetValues,
    1337                 :          0 :                                         dataGroup.metadata );
    1338                 :            : 
    1339                 :          0 :           if ( abs( value.x() ) == std::numeric_limits<double>::quiet_NaN() )
    1340                 :          0 :             textLine << QString( ' ' );
    1341                 :            :           else
    1342                 :          0 :             textLine << QString::number( value.scalar(), 'f', datasetDigits );
    1343                 :          0 :         }
    1344                 :          0 :       }
    1345                 :            :       else
    1346                 :          0 :         for ( int i = 0; i < mDataPerGroup.count(); ++i )
    1347                 :          0 :           textLine << QString( ' ' );
    1348                 :            : 
    1349                 :          0 :       textStream << textLine.join( ',' ) << QStringLiteral( "\n" );
    1350                 :            : 
    1351                 :          0 :       offset += resolution;
    1352                 :          0 :     }
    1353                 :            : 
    1354                 :          0 :     if ( feedback )
    1355                 :            :     {
    1356                 :          0 :       feedback->setProgress( 100 * featCounter / featCount );
    1357                 :          0 :       if ( feedback->isCanceled() )
    1358                 :          0 :         return QVariantMap();
    1359                 :          0 :     }
    1360                 :          0 :   }
    1361                 :            : 
    1362                 :          0 :   file.close();
    1363                 :            : 
    1364                 :          0 :   QVariantMap ret;
    1365                 :          0 :   ret[QStringLiteral( "OUTPUT" )] = outputFileName;
    1366                 :          0 :   return ret;
    1367                 :          0 : }
    1368                 :            : 
    1369                 :          0 : QString QgsMeshExportTimeSeries::name() const
    1370                 :            : {
    1371                 :          0 :   return QStringLiteral( "meshexporttimeseries" );
    1372                 :            : }
    1373                 :            : 
    1374                 :          0 : QString QgsMeshExportTimeSeries::displayName() const
    1375                 :            : {
    1376                 :          0 :   return QObject::tr( "Export time series values from points of a mesh dataset" );
    1377                 :            : }
    1378                 :            : 
    1379                 :          0 : QString QgsMeshExportTimeSeries::group() const
    1380                 :            : {
    1381                 :          0 :   return QObject::tr( "Mesh" );
    1382                 :            : }
    1383                 :            : 
    1384                 :          0 : QString QgsMeshExportTimeSeries::groupId() const
    1385                 :            : {
    1386                 :          0 :   return QStringLiteral( "mesh" );
    1387                 :            : }
    1388                 :            : 
    1389                 :          0 : QString QgsMeshExportTimeSeries::shortHelpString() const
    1390                 :            : {
    1391                 :          0 :   return QObject::tr( "This algorithm extracts mesh's dataset time series values from points contained in a vector layer.\n"
    1392                 :            :                       "If the time step is kept to its default value (0 hours), the time step used is the one of the two first datasets of the first selected dataset group" );
    1393                 :            : }
    1394                 :            : 
    1395                 :          0 : QgsProcessingAlgorithm *QgsMeshExportTimeSeries::createInstance() const
    1396                 :            : {
    1397                 :          0 :   return new QgsMeshExportTimeSeries();
    1398                 :          0 : }
    1399                 :            : 
    1400                 :          0 : void QgsMeshExportTimeSeries::initAlgorithm( const QVariantMap &configuration )
    1401                 :            : {
    1402                 :          0 :   Q_UNUSED( configuration );
    1403                 :            : 
    1404                 :          0 :   addParameter( new QgsProcessingParameterMeshLayer( QStringLiteral( "INPUT" ), QObject::tr( "Input Mesh Layer" ) ) );
    1405                 :            : 
    1406                 :          0 :   addParameter( new QgsProcessingParameterMeshDatasetGroups(
    1407                 :          0 :                   QStringLiteral( "DATASET_GROUPS" ),
    1408                 :          0 :                   QObject::tr( "Dataset groups" ),
    1409                 :          0 :                   QStringLiteral( "INPUT" ),
    1410                 :          0 :                   supportedDataType() ) );
    1411                 :            : 
    1412                 :          0 :   addParameter( new QgsProcessingParameterMeshDatasetTime(
    1413                 :          0 :                   QStringLiteral( "STARTING_TIME" ),
    1414                 :          0 :                   QObject::tr( "Starting time" ),
    1415                 :          0 :                   QStringLiteral( "INPUT" ),
    1416                 :          0 :                   QStringLiteral( "DATASET_GROUPS" ) ) );
    1417                 :            : 
    1418                 :          0 :   addParameter( new QgsProcessingParameterMeshDatasetTime(
    1419                 :          0 :                   QStringLiteral( "FINISHING_TIME" ),
    1420                 :          0 :                   QObject::tr( "Finishing time" ),
    1421                 :          0 :                   QStringLiteral( "INPUT" ),
    1422                 :          0 :                   QStringLiteral( "DATASET_GROUPS" ) ) );
    1423                 :            : 
    1424                 :          0 :   addParameter( new QgsProcessingParameterNumber(
    1425                 :          0 :                   QStringLiteral( "TIME_STEP" ), QObject::tr( "Time step (hours)" ), QgsProcessingParameterNumber::Double, 0, true, 0 ) );
    1426                 :            : 
    1427                 :          0 :   QList<int> datatype;
    1428                 :          0 :   datatype << QgsProcessing::TypeVectorPoint;
    1429                 :          0 :   addParameter( new QgsProcessingParameterFeatureSource(
    1430                 :          0 :                   QStringLiteral( "INPUT_POINTS" ), QObject::tr( "Points for data export" ), datatype, QVariant(), false ) );
    1431                 :            : 
    1432                 :          0 :   addParameter( new QgsProcessingParameterNumber(
    1433                 :          0 :                   QStringLiteral( "COORDINATES_DIGITS" ), QObject::tr( "Digits count for coordinates" ), QgsProcessingParameterNumber::Integer, 2 ) );
    1434                 :            : 
    1435                 :          0 :   addParameter( new QgsProcessingParameterNumber(
    1436                 :          0 :                   QStringLiteral( "DATASET_DIGITS" ), QObject::tr( "Digits count for dataset value" ), QgsProcessingParameterNumber::Integer, 2 ) );
    1437                 :            : 
    1438                 :          0 :   addParameter( new QgsProcessingParameterFileDestination(
    1439                 :          0 :                   QStringLiteral( "OUTPUT" ), QObject::tr( "Exported data CSV file" ), QObject::tr( "CSV file (*.csv)" ) ) );
    1440                 :          0 : }
    1441                 :            : 
    1442                 :          0 : bool QgsMeshExportTimeSeries::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
    1443                 :            : {
    1444                 :          0 :   QgsMeshLayer *meshLayer = parameterAsMeshLayer( parameters, QStringLiteral( "INPUT" ), context );
    1445                 :            : 
    1446                 :          0 :   if ( !meshLayer || !meshLayer->isValid() )
    1447                 :          0 :     return false;
    1448                 :            : 
    1449                 :          0 :   mMeshLayerCrs = meshLayer->crs();
    1450                 :          0 :   mTriangularMesh = *meshLayer->triangularMesh();
    1451                 :            : 
    1452                 :            :   QList<int> datasetGroups =
    1453                 :          0 :     QgsProcessingParameterMeshDatasetGroups::valueAsDatasetGroup( parameters.value( QStringLiteral( "DATASET_GROUPS" ) ) );
    1454                 :            : 
    1455                 :          0 :   if ( feedback )
    1456                 :            :   {
    1457                 :          0 :     feedback->setProgressText( QObject::tr( "Preparing data" ) );
    1458                 :          0 :   }
    1459                 :            : 
    1460                 :            :   // Extract the date times used to export dataset values
    1461                 :          0 :   QVariant parameterStartTimeVariant = parameters.value( QStringLiteral( "STARTING_TIME" ) );
    1462                 :          0 :   QgsInterval relativeStartTime = datasetRelativetime( parameterStartTimeVariant, meshLayer, context );
    1463                 :            : 
    1464                 :          0 :   QVariant parameterEndTimeVariant = parameters.value( QStringLiteral( "FINISHING_TIME" ) );
    1465                 :          0 :   QgsInterval relativeEndTime = datasetRelativetime( parameterEndTimeVariant, meshLayer, context );
    1466                 :            : 
    1467                 :            :   // calculate time steps
    1468                 :          0 :   qint64 timeStepInterval = parameterAsDouble( parameters, QStringLiteral( "TIME_STEP" ), context ) * 1000 * 3600;
    1469                 :          0 :   if ( timeStepInterval == 0 )
    1470                 :            :   {
    1471                 :            :     //take the first time step of the first temporal dataset group
    1472                 :          0 :     for ( int groupIndex : datasetGroups )
    1473                 :            :     {
    1474                 :          0 :       QgsMeshDatasetGroupMetadata meta = meshLayer->datasetGroupMetadata( QgsMeshDatasetIndex( groupIndex, 0 ) );
    1475                 :          0 :       if ( !meta.isTemporal() && meshLayer->datasetCount( QgsMeshDatasetIndex( groupIndex, 0 ) ) < 2 )
    1476                 :          0 :         continue;
    1477                 :            :       else
    1478                 :            :       {
    1479                 :          0 :         timeStepInterval = meshLayer->datasetRelativeTimeInMilliseconds( QgsMeshDatasetIndex( groupIndex, 1 ) )
    1480                 :          0 :                            - meshLayer->datasetRelativeTimeInMilliseconds( QgsMeshDatasetIndex( groupIndex, 0 ) );
    1481                 :          0 :         break;
    1482                 :            :       }
    1483                 :          0 :     }
    1484                 :          0 :   }
    1485                 :            : 
    1486                 :          0 :   mRelativeTimeSteps.clear();
    1487                 :          0 :   mTimeStepString.clear();
    1488                 :          0 :   if ( timeStepInterval != 0 )
    1489                 :            :   {
    1490                 :          0 :     mRelativeTimeSteps.append( relativeStartTime.seconds() * 1000 );
    1491                 :          0 :     while ( mRelativeTimeSteps.last() < relativeEndTime.seconds() * 1000 )
    1492                 :          0 :       mRelativeTimeSteps.append( mRelativeTimeSteps.last() + timeStepInterval );
    1493                 :            : 
    1494                 :          0 :     for ( qint64  relativeTimeStep : mRelativeTimeSteps )
    1495                 :            :     {
    1496                 :          0 :       mTimeStepString.append( meshLayer->formatTime( relativeTimeStep / 3600.0 / 1000.0 ) );
    1497                 :            :     }
    1498                 :          0 :   }
    1499                 :            : 
    1500                 :            :   //Extract needed dataset values
    1501                 :          0 :   for ( int i = 0; i < datasetGroups.count(); ++i )
    1502                 :            :   {
    1503                 :          0 :     int  groupIndex = datasetGroups.at( i );
    1504                 :          0 :     QgsMeshDatasetGroupMetadata meta = meshLayer->datasetGroupMetadata( QgsMeshDatasetIndex( groupIndex, 0 ) );
    1505                 :          0 :     if ( supportedDataType().contains( meta.dataType() ) )
    1506                 :            :     {
    1507                 :          0 :       mGroupIndexes.append( groupIndex );
    1508                 :          0 :       mGroupsMetadata[groupIndex] = meta;
    1509                 :          0 :       int valueCount = meta.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices ?
    1510                 :          0 :                        mTriangularMesh.vertices().count() : meshLayer->nativeMesh()->faceCount();
    1511                 :            : 
    1512                 :          0 :       if ( !mRelativeTimeSteps.isEmpty() )
    1513                 :            :       {
    1514                 :            :         //QMap<qint64, DataGroup> temporalGroup;
    1515                 :          0 :         QgsMeshDatasetIndex lastDatasetIndex;
    1516                 :          0 :         for ( qint64  relativeTimeStep : mRelativeTimeSteps )
    1517                 :            :         {
    1518                 :          0 :           QMap<int, int> &groupIndexToData = mRelativeTimeToData[relativeTimeStep];
    1519                 :          0 :           QgsInterval timeStepInterval( relativeTimeStep / 1000.0 );
    1520                 :          0 :           QgsMeshDatasetIndex datasetIndex = meshLayer->datasetIndexAtRelativeTime( timeStepInterval, groupIndex );
    1521                 :          0 :           if ( !datasetIndex.isValid() )
    1522                 :          0 :             continue;
    1523                 :          0 :           if ( datasetIndex != lastDatasetIndex )
    1524                 :            :           {
    1525                 :          0 :             DataGroup dataGroup;
    1526                 :          0 :             dataGroup.metadata = meta;
    1527                 :          0 :             dataGroup.datasetValues = meshLayer->datasetValues( datasetIndex, 0, valueCount );
    1528                 :          0 :             dataGroup.activeFaces = meshLayer->areFacesActive( datasetIndex, 0, meshLayer->nativeMesh()->faceCount() );
    1529                 :          0 :             if ( dataGroup.metadata.dataType() == QgsMeshDatasetGroupMetadata::DataOnVolumes )
    1530                 :            :             {
    1531                 :          0 :               dataGroup.dataset3dStakedValue = meshLayer->dataset3dValues( datasetIndex, 0, valueCount );
    1532                 :          0 :             }
    1533                 :          0 :             mDatasets.append( dataGroup );
    1534                 :          0 :             lastDatasetIndex = datasetIndex;
    1535                 :          0 :           }
    1536                 :          0 :           groupIndexToData[groupIndex] = mDatasets.count() - 1;
    1537                 :            :         }
    1538                 :          0 :       }
    1539                 :            :       else
    1540                 :            :       {
    1541                 :            :         // we have only static dataset group
    1542                 :          0 :         QMap<int, int> &groupIndexToData = mRelativeTimeToData[0];
    1543                 :          0 :         QgsMeshDatasetIndex datasetIndex( groupIndex, 0 );
    1544                 :          0 :         DataGroup dataGroup;
    1545                 :          0 :         dataGroup.metadata = meta;
    1546                 :          0 :         dataGroup.datasetValues = meshLayer->datasetValues( datasetIndex, 0, valueCount );
    1547                 :          0 :         dataGroup.activeFaces = meshLayer->areFacesActive( datasetIndex, 0, meshLayer->nativeMesh()->faceCount() );
    1548                 :          0 :         if ( dataGroup.metadata.dataType() == QgsMeshDatasetGroupMetadata::DataOnVolumes )
    1549                 :            :         {
    1550                 :          0 :           dataGroup.dataset3dStakedValue = meshLayer->dataset3dValues( datasetIndex, 0, valueCount );
    1551                 :          0 :         }
    1552                 :          0 :         mDatasets.append( dataGroup );
    1553                 :          0 :         groupIndexToData[groupIndex] = mDatasets.count() - 1;
    1554                 :          0 :       }
    1555                 :          0 :     }
    1556                 :            : 
    1557                 :          0 :     if ( feedback )
    1558                 :          0 :       feedback->setProgress( 100 * i / datasetGroups.count() );
    1559                 :          0 :   }
    1560                 :            : 
    1561                 :          0 :   mLayerRendererSettings = meshLayer->rendererSettings();
    1562                 :            : 
    1563                 :          0 :   return true;
    1564                 :          0 : }
    1565                 :            : 
    1566                 :            : 
    1567                 :          0 : QVariantMap QgsMeshExportTimeSeries::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
    1568                 :            : {
    1569                 :          0 :   if ( feedback )
    1570                 :          0 :     feedback->setProgress( 0 );
    1571                 :            :   //First, if present, average 3D staked dataset value to 2D face value
    1572                 :          0 :   const QgsMesh3dAveragingMethod *avgMethod = mLayerRendererSettings.averagingMethod();
    1573                 :            : 
    1574                 :          0 :   for ( DataGroup &dataGroup : mDatasets )
    1575                 :            :   {
    1576                 :          0 :     if ( dataGroup.dataset3dStakedValue.isValid() )
    1577                 :          0 :       dataGroup.datasetValues = avgMethod->calculate( dataGroup.dataset3dStakedValue );
    1578                 :            :   }
    1579                 :            : 
    1580                 :          0 :   int datasetDigits = parameterAsInt( parameters, QStringLiteral( "DATASET_DIGITS" ), context );
    1581                 :          0 :   int coordDigits = parameterAsInt( parameters, QStringLiteral( "COORDINATES_DIGITS" ), context );
    1582                 :            : 
    1583                 :          0 :   QgsProcessingFeatureSource *featureSource = parameterAsSource( parameters, QStringLiteral( "INPUT_POINTS" ), context );
    1584                 :          0 :   if ( !featureSource )
    1585                 :          0 :     throw QgsProcessingException( QObject::tr( "Input points vector layer required" ) );
    1586                 :            : 
    1587                 :          0 :   QgsCoordinateTransform transform( featureSource->sourceCrs(), mMeshLayerCrs, context.transformContext() );
    1588                 :            : 
    1589                 :          0 :   QString outputFileName = parameterAsFileOutput( parameters, QStringLiteral( "OUTPUT" ), context );
    1590                 :          0 :   QFile file( outputFileName );
    1591                 :          0 :   if ( ! file.open( QIODevice::WriteOnly ) )
    1592                 :          0 :     throw QgsProcessingException( QObject::tr( "Unable to create the outputfile" ) );
    1593                 :            : 
    1594                 :          0 :   QTextStream textStream( &file );
    1595                 :          0 :   QStringList header;
    1596                 :          0 :   header << QStringLiteral( "fid" ) << QStringLiteral( "x" ) << QStringLiteral( "y" ) << QObject::tr( "time" );
    1597                 :            : 
    1598                 :          0 :   for ( int gi : mGroupIndexes )
    1599                 :          0 :     header << mGroupsMetadata.value( gi ).name();
    1600                 :            : 
    1601                 :          0 :   textStream << header.join( ',' ) << QStringLiteral( "\n" );
    1602                 :            : 
    1603                 :          0 :   int featCount = featureSource->featureCount();
    1604                 :          0 :   int featCounter = 0;
    1605                 :          0 :   QgsFeatureIterator featIt = featureSource->getFeatures();
    1606                 :          0 :   QgsFeature feat;
    1607                 :          0 :   while ( featIt.nextFeature( feat ) )
    1608                 :            :   {
    1609                 :          0 :     int fid = feat.id();
    1610                 :          0 :     QgsGeometry geom = feat.geometry();
    1611                 :            :     try
    1612                 :            :     {
    1613                 :          0 :       geom.transform( transform );
    1614                 :          0 :     }
    1615                 :            :     catch ( QgsCsException & )
    1616                 :            :     {
    1617                 :          0 :       geom = feat.geometry();
    1618                 :          0 :       feedback->reportError( QObject::tr( "Could not transform line to mesh CRS" ) );
    1619                 :          0 :     }
    1620                 :            : 
    1621                 :          0 :     if ( geom.isEmpty() )
    1622                 :          0 :       continue;
    1623                 :            : 
    1624                 :          0 :     QgsPointXY point = geom.asPoint();
    1625                 :          0 :     int triangularFaceIndex = mTriangularMesh.faceIndexForPoint_v2( point );
    1626                 :            : 
    1627                 :          0 :     if ( triangularFaceIndex >= 0 )
    1628                 :            :     {
    1629                 :          0 :       int nativeFaceIndex = mTriangularMesh.trianglesToNativeFaces().at( triangularFaceIndex );
    1630                 :          0 :       if ( !mRelativeTimeSteps.isEmpty() )
    1631                 :            :       {
    1632                 :          0 :         for ( int timeIndex = 0; timeIndex < mRelativeTimeSteps.count(); ++timeIndex )
    1633                 :            :         {
    1634                 :          0 :           qint64 timeStep = mRelativeTimeSteps.at( timeIndex );
    1635                 :          0 :           QStringList textLine;
    1636                 :          0 :           textLine << QString::number( fid )
    1637                 :          0 :                    << QString::number( point.x(), 'f', coordDigits )
    1638                 :          0 :                    << QString::number( point.y(), 'f', coordDigits )
    1639                 :          0 :                    << mTimeStepString.at( timeIndex );
    1640                 :            : 
    1641                 :          0 :           if ( mRelativeTimeToData.contains( timeStep ) )
    1642                 :            :           {
    1643                 :          0 :             const QMap<int, int> &groupToData = mRelativeTimeToData.value( timeStep );
    1644                 :          0 :             for ( int groupIndex : mGroupIndexes )
    1645                 :            :             {
    1646                 :          0 :               if ( !groupToData.contains( groupIndex ) )
    1647                 :          0 :                 continue;
    1648                 :          0 :               int dataIndex = groupToData.value( groupIndex );
    1649                 :          0 :               if ( dataIndex < 0 || dataIndex > mDatasets.count() - 1 )
    1650                 :          0 :                 continue;
    1651                 :            : 
    1652                 :          0 :               const DataGroup &dataGroup = mDatasets.at( dataIndex );
    1653                 :          0 :               QgsMeshDatasetValue value = extractDatasetValue( point,
    1654                 :          0 :                                           nativeFaceIndex,
    1655                 :          0 :                                           triangularFaceIndex,
    1656                 :          0 :                                           mTriangularMesh,
    1657                 :          0 :                                           dataGroup.activeFaces,
    1658                 :          0 :                                           dataGroup.datasetValues,
    1659                 :          0 :                                           dataGroup.metadata );
    1660                 :          0 :               if ( abs( value.x() ) == std::numeric_limits<double>::quiet_NaN() )
    1661                 :          0 :                 textLine << QString( ' ' );
    1662                 :            :               else
    1663                 :          0 :                 textLine << QString::number( value.scalar(), 'f', datasetDigits ) ;
    1664                 :            :             }
    1665                 :          0 :           }
    1666                 :          0 :           textStream << textLine.join( ',' ) << QStringLiteral( "\n" );
    1667                 :          0 :         }
    1668                 :          0 :       }
    1669                 :            :       else
    1670                 :            :       {
    1671                 :          0 :         QStringList textLine;
    1672                 :          0 :         textLine << QString::number( fid )
    1673                 :          0 :                  << QString::number( point.x(), 'f', coordDigits )
    1674                 :          0 :                  << QString::number( point.y(), 'f', coordDigits )
    1675                 :          0 :                  << QObject::tr( "static dataset" );
    1676                 :          0 :         const QMap<int, int> &groupToData = mRelativeTimeToData.value( 0 );
    1677                 :          0 :         for ( int groupIndex : mGroupIndexes )
    1678                 :            :         {
    1679                 :          0 :           if ( !groupToData.contains( groupIndex ) )
    1680                 :          0 :             continue;
    1681                 :          0 :           int dataIndex = groupToData.value( groupIndex );
    1682                 :          0 :           if ( dataIndex < 0 || dataIndex > mDatasets.count() - 1 )
    1683                 :          0 :             continue;
    1684                 :          0 :           const DataGroup &dataGroup = mDatasets.at( dataIndex );
    1685                 :          0 :           QgsMeshDatasetValue value = extractDatasetValue( point,
    1686                 :          0 :                                       nativeFaceIndex,
    1687                 :          0 :                                       triangularFaceIndex,
    1688                 :          0 :                                       mTriangularMesh,
    1689                 :          0 :                                       dataGroup.activeFaces,
    1690                 :          0 :                                       dataGroup.datasetValues,
    1691                 :          0 :                                       dataGroup.metadata );
    1692                 :          0 :           if ( abs( value.x() ) == std::numeric_limits<double>::quiet_NaN() )
    1693                 :          0 :             textLine << QString( ' ' );
    1694                 :            :           else
    1695                 :          0 :             textLine << QString::number( value.scalar(), 'f', datasetDigits );
    1696                 :            :         }
    1697                 :          0 :         textStream << textLine.join( ',' ) << QStringLiteral( "\n" );
    1698                 :          0 :       }
    1699                 :          0 :     }
    1700                 :          0 :     featCounter++;
    1701                 :          0 :     if ( feedback )
    1702                 :            :     {
    1703                 :          0 :       feedback->setProgress( 100 * featCounter / featCount );
    1704                 :          0 :       if ( feedback->isCanceled() )
    1705                 :          0 :         return QVariantMap();
    1706                 :          0 :     }
    1707                 :          0 :   }
    1708                 :            : 
    1709                 :          0 :   file.close();
    1710                 :            : 
    1711                 :          0 :   QVariantMap ret;
    1712                 :          0 :   ret[QStringLiteral( "OUTPUT" )] = outputFileName;
    1713                 :          0 :   return ret;
    1714                 :          0 : }
    1715                 :            : 
    1716                 :            : ///@endcond PRIVATE

Generated by: LCOV version 1.14