QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
qgsmeshlayer.cpp
Go to the documentation of this file.
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"
30 #include "qgsmeshlayer.h"
31 #include "qgsmeshlayerrenderer.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"
42 
43 QgsMeshLayer::QgsMeshLayer( const QString &meshLayerPath,
44  const QString &baseName,
45  const QString &providerKey,
46  const QgsMeshLayer::LayerOptions &options )
47  : QgsMapLayer( QgsMapLayerType::MeshLayer, baseName, meshLayerPath ),
48  mDatasetGroupStore( new QgsMeshDatasetGroupStore( this ) ),
49  mTemporalProperties( new QgsMeshLayerTemporalProperties( this ) )
50 
51 {
53 
54  setProviderType( providerKey );
55  // if we’re given a provider type, try to create and bind one to this layer
56  bool ok = false;
57  if ( !meshLayerPath.isEmpty() && !providerKey.isEmpty() )
58  {
59  QgsDataProvider::ProviderOptions providerOptions { options.transformContext };
60  QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags();
62  {
64  }
65  ok = setDataProvider( providerKey, providerOptions, flags );
66  }
67 
69  if ( ok )
70  {
71  setDefaultRendererSettings( mDatasetGroupStore->datasetGroupIndexes() );
72 
73  if ( mDataProvider )
74  {
75  mTemporalProperties->setDefaultsFromDataProviderTemporalCapabilities( mDataProvider->temporalCapabilities() );
77  }
78  }
79 
80  connect( mDatasetGroupStore.get(), &QgsMeshDatasetGroupStore::datasetGroupsAdded, this, &QgsMeshLayer::onDatasetGroupsAdded );
81 }
82 
83 
84 void QgsMeshLayer::setDefaultRendererSettings( const QList<int> &groupIndexes )
85 {
86  QgsMeshRendererMeshSettings meshSettings;
87  if ( groupIndexes.count() > 0 )
88  {
89  // Show data from the first dataset group
90  mRendererSettings.setActiveScalarDatasetGroup( 0 );
91  // If the first dataset group has nan min/max, display the mesh to avoid nothing displayed
93  if ( meta.maximum() == std::numeric_limits<double>::quiet_NaN() &&
94  meta.minimum() == std::numeric_limits<double>::quiet_NaN() )
95  meshSettings.setEnabled( true );
96  }
97  else
98  {
99  // show at least the mesh by default
100  meshSettings.setEnabled( true );
101  return;
102  }
103  mRendererSettings.setNativeMeshSettings( meshSettings );
104 
105  // Sets default resample method for scalar dataset
106  for ( int i : groupIndexes )
107  {
109  QgsMeshRendererScalarSettings scalarSettings = mRendererSettings.scalarSettings( i );
110  switch ( meta.dataType() )
111  {
113  case QgsMeshDatasetGroupMetadata::DataOnVolumes: // data on volumes are averaged to 2D data on faces
115  break;
118  break;
120  break;
121  }
122 
123  //override color ramp if the values in the dataset group are classified
124  applyClassificationOnScalarSettings( meta, scalarSettings );
125 
126  mRendererSettings.setScalarSettings( i, scalarSettings );
127  }
128 
129 }
130 
131 void QgsMeshLayer::createSimplifiedMeshes()
132 {
133  if ( mSimplificationSettings.isEnabled() && !hasSimplifiedMeshes() )
134  {
135  double reductionFactor = mSimplificationSettings.reductionFactor();
136 
137  QVector<QgsTriangularMesh *> simplifyMeshes =
138  mTriangularMeshes[0]->simplifyMesh( reductionFactor );
139 
140  for ( int i = 0; i < simplifyMeshes.count() ; ++i )
141  {
142  mTriangularMeshes.emplace_back( simplifyMeshes[i] );
143  }
144  }
145 }
146 
147 bool QgsMeshLayer::hasSimplifiedMeshes() const
148 {
149  //First mesh is the base mesh, so if size>1, there is no simplified meshes
150  return ( mTriangularMeshes.size() > 1 );
151 }
152 
154 {
155  delete mDataProvider;
156 }
157 
159 {
160  return mDataProvider;
161 }
162 
164 {
165  return mDataProvider;
166 }
167 
169 {
171  if ( mDataProvider )
172  {
173  options.transformContext = mDataProvider->transformContext();
174  }
175  QgsMeshLayer *layer = new QgsMeshLayer( source(), name(), mProviderKey, options );
176  QgsMapLayer::clone( layer );
177  return layer;
178 }
179 
181 {
182  if ( mDataProvider )
183  return mDataProvider->extent();
184  else
185  {
186  QgsRectangle rec;
187  rec.setMinimal();
188  return rec;
189  }
190 }
191 
193 {
194  return mProviderKey;
195 }
196 
197 bool QgsMeshLayer::addDatasets( const QString &path, const QDateTime &defaultReferenceTime )
198 {
199  bool isTemporalBefore = dataProvider()->temporalCapabilities()->hasTemporalCapabilities();
200  if ( mDatasetGroupStore->addPersistentDatasets( path ) )
201  {
202  QgsMeshLayerTemporalProperties *temporalProperties = qobject_cast< QgsMeshLayerTemporalProperties * >( mTemporalProperties );
203  if ( !isTemporalBefore && dataProvider()->temporalCapabilities()->hasTemporalCapabilities() )
204  {
206  dataProvider()->temporalCapabilities() );
207 
208  if ( ! temporalProperties->referenceTime().isValid() )
209  {
210  QDateTime referenceTime = defaultReferenceTime;
211  if ( !defaultReferenceTime.isValid() ) // If project reference time is invalid, use current date
212  referenceTime = QDateTime( QDate::currentDate(), QTime( 0, 0, 0 ), Qt::UTC );
213  temporalProperties->setReferenceTime( referenceTime, dataProvider()->temporalCapabilities() );
214  }
215 
216  mTemporalProperties->setIsActive( true );
217  }
218  emit dataSourceChanged();
219  return true;
220  }
221 
222  return false;
223 }
224 
226 {
227  if ( mDatasetGroupStore->addDatasetGroup( datasetGroup ) )
228  {
229  emit dataChanged();
230  return true;
231  }
232  return false;
233 }
234 
235 bool QgsMeshLayer::saveDataset( const QString &path, int datasetGroupIndex, QString driver )
236 {
237  return mDatasetGroupStore->saveDatasetGroup( path, datasetGroupIndex, driver );
238 }
239 
241 {
242  return mNativeMesh.get();
243 }
244 
246 {
247  return mNativeMesh.get();
248 }
249 
250 QgsTriangularMesh *QgsMeshLayer::triangularMesh( double minimumTriangleSize ) const
251 {
252  for ( const std::unique_ptr<QgsTriangularMesh> &lod : mTriangularMeshes )
253  {
254  if ( lod && lod->averageTriangleSize() > minimumTriangleSize )
255  return lod.get();
256  }
257 
258  if ( !mTriangularMeshes.empty() )
259  return mTriangularMeshes.back().get();
260  else
261  return nullptr;
262 }
263 
265 {
266  return mTriangularMeshes.size();
267 }
268 
270 {
271  if ( mTriangularMeshes.empty() )
272  return nullptr;
273  if ( lodIndex < 0 )
274  return mTriangularMeshes.front().get();
275 
276  if ( lodIndex >= int( mTriangularMeshes.size() ) )
277  return mTriangularMeshes.back().get();
278 
279  return mTriangularMeshes.at( lodIndex ).get();
280 }
281 
283 {
284  // Native mesh
285  if ( !mNativeMesh )
286  {
287  // lazy loading of mesh data
288  fillNativeMesh();
289  }
290 
291  // Triangular mesh
292  if ( mTriangularMeshes.empty() )
293  {
294  QgsTriangularMesh *baseMesh = new QgsTriangularMesh;
295  mTriangularMeshes.emplace_back( baseMesh );
296  }
297 
298  if ( mTriangularMeshes[0].get()->update( mNativeMesh.get(), transform ) )
299  mTriangularMeshes.resize( 1 ); //if the base triangular mesh is effectivly updated, remove simplified meshes
300 
301  createSimplifiedMeshes();
302 }
303 
304 QgsMeshLayerRendererCache *QgsMeshLayer::rendererCache()
305 {
306  return mRendererCache.get();
307 }
308 
310 {
311  return mRendererSettings;
312 }
313 
315 {
316  int oldActiveScalar = mRendererSettings.activeScalarDatasetGroup();
317  int oldActiveVector = mRendererSettings.activeVectorDatasetGroup();
318  mRendererSettings = settings;
319 
320  if ( oldActiveScalar != mRendererSettings.activeScalarDatasetGroup() )
321  emit activeScalarDatasetGroupChanged( mRendererSettings.activeScalarDatasetGroup() );
322 
323  if ( oldActiveVector != mRendererSettings.activeVectorDatasetGroup() )
324  emit activeVectorDatasetGroupChanged( mRendererSettings.activeVectorDatasetGroup() );
325 
326  emit rendererChanged();
327  triggerRepaint();
328 }
329 
331 {
332  return mTimeSettings;
333 }
334 
336 {
337  mTimeSettings = settings;
338  emit timeSettingsChanged();
339 }
340 
341 QString QgsMeshLayer::formatTime( double hours )
342 {
343  if ( dataProvider() && dataProvider()->temporalCapabilities()->hasReferenceTime() )
344  return QgsMeshLayerUtils::formatTime( hours, mTemporalProperties->referenceTime(), mTimeSettings );
345  else
346  return QgsMeshLayerUtils::formatTime( hours, QDateTime(), mTimeSettings );
347 }
348 
350 {
351  return mDatasetGroupStore->datasetGroupCount();
352 }
353 
355 {
356  return mDatasetGroupStore->extraDatasetGroupCount();
357 }
358 
360 {
361  return mDatasetGroupStore->datasetGroupIndexes();
362 }
363 
365 {
366  return mDatasetGroupStore->enabledDatasetGroupIndexes();
367 }
368 
370 {
371  return mDatasetGroupStore->datasetGroupMetadata( index );
372 }
373 
375 {
376  return mDatasetGroupStore->datasetCount( index.group() );
377 }
378 
380 {
381  return mDatasetGroupStore->datasetMetadata( index );
382 }
383 
385 {
386  return mDatasetGroupStore->datasetValue( index, valueIndex );
387 }
388 
389 QgsMeshDataBlock QgsMeshLayer::datasetValues( const QgsMeshDatasetIndex &index, int valueIndex, int count ) const
390 {
391  return mDatasetGroupStore->datasetValues( index, valueIndex, count );
392 }
393 
394 QgsMesh3dDataBlock QgsMeshLayer::dataset3dValues( const QgsMeshDatasetIndex &index, int faceIndex, int count ) const
395 {
396  return mDatasetGroupStore->dataset3dValues( index, faceIndex, count );
397 }
398 
399 QgsMeshDataBlock QgsMeshLayer::areFacesActive( const QgsMeshDatasetIndex &index, int faceIndex, int count ) const
400 {
401  return mDatasetGroupStore->areFacesActive( index, faceIndex, count );
402 }
403 
404 bool QgsMeshLayer::isFaceActive( const QgsMeshDatasetIndex &index, int faceIndex ) const
405 {
406  return mDatasetGroupStore->isFaceActive( index, faceIndex );
407 }
408 
409 QgsMeshDatasetValue QgsMeshLayer::datasetValue( const QgsMeshDatasetIndex &index, const QgsPointXY &point, double searchRadius ) const
410 {
411  QgsMeshDatasetValue value;
412  const QgsTriangularMesh *mesh = triangularMesh();
413 
414  if ( mesh && dataProvider() && dataProvider()->isValid() && index.isValid() )
415  {
416  if ( dataProvider()->contains( QgsMesh::ElementType::Edge ) )
417  {
418  QgsRectangle searchRectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
419  return dataset1dValue( index, point, searchRadius );
420  }
421  int faceIndex = mesh->faceIndexForPoint_v2( point ) ;
422  if ( faceIndex >= 0 )
423  {
424  int nativeFaceIndex = mesh->trianglesToNativeFaces().at( faceIndex );
426  if ( isFaceActive( index, nativeFaceIndex ) )
427  {
428  switch ( dataType )
429  {
431  {
432  value = datasetValue( index, nativeFaceIndex );
433  }
434  break;
435 
437  {
438  const QgsMeshFace &face = mesh->triangles()[faceIndex];
439  const int v1 = face[0], v2 = face[1], v3 = face[2];
440  const QgsPoint p1 = mesh->vertices()[v1], p2 = mesh->vertices()[v2], p3 = mesh->vertices()[v3];
441  const QgsMeshDatasetValue val1 = datasetValue( index, v1 );
442  const QgsMeshDatasetValue val2 = datasetValue( index, v2 );
443  const QgsMeshDatasetValue val3 = datasetValue( index, v3 );
444  const double x = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.x(), val2.x(), val3.x(), point );
445  double y = std::numeric_limits<double>::quiet_NaN();
446  bool isVector = datasetGroupMetadata( index ).isVector();
447  if ( isVector )
448  y = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.y(), val2.y(), val3.y(), point );
449 
450  value = QgsMeshDatasetValue( x, y );
451  }
452  break;
453 
455  {
456  const QgsMesh3dAveragingMethod *avgMethod = mRendererSettings.averagingMethod();
457  if ( avgMethod )
458  {
459  const QgsMesh3dDataBlock block3d = dataset3dValues( index, nativeFaceIndex, 1 );
460  const QgsMeshDataBlock block2d = avgMethod->calculate( block3d );
461  if ( block2d.isValid() )
462  {
463  value = block2d.value( 0 );
464  }
465  }
466  }
467  break;
468 
469  default:
470  break;
471  }
472  }
473  }
474  }
475 
476  return value;
477 }
478 
480 {
481  QgsMesh3dDataBlock block3d;
482 
483  const QgsTriangularMesh *baseTriangularMesh = triangularMesh();
484 
485  if ( baseTriangularMesh && dataProvider() && dataProvider()->isValid() && index.isValid() )
486  {
489  {
490  int faceIndex = baseTriangularMesh->faceIndexForPoint_v2( point );
491  if ( faceIndex >= 0 )
492  {
493  int nativeFaceIndex = baseTriangularMesh->trianglesToNativeFaces().at( faceIndex );
494  block3d = dataset3dValues( index, nativeFaceIndex, 1 );
495  }
496  }
497  }
498  return block3d;
499 }
500 
501 QgsMeshDatasetValue QgsMeshLayer::dataset1dValue( const QgsMeshDatasetIndex &index, const QgsPointXY &point, double searchRadius ) const
502 {
503  QgsMeshDatasetValue value;
504  QgsPointXY projectedPoint;
505  int selectedIndex = closestEdge( point, searchRadius, projectedPoint );
506  const QgsTriangularMesh *mesh = triangularMesh();
507  if ( selectedIndex >= 0 )
508  {
510  switch ( dataType )
511  {
513  {
514  value = datasetValue( index, selectedIndex );
515  }
516  break;
517 
519  {
520  const QgsMeshEdge &edge = mesh->edges()[selectedIndex];
521  const int v1 = edge.first, v2 = edge.second;
522  const QgsPoint p1 = mesh->vertices()[v1], p2 = mesh->vertices()[v2];
523  const QgsMeshDatasetValue val1 = datasetValue( index, v1 );
524  const QgsMeshDatasetValue val2 = datasetValue( index, v2 );
525  double edgeLength = p1.distance( p2 );
526  double dist1 = p1.distance( projectedPoint.x(), projectedPoint.y() );
527  value = QgsMeshLayerUtils::interpolateFromVerticesData( dist1 / edgeLength, val1, val2 );
528  }
529  break;
530  default:
531  break;
532  }
533  }
534 
535  return value;
536 }
537 
539 {
540  if ( mDataProvider )
541  mDataProvider->setTransformContext( transformContext );
542 }
543 
544 QgsMeshDatasetIndex QgsMeshLayer::datasetIndexAtTime( const QgsDateTimeRange &timeRange, int datasetGroupIndex ) const
545 {
546  if ( ! mTemporalProperties->isActive() )
547  return QgsMeshDatasetIndex( datasetGroupIndex, -1 );
548 
549  const QDateTime layerReferenceTime = mTemporalProperties->referenceTime();
550  qint64 startTime = layerReferenceTime.msecsTo( timeRange.begin() );
551 
552  return mDatasetGroupStore->datasetIndexAtTime( startTime, datasetGroupIndex, mTemporalProperties->matchingMethod() );
553 }
554 
555 QgsMeshDatasetIndex QgsMeshLayer::datasetIndexAtRelativeTime( const QgsInterval &relativeTime, int datasetGroupIndex ) const
556 {
557  qint64 usedRelativeTime = relativeTime.seconds() * 1000;
558 
559  //adjust relative time if layer reference time is different from provider reference time
560  if ( mTemporalProperties->referenceTime().isValid() &&
561  mDataProvider &&
562  mDataProvider->isValid() &&
563  mTemporalProperties->referenceTime() != mDataProvider->temporalCapabilities()->referenceTime() )
564  usedRelativeTime = usedRelativeTime + mTemporalProperties->referenceTime().msecsTo( mDataProvider->temporalCapabilities()->referenceTime() );
565 
566  return mDatasetGroupStore->datasetIndexAtTime( relativeTime.seconds() * 1000, datasetGroupIndex, mTemporalProperties->matchingMethod() );
567 }
568 
569 void QgsMeshLayer::applyClassificationOnScalarSettings( const QgsMeshDatasetGroupMetadata &meta, QgsMeshRendererScalarSettings &scalarSettings ) const
570 {
571  if ( meta.extraOptions().contains( QStringLiteral( "classification" ) ) )
572  {
573  QgsColorRampShader colorRampShader = scalarSettings.colorRampShader();
574  QgsColorRamp *colorRamp = colorRampShader.sourceColorRamp();
575  QStringList classes = meta.extraOptions()[QStringLiteral( "classification" )].split( QStringLiteral( ";;" ) );
576 
577  QString units;
578  if ( meta.extraOptions().contains( QStringLiteral( "units" ) ) )
579  units = meta.extraOptions()[ QStringLiteral( "units" )];
580 
581  QVector<QVector<double>> bounds;
582  for ( const QString &classe : classes )
583  {
584  QStringList boundsStr = classe.split( ',' );
585  QVector<double> bound;
586  for ( const QString &boundStr : boundsStr )
587  bound.append( boundStr.toDouble() );
588  bounds.append( bound );
589  }
590 
591  if ( ( bounds.count() == 1 && bounds.first().count() > 2 ) || // at least a class with two value
592  ( bounds.count() > 1 ) ) // or at least two classes
593  {
594  const QVector<double> firstClass = bounds.first();
595  const QVector<double> lastClass = bounds.last();
596  double minValue = firstClass.count() > 1 ? ( firstClass.first() + firstClass.last() ) / 2 : firstClass.first();
597  double maxValue = lastClass.count() > 1 ? ( lastClass.first() + lastClass.last() ) / 2 : lastClass.first();
598  double diff = maxValue - minValue;
599  QList<QgsColorRampShader::ColorRampItem> colorRampItemlist;
600  for ( int i = 0; i < bounds.count(); ++i )
601  {
602  const QVector<double> &boundClass = bounds.at( i );
604  item.value = i + 1;
605  if ( !boundClass.isEmpty() )
606  {
607  double scalarValue = ( boundClass.first() + boundClass.last() ) / 2;
608  item.color = colorRamp->color( ( scalarValue - minValue ) / diff );
609  if ( i != 0 && i < bounds.count() - 1 ) //The first and last labels are treated after
610  {
611  item.label = QString( ( "%1 - %2 %3" ) ).
612  arg( QString::number( boundClass.first() ) ).
613  arg( QString::number( boundClass.last() ) ).
614  arg( units );
615  }
616  }
617  colorRampItemlist.append( item );
618  }
619  //treat first and last labels
620  if ( firstClass.count() == 1 )
621  colorRampItemlist.first().label = QObject::tr( "below %1 %2" ).
622  arg( QString::number( firstClass.first() ) ).
623  arg( units );
624  else
625  {
626  colorRampItemlist.first().label = QString( ( "%1 - %2 %3" ) ).
627  arg( QString::number( firstClass.first() ) ).
628  arg( QString::number( firstClass.last() ) ).
629  arg( units );
630  }
631 
632  if ( lastClass.count() == 1 )
633  colorRampItemlist.last().label = QObject::tr( "above %1 %2" ).
634  arg( QString::number( lastClass.first() ) ).
635  arg( units );
636  else
637  {
638  colorRampItemlist.last().label = QString( ( "%1 - %2 %3" ) ).
639  arg( QString::number( lastClass.first() ) ).
640  arg( QString::number( lastClass.last() ) ).
641  arg( units );
642  }
643 
644  colorRampShader.setMinimumValue( 0 );
645  colorRampShader.setMaximumValue( colorRampItemlist.count() - 1 );
646  scalarSettings.setClassificationMinimumMaximum( 0, colorRampItemlist.count() - 1 );
647  colorRampShader.setColorRampItemList( colorRampItemlist );
648  colorRampShader.setColorRampType( QgsColorRampShader::Exact );
650  }
651 
652  scalarSettings.setColorRampShader( colorRampShader );
654  }
655 }
656 
657 QgsMeshDatasetIndex QgsMeshLayer::activeScalarDatasetAtTime( const QgsDateTimeRange &timeRange ) const
658 {
659  if ( mTemporalProperties->isActive() )
660  return datasetIndexAtTime( timeRange, mRendererSettings.activeScalarDatasetGroup() );
661  else
662  return QgsMeshDatasetIndex( mRendererSettings.activeScalarDatasetGroup(), mStaticScalarDatasetIndex );
663 }
664 
665 QgsMeshDatasetIndex QgsMeshLayer::activeVectorDatasetAtTime( const QgsDateTimeRange &timeRange ) const
666 {
667  if ( mTemporalProperties->isActive() )
668  return datasetIndexAtTime( timeRange, mRendererSettings.activeVectorDatasetGroup() );
669  else
670  return QgsMeshDatasetIndex( mRendererSettings.activeVectorDatasetGroup(), mStaticVectorDatasetIndex );
671 }
672 
673 void QgsMeshLayer::fillNativeMesh()
674 {
675  Q_ASSERT( !mNativeMesh );
676 
677  mNativeMesh.reset( new QgsMesh() );
678 
679  if ( !( dataProvider() && dataProvider()->isValid() ) )
680  return;
681 
682  dataProvider()->populateMesh( mNativeMesh.get() );
683 }
684 
685 void QgsMeshLayer::onDatasetGroupsAdded( const QList<int> &datasetGroupIndexes )
686 {
687  // assign default style to new dataset groups
688  for ( int i = 0; i < datasetGroupIndexes.count(); ++i )
689  assignDefaultStyleToDatasetGroup( datasetGroupIndexes.at( i ) );
690 
691  temporalProperties()->setIsActive( mDatasetGroupStore->hasTemporalCapabilities() );
692  emit rendererChanged();
693 }
694 
696 {
697  return mDatasetGroupStore->datasetGroupTreeItem();
698 }
699 
701 {
702  mDatasetGroupStore->setDatasetGroupTreeItem( rootItem );
703  updateActiveDatasetGroups();
704 }
705 
706 int QgsMeshLayer::closestEdge( const QgsPointXY &point, double searchRadius, QgsPointXY &projectedPoint ) const
707 {
708  QgsRectangle searchRectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
709  const QgsTriangularMesh *mesh = triangularMesh();
710  // search for the closest edge in search area from point
711  const QList<int> edgeIndexes = mesh->edgeIndexesForRectangle( searchRectangle );
712  int selectedIndex = -1;
713  if ( mesh->contains( QgsMesh::Edge ) &&
714  mDataProvider->isValid() )
715  {
716  double sqrMaxDistFromPoint = pow( searchRadius, 2 );
717  for ( const int edgeIndex : edgeIndexes )
718  {
719  const QgsMeshEdge &edge = mesh->edges().at( edgeIndex );
720  const QgsMeshVertex &vertex1 = mesh->vertices()[edge.first];
721  const QgsMeshVertex &vertex2 = mesh->vertices()[edge.second];
722  QgsPointXY projPoint;
723  double sqrDist = point.sqrDistToSegment( vertex1.x(), vertex1.y(), vertex2.x(), vertex2.y(), projPoint );
724  if ( sqrDist < sqrMaxDistFromPoint )
725  {
726  selectedIndex = edgeIndex;
727  projectedPoint = projPoint;
728  sqrMaxDistFromPoint = sqrDist;
729  }
730  }
731  }
732 
733  return selectedIndex;
734 }
735 
737 {
738  return QgsMeshDatasetIndex( mRendererSettings.activeVectorDatasetGroup(), mStaticVectorDatasetIndex );
739 }
740 
741 void QgsMeshLayer::setReferenceTime( const QDateTime &referenceTime )
742 {
743  if ( auto *lDataProvider = dataProvider() )
744  mTemporalProperties->setReferenceTime( referenceTime, lDataProvider->temporalCapabilities() );
745  else
746  mTemporalProperties->setReferenceTime( referenceTime, nullptr );
747 }
748 
750 {
751  mTemporalProperties->setMatchingMethod( matchingMethod );
752 }
753 
754 QgsPointXY QgsMeshLayer::snapOnVertex( const QgsPointXY &point, double searchRadius )
755 {
756  const QgsTriangularMesh *mesh = triangularMesh();
757  QgsPointXY exactPosition;
758  if ( !mesh )
759  return exactPosition;
760  QgsRectangle rectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
761  double maxDistance = searchRadius;
762  //attempt to snap on edges's vertices
763  QList<int> edgeIndexes = mesh->edgeIndexesForRectangle( rectangle );
764  for ( const int edgeIndex : edgeIndexes )
765  {
766  const QgsMeshEdge &edge = mesh->edges().at( edgeIndex );
767  const QgsMeshVertex &vertex1 = mesh->vertices()[edge.first];
768  const QgsMeshVertex &vertex2 = mesh->vertices()[edge.second];
769  double dist1 = point.distance( vertex1 );
770  double dist2 = point.distance( vertex2 );
771  if ( dist1 < maxDistance )
772  {
773  maxDistance = dist1;
774  exactPosition = vertex1;
775  }
776  if ( dist2 < maxDistance )
777  {
778  maxDistance = dist2;
779  exactPosition = vertex2;
780  }
781  }
782 
783  //attempt to snap on face's vertices
784  QList<int> faceIndexes = mesh->faceIndexesForRectangle( rectangle );
785  for ( const int faceIndex : faceIndexes )
786  {
787  const QgsMeshFace &face = mesh->triangles().at( faceIndex );
788  for ( int i = 0; i < 3; ++i )
789  {
790  const QgsMeshVertex &vertex = mesh->vertices()[face.at( i )];
791  double dist = point.distance( vertex );
792  if ( dist < maxDistance )
793  {
794  maxDistance = dist;
795  exactPosition = vertex;
796  }
797  }
798  }
799 
800  return exactPosition;
801 }
802 
803 QgsPointXY QgsMeshLayer::snapOnEdge( const QgsPointXY &point, double searchRadius )
804 {
805  QgsPointXY projectedPoint;
806  closestEdge( point, searchRadius, projectedPoint );
807 
808  return projectedPoint;
809 }
810 
811 QgsPointXY QgsMeshLayer::snapOnFace( const QgsPointXY &point, double searchRadius )
812 {
813  const QgsTriangularMesh *mesh = triangularMesh();
814  QgsPointXY centroidPosition;
815  if ( !mesh )
816  return centroidPosition;
817  QgsRectangle rectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
818  double maxDistance = std::numeric_limits<double>::max();
819 
820  QList<int> faceIndexes = mesh->faceIndexesForRectangle( rectangle );
821  for ( const int faceIndex : faceIndexes )
822  {
823  int nativefaceIndex = mesh->trianglesToNativeFaces().at( faceIndex );
824  if ( nativefaceIndex < 0 && nativefaceIndex >= mesh->faceCentroids().count() )
825  continue;
826  const QgsPointXY centroid = mesh->faceCentroids()[nativefaceIndex];
827  double dist = point.distance( centroid );
828  if ( dist < maxDistance )
829  {
830  maxDistance = dist;
831  centroidPosition = centroid;
832  }
833  }
834 
835  return centroidPosition;
836 }
837 
839 {
840  mDatasetGroupStore->resetDatasetGroupTreeItem();
841  updateActiveDatasetGroups();
842 }
843 
845 {
846  if ( !mDataProvider )
847  return QgsInterval();
848  int groupCount = mDataProvider->datasetGroupCount();
849  for ( int i = 0; i < groupCount; ++i )
850  {
851  qint64 timeStep = mDataProvider->temporalCapabilities()->firstTimeStepDuration( i );
852  if ( timeStep > 0 )
854  }
855 
856  return QgsInterval();
857 }
858 
860 {
861  qint64 time = mDatasetGroupStore->datasetRelativeTime( index );
862 
863  if ( time == INVALID_MESHLAYER_TIME )
864  return QgsInterval();
865  else
867 }
868 
870 {
871  return mDatasetGroupStore->datasetRelativeTime( index );
872 }
873 
874 void QgsMeshLayer::updateActiveDatasetGroups()
875 {
876  QgsMeshDatasetGroupTreeItem *treeItem = mDatasetGroupStore->datasetGroupTreeItem();
877 
878  if ( !mDatasetGroupStore->datasetGroupTreeItem() )
879  return;
880 
882  int oldActiveScalar = settings.activeScalarDatasetGroup();
883  int oldActiveVector = settings.activeVectorDatasetGroup();
884 
885  QgsMeshDatasetGroupTreeItem *activeScalarItem =
886  treeItem->childFromDatasetGroupIndex( oldActiveScalar );
887 
888  if ( !activeScalarItem && treeItem->childCount() > 0 )
889  activeScalarItem = treeItem->child( 0 );
890 
891  if ( activeScalarItem && !activeScalarItem->isEnabled() )
892  {
893  for ( int i = 0; i < treeItem->childCount(); ++i )
894  {
895  activeScalarItem = treeItem->child( i );
896  if ( activeScalarItem->isEnabled() )
897  break;
898  else
899  activeScalarItem = nullptr;
900  }
901  }
902 
903  if ( activeScalarItem )
904  settings.setActiveScalarDatasetGroup( activeScalarItem->datasetGroupIndex() );
905  else
906  settings.setActiveScalarDatasetGroup( -1 );
907 
908  QgsMeshDatasetGroupTreeItem *activeVectorItem =
909  treeItem->childFromDatasetGroupIndex( oldActiveVector );
910 
911  if ( !( activeVectorItem && activeVectorItem->isEnabled() ) )
912  settings.setActiveVectorDatasetGroup( -1 );
913 
914  setRendererSettings( settings );
915 
916  if ( oldActiveScalar != settings.activeScalarDatasetGroup() )
918  if ( oldActiveVector != settings.activeVectorDatasetGroup() )
920 }
921 
922 QgsPointXY QgsMeshLayer::snapOnElement( QgsMesh::ElementType elementType, const QgsPointXY &point, double searchRadius )
923 {
924  switch ( elementType )
925  {
926  case QgsMesh::Vertex:
927  return snapOnVertex( point, searchRadius );
928  case QgsMesh::Edge:
929  return snapOnEdge( point, searchRadius );
930  case QgsMesh::Face:
931  return snapOnFace( point, searchRadius );
932  }
933  return QgsPointXY(); // avoid warnings
934 }
935 
937 {
938  return QgsMeshDatasetIndex( mRendererSettings.activeScalarDatasetGroup(), mStaticScalarDatasetIndex );
939 }
940 
941 void QgsMeshLayer::setStaticVectorDatasetIndex( const QgsMeshDatasetIndex &staticVectorDatasetIndex )
942 {
943  int oldActiveVector = mRendererSettings.activeVectorDatasetGroup();
944 
945  mStaticVectorDatasetIndex = staticVectorDatasetIndex.dataset();
947 
948  if ( oldActiveVector != mRendererSettings.activeVectorDatasetGroup() )
949  emit activeVectorDatasetGroupChanged( mRendererSettings.activeVectorDatasetGroup() );
950 }
951 
952 void QgsMeshLayer::setStaticScalarDatasetIndex( const QgsMeshDatasetIndex &staticScalarDatasetIndex )
953 {
954  int oldActiveScalar = mRendererSettings.activeScalarDatasetGroup();
955 
956  mStaticScalarDatasetIndex = staticScalarDatasetIndex.dataset();
958 
959  if ( oldActiveScalar != mRendererSettings.activeScalarDatasetGroup() )
960  emit activeScalarDatasetGroupChanged( mRendererSettings.activeScalarDatasetGroup() );
961 }
962 
964 {
965  return mSimplificationSettings;
966 }
967 
969 {
970  mSimplificationSettings = simplifySettings;
971 }
972 
973 static QgsColorRamp *_createDefaultColorRamp()
974 {
975  QgsColorRamp *ramp = QgsStyle::defaultStyle()->colorRamp( QStringLiteral( "Plasma" ) );
976  if ( ramp )
977  return ramp;
978 
979  // definition of "Plasma" color ramp (in case it is not available in the style for some reason)
980  QVariantMap props;
981  props["color1"] = "13,8,135,255";
982  props["color2"] = "240,249,33,255";
983  props["stops"] =
984  "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:"
985  "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:"
986  "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:"
987  "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:"
988  "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:"
989  "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:"
990  "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:"
991  "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:"
992  "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:"
993  "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";
994  return QgsGradientColorRamp::create( props );
995 }
996 
997 void QgsMeshLayer::assignDefaultStyleToDatasetGroup( int groupIndex )
998 {
1000  double groupMin = metadata.minimum();
1001  double groupMax = metadata.maximum();
1002 
1003  QgsColorRampShader fcn( groupMin, groupMax, _createDefaultColorRamp() );
1004  fcn.classifyColorRamp( 5, -1, QgsRectangle(), nullptr );
1005 
1006  QgsMeshRendererScalarSettings scalarSettings;
1007  scalarSettings.setClassificationMinimumMaximum( groupMin, groupMax );
1008  scalarSettings.setColorRampShader( fcn );
1009  QgsInterpolatedLineWidth edgeStrokeWidth;
1010  edgeStrokeWidth.setMinimumValue( groupMin );
1011  edgeStrokeWidth.setMaximumValue( groupMax );
1012  QgsInterpolatedLineColor edgeStrokeColor( fcn );
1013  QgsInterpolatedLineRenderer edgeStrokePen;
1014  scalarSettings.setEdgeStrokeWidth( edgeStrokeWidth );
1015  mRendererSettings.setScalarSettings( groupIndex, scalarSettings );
1016 
1017  if ( metadata.isVector() )
1018  {
1019  QgsMeshRendererVectorSettings vectorSettings;
1020  vectorSettings.setColorRampShader( fcn );
1021  mRendererSettings.setVectorSettings( groupIndex, vectorSettings );
1022  }
1023 }
1024 
1026 {
1027  // Triangular mesh
1028  updateTriangularMesh( rendererContext.coordinateTransform() );
1029 
1030  // Build overview triangular meshes if needed
1031  createSimplifiedMeshes();
1032 
1033  // Cache
1034  if ( !mRendererCache )
1035  mRendererCache.reset( new QgsMeshLayerRendererCache() );
1036 
1037  return new QgsMeshLayerRenderer( this, rendererContext );
1038 }
1039 
1040 bool QgsMeshLayer::readSymbology( const QDomNode &node, QString &errorMessage,
1041  QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
1042 {
1043  Q_UNUSED( errorMessage )
1044  // TODO: implement categories for raster layer
1045 
1046  QDomElement elem = node.toElement();
1047 
1048  readCommonStyle( elem, context, categories );
1049 
1050  QDomElement elemRendererSettings = elem.firstChildElement( "mesh-renderer-settings" );
1051  if ( !elemRendererSettings.isNull() )
1052  mRendererSettings.readXml( elemRendererSettings, context );
1053 
1054  QDomElement elemSimplifySettings = elem.firstChildElement( "mesh-simplify-settings" );
1055  if ( !elemSimplifySettings.isNull() )
1056  mSimplificationSettings.readXml( elemSimplifySettings, context );
1057 
1058  // get and set the blend mode if it exists
1059  QDomNode blendModeNode = node.namedItem( QStringLiteral( "blendMode" ) );
1060  if ( !blendModeNode.isNull() )
1061  {
1062  QDomElement e = blendModeNode.toElement();
1063  setBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( e.text().toInt() ) ) );
1064  }
1065 
1066  // get and set the layer transparency
1067  if ( categories.testFlag( Rendering ) )
1068  {
1069  QDomNode layerOpacityNode = node.namedItem( QStringLiteral( "layerOpacity" ) );
1070  if ( !layerOpacityNode.isNull() )
1071  {
1072  QDomElement e = layerOpacityNode.toElement();
1073  setOpacity( e.text().toDouble() );
1074  }
1075  }
1076 
1077  return true;
1078 }
1079 
1080 bool QgsMeshLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage,
1081  const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1082 {
1083  Q_UNUSED( errorMessage )
1084  // TODO: implement categories for raster layer
1085 
1086  QDomElement elem = node.toElement();
1087 
1088  writeCommonStyle( elem, doc, context, categories );
1089 
1090  QDomElement elemRendererSettings = mRendererSettings.writeXml( doc, context );
1091  elem.appendChild( elemRendererSettings );
1092 
1093  QDomElement elemSimplifySettings = mSimplificationSettings.writeXml( doc, context );
1094  elem.appendChild( elemSimplifySettings );
1095 
1096  // add blend mode node
1097  QDomElement blendModeElement = doc.createElement( QStringLiteral( "blendMode" ) );
1098  QDomText blendModeText = doc.createTextNode( QString::number( QgsPainting::getBlendModeEnum( blendMode() ) ) );
1099  blendModeElement.appendChild( blendModeText );
1100  node.appendChild( blendModeElement );
1101 
1102  // add the layer opacity
1103  if ( categories.testFlag( Rendering ) )
1104  {
1105  QDomElement layerOpacityElem = doc.createElement( QStringLiteral( "layerOpacity" ) );
1106  QDomText layerOpacityText = doc.createTextNode( QString::number( opacity() ) );
1107  layerOpacityElem.appendChild( layerOpacityText );
1108  node.appendChild( layerOpacityElem );
1109  }
1110 
1111  return true;
1112 }
1113 
1114 bool QgsMeshLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1115 {
1116  return writeSymbology( node, doc, errorMessage, context, categories );
1117 }
1118 
1119 bool QgsMeshLayer::readStyle( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
1120 {
1121  return readSymbology( node, errorMessage, context, categories );
1122 }
1123 
1124 QString QgsMeshLayer::decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const
1125 {
1126  QString src( source );
1127  if ( provider == QLatin1String( "mdal" ) )
1128  {
1129  src = context.pathResolver().readPath( src );
1130  }
1131  return src;
1132 }
1133 
1134 QString QgsMeshLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
1135 {
1136  QString src( source );
1137  if ( providerType() == QLatin1String( "mdal" ) )
1138  {
1139  src = context.pathResolver().writePath( src );
1140  }
1141  return src;
1142 }
1143 
1144 bool QgsMeshLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &context )
1145 {
1146  QgsDebugMsgLevel( QStringLiteral( "Datasource in QgsMeshLayer::readXml: %1" ).arg( mDataSource.toLocal8Bit().data() ), 3 );
1147 
1148  //process provider key
1149  QDomNode pkeyNode = layer_node.namedItem( QStringLiteral( "provider" ) );
1150 
1151  if ( pkeyNode.isNull() )
1152  {
1153  mProviderKey.clear();
1154  }
1155  else
1156  {
1157  QDomElement pkeyElt = pkeyNode.toElement();
1158  mProviderKey = pkeyElt.text();
1159  }
1160 
1162  {
1163  return false;
1164  }
1165 
1166  QgsDataProvider::ProviderOptions providerOptions;
1167  QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags();
1169  {
1171  }
1172  if ( !setDataProvider( mProviderKey, providerOptions, flags ) )
1173  {
1174  return false;
1175  }
1176 
1177  QDomElement elemExtraDatasets = layer_node.firstChildElement( QStringLiteral( "extra-datasets" ) );
1178  if ( !elemExtraDatasets.isNull() )
1179  {
1180  QDomElement elemUri = elemExtraDatasets.firstChildElement( QStringLiteral( "uri" ) );
1181  while ( !elemUri.isNull() )
1182  {
1183  QString uri = context.pathResolver().readPath( elemUri.text() );
1184 
1185  bool res = mDataProvider->addDataset( uri );
1186 #ifdef QGISDEBUG
1187  QgsDebugMsg( QStringLiteral( "extra dataset (res %1): %2" ).arg( res ).arg( uri ) );
1188 #else
1189  ( void )res; // avoid unused warning in release builds
1190 #endif
1191 
1192  elemUri = elemUri.nextSiblingElement( QStringLiteral( "uri" ) );
1193  }
1194  }
1195 
1196  if ( mDataProvider && pkeyNode.toElement().hasAttribute( QStringLiteral( "time-unit" ) ) )
1197  mDataProvider->setTemporalUnit(
1198  static_cast<QgsUnitTypes::TemporalUnit>( pkeyNode.toElement().attribute( QStringLiteral( "time-unit" ) ).toInt() ) );
1199 
1200  // read dataset group store
1201  QDomElement elemDatasetGroupsStore = layer_node.firstChildElement( QStringLiteral( "mesh-dataset-groups-store" ) );
1202  if ( elemDatasetGroupsStore.isNull() )
1204  else
1205  mDatasetGroupStore->readXml( elemDatasetGroupsStore, context );
1206 
1207  QString errorMsg;
1208  readSymbology( layer_node, errorMsg, context );
1209 
1210  if ( !mTemporalProperties->timeExtent().begin().isValid() )
1212 
1213  // read static dataset
1214  QDomElement elemStaticDataset = layer_node.firstChildElement( QStringLiteral( "static-active-dataset" ) );
1215  if ( elemStaticDataset.hasAttribute( QStringLiteral( "scalar" ) ) )
1216  {
1217  mStaticScalarDatasetIndex = elemStaticDataset.attribute( QStringLiteral( "scalar" ) ).toInt();
1218  }
1219  if ( elemStaticDataset.hasAttribute( QStringLiteral( "vector" ) ) )
1220  {
1221  mStaticVectorDatasetIndex = elemStaticDataset.attribute( QStringLiteral( "vector" ) ).toInt();
1222  }
1223 
1224  return isValid(); // should be true if read successfully
1225 }
1226 
1227 bool QgsMeshLayer::writeXml( QDomNode &layer_node, QDomDocument &document, const QgsReadWriteContext &context ) const
1228 {
1229  // first get the layer element so that we can append the type attribute
1230  QDomElement mapLayerNode = layer_node.toElement();
1231 
1232  if ( mapLayerNode.isNull() || ( QLatin1String( "maplayer" ) != mapLayerNode.nodeName() ) )
1233  {
1234  QgsDebugMsgLevel( QStringLiteral( "can't find <maplayer>" ), 2 );
1235  return false;
1236  }
1237 
1238  mapLayerNode.setAttribute( QStringLiteral( "type" ), QgsMapLayerFactory::typeToString( QgsMapLayerType::MeshLayer ) );
1239 
1240  // add provider node
1241  if ( mDataProvider )
1242  {
1243  QDomElement provider = document.createElement( QStringLiteral( "provider" ) );
1244  QDomText providerText = document.createTextNode( providerType() );
1245  provider.appendChild( providerText );
1246  layer_node.appendChild( provider );
1247  provider.setAttribute( QStringLiteral( "time-unit" ), mDataProvider->temporalCapabilities()->temporalUnit() );
1248 
1249  const QStringList extraDatasetUris = mDataProvider->extraDatasets();
1250  QDomElement elemExtraDatasets = document.createElement( QStringLiteral( "extra-datasets" ) );
1251  for ( const QString &uri : extraDatasetUris )
1252  {
1253  QString path = context.pathResolver().writePath( uri );
1254  QDomElement elemUri = document.createElement( QStringLiteral( "uri" ) );
1255  elemUri.appendChild( document.createTextNode( path ) );
1256  elemExtraDatasets.appendChild( elemUri );
1257  }
1258  layer_node.appendChild( elemExtraDatasets );
1259  }
1260 
1261  QDomElement elemStaticDataset = document.createElement( QStringLiteral( "static-active-dataset" ) );
1262  elemStaticDataset.setAttribute( QStringLiteral( "scalar" ), mStaticScalarDatasetIndex );
1263  elemStaticDataset.setAttribute( QStringLiteral( "vector" ), mStaticVectorDatasetIndex );
1264  layer_node.appendChild( elemStaticDataset );
1265 
1266  // write dataset group store
1267  layer_node.appendChild( mDatasetGroupStore->writeXml( document, context ) );
1268 
1269  // renderer specific settings
1270  QString errorMsg;
1271  return writeSymbology( layer_node, document, errorMsg, context );
1272 }
1273 
1275 {
1276  if ( mDataProvider && mDataProvider->isValid() )
1277  {
1278  mDataProvider->reloadData();
1279 
1280  //reload the mesh structure
1281  if ( !mNativeMesh )
1282  mNativeMesh.reset( new QgsMesh );
1283 
1284  dataProvider()->populateMesh( mNativeMesh.get() );
1285 
1286  //clear the TriangularMeshes
1287  mTriangularMeshes.clear();
1288 
1289  //clear the rendererCache
1290  mRendererCache.reset( new QgsMeshLayerRendererCache() );
1291  }
1292 }
1293 
1294 QStringList QgsMeshLayer::subLayers() const
1295 {
1296  if ( mDataProvider )
1297  return mDataProvider->subLayers();
1298  else
1299  return QStringList();
1300 }
1301 
1303 {
1304  QgsLayerMetadataFormatter htmlFormatter( metadata() );
1305  QString myMetadata = QStringLiteral( "<html>\n<body>\n" );
1306 
1307  // Begin Provider section
1308  myMetadata += QStringLiteral( "<h1>" ) + tr( "Information from provider" ) + QStringLiteral( "</h1>\n<hr>\n" );
1309  myMetadata += QLatin1String( "<table class=\"list-view\">\n" );
1310 
1311  // name
1312  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Name" ) + QStringLiteral( "</td><td>" ) + name() + QStringLiteral( "</td></tr>\n" );
1313 
1314  // local path
1315  QVariantMap uriComponents = QgsProviderRegistry::instance()->decodeUri( mProviderKey, publicSource() );
1316  QString path;
1317  if ( uriComponents.contains( QStringLiteral( "path" ) ) )
1318  {
1319  path = uriComponents[QStringLiteral( "path" )].toString();
1320  if ( QFile::exists( path ) )
1321  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" );
1322  }
1323  if ( uriComponents.contains( QStringLiteral( "url" ) ) )
1324  {
1325  const QString url = uriComponents[QStringLiteral( "url" )].toString();
1326  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" );
1327  }
1328 
1329  // data source
1330  if ( publicSource() != path )
1331  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Source" ) + QStringLiteral( "</td><td>%1" ).arg( publicSource() ) + QStringLiteral( "</td></tr>\n" );
1332 
1333  // EPSG
1334  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "CRS" ) + QStringLiteral( "</td><td>" );
1335  if ( crs().isValid() )
1336  {
1337  myMetadata += crs().userFriendlyIdentifier( QgsCoordinateReferenceSystem::FullString ) + QStringLiteral( " - " );
1338  if ( crs().isGeographic() )
1339  myMetadata += tr( "Geographic" );
1340  else
1341  myMetadata += tr( "Projected" );
1342  }
1343  myMetadata += QLatin1String( "</td></tr>\n" );
1344 
1345  // Extent
1346  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Extent" ) + QStringLiteral( "</td><td>" ) + extent().toString() + QStringLiteral( "</td></tr>\n" );
1347 
1348  // unit
1349  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Unit" ) + QStringLiteral( "</td><td>" ) + QgsUnitTypes::toString( crs().mapUnits() ) + QStringLiteral( "</td></tr>\n" );
1350 
1351  // feature count
1352  QLocale locale = QLocale();
1353  locale.setNumberOptions( locale.numberOptions() &= ~QLocale::NumberOption::OmitGroupSeparator );
1354 
1355  if ( dataProvider() )
1356  {
1357  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
1358  + tr( "Vertex count" ) + QStringLiteral( "</td><td>" )
1359  + ( locale.toString( static_cast<qlonglong>( dataProvider()->vertexCount() ) ) )
1360  + QStringLiteral( "</td></tr>\n" );
1361  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
1362  + tr( "Face count" ) + QStringLiteral( "</td><td>" )
1363  + ( locale.toString( static_cast<qlonglong>( dataProvider()->faceCount() ) ) )
1364  + QStringLiteral( "</td></tr>\n" );
1365  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
1366  + tr( "Edge count" ) + QStringLiteral( "</td><td>" )
1367  + ( locale.toString( static_cast<qlonglong>( dataProvider()->edgeCount() ) ) )
1368  + QStringLiteral( "</td></tr>\n" );
1369  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
1370  + tr( "Dataset groups count" ) + QStringLiteral( "</td><td>" )
1371  + ( locale.toString( static_cast<qlonglong>( dataProvider()->datasetGroupCount() ) ) )
1372  + QStringLiteral( "</td></tr>\n" );
1373  }
1374 
1375  // End Provider section
1376  myMetadata += QLatin1String( "</table>\n<br><br>" );
1377 
1378  // identification section
1379  myMetadata += QStringLiteral( "<h1>" ) + tr( "Identification" ) + QStringLiteral( "</h1>\n<hr>\n" );
1380  myMetadata += htmlFormatter.identificationSectionHtml( );
1381  myMetadata += QLatin1String( "<br><br>\n" );
1382 
1383  // extent section
1384  myMetadata += QStringLiteral( "<h1>" ) + tr( "Extent" ) + QStringLiteral( "</h1>\n<hr>\n" );
1385  myMetadata += htmlFormatter.extentSectionHtml( isSpatial() );
1386  myMetadata += QLatin1String( "<br><br>\n" );
1387 
1388  // Start the Access section
1389  myMetadata += QStringLiteral( "<h1>" ) + tr( "Access" ) + QStringLiteral( "</h1>\n<hr>\n" );
1390  myMetadata += htmlFormatter.accessSectionHtml( );
1391  myMetadata += QLatin1String( "<br><br>\n" );
1392 
1393  // Start the contacts section
1394  myMetadata += QStringLiteral( "<h1>" ) + tr( "Contacts" ) + QStringLiteral( "</h1>\n<hr>\n" );
1395  myMetadata += htmlFormatter.contactsSectionHtml( );
1396  myMetadata += QLatin1String( "<br><br>\n" );
1397 
1398  // Start the links section
1399  myMetadata += QStringLiteral( "<h1>" ) + tr( "Links" ) + QStringLiteral( "</h1>\n<hr>\n" );
1400  myMetadata += htmlFormatter.linksSectionHtml( );
1401  myMetadata += QLatin1String( "<br><br>\n" );
1402 
1403  // Start the history section
1404  myMetadata += QStringLiteral( "<h1>" ) + tr( "History" ) + QStringLiteral( "</h1>\n<hr>\n" );
1405  myMetadata += htmlFormatter.historySectionHtml( );
1406  myMetadata += QLatin1String( "<br><br>\n" );
1407 
1408  myMetadata += QLatin1String( "\n</body>\n</html>\n" );
1409  return myMetadata;
1410 }
1411 
1412 bool QgsMeshLayer::setDataProvider( QString const &provider, const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags )
1413 {
1414  delete mDataProvider;
1415 
1416  mProviderKey = provider;
1417  QString dataSource = mDataSource;
1418 
1419  mDataProvider = qobject_cast<QgsMeshDataProvider *>( QgsProviderRegistry::instance()->createProvider( provider, dataSource, options, flags ) );
1420  if ( !mDataProvider )
1421  {
1422  QgsDebugMsgLevel( QStringLiteral( "Unable to get mesh data provider" ), 2 );
1423  return false;
1424  }
1425 
1426  mDataProvider->setParent( this );
1427  QgsDebugMsgLevel( QStringLiteral( "Instantiated the mesh data provider plugin" ), 2 );
1428 
1429  setValid( mDataProvider->isValid() );
1430  if ( !isValid() )
1431  {
1432  QgsDebugMsgLevel( QStringLiteral( "Invalid mesh provider plugin %1" ).arg( QString( mDataSource.toUtf8() ) ), 2 );
1433  return false;
1434  }
1435 
1436  setCrs( mDataProvider->crs() );
1437 
1438  if ( provider == QLatin1String( "mesh_memory" ) )
1439  {
1440  // required so that source differs between memory layers
1441  mDataSource = mDataSource + QStringLiteral( "&uid=%1" ).arg( QUuid::createUuid().toString() );
1442  }
1443 
1444  mDatasetGroupStore->setPersistentProvider( mDataProvider );
1445 
1446  for ( int i = 0; i < mDataProvider->datasetGroupCount(); ++i )
1447  assignDefaultStyleToDatasetGroup( i );
1448 
1449  connect( mDataProvider, &QgsMeshDataProvider::dataChanged, this, &QgsMeshLayer::dataChanged );
1450 
1451  return true;
1452 }
1453 
1455 {
1456  return mTemporalProperties;
1457 }
A ramp shader will color a raster pixel based on a list of values ranges in a ramp.
@ EqualInterval
Uses equal interval.
QgsColorRamp * sourceColorRamp() const
Returns the source color ramp.
@ Exact
Assigns the color of the exact matching value in the color ramp item list.
void setClassificationMode(ClassificationMode classificationMode)
Sets classification mode.
void setColorRampItemList(const QList< QgsColorRampShader::ColorRampItem > &list)
Sets a custom colormap.
void setColorRampType(QgsColorRampShader::Type colorRampType)
Sets the color ramp type.
Abstract base class for color ramps.
Definition: qgscolorramp.h:32
virtual QColor color(double value) const =0
Returns the color corresponding to a specified value.
@ FullString
Full definition – possibly a very lengthy string, e.g. with no truncation of custom WKT definitions.
QString userFriendlyIdentifier(IdentifierType type=MediumString) const
Returns a user friendly identifier for the CRS.
Contains information about the context in which a coordinate transform is executed.
Class for doing transforms between two map coordinate systems.
bool hasTemporalCapabilities() const
Returns true if the provider has temporal capabilities available.
@ FlagTrustDataSource
Trust datasource config (primary key unicity, geometry type and srid, etc). Improves provider load ti...
QgsCoordinateTransformContext transformContext() const
Returns data provider coordinate transform context.
virtual QgsCoordinateReferenceSystem crs() const =0
Returns the coordinate system for the data source.
void dataChanged()
Emitted whenever a change is made to the data provider which may have caused changes in the provider'...
virtual bool isValid() const =0
Returns true if this is a valid layer.
virtual QStringList subLayers() const
Sub-layers handled by this provider, in order from bottom to top.
virtual void reloadData()
Reloads the data from the source for providers with data caches to synchronize, changes in the data s...
virtual QgsRectangle extent() const =0
Returns the extent of the layer.
virtual void setTransformContext(const QgsCoordinateTransformContext &transformContext)
Sets data coordinate transform context to transformContext.
static QgsColorRamp * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsColorRamp from a map of properties.
Class defining color to render mesh datasets.
Represents a line with width and color varying depending on values.
Represents a width than can vary depending on values.
void setMaximumValue(double maximumValue)
Sets the maximum value used to defined the variable width.
void setMinimumValue(double minimumValue)
Sets the minimum value used to defined the variable width.
A representation of the interval between two datetime values.
Definition: qgsinterval.h:42
double seconds() const
Returns the interval duration in seconds.
Definition: qgsinterval.h:236
Class for metadata formatter.
QString linksSectionHtml() const
Formats the "Links" section according to a metadata object.
QString extentSectionHtml(const bool showSpatialExtent=true) const
Formats the "Extents" section according to a metadata object (extent and temporal).
QString contactsSectionHtml() const
Formats the "Contacts" section according to a metadata object.
QString identificationSectionHtml() const
Formats the "Identification" section according to a metadata object.
QString historySectionHtml() const
Formats the "History" section according to a metadata object.
QString accessSectionHtml() const
Formats the "Access" section according to a metadata object.
static QString typeToString(QgsMapLayerType type)
Converts a map layer type to a string value.
static QgsMapLayerLegend * defaultMeshLegend(QgsMeshLayer *ml)
Create new legend implementation for mesh layer.
Base class for utility classes that encapsulate information necessary for rendering of map layers.
Base class for storage of map layer temporal properties.
virtual void setDefaultsFromDataProviderTemporalCapabilities(const QgsDataProviderTemporalCapabilities *capabilities)=0
Sets the layers temporal settings to appropriate defaults based on a provider's temporal capabilities...
Base class for all map layer types.
Definition: qgsmaplayer.h:85
QString name
Definition: qgsmaplayer.h:88
virtual bool isSpatial() const
Returns true if the layer is considered a spatial layer, ie it has some form of geometry associated w...
QString source() const
Returns the source for the layer.
void setBlendMode(QPainter::CompositionMode blendMode)
Set the blending mode used for rendering a layer.
QString publicSource() const
Gets a version of the internal layer definition that has sensitive bits removed (for example,...
QgsMapLayer::LayerFlags flags() const
Returns the flags for this layer.
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:91
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted.
QgsLayerMetadata metadata
Definition: qgsmaplayer.h:90
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
virtual void setOpacity(double opacity)
Sets the opacity for the layer, where opacity is a value between 0 (totally transparent) and 1....
QString mProviderKey
Data provider key (name of the data provider)
Definition: qgsmaplayer.h:1658
QgsCoordinateTransformContext transformContext() const
Returns the layer data provider coordinate transform context or a default transform context if the la...
void rendererChanged()
Signal emitted when renderer is changed.
void dataSourceChanged()
Emitted whenever the layer's data source has been changed.
virtual QgsMapLayer * clone() const =0
Returns a new instance equivalent to this one except for the id which is still unique.
void dataChanged()
Data of layer changed.
bool isValid
Definition: qgsmaplayer.h:93
QString mDataSource
Data source description string, varies by layer type.
Definition: qgsmaplayer.h:1612
@ FlagTrustLayerMetadata
Trust layer metadata. Improves layer load time by skipping expensive checks like primary key unicity,...
Definition: qgsmaplayer.h:585
@ FlagDontResolveLayers
Don't resolve layer paths or create data providers for layers.
Definition: qgsmaplayer.h:584
void setValid(bool valid)
Sets whether layer is valid or not.
void readCommonStyle(const QDomElement &layerElement, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories)
Read style data common to all layer types.
QgsMapLayer::ReadFlags mReadFlags
Read flags. It's up to the subclass to respect these when restoring state from XML.
Definition: qgsmaplayer.h:1663
void setLegend(QgsMapLayerLegend *legend)
Assign a legend controller to the map layer.
double opacity
Definition: qgsmaplayer.h:94
@ Rendering
Rendering: scale visibility, simplify method, opacity.
Definition: qgsmaplayer.h:179
void setProviderType(const QString &providerType)
Sets the providerType (provider key)
void writeCommonStyle(QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) const
Write style data common to all layer types.
bool mShouldValidateCrs
true if the layer's CRS should be validated and invalid CRSes are not permitted.
Definition: qgsmaplayer.h:1670
void setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer's spatial reference system.
Abstract class to interpolate 3d stacked mesh data to 2d data.
QgsMeshDataBlock calculate(const QgsMesh3dDataBlock &block3d, QgsFeedback *feedback=nullptr) const
Calculated 2d block values from 3d stacked mesh values.
QgsMesh3dDataBlock is a block of 3d stacked mesh data related N faces defined on base mesh frame.
QgsMeshDataBlock is a block of integers/doubles that can be used to retrieve: active flags (e....
QgsMeshDatasetValue value(int index) const
Returns a value represented by the index For active flag the behavior is undefined.
bool isValid() const
Whether the block is valid.
QgsUnitTypes::TemporalUnit temporalUnit() const
Returns the temporal unit used to read data by the data provider.
QDateTime referenceTime() const
Returns the reference time.
MatchingTemporalDatasetMethod
Method for selection of temporal mesh dataset from a range time.
qint64 firstTimeStepDuration(int group) const
Returns the duration of the first time step of the dataset group with index group.
Base class for providing data for QgsMeshLayer.
QgsMeshDataProviderTemporalCapabilities * temporalCapabilities() override
Returns the provider's temporal capabilities.
void setTemporalUnit(QgsUnitTypes::TemporalUnit unit)
Sets the temporal unit of the provider and reload data if it changes.
virtual void populateMesh(QgsMesh *mesh) const =0
Populates the mesh vertices, edges and faces.
QgsMeshDatasetGroupMetadata is a collection of dataset group metadata such as whether the data is vec...
QMap< QString, QString > extraOptions() const
Returns extra metadata options, for example description.
bool isVector() const
Returns whether dataset group has vector data.
DataType dataType() const
Returns whether dataset group data is defined on vertices or faces or volumes.
double minimum() const
Returns minimum scalar value/vector magnitude present for whole dataset group.
double maximum() const
Returns maximum scalar value/vector magnitude present for whole dataset group.
DataType
Location of where data is specified for datasets in the dataset group.
@ DataOnEdges
Data is defined on edges.
@ DataOnFaces
Data is defined on faces.
@ DataOnVertices
Data is defined on vertices.
@ DataOnVolumes
Data is defined on volumes.
Class used to register and access all the dataset groups related to a mesh layer.
void datasetGroupsAdded(QList< int > indexes)
Emitted after dataset groups are added.
Tree item for display of the mesh dataset groups.
int childCount() const
Returns the count of children.
QgsMeshDatasetGroupTreeItem * childFromDatasetGroupIndex(int index)
Returns the child with dataset group index Searches as depper as needed on the child hierarchy.
QgsMeshDatasetGroupTreeItem * child(int row) const
Returns a child.
Abstract class that represents a dataset group.
QgsMeshDatasetIndex is index that identifies the dataset group (e.g.
bool isValid() const
Returns whether index is valid, ie at least groups is set.
int group() const
Returns a group index.
int dataset() const
Returns a dataset index within group()
QgsMeshDatasetMetadata is a collection of mesh dataset metadata such as whether the data is valid or ...
virtual int datasetGroupCount() const =0
Returns number of datasets groups loaded.
virtual QStringList extraDatasets() const =0
Returns list of additional dataset file URIs added using addDataset() calls.
virtual bool addDataset(const QString &uri)=0
Associate dataset with the mesh.
QgsMeshDatasetValue represents single dataset value.
double y() const
Returns y value.
double x() const
Returns x value.
Implementation of threaded rendering for mesh layers.
Implementation of map layer temporal properties for mesh layers.
QDateTime referenceTime() const
Returns the reference time.
void setMatchingMethod(const QgsMeshDataProviderTemporalCapabilities::MatchingTemporalDatasetMethod &matchingMethod)
Sets the method used to match dataset from temporal capabilities.
QgsMeshDataProviderTemporalCapabilities::MatchingTemporalDatasetMethod matchingMethod() const
Returns the method used to match dataset from temporal capabilities.
void setReferenceTime(const QDateTime &referenceTime, const QgsDataProviderTemporalCapabilities *capabilities)
Sets the reference time and update the time extent from the temporal capabilities,...
void setDefaultsFromDataProviderTemporalCapabilities(const QgsDataProviderTemporalCapabilities *capabilities) override
Sets the layers temporal settings to appropriate defaults based on a provider's temporal capabilities...
QgsDateTimeRange timeExtent() const
Returns the time extent.
Represents a mesh layer supporting display of data on structured or unstructured meshes.
Definition: qgsmeshlayer.h:95
~QgsMeshLayer() override
void setMeshSimplificationSettings(const QgsMeshSimplificationSettings &meshSimplificationSettings)
Sets mesh simplification settings.
int datasetCount(const QgsMeshDatasetIndex &index) const
Returns the dataset count in the dataset groups.
QList< int > datasetGroupsIndexes() const
Returns the list of indexes of dataset groups handled by the layer.
QgsRectangle extent() const override
Returns the extent of the layer.
void setStaticVectorDatasetIndex(const QgsMeshDatasetIndex &staticVectorDatasetIndex)
Sets the static vector dataset index that is rendered if the temporal properties is not active.
void setStaticScalarDatasetIndex(const QgsMeshDatasetIndex &staticScalarDatasetIndex)
Sets the static scalar dataset index that is rendered if the temporal properties is not active.
QgsMeshRendererSettings rendererSettings() const
Returns renderer settings.
QgsMesh3dDataBlock dataset3dValues(const QgsMeshDatasetIndex &index, int faceIndex, int count) const
Returns N vector/scalar values from the face index from the dataset for 3d stacked meshes.
void activeScalarDatasetGroupChanged(int index)
Emitted when active scalar group dataset is changed.
int datasetGroupCount() const
Returns the dataset groups count handle by the layer.
void updateTriangularMesh(const QgsCoordinateTransform &transform=QgsCoordinateTransform())
Gets native mesh and updates (creates if it doesn't exist) the base triangular mesh.
bool addDatasets(const QString &path, const QDateTime &defaultReferenceTime=QDateTime())
Adds datasets to the mesh from file with path.
void activeVectorDatasetGroupChanged(int index)
Emitted when active vector group dataset is changed.
void reload() override
Synchronises with changes in the datasource.
QgsMeshDatasetIndex activeScalarDatasetAtTime(const QgsDateTimeRange &timeRange) const
Returns dataset index from active scalar group depending on the time range.
QgsPointXY snapOnElement(QgsMesh::ElementType elementType, const QgsPointXY &point, double searchRadius)
Returns the position of the snapped point on the mesh element closest to point intersecting with the ...
bool readXml(const QDomNode &layer_node, QgsReadWriteContext &context) override
Called by readLayerXML(), used by children to read state specific to them from project files.
QStringList subLayers() const override
Returns the sublayers of this layer.
void setDatasetGroupTreeRootItem(QgsMeshDatasetGroupTreeItem *rootItem)
Sets the root items of the dataset group tree item.
QgsMeshDatasetValue dataset1dValue(const QgsMeshDatasetIndex &index, const QgsPointXY &point, double searchRadius) const
Returns the value of 1D mesh dataset defined on edge that are in the search area defined by point ans...
QgsMesh * nativeMesh()
Returns native mesh (nullptr before rendering or calling to updateMesh)
QgsTriangularMesh * triangularMeshByLodIndex(int lodIndex) const
Returns triangular corresponding to the index of level of details.
QString htmlMetadata() const override
Obtain a formatted HTML string containing assorted metadata for this layer.
QgsMesh3dDataBlock dataset3dValue(const QgsMeshDatasetIndex &index, const QgsPointXY &point) const
Returns the 3d values of stacked 3d mesh defined by the given point.
QgsMeshLayer * clone() const override
Returns a new instance equivalent to this one except for the id which is still unique.
void timeSettingsChanged()
Emitted when time format is changed.
QList< int > enabledDatasetGroupsIndexes() const
Returns the list of indexes of enables dataset groups handled by the layer.
void resetDatasetGroupTreeItem()
Reset the dataset group tree item to default from provider.
int triangularMeshLevelOfDetailCount() const
Returns the count of levels of detail of the mesh simplification.
QString encodedSource(const QString &source, const QgsReadWriteContext &context) const override
Called by writeLayerXML(), used by derived classes to encode provider's specific data source to proje...
QgsMeshDatasetIndex staticVectorDatasetIndex() const
Returns the static vector dataset index that is rendered if the temporal properties is not active.
QgsMeshDatasetIndex datasetIndexAtRelativeTime(const QgsInterval &relativeTime, int datasetGroupIndex) const
Returns dataset index from datasets group depending on the relative time from the layer reference tim...
bool writeXml(QDomNode &layer_node, QDomDocument &doc, const QgsReadWriteContext &context) const override
Called by writeLayerXML(), used by children to write state specific to them to project files.
QgsMeshDataBlock datasetValues(const QgsMeshDatasetIndex &index, int valueIndex, int count) const
Returns N vector/scalar values from the index from the dataset.
bool writeStyle(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) const override
Write just the symbology information for the layer into the document.
void setTransformContext(const QgsCoordinateTransformContext &transformContext) override
Sets the coordinate transform context to transformContext.
QgsMeshSimplificationSettings meshSimplificationSettings() const
Returns mesh simplification settings.
QgsMapLayerRenderer * createMapRenderer(QgsRenderContext &rendererContext) override
Returns new instance of QgsMapLayerRenderer that will be used for rendering of given context.
QgsMeshDatasetIndex activeVectorDatasetAtTime(const QgsDateTimeRange &timeRange) const
Returns dataset index from active vector group depending on the time range If the temporal properties...
QgsMeshDataBlock areFacesActive(const QgsMeshDatasetIndex &index, int faceIndex, int count) const
Returns whether the faces are active for particular dataset.
QgsMeshDatasetIndex staticScalarDatasetIndex() const
Returns the static scalar dataset index that is rendered if the temporal properties is not active.
bool isFaceActive(const QgsMeshDatasetIndex &index, int faceIndex) const
Returns N vector/scalar values from the face index from the dataset for 3d stacked meshes.
QgsMeshDatasetMetadata datasetMetadata(const QgsMeshDatasetIndex &index) const
Returns the dataset metadata.
bool saveDataset(const QString &path, int datasetGroupIndex, QString driver)
Saves datasets group on file with the specified driver.
QgsMeshDataProvider * dataProvider() override
Returns the layer's data provider, it may be nullptr.
QgsInterval firstValidTimeStep() const
Returns the first valid time step of the dataset groups, invalid QgInterval if no time step is presen...
QgsInterval datasetRelativeTime(const QgsMeshDatasetIndex &index)
Returns the relative time of the dataset from the reference time of its group.
QgsMeshDatasetIndex datasetIndexAtTime(const QgsDateTimeRange &timeRange, int datasetGroupIndex) const
Returns dataset index from datasets group depending on the time range.
QgsMeshDatasetValue datasetValue(const QgsMeshDatasetIndex &index, int valueIndex) const
Returns vector/scalar value associated with the index from the dataset To read multiple continuous va...
QgsMeshTimeSettings timeSettings() const
Returns time format settings.
QgsMapLayerTemporalProperties * temporalProperties() override
Returns the layer's temporal properties.
bool writeSymbology(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) const override
void setReferenceTime(const QDateTime &referenceTime)
Sets the reference time of the layer.
bool readStyle(const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) override
Read the style for the current layer from the DOM node supplied.
int extraDatasetGroupCount() const
Returns the extra dataset groups count handle by the layer.
void setRendererSettings(const QgsMeshRendererSettings &settings)
Sets new renderer settings.
qint64 datasetRelativeTimeInMilliseconds(const QgsMeshDatasetIndex &index)
Returns the relative time (in milliseconds) of the dataset from the reference time of its group.
QgsTriangularMesh * triangularMesh(double minimumTriangleSize=0) const
Returns triangular mesh (nullptr before rendering or calling to updateMesh).
void setTemporalMatchingMethod(const QgsMeshDataProviderTemporalCapabilities::MatchingTemporalDatasetMethod &matchingMethod)
Sets the method used to match the temporal dataset from a requested time, see activeVectorDatasetAtTi...
QgsMeshDatasetGroupTreeItem * datasetGroupTreeRootItem() const
Returns the root items of the dataset group tree item.
bool readSymbology(const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) override
QString providerType() const
Returns the provider type for this layer.
QString decodedSource(const QString &source, const QString &provider, const QgsReadWriteContext &context) const override
Called by readLayerXML(), used by derived classes to decode provider's specific data source from proj...
QString formatTime(double hours)
Returns (date) time in hours formatted to human readable form.
QgsMeshDatasetGroupMetadata datasetGroupMetadata(const QgsMeshDatasetIndex &index) const
Returns the dataset groups metadata.
QgsMeshLayerRendererCache * rendererCache()
Returns native mesh (nullptr before rendering)
void setTimeSettings(const QgsMeshTimeSettings &settings)
Sets time format settings.
QgsMeshLayer(const QString &path=QString(), const QString &baseName=QString(), const QString &providerLib=QStringLiteral("mesh_memory"), const QgsMeshLayer::LayerOptions &options=QgsMeshLayer::LayerOptions())
Constructor - creates a mesh layer.
Represents a mesh renderer settings for mesh object.
void setEnabled(bool enabled)
Sets whether mesh structure rendering is enabled.
Represents a mesh renderer settings for scalar datasets.
void setClassificationMinimumMaximum(double minimum, double maximum)
Sets min/max values used for creation of the color ramp shader.
void setColorRampShader(const QgsColorRampShader &shader)
Sets color ramp shader function.
QgsColorRampShader colorRampShader() const
Returns color ramp shader function.
@ NeighbourAverage
Does a simple average of values defined for all surrounding faces/vertices.
void setEdgeStrokeWidth(const QgsInterpolatedLineWidth &strokeWidth)
Sets the stroke width used to render edges scalar dataset.
void setDataResamplingMethod(const DataResamplingMethod &dataResamplingMethod)
Sets data interpolation method.
Represents all mesh renderer settings.
void setActiveVectorDatasetGroup(int activeVectorDatasetGroup)
Sets the active vector dataset group.
QgsMeshRendererScalarSettings scalarSettings(int groupIndex) const
Returns renderer settings.
int activeVectorDatasetGroup() const
Returns the active vector dataset group.
int activeScalarDatasetGroup() const
Returns the active scalar dataset group.
QgsMesh3dAveragingMethod * averagingMethod() const
Returns averaging method for conversion of 3d stacked mesh data to 2d data.
void setActiveScalarDatasetGroup(int activeScalarDatasetGroup)
Sets the active scalar dataset group.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context=QgsReadWriteContext())
Reads configuration from the given DOM element.
void setVectorSettings(int groupIndex, const QgsMeshRendererVectorSettings &settings)
Sets new renderer settings.
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context=QgsReadWriteContext()) const
Writes configuration to a new DOM element.
void setScalarSettings(int groupIndex, const QgsMeshRendererScalarSettings &settings)
Sets new renderer settings.
void setNativeMeshSettings(const QgsMeshRendererMeshSettings &settings)
Sets new native mesh renderer settings, triggers repaint.
Represents a renderer settings for vector datasets.
void setColorRampShader(const QgsColorRampShader &colorRampShader)
Returns the color ramp shader used to render vector datasets.
Represents a overview renderer settings.
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Writes configuration to a new DOM element.
double reductionFactor() const
Returns the reduction factor used to build simplified mesh.
bool isEnabled() const
Returns if the overview is active.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Reads configuration from the given DOM element.
Represents a mesh time settings for mesh datasets.
static QgsPainting::BlendMode getBlendModeEnum(QPainter::CompositionMode blendMode)
Returns a BlendMode corresponding to a QPainter::CompositionMode.
Definition: qgspainting.cpp:80
static QPainter::CompositionMode getCompositionMode(QgsPainting::BlendMode blendMode)
Returns a QPainter::CompositionMode corresponding to a BlendMode.
Definition: qgspainting.cpp:20
BlendMode
Blending modes enum defining the available composition modes that can be used when rendering a layer.
Definition: qgspainting.h:37
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
QString readPath(const QString &filename) const
Turn filename read from the project file to an absolute path.
A class to represent a 2D point.
Definition: qgspointxy.h:44
double y
Definition: qgspointxy.h:48
Q_GADGET double x
Definition: qgspointxy.h:47
double distance(double x, double y) const SIP_HOLDGIL
Returns the distance between this point and a specified x, y coordinate.
Definition: qgspointxy.h:196
double sqrDistToSegment(double x1, double y1, double x2, double y2, QgsPointXY &minDistPoint, double epsilon=DEFAULT_SEGMENT_EPSILON) const SIP_HOLDGIL
Returns the minimum distance between this point and a segment.
Definition: qgspointxy.cpp:95
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:38
double distance(double x, double y) const SIP_HOLDGIL
Returns the Cartesian 2D distance between this point and a specified x, y coordinate.
Definition: qgspoint.h:332
Q_GADGET double x
Definition: qgspoint.h:41
double y
Definition: qgspoint.h:42
QVariantMap decodeUri(const QString &providerKey, const QString &uri)
Breaks a provider data source URI into its component paths (e.g.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
virtual void setMaximumValue(double value)
Sets the maximum value for the raster shader.
virtual void setMinimumValue(double value)
Sets the minimum value for the raster shader.
The class is used as a container of context for various read/write operations on other objects.
const QgsPathResolver & pathResolver() const
Returns path resolver for conversion between relative and absolute paths.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
void setMinimal() SIP_HOLDGIL
Set a rectangle so that min corner is at max and max corner is at min.
Definition: qgsrectangle.h:151
Contains information about the context of a rendering operation.
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
static QgsStyle * defaultStyle()
Returns default application-wide style.
Definition: qgsstyle.cpp:128
QgsColorRamp * colorRamp(const QString &name) const
Returns a new copy of the specified color ramp.
Definition: qgsstyle.cpp:439
bool isActive() const
Returns true if the temporal property is active.
void setIsActive(bool active)
Sets whether the temporal property is active.
Triangular/Derived Mesh is mesh with vertices in map coordinates.
const QVector< QgsMeshFace > & triangles() const
Returns triangles.
QList< int > edgeIndexesForRectangle(const QgsRectangle &rectangle) const
Finds indexes of edges intersecting given bounding box It uses spatial indexing.
const QVector< QgsMeshVertex > & vertices() const
Returns vertices in map coordinate system.
const QVector< QgsMeshEdge > & edges() const
Returns edges.
bool contains(const QgsMesh::ElementType &type) const
Returns whether the mesh contains at mesh elements of given type.
const QVector< QgsMeshVertex > & faceCentroids() const
Returns centroids of the native faces in map CRS.
const QVector< int > & trianglesToNativeFaces() const
Returns mapping between triangles and original faces.
QList< int > faceIndexesForRectangle(const QgsRectangle &rectangle) const
Finds indexes of triangles intersecting given bounding box It uses spatial indexing.
int faceIndexForPoint_v2(const QgsPointXY &point) const
Finds index of triangle at given point It uses spatial indexing and don't use geos to be faster.
static Q_INVOKABLE QString toString(QgsUnitTypes::DistanceUnit unit)
Returns a translated string representing a distance unit.
TemporalUnit
Temporal units.
Definition: qgsunittypes.h:150
@ TemporalMilliseconds
Milliseconds.
Definition: qgsunittypes.h:151
QgsMapLayerType
Types of layers that can be added to a map.
Definition: qgsmaplayer.h:69
@ MeshLayer
Added in 3.2.
#define SIP_SKIP
Definition: qgis_sip.h:126
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QVector< int > QgsMeshFace
List of vertex indexes.
QPair< int, int > QgsMeshEdge
Edge is a straight line seqment between 2 points.
Setting options for creating vector data providers.
Setting options for loading mesh layers.
Definition: qgsmeshlayer.h:103
QgsCoordinateTransformContext transformContext
Definition: qgsmeshlayer.h:113
bool skipCrsValidation
Controls whether the layer is allowed to have an invalid/unknown CRS.
Definition: qgsmeshlayer.h:128
Mesh - vertices, edges and faces.
ElementType
Defines type of mesh elements.