LCOV - code coverage report
Current view: top level - core/mesh - qgsmeshlayer.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 0 862 0.0 %
Date: 2021-03-26 12:19:53 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :                          qgsmeshlayer.cpp
       3                 :            :                          ----------------
       4                 :            :     begin                : April 2018
       5                 :            :     copyright            : (C) 2018 by Peter Petrik
       6                 :            :     email                : zilolv at gmail dot com
       7                 :            :  ***************************************************************************/
       8                 :            : 
       9                 :            : /***************************************************************************
      10                 :            :  *                                                                         *
      11                 :            :  *   This program is free software; you can redistribute it and/or modify  *
      12                 :            :  *   it under the terms of the GNU General Public License as published by  *
      13                 :            :  *   the Free Software Foundation; either version 2 of the License, or     *
      14                 :            :  *   (at your option) any later version.                                   *
      15                 :            :  *                                                                         *
      16                 :            :  ***************************************************************************/
      17                 :            : 
      18                 :            : #include <cstddef>
      19                 :            : #include <limits>
      20                 :            : 
      21                 :            : #include <QUuid>
      22                 :            : #include <QUrl>
      23                 :            : 
      24                 :            : #include "qgscolorramp.h"
      25                 :            : #include "qgslogger.h"
      26                 :            : #include "qgsmaplayerlegend.h"
      27                 :            : #include "qgsmaplayerfactory.h"
      28                 :            : #include "qgsmeshdataprovider.h"
      29                 :            : #include "qgsmeshdatasetgroupstore.h"
      30                 :            : #include "qgsmeshlayer.h"
      31                 :            : #include "qgsmeshlayerrenderer.h"
      32                 :            : #include "qgsmeshlayertemporalproperties.h"
      33                 :            : #include "qgsmeshlayerutils.h"
      34                 :            : #include "qgsmeshtimesettings.h"
      35                 :            : #include "qgspainting.h"
      36                 :            : #include "qgsproviderregistry.h"
      37                 :            : #include "qgsreadwritecontext.h"
      38                 :            : #include "qgsstyle.h"
      39                 :            : #include "qgstriangularmesh.h"
      40                 :            : #include "qgsmesh3daveraging.h"
      41                 :            : #include "qgslayermetadataformatter.h"
      42                 :            : 
      43                 :          0 : QgsMeshLayer::QgsMeshLayer( const QString &meshLayerPath,
      44                 :            :                             const QString &baseName,
      45                 :            :                             const QString &providerKey,
      46                 :            :                             const QgsMeshLayer::LayerOptions &options )
      47                 :          0 :   : QgsMapLayer( QgsMapLayerType::MeshLayer, baseName, meshLayerPath ),
      48                 :          0 :     mDatasetGroupStore( new QgsMeshDatasetGroupStore( this ) ),
      49                 :          0 :     mTemporalProperties( new QgsMeshLayerTemporalProperties( this ) )
      50                 :            : 
      51                 :          0 : {
      52                 :          0 :   mShouldValidateCrs = !options.skipCrsValidation;
      53                 :            : 
      54                 :          0 :   setProviderType( providerKey );
      55                 :            :   // if we’re given a provider type, try to create and bind one to this layer
      56                 :          0 :   bool ok = false;
      57                 :          0 :   if ( !meshLayerPath.isEmpty() && !providerKey.isEmpty() )
      58                 :            :   {
      59                 :          0 :     QgsDataProvider::ProviderOptions providerOptions { options.transformContext };
      60                 :          0 :     QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags();
      61                 :          0 :     if ( mReadFlags & QgsMapLayer::FlagTrustLayerMetadata )
      62                 :            :     {
      63                 :          0 :       flags |= QgsDataProvider::FlagTrustDataSource;
      64                 :          0 :     }
      65                 :          0 :     ok = setDataProvider( providerKey, providerOptions, flags );
      66                 :          0 :   }
      67                 :            : 
      68                 :          0 :   setLegend( QgsMapLayerLegend::defaultMeshLegend( this ) );
      69                 :          0 :   if ( ok )
      70                 :            :   {
      71                 :          0 :     setDefaultRendererSettings( mDatasetGroupStore->datasetGroupIndexes() );
      72                 :            : 
      73                 :          0 :     if ( mDataProvider )
      74                 :            :     {
      75                 :          0 :       mTemporalProperties->setDefaultsFromDataProviderTemporalCapabilities( mDataProvider->temporalCapabilities() );
      76                 :          0 :       resetDatasetGroupTreeItem();
      77                 :          0 :     }
      78                 :          0 :   }
      79                 :            : 
      80                 :          0 :   connect( mDatasetGroupStore.get(), &QgsMeshDatasetGroupStore::datasetGroupsAdded, this, &QgsMeshLayer::onDatasetGroupsAdded );
      81                 :          0 : }
      82                 :            : 
      83                 :            : 
      84                 :          0 : void QgsMeshLayer::setDefaultRendererSettings( const QList<int> &groupIndexes )
      85                 :            : {
      86                 :          0 :   QgsMeshRendererMeshSettings meshSettings;
      87                 :          0 :   if ( groupIndexes.count() > 0 )
      88                 :            :   {
      89                 :            :     // Show data from the first dataset group
      90                 :          0 :     mRendererSettings.setActiveScalarDatasetGroup( 0 );
      91                 :            :     // If the first dataset group has nan min/max, display the mesh to avoid nothing displayed
      92                 :          0 :     const QgsMeshDatasetGroupMetadata &meta = datasetGroupMetadata( 0 );
      93                 :          0 :     if ( meta.maximum() == std::numeric_limits<double>::quiet_NaN() &&
      94                 :          0 :          meta.minimum() == std::numeric_limits<double>::quiet_NaN() )
      95                 :          0 :       meshSettings.setEnabled( true );
      96                 :          0 :   }
      97                 :            :   else
      98                 :            :   {
      99                 :            :     // show at least the mesh by default
     100                 :          0 :     meshSettings.setEnabled( true );
     101                 :          0 :     return;
     102                 :            :   }
     103                 :          0 :   mRendererSettings.setNativeMeshSettings( meshSettings );
     104                 :            : 
     105                 :            :   // Sets default resample method for scalar dataset
     106                 :          0 :   for ( int i : groupIndexes )
     107                 :            :   {
     108                 :          0 :     QgsMeshDatasetGroupMetadata meta = datasetGroupMetadata( i );
     109                 :          0 :     QgsMeshRendererScalarSettings scalarSettings = mRendererSettings.scalarSettings( i );
     110                 :          0 :     switch ( meta.dataType() )
     111                 :            :     {
     112                 :            :       case QgsMeshDatasetGroupMetadata::DataOnFaces:
     113                 :            :       case QgsMeshDatasetGroupMetadata::DataOnVolumes: // data on volumes are averaged to 2D data on faces
     114                 :          0 :         scalarSettings.setDataResamplingMethod( QgsMeshRendererScalarSettings::NeighbourAverage );
     115                 :          0 :         break;
     116                 :            :       case QgsMeshDatasetGroupMetadata::DataOnVertices:
     117                 :          0 :         scalarSettings.setDataResamplingMethod( QgsMeshRendererScalarSettings::None );
     118                 :          0 :         break;
     119                 :            :       case QgsMeshDatasetGroupMetadata::DataOnEdges:
     120                 :          0 :         break;
     121                 :            :     }
     122                 :            : 
     123                 :            :     //override color ramp if the values in the dataset group are classified
     124                 :          0 :     applyClassificationOnScalarSettings( meta, scalarSettings );
     125                 :            : 
     126                 :          0 :     mRendererSettings.setScalarSettings( i, scalarSettings );
     127                 :          0 :   }
     128                 :            : 
     129                 :          0 : }
     130                 :            : 
     131                 :          0 : void QgsMeshLayer::createSimplifiedMeshes()
     132                 :            : {
     133                 :          0 :   if ( mSimplificationSettings.isEnabled() && !hasSimplifiedMeshes() )
     134                 :            :   {
     135                 :          0 :     double reductionFactor = mSimplificationSettings.reductionFactor();
     136                 :            : 
     137                 :            :     QVector<QgsTriangularMesh *> simplifyMeshes =
     138                 :          0 :       mTriangularMeshes[0]->simplifyMesh( reductionFactor );
     139                 :            : 
     140                 :          0 :     for ( int i = 0; i < simplifyMeshes.count() ; ++i )
     141                 :            :     {
     142                 :          0 :       mTriangularMeshes.emplace_back( simplifyMeshes[i] );
     143                 :          0 :     }
     144                 :          0 :   }
     145                 :          0 : }
     146                 :            : 
     147                 :          0 : bool QgsMeshLayer::hasSimplifiedMeshes() const
     148                 :            : {
     149                 :            :   //First mesh is the base mesh, so if size>1, there is no simplified meshes
     150                 :          0 :   return ( mTriangularMeshes.size() > 1 );
     151                 :            : }
     152                 :            : 
     153                 :          0 : QgsMeshLayer::~QgsMeshLayer()
     154                 :          0 : {
     155                 :          0 :   delete mDataProvider;
     156                 :          0 : }
     157                 :            : 
     158                 :          0 : QgsMeshDataProvider *QgsMeshLayer::dataProvider()
     159                 :            : {
     160                 :          0 :   return mDataProvider;
     161                 :            : }
     162                 :            : 
     163                 :          0 : const QgsMeshDataProvider *QgsMeshLayer::dataProvider() const
     164                 :            : {
     165                 :          0 :   return mDataProvider;
     166                 :            : }
     167                 :            : 
     168                 :          0 : QgsMeshLayer *QgsMeshLayer::clone() const
     169                 :            : {
     170                 :          0 :   QgsMeshLayer::LayerOptions options;
     171                 :          0 :   if ( mDataProvider )
     172                 :            :   {
     173                 :          0 :     options.transformContext = mDataProvider->transformContext();
     174                 :          0 :   }
     175                 :          0 :   QgsMeshLayer *layer = new QgsMeshLayer( source(), name(), mProviderKey,  options );
     176                 :          0 :   QgsMapLayer::clone( layer );
     177                 :          0 :   return layer;
     178                 :          0 : }
     179                 :            : 
     180                 :          0 : QgsRectangle QgsMeshLayer::extent() const
     181                 :            : {
     182                 :          0 :   if ( mDataProvider )
     183                 :          0 :     return mDataProvider->extent();
     184                 :            :   else
     185                 :            :   {
     186                 :          0 :     QgsRectangle rec;
     187                 :          0 :     rec.setMinimal();
     188                 :          0 :     return rec;
     189                 :            :   }
     190                 :          0 : }
     191                 :            : 
     192                 :          0 : QString QgsMeshLayer::providerType() const
     193                 :            : {
     194                 :          0 :   return mProviderKey;
     195                 :            : }
     196                 :            : 
     197                 :          0 : bool QgsMeshLayer::addDatasets( const QString &path, const QDateTime &defaultReferenceTime )
     198                 :            : {
     199                 :          0 :   bool isTemporalBefore = dataProvider()->temporalCapabilities()->hasTemporalCapabilities();
     200                 :          0 :   if ( mDatasetGroupStore->addPersistentDatasets( path ) )
     201                 :            :   {
     202                 :          0 :     QgsMeshLayerTemporalProperties *temporalProperties = qobject_cast< QgsMeshLayerTemporalProperties * >( mTemporalProperties );
     203                 :          0 :     if ( !isTemporalBefore && dataProvider()->temporalCapabilities()->hasTemporalCapabilities() )
     204                 :            :     {
     205                 :          0 :       mTemporalProperties->setDefaultsFromDataProviderTemporalCapabilities(
     206                 :          0 :         dataProvider()->temporalCapabilities() );
     207                 :            : 
     208                 :          0 :       if ( ! temporalProperties->referenceTime().isValid() )
     209                 :            :       {
     210                 :          0 :         QDateTime referenceTime = defaultReferenceTime;
     211                 :          0 :         if ( !defaultReferenceTime.isValid() ) // If project reference time is invalid, use current date
     212                 :          0 :           referenceTime = QDateTime( QDate::currentDate(), QTime( 0, 0, 0 ), Qt::UTC );
     213                 :          0 :         temporalProperties->setReferenceTime( referenceTime, dataProvider()->temporalCapabilities() );
     214                 :          0 :       }
     215                 :            : 
     216                 :          0 :       mTemporalProperties->setIsActive( true );
     217                 :          0 :     }
     218                 :          0 :     emit dataSourceChanged();
     219                 :          0 :     return true;
     220                 :            :   }
     221                 :            : 
     222                 :          0 :   return false;
     223                 :          0 : }
     224                 :            : 
     225                 :          0 : bool QgsMeshLayer::addDatasets( QgsMeshDatasetGroup *datasetGroup )
     226                 :            : {
     227                 :          0 :   if ( mDatasetGroupStore->addDatasetGroup( datasetGroup ) )
     228                 :            :   {
     229                 :          0 :     emit dataChanged();
     230                 :          0 :     return true;
     231                 :            :   }
     232                 :          0 :   return false;
     233                 :          0 : }
     234                 :            : 
     235                 :          0 : bool QgsMeshLayer::saveDataset( const QString &path, int datasetGroupIndex, QString driver )
     236                 :            : {
     237                 :          0 :   return mDatasetGroupStore->saveDatasetGroup( path, datasetGroupIndex, driver );
     238                 :          0 : }
     239                 :            : 
     240                 :          0 : QgsMesh *QgsMeshLayer::nativeMesh()
     241                 :            : {
     242                 :          0 :   return mNativeMesh.get();
     243                 :            : }
     244                 :            : 
     245                 :          0 : const QgsMesh *QgsMeshLayer::nativeMesh() const
     246                 :            : {
     247                 :          0 :   return mNativeMesh.get();
     248                 :            : }
     249                 :            : 
     250                 :          0 : QgsTriangularMesh *QgsMeshLayer::triangularMesh( double minimumTriangleSize ) const
     251                 :            : {
     252                 :          0 :   for ( const std::unique_ptr<QgsTriangularMesh> &lod : mTriangularMeshes )
     253                 :            :   {
     254                 :          0 :     if ( lod && lod->averageTriangleSize() > minimumTriangleSize )
     255                 :          0 :       return lod.get();
     256                 :            :   }
     257                 :            : 
     258                 :          0 :   if ( !mTriangularMeshes.empty() )
     259                 :          0 :     return mTriangularMeshes.back().get();
     260                 :            :   else
     261                 :          0 :     return nullptr;
     262                 :          0 : }
     263                 :            : 
     264                 :          0 : int QgsMeshLayer::triangularMeshLevelOfDetailCount() const SIP_SKIP
     265                 :            : {
     266                 :          0 :   return mTriangularMeshes.size();
     267                 :            : }
     268                 :            : 
     269                 :          0 : QgsTriangularMesh *QgsMeshLayer::triangularMeshByLodIndex( int lodIndex ) const SIP_SKIP
     270                 :            : {
     271                 :          0 :   if ( mTriangularMeshes.empty() )
     272                 :          0 :     return nullptr;
     273                 :          0 :   if ( lodIndex < 0 )
     274                 :          0 :     return mTriangularMeshes.front().get();
     275                 :            : 
     276                 :          0 :   if ( lodIndex >= int( mTriangularMeshes.size() ) )
     277                 :          0 :     return mTriangularMeshes.back().get();
     278                 :            : 
     279                 :          0 :   return mTriangularMeshes.at( lodIndex ).get();
     280                 :          0 : }
     281                 :            : 
     282                 :          0 : void  QgsMeshLayer::updateTriangularMesh( const QgsCoordinateTransform &transform )
     283                 :            : {
     284                 :            :   // Native mesh
     285                 :          0 :   if ( !mNativeMesh )
     286                 :            :   {
     287                 :            :     // lazy loading of mesh data
     288                 :          0 :     fillNativeMesh();
     289                 :          0 :   }
     290                 :            : 
     291                 :            :   // Triangular mesh
     292                 :          0 :   if ( mTriangularMeshes.empty() )
     293                 :            :   {
     294                 :          0 :     QgsTriangularMesh *baseMesh = new QgsTriangularMesh;
     295                 :          0 :     mTriangularMeshes.emplace_back( baseMesh );
     296                 :          0 :   }
     297                 :            : 
     298                 :          0 :   if ( mTriangularMeshes[0].get()->update( mNativeMesh.get(), transform ) )
     299                 :          0 :     mTriangularMeshes.resize( 1 ); //if the base triangular mesh is effectivly updated, remove simplified meshes
     300                 :            : 
     301                 :          0 :   createSimplifiedMeshes();
     302                 :          0 : }
     303                 :            : 
     304                 :          0 : QgsMeshLayerRendererCache *QgsMeshLayer::rendererCache()
     305                 :            : {
     306                 :          0 :   return mRendererCache.get();
     307                 :            : }
     308                 :            : 
     309                 :          0 : QgsMeshRendererSettings QgsMeshLayer::rendererSettings() const
     310                 :            : {
     311                 :          0 :   return mRendererSettings;
     312                 :            : }
     313                 :            : 
     314                 :          0 : void QgsMeshLayer::setRendererSettings( const QgsMeshRendererSettings &settings )
     315                 :            : {
     316                 :          0 :   int oldActiveScalar = mRendererSettings.activeScalarDatasetGroup();
     317                 :          0 :   int oldActiveVector = mRendererSettings.activeVectorDatasetGroup();
     318                 :          0 :   mRendererSettings = settings;
     319                 :            : 
     320                 :          0 :   if ( oldActiveScalar != mRendererSettings.activeScalarDatasetGroup() )
     321                 :          0 :     emit activeScalarDatasetGroupChanged( mRendererSettings.activeScalarDatasetGroup() );
     322                 :            : 
     323                 :          0 :   if ( oldActiveVector != mRendererSettings.activeVectorDatasetGroup() )
     324                 :          0 :     emit activeVectorDatasetGroupChanged( mRendererSettings.activeVectorDatasetGroup() );
     325                 :            : 
     326                 :          0 :   emit rendererChanged();
     327                 :          0 :   triggerRepaint();
     328                 :          0 : }
     329                 :            : 
     330                 :          0 : QgsMeshTimeSettings QgsMeshLayer::timeSettings() const
     331                 :            : {
     332                 :          0 :   return mTimeSettings;
     333                 :            : }
     334                 :            : 
     335                 :          0 : void QgsMeshLayer::setTimeSettings( const QgsMeshTimeSettings &settings )
     336                 :            : {
     337                 :          0 :   mTimeSettings = settings;
     338                 :          0 :   emit timeSettingsChanged();
     339                 :          0 : }
     340                 :            : 
     341                 :          0 : QString QgsMeshLayer::formatTime( double hours )
     342                 :            : {
     343                 :          0 :   if ( dataProvider() && dataProvider()->temporalCapabilities()->hasReferenceTime() )
     344                 :          0 :     return QgsMeshLayerUtils::formatTime( hours, mTemporalProperties->referenceTime(), mTimeSettings );
     345                 :            :   else
     346                 :          0 :     return QgsMeshLayerUtils::formatTime( hours, QDateTime(), mTimeSettings );
     347                 :          0 : }
     348                 :            : 
     349                 :          0 : int QgsMeshLayer::datasetGroupCount() const
     350                 :            : {
     351                 :          0 :   return mDatasetGroupStore->datasetGroupCount();
     352                 :            : }
     353                 :            : 
     354                 :          0 : int QgsMeshLayer::extraDatasetGroupCount() const
     355                 :            : {
     356                 :          0 :   return mDatasetGroupStore->extraDatasetGroupCount();
     357                 :            : }
     358                 :            : 
     359                 :          0 : QList<int> QgsMeshLayer::datasetGroupsIndexes() const
     360                 :            : {
     361                 :          0 :   return mDatasetGroupStore->datasetGroupIndexes();
     362                 :            : }
     363                 :            : 
     364                 :          0 : QList<int> QgsMeshLayer::enabledDatasetGroupsIndexes() const
     365                 :            : {
     366                 :          0 :   return mDatasetGroupStore->enabledDatasetGroupIndexes();
     367                 :            : }
     368                 :            : 
     369                 :          0 : QgsMeshDatasetGroupMetadata QgsMeshLayer::datasetGroupMetadata( const QgsMeshDatasetIndex &index ) const
     370                 :            : {
     371                 :          0 :   return mDatasetGroupStore->datasetGroupMetadata( index );
     372                 :            : }
     373                 :            : 
     374                 :          0 : int QgsMeshLayer::datasetCount( const QgsMeshDatasetIndex &index ) const
     375                 :            : {
     376                 :          0 :   return mDatasetGroupStore->datasetCount( index.group() );
     377                 :            : }
     378                 :            : 
     379                 :          0 : QgsMeshDatasetMetadata QgsMeshLayer::datasetMetadata( const QgsMeshDatasetIndex &index ) const
     380                 :            : {
     381                 :          0 :   return mDatasetGroupStore->datasetMetadata( index );
     382                 :            : }
     383                 :            : 
     384                 :          0 : QgsMeshDatasetValue QgsMeshLayer::datasetValue( const QgsMeshDatasetIndex &index, int valueIndex ) const
     385                 :            : {
     386                 :          0 :   return mDatasetGroupStore->datasetValue( index, valueIndex );
     387                 :            : }
     388                 :            : 
     389                 :          0 : QgsMeshDataBlock QgsMeshLayer::datasetValues( const QgsMeshDatasetIndex &index, int valueIndex, int count ) const
     390                 :            : {
     391                 :          0 :   return mDatasetGroupStore->datasetValues( index, valueIndex, count );
     392                 :            : }
     393                 :            : 
     394                 :          0 : QgsMesh3dDataBlock QgsMeshLayer::dataset3dValues( const QgsMeshDatasetIndex &index, int faceIndex, int count ) const
     395                 :            : {
     396                 :          0 :   return mDatasetGroupStore->dataset3dValues( index, faceIndex, count );
     397                 :            : }
     398                 :            : 
     399                 :          0 : QgsMeshDataBlock QgsMeshLayer::areFacesActive( const QgsMeshDatasetIndex &index, int faceIndex, int count ) const
     400                 :            : {
     401                 :          0 :   return mDatasetGroupStore->areFacesActive( index, faceIndex, count );
     402                 :            : }
     403                 :            : 
     404                 :          0 : bool QgsMeshLayer::isFaceActive( const QgsMeshDatasetIndex &index, int faceIndex ) const
     405                 :            : {
     406                 :          0 :   return mDatasetGroupStore->isFaceActive( index, faceIndex );
     407                 :            : }
     408                 :            : 
     409                 :          0 : QgsMeshDatasetValue QgsMeshLayer::datasetValue( const QgsMeshDatasetIndex &index, const QgsPointXY &point, double searchRadius ) const
     410                 :            : {
     411                 :          0 :   QgsMeshDatasetValue value;
     412                 :          0 :   const QgsTriangularMesh *mesh = triangularMesh();
     413                 :            : 
     414                 :          0 :   if ( mesh && dataProvider() && dataProvider()->isValid() && index.isValid() )
     415                 :            :   {
     416                 :          0 :     if ( dataProvider()->contains( QgsMesh::ElementType::Edge ) )
     417                 :            :     {
     418                 :          0 :       QgsRectangle searchRectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
     419                 :          0 :       return dataset1dValue( index, point, searchRadius );
     420                 :            :     }
     421                 :          0 :     int faceIndex = mesh->faceIndexForPoint_v2( point ) ;
     422                 :          0 :     if ( faceIndex >= 0 )
     423                 :            :     {
     424                 :          0 :       int nativeFaceIndex = mesh->trianglesToNativeFaces().at( faceIndex );
     425                 :          0 :       const QgsMeshDatasetGroupMetadata::DataType dataType = datasetGroupMetadata( index ).dataType();
     426                 :          0 :       if ( isFaceActive( index, nativeFaceIndex ) )
     427                 :            :       {
     428                 :          0 :         switch ( dataType )
     429                 :            :         {
     430                 :            :           case QgsMeshDatasetGroupMetadata::DataOnFaces:
     431                 :            :           {
     432                 :          0 :             value = datasetValue( index, nativeFaceIndex );
     433                 :            :           }
     434                 :          0 :           break;
     435                 :            : 
     436                 :            :           case QgsMeshDatasetGroupMetadata::DataOnVertices:
     437                 :            :           {
     438                 :          0 :             const QgsMeshFace &face = mesh->triangles()[faceIndex];
     439                 :          0 :             const int v1 = face[0], v2 = face[1], v3 = face[2];
     440                 :          0 :             const QgsPoint p1 = mesh->vertices()[v1], p2 = mesh->vertices()[v2], p3 = mesh->vertices()[v3];
     441                 :          0 :             const QgsMeshDatasetValue val1 = datasetValue( index, v1 );
     442                 :          0 :             const QgsMeshDatasetValue val2 = datasetValue( index, v2 );
     443                 :          0 :             const QgsMeshDatasetValue val3 = datasetValue( index, v3 );
     444                 :          0 :             const double x = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.x(), val2.x(), val3.x(), point );
     445                 :          0 :             double y = std::numeric_limits<double>::quiet_NaN();
     446                 :          0 :             bool isVector = datasetGroupMetadata( index ).isVector();
     447                 :          0 :             if ( isVector )
     448                 :          0 :               y = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.y(), val2.y(), val3.y(), point );
     449                 :            : 
     450                 :          0 :             value = QgsMeshDatasetValue( x, y );
     451                 :          0 :           }
     452                 :          0 :           break;
     453                 :            : 
     454                 :            :           case QgsMeshDatasetGroupMetadata::DataOnVolumes:
     455                 :            :           {
     456                 :          0 :             const QgsMesh3dAveragingMethod *avgMethod = mRendererSettings.averagingMethod();
     457                 :          0 :             if ( avgMethod )
     458                 :            :             {
     459                 :          0 :               const QgsMesh3dDataBlock block3d = dataset3dValues( index, nativeFaceIndex, 1 );
     460                 :          0 :               const QgsMeshDataBlock block2d = avgMethod->calculate( block3d );
     461                 :          0 :               if ( block2d.isValid() )
     462                 :            :               {
     463                 :          0 :                 value = block2d.value( 0 );
     464                 :          0 :               }
     465                 :          0 :             }
     466                 :            :           }
     467                 :          0 :           break;
     468                 :            : 
     469                 :            :           default:
     470                 :          0 :             break;
     471                 :            :         }
     472                 :          0 :       }
     473                 :          0 :     }
     474                 :          0 :   }
     475                 :            : 
     476                 :          0 :   return value;
     477                 :          0 : }
     478                 :            : 
     479                 :          0 : QgsMesh3dDataBlock QgsMeshLayer::dataset3dValue( const QgsMeshDatasetIndex &index, const QgsPointXY &point ) const
     480                 :            : {
     481                 :          0 :   QgsMesh3dDataBlock block3d;
     482                 :            : 
     483                 :          0 :   const QgsTriangularMesh *baseTriangularMesh = triangularMesh();
     484                 :            : 
     485                 :          0 :   if ( baseTriangularMesh && dataProvider() && dataProvider()->isValid() && index.isValid() )
     486                 :            :   {
     487                 :          0 :     const QgsMeshDatasetGroupMetadata::DataType dataType = datasetGroupMetadata( index ).dataType();
     488                 :          0 :     if ( dataType == QgsMeshDatasetGroupMetadata::DataOnVolumes )
     489                 :            :     {
     490                 :          0 :       int faceIndex = baseTriangularMesh->faceIndexForPoint_v2( point );
     491                 :          0 :       if ( faceIndex >= 0 )
     492                 :            :       {
     493                 :          0 :         int nativeFaceIndex = baseTriangularMesh->trianglesToNativeFaces().at( faceIndex );
     494                 :          0 :         block3d = dataset3dValues( index, nativeFaceIndex, 1 );
     495                 :          0 :       }
     496                 :          0 :     }
     497                 :          0 :   }
     498                 :          0 :   return block3d;
     499                 :          0 : }
     500                 :            : 
     501                 :          0 : QgsMeshDatasetValue QgsMeshLayer::dataset1dValue( const QgsMeshDatasetIndex &index, const QgsPointXY &point, double searchRadius ) const
     502                 :            : {
     503                 :          0 :   QgsMeshDatasetValue value;
     504                 :          0 :   QgsPointXY projectedPoint;
     505                 :          0 :   int selectedIndex = closestEdge( point, searchRadius, projectedPoint );
     506                 :          0 :   const QgsTriangularMesh *mesh = triangularMesh();
     507                 :          0 :   if ( selectedIndex >= 0 )
     508                 :            :   {
     509                 :          0 :     const QgsMeshDatasetGroupMetadata::DataType dataType = datasetGroupMetadata( index ).dataType();
     510                 :          0 :     switch ( dataType )
     511                 :            :     {
     512                 :            :       case QgsMeshDatasetGroupMetadata::DataOnEdges:
     513                 :            :       {
     514                 :          0 :         value = datasetValue( index, selectedIndex );
     515                 :            :       }
     516                 :          0 :       break;
     517                 :            : 
     518                 :            :       case QgsMeshDatasetGroupMetadata::DataOnVertices:
     519                 :            :       {
     520                 :          0 :         const QgsMeshEdge &edge = mesh->edges()[selectedIndex];
     521                 :          0 :         const int v1 = edge.first, v2 = edge.second;
     522                 :          0 :         const QgsPoint p1 = mesh->vertices()[v1], p2 = mesh->vertices()[v2];
     523                 :          0 :         const QgsMeshDatasetValue val1 = datasetValue( index, v1 );
     524                 :          0 :         const QgsMeshDatasetValue val2 = datasetValue( index, v2 );
     525                 :          0 :         double edgeLength = p1.distance( p2 );
     526                 :          0 :         double dist1 = p1.distance( projectedPoint.x(), projectedPoint.y() );
     527                 :          0 :         value = QgsMeshLayerUtils::interpolateFromVerticesData( dist1 / edgeLength, val1, val2 );
     528                 :          0 :       }
     529                 :          0 :       break;
     530                 :            :       default:
     531                 :          0 :         break;
     532                 :            :     }
     533                 :          0 :   }
     534                 :            : 
     535                 :          0 :   return value;
     536                 :          0 : }
     537                 :            : 
     538                 :          0 : void QgsMeshLayer::setTransformContext( const QgsCoordinateTransformContext &transformContext )
     539                 :            : {
     540                 :          0 :   if ( mDataProvider )
     541                 :          0 :     mDataProvider->setTransformContext( transformContext );
     542                 :          0 :   invalidateWgs84Extent();
     543                 :          0 : }
     544                 :            : 
     545                 :          0 : QgsMeshDatasetIndex QgsMeshLayer::datasetIndexAtTime( const QgsDateTimeRange &timeRange, int datasetGroupIndex ) const
     546                 :            : {
     547                 :          0 :   if ( ! mTemporalProperties->isActive() )
     548                 :          0 :     return QgsMeshDatasetIndex( datasetGroupIndex, -1 );
     549                 :            : 
     550                 :          0 :   const QDateTime layerReferenceTime = mTemporalProperties->referenceTime();
     551                 :          0 :   qint64 startTime = layerReferenceTime.msecsTo( timeRange.begin() );
     552                 :            : 
     553                 :          0 :   return  mDatasetGroupStore->datasetIndexAtTime( startTime, datasetGroupIndex, mTemporalProperties->matchingMethod() );
     554                 :          0 : }
     555                 :            : 
     556                 :          0 : QgsMeshDatasetIndex QgsMeshLayer::datasetIndexAtRelativeTime( const QgsInterval &relativeTime, int datasetGroupIndex ) const
     557                 :            : {
     558                 :          0 :   qint64 usedRelativeTime = relativeTime.seconds() * 1000;
     559                 :            : 
     560                 :            :   //adjust relative time if layer reference time is different from provider reference time
     561                 :          0 :   if ( mTemporalProperties->referenceTime().isValid() &&
     562                 :          0 :        mDataProvider &&
     563                 :          0 :        mDataProvider->isValid() &&
     564                 :          0 :        mTemporalProperties->referenceTime() != mDataProvider->temporalCapabilities()->referenceTime() )
     565                 :          0 :     usedRelativeTime = usedRelativeTime + mTemporalProperties->referenceTime().msecsTo( mDataProvider->temporalCapabilities()->referenceTime() );
     566                 :            : 
     567                 :          0 :   return  mDatasetGroupStore->datasetIndexAtTime( relativeTime.seconds() * 1000, datasetGroupIndex, mTemporalProperties->matchingMethod() );
     568                 :          0 : }
     569                 :            : 
     570                 :          0 : void QgsMeshLayer::applyClassificationOnScalarSettings( const QgsMeshDatasetGroupMetadata &meta, QgsMeshRendererScalarSettings &scalarSettings ) const
     571                 :            : {
     572                 :          0 :   if ( meta.extraOptions().contains( QStringLiteral( "classification" ) ) )
     573                 :            :   {
     574                 :          0 :     QgsColorRampShader colorRampShader = scalarSettings.colorRampShader();
     575                 :          0 :     QgsColorRamp *colorRamp = colorRampShader.sourceColorRamp();
     576                 :          0 :     QStringList classes = meta.extraOptions()[QStringLiteral( "classification" )].split( QStringLiteral( ";;" ) );
     577                 :            : 
     578                 :          0 :     QString units;
     579                 :          0 :     if ( meta.extraOptions().contains( QStringLiteral( "units" ) ) )
     580                 :          0 :       units = meta.extraOptions()[ QStringLiteral( "units" )];
     581                 :            : 
     582                 :          0 :     QVector<QVector<double>> bounds;
     583                 :          0 :     for ( const QString &classe : classes )
     584                 :            :     {
     585                 :          0 :       QStringList boundsStr = classe.split( ',' );
     586                 :          0 :       QVector<double> bound;
     587                 :          0 :       for ( const QString &boundStr : boundsStr )
     588                 :          0 :         bound.append( boundStr.toDouble() );
     589                 :          0 :       bounds.append( bound );
     590                 :          0 :     }
     591                 :            : 
     592                 :          0 :     if ( ( bounds.count() == 1  && bounds.first().count() > 2 ) || // at least a class with two value
     593                 :          0 :          ( bounds.count() > 1 ) ) // or at least two classes
     594                 :            :     {
     595                 :          0 :       const QVector<double> firstClass = bounds.first();
     596                 :          0 :       const QVector<double> lastClass = bounds.last();
     597                 :          0 :       double minValue = firstClass.count() > 1 ? ( firstClass.first() + firstClass.last() ) / 2 : firstClass.first();
     598                 :          0 :       double maxValue = lastClass.count() > 1 ? ( lastClass.first() + lastClass.last() ) / 2 : lastClass.first();
     599                 :          0 :       double diff = maxValue - minValue;
     600                 :          0 :       QList<QgsColorRampShader::ColorRampItem> colorRampItemlist;
     601                 :          0 :       for ( int i = 0; i < bounds.count(); ++i )
     602                 :            :       {
     603                 :          0 :         const QVector<double> &boundClass = bounds.at( i );
     604                 :          0 :         QgsColorRampShader::ColorRampItem item;
     605                 :          0 :         item.value = i + 1;
     606                 :          0 :         if ( !boundClass.isEmpty() )
     607                 :            :         {
     608                 :          0 :           double scalarValue = ( boundClass.first() + boundClass.last() ) / 2;
     609                 :          0 :           item.color = colorRamp->color( ( scalarValue - minValue ) / diff );
     610                 :          0 :           if ( i != 0 && i < bounds.count() - 1 ) //The first and last labels are treated after
     611                 :            :           {
     612                 :          0 :             item.label = QString( ( "%1 - %2 %3" ) ).
     613                 :          0 :                          arg( QString::number( boundClass.first() ) ).
     614                 :          0 :                          arg( QString::number( boundClass.last() ) ).
     615                 :          0 :                          arg( units );
     616                 :          0 :           }
     617                 :          0 :         }
     618                 :          0 :         colorRampItemlist.append( item );
     619                 :          0 :       }
     620                 :            :       //treat first and last labels
     621                 :          0 :       if ( firstClass.count() == 1 )
     622                 :          0 :         colorRampItemlist.first().label = QObject::tr( "below %1 %2" ).
     623                 :          0 :                                           arg( QString::number( firstClass.first() ) ).
     624                 :          0 :                                           arg( units );
     625                 :            :       else
     626                 :            :       {
     627                 :          0 :         colorRampItemlist.first().label = QString( ( "%1 - %2 %3" ) ).
     628                 :          0 :                                           arg( QString::number( firstClass.first() ) ).
     629                 :          0 :                                           arg( QString::number( firstClass.last() ) ).
     630                 :          0 :                                           arg( units );
     631                 :            :       }
     632                 :            : 
     633                 :          0 :       if ( lastClass.count() == 1 )
     634                 :          0 :         colorRampItemlist.last().label = QObject::tr( "above %1 %2" ).
     635                 :          0 :                                          arg( QString::number( lastClass.first() ) ).
     636                 :          0 :                                          arg( units );
     637                 :            :       else
     638                 :            :       {
     639                 :          0 :         colorRampItemlist.last().label = QString( ( "%1 - %2 %3" ) ).
     640                 :          0 :                                          arg( QString::number( lastClass.first() ) ).
     641                 :          0 :                                          arg( QString::number( lastClass.last() ) ).
     642                 :          0 :                                          arg( units );
     643                 :            :       }
     644                 :            : 
     645                 :          0 :       colorRampShader.setMinimumValue( 0 );
     646                 :          0 :       colorRampShader.setMaximumValue( colorRampItemlist.count() - 1 );
     647                 :          0 :       scalarSettings.setClassificationMinimumMaximum( 0, colorRampItemlist.count() - 1 );
     648                 :          0 :       colorRampShader.setColorRampItemList( colorRampItemlist );
     649                 :          0 :       colorRampShader.setColorRampType( QgsColorRampShader::Exact );
     650                 :          0 :       colorRampShader.setClassificationMode( QgsColorRampShader::EqualInterval );
     651                 :          0 :     }
     652                 :            : 
     653                 :          0 :     scalarSettings.setColorRampShader( colorRampShader );
     654                 :          0 :     scalarSettings.setDataResamplingMethod( QgsMeshRendererScalarSettings::None );
     655                 :          0 :   }
     656                 :          0 : }
     657                 :            : 
     658                 :          0 : QgsMeshDatasetIndex QgsMeshLayer::activeScalarDatasetAtTime( const QgsDateTimeRange &timeRange ) const
     659                 :            : {
     660                 :          0 :   if ( mTemporalProperties->isActive() )
     661                 :          0 :     return datasetIndexAtTime( timeRange, mRendererSettings.activeScalarDatasetGroup() );
     662                 :            :   else
     663                 :          0 :     return QgsMeshDatasetIndex( mRendererSettings.activeScalarDatasetGroup(), mStaticScalarDatasetIndex );
     664                 :          0 : }
     665                 :            : 
     666                 :          0 : QgsMeshDatasetIndex QgsMeshLayer::activeVectorDatasetAtTime( const QgsDateTimeRange &timeRange ) const
     667                 :            : {
     668                 :          0 :   if ( mTemporalProperties->isActive() )
     669                 :          0 :     return datasetIndexAtTime( timeRange, mRendererSettings.activeVectorDatasetGroup() );
     670                 :            :   else
     671                 :          0 :     return QgsMeshDatasetIndex( mRendererSettings.activeVectorDatasetGroup(), mStaticVectorDatasetIndex );
     672                 :          0 : }
     673                 :            : 
     674                 :          0 : void QgsMeshLayer::fillNativeMesh()
     675                 :            : {
     676                 :            :   Q_ASSERT( !mNativeMesh );
     677                 :            : 
     678                 :          0 :   mNativeMesh.reset( new QgsMesh() );
     679                 :            : 
     680                 :          0 :   if ( !( dataProvider() && dataProvider()->isValid() ) )
     681                 :          0 :     return;
     682                 :            : 
     683                 :          0 :   dataProvider()->populateMesh( mNativeMesh.get() );
     684                 :          0 : }
     685                 :            : 
     686                 :          0 : void QgsMeshLayer::onDatasetGroupsAdded( const QList<int> &datasetGroupIndexes )
     687                 :            : {
     688                 :            :   // assign default style to new dataset groups
     689                 :          0 :   for ( int i = 0; i < datasetGroupIndexes.count(); ++i )
     690                 :          0 :     assignDefaultStyleToDatasetGroup( datasetGroupIndexes.at( i ) );
     691                 :            : 
     692                 :          0 :   temporalProperties()->setIsActive( mDatasetGroupStore->hasTemporalCapabilities() );
     693                 :          0 :   emit rendererChanged();
     694                 :          0 : }
     695                 :            : 
     696                 :          0 : QgsMeshDatasetGroupTreeItem *QgsMeshLayer::datasetGroupTreeRootItem() const
     697                 :            : {
     698                 :          0 :   return mDatasetGroupStore->datasetGroupTreeItem();
     699                 :            : }
     700                 :            : 
     701                 :          0 : void QgsMeshLayer::setDatasetGroupTreeRootItem( QgsMeshDatasetGroupTreeItem *rootItem )
     702                 :            : {
     703                 :          0 :   mDatasetGroupStore->setDatasetGroupTreeItem( rootItem );
     704                 :          0 :   updateActiveDatasetGroups();
     705                 :          0 : }
     706                 :            : 
     707                 :          0 : int QgsMeshLayer::closestEdge( const QgsPointXY &point, double searchRadius, QgsPointXY &projectedPoint ) const
     708                 :            : {
     709                 :          0 :   QgsRectangle searchRectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
     710                 :          0 :   const QgsTriangularMesh *mesh = triangularMesh();
     711                 :            :   // search for the closest edge in search area from point
     712                 :          0 :   const QList<int> edgeIndexes = mesh->edgeIndexesForRectangle( searchRectangle );
     713                 :          0 :   int selectedIndex = -1;
     714                 :          0 :   if ( mesh->contains( QgsMesh::Edge ) &&
     715                 :          0 :        mDataProvider->isValid() )
     716                 :            :   {
     717                 :          0 :     double sqrMaxDistFromPoint = pow( searchRadius, 2 );
     718                 :          0 :     for ( const int edgeIndex : edgeIndexes )
     719                 :            :     {
     720                 :          0 :       const QgsMeshEdge &edge = mesh->edges().at( edgeIndex );
     721                 :          0 :       const QgsMeshVertex &vertex1 = mesh->vertices()[edge.first];
     722                 :          0 :       const QgsMeshVertex &vertex2 = mesh->vertices()[edge.second];
     723                 :          0 :       QgsPointXY projPoint;
     724                 :          0 :       double sqrDist = point.sqrDistToSegment( vertex1.x(), vertex1.y(), vertex2.x(), vertex2.y(), projPoint );
     725                 :          0 :       if ( sqrDist < sqrMaxDistFromPoint )
     726                 :            :       {
     727                 :          0 :         selectedIndex = edgeIndex;
     728                 :          0 :         projectedPoint = projPoint;
     729                 :          0 :         sqrMaxDistFromPoint = sqrDist;
     730                 :          0 :       }
     731                 :            :     }
     732                 :          0 :   }
     733                 :            : 
     734                 :          0 :   return selectedIndex;
     735                 :          0 : }
     736                 :            : 
     737                 :          0 : QgsMeshDatasetIndex QgsMeshLayer::staticVectorDatasetIndex() const
     738                 :            : {
     739                 :          0 :   return QgsMeshDatasetIndex( mRendererSettings.activeVectorDatasetGroup(), mStaticVectorDatasetIndex );
     740                 :            : }
     741                 :            : 
     742                 :          0 : void QgsMeshLayer::setReferenceTime( const QDateTime &referenceTime )
     743                 :            : {
     744                 :          0 :   if ( auto *lDataProvider = dataProvider() )
     745                 :          0 :     mTemporalProperties->setReferenceTime( referenceTime, lDataProvider->temporalCapabilities() );
     746                 :            :   else
     747                 :          0 :     mTemporalProperties->setReferenceTime( referenceTime, nullptr );
     748                 :          0 : }
     749                 :            : 
     750                 :          0 : void QgsMeshLayer::setTemporalMatchingMethod( const QgsMeshDataProviderTemporalCapabilities::MatchingTemporalDatasetMethod &matchingMethod )
     751                 :            : {
     752                 :          0 :   mTemporalProperties->setMatchingMethod( matchingMethod );
     753                 :          0 : }
     754                 :            : 
     755                 :          0 : QgsPointXY QgsMeshLayer::snapOnVertex( const QgsPointXY &point, double searchRadius )
     756                 :            : {
     757                 :          0 :   const QgsTriangularMesh *mesh = triangularMesh();
     758                 :          0 :   QgsPointXY exactPosition;
     759                 :          0 :   if ( !mesh )
     760                 :          0 :     return exactPosition;
     761                 :          0 :   QgsRectangle rectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
     762                 :          0 :   double maxDistance = searchRadius;
     763                 :            :   //attempt to snap on edges's vertices
     764                 :          0 :   QList<int> edgeIndexes = mesh->edgeIndexesForRectangle( rectangle );
     765                 :          0 :   for ( const int edgeIndex : edgeIndexes )
     766                 :            :   {
     767                 :          0 :     const QgsMeshEdge &edge = mesh->edges().at( edgeIndex );
     768                 :          0 :     const QgsMeshVertex &vertex1 = mesh->vertices()[edge.first];
     769                 :          0 :     const QgsMeshVertex &vertex2 = mesh->vertices()[edge.second];
     770                 :          0 :     double dist1 = point.distance( vertex1 );
     771                 :          0 :     double dist2 = point.distance( vertex2 );
     772                 :          0 :     if ( dist1 < maxDistance )
     773                 :            :     {
     774                 :          0 :       maxDistance = dist1;
     775                 :          0 :       exactPosition = vertex1;
     776                 :          0 :     }
     777                 :          0 :     if ( dist2 < maxDistance )
     778                 :            :     {
     779                 :          0 :       maxDistance = dist2;
     780                 :          0 :       exactPosition = vertex2;
     781                 :          0 :     }
     782                 :            :   }
     783                 :            : 
     784                 :            :   //attempt to snap on face's vertices
     785                 :          0 :   QList<int> faceIndexes = mesh->faceIndexesForRectangle( rectangle );
     786                 :          0 :   for ( const int faceIndex : faceIndexes )
     787                 :            :   {
     788                 :          0 :     const QgsMeshFace &face = mesh->triangles().at( faceIndex );
     789                 :          0 :     for ( int i = 0; i < 3; ++i )
     790                 :            :     {
     791                 :          0 :       const QgsMeshVertex &vertex = mesh->vertices()[face.at( i )];
     792                 :          0 :       double dist = point.distance( vertex );
     793                 :          0 :       if ( dist < maxDistance )
     794                 :            :       {
     795                 :          0 :         maxDistance = dist;
     796                 :          0 :         exactPosition = vertex;
     797                 :          0 :       }
     798                 :          0 :     }
     799                 :            :   }
     800                 :            : 
     801                 :            :   return exactPosition;
     802                 :          0 : }
     803                 :            : 
     804                 :          0 : QgsPointXY QgsMeshLayer::snapOnEdge( const QgsPointXY &point, double searchRadius )
     805                 :            : {
     806                 :          0 :   QgsPointXY projectedPoint;
     807                 :          0 :   closestEdge( point, searchRadius, projectedPoint );
     808                 :            : 
     809                 :          0 :   return projectedPoint;
     810                 :            : }
     811                 :            : 
     812                 :          0 : QgsPointXY QgsMeshLayer::snapOnFace( const QgsPointXY &point, double searchRadius )
     813                 :          0 : {
     814                 :          0 :   const QgsTriangularMesh *mesh = triangularMesh();
     815                 :          0 :   QgsPointXY centroidPosition;
     816                 :          0 :   if ( !mesh )
     817                 :          0 :     return centroidPosition;
     818                 :          0 :   QgsRectangle rectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
     819                 :          0 :   double maxDistance = std::numeric_limits<double>::max();
     820                 :            : 
     821                 :          0 :   QList<int> faceIndexes = mesh->faceIndexesForRectangle( rectangle );
     822                 :          0 :   for ( const int faceIndex : faceIndexes )
     823                 :            :   {
     824                 :          0 :     int nativefaceIndex = mesh->trianglesToNativeFaces().at( faceIndex );
     825                 :          0 :     if ( nativefaceIndex < 0 && nativefaceIndex >= mesh->faceCentroids().count() )
     826                 :          0 :       continue;
     827                 :          0 :     const QgsPointXY centroid = mesh->faceCentroids()[nativefaceIndex];
     828                 :          0 :     double dist = point.distance( centroid );
     829                 :          0 :     if ( dist < maxDistance )
     830                 :            :     {
     831                 :          0 :       maxDistance = dist;
     832                 :          0 :       centroidPosition = centroid;
     833                 :          0 :     }
     834                 :            :   }
     835                 :            : 
     836                 :            :   return centroidPosition;
     837                 :          0 : }
     838                 :            : 
     839                 :          0 : void QgsMeshLayer::resetDatasetGroupTreeItem()
     840                 :            : {
     841                 :          0 :   mDatasetGroupStore->resetDatasetGroupTreeItem();
     842                 :          0 :   updateActiveDatasetGroups();
     843                 :          0 : }
     844                 :            : 
     845                 :          0 : QgsInterval QgsMeshLayer::firstValidTimeStep() const
     846                 :            : {
     847                 :          0 :   if ( !mDataProvider )
     848                 :          0 :     return QgsInterval();
     849                 :          0 :   int groupCount = mDataProvider->datasetGroupCount();
     850                 :          0 :   for ( int i = 0; i < groupCount; ++i )
     851                 :            :   {
     852                 :          0 :     qint64 timeStep = mDataProvider->temporalCapabilities()->firstTimeStepDuration( i );
     853                 :          0 :     if ( timeStep > 0 )
     854                 :          0 :       return QgsInterval( timeStep, QgsUnitTypes::TemporalMilliseconds );
     855                 :          0 :   }
     856                 :            : 
     857                 :          0 :   return QgsInterval();
     858                 :          0 : }
     859                 :            : 
     860                 :          0 : QgsInterval QgsMeshLayer::datasetRelativeTime( const QgsMeshDatasetIndex &index )
     861                 :            : {
     862                 :          0 :   qint64 time = mDatasetGroupStore->datasetRelativeTime( index );
     863                 :            : 
     864                 :          0 :   if ( time == INVALID_MESHLAYER_TIME )
     865                 :          0 :     return QgsInterval();
     866                 :            :   else
     867                 :          0 :     return QgsInterval( time, QgsUnitTypes::TemporalMilliseconds );
     868                 :          0 : }
     869                 :            : 
     870                 :          0 : qint64 QgsMeshLayer::datasetRelativeTimeInMilliseconds( const QgsMeshDatasetIndex &index )
     871                 :            : {
     872                 :          0 :   return mDatasetGroupStore->datasetRelativeTime( index );
     873                 :            : }
     874                 :            : 
     875                 :          0 : void QgsMeshLayer::updateActiveDatasetGroups()
     876                 :            : {
     877                 :          0 :   QgsMeshDatasetGroupTreeItem *treeItem = mDatasetGroupStore->datasetGroupTreeItem();
     878                 :            : 
     879                 :          0 :   if ( !mDatasetGroupStore->datasetGroupTreeItem() )
     880                 :          0 :     return;
     881                 :            : 
     882                 :          0 :   QgsMeshRendererSettings settings = rendererSettings();
     883                 :          0 :   int oldActiveScalar = settings.activeScalarDatasetGroup();
     884                 :          0 :   int oldActiveVector = settings.activeVectorDatasetGroup();
     885                 :            : 
     886                 :          0 :   QgsMeshDatasetGroupTreeItem *activeScalarItem =
     887                 :          0 :     treeItem->childFromDatasetGroupIndex( oldActiveScalar );
     888                 :            : 
     889                 :          0 :   if ( !activeScalarItem && treeItem->childCount() > 0 )
     890                 :          0 :     activeScalarItem = treeItem->child( 0 );
     891                 :            : 
     892                 :          0 :   if ( activeScalarItem && !activeScalarItem->isEnabled() )
     893                 :            :   {
     894                 :          0 :     for ( int i = 0; i < treeItem->childCount(); ++i )
     895                 :            :     {
     896                 :          0 :       activeScalarItem = treeItem->child( i );
     897                 :          0 :       if ( activeScalarItem->isEnabled() )
     898                 :          0 :         break;
     899                 :            :       else
     900                 :          0 :         activeScalarItem = nullptr;
     901                 :          0 :     }
     902                 :          0 :   }
     903                 :            : 
     904                 :          0 :   if ( activeScalarItem )
     905                 :          0 :     settings.setActiveScalarDatasetGroup( activeScalarItem->datasetGroupIndex() );
     906                 :            :   else
     907                 :          0 :     settings.setActiveScalarDatasetGroup( -1 );
     908                 :            : 
     909                 :          0 :   QgsMeshDatasetGroupTreeItem *activeVectorItem =
     910                 :          0 :     treeItem->childFromDatasetGroupIndex( oldActiveVector );
     911                 :            : 
     912                 :          0 :   if ( !( activeVectorItem && activeVectorItem->isEnabled() ) )
     913                 :          0 :     settings.setActiveVectorDatasetGroup( -1 );
     914                 :            : 
     915                 :          0 :   setRendererSettings( settings );
     916                 :            : 
     917                 :          0 :   if ( oldActiveScalar != settings.activeScalarDatasetGroup() )
     918                 :          0 :     emit activeScalarDatasetGroupChanged( settings.activeScalarDatasetGroup() );
     919                 :          0 :   if ( oldActiveVector != settings.activeVectorDatasetGroup() )
     920                 :          0 :     emit activeVectorDatasetGroupChanged( settings.activeVectorDatasetGroup() );
     921                 :          0 : }
     922                 :            : 
     923                 :          0 : QgsPointXY QgsMeshLayer::snapOnElement( QgsMesh::ElementType elementType, const QgsPointXY &point, double searchRadius )
     924                 :            : {
     925                 :          0 :   switch ( elementType )
     926                 :            :   {
     927                 :            :     case QgsMesh::Vertex:
     928                 :          0 :       return snapOnVertex( point, searchRadius );
     929                 :            :     case QgsMesh::Edge:
     930                 :          0 :       return snapOnEdge( point, searchRadius );
     931                 :            :     case QgsMesh::Face:
     932                 :          0 :       return snapOnFace( point, searchRadius );
     933                 :            :   }
     934                 :          0 :   return QgsPointXY(); // avoid warnings
     935                 :          0 : }
     936                 :            : 
     937                 :          0 : QgsMeshDatasetIndex QgsMeshLayer::staticScalarDatasetIndex() const
     938                 :            : {
     939                 :          0 :   return QgsMeshDatasetIndex( mRendererSettings.activeScalarDatasetGroup(), mStaticScalarDatasetIndex );
     940                 :            : }
     941                 :            : 
     942                 :          0 : void QgsMeshLayer::setStaticVectorDatasetIndex( const QgsMeshDatasetIndex &staticVectorDatasetIndex )
     943                 :            : {
     944                 :          0 :   int oldActiveVector = mRendererSettings.activeVectorDatasetGroup();
     945                 :            : 
     946                 :          0 :   mStaticVectorDatasetIndex = staticVectorDatasetIndex.dataset();
     947                 :          0 :   mRendererSettings.setActiveVectorDatasetGroup( staticVectorDatasetIndex.group() );
     948                 :            : 
     949                 :          0 :   if ( oldActiveVector != mRendererSettings.activeVectorDatasetGroup() )
     950                 :          0 :     emit activeVectorDatasetGroupChanged( mRendererSettings.activeVectorDatasetGroup() );
     951                 :          0 : }
     952                 :            : 
     953                 :          0 : void QgsMeshLayer::setStaticScalarDatasetIndex( const QgsMeshDatasetIndex &staticScalarDatasetIndex )
     954                 :            : {
     955                 :          0 :   int oldActiveScalar = mRendererSettings.activeScalarDatasetGroup();
     956                 :            : 
     957                 :          0 :   mStaticScalarDatasetIndex = staticScalarDatasetIndex.dataset();
     958                 :          0 :   mRendererSettings.setActiveScalarDatasetGroup( staticScalarDatasetIndex.group() );
     959                 :            : 
     960                 :          0 :   if ( oldActiveScalar != mRendererSettings.activeScalarDatasetGroup() )
     961                 :          0 :     emit activeScalarDatasetGroupChanged( mRendererSettings.activeScalarDatasetGroup() );
     962                 :          0 : }
     963                 :            : 
     964                 :          0 : QgsMeshSimplificationSettings QgsMeshLayer::meshSimplificationSettings() const
     965                 :            : {
     966                 :          0 :   return mSimplificationSettings;
     967                 :            : }
     968                 :            : 
     969                 :          0 : void QgsMeshLayer::setMeshSimplificationSettings( const QgsMeshSimplificationSettings &simplifySettings )
     970                 :            : {
     971                 :          0 :   mSimplificationSettings = simplifySettings;
     972                 :          0 : }
     973                 :            : 
     974                 :          0 : static QgsColorRamp *_createDefaultColorRamp()
     975                 :            : {
     976                 :          0 :   QgsColorRamp *ramp = QgsStyle::defaultStyle()->colorRamp( QStringLiteral( "Plasma" ) );
     977                 :          0 :   if ( ramp )
     978                 :          0 :     return ramp;
     979                 :            : 
     980                 :            :   // definition of "Plasma" color ramp (in case it is not available in the style for some reason)
     981                 :          0 :   QVariantMap props;
     982                 :          0 :   props["color1"] = "13,8,135,255";
     983                 :          0 :   props["color2"] = "240,249,33,255";
     984                 :          0 :   props["stops"] =
     985                 :          0 :     "0.0196078;27,6,141,255:0.0392157;38,5,145,255:0.0588235;47,5,150,255:0.0784314;56,4,154,255:0.0980392;65,4,157,255:"
     986                 :            :     "0.117647;73,3,160,255:0.137255;81,2,163,255:0.156863;89,1,165,255:0.176471;97,0,167,255:0.196078;105,0,168,255:"
     987                 :            :     "0.215686;113,0,168,255:0.235294;120,1,168,255:0.254902;128,4,168,255:0.27451;135,7,166,255:0.294118;142,12,164,255:"
     988                 :            :     "0.313725;149,17,161,255:0.333333;156,23,158,255:0.352941;162,29,154,255:0.372549;168,34,150,255:0.392157;174,40,146,255:"
     989                 :            :     "0.411765;180,46,141,255:0.431373;186,51,136,255:0.45098;191,57,132,255:0.470588;196,62,127,255:0.490196;201,68,122,255:"
     990                 :            :     "0.509804;205,74,118,255:0.529412;210,79,113,255:0.54902;214,85,109,255:0.568627;218,91,105,255:0.588235;222,97,100,255:"
     991                 :            :     "0.607843;226,102,96,255:0.627451;230,108,92,255:0.647059;233,114,87,255:0.666667;237,121,83,255:0.686275;240,127,79,255:"
     992                 :            :     "0.705882;243,133,75,255:0.72549;245,140,70,255:0.745098;247,147,66,255:0.764706;249,154,62,255:0.784314;251,161,57,255:"
     993                 :            :     "0.803922;252,168,53,255:0.823529;253,175,49,255:0.843137;254,183,45,255:0.862745;254,190,42,255:0.882353;253,198,39,255:"
     994                 :            :     "0.901961;252,206,37,255:0.921569;251,215,36,255:0.941176;248,223,37,255:0.960784;246,232,38,255:0.980392;243,240,39,255";
     995                 :          0 :   return QgsGradientColorRamp::create( props );
     996                 :          0 : }
     997                 :            : 
     998                 :          0 : void QgsMeshLayer::assignDefaultStyleToDatasetGroup( int groupIndex )
     999                 :            : {
    1000                 :          0 :   const QgsMeshDatasetGroupMetadata metadata = datasetGroupMetadata( groupIndex );
    1001                 :          0 :   double groupMin = metadata.minimum();
    1002                 :          0 :   double groupMax = metadata.maximum();
    1003                 :            : 
    1004                 :          0 :   QgsColorRampShader fcn( groupMin, groupMax, _createDefaultColorRamp() );
    1005                 :          0 :   fcn.classifyColorRamp( 5, -1, QgsRectangle(), nullptr );
    1006                 :            : 
    1007                 :          0 :   QgsMeshRendererScalarSettings scalarSettings;
    1008                 :          0 :   scalarSettings.setClassificationMinimumMaximum( groupMin, groupMax );
    1009                 :          0 :   scalarSettings.setColorRampShader( fcn );
    1010                 :          0 :   QgsInterpolatedLineWidth edgeStrokeWidth;
    1011                 :          0 :   edgeStrokeWidth.setMinimumValue( groupMin );
    1012                 :          0 :   edgeStrokeWidth.setMaximumValue( groupMax );
    1013                 :          0 :   QgsInterpolatedLineColor edgeStrokeColor( fcn );
    1014                 :          0 :   QgsInterpolatedLineRenderer edgeStrokePen;
    1015                 :          0 :   scalarSettings.setEdgeStrokeWidth( edgeStrokeWidth );
    1016                 :          0 :   mRendererSettings.setScalarSettings( groupIndex, scalarSettings );
    1017                 :            : 
    1018                 :          0 :   if ( metadata.isVector() )
    1019                 :            :   {
    1020                 :          0 :     QgsMeshRendererVectorSettings vectorSettings;
    1021                 :          0 :     vectorSettings.setColorRampShader( fcn );
    1022                 :          0 :     mRendererSettings.setVectorSettings( groupIndex, vectorSettings );
    1023                 :          0 :   }
    1024                 :          0 : }
    1025                 :            : 
    1026                 :          0 : QgsMapLayerRenderer *QgsMeshLayer::createMapRenderer( QgsRenderContext &rendererContext )
    1027                 :            : {
    1028                 :            :   // Triangular mesh
    1029                 :          0 :   updateTriangularMesh( rendererContext.coordinateTransform() );
    1030                 :            : 
    1031                 :            :   // Build overview triangular meshes if needed
    1032                 :          0 :   createSimplifiedMeshes();
    1033                 :            : 
    1034                 :            :   // Cache
    1035                 :          0 :   if ( !mRendererCache )
    1036                 :          0 :     mRendererCache.reset( new QgsMeshLayerRendererCache() );
    1037                 :            : 
    1038                 :          0 :   return new QgsMeshLayerRenderer( this, rendererContext );
    1039                 :          0 : }
    1040                 :            : 
    1041                 :          0 : bool QgsMeshLayer::readSymbology( const QDomNode &node, QString &errorMessage,
    1042                 :            :                                   QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
    1043                 :            : {
    1044                 :          0 :   Q_UNUSED( errorMessage )
    1045                 :            :   // TODO: implement categories for raster layer
    1046                 :            : 
    1047                 :          0 :   QDomElement elem = node.toElement();
    1048                 :            : 
    1049                 :          0 :   readCommonStyle( elem, context, categories );
    1050                 :            : 
    1051                 :          0 :   QDomElement elemRendererSettings = elem.firstChildElement( "mesh-renderer-settings" );
    1052                 :          0 :   if ( !elemRendererSettings.isNull() )
    1053                 :          0 :     mRendererSettings.readXml( elemRendererSettings, context );
    1054                 :            : 
    1055                 :          0 :   QDomElement elemSimplifySettings = elem.firstChildElement( "mesh-simplify-settings" );
    1056                 :          0 :   if ( !elemSimplifySettings.isNull() )
    1057                 :          0 :     mSimplificationSettings.readXml( elemSimplifySettings, context );
    1058                 :            : 
    1059                 :            :   // get and set the blend mode if it exists
    1060                 :          0 :   QDomNode blendModeNode = node.namedItem( QStringLiteral( "blendMode" ) );
    1061                 :          0 :   if ( !blendModeNode.isNull() )
    1062                 :            :   {
    1063                 :          0 :     QDomElement e = blendModeNode.toElement();
    1064                 :          0 :     setBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( e.text().toInt() ) ) );
    1065                 :          0 :   }
    1066                 :            : 
    1067                 :            :   // get and set the layer transparency
    1068                 :          0 :   if ( categories.testFlag( Rendering ) )
    1069                 :            :   {
    1070                 :          0 :     QDomNode layerOpacityNode = node.namedItem( QStringLiteral( "layerOpacity" ) );
    1071                 :          0 :     if ( !layerOpacityNode.isNull() )
    1072                 :            :     {
    1073                 :          0 :       QDomElement e = layerOpacityNode.toElement();
    1074                 :          0 :       setOpacity( e.text().toDouble() );
    1075                 :          0 :     }
    1076                 :          0 :   }
    1077                 :            : 
    1078                 :            :   return true;
    1079                 :          0 : }
    1080                 :            : 
    1081                 :          0 : bool QgsMeshLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage,
    1082                 :            :                                    const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
    1083                 :            : {
    1084                 :          0 :   Q_UNUSED( errorMessage )
    1085                 :            :   // TODO: implement categories for raster layer
    1086                 :            : 
    1087                 :          0 :   QDomElement elem = node.toElement();
    1088                 :            : 
    1089                 :          0 :   writeCommonStyle( elem, doc, context, categories );
    1090                 :            : 
    1091                 :          0 :   QDomElement elemRendererSettings = mRendererSettings.writeXml( doc, context );
    1092                 :          0 :   elem.appendChild( elemRendererSettings );
    1093                 :            : 
    1094                 :          0 :   QDomElement elemSimplifySettings = mSimplificationSettings.writeXml( doc, context );
    1095                 :          0 :   elem.appendChild( elemSimplifySettings );
    1096                 :            : 
    1097                 :            :   // add blend mode node
    1098                 :          0 :   QDomElement blendModeElement  = doc.createElement( QStringLiteral( "blendMode" ) );
    1099                 :          0 :   QDomText blendModeText = doc.createTextNode( QString::number( QgsPainting::getBlendModeEnum( blendMode() ) ) );
    1100                 :          0 :   blendModeElement.appendChild( blendModeText );
    1101                 :          0 :   node.appendChild( blendModeElement );
    1102                 :            : 
    1103                 :            :   // add the layer opacity
    1104                 :          0 :   if ( categories.testFlag( Rendering ) )
    1105                 :            :   {
    1106                 :          0 :     QDomElement layerOpacityElem  = doc.createElement( QStringLiteral( "layerOpacity" ) );
    1107                 :          0 :     QDomText layerOpacityText = doc.createTextNode( QString::number( opacity() ) );
    1108                 :          0 :     layerOpacityElem.appendChild( layerOpacityText );
    1109                 :          0 :     node.appendChild( layerOpacityElem );
    1110                 :          0 :   }
    1111                 :            : 
    1112                 :            :   return true;
    1113                 :          0 : }
    1114                 :            : 
    1115                 :          0 : bool QgsMeshLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
    1116                 :            : {
    1117                 :          0 :   return writeSymbology( node, doc, errorMessage, context, categories );
    1118                 :            : }
    1119                 :            : 
    1120                 :          0 : bool QgsMeshLayer::readStyle( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
    1121                 :            : {
    1122                 :          0 :   return readSymbology( node, errorMessage, context, categories );
    1123                 :            : }
    1124                 :            : 
    1125                 :          0 : QString QgsMeshLayer::decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const
    1126                 :            : {
    1127                 :          0 :   QString src( source );
    1128                 :          0 :   if ( provider == QLatin1String( "mdal" ) )
    1129                 :            :   {
    1130                 :          0 :     src = context.pathResolver().readPath( src );
    1131                 :          0 :   }
    1132                 :          0 :   return src;
    1133                 :          0 : }
    1134                 :            : 
    1135                 :          0 : QString QgsMeshLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
    1136                 :            : {
    1137                 :          0 :   QString src( source );
    1138                 :          0 :   if ( providerType() == QLatin1String( "mdal" ) )
    1139                 :            :   {
    1140                 :          0 :     src = context.pathResolver().writePath( src );
    1141                 :          0 :   }
    1142                 :          0 :   return src;
    1143                 :          0 : }
    1144                 :            : 
    1145                 :          0 : bool QgsMeshLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &context )
    1146                 :            : {
    1147                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "Datasource in QgsMeshLayer::readXml: %1" ).arg( mDataSource.toLocal8Bit().data() ), 3 );
    1148                 :            : 
    1149                 :            :   //process provider key
    1150                 :          0 :   QDomNode pkeyNode = layer_node.namedItem( QStringLiteral( "provider" ) );
    1151                 :            : 
    1152                 :          0 :   if ( pkeyNode.isNull() )
    1153                 :            :   {
    1154                 :          0 :     mProviderKey.clear();
    1155                 :          0 :   }
    1156                 :            :   else
    1157                 :            :   {
    1158                 :          0 :     QDomElement pkeyElt = pkeyNode.toElement();
    1159                 :          0 :     mProviderKey = pkeyElt.text();
    1160                 :          0 :   }
    1161                 :            : 
    1162                 :          0 :   if ( mReadFlags & QgsMapLayer::FlagDontResolveLayers )
    1163                 :            :   {
    1164                 :          0 :     return false;
    1165                 :            :   }
    1166                 :            : 
    1167                 :          0 :   QgsDataProvider::ProviderOptions providerOptions;
    1168                 :          0 :   QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags();
    1169                 :          0 :   if ( mReadFlags & QgsMapLayer::FlagTrustLayerMetadata )
    1170                 :            :   {
    1171                 :          0 :     flags |= QgsDataProvider::FlagTrustDataSource;
    1172                 :          0 :   }
    1173                 :          0 :   if ( !setDataProvider( mProviderKey, providerOptions, flags ) )
    1174                 :            :   {
    1175                 :          0 :     return false;
    1176                 :            :   }
    1177                 :            : 
    1178                 :          0 :   QDomElement elemExtraDatasets = layer_node.firstChildElement( QStringLiteral( "extra-datasets" ) );
    1179                 :          0 :   if ( !elemExtraDatasets.isNull() )
    1180                 :            :   {
    1181                 :          0 :     QDomElement elemUri = elemExtraDatasets.firstChildElement( QStringLiteral( "uri" ) );
    1182                 :          0 :     while ( !elemUri.isNull() )
    1183                 :            :     {
    1184                 :          0 :       QString uri = context.pathResolver().readPath( elemUri.text() );
    1185                 :            : 
    1186                 :          0 :       bool res = mDataProvider->addDataset( uri );
    1187                 :            : #ifdef QGISDEBUG
    1188                 :            :       QgsDebugMsg( QStringLiteral( "extra dataset (res %1): %2" ).arg( res ).arg( uri ) );
    1189                 :            : #else
    1190                 :            :       ( void )res; // avoid unused warning in release builds
    1191                 :            : #endif
    1192                 :            : 
    1193                 :          0 :       elemUri = elemUri.nextSiblingElement( QStringLiteral( "uri" ) );
    1194                 :          0 :     }
    1195                 :          0 :   }
    1196                 :            : 
    1197                 :          0 :   if ( mDataProvider && pkeyNode.toElement().hasAttribute( QStringLiteral( "time-unit" ) ) )
    1198                 :          0 :     mDataProvider->setTemporalUnit(
    1199                 :          0 :       static_cast<QgsUnitTypes::TemporalUnit>( pkeyNode.toElement().attribute( QStringLiteral( "time-unit" ) ).toInt() ) );
    1200                 :            : 
    1201                 :            :   // read dataset group store
    1202                 :          0 :   QDomElement elemDatasetGroupsStore = layer_node.firstChildElement( QStringLiteral( "mesh-dataset-groups-store" ) );
    1203                 :          0 :   if ( elemDatasetGroupsStore.isNull() )
    1204                 :          0 :     resetDatasetGroupTreeItem();
    1205                 :            :   else
    1206                 :          0 :     mDatasetGroupStore->readXml( elemDatasetGroupsStore, context );
    1207                 :            : 
    1208                 :          0 :   QString errorMsg;
    1209                 :          0 :   readSymbology( layer_node, errorMsg, context );
    1210                 :            : 
    1211                 :          0 :   if ( !mTemporalProperties->timeExtent().begin().isValid() )
    1212                 :          0 :     temporalProperties()->setDefaultsFromDataProviderTemporalCapabilities( dataProvider()->temporalCapabilities() );
    1213                 :            : 
    1214                 :            :   // read static dataset
    1215                 :          0 :   QDomElement elemStaticDataset = layer_node.firstChildElement( QStringLiteral( "static-active-dataset" ) );
    1216                 :          0 :   if ( elemStaticDataset.hasAttribute( QStringLiteral( "scalar" ) ) )
    1217                 :            :   {
    1218                 :          0 :     mStaticScalarDatasetIndex = elemStaticDataset.attribute( QStringLiteral( "scalar" ) ).toInt();
    1219                 :          0 :   }
    1220                 :          0 :   if ( elemStaticDataset.hasAttribute( QStringLiteral( "vector" ) ) )
    1221                 :            :   {
    1222                 :          0 :     mStaticVectorDatasetIndex = elemStaticDataset.attribute( QStringLiteral( "vector" ) ).toInt();
    1223                 :          0 :   }
    1224                 :            : 
    1225                 :          0 :   return isValid(); // should be true if read successfully
    1226                 :          0 : }
    1227                 :            : 
    1228                 :          0 : bool QgsMeshLayer::writeXml( QDomNode &layer_node, QDomDocument &document, const QgsReadWriteContext &context ) const
    1229                 :            : {
    1230                 :            :   // first get the layer element so that we can append the type attribute
    1231                 :          0 :   QDomElement mapLayerNode = layer_node.toElement();
    1232                 :            : 
    1233                 :          0 :   if ( mapLayerNode.isNull() || ( QLatin1String( "maplayer" ) != mapLayerNode.nodeName() ) )
    1234                 :            :   {
    1235                 :          0 :     QgsDebugMsgLevel( QStringLiteral( "can't find <maplayer>" ), 2 );
    1236                 :          0 :     return false;
    1237                 :            :   }
    1238                 :            : 
    1239                 :          0 :   mapLayerNode.setAttribute( QStringLiteral( "type" ), QgsMapLayerFactory::typeToString( QgsMapLayerType::MeshLayer ) );
    1240                 :            : 
    1241                 :            :   // add provider node
    1242                 :          0 :   if ( mDataProvider )
    1243                 :            :   {
    1244                 :          0 :     QDomElement provider  = document.createElement( QStringLiteral( "provider" ) );
    1245                 :          0 :     QDomText providerText = document.createTextNode( providerType() );
    1246                 :          0 :     provider.appendChild( providerText );
    1247                 :          0 :     layer_node.appendChild( provider );
    1248                 :          0 :     provider.setAttribute( QStringLiteral( "time-unit" ), mDataProvider->temporalCapabilities()->temporalUnit() );
    1249                 :            : 
    1250                 :          0 :     const QStringList extraDatasetUris = mDataProvider->extraDatasets();
    1251                 :          0 :     QDomElement elemExtraDatasets = document.createElement( QStringLiteral( "extra-datasets" ) );
    1252                 :          0 :     for ( const QString &uri : extraDatasetUris )
    1253                 :            :     {
    1254                 :          0 :       QString path = context.pathResolver().writePath( uri );
    1255                 :          0 :       QDomElement elemUri = document.createElement( QStringLiteral( "uri" ) );
    1256                 :          0 :       elemUri.appendChild( document.createTextNode( path ) );
    1257                 :          0 :       elemExtraDatasets.appendChild( elemUri );
    1258                 :          0 :     }
    1259                 :          0 :     layer_node.appendChild( elemExtraDatasets );
    1260                 :          0 :   }
    1261                 :            : 
    1262                 :          0 :   QDomElement elemStaticDataset = document.createElement( QStringLiteral( "static-active-dataset" ) );
    1263                 :          0 :   elemStaticDataset.setAttribute( QStringLiteral( "scalar" ), mStaticScalarDatasetIndex );
    1264                 :          0 :   elemStaticDataset.setAttribute( QStringLiteral( "vector" ), mStaticVectorDatasetIndex );
    1265                 :          0 :   layer_node.appendChild( elemStaticDataset );
    1266                 :            : 
    1267                 :            :   // write dataset group store
    1268                 :          0 :   layer_node.appendChild( mDatasetGroupStore->writeXml( document, context ) );
    1269                 :            : 
    1270                 :            :   // renderer specific settings
    1271                 :          0 :   QString errorMsg;
    1272                 :          0 :   return writeSymbology( layer_node, document, errorMsg, context );
    1273                 :          0 : }
    1274                 :            : 
    1275                 :          0 : void QgsMeshLayer::reload()
    1276                 :            : {
    1277                 :          0 :   if ( mDataProvider && mDataProvider->isValid() )
    1278                 :            :   {
    1279                 :          0 :     mDataProvider->reloadData();
    1280                 :            : 
    1281                 :            :     //reload the mesh structure
    1282                 :          0 :     if ( !mNativeMesh )
    1283                 :          0 :       mNativeMesh.reset( new QgsMesh );
    1284                 :            : 
    1285                 :          0 :     dataProvider()->populateMesh( mNativeMesh.get() );
    1286                 :            : 
    1287                 :            :     //clear the TriangularMeshes
    1288                 :          0 :     mTriangularMeshes.clear();
    1289                 :            : 
    1290                 :            :     //clear the rendererCache
    1291                 :          0 :     mRendererCache.reset( new QgsMeshLayerRendererCache() );
    1292                 :          0 :   }
    1293                 :          0 : }
    1294                 :            : 
    1295                 :          0 : QStringList QgsMeshLayer::subLayers() const
    1296                 :            : {
    1297                 :          0 :   if ( mDataProvider )
    1298                 :          0 :     return mDataProvider->subLayers();
    1299                 :            :   else
    1300                 :          0 :     return QStringList();
    1301                 :          0 : }
    1302                 :            : 
    1303                 :          0 : QString QgsMeshLayer::htmlMetadata() const
    1304                 :            : {
    1305                 :          0 :   QgsLayerMetadataFormatter htmlFormatter( metadata() );
    1306                 :          0 :   QString myMetadata = QStringLiteral( "<html>\n<body>\n" );
    1307                 :            : 
    1308                 :            :   // Begin Provider section
    1309                 :          0 :   myMetadata += QStringLiteral( "<h1>" ) + tr( "Information from provider" ) + QStringLiteral( "</h1>\n<hr>\n" );
    1310                 :          0 :   myMetadata += QLatin1String( "<table class=\"list-view\">\n" );
    1311                 :            : 
    1312                 :            :   // name
    1313                 :          0 :   myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Name" ) + QStringLiteral( "</td><td>" ) + name() + QStringLiteral( "</td></tr>\n" );
    1314                 :            : 
    1315                 :            :   // local path
    1316                 :          0 :   QVariantMap uriComponents = QgsProviderRegistry::instance()->decodeUri( mProviderKey, publicSource() );
    1317                 :          0 :   QString path;
    1318                 :          0 :   if ( uriComponents.contains( QStringLiteral( "path" ) ) )
    1319                 :            :   {
    1320                 :          0 :     path = uriComponents[QStringLiteral( "path" )].toString();
    1321                 :          0 :     if ( QFile::exists( path ) )
    1322                 :          0 :       myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Path" ) + QStringLiteral( "</td><td>%1" ).arg( QStringLiteral( "<a href=\"%1\">%2</a>" ).arg( QUrl::fromLocalFile( path ).toString(), QDir::toNativeSeparators( path ) ) ) + QStringLiteral( "</td></tr>\n" );
    1323                 :          0 :   }
    1324                 :          0 :   if ( uriComponents.contains( QStringLiteral( "url" ) ) )
    1325                 :            :   {
    1326                 :          0 :     const QString url = uriComponents[QStringLiteral( "url" )].toString();
    1327                 :          0 :     myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "URL" ) + QStringLiteral( "</td><td>%1" ).arg( QStringLiteral( "<a href=\"%1\">%2</a>" ).arg( QUrl( url ).toString(), url ) ) + QStringLiteral( "</td></tr>\n" );
    1328                 :          0 :   }
    1329                 :            : 
    1330                 :            :   // data source
    1331                 :          0 :   if ( publicSource() != path )
    1332                 :          0 :     myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Source" ) + QStringLiteral( "</td><td>%1" ).arg( publicSource() ) + QStringLiteral( "</td></tr>\n" );
    1333                 :            : 
    1334                 :            :   // EPSG
    1335                 :          0 :   myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "CRS" ) + QStringLiteral( "</td><td>" );
    1336                 :          0 :   if ( crs().isValid() )
    1337                 :            :   {
    1338                 :          0 :     myMetadata += crs().userFriendlyIdentifier( QgsCoordinateReferenceSystem::FullString ) + QStringLiteral( " - " );
    1339                 :          0 :     if ( crs().isGeographic() )
    1340                 :          0 :       myMetadata += tr( "Geographic" );
    1341                 :            :     else
    1342                 :          0 :       myMetadata += tr( "Projected" );
    1343                 :          0 :   }
    1344                 :          0 :   myMetadata += QLatin1String( "</td></tr>\n" );
    1345                 :            : 
    1346                 :            :   // Extent
    1347                 :          0 :   myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Extent" ) + QStringLiteral( "</td><td>" ) + extent().toString() + QStringLiteral( "</td></tr>\n" );
    1348                 :            : 
    1349                 :            :   // unit
    1350                 :          0 :   myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Unit" ) + QStringLiteral( "</td><td>" ) + QgsUnitTypes::toString( crs().mapUnits() ) + QStringLiteral( "</td></tr>\n" );
    1351                 :            : 
    1352                 :            :   // feature count
    1353                 :          0 :   QLocale locale = QLocale();
    1354                 :          0 :   locale.setNumberOptions( locale.numberOptions() &= ~QLocale::NumberOption::OmitGroupSeparator );
    1355                 :            : 
    1356                 :          0 :   if ( dataProvider() )
    1357                 :            :   {
    1358                 :          0 :     myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
    1359                 :          0 :                   + tr( "Vertex count" ) + QStringLiteral( "</td><td>" )
    1360                 :          0 :                   + ( locale.toString( static_cast<qlonglong>( dataProvider()->vertexCount() ) ) )
    1361                 :          0 :                   + QStringLiteral( "</td></tr>\n" );
    1362                 :          0 :     myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
    1363                 :          0 :                   + tr( "Face count" ) + QStringLiteral( "</td><td>" )
    1364                 :          0 :                   + ( locale.toString( static_cast<qlonglong>( dataProvider()->faceCount() ) ) )
    1365                 :          0 :                   + QStringLiteral( "</td></tr>\n" );
    1366                 :          0 :     myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
    1367                 :          0 :                   + tr( "Edge count" ) + QStringLiteral( "</td><td>" )
    1368                 :          0 :                   + ( locale.toString( static_cast<qlonglong>( dataProvider()->edgeCount() ) ) )
    1369                 :          0 :                   + QStringLiteral( "</td></tr>\n" );
    1370                 :          0 :     myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
    1371                 :          0 :                   + tr( "Dataset groups count" ) + QStringLiteral( "</td><td>" )
    1372                 :          0 :                   + ( locale.toString( static_cast<qlonglong>( dataProvider()->datasetGroupCount() ) ) )
    1373                 :          0 :                   + QStringLiteral( "</td></tr>\n" );
    1374                 :          0 :   }
    1375                 :            : 
    1376                 :            :   // End Provider section
    1377                 :          0 :   myMetadata += QLatin1String( "</table>\n<br><br>" );
    1378                 :            : 
    1379                 :            :   // identification section
    1380                 :          0 :   myMetadata += QStringLiteral( "<h1>" ) + tr( "Identification" ) + QStringLiteral( "</h1>\n<hr>\n" );
    1381                 :          0 :   myMetadata += htmlFormatter.identificationSectionHtml( );
    1382                 :          0 :   myMetadata += QLatin1String( "<br><br>\n" );
    1383                 :            : 
    1384                 :            :   // extent section
    1385                 :          0 :   myMetadata += QStringLiteral( "<h1>" ) + tr( "Extent" ) + QStringLiteral( "</h1>\n<hr>\n" );
    1386                 :          0 :   myMetadata += htmlFormatter.extentSectionHtml( isSpatial() );
    1387                 :          0 :   myMetadata += QLatin1String( "<br><br>\n" );
    1388                 :            : 
    1389                 :            :   // Start the Access section
    1390                 :          0 :   myMetadata += QStringLiteral( "<h1>" ) + tr( "Access" ) + QStringLiteral( "</h1>\n<hr>\n" );
    1391                 :          0 :   myMetadata += htmlFormatter.accessSectionHtml( );
    1392                 :          0 :   myMetadata += QLatin1String( "<br><br>\n" );
    1393                 :            : 
    1394                 :            :   // Start the contacts section
    1395                 :          0 :   myMetadata += QStringLiteral( "<h1>" ) + tr( "Contacts" ) + QStringLiteral( "</h1>\n<hr>\n" );
    1396                 :          0 :   myMetadata += htmlFormatter.contactsSectionHtml( );
    1397                 :          0 :   myMetadata += QLatin1String( "<br><br>\n" );
    1398                 :            : 
    1399                 :            :   // Start the links section
    1400                 :          0 :   myMetadata += QStringLiteral( "<h1>" ) + tr( "Links" ) + QStringLiteral( "</h1>\n<hr>\n" );
    1401                 :          0 :   myMetadata += htmlFormatter.linksSectionHtml( );
    1402                 :          0 :   myMetadata += QLatin1String( "<br><br>\n" );
    1403                 :            : 
    1404                 :            :   // Start the history section
    1405                 :          0 :   myMetadata += QStringLiteral( "<h1>" ) + tr( "History" ) + QStringLiteral( "</h1>\n<hr>\n" );
    1406                 :          0 :   myMetadata += htmlFormatter.historySectionHtml( );
    1407                 :          0 :   myMetadata += QLatin1String( "<br><br>\n" );
    1408                 :            : 
    1409                 :          0 :   myMetadata += QLatin1String( "\n</body>\n</html>\n" );
    1410                 :          0 :   return myMetadata;
    1411                 :          0 : }
    1412                 :            : 
    1413                 :          0 : bool QgsMeshLayer::setDataProvider( QString const &provider, const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags )
    1414                 :            : {
    1415                 :          0 :   delete mDataProvider;
    1416                 :            : 
    1417                 :          0 :   mProviderKey = provider;
    1418                 :          0 :   QString dataSource = mDataSource;
    1419                 :            : 
    1420                 :          0 :   mDataProvider = qobject_cast<QgsMeshDataProvider *>( QgsProviderRegistry::instance()->createProvider( provider, dataSource, options, flags ) );
    1421                 :          0 :   if ( !mDataProvider )
    1422                 :            :   {
    1423                 :          0 :     QgsDebugMsgLevel( QStringLiteral( "Unable to get mesh data provider" ), 2 );
    1424                 :          0 :     return false;
    1425                 :            :   }
    1426                 :            : 
    1427                 :          0 :   mDataProvider->setParent( this );
    1428                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "Instantiated the mesh data provider plugin" ), 2 );
    1429                 :            : 
    1430                 :          0 :   setValid( mDataProvider->isValid() );
    1431                 :          0 :   if ( !isValid() )
    1432                 :            :   {
    1433                 :          0 :     QgsDebugMsgLevel( QStringLiteral( "Invalid mesh provider plugin %1" ).arg( QString( mDataSource.toUtf8() ) ), 2 );
    1434                 :          0 :     return false;
    1435                 :            :   }
    1436                 :            : 
    1437                 :          0 :   setCrs( mDataProvider->crs() );
    1438                 :            : 
    1439                 :          0 :   if ( provider == QLatin1String( "mesh_memory" ) )
    1440                 :            :   {
    1441                 :            :     // required so that source differs between memory layers
    1442                 :          0 :     mDataSource = mDataSource + QStringLiteral( "&uid=%1" ).arg( QUuid::createUuid().toString() );
    1443                 :          0 :   }
    1444                 :            : 
    1445                 :          0 :   mDatasetGroupStore->setPersistentProvider( mDataProvider );
    1446                 :            : 
    1447                 :          0 :   for ( int i = 0; i < mDataProvider->datasetGroupCount(); ++i )
    1448                 :          0 :     assignDefaultStyleToDatasetGroup( i );
    1449                 :            : 
    1450                 :          0 :   connect( mDataProvider, &QgsMeshDataProvider::dataChanged, this, &QgsMeshLayer::dataChanged );
    1451                 :            : 
    1452                 :          0 :   return true;
    1453                 :          0 : }
    1454                 :            : 
    1455                 :          0 : QgsMapLayerTemporalProperties *QgsMeshLayer::temporalProperties()
    1456                 :            : {
    1457                 :          0 :   return mTemporalProperties;
    1458                 :            : }

Generated by: LCOV version 1.14