QGIS API Documentation  3.21.0-Master (5b68dc587e)
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 "qgsmaplayerutils.h"
29 #include "qgsmeshdataprovider.h"
31 #include "qgsmeshlayer.h"
32 #include "qgsmeshlayerrenderer.h"
34 #include "qgsmeshlayerutils.h"
35 #include "qgsmeshtimesettings.h"
36 #include "qgspainting.h"
37 #include "qgsproviderregistry.h"
38 #include "qgsreadwritecontext.h"
39 #include "qgsstyle.h"
40 #include "qgstriangularmesh.h"
41 #include "qgsmesh3daveraging.h"
43 #include "qgsmesheditor.h"
44 #include "qgsmessagelog.h"
46 
47 QgsMeshLayer::QgsMeshLayer( const QString &meshLayerPath,
48  const QString &baseName,
49  const QString &providerKey,
50  const QgsMeshLayer::LayerOptions &options )
51  : QgsMapLayer( QgsMapLayerType::MeshLayer, baseName, meshLayerPath ),
52  mDatasetGroupStore( new QgsMeshDatasetGroupStore( this ) ),
53  mTemporalProperties( new QgsMeshLayerTemporalProperties( this ) )
54 
55 {
57 
58  const QgsDataProvider::ProviderOptions providerOptions { options.transformContext };
59  QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags();
61  {
63  }
64  setDataSourcePrivate( meshLayerPath, baseName, providerKey, providerOptions, flags );
67 
68  if ( isValid() )
69  setDefaultRendererSettings( mDatasetGroupStore->datasetGroupIndexes() );
70 
71  connect( mDatasetGroupStore.get(), &QgsMeshDatasetGroupStore::datasetGroupsAdded, this, &QgsMeshLayer::onDatasetGroupsAdded );
72 }
73 
74 
75 void QgsMeshLayer::setDefaultRendererSettings( const QList<int> &groupIndexes )
76 {
77  QgsMeshRendererMeshSettings meshSettings;
78  if ( groupIndexes.count() > 0 )
79  {
80  // Show data from the first dataset group
81  mRendererSettings.setActiveScalarDatasetGroup( 0 );
82  // If the first dataset group has nan min/max, display the mesh to avoid nothing displayed
84  if ( meta.maximum() == std::numeric_limits<double>::quiet_NaN() &&
85  meta.minimum() == std::numeric_limits<double>::quiet_NaN() )
86  meshSettings.setEnabled( true );
87  }
88  else
89  {
90  // show at least the mesh by default
91  meshSettings.setEnabled( true );
92  return;
93  }
94  mRendererSettings.setNativeMeshSettings( meshSettings );
95 
96  // Sets default resample method for scalar dataset
97  for ( const int i : groupIndexes )
98  {
100  QgsMeshRendererScalarSettings scalarSettings = mRendererSettings.scalarSettings( i );
101  switch ( meta.dataType() )
102  {
104  case QgsMeshDatasetGroupMetadata::DataOnVolumes: // data on volumes are averaged to 2D data on faces
106  break;
109  break;
111  break;
112  }
113 
114  //override color ramp if the values in the dataset group are classified
115  applyClassificationOnScalarSettings( meta, scalarSettings );
116 
117  mRendererSettings.setScalarSettings( i, scalarSettings );
118  }
119 
120 }
121 
122 void QgsMeshLayer::createSimplifiedMeshes()
123 {
124  if ( mSimplificationSettings.isEnabled() && !hasSimplifiedMeshes() )
125  {
126  const double reductionFactor = mSimplificationSettings.reductionFactor();
127 
128  QVector<QgsTriangularMesh *> simplifyMeshes =
129  mTriangularMeshes[0]->simplifyMesh( reductionFactor );
130 
131  for ( int i = 0; i < simplifyMeshes.count() ; ++i )
132  {
133  mTriangularMeshes.emplace_back( simplifyMeshes[i] );
134  }
135  }
136 }
137 
138 bool QgsMeshLayer::hasSimplifiedMeshes() const
139 {
140  //First mesh is the base mesh, so if size>1, there is no simplified meshes
141  return ( mTriangularMeshes.size() > 1 );
142 }
143 
145 {
146  delete mDataProvider;
147 }
148 
150 {
151  return mDataProvider;
152 }
153 
155 {
156  return mDataProvider;
157 }
158 
160 {
162  if ( mDataProvider )
163  {
164  options.transformContext = mDataProvider->transformContext();
165  }
166  QgsMeshLayer *layer = new QgsMeshLayer( source(), name(), mProviderKey, options );
167  QgsMapLayer::clone( layer );
168  return layer;
169 }
170 
172 {
173  if ( mMeshEditor )
174  return mMeshEditor->extent();
175 
176  if ( mDataProvider )
177  return mDataProvider->extent();
178  else
179  {
180  QgsRectangle rec;
181  rec.setMinimal();
182  return rec;
183  }
184 }
185 
187 {
188  return mProviderKey;
189 }
190 
192 {
193  if ( !mDataProvider )
194  return false;
195 
196  if ( mMeshEditor )
197  return true;
198 
199  const QgsMeshDriverMetadata driverMetadata = mDataProvider->driverMetadata();
200 
201  return driverMetadata.capabilities() & QgsMeshDriverMetadata::CanWriteMeshData;
202 }
203 
204 bool QgsMeshLayer::addDatasets( const QString &path, const QDateTime &defaultReferenceTime )
205 {
206  const bool isTemporalBefore = dataProvider()->temporalCapabilities()->hasTemporalCapabilities();
207  if ( mDatasetGroupStore->addPersistentDatasets( path ) )
208  {
209  mExtraDatasetUri.append( path );
210  QgsMeshLayerTemporalProperties *temporalProperties = qobject_cast< QgsMeshLayerTemporalProperties * >( mTemporalProperties );
211  if ( !isTemporalBefore && dataProvider()->temporalCapabilities()->hasTemporalCapabilities() )
212  {
214  dataProvider()->temporalCapabilities() );
215 
216  if ( ! temporalProperties->referenceTime().isValid() )
217  {
218  QDateTime referenceTime = defaultReferenceTime;
219  if ( !defaultReferenceTime.isValid() ) // If project reference time is invalid, use current date
220  referenceTime = QDateTime( QDate::currentDate(), QTime( 0, 0, 0 ), Qt::UTC );
221  temporalProperties->setReferenceTime( referenceTime, dataProvider()->temporalCapabilities() );
222  }
223 
224  mTemporalProperties->setIsActive( true );
225  }
226  emit dataSourceChanged();
227  return true;
228  }
229 
230  return false;
231 }
232 
234 {
235  if ( mDatasetGroupStore->addDatasetGroup( datasetGroup ) )
236  {
237  emit dataChanged();
238  return true;
239  }
240  return false;
241 }
242 
243 bool QgsMeshLayer::saveDataset( const QString &path, int datasetGroupIndex, QString driver )
244 {
245  return mDatasetGroupStore->saveDatasetGroup( path, datasetGroupIndex, driver );
246 }
247 
249 {
250  return mNativeMesh.get();
251 }
252 
254 {
255  return mNativeMesh.get();
256 }
257 
258 QgsTriangularMesh *QgsMeshLayer::triangularMesh( double minimumTriangleSize ) const
259 {
260  for ( const std::unique_ptr<QgsTriangularMesh> &lod : mTriangularMeshes )
261  {
262  if ( lod && lod->averageTriangleSize() > minimumTriangleSize )
263  return lod.get();
264  }
265 
266  if ( !mTriangularMeshes.empty() )
267  return mTriangularMeshes.back().get();
268  else
269  return nullptr;
270 }
271 
273 {
274  return mTriangularMeshes.size();
275 }
276 
278 {
279  if ( mTriangularMeshes.empty() )
280  return nullptr;
281  if ( lodIndex < 0 )
282  return mTriangularMeshes.front().get();
283 
284  if ( lodIndex >= int( mTriangularMeshes.size() ) )
285  return mTriangularMeshes.back().get();
286 
287  return mTriangularMeshes.at( lodIndex ).get();
288 }
289 
291 {
292  // Native mesh
293  if ( !mNativeMesh )
294  {
295  // lazy loading of mesh data
296  fillNativeMesh();
297  }
298 
299  // Triangular mesh
300  if ( mTriangularMeshes.empty() )
301  {
302  QgsTriangularMesh *baseMesh = new QgsTriangularMesh;
303  mTriangularMeshes.emplace_back( baseMesh );
304  }
305 
306  if ( mTriangularMeshes[0].get()->update( mNativeMesh.get(), transform ) )
307  mTriangularMeshes.resize( 1 ); //if the base triangular mesh is effectivly updated, remove simplified meshes
308 
309  createSimplifiedMeshes();
310 }
311 
312 QgsMeshLayerRendererCache *QgsMeshLayer::rendererCache()
313 {
314  return mRendererCache.get();
315 }
316 
318 {
319  return mRendererSettings;
320 }
321 
323 {
324  const int oldActiveScalar = mRendererSettings.activeScalarDatasetGroup();
325  const int oldActiveVector = mRendererSettings.activeVectorDatasetGroup();
326  mRendererSettings = settings;
327 
328  if ( oldActiveScalar != mRendererSettings.activeScalarDatasetGroup() )
329  emit activeScalarDatasetGroupChanged( mRendererSettings.activeScalarDatasetGroup() );
330 
331  if ( oldActiveVector != mRendererSettings.activeVectorDatasetGroup() )
332  emit activeVectorDatasetGroupChanged( mRendererSettings.activeVectorDatasetGroup() );
333 
334  emit rendererChanged();
335  triggerRepaint();
336 }
337 
339 {
340  return mTimeSettings;
341 }
342 
344 {
345  mTimeSettings = settings;
346  emit timeSettingsChanged();
347 }
348 
349 QString QgsMeshLayer::formatTime( double hours )
350 {
351  if ( dataProvider() && dataProvider()->temporalCapabilities()->hasReferenceTime() )
352  return QgsMeshLayerUtils::formatTime( hours, mTemporalProperties->referenceTime(), mTimeSettings );
353  else
354  return QgsMeshLayerUtils::formatTime( hours, QDateTime(), mTimeSettings );
355 }
356 
358 {
359  return mDatasetGroupStore->datasetGroupCount();
360 }
361 
363 {
364  return mDatasetGroupStore->extraDatasetGroupCount();
365 }
366 
368 {
369  return mDatasetGroupStore->datasetGroupIndexes();
370 }
371 
373 {
374  return mDatasetGroupStore->enabledDatasetGroupIndexes();
375 }
376 
378 {
379  return mDatasetGroupStore->datasetGroupMetadata( index );
380 }
381 
383 {
384  return mDatasetGroupStore->datasetCount( index.group() );
385 }
386 
388 {
389  return mDatasetGroupStore->datasetMetadata( index );
390 }
391 
393 {
394  return mDatasetGroupStore->datasetValue( index, valueIndex );
395 }
396 
397 QgsMeshDataBlock QgsMeshLayer::datasetValues( const QgsMeshDatasetIndex &index, int valueIndex, int count ) const
398 {
399  return mDatasetGroupStore->datasetValues( index, valueIndex, count );
400 }
401 
402 QgsMesh3dDataBlock QgsMeshLayer::dataset3dValues( const QgsMeshDatasetIndex &index, int faceIndex, int count ) const
403 {
404  return mDatasetGroupStore->dataset3dValues( index, faceIndex, count );
405 }
406 
407 QgsMeshDataBlock QgsMeshLayer::areFacesActive( const QgsMeshDatasetIndex &index, int faceIndex, int count ) const
408 {
409  return mDatasetGroupStore->areFacesActive( index, faceIndex, count );
410 }
411 
412 bool QgsMeshLayer::isFaceActive( const QgsMeshDatasetIndex &index, int faceIndex ) const
413 {
414  return mDatasetGroupStore->isFaceActive( index, faceIndex );
415 }
416 
417 QgsMeshDatasetValue QgsMeshLayer::datasetValue( const QgsMeshDatasetIndex &index, const QgsPointXY &point, double searchRadius ) const
418 {
419  QgsMeshDatasetValue value;
420  const QgsTriangularMesh *mesh = triangularMesh();
421 
422  if ( mesh && index.isValid() )
423  {
424  if ( contains( QgsMesh::ElementType::Edge ) )
425  {
426  const QgsRectangle searchRectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
427  return dataset1dValue( index, point, searchRadius );
428  }
429  const int faceIndex = mesh->faceIndexForPoint_v2( point ) ;
430  if ( faceIndex >= 0 )
431  {
432  const int nativeFaceIndex = mesh->trianglesToNativeFaces().at( faceIndex );
434  if ( isFaceActive( index, nativeFaceIndex ) )
435  {
436  switch ( dataType )
437  {
439  {
440  value = datasetValue( index, nativeFaceIndex );
441  }
442  break;
443 
445  {
446  const QgsMeshFace &face = mesh->triangles()[faceIndex];
447  const int v1 = face[0], v2 = face[1], v3 = face[2];
448  const QgsPoint p1 = mesh->vertices()[v1], p2 = mesh->vertices()[v2], p3 = mesh->vertices()[v3];
449  const QgsMeshDatasetValue val1 = datasetValue( index, v1 );
450  const QgsMeshDatasetValue val2 = datasetValue( index, v2 );
451  const QgsMeshDatasetValue val3 = datasetValue( index, v3 );
452  const double x = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.x(), val2.x(), val3.x(), point );
453  double y = std::numeric_limits<double>::quiet_NaN();
454  const bool isVector = datasetGroupMetadata( index ).isVector();
455  if ( isVector )
456  y = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.y(), val2.y(), val3.y(), point );
457 
458  value = QgsMeshDatasetValue( x, y );
459  }
460  break;
461 
463  {
464  const QgsMesh3dAveragingMethod *avgMethod = mRendererSettings.averagingMethod();
465  if ( avgMethod )
466  {
467  const QgsMesh3dDataBlock block3d = dataset3dValues( index, nativeFaceIndex, 1 );
468  const QgsMeshDataBlock block2d = avgMethod->calculate( block3d );
469  if ( block2d.isValid() )
470  {
471  value = block2d.value( 0 );
472  }
473  }
474  }
475  break;
476 
477  default:
478  break;
479  }
480  }
481  }
482  }
483 
484  return value;
485 }
486 
488 {
489  QgsMesh3dDataBlock block3d;
490 
491  const QgsTriangularMesh *baseTriangularMesh = triangularMesh();
492 
493  if ( baseTriangularMesh && dataProvider() && dataProvider()->isValid() && index.isValid() )
494  {
497  {
498  const int faceIndex = baseTriangularMesh->faceIndexForPoint_v2( point );
499  if ( faceIndex >= 0 )
500  {
501  const int nativeFaceIndex = baseTriangularMesh->trianglesToNativeFaces().at( faceIndex );
502  block3d = dataset3dValues( index, nativeFaceIndex, 1 );
503  }
504  }
505  }
506  return block3d;
507 }
508 
509 QgsMeshDatasetValue QgsMeshLayer::dataset1dValue( const QgsMeshDatasetIndex &index, const QgsPointXY &point, double searchRadius ) const
510 {
511  QgsMeshDatasetValue value;
512  QgsPointXY projectedPoint;
513  const int selectedIndex = closestEdge( point, searchRadius, projectedPoint );
514  const QgsTriangularMesh *mesh = triangularMesh();
515  if ( selectedIndex >= 0 )
516  {
518  switch ( dataType )
519  {
521  {
522  value = datasetValue( index, selectedIndex );
523  }
524  break;
525 
527  {
528  const QgsMeshEdge &edge = mesh->edges()[selectedIndex];
529  const int v1 = edge.first, v2 = edge.second;
530  const QgsPoint p1 = mesh->vertices()[v1], p2 = mesh->vertices()[v2];
531  const QgsMeshDatasetValue val1 = datasetValue( index, v1 );
532  const QgsMeshDatasetValue val2 = datasetValue( index, v2 );
533  const double edgeLength = p1.distance( p2 );
534  const double dist1 = p1.distance( projectedPoint.x(), projectedPoint.y() );
535  value = QgsMeshLayerUtils::interpolateFromVerticesData( dist1 / edgeLength, val1, val2 );
536  }
537  break;
538  default:
539  break;
540  }
541  }
542 
543  return value;
544 }
545 
547 {
548  if ( mDataProvider )
549  mDataProvider->setTransformContext( transformContext );
551 }
552 
553 QgsMeshDatasetIndex QgsMeshLayer::datasetIndexAtTime( const QgsDateTimeRange &timeRange, int datasetGroupIndex ) const
554 {
555  if ( ! mTemporalProperties->isActive() )
556  return QgsMeshDatasetIndex( datasetGroupIndex, -1 );
557 
558  const QDateTime layerReferenceTime = mTemporalProperties->referenceTime();
559  QDateTime utcTime = timeRange.begin();
560  if ( utcTime.timeSpec() != Qt::UTC )
561  utcTime.setTimeSpec( Qt::UTC );
562  const qint64 startTime = layerReferenceTime.msecsTo( utcTime );
563 
564  return mDatasetGroupStore->datasetIndexAtTime( startTime, datasetGroupIndex, mTemporalProperties->matchingMethod() );
565 }
566 
567 QgsMeshDatasetIndex QgsMeshLayer::datasetIndexAtRelativeTime( const QgsInterval &relativeTime, int datasetGroupIndex ) const
568 {
569  qint64 usedRelativeTime = relativeTime.seconds() * 1000;
570 
571  //adjust relative time if layer reference time is different from provider reference time
572  if ( mTemporalProperties->referenceTime().isValid() &&
573  mDataProvider &&
574  mDataProvider->isValid() &&
575  mTemporalProperties->referenceTime() != mDataProvider->temporalCapabilities()->referenceTime() )
576  usedRelativeTime = usedRelativeTime + mTemporalProperties->referenceTime().msecsTo( mDataProvider->temporalCapabilities()->referenceTime() );
577 
578  return mDatasetGroupStore->datasetIndexAtTime( relativeTime.seconds() * 1000, datasetGroupIndex, mTemporalProperties->matchingMethod() );
579 }
580 
581 void QgsMeshLayer::applyClassificationOnScalarSettings( const QgsMeshDatasetGroupMetadata &meta, QgsMeshRendererScalarSettings &scalarSettings ) const
582 {
583  if ( meta.extraOptions().contains( QStringLiteral( "classification" ) ) )
584  {
585  QgsColorRampShader colorRampShader = scalarSettings.colorRampShader();
586  QgsColorRamp *colorRamp = colorRampShader.sourceColorRamp();
587  const QStringList classes = meta.extraOptions()[QStringLiteral( "classification" )].split( QStringLiteral( ";;" ) );
588 
589  QString units;
590  if ( meta.extraOptions().contains( QStringLiteral( "units" ) ) )
591  units = meta.extraOptions()[ QStringLiteral( "units" )];
592 
593  QVector<QVector<double>> bounds;
594  for ( const QString &classe : classes )
595  {
596  const QStringList boundsStr = classe.split( ',' );
597  QVector<double> bound;
598  for ( const QString &boundStr : boundsStr )
599  bound.append( boundStr.toDouble() );
600  bounds.append( bound );
601  }
602 
603  if ( ( bounds.count() == 1 && bounds.first().count() > 2 ) || // at least a class with two value
604  ( bounds.count() > 1 ) ) // or at least two classes
605  {
606  const QVector<double> firstClass = bounds.first();
607  const QVector<double> lastClass = bounds.last();
608  const double minValue = firstClass.count() > 1 ? ( firstClass.first() + firstClass.last() ) / 2 : firstClass.first();
609  const double maxValue = lastClass.count() > 1 ? ( lastClass.first() + lastClass.last() ) / 2 : lastClass.first();
610  const double diff = maxValue - minValue;
611  QList<QgsColorRampShader::ColorRampItem> colorRampItemlist;
612  for ( int i = 0; i < bounds.count(); ++i )
613  {
614  const QVector<double> &boundClass = bounds.at( i );
616  item.value = i + 1;
617  if ( !boundClass.isEmpty() )
618  {
619  const double scalarValue = ( boundClass.first() + boundClass.last() ) / 2;
620  item.color = colorRamp->color( ( scalarValue - minValue ) / diff );
621  if ( i != 0 && i < bounds.count() - 1 ) //The first and last labels are treated after
622  {
623  item.label = QString( ( "%1 - %2 %3" ) ).
624  arg( QString::number( boundClass.first() ) ).
625  arg( QString::number( boundClass.last() ) ).
626  arg( units );
627  }
628  }
629  colorRampItemlist.append( item );
630  }
631  //treat first and last labels
632  if ( firstClass.count() == 1 )
633  colorRampItemlist.first().label = QObject::tr( "below %1 %2" ).
634  arg( QString::number( firstClass.first() ) ).
635  arg( units );
636  else
637  {
638  colorRampItemlist.first().label = QString( ( "%1 - %2 %3" ) ).
639  arg( QString::number( firstClass.first() ) ).
640  arg( QString::number( firstClass.last() ) ).
641  arg( units );
642  }
643 
644  if ( lastClass.count() == 1 )
645  colorRampItemlist.last().label = QObject::tr( "above %1 %2" ).
646  arg( QString::number( lastClass.first() ) ).
647  arg( units );
648  else
649  {
650  colorRampItemlist.last().label = QString( ( "%1 - %2 %3" ) ).
651  arg( QString::number( lastClass.first() ) ).
652  arg( QString::number( lastClass.last() ) ).
653  arg( units );
654  }
655 
656  colorRampShader.setMinimumValue( 0 );
657  colorRampShader.setMaximumValue( colorRampItemlist.count() - 1 );
658  scalarSettings.setClassificationMinimumMaximum( 0, colorRampItemlist.count() - 1 );
659  colorRampShader.setColorRampItemList( colorRampItemlist );
660  colorRampShader.setColorRampType( QgsColorRampShader::Exact );
662  }
663 
664  scalarSettings.setColorRampShader( colorRampShader );
666  }
667 }
668 
669 QgsMeshDatasetIndex QgsMeshLayer::activeScalarDatasetAtTime( const QgsDateTimeRange &timeRange ) const
670 {
671  if ( mTemporalProperties->isActive() )
672  return datasetIndexAtTime( timeRange, mRendererSettings.activeScalarDatasetGroup() );
673  else
674  return QgsMeshDatasetIndex( mRendererSettings.activeScalarDatasetGroup(), mStaticScalarDatasetIndex );
675 }
676 
677 QgsMeshDatasetIndex QgsMeshLayer::activeVectorDatasetAtTime( const QgsDateTimeRange &timeRange ) const
678 {
679  if ( mTemporalProperties->isActive() )
680  return datasetIndexAtTime( timeRange, mRendererSettings.activeVectorDatasetGroup() );
681  else
682  return QgsMeshDatasetIndex( mRendererSettings.activeVectorDatasetGroup(), mStaticVectorDatasetIndex );
683 }
684 
685 void QgsMeshLayer::fillNativeMesh()
686 {
687  Q_ASSERT( !mNativeMesh );
688 
689  mNativeMesh.reset( new QgsMesh() );
690 
691  if ( !( dataProvider() && dataProvider()->isValid() ) )
692  return;
693 
694  dataProvider()->populateMesh( mNativeMesh.get() );
695 }
696 
697 void QgsMeshLayer::onDatasetGroupsAdded( const QList<int> &datasetGroupIndexes )
698 {
699  // assign default style to new dataset groups
700  for ( int i = 0; i < datasetGroupIndexes.count(); ++i )
701  assignDefaultStyleToDatasetGroup( datasetGroupIndexes.at( i ) );
702 
703  temporalProperties()->setIsActive( mDatasetGroupStore->hasTemporalCapabilities() );
704  emit rendererChanged();
705 }
706 
707 void QgsMeshLayer::onMeshEdited()
708 {
709  mRendererCache.reset( new QgsMeshLayerRendererCache() );
710  emit layerModified();
711  triggerRepaint();
712  trigger3DUpdate();
713 }
714 
716 {
717  return mDatasetGroupStore->datasetGroupTreeItem();
718 }
719 
721 {
722  mDatasetGroupStore->setDatasetGroupTreeItem( rootItem );
723  updateActiveDatasetGroups();
724 }
725 
726 int QgsMeshLayer::closestEdge( const QgsPointXY &point, double searchRadius, QgsPointXY &projectedPoint ) const
727 {
728  const QgsRectangle searchRectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
729  const QgsTriangularMesh *mesh = triangularMesh();
730  // search for the closest edge in search area from point
731  const QList<int> edgeIndexes = mesh->edgeIndexesForRectangle( searchRectangle );
732  int selectedIndex = -1;
733  if ( mesh->contains( QgsMesh::Edge ) &&
734  mDataProvider->isValid() )
735  {
736  double sqrMaxDistFromPoint = pow( searchRadius, 2 );
737  for ( const int edgeIndex : edgeIndexes )
738  {
739  const QgsMeshEdge &edge = mesh->edges().at( edgeIndex );
740  const QgsMeshVertex &vertex1 = mesh->vertices()[edge.first];
741  const QgsMeshVertex &vertex2 = mesh->vertices()[edge.second];
742  QgsPointXY projPoint;
743  const double sqrDist = point.sqrDistToSegment( vertex1.x(), vertex1.y(), vertex2.x(), vertex2.y(), projPoint );
744  if ( sqrDist < sqrMaxDistFromPoint )
745  {
746  selectedIndex = edgeIndex;
747  projectedPoint = projPoint;
748  sqrMaxDistFromPoint = sqrDist;
749  }
750  }
751  }
752 
753  return selectedIndex;
754 }
755 
757 {
758  return QgsMeshDatasetIndex( mRendererSettings.activeVectorDatasetGroup(), mStaticVectorDatasetIndex );
759 }
760 
761 void QgsMeshLayer::setReferenceTime( const QDateTime &referenceTime )
762 {
763  if ( auto *lDataProvider = dataProvider() )
764  mTemporalProperties->setReferenceTime( referenceTime, lDataProvider->temporalCapabilities() );
765  else
766  mTemporalProperties->setReferenceTime( referenceTime, nullptr );
767 }
768 
770 {
771  mTemporalProperties->setMatchingMethod( matchingMethod );
772 }
773 
774 QgsPointXY QgsMeshLayer::snapOnVertex( const QgsPointXY &point, double searchRadius )
775 {
776  const QgsTriangularMesh *mesh = triangularMesh();
777  QgsPointXY exactPosition;
778  if ( !mesh )
779  return exactPosition;
780  const QgsRectangle rectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
781  double maxDistance = searchRadius;
782  //attempt to snap on edges's vertices
783  const QList<int> edgeIndexes = mesh->edgeIndexesForRectangle( rectangle );
784  for ( const int edgeIndex : edgeIndexes )
785  {
786  const QgsMeshEdge &edge = mesh->edges().at( edgeIndex );
787  const QgsMeshVertex &vertex1 = mesh->vertices()[edge.first];
788  const QgsMeshVertex &vertex2 = mesh->vertices()[edge.second];
789  const double dist1 = point.distance( vertex1 );
790  const double dist2 = point.distance( vertex2 );
791  if ( dist1 < maxDistance )
792  {
793  maxDistance = dist1;
794  exactPosition = vertex1;
795  }
796  if ( dist2 < maxDistance )
797  {
798  maxDistance = dist2;
799  exactPosition = vertex2;
800  }
801  }
802 
803  //attempt to snap on face's vertices
804  const QList<int> faceIndexes = mesh->faceIndexesForRectangle( rectangle );
805  for ( const int faceIndex : faceIndexes )
806  {
807  const QgsMeshFace &face = mesh->triangles().at( faceIndex );
808  for ( int i = 0; i < 3; ++i )
809  {
810  const QgsMeshVertex &vertex = mesh->vertices()[face.at( i )];
811  const double dist = point.distance( vertex );
812  if ( dist < maxDistance )
813  {
814  maxDistance = dist;
815  exactPosition = vertex;
816  }
817  }
818  }
819 
820  return exactPosition;
821 }
822 
823 QgsPointXY QgsMeshLayer::snapOnEdge( const QgsPointXY &point, double searchRadius )
824 {
825  QgsPointXY projectedPoint;
826  closestEdge( point, searchRadius, projectedPoint );
827 
828  return projectedPoint;
829 }
830 
831 QgsPointXY QgsMeshLayer::snapOnFace( const QgsPointXY &point, double searchRadius )
832 {
833  const QgsTriangularMesh *mesh = triangularMesh();
834  QgsPointXY centroidPosition;
835  if ( !mesh )
836  return centroidPosition;
837  const QgsRectangle rectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
838  double maxDistance = std::numeric_limits<double>::max();
839 
840  const QList<int> faceIndexes = mesh->faceIndexesForRectangle( rectangle );
841  for ( const int faceIndex : faceIndexes )
842  {
843  const int nativefaceIndex = mesh->trianglesToNativeFaces().at( faceIndex );
844  if ( nativefaceIndex < 0 && nativefaceIndex >= mesh->faceCentroids().count() )
845  continue;
846  const QgsPointXY centroid = mesh->faceCentroids()[nativefaceIndex];
847  const double dist = point.distance( centroid );
848  if ( dist < maxDistance )
849  {
850  maxDistance = dist;
851  centroidPosition = centroid;
852  }
853  }
854 
855  return centroidPosition;
856 }
857 
859 {
860  mDatasetGroupStore->resetDatasetGroupTreeItem();
861  updateActiveDatasetGroups();
862 }
863 
865 {
866  if ( !mDataProvider )
867  return QgsInterval();
868  const int groupCount = mDataProvider->datasetGroupCount();
869  for ( int i = 0; i < groupCount; ++i )
870  {
871  const qint64 timeStep = mDataProvider->temporalCapabilities()->firstTimeStepDuration( i );
872  if ( timeStep > 0 )
874  }
875 
876  return QgsInterval();
877 }
878 
880 {
881  const qint64 time = mDatasetGroupStore->datasetRelativeTime( index );
882 
883  if ( time == INVALID_MESHLAYER_TIME )
884  return QgsInterval();
885  else
887 }
888 
890 {
891  return mDatasetGroupStore->datasetRelativeTime( index );
892 }
893 
895 {
896  if ( !supportsEditing() )
897  {
898  QgsMessageLog::logMessage( QObject::tr( "Mesh layer \"%1\" not support mesh editing" ).arg( name() ) );
899  return false;
900  }
901 
902  if ( mMeshEditor )
903  {
904  QgsMessageLog::logMessage( QObject::tr( "Mesh layer \"%1\" already in editing mode" ).arg( name() ) );
905  return false;
906  }
907 
908  updateTriangularMesh( transform );
909 
910  mMeshEditor = new QgsMeshEditor( this );
911 
912  const QgsMeshEditingError error = mMeshEditor->initialize();
913 
914  if ( error.errorType != Qgis::MeshEditingErrorType::NoError )
915  {
916  mMeshEditor->deleteLater();
917  mMeshEditor = nullptr;
918  QgsMessageLog::logMessage( QObject::tr( "Unable to start editing of mesh layer \"%1\"." ).arg( name() ), QString(), Qgis::MessageLevel::Critical );
919  return false;
920  }
921 
922  // During editing, we don't need anymore the provider data. Mesh frame data is stored in the mesh editor.
923  mDataProvider->close();
924 
925  // All dataset group are removed and replace by a unique virtual dataset group that provide vertices elevation value.
926  mExtraDatasetUri.clear();
927  mDatasetGroupStore.reset( new QgsMeshDatasetGroupStore( this ) );
928  mDatasetGroupStore->addDatasetGroup( mMeshEditor->createZValueDatasetGroup() );
930 
931  connect( mMeshEditor, &QgsMeshEditor::meshEdited, this, &QgsMeshLayer::onMeshEdited );
932 
933  emit dataChanged();
934  emit editingStarted();
935 
936  return true;
937 }
938 
939 bool QgsMeshLayer::commitFrameEditing( const QgsCoordinateTransform &transform, bool continueEditing )
940 {
941  if ( !mMeshEditor->checkConsistency() )
942  {
943  QgsMessageLog::logMessage( QObject::tr( "Mesh layer \"%1\" not support mesh editing" ).arg( name() ), QString(), Qgis::MessageLevel::Critical );
944  return false;
945  }
946 
947  stopFrameEditing( transform );
948 
949  if ( !mDataProvider )
950  return false;
951 
952  const bool res = mDataProvider->saveMeshFrame( *mNativeMesh.get() );
953 
954  if ( continueEditing )
955  {
956  mMeshEditor->initialize();
957  emit layerModified();
958  return res;
959  }
960 
961  mMeshEditor->deleteLater();
962  mMeshEditor = nullptr;
963  emit editingStopped();
964 
965  mDataProvider->reloadData();
966  mDataProvider->populateMesh( mNativeMesh.get() );
967  mDatasetGroupStore.reset( new QgsMeshDatasetGroupStore( this ) );
968  mDatasetGroupStore->setPersistentProvider( mDataProvider, QStringList() );
970  return true;
971 }
972 
973 bool QgsMeshLayer::rollBackFrameEditing( const QgsCoordinateTransform &transform, bool continueEditing )
974 {
975  stopFrameEditing( transform );
976 
977  if ( !mDataProvider )
978  return false;
979 
980  mTriangularMeshes.clear();
981  mDataProvider->reloadData();
982  mDataProvider->populateMesh( mNativeMesh.get() );
983  updateTriangularMesh( transform );
984  mRendererCache.reset( new QgsMeshLayerRendererCache() );
985  trigger3DUpdate();
986 
987  if ( continueEditing )
988  {
989  mMeshEditor->resetTriangularMesh( triangularMesh() );
990  return mMeshEditor->initialize() == QgsMeshEditingError();
991  }
992  else
993  {
994  mMeshEditor->deleteLater();
995  mMeshEditor = nullptr;
996  emit editingStopped();
997 
998  mDatasetGroupStore.reset( new QgsMeshDatasetGroupStore( this ) );
999  mDatasetGroupStore->setPersistentProvider( mDataProvider, QStringList() );
1001  emit dataChanged();
1002  return true;
1003  }
1004 }
1005 
1007 {
1008  if ( !mMeshEditor )
1009  return;
1010 
1011  mMeshEditor->stopEditing();
1012  mTriangularMeshes.at( 0 )->update( mNativeMesh.get(), transform );
1013  mRendererCache.reset( new QgsMeshLayerRendererCache() );
1014 }
1015 
1016 bool QgsMeshLayer::reindex( const QgsCoordinateTransform &transform, bool renumber )
1017 {
1018  if ( !mMeshEditor )
1019  return false;
1020 
1021  if ( !mMeshEditor->reindex( renumber ) )
1022  return false;
1023 
1024  mTriangularMeshes.clear();
1025  mTriangularMeshes.emplace_back( new QgsTriangularMesh );
1026  mTriangularMeshes.at( 0 )->update( mNativeMesh.get(), transform );
1027  mRendererCache.reset( new QgsMeshLayerRendererCache() );
1028  mMeshEditor->resetTriangularMesh( mTriangularMeshes.at( 0 ).get() );
1029 
1030  return true;
1031 }
1032 
1034 {
1035  return mMeshEditor;
1036 }
1037 
1039 {
1040  if ( mMeshEditor )
1041  return mMeshEditor->isModified();
1042 
1043  return false;
1044 }
1045 
1047 {
1048  switch ( type )
1049  {
1050  case QgsMesh::ElementType::Vertex:
1051  return meshVertexCount() != 0;
1052  case QgsMesh::ElementType::Edge:
1053  return meshEdgeCount() != 0;
1054  case QgsMesh::ElementType::Face:
1055  return meshFaceCount() != 0;
1056  }
1057  return false;
1058 }
1059 
1061 {
1062  if ( mMeshEditor )
1063  return mMeshEditor->validVerticesCount();
1064  else if ( mDataProvider )
1065  return mDataProvider->vertexCount();
1066  else return 0;
1067 }
1068 
1070 {
1071  if ( mMeshEditor )
1072  return mMeshEditor->validFacesCount();
1073  else if ( mDataProvider )
1074  return mDataProvider->faceCount();
1075  else return 0;
1076 }
1077 
1079 {
1080  if ( mMeshEditor )
1081  return mNativeMesh->edgeCount();
1082  else if ( mDataProvider )
1083  return mDataProvider->edgeCount();
1084  else return 0;
1085 }
1086 
1087 void QgsMeshLayer::updateActiveDatasetGroups()
1088 {
1089  QgsMeshDatasetGroupTreeItem *treeItem = mDatasetGroupStore->datasetGroupTreeItem();
1090 
1091  if ( !mDatasetGroupStore->datasetGroupTreeItem() )
1092  return;
1093 
1095  const int oldActiveScalar = settings.activeScalarDatasetGroup();
1096  const int oldActiveVector = settings.activeVectorDatasetGroup();
1097 
1098  QgsMeshDatasetGroupTreeItem *activeScalarItem =
1099  treeItem->childFromDatasetGroupIndex( oldActiveScalar );
1100 
1101  if ( !activeScalarItem && treeItem->childCount() > 0 )
1102  activeScalarItem = treeItem->child( 0 );
1103 
1104  if ( activeScalarItem && !activeScalarItem->isEnabled() )
1105  {
1106  for ( int i = 0; i < treeItem->childCount(); ++i )
1107  {
1108  activeScalarItem = treeItem->child( i );
1109  if ( activeScalarItem->isEnabled() )
1110  break;
1111  else
1112  activeScalarItem = nullptr;
1113  }
1114  }
1115 
1116  if ( activeScalarItem )
1117  settings.setActiveScalarDatasetGroup( activeScalarItem->datasetGroupIndex() );
1118  else
1119  settings.setActiveScalarDatasetGroup( -1 );
1120 
1121  QgsMeshDatasetGroupTreeItem *activeVectorItem =
1122  treeItem->childFromDatasetGroupIndex( oldActiveVector );
1123 
1124  if ( !( activeVectorItem && activeVectorItem->isEnabled() ) )
1125  settings.setActiveVectorDatasetGroup( -1 );
1126 
1127  setRendererSettings( settings );
1128 
1129  if ( oldActiveScalar != settings.activeScalarDatasetGroup() )
1131  if ( oldActiveVector != settings.activeVectorDatasetGroup() )
1133 }
1134 
1135 void QgsMeshLayer::setDataSourcePrivate( const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags )
1136 {
1137  mDataSource = dataSource;
1138  mLayerName = baseName;
1139  setProviderType( provider );
1140 
1141  // if we’re given a provider type, try to create and bind one to this layer
1142  bool ok = false;
1143  if ( !mDataSource.isEmpty() && !provider.isEmpty() )
1144  {
1145  ok = setDataProvider( provider, options, flags );
1146  }
1147 
1148  if ( ok )
1149  {
1150  mTemporalProperties->setDefaultsFromDataProviderTemporalCapabilities( mDataProvider->temporalCapabilities() );
1151  }
1152 }
1153 
1154 QgsPointXY QgsMeshLayer::snapOnElement( QgsMesh::ElementType elementType, const QgsPointXY &point, double searchRadius )
1155 {
1156  switch ( elementType )
1157  {
1158  case QgsMesh::Vertex:
1159  return snapOnVertex( point, searchRadius );
1160  case QgsMesh::Edge:
1161  return snapOnEdge( point, searchRadius );
1162  case QgsMesh::Face:
1163  return snapOnFace( point, searchRadius );
1164  }
1165  return QgsPointXY(); // avoid warnings
1166 }
1167 
1169 {
1170  if ( !mNativeMesh )
1171  {
1172  // lazy loading of mesh data
1173  fillNativeMesh();
1174  }
1175 
1176  QList<int> ret;
1177 
1178  if ( !mNativeMesh )
1179  return ret;
1180 
1181  QgsExpressionContext context;
1182  std::unique_ptr<QgsExpressionContextScope> expScope( QgsExpressionContextUtils::meshExpressionScope( QgsMesh::Vertex ) );
1183  context.appendScope( expScope.release() );
1184  context.lastScope()->setVariable( QStringLiteral( "_mesh_layer" ), QVariant::fromValue( this ) );
1185 
1186  expression.prepare( &context );
1187 
1188  for ( int i = 0; i < mNativeMesh->vertexCount(); ++i )
1189  {
1190  context.lastScope()->setVariable( QStringLiteral( "_mesh_vertex_index" ), i, false );
1191 
1192  if ( expression.evaluate( &context ).toBool() )
1193  ret.append( i );
1194  }
1195 
1196  return ret;
1197 }
1198 
1200 {
1201  if ( !mNativeMesh )
1202  {
1203  // lazy loading of mesh data
1204  fillNativeMesh();
1205  }
1206 
1207  QList<int> ret;
1208 
1209  if ( !mNativeMesh )
1210  return ret;
1211 
1212  QgsExpressionContext context;
1213  std::unique_ptr<QgsExpressionContextScope> expScope( QgsExpressionContextUtils::meshExpressionScope( QgsMesh::Face ) );
1214  context.appendScope( expScope.release() );
1215  context.lastScope()->setVariable( QStringLiteral( "_mesh_layer" ), QVariant::fromValue( this ) );
1216 
1217  expression.prepare( &context );
1218 
1219  for ( int i = 0; i < mNativeMesh->faceCount(); ++i )
1220  {
1221  context.lastScope()->setVariable( QStringLiteral( "_mesh_face_index" ), i, false );
1222 
1223  if ( expression.evaluate( &context ).toBool() )
1224  ret.append( i );
1225  }
1226 
1227  return ret;
1228 }
1229 
1231 {
1232  return QgsMeshDatasetIndex( mRendererSettings.activeScalarDatasetGroup(), mStaticScalarDatasetIndex );
1233 }
1234 
1236 {
1237  const int oldActiveVector = mRendererSettings.activeVectorDatasetGroup();
1238 
1239  mStaticVectorDatasetIndex = staticVectorDatasetIndex.dataset();
1241 
1242  if ( oldActiveVector != mRendererSettings.activeVectorDatasetGroup() )
1243  emit activeVectorDatasetGroupChanged( mRendererSettings.activeVectorDatasetGroup() );
1244 }
1245 
1247 {
1248  const int oldActiveScalar = mRendererSettings.activeScalarDatasetGroup();
1249 
1250  mStaticScalarDatasetIndex = staticScalarDatasetIndex.dataset();
1252 
1253  if ( oldActiveScalar != mRendererSettings.activeScalarDatasetGroup() )
1254  emit activeScalarDatasetGroupChanged( mRendererSettings.activeScalarDatasetGroup() );
1255 }
1256 
1258 {
1259  return mSimplificationSettings;
1260 }
1261 
1263 {
1264  mSimplificationSettings = simplifySettings;
1265 }
1266 
1267 static QgsColorRamp *_createDefaultColorRamp()
1268 {
1269  QgsColorRamp *ramp = QgsStyle::defaultStyle()->colorRamp( QStringLiteral( "Plasma" ) );
1270  if ( ramp )
1271  return ramp;
1272 
1273  // definition of "Plasma" color ramp (in case it is not available in the style for some reason)
1274  QVariantMap props;
1275  props["color1"] = "13,8,135,255";
1276  props["color2"] = "240,249,33,255";
1277  props["stops"] =
1278  "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:"
1279  "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:"
1280  "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:"
1281  "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:"
1282  "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:"
1283  "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:"
1284  "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:"
1285  "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:"
1286  "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:"
1287  "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";
1288  return QgsGradientColorRamp::create( props );
1289 }
1290 
1291 void QgsMeshLayer::assignDefaultStyleToDatasetGroup( int groupIndex )
1292 {
1294  const double groupMin = metadata.minimum();
1295  const double groupMax = metadata.maximum();
1296 
1297  QgsColorRampShader fcn( groupMin, groupMax, _createDefaultColorRamp() );
1298  fcn.classifyColorRamp( 5, -1, QgsRectangle(), nullptr );
1299 
1300  QgsMeshRendererScalarSettings scalarSettings;
1301  scalarSettings.setClassificationMinimumMaximum( groupMin, groupMax );
1302  scalarSettings.setColorRampShader( fcn );
1303  QgsInterpolatedLineWidth edgeStrokeWidth;
1304  edgeStrokeWidth.setMinimumValue( groupMin );
1305  edgeStrokeWidth.setMaximumValue( groupMax );
1306  const QgsInterpolatedLineColor edgeStrokeColor( fcn );
1307  const QgsInterpolatedLineRenderer edgeStrokePen;
1308  scalarSettings.setEdgeStrokeWidth( edgeStrokeWidth );
1309  mRendererSettings.setScalarSettings( groupIndex, scalarSettings );
1310 
1311  if ( metadata.isVector() )
1312  {
1313  QgsMeshRendererVectorSettings vectorSettings;
1314  vectorSettings.setColorRampShader( fcn );
1315  mRendererSettings.setVectorSettings( groupIndex, vectorSettings );
1316  }
1317 }
1318 
1320 {
1321  // Triangular mesh
1322  updateTriangularMesh( rendererContext.coordinateTransform() );
1323 
1324  // Build overview triangular meshes if needed
1325  createSimplifiedMeshes();
1326 
1327  // Cache
1328  if ( !mRendererCache )
1329  mRendererCache.reset( new QgsMeshLayerRendererCache() );
1330 
1331  return new QgsMeshLayerRenderer( this, rendererContext );
1332 }
1333 
1334 bool QgsMeshLayer::readSymbology( const QDomNode &node, QString &errorMessage,
1335  QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
1336 {
1337  Q_UNUSED( errorMessage )
1338  // TODO: implement categories for raster layer
1339 
1340  const QDomElement elem = node.toElement();
1341 
1342  readCommonStyle( elem, context, categories );
1343 
1344  const QDomElement elemRendererSettings = elem.firstChildElement( "mesh-renderer-settings" );
1345  if ( !elemRendererSettings.isNull() )
1346  mRendererSettings.readXml( elemRendererSettings, context );
1347 
1348  const QDomElement elemSimplifySettings = elem.firstChildElement( "mesh-simplify-settings" );
1349  if ( !elemSimplifySettings.isNull() )
1350  mSimplificationSettings.readXml( elemSimplifySettings, context );
1351 
1352  // get and set the blend mode if it exists
1353  const QDomNode blendModeNode = node.namedItem( QStringLiteral( "blendMode" ) );
1354  if ( !blendModeNode.isNull() )
1355  {
1356  const QDomElement e = blendModeNode.toElement();
1357  setBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( e.text().toInt() ) ) );
1358  }
1359 
1360  // get and set the layer transparency
1361  if ( categories.testFlag( Rendering ) )
1362  {
1363  const QDomNode layerOpacityNode = node.namedItem( QStringLiteral( "layerOpacity" ) );
1364  if ( !layerOpacityNode.isNull() )
1365  {
1366  const QDomElement e = layerOpacityNode.toElement();
1367  setOpacity( e.text().toDouble() );
1368  }
1369  }
1370 
1371  return true;
1372 }
1373 
1374 bool QgsMeshLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage,
1375  const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1376 {
1377  Q_UNUSED( errorMessage )
1378  // TODO: implement categories for raster layer
1379 
1380  QDomElement elem = node.toElement();
1381 
1382  writeCommonStyle( elem, doc, context, categories );
1383 
1384  const QDomElement elemRendererSettings = mRendererSettings.writeXml( doc, context );
1385  elem.appendChild( elemRendererSettings );
1386 
1387  const QDomElement elemSimplifySettings = mSimplificationSettings.writeXml( doc, context );
1388  elem.appendChild( elemSimplifySettings );
1389 
1390  // add blend mode node
1391  QDomElement blendModeElement = doc.createElement( QStringLiteral( "blendMode" ) );
1392  const QDomText blendModeText = doc.createTextNode( QString::number( QgsPainting::getBlendModeEnum( blendMode() ) ) );
1393  blendModeElement.appendChild( blendModeText );
1394  node.appendChild( blendModeElement );
1395 
1396  // add the layer opacity
1397  if ( categories.testFlag( Rendering ) )
1398  {
1399  QDomElement layerOpacityElem = doc.createElement( QStringLiteral( "layerOpacity" ) );
1400  const QDomText layerOpacityText = doc.createTextNode( QString::number( opacity() ) );
1401  layerOpacityElem.appendChild( layerOpacityText );
1402  node.appendChild( layerOpacityElem );
1403  }
1404 
1405  return true;
1406 }
1407 
1408 bool QgsMeshLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1409 {
1410  return writeSymbology( node, doc, errorMessage, context, categories );
1411 }
1412 
1413 bool QgsMeshLayer::readStyle( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
1414 {
1415  return readSymbology( node, errorMessage, context, categories );
1416 }
1417 
1418 QString QgsMeshLayer::decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const
1419 {
1420  QString src( source );
1421  if ( provider == QLatin1String( "mdal" ) )
1422  {
1423  src = context.pathResolver().readPath( src );
1424  }
1425  return src;
1426 }
1427 
1428 QString QgsMeshLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
1429 {
1430  QString src( source );
1431  if ( providerType() == QLatin1String( "mdal" ) )
1432  {
1433  src = context.pathResolver().writePath( src );
1434  }
1435  return src;
1436 }
1437 
1438 bool QgsMeshLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &context )
1439 {
1440  QgsDebugMsgLevel( QStringLiteral( "Datasource in QgsMeshLayer::readXml: %1" ).arg( mDataSource.toLocal8Bit().data() ), 3 );
1441 
1442  //process provider key
1443  const QDomNode pkeyNode = layer_node.namedItem( QStringLiteral( "provider" ) );
1444 
1445  if ( pkeyNode.isNull() )
1446  {
1447  mProviderKey.clear();
1448  }
1449  else
1450  {
1451  const QDomElement pkeyElt = pkeyNode.toElement();
1452  mProviderKey = pkeyElt.text();
1453  }
1454 
1456  {
1457  return false;
1458  }
1459 
1460  const QgsDataProvider::ProviderOptions providerOptions;
1461  QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags();
1463  {
1465  }
1466 
1467  const QDomElement elemExtraDatasets = layer_node.firstChildElement( QStringLiteral( "extra-datasets" ) );
1468  if ( !elemExtraDatasets.isNull() )
1469  {
1470  QDomElement elemUri = elemExtraDatasets.firstChildElement( QStringLiteral( "uri" ) );
1471  while ( !elemUri.isNull() )
1472  {
1473  const QString uri = context.pathResolver().readPath( elemUri.text() );
1474  mExtraDatasetUri.append( uri );
1475  elemUri = elemUri.nextSiblingElement( QStringLiteral( "uri" ) );
1476  }
1477  }
1478 
1479  if ( pkeyNode.toElement().hasAttribute( QStringLiteral( "time-unit" ) ) )
1480  mTemporalUnit = static_cast<QgsUnitTypes::TemporalUnit>( pkeyNode.toElement().attribute( QStringLiteral( "time-unit" ) ).toInt() );
1481 
1482  // read dataset group store
1483  const QDomElement elemDatasetGroupsStore = layer_node.firstChildElement( QStringLiteral( "mesh-dataset-groups-store" ) );
1484  if ( elemDatasetGroupsStore.isNull() )
1486  else
1487  mDatasetGroupStore->readXml( elemDatasetGroupsStore, context );
1488 
1489  setDataProvider( mProviderKey, providerOptions, flags );
1490 
1491  QString errorMsg;
1492  readSymbology( layer_node, errorMsg, context );
1493 
1494  if ( !mTemporalProperties->timeExtent().begin().isValid() )
1496 
1497  // read static dataset
1498  const QDomElement elemStaticDataset = layer_node.firstChildElement( QStringLiteral( "static-active-dataset" ) );
1499  if ( elemStaticDataset.hasAttribute( QStringLiteral( "scalar" ) ) )
1500  {
1501  mStaticScalarDatasetIndex = elemStaticDataset.attribute( QStringLiteral( "scalar" ) ).toInt();
1502  }
1503  if ( elemStaticDataset.hasAttribute( QStringLiteral( "vector" ) ) )
1504  {
1505  mStaticVectorDatasetIndex = elemStaticDataset.attribute( QStringLiteral( "vector" ) ).toInt();
1506  }
1507 
1508  return isValid(); // should be true if read successfully
1509 }
1510 
1511 bool QgsMeshLayer::writeXml( QDomNode &layer_node, QDomDocument &document, const QgsReadWriteContext &context ) const
1512 {
1513  // first get the layer element so that we can append the type attribute
1514  QDomElement mapLayerNode = layer_node.toElement();
1515 
1516  if ( mapLayerNode.isNull() || ( QLatin1String( "maplayer" ) != mapLayerNode.nodeName() ) )
1517  {
1518  QgsDebugMsgLevel( QStringLiteral( "can't find <maplayer>" ), 2 );
1519  return false;
1520  }
1521 
1522  mapLayerNode.setAttribute( QStringLiteral( "type" ), QgsMapLayerFactory::typeToString( QgsMapLayerType::MeshLayer ) );
1523 
1524  // add provider node
1525  if ( mDataProvider )
1526  {
1527  QDomElement provider = document.createElement( QStringLiteral( "provider" ) );
1528  const QDomText providerText = document.createTextNode( providerType() );
1529  provider.appendChild( providerText );
1530  layer_node.appendChild( provider );
1531  provider.setAttribute( QStringLiteral( "time-unit" ), mDataProvider->temporalCapabilities()->temporalUnit() );
1532 
1533  const QStringList extraDatasetUris = mDataProvider->extraDatasets();
1534  QDomElement elemExtraDatasets = document.createElement( QStringLiteral( "extra-datasets" ) );
1535  for ( const QString &uri : extraDatasetUris )
1536  {
1537  const QString path = context.pathResolver().writePath( uri );
1538  QDomElement elemUri = document.createElement( QStringLiteral( "uri" ) );
1539  elemUri.appendChild( document.createTextNode( path ) );
1540  elemExtraDatasets.appendChild( elemUri );
1541  }
1542  layer_node.appendChild( elemExtraDatasets );
1543  }
1544 
1545  QDomElement elemStaticDataset = document.createElement( QStringLiteral( "static-active-dataset" ) );
1546  elemStaticDataset.setAttribute( QStringLiteral( "scalar" ), mStaticScalarDatasetIndex );
1547  elemStaticDataset.setAttribute( QStringLiteral( "vector" ), mStaticVectorDatasetIndex );
1548  layer_node.appendChild( elemStaticDataset );
1549 
1550  // write dataset group store if not in edting mode
1551  if ( !isEditable() )
1552  layer_node.appendChild( mDatasetGroupStore->writeXml( document, context ) );
1553 
1554  // renderer specific settings
1555  QString errorMsg;
1556  return writeSymbology( layer_node, document, errorMsg, context );
1557 }
1558 
1560 {
1561  if ( !mMeshEditor && mDataProvider && mDataProvider->isValid() )
1562  {
1563  mDataProvider->reloadData();
1564 
1565  //reload the mesh structure
1566  if ( !mNativeMesh )
1567  mNativeMesh.reset( new QgsMesh );
1568 
1569  dataProvider()->populateMesh( mNativeMesh.get() );
1570 
1571  //clear the TriangularMeshes
1572  mTriangularMeshes.clear();
1573 
1574  //clear the rendererCache
1575  mRendererCache.reset( new QgsMeshLayerRendererCache() );
1576  }
1577 }
1578 
1579 QStringList QgsMeshLayer::subLayers() const
1580 {
1581  if ( mDataProvider )
1582  return mDataProvider->subLayers();
1583  else
1584  return QStringList();
1585 }
1586 
1588 {
1589  const QgsLayerMetadataFormatter htmlFormatter( metadata() );
1590  QString myMetadata = QStringLiteral( "<html>\n<body>\n" );
1591 
1592  myMetadata += generalHtmlMetadata();
1593 
1594  // Begin Provider section
1595  myMetadata += QStringLiteral( "<h1>" ) + tr( "Information from provider" ) + QStringLiteral( "</h1>\n<hr>\n" );
1596  myMetadata += QLatin1String( "<table class=\"list-view\">\n" );
1597 
1598  // Extent
1599  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Extent" ) + QStringLiteral( "</td><td>" ) + extent().toString() + QStringLiteral( "</td></tr>\n" );
1600 
1601  // feature count
1602  QLocale locale = QLocale();
1603  locale.setNumberOptions( locale.numberOptions() &= ~QLocale::NumberOption::OmitGroupSeparator );
1604 
1605  if ( dataProvider() )
1606  {
1607  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
1608  + tr( "Vertex count" ) + QStringLiteral( "</td><td>" )
1609  + ( locale.toString( static_cast<qlonglong>( meshVertexCount() ) ) )
1610  + QStringLiteral( "</td></tr>\n" );
1611  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
1612  + tr( "Face count" ) + QStringLiteral( "</td><td>" )
1613  + ( locale.toString( static_cast<qlonglong>( meshFaceCount() ) ) )
1614  + QStringLiteral( "</td></tr>\n" );
1615  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
1616  + tr( "Edge count" ) + QStringLiteral( "</td><td>" )
1617  + ( locale.toString( static_cast<qlonglong>( meshEdgeCount() ) ) )
1618  + QStringLiteral( "</td></tr>\n" );
1619  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
1620  + tr( "Dataset groups count" ) + QStringLiteral( "</td><td>" )
1621  + ( locale.toString( static_cast<qlonglong>( datasetGroupCount() ) ) )
1622  + QStringLiteral( "</td></tr>\n" );
1623  }
1624 
1625  // End Provider section
1626  myMetadata += QLatin1String( "</table>\n<br><br>" );
1627 
1628  // CRS
1629  myMetadata += crsHtmlMetadata();
1630 
1631  // identification section
1632  myMetadata += QStringLiteral( "<h1>" ) + tr( "Identification" ) + QStringLiteral( "</h1>\n<hr>\n" );
1633  myMetadata += htmlFormatter.identificationSectionHtml( );
1634  myMetadata += QLatin1String( "<br><br>\n" );
1635 
1636  // extent section
1637  myMetadata += QStringLiteral( "<h1>" ) + tr( "Extent" ) + QStringLiteral( "</h1>\n<hr>\n" );
1638  myMetadata += htmlFormatter.extentSectionHtml( isSpatial() );
1639  myMetadata += QLatin1String( "<br><br>\n" );
1640 
1641  // Start the Access section
1642  myMetadata += QStringLiteral( "<h1>" ) + tr( "Access" ) + QStringLiteral( "</h1>\n<hr>\n" );
1643  myMetadata += htmlFormatter.accessSectionHtml( );
1644  myMetadata += QLatin1String( "<br><br>\n" );
1645 
1646  // Start the contacts section
1647  myMetadata += QStringLiteral( "<h1>" ) + tr( "Contacts" ) + QStringLiteral( "</h1>\n<hr>\n" );
1648  myMetadata += htmlFormatter.contactsSectionHtml( );
1649  myMetadata += QLatin1String( "<br><br>\n" );
1650 
1651  // Start the links section
1652  myMetadata += QStringLiteral( "<h1>" ) + tr( "Links" ) + QStringLiteral( "</h1>\n<hr>\n" );
1653  myMetadata += htmlFormatter.linksSectionHtml( );
1654  myMetadata += QLatin1String( "<br><br>\n" );
1655 
1656  // Start the history section
1657  myMetadata += QStringLiteral( "<h1>" ) + tr( "History" ) + QStringLiteral( "</h1>\n<hr>\n" );
1658  myMetadata += htmlFormatter.historySectionHtml( );
1659  myMetadata += QLatin1String( "<br><br>\n" );
1660 
1661  myMetadata += QLatin1String( "\n</body>\n</html>\n" );
1662  return myMetadata;
1663 }
1664 
1666 {
1667  return mMeshEditor != nullptr;
1668 }
1669 
1670 bool QgsMeshLayer::setDataProvider( QString const &provider, const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags )
1671 {
1672  mDatasetGroupStore->setPersistentProvider( nullptr, QStringList() );
1673 
1674  delete mDataProvider;
1675  mProviderKey = provider;
1676  const QString dataSource = mDataSource;
1677 
1678  mDataProvider = qobject_cast<QgsMeshDataProvider *>( QgsProviderRegistry::instance()->createProvider( provider, dataSource, options, flags ) );
1679 
1680  if ( !mDataProvider )
1681  {
1682  QgsDebugMsgLevel( QStringLiteral( "Unable to get mesh data provider" ), 2 );
1683  return false;
1684  }
1685 
1686  mDataProvider->setParent( this );
1687  QgsDebugMsgLevel( QStringLiteral( "Instantiated the mesh data provider plugin" ), 2 );
1688 
1689  setValid( mDataProvider->isValid() );
1690  if ( !isValid() )
1691  {
1692  QgsDebugMsgLevel( QStringLiteral( "Invalid mesh provider plugin %1" ).arg( QString( mDataSource.toUtf8() ) ), 2 );
1693  return false;
1694  }
1695 
1696  mDataProvider->setTemporalUnit( mTemporalUnit );
1697  mDatasetGroupStore->setPersistentProvider( mDataProvider, mExtraDatasetUri );
1698  setCrs( mDataProvider->crs() );
1699 
1700  if ( provider == QLatin1String( "mesh_memory" ) )
1701  {
1702  // required so that source differs between memory layers
1703  mDataSource = mDataSource + QStringLiteral( "&uid=%1" ).arg( QUuid::createUuid().toString() );
1704  }
1705 
1706  for ( int i = 0; i < mDataProvider->datasetGroupCount(); ++i )
1707  assignDefaultStyleToDatasetGroup( i );
1708 
1709  connect( mDataProvider, &QgsMeshDataProvider::dataChanged, this, &QgsMeshLayer::dataChanged );
1710 
1711  return true;
1712 }
1713 
1715 {
1716  return mTemporalProperties;
1717 }
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.
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.
void setVariable(const QString &name, const QVariant &value, bool isStatic=false)
Convenience method for setting a variable in the context scope by name name and value.
static QgsExpressionContextScope * meshExpressionScope(QgsMesh::ElementType elementType)
Creates a new scope which contains functions relating to mesh layer element elementType.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QgsExpressionContextScope * lastScope()
Returns the last scope added to the context.
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
Class for parsing and evaluation of expressions (formerly called "search strings").
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
QVariant evaluate()
Evaluate the feature and return the result.
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 simple line renderer 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:73
QString name
Definition: qgsmaplayer.h:76
virtual bool isSpatial() const
Returns true if the layer is considered a spatial layer, ie it has some form of geometry associated w...
void editingStopped()
Emitted when edited changes have been successfully written to the data provider.
QString source() const
Returns the source for the layer.
void setBlendMode(QPainter::CompositionMode blendMode)
Set the blending mode used for rendering a layer.
QgsMapLayerType type
Definition: qgsmaplayer.h:80
void trigger3DUpdate()
Will advise any 3D maps that this layer requires to be updated in the scene.
QgsMapLayer::LayerFlags flags() const
Returns the flags for this layer.
void editingStarted()
Emitted when editing on this layer has started.
QString mLayerName
Name of the layer - used for display.
Definition: qgsmaplayer.h:1928
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted.
QString crsHtmlMetadata() const
Returns a HTML fragment containing the layer's CRS metadata, for use in the htmlMetadata() method.
QgsLayerMetadata metadata
Definition: qgsmaplayer.h:78
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:1966
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.
virtual QgsError error() const
Gets current status error.
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:81
QString mDataSource
Data source description string, varies by layer type.
Definition: qgsmaplayer.h:1925
@ FlagTrustLayerMetadata
Trust layer metadata. Improves layer load time by skipping expensive checks like primary key unicity,...
Definition: qgsmaplayer.h:638
@ FlagDontResolveLayers
Don't resolve layer paths or create data providers for layers.
Definition: qgsmaplayer.h:637
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:1971
void setLegend(QgsMapLayerLegend *legend)
Assign a legend controller to the map layer.
double opacity
Definition: qgsmaplayer.h:82
@ Rendering
Rendering: scale visibility, simplify method, opacity.
Definition: qgsmaplayer.h:167
void layerModified()
Emitted when modifications has been done on layer.
void setProviderType(const QString &providerType)
Sets the providerType (provider key)
QString generalHtmlMetadata() const
Returns an HTML fragment containing general metadata information, for use in the htmlMetadata() metho...
void writeCommonStyle(QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) const
Write style data common to all layer types.
void invalidateWgs84Extent()
Invalidates the WGS84 extent.
bool mShouldValidateCrs
true if the layer's CRS should be validated and invalid CRSes are not permitted.
Definition: qgsmaplayer.h:1978
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.
virtual QgsMeshDriverMetadata driverMetadata() const
Returns the mesh driver metadata of the provider.
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 close()=0
Closes the data provider and free every resources used.
virtual int vertexCount() const =0
Returns number of vertices in the native mesh.
virtual void populateMesh(QgsMesh *mesh) const =0
Populates the mesh vertices, edges and faces.
virtual bool saveMeshFrame(const QgsMesh &mesh)=0
Saves the mesh frame to the source.
virtual int edgeCount() const =0
Returns number of edges in the native mesh.
virtual int faceCount() const =0
Returns number of faces in the native mesh.
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.
QgsMeshDatasetValue represents single dataset value.
double y() const
Returns y value.
double x() const
Returns x value.
Holds metadata about mesh driver.
@ CanWriteMeshData
If the driver can write mesh data on file.
MeshDriverCapabilities capabilities() const
Returns the capabilities for this driver.
Class that represents an error during mesh editing.
Definition: qgsmesheditor.h:40
Class that makes edit operation on a mesh.
Definition: qgsmesheditor.h:65
QgsMeshEditingError initialize()
Initialize the mesh editor and return errors if the internal native mesh have topologic errors.
int validFacesCount() const
Returns the count of valid faces, that is non void faces in the mesh.
QgsRectangle extent() const
Returns the extent of the edited mesh.
void stopEditing()
Stops editing.
void meshEdited()
Emitted when the mesh is edited.
bool checkConsistency() const
Return true if the edited mesh is consistent.
void resetTriangularMesh(QgsTriangularMesh *triangularMesh)
Resets the triangular mesh.
bool isModified() const
Returns whether the mesh has been modified.
int validVerticesCount() const
Returns the count of valid vertices, that is non void vertices in the mesh.
bool reindex(bool renumbering)
Reindexes the mesh, that is remove unusued index of face and vertices, this operation void the undo/r...
QgsMeshDatasetGroup * createZValueDatasetGroup()
Creates and returns a scalar dataset group with value on vertex that is can be used to access the Z v...
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:97
~QgsMeshLayer() override
QList< int > selectVerticesByExpression(QgsExpression expression)
Returns a list of vertex indexes that meet the condition defined by expression with the context expre...
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.
void stopFrameEditing(const QgsCoordinateTransform &transform)
Stops edition of the mesh, re-indexes the faces and vertices, rebuilds the triangular mesh and its sp...
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.
bool contains(const QgsMesh::ElementType &type) const
Returns whether the mesh contains at mesh elements of given type.
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.
bool isModified() const override
Returns whether the mesh frame has been modified since the last save.
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.
QgsMeshEditor * meshEditor()
Returns a pointer to the mesh editor own by the mesh 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.
int meshFaceCount() const
Returns the faces count of the mesh frame.
QList< int > selectFacesByExpression(QgsExpression expression)
Returns a list of faces indexes that meet the condition defined by expression with the context expres...
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.
bool rollBackFrameEditing(const QgsCoordinateTransform &transform, bool continueEditing=true)
Rolls Back edition of the mesh frame.
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.
bool commitFrameEditing(const QgsCoordinateTransform &transform, bool continueEditing=true)
Commits edition of the mesh frame, Rebuilds the triangular mesh and its spatial index with transform,...
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.
int meshEdgeCount() const
Returns the edges count of the mesh frame.
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...
bool isEditable() const override
Returns true if the layer can be edited.
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.
bool supportsEditing() const override
Returns whether the layer supports editing or not.
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.
bool startFrameEditing(const QgsCoordinateTransform &transform)
Starts edition of the mesh frame.
bool reindex(const QgsCoordinateTransform &transform, bool renumber)
Re-indexes the faces and vertices, and renumber the indexes if renumber is true.
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
int meshVertexCount() const
Returns the vertices count of the mesh frame.
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 an 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 void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
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:59
double y
Definition: qgspointxy.h:63
Q_GADGET double x
Definition: qgspointxy.h:62
double distance(double x, double y) const SIP_HOLDGIL
Returns the distance between this point and a specified x, y coordinate.
Definition: qgspointxy.h:211
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:49
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:343
Q_GADGET double x
Definition: qgspoint.h:52
double y
Definition: qgspoint.h:53
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:172
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:131
QgsColorRamp * colorRamp(const QString &name) const
Returns a new copy of the specified color ramp.
Definition: qgsstyle.cpp:446
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 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.
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: qgis.h:47
@ MeshLayer
Added in 3.2.
CORE_EXPORT QgsMeshVertex centroid(const QgsMeshFace &face, const QVector< QgsMeshVertex > &vertices)
Returns the centroid of the face.
#define SIP_SKIP
Definition: qgis_sip.h:126
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
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:105
QgsCoordinateTransformContext transformContext
Definition: qgsmeshlayer.h:115
bool skipCrsValidation
Controls whether the layer is allowed to have an invalid/unknown CRS.
Definition: qgsmeshlayer.h:130
Mesh - vertices, edges and faces.
ElementType
Defines type of mesh elements.