QGIS API Documentation 3.41.0-Master (af5edcb665c)
Loading...
Searching...
No Matches
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 "qgscolorrampimpl.h"
25#include "qgslogger.h"
26#include "qgsmaplayerlegend.h"
27#include "qgsmaplayerfactory.h"
28#include "qgsmeshdataprovider.h"
30#include "qgsmeshlayer.h"
31#include "moc_qgsmeshlayer.cpp"
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"
48#include "qgsthreadingutils.h"
49#include "qgsapplication.h"
50#include "qgsruntimeprofiler.h"
52
53QgsMeshLayer::QgsMeshLayer( const QString &meshLayerPath,
54 const QString &baseName,
55 const QString &providerKey,
56 const QgsMeshLayer::LayerOptions &options )
57 : QgsMapLayer( Qgis::LayerType::Mesh, baseName, meshLayerPath )
58 , mDatasetGroupStore( new QgsMeshDatasetGroupStore( this ) )
59 , mTemporalProperties( new QgsMeshLayerTemporalProperties( this ) )
60 , mElevationProperties( new QgsMeshLayerElevationProperties( this ) )
61{
63
64 const QgsDataProvider::ProviderOptions providerOptions { options.transformContext };
66 if ( options.loadDefaultStyle )
67 {
69 }
70 QgsMeshLayer::setDataSourcePrivate( meshLayerPath, baseName, providerKey, providerOptions, flags );
73
74 if ( isValid() && options.loadDefaultStyle )
75 {
76 bool result = false;
77 loadDefaultStyle( result );
78 }
79
80 connect( mDatasetGroupStore.get(), &QgsMeshDatasetGroupStore::datasetGroupsAdded, this, &QgsMeshLayer::onDatasetGroupsAdded );
81}
82
83void QgsMeshLayer::createSimplifiedMeshes()
84{
86
87 if ( mSimplificationSettings.isEnabled() && !hasSimplifiedMeshes() )
88 {
89 const double reductionFactor = mSimplificationSettings.reductionFactor();
90
91 QVector<QgsTriangularMesh *> simplifyMeshes =
92 mTriangularMeshes[0]->simplifyMesh( reductionFactor );
93
94 for ( int i = 0; i < simplifyMeshes.count() ; ++i )
95 {
96 mTriangularMeshes.emplace_back( simplifyMeshes[i] );
97 }
98 }
99}
100
101bool QgsMeshLayer::hasSimplifiedMeshes() const
102{
104
105 //First mesh is the base mesh, so if size>1, there is no simplified meshes
106 return ( mTriangularMeshes.size() > 1 );
107}
108
110{
111 delete mLabeling;
112 delete mDataProvider;
113}
114
121
123{
125
126 return mDataProvider;
127}
128
130{
132
134 if ( mDataProvider )
135 {
136 options.transformContext = mDataProvider->transformContext();
137 }
138 QgsMeshLayer *layer = new QgsMeshLayer( source(), name(), mProviderKey, options );
139 QgsMapLayer::clone( layer );
140
141 layer->mElevationProperties = mElevationProperties->clone();
142 layer->mElevationProperties->setParent( layer );
143
144 if ( auto *lLabeling = labeling() )
145 {
146 layer->setLabeling( lLabeling->clone() );
147 }
149
150 return layer;
151}
152
154{
156
157 if ( mMeshEditor )
158 return mMeshEditor->extent();
159
160 if ( mDataProvider )
161 return mDataProvider->extent();
162 else
163 {
164 QgsRectangle rec;
165 rec.setNull();
166 return rec;
167 }
168}
169
176
178{
180
181 if ( !mDataProvider )
182 return false;
183
184 if ( mMeshEditor )
185 return true;
186
187 const QgsMeshDriverMetadata driverMetadata = mDataProvider->driverMetadata();
188
190}
191
192QString QgsMeshLayer::loadDefaultStyle( bool &resultFlag )
193{
195
196 const QList<int> groupsList = datasetGroupsIndexes();
197
198 for ( const int index : groupsList )
199 assignDefaultStyleToDatasetGroup( index );
200
201
202 QgsMeshRendererMeshSettings meshSettings;
203 if ( !groupsList.isEmpty() )
204 {
205 // Show data from the first dataset group
206 mRendererSettings.setActiveScalarDatasetGroup( 0 );
207 // If the first dataset group has nan min/max, display the mesh to avoid nothing displayed
209 if ( meta.maximum() == std::numeric_limits<double>::quiet_NaN() &&
210 meta.minimum() == std::numeric_limits<double>::quiet_NaN() )
211 meshSettings.setEnabled( true );
212 }
213 else
214 {
215 // show at least the mesh by default
216 meshSettings.setEnabled( true );
217 }
218
219 mRendererSettings.setNativeMeshSettings( meshSettings );
220
221 for ( const int i : groupsList )
222 {
223 assignDefaultStyleToDatasetGroup( i );
224
225 // Sets default resample method for scalar dataset
227 QgsMeshRendererScalarSettings scalarSettings = mRendererSettings.scalarSettings( i );
228 switch ( meta.dataType() )
229 {
231 case QgsMeshDatasetGroupMetadata::DataOnVolumes: // data on volumes are averaged to 2D data on faces
233 break;
236 break;
238 break;
239 }
240
241 //override color ramp if the values in the dataset group are classified
242 applyClassificationOnScalarSettings( meta, scalarSettings );
243
244 mRendererSettings.setScalarSettings( i, scalarSettings );
245 }
246
247 if ( !groupsList.isEmpty() )
248 {
249 emit rendererChanged();
251 }
252
253 return QgsMapLayer::loadDefaultStyle( resultFlag );
254}
255
256bool QgsMeshLayer::removeDatasets( const QString &name )
257{
258 const int index = mDatasetGroupStore->indexFromGroupName( name );
259
260 if ( index == -1 )
261 {
262 return false;
263 }
264
265 const QgsMeshDatasetGroupMetadata groupMetadata = datasetGroupMetadata( index );
266
267 mDatasetGroupStore->removeDatasetGroup( index );
268
269 if ( mExtraDatasetUri.contains( groupMetadata.uri() ) )
270 {
271 mExtraDatasetUri.removeOne( groupMetadata.uri() );
272 }
273
275
276 emit dataSourceChanged();
277 return true;
278}
279
280bool QgsMeshLayer::addDatasets( const QString &path, const QDateTime &defaultReferenceTime )
281{
283
285 const bool isTemporalBefore = temporalCapabilities->hasTemporalCapabilities();
286 if ( mDatasetGroupStore->addPersistentDatasets( path ) )
287 {
288 mExtraDatasetUri.append( path );
289 QgsMeshLayerTemporalProperties *temporalProperties = qobject_cast< QgsMeshLayerTemporalProperties * >( mTemporalProperties );
290 if ( !isTemporalBefore && temporalCapabilities->hasTemporalCapabilities() )
291 {
293 temporalCapabilities );
294
295 if ( ! temporalProperties->referenceTime().isValid() )
296 {
297 QDateTime referenceTime = defaultReferenceTime;
298 if ( !defaultReferenceTime.isValid() ) // If project reference time is invalid, use current date
299 referenceTime = QDateTime( QDate::currentDate(), QTime( 0, 0, 0 ), Qt::UTC );
300 temporalProperties->setReferenceTime( referenceTime, temporalCapabilities );
301 }
302
303 mTemporalProperties->setIsActive( true );
304 }
305 emit dataSourceChanged();
306 return true;
307 }
308
309 return false;
310}
311
313{
315
316 if ( mDatasetGroupStore->addDatasetGroup( datasetGroup ) )
317 {
318 emit dataChanged();
319 return true;
320 }
321 return false;
322}
323
324bool QgsMeshLayer::saveDataset( const QString &path, int datasetGroupIndex, QString driver )
325{
327
328 return mDatasetGroupStore->saveDatasetGroup( path, datasetGroupIndex, driver );
329}
330
332{
334
335 return mNativeMesh.get();
336}
337
339{
341
342 return mNativeMesh.get();
343}
344
345QgsTriangularMesh *QgsMeshLayer::triangularMesh( double minimumTriangleSize ) const
346{
348
349 for ( const std::unique_ptr<QgsTriangularMesh> &lod : mTriangularMeshes )
350 {
351 if ( lod && lod->averageTriangleSize() > minimumTriangleSize )
352 return lod.get();
353 }
354
355 if ( !mTriangularMeshes.empty() )
356 return mTriangularMeshes.back().get();
357 else
358 return nullptr;
359}
360
362{
364
365 return mTriangularMeshes.size();
366}
367
369{
371
372 if ( mTriangularMeshes.empty() )
373 return nullptr;
374 if ( lodIndex < 0 )
375 return mTriangularMeshes.front().get();
376
377 if ( lodIndex >= int( mTriangularMeshes.size() ) )
378 return mTriangularMeshes.back().get();
379
380 return mTriangularMeshes.at( lodIndex ).get();
381}
382
384{
386
387 // Native mesh
388 if ( !mNativeMesh )
389 {
390 // lazy loading of mesh data
391 fillNativeMesh();
392 }
393
394 // Triangular mesh
395 if ( mTriangularMeshes.empty() )
396 {
397 QgsTriangularMesh *baseMesh = new QgsTriangularMesh;
398 mTriangularMeshes.emplace_back( baseMesh );
399 }
400
401 if ( mTriangularMeshes[0].get()->update( mNativeMesh.get(), transform ) )
402 mTriangularMeshes.resize( 1 ); //if the base triangular mesh is effectivly updated, remove simplified meshes
403
404 createSimplifiedMeshes();
405}
406
407QgsMeshLayerRendererCache *QgsMeshLayer::rendererCache()
408{
410
411 return mRendererCache.get();
412}
413
420
422{
424
425 const int oldActiveScalar = mRendererSettings.activeScalarDatasetGroup();
426 const int oldActiveVector = mRendererSettings.activeVectorDatasetGroup();
427 mRendererSettings = settings;
428
429 if ( oldActiveScalar != mRendererSettings.activeScalarDatasetGroup() )
431
432 if ( oldActiveVector != mRendererSettings.activeVectorDatasetGroup() )
434
435 emit rendererChanged();
437}
438
445
447{
449
450 mTimeSettings = settings;
451 emit timeSettingsChanged();
452}
453
454QString QgsMeshLayer::formatTime( double hours )
455{
457
458 if ( dataProvider() && dataProvider()->temporalCapabilities()->hasReferenceTime() )
459 return QgsMeshLayerUtils::formatTime( hours, mTemporalProperties->referenceTime(), mTimeSettings );
460 else
461 return QgsMeshLayerUtils::formatTime( hours, QDateTime(), mTimeSettings );
462}
463
465{
467
468 return mDatasetGroupStore->datasetGroupCount();
469}
470
472{
474
475 return mDatasetGroupStore->extraDatasetGroupCount();
476}
477
479{
481
482 return mDatasetGroupStore->datasetGroupIndexes();
483}
484
486{
488
489 return mDatasetGroupStore->enabledDatasetGroupIndexes();
490}
491
493{
495
496 return mDatasetGroupStore->datasetGroupMetadata( index );
497}
498
500{
502
503 return mDatasetGroupStore->datasetCount( index.group() );
504}
505
507{
509
510 return mDatasetGroupStore->datasetMetadata( index );
511}
512
514{
516
517 return mDatasetGroupStore->datasetValue( index, valueIndex );
518}
519
520QgsMeshDataBlock QgsMeshLayer::datasetValues( const QgsMeshDatasetIndex &index, int valueIndex, int count ) const
521{
523
524 return mDatasetGroupStore->datasetValues( index, valueIndex, count );
525}
526
527QgsMesh3DDataBlock QgsMeshLayer::dataset3dValues( const QgsMeshDatasetIndex &index, int faceIndex, int count ) const
528{
530
531 return mDatasetGroupStore->dataset3dValues( index, faceIndex, count );
532}
533
534QgsMeshDataBlock QgsMeshLayer::areFacesActive( const QgsMeshDatasetIndex &index, int faceIndex, int count ) const
535{
537
538 return mDatasetGroupStore->areFacesActive( index, faceIndex, count );
539}
540
541bool QgsMeshLayer::isFaceActive( const QgsMeshDatasetIndex &index, int faceIndex ) const
542{
544
545 return mDatasetGroupStore->isFaceActive( index, faceIndex );
546}
547
548QgsMeshDatasetValue QgsMeshLayer::datasetValue( const QgsMeshDatasetIndex &index, const QgsPointXY &point, double searchRadius ) const
549{
551
553 const QgsTriangularMesh *mesh = triangularMesh();
554
555 if ( mesh && index.isValid() )
556 {
558 {
559 const QgsRectangle searchRectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
560 return dataset1dValue( index, point, searchRadius );
561 }
562 const int faceIndex = mesh->faceIndexForPoint_v2( point ) ;
563 if ( faceIndex >= 0 )
564 {
565 const int nativeFaceIndex = mesh->trianglesToNativeFaces().at( faceIndex );
567 if ( isFaceActive( index, nativeFaceIndex ) )
568 {
569 switch ( dataType )
570 {
572 {
573 value = datasetValue( index, nativeFaceIndex );
574 }
575 break;
576
578 {
579 const QgsMeshFace &face = mesh->triangles()[faceIndex];
580 const int v1 = face[0], v2 = face[1], v3 = face[2];
581 const QgsPoint p1 = mesh->vertices()[v1], p2 = mesh->vertices()[v2], p3 = mesh->vertices()[v3];
582 const QgsMeshDatasetValue val1 = datasetValue( index, v1 );
583 const QgsMeshDatasetValue val2 = datasetValue( index, v2 );
584 const QgsMeshDatasetValue val3 = datasetValue( index, v3 );
585 const double x = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.x(), val2.x(), val3.x(), point );
586 double y = std::numeric_limits<double>::quiet_NaN();
587 const bool isVector = datasetGroupMetadata( index ).isVector();
588 if ( isVector )
589 y = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.y(), val2.y(), val3.y(), point );
590
591 value = QgsMeshDatasetValue( x, y );
592 }
593 break;
594
596 {
597 const QgsMesh3DAveragingMethod *avgMethod = mRendererSettings.averagingMethod();
598 if ( avgMethod )
599 {
600 const QgsMesh3DDataBlock block3d = dataset3dValues( index, nativeFaceIndex, 1 );
601 const QgsMeshDataBlock block2d = avgMethod->calculate( block3d );
602 if ( block2d.isValid() )
603 {
604 value = block2d.value( 0 );
605 }
606 }
607 }
608 break;
609
610 default:
611 break;
612 }
613 }
614 }
615 }
616
617 return value;
618}
619
621{
623
624 QgsMesh3DDataBlock block3d;
625
626 const QgsTriangularMesh *baseTriangularMesh = triangularMesh();
627
628 if ( baseTriangularMesh && dataProvider() && dataProvider()->isValid() && index.isValid() )
629 {
632 {
633 const int faceIndex = baseTriangularMesh->faceIndexForPoint_v2( point );
634 if ( faceIndex >= 0 )
635 {
636 const int nativeFaceIndex = baseTriangularMesh->trianglesToNativeFaces().at( faceIndex );
637 block3d = dataset3dValues( index, nativeFaceIndex, 1 );
638 }
639 }
640 }
641 return block3d;
642}
643
644QgsMeshDatasetValue QgsMeshLayer::dataset1dValue( const QgsMeshDatasetIndex &index, const QgsPointXY &point, double searchRadius ) const
645{
647
649 QgsPointXY projectedPoint;
650 const int selectedIndex = closestEdge( point, searchRadius, projectedPoint );
651 const QgsTriangularMesh *mesh = triangularMesh();
652 if ( selectedIndex >= 0 )
653 {
655 switch ( dataType )
656 {
658 {
659 value = datasetValue( index, selectedIndex );
660 }
661 break;
662
664 {
665 const QgsMeshEdge &edge = mesh->edges()[selectedIndex];
666 const int v1 = edge.first, v2 = edge.second;
667 const QgsPoint p1 = mesh->vertices()[v1], p2 = mesh->vertices()[v2];
668 const QgsMeshDatasetValue val1 = datasetValue( index, v1 );
669 const QgsMeshDatasetValue val2 = datasetValue( index, v2 );
670 const double edgeLength = p1.distance( p2 );
671 const double dist1 = p1.distance( projectedPoint.x(), projectedPoint.y() );
672 value = QgsMeshLayerUtils::interpolateFromVerticesData( dist1 / edgeLength, val1, val2 );
673 }
674 break;
675 default:
676 break;
677 }
678 }
679
680 return value;
681}
682
684{
686
687 if ( mDataProvider )
688 mDataProvider->setTransformContext( transformContext );
690}
691
692QgsMeshDatasetIndex QgsMeshLayer::datasetIndexAtTime( const QgsDateTimeRange &timeRange, int datasetGroupIndex ) const
693{
695
696 if ( ! mTemporalProperties->isActive() )
697 return QgsMeshDatasetIndex( datasetGroupIndex, -1 );
698
699 const QDateTime layerReferenceTime = mTemporalProperties->referenceTime();
700 QDateTime utcTime = timeRange.begin();
701 if ( utcTime.timeSpec() != Qt::UTC )
702 utcTime.setTimeSpec( Qt::UTC );
703 const qint64 startTime = layerReferenceTime.msecsTo( utcTime );
704
705 return mDatasetGroupStore->datasetIndexAtTime( startTime, datasetGroupIndex, mTemporalProperties->matchingMethod() );
706}
707
708QgsMeshDatasetIndex QgsMeshLayer::datasetIndexAtRelativeTime( const QgsInterval &relativeTime, int datasetGroupIndex ) const
709{
711
712 return mDatasetGroupStore->datasetIndexAtTime( relativeTime.seconds() * 1000, datasetGroupIndex, mTemporalProperties->matchingMethod() );
713}
714
715QList<QgsMeshDatasetIndex> QgsMeshLayer::datasetIndexInRelativeTimeInterval( const QgsInterval &startRelativeTime, const QgsInterval &endRelativeTime, int datasetGroupIndex ) const
716{
718
719 qint64 usedRelativeTime1 = startRelativeTime.seconds() * 1000;
720 qint64 usedRelativeTime2 = endRelativeTime.seconds() * 1000;
721
722 //adjust relative time if layer reference time is different from provider reference time
723 if ( mTemporalProperties->referenceTime().isValid() &&
724 mDataProvider &&
725 mDataProvider->isValid() &&
726 mTemporalProperties->referenceTime() != mDataProvider->temporalCapabilities()->referenceTime() )
727 {
728 usedRelativeTime1 = usedRelativeTime1 + mTemporalProperties->referenceTime().msecsTo( mDataProvider->temporalCapabilities()->referenceTime() );
729 usedRelativeTime2 = usedRelativeTime2 + mTemporalProperties->referenceTime().msecsTo( mDataProvider->temporalCapabilities()->referenceTime() );
730 }
731
732 return mDatasetGroupStore->datasetIndexInTimeInterval( usedRelativeTime1, usedRelativeTime2, datasetGroupIndex );
733}
734
735void QgsMeshLayer::applyClassificationOnScalarSettings( const QgsMeshDatasetGroupMetadata &meta, QgsMeshRendererScalarSettings &scalarSettings ) const
736{
738
739 if ( meta.extraOptions().contains( QStringLiteral( "classification" ) ) )
740 {
741 QgsColorRampShader colorRampShader = scalarSettings.colorRampShader();
742 QgsColorRamp *colorRamp = colorRampShader.sourceColorRamp();
743 const QStringList classes = meta.extraOptions()[QStringLiteral( "classification" )].split( QStringLiteral( ";;" ) );
744
745 QString units;
746 if ( meta.extraOptions().contains( QStringLiteral( "units" ) ) )
747 units = meta.extraOptions()[ QStringLiteral( "units" )];
748
749 QVector<QVector<double>> bounds;
750 for ( const QString &classe : classes )
751 {
752 const QStringList boundsStr = classe.split( ',' );
753 QVector<double> bound;
754 for ( const QString &boundStr : boundsStr )
755 bound.append( boundStr.toDouble() );
756 bounds.append( bound );
757 }
758
759 if ( ( bounds.count() == 1 && bounds.first().count() > 2 ) || // at least a class with two value
760 ( bounds.count() > 1 ) ) // or at least two classes
761 {
762 const QVector<double> firstClass = bounds.first();
763 const QVector<double> lastClass = bounds.last();
764 const double minValue = firstClass.count() > 1 ? ( firstClass.first() + firstClass.last() ) / 2 : firstClass.first();
765 const double maxValue = lastClass.count() > 1 ? ( lastClass.first() + lastClass.last() ) / 2 : lastClass.first();
766 const double diff = maxValue - minValue;
767 QList<QgsColorRampShader::ColorRampItem> colorRampItemlist;
768 for ( int i = 0; i < bounds.count(); ++i )
769 {
770 const QVector<double> &boundClass = bounds.at( i );
772 item.value = i + 1;
773 if ( !boundClass.isEmpty() )
774 {
775 const double scalarValue = ( boundClass.first() + boundClass.last() ) / 2;
776 item.color = colorRamp->color( ( scalarValue - minValue ) / diff );
777 if ( i != 0 && i < bounds.count() - 1 ) //The first and last labels are treated after
778 {
779 item.label = QString( ( "%1 - %2 %3" ) ).
780 arg( QString::number( boundClass.first() ) ).
781 arg( QString::number( boundClass.last() ) ).
782 arg( units );
783 }
784 }
785 colorRampItemlist.append( item );
786 }
787 //treat first and last labels
788 if ( firstClass.count() == 1 )
789 colorRampItemlist.first().label = QObject::tr( "below %1 %2" ).
790 arg( QString::number( firstClass.first() ) ).
791 arg( units );
792 else
793 {
794 colorRampItemlist.first().label = QString( ( "%1 - %2 %3" ) ).
795 arg( QString::number( firstClass.first() ) ).
796 arg( QString::number( firstClass.last() ) ).
797 arg( units );
798 }
799
800 if ( lastClass.count() == 1 )
801 colorRampItemlist.last().label = QObject::tr( "above %1 %2" ).
802 arg( QString::number( lastClass.first() ) ).
803 arg( units );
804 else
805 {
806 colorRampItemlist.last().label = QString( ( "%1 - %2 %3" ) ).
807 arg( QString::number( lastClass.first() ) ).
808 arg( QString::number( lastClass.last() ) ).
809 arg( units );
810 }
811
812 colorRampShader.setMinimumValue( 0 );
813 colorRampShader.setMaximumValue( colorRampItemlist.count() - 1 );
814 scalarSettings.setClassificationMinimumMaximum( 0, colorRampItemlist.count() - 1 );
815 colorRampShader.setColorRampItemList( colorRampItemlist );
818 }
819
820 scalarSettings.setColorRampShader( colorRampShader );
822 }
823}
824
826{
828
829 if ( mTemporalProperties->isActive() )
830 return datasetIndexAtTime( timeRange, group >= 0 ? group : mRendererSettings.activeScalarDatasetGroup() );
831 else
832 return QgsMeshDatasetIndex( group >= 0 ? group : mRendererSettings.activeScalarDatasetGroup(), mStaticScalarDatasetIndex );
833}
834
836{
838
839 if ( mTemporalProperties->isActive() )
840 return datasetIndexAtTime( timeRange, group >= 0 ? group : mRendererSettings.activeVectorDatasetGroup() );
841 else
842 return QgsMeshDatasetIndex( group >= 0 ? group : mRendererSettings.activeVectorDatasetGroup(), mStaticVectorDatasetIndex );
843}
844
845void QgsMeshLayer::fillNativeMesh()
846{
848
849 Q_ASSERT( !mNativeMesh );
850
851 mNativeMesh.reset( new QgsMesh() );
852
853 if ( !( dataProvider() && dataProvider()->isValid() ) )
854 return;
855
856 dataProvider()->populateMesh( mNativeMesh.get() );
857}
858
859void QgsMeshLayer::onDatasetGroupsAdded( const QList<int> &datasetGroupIndexes )
860{
862
863 // assign default style to new dataset groups
864 for ( int datasetGroupIndex : datasetGroupIndexes )
865 {
866 if ( !mRendererSettings.hasSettings( datasetGroupIndex ) )
867 assignDefaultStyleToDatasetGroup( datasetGroupIndex );
868 }
869
870 temporalProperties()->setIsActive( mDatasetGroupStore->hasTemporalCapabilities() );
871 emit rendererChanged();
872}
873
874void QgsMeshLayer::onMeshEdited()
875{
877
878 mRendererCache.reset( new QgsMeshLayerRendererCache() );
879 emit layerModified();
882}
883
885{
887
888 return mDatasetGroupStore->datasetGroupTreeItem();
889}
890
892{
894
895 mDatasetGroupStore->setDatasetGroupTreeItem( rootItem );
896 updateActiveDatasetGroups();
897}
898
899int QgsMeshLayer::closestEdge( const QgsPointXY &point, double searchRadius, QgsPointXY &projectedPoint ) const
900{
902
903 const QgsRectangle searchRectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
904 const QgsTriangularMesh *mesh = triangularMesh();
905 // search for the closest edge in search area from point
906 const QList<int> edgeIndexes = mesh->edgeIndexesForRectangle( searchRectangle );
907 int selectedIndex = -1;
908 if ( mesh->contains( QgsMesh::Edge ) &&
909 mDataProvider->isValid() )
910 {
911 double sqrMaxDistFromPoint = pow( searchRadius, 2 );
912 for ( const int edgeIndex : edgeIndexes )
913 {
914 const QgsMeshEdge &edge = mesh->edges().at( edgeIndex );
915 const QgsMeshVertex &vertex1 = mesh->vertices()[edge.first];
916 const QgsMeshVertex &vertex2 = mesh->vertices()[edge.second];
917 QgsPointXY projPoint;
918 const double sqrDist = point.sqrDistToSegment( vertex1.x(), vertex1.y(), vertex2.x(), vertex2.y(), projPoint, 0 );
919 if ( sqrDist < sqrMaxDistFromPoint )
920 {
921 selectedIndex = edgeIndex;
922 projectedPoint = projPoint;
923 sqrMaxDistFromPoint = sqrDist;
924 }
925 }
926 }
927
928 return selectedIndex;
929}
930
932{
934
935 return QgsMeshDatasetIndex( group >= 0 ? group : mRendererSettings.activeVectorDatasetGroup(), mStaticVectorDatasetIndex );
936}
937
938void QgsMeshLayer::setReferenceTime( const QDateTime &referenceTime )
939{
941
942 if ( auto *lDataProvider = dataProvider() )
943 mTemporalProperties->setReferenceTime( referenceTime, lDataProvider->temporalCapabilities() );
944 else
945 mTemporalProperties->setReferenceTime( referenceTime, nullptr );
946}
947
954
955QgsPointXY QgsMeshLayer::snapOnVertex( const QgsPointXY &point, double searchRadius )
956{
958
959 const QgsTriangularMesh *mesh = triangularMesh();
960 QgsPointXY exactPosition;
961 if ( !mesh )
962 return exactPosition;
963 const QgsRectangle rectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
964 double maxDistance = searchRadius;
965 //attempt to snap on edges's vertices
966 const QList<int> edgeIndexes = mesh->edgeIndexesForRectangle( rectangle );
967 for ( const int edgeIndex : edgeIndexes )
968 {
969 const QgsMeshEdge &edge = mesh->edges().at( edgeIndex );
970 const QgsMeshVertex &vertex1 = mesh->vertices()[edge.first];
971 const QgsMeshVertex &vertex2 = mesh->vertices()[edge.second];
972 const double dist1 = point.distance( vertex1 );
973 const double dist2 = point.distance( vertex2 );
974 if ( dist1 < maxDistance )
975 {
976 maxDistance = dist1;
977 exactPosition = vertex1;
978 }
979 if ( dist2 < maxDistance )
980 {
981 maxDistance = dist2;
982 exactPosition = vertex2;
983 }
984 }
985
986 //attempt to snap on face's vertices
987 const QList<int> faceIndexes = mesh->faceIndexesForRectangle( rectangle );
988 for ( const int faceIndex : faceIndexes )
989 {
990 const QgsMeshFace &face = mesh->triangles().at( faceIndex );
991 for ( int i = 0; i < 3; ++i )
992 {
993 const QgsMeshVertex &vertex = mesh->vertices()[face.at( i )];
994 const double dist = point.distance( vertex );
995 if ( dist < maxDistance )
996 {
997 maxDistance = dist;
998 exactPosition = vertex;
999 }
1000 }
1001 }
1002
1003 return exactPosition;
1004}
1005
1006QgsPointXY QgsMeshLayer::snapOnEdge( const QgsPointXY &point, double searchRadius )
1007{
1009
1010 QgsPointXY projectedPoint;
1011 closestEdge( point, searchRadius, projectedPoint );
1012
1013 return projectedPoint;
1014}
1015
1016QgsPointXY QgsMeshLayer::snapOnFace( const QgsPointXY &point, double searchRadius )
1017{
1019
1020 const QgsTriangularMesh *mesh = triangularMesh();
1021 QgsPointXY centroidPosition;
1022 if ( !mesh )
1023 return centroidPosition;
1024 const QgsRectangle rectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
1025 double maxDistance = std::numeric_limits<double>::max();
1026
1027 const QList<int> faceIndexes = mesh->faceIndexesForRectangle( rectangle );
1028 for ( const int faceIndex : faceIndexes )
1029 {
1030 const int nativefaceIndex = mesh->trianglesToNativeFaces().at( faceIndex );
1031 if ( nativefaceIndex < 0 && nativefaceIndex >= mesh->faceCentroids().count() )
1032 continue;
1033 const QgsPointXY centroid = mesh->faceCentroids()[nativefaceIndex];
1034 const double dist = point.distance( centroid );
1035 if ( dist < maxDistance )
1036 {
1037 maxDistance = dist;
1038 centroidPosition = centroid;
1039 }
1040 }
1041
1042 return centroidPosition;
1043}
1044
1046{
1048
1049 mDatasetGroupStore->resetDatasetGroupTreeItem();
1050 updateActiveDatasetGroups();
1051}
1052
1054{
1056
1057 if ( !mDataProvider )
1058 return QgsInterval();
1059 const int groupCount = mDataProvider->datasetGroupCount();
1060 for ( int i = 0; i < groupCount; ++i )
1061 {
1062 const qint64 timeStep = mDataProvider->temporalCapabilities()->firstTimeStepDuration( i );
1063 if ( timeStep > 0 )
1065 }
1066
1067 return QgsInterval();
1068}
1069
1071{
1073
1074 const qint64 time = mDatasetGroupStore->datasetRelativeTime( index );
1075
1076 if ( time == INVALID_MESHLAYER_TIME )
1077 return QgsInterval();
1078 else
1080}
1081
1083{
1085
1086 return mDatasetGroupStore->datasetRelativeTime( index );
1087}
1088
1089static QString detailsErrorMessage( const QgsMeshEditingError &error )
1090{
1091 QString message;
1092
1093 switch ( error.errorType )
1094 {
1096 break;
1098 message = QObject::tr( "Face %1 invalid" ).arg( error.elementIndex );
1099 break;
1101 message = QObject::tr( "Too many vertices for face %1" ).arg( error.elementIndex );
1102 break;
1104 message = QObject::tr( "Face %1 is flat" ).arg( error.elementIndex );
1105 break;
1107 message = QObject::tr( "Vertex %1 is a unique shared vertex" ).arg( error.elementIndex );
1108 break;
1110 message = QObject::tr( "Vertex %1 is invalid" ).arg( error.elementIndex );
1111 break;
1113 message = QObject::tr( "Face %1 is manifold" ).arg( error.elementIndex );
1114 break;
1115 }
1116
1117 return message;
1118}
1119
1121{
1123
1125 return startFrameEditing( transform, error, false );
1126}
1127
1129{
1131
1132 if ( !supportsEditing() )
1133 {
1134 QgsMessageLog::logMessage( QObject::tr( "Mesh layer \"%1\" not support mesh editing" ).arg( name() ) );
1135 return false;
1136 }
1137
1138 if ( mMeshEditor )
1139 {
1140 QgsMessageLog::logMessage( QObject::tr( "Mesh layer \"%1\" already in editing mode" ).arg( name() ) );
1141 return false;
1142 }
1143
1144 mSimplificationSettings.setEnabled( false );
1145
1146 updateTriangularMesh( transform );
1147
1148 mMeshEditor = new QgsMeshEditor( this );
1149
1150 if ( fixErrors )
1151 {
1152 mRendererCache.reset(); // fixing errors could lead to remove faces/vertices
1153 error = mMeshEditor->initializeWithErrorsFix();
1154 }
1155 else
1156 error = mMeshEditor->initialize();
1157
1158 if ( error.errorType != Qgis::MeshEditingErrorType::NoError )
1159 {
1160 mMeshEditor->deleteLater();
1161 mMeshEditor = nullptr;
1162
1163 QgsMessageLog::logMessage( QObject::tr( "Unable to start editing of mesh layer \"%1\": %2" ).
1164 arg( name(), detailsErrorMessage( error ) ), QString(), Qgis::MessageLevel::Critical );
1165 return false;
1166 }
1167
1168 // During editing, we don't need anymore the provider data. Mesh frame data is stored in the mesh editor.
1169 mDataProvider->close();
1170
1171 // All dataset group are removed and replace by a unique virtual dataset group that provide vertices elevation value.
1172 mExtraDatasetUri.clear();
1173 mDatasetGroupStore.reset( new QgsMeshDatasetGroupStore( this ) );
1174
1175 std::unique_ptr<QgsMeshDatasetGroup> zValueDatasetGroup( mMeshEditor->createZValueDatasetGroup() );
1176 if ( mDatasetGroupStore->addDatasetGroup( zValueDatasetGroup.get() ) )
1177 zValueDatasetGroup.release();
1178
1180
1181 connect( mMeshEditor, &QgsMeshEditor::meshEdited, this, &QgsMeshLayer::onMeshEdited );
1182
1183 emit dataChanged();
1184 emit editingStarted();
1185
1186 return true;
1187}
1188
1189bool QgsMeshLayer::commitFrameEditing( const QgsCoordinateTransform &transform, bool continueEditing )
1190{
1192
1194 QString detailsError;
1195 if ( !mMeshEditor->checkConsistency( error ) )
1196 {
1197 if ( error.errorType == Qgis::MeshEditingErrorType::NoError )
1198 detailsError = tr( "Unknown inconsistent mesh error" );
1199 }
1200 else
1201 {
1202 error = QgsTopologicalMesh::checkTopology( *mNativeMesh, mMeshEditor->maximumVerticesPerFace() );
1203 detailsError = detailsErrorMessage( error );
1204 }
1205
1206 if ( !detailsError.isEmpty() )
1207 {
1208 QgsMessageLog::logMessage( QObject::tr( "Edited mesh layer \"%1\" can't be save due to an error: %2" ).
1209 arg( name(), detailsError ), QString(), Qgis::MessageLevel::Critical );
1210 return false;
1211 }
1212
1213 stopFrameEditing( transform );
1214
1215 if ( !mDataProvider )
1216 return false;
1217
1218 const bool res = mDataProvider->saveMeshFrame( *mNativeMesh.get() );
1219
1220 if ( continueEditing )
1221 {
1222 mMeshEditor->initialize();
1223 emit layerModified();
1224 return res;
1225 }
1226
1227 mMeshEditor->deleteLater();
1228 mMeshEditor = nullptr;
1229 emit editingStopped();
1230
1231 mDataProvider->reloadData();
1232 mDataProvider->populateMesh( mNativeMesh.get() );
1233 mDatasetGroupStore.reset( new QgsMeshDatasetGroupStore( this ) );
1234 mDatasetGroupStore->setPersistentProvider( mDataProvider, QStringList() );
1236 return true;
1237}
1238
1239bool QgsMeshLayer::rollBackFrameEditing( const QgsCoordinateTransform &transform, bool continueEditing )
1240{
1242
1243 stopFrameEditing( transform );
1244
1245 if ( !mDataProvider )
1246 return false;
1247
1248 mTriangularMeshes.clear();
1249 mDataProvider->reloadData();
1250 mDataProvider->populateMesh( mNativeMesh.get() );
1251 updateTriangularMesh( transform );
1252 mRendererCache.reset( new QgsMeshLayerRendererCache() );
1254
1255 if ( continueEditing )
1256 {
1257 mMeshEditor->resetTriangularMesh( triangularMesh() );
1258 return mMeshEditor->initialize() == QgsMeshEditingError();
1259 }
1260 else
1261 {
1262 mMeshEditor->deleteLater();
1263 mMeshEditor = nullptr;
1264 emit editingStopped();
1265
1266 mDatasetGroupStore.reset( new QgsMeshDatasetGroupStore( this ) );
1267 mDatasetGroupStore->setPersistentProvider( mDataProvider, QStringList() );
1269 emit dataChanged();
1270 return true;
1271 }
1272}
1273
1275{
1277
1278 if ( !mMeshEditor )
1279 return;
1280
1281 mMeshEditor->stopEditing();
1282 mTriangularMeshes.at( 0 )->update( mNativeMesh.get(), transform );
1283 mRendererCache.reset( new QgsMeshLayerRendererCache() );
1284}
1285
1286bool QgsMeshLayer::reindex( const QgsCoordinateTransform &transform, bool renumber )
1287{
1289
1290 if ( !mMeshEditor )
1291 return false;
1292
1293 if ( !mMeshEditor->reindex( renumber ) )
1294 return false;
1295
1296 mTriangularMeshes.clear();
1297 mTriangularMeshes.emplace_back( new QgsTriangularMesh );
1298 mTriangularMeshes.at( 0 )->update( mNativeMesh.get(), transform );
1299 mRendererCache.reset( new QgsMeshLayerRendererCache() );
1300 mMeshEditor->resetTriangularMesh( mTriangularMeshes.at( 0 ).get() );
1301
1302 return true;
1303}
1304
1306{
1308
1309 return mMeshEditor;
1310}
1311
1313{
1315
1316 if ( mMeshEditor )
1317 return mMeshEditor->isModified();
1318
1319 return false;
1320}
1321
1323{
1325
1326 switch ( type )
1327 {
1329 return meshVertexCount() != 0;
1331 return meshEdgeCount() != 0;
1333 return meshFaceCount() != 0;
1334 }
1335 return false;
1336}
1337
1339{
1341
1342 if ( mMeshEditor )
1343 return mMeshEditor->validVerticesCount();
1344 else if ( mDataProvider )
1345 return mDataProvider->vertexCount();
1346 else return 0;
1347}
1348
1350{
1352
1353 if ( mMeshEditor )
1354 return mMeshEditor->validFacesCount();
1355 else if ( mDataProvider )
1356 return mDataProvider->faceCount();
1357 else return 0;
1358}
1359
1361{
1363
1364 if ( mMeshEditor )
1365 return mNativeMesh->edgeCount();
1366 else if ( mDataProvider )
1367 return mDataProvider->edgeCount();
1368 else return 0;
1369}
1370
1371void QgsMeshLayer::updateActiveDatasetGroups()
1372{
1374
1375 QgsMeshDatasetGroupTreeItem *treeItem = mDatasetGroupStore->datasetGroupTreeItem();
1376
1377 if ( !mDatasetGroupStore->datasetGroupTreeItem() )
1378 return;
1379
1381 const int oldActiveScalar = settings.activeScalarDatasetGroup();
1382 const int oldActiveVector = settings.activeVectorDatasetGroup();
1383
1384 QgsMeshDatasetGroupTreeItem *activeScalarItem =
1385 treeItem->childFromDatasetGroupIndex( oldActiveScalar );
1386
1387 if ( !activeScalarItem && treeItem->childCount() > 0 && oldActiveScalar != -1 )
1388 activeScalarItem = treeItem->child( 0 );
1389
1390 if ( activeScalarItem && !activeScalarItem->isEnabled() )
1391 {
1392 for ( int i = 0; i < treeItem->childCount(); ++i )
1393 {
1394 activeScalarItem = treeItem->child( i );
1395 if ( activeScalarItem->isEnabled() )
1396 break;
1397 else
1398 activeScalarItem = nullptr;
1399 }
1400 }
1401
1402 if ( activeScalarItem )
1403 settings.setActiveScalarDatasetGroup( activeScalarItem->datasetGroupIndex() );
1404 else
1405 settings.setActiveScalarDatasetGroup( -1 );
1406
1407 QgsMeshDatasetGroupTreeItem *activeVectorItem =
1408 treeItem->childFromDatasetGroupIndex( oldActiveVector );
1409
1410 if ( !( activeVectorItem && activeVectorItem->isEnabled() ) )
1411 settings.setActiveVectorDatasetGroup( -1 );
1412
1413 setRendererSettings( settings );
1414
1415 if ( oldActiveScalar != settings.activeScalarDatasetGroup() )
1417 if ( oldActiveVector != settings.activeVectorDatasetGroup() )
1419}
1420
1421QgsMeshRendererSettings QgsMeshLayer::accordSymbologyWithGroupName( const QgsMeshRendererSettings &settings, const QMap<QString, int> &nameToIndex )
1422{
1423 QString activeScalarName;
1424 QString activeVectorName;
1425 QgsMeshRendererSettings consistentSettings = settings;
1426 int activeScalar = consistentSettings.activeScalarDatasetGroup();
1427 int activeVector = consistentSettings.activeVectorDatasetGroup();
1428
1429 for ( auto it = nameToIndex.constBegin(); it != nameToIndex.constEnd(); ++it )
1430 {
1431 int index = it.value();
1432 const QString name = it.key() ;
1433 int globalIndex = mDatasetGroupStore->indexFromGroupName( name );
1434 if ( globalIndex >= 0 )
1435 {
1436 QgsMeshRendererScalarSettings scalarSettings = settings.scalarSettings( index );
1437 consistentSettings.setScalarSettings( globalIndex, scalarSettings );
1438 if ( settings.hasVectorSettings( it.value() ) && mDatasetGroupStore->datasetGroupMetadata( globalIndex ).isVector() )
1439 {
1440 QgsMeshRendererVectorSettings vectorSettings = settings.vectorSettings( index );
1441 consistentSettings.setVectorSettings( globalIndex, vectorSettings );
1442 }
1443 }
1444 else
1445 {
1446 consistentSettings.removeScalarSettings( index );
1447 if ( settings.hasVectorSettings( it.value() ) )
1448 consistentSettings.removeVectorSettings( index );
1449 }
1450
1451 if ( index == activeScalar )
1452 activeScalarName = name;
1453 if ( index == activeVector )
1454 activeVectorName = name;
1455 }
1456
1457 const QList<int> globalIndexes = datasetGroupsIndexes();
1458 for ( int globalIndex : globalIndexes )
1459 {
1460 const QString name = mDatasetGroupStore->groupName( globalIndex );
1461 if ( !nameToIndex.contains( name ) )
1462 {
1463 consistentSettings.setScalarSettings( globalIndex, mRendererSettings.scalarSettings( globalIndex ) );
1464 if ( mDatasetGroupStore->datasetGroupMetadata( globalIndex ).isVector() )
1465 {
1466 consistentSettings.setVectorSettings( globalIndex, mRendererSettings.vectorSettings( globalIndex ) );
1467 }
1468 }
1469 }
1470
1471 if ( !activeScalarName.isEmpty() )
1472 consistentSettings.setActiveScalarDatasetGroup( mDatasetGroupStore->indexFromGroupName( activeScalarName ) );
1473 if ( !activeVectorName.isEmpty() )
1474 consistentSettings.setActiveVectorDatasetGroup( mDatasetGroupStore->indexFromGroupName( activeVectorName ) );
1475
1476 return consistentSettings;
1477}
1478
1479void QgsMeshLayer::setDataSourcePrivate( const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, Qgis::DataProviderReadFlags flags )
1480{
1482
1483 mDataSource = dataSource;
1484 mLayerName = baseName;
1485 setProviderType( provider );
1486
1487 if ( !mDataSource.isEmpty() && !provider.isEmpty() )
1488 setDataProvider( provider, options, flags );
1489}
1490
1491QgsPointXY QgsMeshLayer::snapOnElement( QgsMesh::ElementType elementType, const QgsPointXY &point, double searchRadius )
1492{
1494
1495 switch ( elementType )
1496 {
1497 case QgsMesh::Vertex:
1498 return snapOnVertex( point, searchRadius );
1499 case QgsMesh::Edge:
1500 return snapOnEdge( point, searchRadius );
1501 case QgsMesh::Face:
1502 return snapOnFace( point, searchRadius );
1503 }
1504 return QgsPointXY(); // avoid warnings
1505}
1506
1508{
1510
1511 if ( !mNativeMesh )
1512 {
1513 // lazy loading of mesh data
1514 fillNativeMesh();
1515 }
1516
1517 QList<int> ret;
1518
1519 if ( !mNativeMesh )
1520 return ret;
1521
1522 QgsExpressionContext context;
1523 std::unique_ptr<QgsExpressionContextScope> expScope( QgsExpressionContextUtils::meshExpressionScope( QgsMesh::Vertex ) );
1524 context.appendScope( expScope.release() );
1525 context.lastScope()->setVariable( QStringLiteral( "_native_mesh" ), QVariant::fromValue( *mNativeMesh ) );
1526
1527 expression.prepare( &context );
1528
1529 for ( int i = 0; i < mNativeMesh->vertexCount(); ++i )
1530 {
1531 context.lastScope()->setVariable( QStringLiteral( "_mesh_vertex_index" ), i, false );
1532
1533 if ( expression.evaluate( &context ).toBool() )
1534 ret.append( i );
1535 }
1536
1537 return ret;
1538}
1539
1541{
1543
1544 if ( !mNativeMesh )
1545 {
1546 // lazy loading of mesh data
1547 fillNativeMesh();
1548 }
1549
1550 QList<int> ret;
1551
1552 if ( !mNativeMesh )
1553 return ret;
1554
1555 QgsExpressionContext context;
1556 std::unique_ptr<QgsExpressionContextScope> expScope( QgsExpressionContextUtils::meshExpressionScope( QgsMesh::Face ) );
1557 context.appendScope( expScope.release() );
1558 context.lastScope()->setVariable( QStringLiteral( "_native_mesh" ), QVariant::fromValue( *mNativeMesh ) );
1559
1560 expression.prepare( &context );
1561
1562 for ( int i = 0; i < mNativeMesh->faceCount(); ++i )
1563 {
1564 context.lastScope()->setVariable( QStringLiteral( "_mesh_face_index" ), i, false );
1565
1566 if ( expression.evaluate( &context ).toBool() )
1567 ret.append( i );
1568 }
1569
1570 return ret;
1571}
1572
1574{
1576
1577 return QgsMeshDatasetIndex( group >= 0 ? group : mRendererSettings.activeScalarDatasetGroup(), mStaticScalarDatasetIndex );
1578}
1579
1581{
1583
1584 const int oldActiveVector = mRendererSettings.activeVectorDatasetGroup();
1585
1586 mStaticVectorDatasetIndex = staticVectorDatasetIndex.dataset();
1588
1589 if ( oldActiveVector != mRendererSettings.activeVectorDatasetGroup() )
1591}
1592
1594{
1596
1597 const int oldActiveScalar = mRendererSettings.activeScalarDatasetGroup();
1598
1599 mStaticScalarDatasetIndex = staticScalarDatasetIndex.dataset();
1601
1602 if ( oldActiveScalar != mRendererSettings.activeScalarDatasetGroup() )
1604}
1605
1612
1614{
1616
1617 mSimplificationSettings = simplifySettings;
1618}
1619
1620static QgsColorRamp *_createDefaultColorRamp()
1621{
1622 QgsColorRamp *ramp = QgsStyle::defaultStyle()->colorRamp( QStringLiteral( "Plasma" ) );
1623 if ( ramp )
1624 return ramp;
1625
1626 // definition of "Plasma" color ramp (in case it is not available in the style for some reason)
1627 QVariantMap props;
1628 props["color1"] = "13,8,135,255";
1629 props["color2"] = "240,249,33,255";
1630 props["stops"] =
1631 "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:"
1632 "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:"
1633 "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:"
1634 "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:"
1635 "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:"
1636 "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:"
1637 "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:"
1638 "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:"
1639 "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:"
1640 "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";
1641 return QgsGradientColorRamp::create( props );
1642}
1643
1644void QgsMeshLayer::assignDefaultStyleToDatasetGroup( int groupIndex )
1645{
1647
1649 const double groupMin = metadata.minimum();
1650 const double groupMax = metadata.maximum();
1651
1652 QgsColorRampShader fcn( groupMin, groupMax, _createDefaultColorRamp() );
1653 fcn.classifyColorRamp( 5, -1, QgsRectangle(), nullptr );
1654
1655 QgsMeshRendererScalarSettings scalarSettings;
1656 scalarSettings.setClassificationMinimumMaximum( groupMin, groupMax );
1657 scalarSettings.setColorRampShader( fcn );
1658 QgsInterpolatedLineWidth edgeStrokeWidth;
1659 edgeStrokeWidth.setMinimumValue( groupMin );
1660 edgeStrokeWidth.setMaximumValue( groupMax );
1661 const QgsInterpolatedLineColor edgeStrokeColor( fcn );
1662 const QgsInterpolatedLineRenderer edgeStrokePen;
1663 scalarSettings.setEdgeStrokeWidth( edgeStrokeWidth );
1664 mRendererSettings.setScalarSettings( groupIndex, scalarSettings );
1665
1666 if ( metadata.isVector() )
1667 {
1668 QgsMeshRendererVectorSettings vectorSettings;
1669 vectorSettings.setColorRampShader( fcn );
1670 mRendererSettings.setVectorSettings( groupIndex, vectorSettings );
1671 }
1672}
1673
1675{
1677
1678 // Triangular mesh
1679 updateTriangularMesh( rendererContext.coordinateTransform() );
1680
1681 // Build overview triangular meshes if needed
1682 createSimplifiedMeshes();
1683
1684 // Cache
1685 if ( !mRendererCache )
1686 mRendererCache.reset( new QgsMeshLayerRendererCache() );
1687
1688 return new QgsMeshLayerRenderer( this, rendererContext );
1689}
1690
1692{
1693 if ( rendererContext.isTemporal() )
1694 return activeScalarDatasetAtTime( rendererContext.temporalRange(), mRendererSettings.activeScalarDatasetGroup() );
1695 else
1696 return staticScalarDatasetIndex( mRendererSettings.activeScalarDatasetGroup() );
1697}
1698
1699bool QgsMeshLayer::minimumMaximumActiveScalarDataset( const QgsRectangle &extent, const QgsMeshDatasetIndex &datasetIndex, double &min, double &max )
1700{
1701
1702 if ( extent.isNull() || !this->extent().intersects( extent ) )
1703 return false;
1704
1706
1707 QVector<double> scalarDatasetValues;
1709
1710 if ( !metadata.isScalar() )
1711 {
1712 return false;
1713 }
1714
1715 QgsMeshDatasetGroupMetadata::DataType scalarDataType = QgsMeshLayerUtils::datasetValuesType( metadata.dataType() );
1716
1717 if ( !datasetIndex.isValid() )
1718 {
1719 return false;
1720 }
1721
1722 // populate scalar values
1723 const int count = QgsMeshLayerUtils::datasetValuesCount( mNativeMesh.get(), scalarDataType );
1724 const QgsMeshDataBlock vals = QgsMeshLayerUtils::datasetValues(
1725 this,
1726 datasetIndex,
1727 0,
1728 count );
1729
1730 if ( vals.isValid() )
1731 {
1732 // vals could be scalar or vectors, for contour rendering we want always magnitude
1733 scalarDatasetValues = QgsMeshLayerUtils::calculateMagnitudes( vals );
1734 }
1735 else
1736 {
1737 scalarDatasetValues = QVector<double>( count, std::numeric_limits<double>::quiet_NaN() );
1738 }
1739
1740 QList<int> intersectedFacesIndices = tMesh->faceIndexesForRectangle( extent );
1741
1742 if ( intersectedFacesIndices.isEmpty() )
1743 {
1744 return false;
1745 }
1746
1747 min = std::numeric_limits<double>::max();
1748 max = -std::numeric_limits<double>::max();
1749
1750 double value;
1751
1752 for ( int intersectedFaceIndex : intersectedFacesIndices )
1753 {
1754 QgsMeshFace face = tMesh->triangles().at( intersectedFaceIndex );
1755
1757 {
1758 value = scalarDatasetValues.at( tMesh->trianglesToNativeFaces().at( intersectedFaceIndex ) );
1759 min = std::min( min, value );
1760 max = std::max( max, value );
1761 }
1763 {
1764 QgsMeshVertex vertex;
1765
1766 for ( int vertexIndex : face )
1767 {
1768 value = scalarDatasetValues.at( vertexIndex );
1769 min = std::min( min, value );
1770 max = std::max( max, value );
1771 }
1772 }
1773 }
1774
1775 return true;
1776}
1777
1784
1785void QgsMeshLayer::checkSymbologyConsistency()
1786{
1788
1789 const QList<int> groupIndexes = mDatasetGroupStore->datasetGroupIndexes();
1790 if ( !groupIndexes.contains( mRendererSettings.activeScalarDatasetGroup() ) &&
1791 mRendererSettings.activeScalarDatasetGroup() != -1 )
1792 {
1793 if ( !groupIndexes.empty() )
1794 mRendererSettings.setActiveScalarDatasetGroup( groupIndexes.first() );
1795 else
1796 mRendererSettings.setActiveScalarDatasetGroup( -1 );
1797 }
1798
1799 if ( !groupIndexes.contains( mRendererSettings.activeVectorDatasetGroup() ) &&
1800 mRendererSettings.activeVectorDatasetGroup() != -1 )
1801 {
1802 mRendererSettings.setActiveVectorDatasetGroup( -1 );
1803 }
1804}
1805
1806bool QgsMeshLayer::readSymbology( const QDomNode &node, QString &errorMessage,
1808{
1810
1811 Q_UNUSED( errorMessage )
1812 // TODO: implement categories for raster layer
1813
1814 const QDomElement elem = node.toElement();
1815
1816 readCommonStyle( elem, context, categories );
1817
1819 const QDomElement elemRendererSettings = elem.firstChildElement( "mesh-renderer-settings" );
1820 if ( !elemRendererSettings.isNull() )
1821 rendererSettings.readXml( elemRendererSettings, context );
1822
1823 QMap<QString, int> groupNameToGlobalIndex;
1824 QDomElement nameToIndexElem = elem.firstChildElement( "name-to-global-index" );
1825 while ( !nameToIndexElem.isNull() )
1826 {
1827 const QString name = nameToIndexElem.attribute( QStringLiteral( "name" ) );
1828 int globalIndex = nameToIndexElem.attribute( QStringLiteral( "global-index" ) ).toInt();
1829 groupNameToGlobalIndex.insert( name, globalIndex );
1830 nameToIndexElem = nameToIndexElem.nextSiblingElement( QStringLiteral( "name-to-global-index" ) );
1831 }
1832
1833 mRendererSettings = accordSymbologyWithGroupName( rendererSettings, groupNameToGlobalIndex );
1834
1835 checkSymbologyConsistency();
1836
1837 const QDomElement elemSimplifySettings = elem.firstChildElement( "mesh-simplify-settings" );
1838 if ( !elemSimplifySettings.isNull() )
1839 mSimplificationSettings.readXml( elemSimplifySettings, context );
1840
1841 // get and set the blend mode if it exists
1842 const QDomNode blendModeNode = node.namedItem( QStringLiteral( "blendMode" ) );
1843 if ( !blendModeNode.isNull() )
1844 {
1845 const QDomElement e = blendModeNode.toElement();
1846 setBlendMode( QgsPainting::getCompositionMode( static_cast< Qgis::BlendMode >( e.text().toInt() ) ) );
1847 }
1848
1849 // read labeling definition
1850 if ( categories.testFlag( Labeling ) )
1851 {
1852 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Labeling" ) );
1853
1854 QDomElement labelingElement = node.firstChildElement( QStringLiteral( "labeling" ) );
1855 if ( !labelingElement.isNull() )
1856 {
1858 mLabelsEnabled = node.toElement().attribute( QStringLiteral( "labelsEnabled" ), QStringLiteral( "0" ) ).toInt();
1860 }
1861 }
1862
1863 // get and set the layer transparency
1864 if ( categories.testFlag( Rendering ) )
1865 {
1866 const QDomNode layerOpacityNode = node.namedItem( QStringLiteral( "layerOpacity" ) );
1867 if ( !layerOpacityNode.isNull() )
1868 {
1869 const QDomElement e = layerOpacityNode.toElement();
1870 setOpacity( e.text().toDouble() );
1871 }
1872 }
1873
1874 return true;
1875}
1876
1877bool QgsMeshLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage,
1878 const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1879{
1881
1882 Q_UNUSED( errorMessage )
1883 // TODO: implement categories for raster layer
1884
1885 QDomElement elem = node.toElement();
1886
1887 writeCommonStyle( elem, doc, context, categories );
1888
1889 const QDomElement elemRendererSettings = mRendererSettings.writeXml( doc, context );
1890 elem.appendChild( elemRendererSettings );
1891
1892 const QList<int> groupIndexes = datasetGroupsIndexes();
1893 // we store the relation between name and indexes to be able to retrieve the consistency between name and symbology
1894 for ( int index : groupIndexes )
1895 {
1896 QDomElement elemNameToIndex = doc.createElement( QStringLiteral( "name-to-global-index" ) );
1897 elemNameToIndex.setAttribute( QStringLiteral( "name" ), mDatasetGroupStore->groupName( index ) );
1898 elemNameToIndex.setAttribute( QStringLiteral( "global-index" ), index );
1899 elem.appendChild( elemNameToIndex );
1900 }
1901
1902 const QDomElement elemSimplifySettings = mSimplificationSettings.writeXml( doc, context );
1903 elem.appendChild( elemSimplifySettings );
1904
1905 // add blend mode node
1906 QDomElement blendModeElement = doc.createElement( QStringLiteral( "blendMode" ) );
1907 const QDomText blendModeText = doc.createTextNode( QString::number( static_cast< int >( QgsPainting::getBlendModeEnum( blendMode() ) ) ) );
1908 blendModeElement.appendChild( blendModeText );
1909 node.appendChild( blendModeElement );
1910
1911 if ( categories.testFlag( Labeling ) )
1912 {
1913 if ( mLabeling )
1914 {
1915 QDomElement labelingElement = mLabeling->save( doc, context );
1916 elem.appendChild( labelingElement );
1917 }
1918 elem.setAttribute( QStringLiteral( "labelsEnabled" ), mLabelsEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
1919 }
1920
1921 // add the layer opacity
1922 if ( categories.testFlag( Rendering ) )
1923 {
1924 QDomElement layerOpacityElem = doc.createElement( QStringLiteral( "layerOpacity" ) );
1925 const QDomText layerOpacityText = doc.createTextNode( QString::number( opacity() ) );
1926 layerOpacityElem.appendChild( layerOpacityText );
1927 node.appendChild( layerOpacityElem );
1928 }
1929
1930 return true;
1931}
1932
1933bool QgsMeshLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1934{
1936
1937 return writeSymbology( node, doc, errorMessage, context, categories );
1938}
1939
1940bool QgsMeshLayer::readStyle( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
1941{
1943
1944 return readSymbology( node, errorMessage, context, categories );
1945}
1946
1947QString QgsMeshLayer::decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const
1948{
1950
1951 return QgsProviderRegistry::instance()->relativeToAbsoluteUri( provider, source, context );
1952}
1953
1954QString QgsMeshLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
1955{
1957
1959}
1960
1961bool QgsMeshLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &context )
1962{
1964
1965 QgsDebugMsgLevel( QStringLiteral( "Datasource in QgsMeshLayer::readXml: %1" ).arg( mDataSource.toLocal8Bit().data() ), 3 );
1966
1967 //process provider key
1968 const QDomNode pkeyNode = layer_node.namedItem( QStringLiteral( "provider" ) );
1969
1970 if ( pkeyNode.isNull() )
1971 {
1972 mProviderKey.clear();
1973 }
1974 else
1975 {
1976 const QDomElement pkeyElt = pkeyNode.toElement();
1977 mProviderKey = pkeyElt.text();
1978 }
1979
1981 {
1982 return false;
1983 }
1984
1985 const QgsDataProvider::ProviderOptions providerOptions;
1987
1988 const QDomElement elemExtraDatasets = layer_node.firstChildElement( QStringLiteral( "extra-datasets" ) );
1989 if ( !elemExtraDatasets.isNull() )
1990 {
1991 QDomElement elemUri = elemExtraDatasets.firstChildElement( QStringLiteral( "uri" ) );
1992 while ( !elemUri.isNull() )
1993 {
1994 const QString uri = context.pathResolver().readPath( elemUri.text() );
1995 mExtraDatasetUri.append( uri );
1996 elemUri = elemUri.nextSiblingElement( QStringLiteral( "uri" ) );
1997 }
1998 }
1999
2000 if ( pkeyNode.toElement().hasAttribute( QStringLiteral( "time-unit" ) ) )
2001 mTemporalUnit = static_cast<Qgis::TemporalUnit>( pkeyNode.toElement().attribute( QStringLiteral( "time-unit" ) ).toInt() );
2002
2003 // read dataset group store
2004 const QDomElement elemDatasetGroupsStore = layer_node.firstChildElement( QStringLiteral( "mesh-dataset-groups-store" ) );
2005 if ( elemDatasetGroupsStore.isNull() )
2007 else
2008 mDatasetGroupStore->readXml( elemDatasetGroupsStore, context );
2009
2010 setDataProvider( mProviderKey, providerOptions, flags );
2011
2012 QString errorMsg;
2013 readSymbology( layer_node, errorMsg, context );
2014
2015 if ( !mTemporalProperties->timeExtent().begin().isValid() || mTemporalProperties->alwaysLoadReferenceTimeFromSource() )
2017
2018 // read static dataset
2019 const QDomElement elemStaticDataset = layer_node.firstChildElement( QStringLiteral( "static-active-dataset" ) );
2020 if ( elemStaticDataset.hasAttribute( QStringLiteral( "scalar" ) ) )
2021 {
2022 mStaticScalarDatasetIndex = elemStaticDataset.attribute( QStringLiteral( "scalar" ) ).toInt();
2023 }
2024 if ( elemStaticDataset.hasAttribute( QStringLiteral( "vector" ) ) )
2025 {
2026 mStaticVectorDatasetIndex = elemStaticDataset.attribute( QStringLiteral( "vector" ) ).toInt();
2027 }
2028
2029 return isValid(); // should be true if read successfully
2030}
2031
2032bool QgsMeshLayer::writeXml( QDomNode &layer_node, QDomDocument &document, const QgsReadWriteContext &context ) const
2033{
2035
2036 // first get the layer element so that we can append the type attribute
2037 QDomElement mapLayerNode = layer_node.toElement();
2038
2039 if ( mapLayerNode.isNull() || ( QLatin1String( "maplayer" ) != mapLayerNode.nodeName() ) )
2040 {
2041 QgsDebugMsgLevel( QStringLiteral( "can't find <maplayer>" ), 2 );
2042 return false;
2043 }
2044
2045 mapLayerNode.setAttribute( QStringLiteral( "type" ), QgsMapLayerFactory::typeToString( Qgis::LayerType::Mesh ) );
2046
2047 // add provider node
2048 if ( mDataProvider )
2049 {
2050 QDomElement provider = document.createElement( QStringLiteral( "provider" ) );
2051 const QDomText providerText = document.createTextNode( providerType() );
2052 provider.appendChild( providerText );
2053 layer_node.appendChild( provider );
2054 provider.setAttribute( QStringLiteral( "time-unit" ), static_cast< int >( mDataProvider->temporalCapabilities()->temporalUnit() ) );
2055
2056 const QStringList extraDatasetUris = mDataProvider->extraDatasets();
2057 QDomElement elemExtraDatasets = document.createElement( QStringLiteral( "extra-datasets" ) );
2058 for ( const QString &uri : extraDatasetUris )
2059 {
2060 const QString path = context.pathResolver().writePath( uri );
2061 QDomElement elemUri = document.createElement( QStringLiteral( "uri" ) );
2062 elemUri.appendChild( document.createTextNode( path ) );
2063 elemExtraDatasets.appendChild( elemUri );
2064 }
2065 layer_node.appendChild( elemExtraDatasets );
2066 }
2067
2068 QDomElement elemStaticDataset = document.createElement( QStringLiteral( "static-active-dataset" ) );
2069 elemStaticDataset.setAttribute( QStringLiteral( "scalar" ), mStaticScalarDatasetIndex );
2070 elemStaticDataset.setAttribute( QStringLiteral( "vector" ), mStaticVectorDatasetIndex );
2071 layer_node.appendChild( elemStaticDataset );
2072
2073 // write dataset group store if not in edting mode
2074 if ( !isEditable() )
2075 layer_node.appendChild( mDatasetGroupStore->writeXml( document, context ) );
2076
2077 // renderer specific settings
2078 QString errorMsg;
2079 return writeSymbology( layer_node, document, errorMsg, context );
2080}
2081
2083{
2085
2086 if ( !mMeshEditor && mDataProvider && mDataProvider->isValid() )
2087 {
2088 mDataProvider->reloadData();
2089 mDatasetGroupStore->setPersistentProvider( mDataProvider, QStringList() ); //extra dataset are already loaded
2090
2091 //reload the mesh structure
2092 if ( !mNativeMesh )
2093 mNativeMesh.reset( new QgsMesh );
2094
2095 dataProvider()->populateMesh( mNativeMesh.get() );
2096
2097 if ( mTemporalProperties->alwaysLoadReferenceTimeFromSource() )
2098 mTemporalProperties->setDefaultsFromDataProviderTemporalCapabilities( mDataProvider->temporalCapabilities() );
2099
2100 //clear the TriangularMeshes
2101 mTriangularMeshes.clear();
2102
2103 //clear the rendererCache
2104 mRendererCache.reset( new QgsMeshLayerRendererCache() );
2105
2106 checkSymbologyConsistency();
2107
2108 emit reloaded();
2109 }
2110}
2111
2112QStringList QgsMeshLayer::subLayers() const
2113{
2115
2116 if ( mDataProvider )
2117 return mDataProvider->subLayers();
2118 else
2119 return QStringList();
2120}
2121
2123{
2125
2126 const QgsLayerMetadataFormatter htmlFormatter( metadata() );
2127 QString myMetadata = QStringLiteral( "<html>\n<body>\n" );
2128
2129 myMetadata += generalHtmlMetadata();
2130
2131 // Begin Provider section
2132 myMetadata += QStringLiteral( "<h1>" ) + tr( "Information from provider" ) + QStringLiteral( "</h1>\n<hr>\n" );
2133 myMetadata += QLatin1String( "<table class=\"list-view\">\n" );
2134
2135 // Extent
2136 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Extent" ) + QStringLiteral( "</td><td>" ) + extent().toString() + QStringLiteral( "</td></tr>\n" );
2137
2138 // feature count
2139 QLocale locale = QLocale();
2140 locale.setNumberOptions( locale.numberOptions() &= ~QLocale::NumberOption::OmitGroupSeparator );
2141
2142 if ( const QgsMeshDataProvider *provider = dataProvider() )
2143 {
2144 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
2145 + tr( "Vertex count" ) + QStringLiteral( "</td><td>" )
2146 + ( locale.toString( static_cast<qlonglong>( meshVertexCount() ) ) )
2147 + QStringLiteral( "</td></tr>\n" );
2148 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
2149 + tr( "Face count" ) + QStringLiteral( "</td><td>" )
2150 + ( locale.toString( static_cast<qlonglong>( meshFaceCount() ) ) )
2151 + QStringLiteral( "</td></tr>\n" );
2152 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
2153 + tr( "Edge count" ) + QStringLiteral( "</td><td>" )
2154 + ( locale.toString( static_cast<qlonglong>( meshEdgeCount() ) ) )
2155 + QStringLiteral( "</td></tr>\n" );
2156 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
2157 + tr( "Dataset groups count" ) + QStringLiteral( "</td><td>" )
2158 + ( locale.toString( static_cast<qlonglong>( datasetGroupCount() ) ) )
2159 + QStringLiteral( "</td></tr>\n" );
2160 myMetadata += provider->htmlMetadata();
2161 }
2162
2163 // End Provider section
2164 myMetadata += QLatin1String( "</table>\n<br><br>" );
2165
2166 // CRS
2167 myMetadata += crsHtmlMetadata();
2168
2169 // identification section
2170 myMetadata += QStringLiteral( "<h1>" ) + tr( "Identification" ) + QStringLiteral( "</h1>\n<hr>\n" );
2171 myMetadata += htmlFormatter.identificationSectionHtml( );
2172 myMetadata += QLatin1String( "<br><br>\n" );
2173
2174 // extent section
2175 myMetadata += QStringLiteral( "<h1>" ) + tr( "Extent" ) + QStringLiteral( "</h1>\n<hr>\n" );
2176 myMetadata += htmlFormatter.extentSectionHtml( isSpatial() );
2177 myMetadata += QLatin1String( "<br><br>\n" );
2178
2179 // Start the Access section
2180 myMetadata += QStringLiteral( "<h1>" ) + tr( "Access" ) + QStringLiteral( "</h1>\n<hr>\n" );
2181 myMetadata += htmlFormatter.accessSectionHtml( );
2182 myMetadata += QLatin1String( "<br><br>\n" );
2183
2184 // Start the contacts section
2185 myMetadata += QStringLiteral( "<h1>" ) + tr( "Contacts" ) + QStringLiteral( "</h1>\n<hr>\n" );
2186 myMetadata += htmlFormatter.contactsSectionHtml( );
2187 myMetadata += QLatin1String( "<br><br>\n" );
2188
2189 // Start the links section
2190 myMetadata += QStringLiteral( "<h1>" ) + tr( "Links" ) + QStringLiteral( "</h1>\n<hr>\n" );
2191 myMetadata += htmlFormatter.linksSectionHtml( );
2192 myMetadata += QLatin1String( "<br><br>\n" );
2193
2194 // Start the history section
2195 myMetadata += QStringLiteral( "<h1>" ) + tr( "History" ) + QStringLiteral( "</h1>\n<hr>\n" );
2196 myMetadata += htmlFormatter.historySectionHtml( );
2197 myMetadata += QLatin1String( "<br><br>\n" );
2198
2199 myMetadata += customPropertyHtmlMetadata();
2200
2201 myMetadata += QLatin1String( "\n</body>\n</html>\n" );
2202 return myMetadata;
2203}
2204
2206{
2208
2209 return mMeshEditor;
2210}
2211
2212bool QgsMeshLayer::setDataProvider( QString const &provider, const QgsDataProvider::ProviderOptions &options, Qgis::DataProviderReadFlags flags )
2213{
2215
2216 mDatasetGroupStore->setPersistentProvider( nullptr, QStringList() );
2217
2218 delete mDataProvider;
2219 mProviderKey = provider;
2220 const QString dataSource = mDataSource;
2221
2222 if ( mPreloadedProvider )
2223 {
2224 mDataProvider = qobject_cast< QgsMeshDataProvider * >( mPreloadedProvider.release() );
2225 }
2226 else
2227 {
2228 std::unique_ptr< QgsScopedRuntimeProfile > profile;
2229 if ( QgsApplication::profiler()->groupIsActive( QStringLiteral( "projectload" ) ) )
2230 profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Create %1 provider" ).arg( provider ), QStringLiteral( "projectload" ) );
2231
2232 mDataProvider = qobject_cast<QgsMeshDataProvider *>( QgsProviderRegistry::instance()->createProvider( provider, dataSource, options, flags ) );
2233 }
2234
2235 if ( !mDataProvider )
2236 {
2237 QgsDebugMsgLevel( QStringLiteral( "Unable to get mesh data provider" ), 2 );
2238 return false;
2239 }
2240
2241 mDataProvider->setParent( this );
2242 QgsDebugMsgLevel( QStringLiteral( "Instantiated the mesh data provider plugin" ), 2 );
2243
2244 setValid( mDataProvider->isValid() );
2245 if ( !isValid() )
2246 {
2247 QgsDebugMsgLevel( QStringLiteral( "Invalid mesh provider plugin %1" ).arg( QString( mDataSource.toUtf8() ) ), 2 );
2248 return false;
2249 }
2250
2251 if ( !mTemporalProperties->isValid() )
2252 {
2253 mTemporalProperties->setDefaultsFromDataProviderTemporalCapabilities( dataProvider()->temporalCapabilities() );
2254 }
2255
2256 mDataProvider->setTemporalUnit( mTemporalUnit );
2257
2258 mDatasetGroupStore->setPersistentProvider( mDataProvider, mExtraDatasetUri );
2259
2260 setCrs( mDataProvider->crs() );
2261
2262 if ( provider == QLatin1String( "mesh_memory" ) )
2263 {
2264 // required so that source differs between memory layers
2265 mDataSource = mDataSource + QStringLiteral( "&uid=%1" ).arg( QUuid::createUuid().toString() );
2266 }
2267
2268 // set default style if required by flags or if the dataset group does not has a style yet
2269 for ( int i = 0; i < mDataProvider->datasetGroupCount(); ++i )
2270 {
2271 int globalIndex = mDatasetGroupStore->globalDatasetGroupIndexInSource( mDataProvider, i );
2272 if ( globalIndex != -1 &&
2273 ( !mRendererSettings.hasSettings( globalIndex ) || ( flags & Qgis::DataProviderReadFlag::LoadDefaultStyle ) ) )
2274 assignDefaultStyleToDatasetGroup( globalIndex );
2275 }
2276
2277 emit rendererChanged();
2279
2280 connect( mDataProvider, &QgsMeshDataProvider::dataChanged, this, &QgsMeshLayer::dataChanged );
2281
2282 return true;
2283}
2284
2291
2298
2300{
2302
2303 return mLabelsEnabled && static_cast< bool >( mLabeling );
2304}
2305
2307{
2309
2310 mLabelsEnabled = enabled;
2311}
2312
2314{
2316
2317 if ( mLabeling == labeling )
2318 return;
2319
2320 delete mLabeling;
2321 mLabeling = labeling;
2323}
2324
2325bool QgsMeshLayer::datasetsPathUnique( const QString &path )
2326{
2327 if ( ! mDataProvider )
2328 {
2329 QgsDebugMsgLevel( QStringLiteral( "Unable to get mesh data provider" ), 2 );
2330 return false;
2331 }
2332
2333 if ( mDataProvider->dataSourceUri().contains( path ) )
2334 return false;
2335
2336 return !mExtraDatasetUri.contains( path );
2337}
The Qgis class provides global constants for use throughout the application.
Definition qgis.h:54
@ Exact
Assigns the color of the exact matching value in the color ramp item list.
@ Critical
Critical/error message.
Definition qgis.h:157
@ TooManyVerticesInFace
A face has more vertices than the maximum number supported per face.
@ InvalidFace
An error occurs due to an invalid face (for example, vertex indexes are unordered)
@ UniqueSharedVertex
A least two faces share only one vertices.
@ ManifoldFace
ManifoldFace.
@ InvalidVertex
An error occurs due to an invalid vertex (for example, vertex index is out of range the available ver...
@ FlatFace
A flat face is present.
BlendMode
Blending modes defining the available composition modes that can be used when painting.
Definition qgis.h:4657
TemporalUnit
Temporal units.
Definition qgis.h:4886
@ Milliseconds
Milliseconds.
QFlags< DataProviderReadFlag > DataProviderReadFlags
Flags which control data provider construction.
Definition qgis.h:450
@ EqualInterval
Uses equal interval.
@ Mesh
Mesh layer. Added in QGIS 3.2.
@ LoadDefaultStyle
Reset the layer's style to the default for the datasource.
QgsVertexIterator vertices() const
Returns a read-only, Java-style iterator for traversal of vertices of all the geometry,...
Abstract base class - its implementations define different approaches to the labeling of a mesh layer...
static QgsAbstractMeshLayerLabeling * create(const QDomElement &element, const QgsReadWriteContext &context)
Try to create instance of an implementation based on the XML data.
virtual QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context) const =0
Returns labeling configuration as XML element.
Abstract base class for objects which generate elevation profiles.
static QgsRuntimeProfiler * profiler()
Returns the application runtime profiler.
A ramp shader will color a raster pixel based on a list of values ranges in a ramp.
void setClassificationMode(Qgis::ShaderClassificationMethod classificationMode)
Sets the classification mode.
QgsColorRamp * sourceColorRamp() const
Returns the source color ramp.
void setColorRampType(Qgis::ShaderInterpolationMethod colorRampType)
Sets the color ramp interpolation method.
void setColorRampItemList(const QList< QgsColorRampShader::ColorRampItem > &list)
Sets a custom color map.
Abstract base class for color ramps.
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.
Base class for handling properties relating to a data provider's temporal capabilities.
bool hasTemporalCapabilities() const
Returns true if the provider has temporal capabilities available.
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 QString dataSourceUri(bool expandAuthConfig=false) const
Gets the data source specification.
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:46
double seconds() const
Returns the interval duration in seconds.
Class for metadata formatter.
Base class for storage of map layer elevation properties.
static QString typeToString(Qgis::LayerType 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:76
QString name
Definition qgsmaplayer.h:80
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.
void trigger3DUpdate()
Will advise any 3D maps that this layer requires to be updated in the scene.
static Qgis::DataProviderReadFlags providerReadFlags(const QDomNode &layerNode, QgsMapLayer::ReadFlags layerReadFlags)
Returns provider read flag deduced from layer read flags layerReadFlags and a dom node layerNode that...
QgsMapLayer::LayerFlags flags() const
Returns the flags for this layer.
void editingStarted()
Emitted when editing on this layer has started.
virtual QString loadDefaultStyle(bool &resultFlag)
Retrieve the default style for this layer if one exists (either as a .qml file on disk or as a record...
QString mLayerName
Name of the layer - used for display.
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:82
Qgis::LayerType type
Definition qgsmaplayer.h:86
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....
QFlags< StyleCategory > StyleCategories
QString mProviderKey
Data provider key (name of the data provider)
QgsCoordinateTransformContext transformContext() const
Returns the layer data provider coordinate transform context or a default transform context if the la...
std::unique_ptr< QgsDataProvider > mPreloadedProvider
Optionally used when loading a project, it is released when the layer is effectively created.
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.
void emitStyleChanged()
Triggers an emission of the styleChanged() signal.
void dataChanged()
Data of layer changed.
virtual QgsMapLayer * clone() const =0
Returns a new instance equivalent to this one except for the id which is still unique.
QString mDataSource
Data source description string, varies by layer type.
@ FlagDontResolveLayers
Don't resolve layer paths or create data providers for layers.
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.
void setLegend(QgsMapLayerLegend *legend)
Assign a legend controller to the map layer.
double opacity
Definition qgsmaplayer.h:88
@ Rendering
Rendering: scale visibility, simplify method, opacity.
@ Labeling
Labeling.
void layerModified()
Emitted when modifications has been done on layer.
void setProviderType(const QString &providerType)
Sets the providerType (provider key)
QString customPropertyHtmlMetadata() const
Returns an HTML fragment containing custom property information, for use in the htmlMetadata() method...
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.
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.
QDateTime referenceTime() const
Returns the reference time.
Qgis::TemporalUnit temporalUnit() const
Returns the temporal unit used to read data by the data provider.
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.
void setTemporalUnit(Qgis::TemporalUnit unit)
Sets the temporal unit of the provider and reload data if it changes.
QgsMeshDataProviderTemporalCapabilities * temporalCapabilities() override
Returns the provider's temporal capabilities.
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.
QString uri() const
Returns the uri of the source.
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.
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.
Qgis::MeshEditingErrorType errorType
Class that makes edit operation on a mesh.
QgsMeshEditingError initialize()
Initializes the mesh editor and returns first error if the internal native mesh has topological error...
int validFacesCount() const
Returns the count of valid faces, that is non void faces in the mesh.
bool checkConsistency(QgsMeshEditingError &error) const
Return true if the edited mesh is consistent.
QgsRectangle extent() const
Returns the extent of the edited mesh.
QgsMeshEditingError initializeWithErrorsFix()
Initializes the mesh editor.
int maximumVerticesPerFace() const
Returns the maximum count of vertices per face that the mesh can support.
void stopEditing()
Stops editing.
void meshEdited()
Emitted when the mesh is edited.
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...
Mesh layer specific subclass of QgsMapLayerElevationProperties.
QgsMeshLayerElevationProperties * clone() const override
Creates a clone of the properties.
Implementation of QgsAbstractProfileGenerator for mesh layers.
Implementation of threaded rendering for mesh layers.
Implementation of map layer temporal properties for mesh layers.
QDateTime referenceTime() const
Returns the reference time.
bool isValid() const
Returns whether the instance is valid.
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...
bool alwaysLoadReferenceTimeFromSource() const
Returns whether the time proporties are automatically reloaded from provider when project is opened o...
QgsDateTimeRange timeExtent() const
Returns the time extent.
Represents a mesh layer supporting display of data on structured or unstructured meshes.
~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 editing 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.
QgsMeshDatasetIndex activeScalarDatasetIndex(QgsRenderContext &rendererContext)
Returns current active scalar dataset index for current renderer context.
QgsMeshDatasetIndex activeVectorDatasetAtTime(const QgsDateTimeRange &timeRange, int group=-1) const
Returns dataset index from active vector group depending on the time range If the temporal properties...
QList< QgsMeshDatasetIndex > datasetIndexInRelativeTimeInterval(const QgsInterval &startRelativeTime, const QgsInterval &endRelativeTime, int datasetGroupIndex) const
Returns a list of dataset indexes from datasets group that are in a interval time from the layer refe...
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.
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.
const QgsAbstractMeshLayerLabeling * labeling() const
Access to const labeling configuration.
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...
QgsMeshDatasetIndex staticVectorDatasetIndex(int group=-1) const
Returns the static vector dataset index that is rendered if the temporal properties is not active.
QgsMesh * nativeMesh()
Returns native mesh (nullptr before rendering or calling to updateMesh)
QString loadDefaultStyle(bool &resultFlag) FINAL
Retrieve the default style for this layer if one exists (either as a .qml file on disk or as a record...
bool minimumMaximumActiveScalarDataset(const QgsRectangle &extent, const QgsMeshDatasetIndex &datasetIndex, double &min, double &max)
Extracts minimum and maximum value for active scalar dataset on mesh faces.
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...
QgsMapLayerElevationProperties * elevationProperties() override
Returns the layer's elevation properties.
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 editing 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 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 editing of the mesh frame, Rebuilds the triangular mesh and its spatial index with transform,...
QgsAbstractProfileGenerator * createProfileGenerator(const QgsProfileRequest &request) override
Given a profile request, returns a new profile generator ready for generating elevation profiles.
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 setLabeling(QgsAbstractMeshLayerLabeling *labeling)
Sets labeling configuration.
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.
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.
void setLabelsEnabled(bool enabled)
Sets whether labels should be enabled for the layer.
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.
Q_DECL_DEPRECATED bool startFrameEditing(const QgsCoordinateTransform &transform)
Starts editing 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
Write the style for the layer into the document provided.
int meshVertexCount() const
Returns the vertices count of the mesh frame.
bool labelsEnabled() const
Returns whether the layer contains labels which are enabled and should be drawn.
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.
bool datasetsPathUnique(const QString &path)
Checks whether that datasets path is already added to this mesh layer.
qint64 datasetRelativeTimeInMilliseconds(const QgsMeshDatasetIndex &index)
Returns the relative time (in milliseconds) of the dataset from the reference time of its group.
QgsMeshDatasetIndex activeScalarDatasetAtTime(const QgsDateTimeRange &timeRange, int group=-1) const
Returns dataset index from active scalar group depending on the time range.
QgsTriangularMesh * triangularMesh(double minimumTriangleSize=0) const
Returns triangular mesh (nullptr before rendering or calling to updateMesh).
QgsMeshDatasetIndex staticScalarDatasetIndex(int group=-1) const
Returns the static scalar dataset index that is rendered if the temporal properties is not active.
void setTemporalMatchingMethod(const QgsMeshDataProviderTemporalCapabilities::MatchingTemporalDatasetMethod &matchingMethod)
Sets the method used to match the temporal dataset from a requested time, see activeVectorDatasetAtTi...
bool removeDatasets(const QString &name)
Removes datasets from the mesh with given name.
QgsMeshDatasetGroupTreeItem * datasetGroupTreeRootItem() const
Returns the root items of the dataset group tree item.
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.
QgsMesh3DDataBlock dataset3dValue(const QgsMeshDatasetIndex &index, const QgsPointXY &point) const
Returns the 3d values of stacked 3d mesh defined by the given point.
bool readSymbology(const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) override
Read the symbology for the current layer from the DOM node supplied.
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...
void reloaded()
Emitted when the mesh layer is reloaded, see reload()
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.
@ NoResampling
Does not use resampling.
@ 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.
bool hasVectorSettings(int groupIndex) const
Returns whether groupIndex has existing vector settings.
QgsMesh3DAveragingMethod * averagingMethod() const
Returns averaging method for conversion of 3d stacked mesh data to 2d data.
bool removeVectorSettings(int groupIndex)
Removes vector settings for groupIndex.
bool hasSettings(int datasetGroupIndex) const
Returns whether the group with index has render settings (scalar or vector)
int activeScalarDatasetGroup() const
Returns the active scalar dataset group.
QgsMeshRendererVectorSettings vectorSettings(int groupIndex) const
Returns renderer settings.
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.
bool removeScalarSettings(int groupIndex)
Removes scalar settings with groupIndex.
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.
void setEnabled(bool isEnabled)
Sets if the overview is active.
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 Qgis::BlendMode getBlendModeEnum(QPainter::CompositionMode blendMode)
Returns a Qgis::BlendMode corresponding to a QPainter::CompositionMode.
static QPainter::CompositionMode getCompositionMode(Qgis::BlendMode blendMode)
Returns a QPainter::CompositionMode corresponding to a Qgis::BlendMode.
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:60
double distance(double x, double y) const
Returns the distance between this point and a specified x, y coordinate.
Definition qgspointxy.h:206
double y
Definition qgspointxy.h:64
double sqrDistToSegment(double x1, double y1, double x2, double y2, QgsPointXY &minDistPoint, double epsilon=DEFAULT_SEGMENT_EPSILON) const
Returns the minimum distance between this point and a segment.
double x
Definition qgspointxy.h:63
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:49
double x
Definition qgspoint.h:52
double distance(double x, double y) const
Returns the Cartesian 2D distance between this point and a specified x, y coordinate.
Definition qgspoint.h:393
double y
Definition qgspoint.h:53
Encapsulates properties and constraints relating to fetching elevation profiles from different source...
QString absoluteToRelativeUri(const QString &providerKey, const QString &uri, const QgsReadWriteContext &context) const
Converts absolute path(s) to relative path(s) in the given provider-specific URI.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
QString relativeToAbsoluteUri(const QString &providerKey, const QString &uri, const QgsReadWriteContext &context) const
Converts relative path(s) to absolute path(s) in the given provider-specific URI.
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.
Allows entering a context category and takes care of leaving this category on deletion of the class.
The class is used as a container of context for various read/write operations on other objects.
MAYBE_UNUSED NODISCARD QgsReadWriteContextCategoryPopper enterCategory(const QString &category, const QString &details=QString()) const
Push a category to the stack.
const QgsPathResolver & pathResolver() const
Returns path resolver for conversion between relative and absolute paths.
A rectangle specified with double values.
Q_INVOKABLE QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
void setNull()
Mark a rectangle as being null (holding no spatial information).
Contains information about the context of a rendering operation.
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
QgsColorRamp * colorRamp(const QString &name) const
Returns a new copy of the specified color ramp.
Definition qgsstyle.cpp:495
static QgsStyle * defaultStyle(bool initialize=true)
Returns the default application-wide style.
Definition qgsstyle.cpp:146
bool isActive() const
Returns true if the temporal property is active.
void setIsActive(bool active)
Sets whether the temporal property is active.
const QgsDateTimeRange & temporalRange() const
Returns the datetime range for the object.
bool isTemporal() const
Returns true if the object's temporal range is enabled, and the object will be filtered when renderin...
T begin() const
Returns the beginning of the range.
Definition qgsrange.h:444
static QgsMeshEditingError checkTopology(const QgsMesh &mesh, int maxVerticesPerFace)
Checks the topology of the mesh mesh, if error occurs, this mesh can't be edited.
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< 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.
#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.
#define QGIS_PROTECT_QOBJECT_THREAD_ACCESS
Setting options for creating vector data providers.
Setting options for loading mesh layers.
QgsCoordinateTransformContext transformContext
Coordinate transform context.
bool loadDefaultStyle
Set to true if the default layer style should be loaded.
bool skipCrsValidation
Controls whether the layer is allowed to have an invalid/unknown CRS.
Mesh - vertices, edges and faces.
ElementType
Defines type of mesh elements.