QGIS API Documentation 3.41.0-Master (fda2aa46e9a)
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::addDatasets( const QString &path, const QDateTime &defaultReferenceTime )
257{
259
261 const bool isTemporalBefore = temporalCapabilities->hasTemporalCapabilities();
262 if ( mDatasetGroupStore->addPersistentDatasets( path ) )
263 {
264 mExtraDatasetUri.append( path );
265 QgsMeshLayerTemporalProperties *temporalProperties = qobject_cast< QgsMeshLayerTemporalProperties * >( mTemporalProperties );
266 if ( !isTemporalBefore && temporalCapabilities->hasTemporalCapabilities() )
267 {
269 temporalCapabilities );
270
271 if ( ! temporalProperties->referenceTime().isValid() )
272 {
273 QDateTime referenceTime = defaultReferenceTime;
274 if ( !defaultReferenceTime.isValid() ) // If project reference time is invalid, use current date
275 referenceTime = QDateTime( QDate::currentDate(), QTime( 0, 0, 0 ), Qt::UTC );
276 temporalProperties->setReferenceTime( referenceTime, temporalCapabilities );
277 }
278
279 mTemporalProperties->setIsActive( true );
280 }
281 emit dataSourceChanged();
282 return true;
283 }
284
285 return false;
286}
287
289{
291
292 if ( mDatasetGroupStore->addDatasetGroup( datasetGroup ) )
293 {
294 emit dataChanged();
295 return true;
296 }
297 return false;
298}
299
300bool QgsMeshLayer::saveDataset( const QString &path, int datasetGroupIndex, QString driver )
301{
303
304 return mDatasetGroupStore->saveDatasetGroup( path, datasetGroupIndex, driver );
305}
306
308{
310
311 return mNativeMesh.get();
312}
313
315{
317
318 return mNativeMesh.get();
319}
320
321QgsTriangularMesh *QgsMeshLayer::triangularMesh( double minimumTriangleSize ) const
322{
324
325 for ( const std::unique_ptr<QgsTriangularMesh> &lod : mTriangularMeshes )
326 {
327 if ( lod && lod->averageTriangleSize() > minimumTriangleSize )
328 return lod.get();
329 }
330
331 if ( !mTriangularMeshes.empty() )
332 return mTriangularMeshes.back().get();
333 else
334 return nullptr;
335}
336
338{
340
341 return mTriangularMeshes.size();
342}
343
345{
347
348 if ( mTriangularMeshes.empty() )
349 return nullptr;
350 if ( lodIndex < 0 )
351 return mTriangularMeshes.front().get();
352
353 if ( lodIndex >= int( mTriangularMeshes.size() ) )
354 return mTriangularMeshes.back().get();
355
356 return mTriangularMeshes.at( lodIndex ).get();
357}
358
360{
362
363 // Native mesh
364 if ( !mNativeMesh )
365 {
366 // lazy loading of mesh data
367 fillNativeMesh();
368 }
369
370 // Triangular mesh
371 if ( mTriangularMeshes.empty() )
372 {
373 QgsTriangularMesh *baseMesh = new QgsTriangularMesh;
374 mTriangularMeshes.emplace_back( baseMesh );
375 }
376
377 if ( mTriangularMeshes[0].get()->update( mNativeMesh.get(), transform ) )
378 mTriangularMeshes.resize( 1 ); //if the base triangular mesh is effectivly updated, remove simplified meshes
379
380 createSimplifiedMeshes();
381}
382
383QgsMeshLayerRendererCache *QgsMeshLayer::rendererCache()
384{
386
387 return mRendererCache.get();
388}
389
396
398{
400
401 const int oldActiveScalar = mRendererSettings.activeScalarDatasetGroup();
402 const int oldActiveVector = mRendererSettings.activeVectorDatasetGroup();
403 mRendererSettings = settings;
404
405 if ( oldActiveScalar != mRendererSettings.activeScalarDatasetGroup() )
407
408 if ( oldActiveVector != mRendererSettings.activeVectorDatasetGroup() )
410
411 emit rendererChanged();
413}
414
421
423{
425
426 mTimeSettings = settings;
427 emit timeSettingsChanged();
428}
429
430QString QgsMeshLayer::formatTime( double hours )
431{
433
434 if ( dataProvider() && dataProvider()->temporalCapabilities()->hasReferenceTime() )
435 return QgsMeshLayerUtils::formatTime( hours, mTemporalProperties->referenceTime(), mTimeSettings );
436 else
437 return QgsMeshLayerUtils::formatTime( hours, QDateTime(), mTimeSettings );
438}
439
441{
443
444 return mDatasetGroupStore->datasetGroupCount();
445}
446
448{
450
451 return mDatasetGroupStore->extraDatasetGroupCount();
452}
453
455{
457
458 return mDatasetGroupStore->datasetGroupIndexes();
459}
460
462{
464
465 return mDatasetGroupStore->enabledDatasetGroupIndexes();
466}
467
469{
471
472 return mDatasetGroupStore->datasetGroupMetadata( index );
473}
474
476{
478
479 return mDatasetGroupStore->datasetCount( index.group() );
480}
481
483{
485
486 return mDatasetGroupStore->datasetMetadata( index );
487}
488
490{
492
493 return mDatasetGroupStore->datasetValue( index, valueIndex );
494}
495
496QgsMeshDataBlock QgsMeshLayer::datasetValues( const QgsMeshDatasetIndex &index, int valueIndex, int count ) const
497{
499
500 return mDatasetGroupStore->datasetValues( index, valueIndex, count );
501}
502
503QgsMesh3DDataBlock QgsMeshLayer::dataset3dValues( const QgsMeshDatasetIndex &index, int faceIndex, int count ) const
504{
506
507 return mDatasetGroupStore->dataset3dValues( index, faceIndex, count );
508}
509
510QgsMeshDataBlock QgsMeshLayer::areFacesActive( const QgsMeshDatasetIndex &index, int faceIndex, int count ) const
511{
513
514 return mDatasetGroupStore->areFacesActive( index, faceIndex, count );
515}
516
517bool QgsMeshLayer::isFaceActive( const QgsMeshDatasetIndex &index, int faceIndex ) const
518{
520
521 return mDatasetGroupStore->isFaceActive( index, faceIndex );
522}
523
524QgsMeshDatasetValue QgsMeshLayer::datasetValue( const QgsMeshDatasetIndex &index, const QgsPointXY &point, double searchRadius ) const
525{
527
529 const QgsTriangularMesh *mesh = triangularMesh();
530
531 if ( mesh && index.isValid() )
532 {
534 {
535 const QgsRectangle searchRectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
536 return dataset1dValue( index, point, searchRadius );
537 }
538 const int faceIndex = mesh->faceIndexForPoint_v2( point ) ;
539 if ( faceIndex >= 0 )
540 {
541 const int nativeFaceIndex = mesh->trianglesToNativeFaces().at( faceIndex );
543 if ( isFaceActive( index, nativeFaceIndex ) )
544 {
545 switch ( dataType )
546 {
548 {
549 value = datasetValue( index, nativeFaceIndex );
550 }
551 break;
552
554 {
555 const QgsMeshFace &face = mesh->triangles()[faceIndex];
556 const int v1 = face[0], v2 = face[1], v3 = face[2];
557 const QgsPoint p1 = mesh->vertices()[v1], p2 = mesh->vertices()[v2], p3 = mesh->vertices()[v3];
558 const QgsMeshDatasetValue val1 = datasetValue( index, v1 );
559 const QgsMeshDatasetValue val2 = datasetValue( index, v2 );
560 const QgsMeshDatasetValue val3 = datasetValue( index, v3 );
561 const double x = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.x(), val2.x(), val3.x(), point );
562 double y = std::numeric_limits<double>::quiet_NaN();
563 const bool isVector = datasetGroupMetadata( index ).isVector();
564 if ( isVector )
565 y = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.y(), val2.y(), val3.y(), point );
566
567 value = QgsMeshDatasetValue( x, y );
568 }
569 break;
570
572 {
573 const QgsMesh3DAveragingMethod *avgMethod = mRendererSettings.averagingMethod();
574 if ( avgMethod )
575 {
576 const QgsMesh3DDataBlock block3d = dataset3dValues( index, nativeFaceIndex, 1 );
577 const QgsMeshDataBlock block2d = avgMethod->calculate( block3d );
578 if ( block2d.isValid() )
579 {
580 value = block2d.value( 0 );
581 }
582 }
583 }
584 break;
585
586 default:
587 break;
588 }
589 }
590 }
591 }
592
593 return value;
594}
595
597{
599
600 QgsMesh3DDataBlock block3d;
601
602 const QgsTriangularMesh *baseTriangularMesh = triangularMesh();
603
604 if ( baseTriangularMesh && dataProvider() && dataProvider()->isValid() && index.isValid() )
605 {
608 {
609 const int faceIndex = baseTriangularMesh->faceIndexForPoint_v2( point );
610 if ( faceIndex >= 0 )
611 {
612 const int nativeFaceIndex = baseTriangularMesh->trianglesToNativeFaces().at( faceIndex );
613 block3d = dataset3dValues( index, nativeFaceIndex, 1 );
614 }
615 }
616 }
617 return block3d;
618}
619
620QgsMeshDatasetValue QgsMeshLayer::dataset1dValue( const QgsMeshDatasetIndex &index, const QgsPointXY &point, double searchRadius ) const
621{
623
625 QgsPointXY projectedPoint;
626 const int selectedIndex = closestEdge( point, searchRadius, projectedPoint );
627 const QgsTriangularMesh *mesh = triangularMesh();
628 if ( selectedIndex >= 0 )
629 {
631 switch ( dataType )
632 {
634 {
635 value = datasetValue( index, selectedIndex );
636 }
637 break;
638
640 {
641 const QgsMeshEdge &edge = mesh->edges()[selectedIndex];
642 const int v1 = edge.first, v2 = edge.second;
643 const QgsPoint p1 = mesh->vertices()[v1], p2 = mesh->vertices()[v2];
644 const QgsMeshDatasetValue val1 = datasetValue( index, v1 );
645 const QgsMeshDatasetValue val2 = datasetValue( index, v2 );
646 const double edgeLength = p1.distance( p2 );
647 const double dist1 = p1.distance( projectedPoint.x(), projectedPoint.y() );
648 value = QgsMeshLayerUtils::interpolateFromVerticesData( dist1 / edgeLength, val1, val2 );
649 }
650 break;
651 default:
652 break;
653 }
654 }
655
656 return value;
657}
658
660{
662
663 if ( mDataProvider )
664 mDataProvider->setTransformContext( transformContext );
666}
667
668QgsMeshDatasetIndex QgsMeshLayer::datasetIndexAtTime( const QgsDateTimeRange &timeRange, int datasetGroupIndex ) const
669{
671
672 if ( ! mTemporalProperties->isActive() )
673 return QgsMeshDatasetIndex( datasetGroupIndex, -1 );
674
675 const QDateTime layerReferenceTime = mTemporalProperties->referenceTime();
676 QDateTime utcTime = timeRange.begin();
677 if ( utcTime.timeSpec() != Qt::UTC )
678 utcTime.setTimeSpec( Qt::UTC );
679 const qint64 startTime = layerReferenceTime.msecsTo( utcTime );
680
681 return mDatasetGroupStore->datasetIndexAtTime( startTime, datasetGroupIndex, mTemporalProperties->matchingMethod() );
682}
683
684QgsMeshDatasetIndex QgsMeshLayer::datasetIndexAtRelativeTime( const QgsInterval &relativeTime, int datasetGroupIndex ) const
685{
687
688 return mDatasetGroupStore->datasetIndexAtTime( relativeTime.seconds() * 1000, datasetGroupIndex, mTemporalProperties->matchingMethod() );
689}
690
691QList<QgsMeshDatasetIndex> QgsMeshLayer::datasetIndexInRelativeTimeInterval( const QgsInterval &startRelativeTime, const QgsInterval &endRelativeTime, int datasetGroupIndex ) const
692{
694
695 qint64 usedRelativeTime1 = startRelativeTime.seconds() * 1000;
696 qint64 usedRelativeTime2 = endRelativeTime.seconds() * 1000;
697
698 //adjust relative time if layer reference time is different from provider reference time
699 if ( mTemporalProperties->referenceTime().isValid() &&
700 mDataProvider &&
701 mDataProvider->isValid() &&
702 mTemporalProperties->referenceTime() != mDataProvider->temporalCapabilities()->referenceTime() )
703 {
704 usedRelativeTime1 = usedRelativeTime1 + mTemporalProperties->referenceTime().msecsTo( mDataProvider->temporalCapabilities()->referenceTime() );
705 usedRelativeTime2 = usedRelativeTime2 + mTemporalProperties->referenceTime().msecsTo( mDataProvider->temporalCapabilities()->referenceTime() );
706 }
707
708 return mDatasetGroupStore->datasetIndexInTimeInterval( usedRelativeTime1, usedRelativeTime2, datasetGroupIndex );
709}
710
711void QgsMeshLayer::applyClassificationOnScalarSettings( const QgsMeshDatasetGroupMetadata &meta, QgsMeshRendererScalarSettings &scalarSettings ) const
712{
714
715 if ( meta.extraOptions().contains( QStringLiteral( "classification" ) ) )
716 {
717 QgsColorRampShader colorRampShader = scalarSettings.colorRampShader();
718 QgsColorRamp *colorRamp = colorRampShader.sourceColorRamp();
719 const QStringList classes = meta.extraOptions()[QStringLiteral( "classification" )].split( QStringLiteral( ";;" ) );
720
721 QString units;
722 if ( meta.extraOptions().contains( QStringLiteral( "units" ) ) )
723 units = meta.extraOptions()[ QStringLiteral( "units" )];
724
725 QVector<QVector<double>> bounds;
726 for ( const QString &classe : classes )
727 {
728 const QStringList boundsStr = classe.split( ',' );
729 QVector<double> bound;
730 for ( const QString &boundStr : boundsStr )
731 bound.append( boundStr.toDouble() );
732 bounds.append( bound );
733 }
734
735 if ( ( bounds.count() == 1 && bounds.first().count() > 2 ) || // at least a class with two value
736 ( bounds.count() > 1 ) ) // or at least two classes
737 {
738 const QVector<double> firstClass = bounds.first();
739 const QVector<double> lastClass = bounds.last();
740 const double minValue = firstClass.count() > 1 ? ( firstClass.first() + firstClass.last() ) / 2 : firstClass.first();
741 const double maxValue = lastClass.count() > 1 ? ( lastClass.first() + lastClass.last() ) / 2 : lastClass.first();
742 const double diff = maxValue - minValue;
743 QList<QgsColorRampShader::ColorRampItem> colorRampItemlist;
744 for ( int i = 0; i < bounds.count(); ++i )
745 {
746 const QVector<double> &boundClass = bounds.at( i );
748 item.value = i + 1;
749 if ( !boundClass.isEmpty() )
750 {
751 const double scalarValue = ( boundClass.first() + boundClass.last() ) / 2;
752 item.color = colorRamp->color( ( scalarValue - minValue ) / diff );
753 if ( i != 0 && i < bounds.count() - 1 ) //The first and last labels are treated after
754 {
755 item.label = QString( ( "%1 - %2 %3" ) ).
756 arg( QString::number( boundClass.first() ) ).
757 arg( QString::number( boundClass.last() ) ).
758 arg( units );
759 }
760 }
761 colorRampItemlist.append( item );
762 }
763 //treat first and last labels
764 if ( firstClass.count() == 1 )
765 colorRampItemlist.first().label = QObject::tr( "below %1 %2" ).
766 arg( QString::number( firstClass.first() ) ).
767 arg( units );
768 else
769 {
770 colorRampItemlist.first().label = QString( ( "%1 - %2 %3" ) ).
771 arg( QString::number( firstClass.first() ) ).
772 arg( QString::number( firstClass.last() ) ).
773 arg( units );
774 }
775
776 if ( lastClass.count() == 1 )
777 colorRampItemlist.last().label = QObject::tr( "above %1 %2" ).
778 arg( QString::number( lastClass.first() ) ).
779 arg( units );
780 else
781 {
782 colorRampItemlist.last().label = QString( ( "%1 - %2 %3" ) ).
783 arg( QString::number( lastClass.first() ) ).
784 arg( QString::number( lastClass.last() ) ).
785 arg( units );
786 }
787
788 colorRampShader.setMinimumValue( 0 );
789 colorRampShader.setMaximumValue( colorRampItemlist.count() - 1 );
790 scalarSettings.setClassificationMinimumMaximum( 0, colorRampItemlist.count() - 1 );
791 colorRampShader.setColorRampItemList( colorRampItemlist );
794 }
795
796 scalarSettings.setColorRampShader( colorRampShader );
798 }
799}
800
802{
804
805 if ( mTemporalProperties->isActive() )
806 return datasetIndexAtTime( timeRange, group >= 0 ? group : mRendererSettings.activeScalarDatasetGroup() );
807 else
808 return QgsMeshDatasetIndex( group >= 0 ? group : mRendererSettings.activeScalarDatasetGroup(), mStaticScalarDatasetIndex );
809}
810
812{
814
815 if ( mTemporalProperties->isActive() )
816 return datasetIndexAtTime( timeRange, group >= 0 ? group : mRendererSettings.activeVectorDatasetGroup() );
817 else
818 return QgsMeshDatasetIndex( group >= 0 ? group : mRendererSettings.activeVectorDatasetGroup(), mStaticVectorDatasetIndex );
819}
820
821void QgsMeshLayer::fillNativeMesh()
822{
824
825 Q_ASSERT( !mNativeMesh );
826
827 mNativeMesh.reset( new QgsMesh() );
828
829 if ( !( dataProvider() && dataProvider()->isValid() ) )
830 return;
831
832 dataProvider()->populateMesh( mNativeMesh.get() );
833}
834
835void QgsMeshLayer::onDatasetGroupsAdded( const QList<int> &datasetGroupIndexes )
836{
838
839 // assign default style to new dataset groups
840 for ( int datasetGroupIndex : datasetGroupIndexes )
841 {
842 if ( !mRendererSettings.hasSettings( datasetGroupIndex ) )
843 assignDefaultStyleToDatasetGroup( datasetGroupIndex );
844 }
845
846 temporalProperties()->setIsActive( mDatasetGroupStore->hasTemporalCapabilities() );
847 emit rendererChanged();
848}
849
850void QgsMeshLayer::onMeshEdited()
851{
853
854 mRendererCache.reset( new QgsMeshLayerRendererCache() );
855 emit layerModified();
858}
859
861{
863
864 return mDatasetGroupStore->datasetGroupTreeItem();
865}
866
868{
870
871 mDatasetGroupStore->setDatasetGroupTreeItem( rootItem );
872 updateActiveDatasetGroups();
873}
874
875int QgsMeshLayer::closestEdge( const QgsPointXY &point, double searchRadius, QgsPointXY &projectedPoint ) const
876{
878
879 const QgsRectangle searchRectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
880 const QgsTriangularMesh *mesh = triangularMesh();
881 // search for the closest edge in search area from point
882 const QList<int> edgeIndexes = mesh->edgeIndexesForRectangle( searchRectangle );
883 int selectedIndex = -1;
884 if ( mesh->contains( QgsMesh::Edge ) &&
885 mDataProvider->isValid() )
886 {
887 double sqrMaxDistFromPoint = pow( searchRadius, 2 );
888 for ( const int edgeIndex : edgeIndexes )
889 {
890 const QgsMeshEdge &edge = mesh->edges().at( edgeIndex );
891 const QgsMeshVertex &vertex1 = mesh->vertices()[edge.first];
892 const QgsMeshVertex &vertex2 = mesh->vertices()[edge.second];
893 QgsPointXY projPoint;
894 const double sqrDist = point.sqrDistToSegment( vertex1.x(), vertex1.y(), vertex2.x(), vertex2.y(), projPoint, 0 );
895 if ( sqrDist < sqrMaxDistFromPoint )
896 {
897 selectedIndex = edgeIndex;
898 projectedPoint = projPoint;
899 sqrMaxDistFromPoint = sqrDist;
900 }
901 }
902 }
903
904 return selectedIndex;
905}
906
908{
910
911 return QgsMeshDatasetIndex( group >= 0 ? group : mRendererSettings.activeVectorDatasetGroup(), mStaticVectorDatasetIndex );
912}
913
914void QgsMeshLayer::setReferenceTime( const QDateTime &referenceTime )
915{
917
918 if ( auto *lDataProvider = dataProvider() )
919 mTemporalProperties->setReferenceTime( referenceTime, lDataProvider->temporalCapabilities() );
920 else
921 mTemporalProperties->setReferenceTime( referenceTime, nullptr );
922}
923
930
931QgsPointXY QgsMeshLayer::snapOnVertex( const QgsPointXY &point, double searchRadius )
932{
934
935 const QgsTriangularMesh *mesh = triangularMesh();
936 QgsPointXY exactPosition;
937 if ( !mesh )
938 return exactPosition;
939 const QgsRectangle rectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
940 double maxDistance = searchRadius;
941 //attempt to snap on edges's vertices
942 const QList<int> edgeIndexes = mesh->edgeIndexesForRectangle( rectangle );
943 for ( const int edgeIndex : edgeIndexes )
944 {
945 const QgsMeshEdge &edge = mesh->edges().at( edgeIndex );
946 const QgsMeshVertex &vertex1 = mesh->vertices()[edge.first];
947 const QgsMeshVertex &vertex2 = mesh->vertices()[edge.second];
948 const double dist1 = point.distance( vertex1 );
949 const double dist2 = point.distance( vertex2 );
950 if ( dist1 < maxDistance )
951 {
952 maxDistance = dist1;
953 exactPosition = vertex1;
954 }
955 if ( dist2 < maxDistance )
956 {
957 maxDistance = dist2;
958 exactPosition = vertex2;
959 }
960 }
961
962 //attempt to snap on face's vertices
963 const QList<int> faceIndexes = mesh->faceIndexesForRectangle( rectangle );
964 for ( const int faceIndex : faceIndexes )
965 {
966 const QgsMeshFace &face = mesh->triangles().at( faceIndex );
967 for ( int i = 0; i < 3; ++i )
968 {
969 const QgsMeshVertex &vertex = mesh->vertices()[face.at( i )];
970 const double dist = point.distance( vertex );
971 if ( dist < maxDistance )
972 {
973 maxDistance = dist;
974 exactPosition = vertex;
975 }
976 }
977 }
978
979 return exactPosition;
980}
981
982QgsPointXY QgsMeshLayer::snapOnEdge( const QgsPointXY &point, double searchRadius )
983{
985
986 QgsPointXY projectedPoint;
987 closestEdge( point, searchRadius, projectedPoint );
988
989 return projectedPoint;
990}
991
992QgsPointXY QgsMeshLayer::snapOnFace( const QgsPointXY &point, double searchRadius )
993{
995
996 const QgsTriangularMesh *mesh = triangularMesh();
997 QgsPointXY centroidPosition;
998 if ( !mesh )
999 return centroidPosition;
1000 const QgsRectangle rectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
1001 double maxDistance = std::numeric_limits<double>::max();
1002
1003 const QList<int> faceIndexes = mesh->faceIndexesForRectangle( rectangle );
1004 for ( const int faceIndex : faceIndexes )
1005 {
1006 const int nativefaceIndex = mesh->trianglesToNativeFaces().at( faceIndex );
1007 if ( nativefaceIndex < 0 && nativefaceIndex >= mesh->faceCentroids().count() )
1008 continue;
1009 const QgsPointXY centroid = mesh->faceCentroids()[nativefaceIndex];
1010 const double dist = point.distance( centroid );
1011 if ( dist < maxDistance )
1012 {
1013 maxDistance = dist;
1014 centroidPosition = centroid;
1015 }
1016 }
1017
1018 return centroidPosition;
1019}
1020
1022{
1024
1025 mDatasetGroupStore->resetDatasetGroupTreeItem();
1026 updateActiveDatasetGroups();
1027}
1028
1030{
1032
1033 if ( !mDataProvider )
1034 return QgsInterval();
1035 const int groupCount = mDataProvider->datasetGroupCount();
1036 for ( int i = 0; i < groupCount; ++i )
1037 {
1038 const qint64 timeStep = mDataProvider->temporalCapabilities()->firstTimeStepDuration( i );
1039 if ( timeStep > 0 )
1041 }
1042
1043 return QgsInterval();
1044}
1045
1047{
1049
1050 const qint64 time = mDatasetGroupStore->datasetRelativeTime( index );
1051
1052 if ( time == INVALID_MESHLAYER_TIME )
1053 return QgsInterval();
1054 else
1056}
1057
1059{
1061
1062 return mDatasetGroupStore->datasetRelativeTime( index );
1063}
1064
1065static QString detailsErrorMessage( const QgsMeshEditingError &error )
1066{
1067 QString message;
1068
1069 switch ( error.errorType )
1070 {
1072 break;
1074 message = QObject::tr( "Face %1 invalid" ).arg( error.elementIndex );
1075 break;
1077 message = QObject::tr( "Too many vertices for face %1" ).arg( error.elementIndex );
1078 break;
1080 message = QObject::tr( "Face %1 is flat" ).arg( error.elementIndex );
1081 break;
1083 message = QObject::tr( "Vertex %1 is a unique shared vertex" ).arg( error.elementIndex );
1084 break;
1086 message = QObject::tr( "Vertex %1 is invalid" ).arg( error.elementIndex );
1087 break;
1089 message = QObject::tr( "Face %1 is manifold" ).arg( error.elementIndex );
1090 break;
1091 }
1092
1093 return message;
1094}
1095
1097{
1099
1101 return startFrameEditing( transform, error, false );
1102}
1103
1105{
1107
1108 if ( !supportsEditing() )
1109 {
1110 QgsMessageLog::logMessage( QObject::tr( "Mesh layer \"%1\" not support mesh editing" ).arg( name() ) );
1111 return false;
1112 }
1113
1114 if ( mMeshEditor )
1115 {
1116 QgsMessageLog::logMessage( QObject::tr( "Mesh layer \"%1\" already in editing mode" ).arg( name() ) );
1117 return false;
1118 }
1119
1120 mSimplificationSettings.setEnabled( false );
1121
1122 updateTriangularMesh( transform );
1123
1124 mMeshEditor = new QgsMeshEditor( this );
1125
1126 if ( fixErrors )
1127 {
1128 mRendererCache.reset(); // fixing errors could lead to remove faces/vertices
1129 error = mMeshEditor->initializeWithErrorsFix();
1130 }
1131 else
1132 error = mMeshEditor->initialize();
1133
1134 if ( error.errorType != Qgis::MeshEditingErrorType::NoError )
1135 {
1136 mMeshEditor->deleteLater();
1137 mMeshEditor = nullptr;
1138
1139 QgsMessageLog::logMessage( QObject::tr( "Unable to start editing of mesh layer \"%1\": %2" ).
1140 arg( name(), detailsErrorMessage( error ) ), QString(), Qgis::MessageLevel::Critical );
1141 return false;
1142 }
1143
1144 // During editing, we don't need anymore the provider data. Mesh frame data is stored in the mesh editor.
1145 mDataProvider->close();
1146
1147 // All dataset group are removed and replace by a unique virtual dataset group that provide vertices elevation value.
1148 mExtraDatasetUri.clear();
1149 mDatasetGroupStore.reset( new QgsMeshDatasetGroupStore( this ) );
1150
1151 std::unique_ptr<QgsMeshDatasetGroup> zValueDatasetGroup( mMeshEditor->createZValueDatasetGroup() );
1152 if ( mDatasetGroupStore->addDatasetGroup( zValueDatasetGroup.get() ) )
1153 zValueDatasetGroup.release();
1154
1156
1157 connect( mMeshEditor, &QgsMeshEditor::meshEdited, this, &QgsMeshLayer::onMeshEdited );
1158
1159 emit dataChanged();
1160 emit editingStarted();
1161
1162 return true;
1163}
1164
1165bool QgsMeshLayer::commitFrameEditing( const QgsCoordinateTransform &transform, bool continueEditing )
1166{
1168
1170 QString detailsError;
1171 if ( !mMeshEditor->checkConsistency( error ) )
1172 {
1173 if ( error.errorType == Qgis::MeshEditingErrorType::NoError )
1174 detailsError = tr( "Unknown inconsistent mesh error" );
1175 }
1176 else
1177 {
1178 error = QgsTopologicalMesh::checkTopology( *mNativeMesh, mMeshEditor->maximumVerticesPerFace() );
1179 detailsError = detailsErrorMessage( error );
1180 }
1181
1182 if ( !detailsError.isEmpty() )
1183 {
1184 QgsMessageLog::logMessage( QObject::tr( "Edited mesh layer \"%1\" can't be save due to an error: %2" ).
1185 arg( name(), detailsError ), QString(), Qgis::MessageLevel::Critical );
1186 return false;
1187 }
1188
1189 stopFrameEditing( transform );
1190
1191 if ( !mDataProvider )
1192 return false;
1193
1194 const bool res = mDataProvider->saveMeshFrame( *mNativeMesh.get() );
1195
1196 if ( continueEditing )
1197 {
1198 mMeshEditor->initialize();
1199 emit layerModified();
1200 return res;
1201 }
1202
1203 mMeshEditor->deleteLater();
1204 mMeshEditor = nullptr;
1205 emit editingStopped();
1206
1207 mDataProvider->reloadData();
1208 mDataProvider->populateMesh( mNativeMesh.get() );
1209 mDatasetGroupStore.reset( new QgsMeshDatasetGroupStore( this ) );
1210 mDatasetGroupStore->setPersistentProvider( mDataProvider, QStringList() );
1212 return true;
1213}
1214
1215bool QgsMeshLayer::rollBackFrameEditing( const QgsCoordinateTransform &transform, bool continueEditing )
1216{
1218
1219 stopFrameEditing( transform );
1220
1221 if ( !mDataProvider )
1222 return false;
1223
1224 mTriangularMeshes.clear();
1225 mDataProvider->reloadData();
1226 mDataProvider->populateMesh( mNativeMesh.get() );
1227 updateTriangularMesh( transform );
1228 mRendererCache.reset( new QgsMeshLayerRendererCache() );
1230
1231 if ( continueEditing )
1232 {
1233 mMeshEditor->resetTriangularMesh( triangularMesh() );
1234 return mMeshEditor->initialize() == QgsMeshEditingError();
1235 }
1236 else
1237 {
1238 mMeshEditor->deleteLater();
1239 mMeshEditor = nullptr;
1240 emit editingStopped();
1241
1242 mDatasetGroupStore.reset( new QgsMeshDatasetGroupStore( this ) );
1243 mDatasetGroupStore->setPersistentProvider( mDataProvider, QStringList() );
1245 emit dataChanged();
1246 return true;
1247 }
1248}
1249
1251{
1253
1254 if ( !mMeshEditor )
1255 return;
1256
1257 mMeshEditor->stopEditing();
1258 mTriangularMeshes.at( 0 )->update( mNativeMesh.get(), transform );
1259 mRendererCache.reset( new QgsMeshLayerRendererCache() );
1260}
1261
1262bool QgsMeshLayer::reindex( const QgsCoordinateTransform &transform, bool renumber )
1263{
1265
1266 if ( !mMeshEditor )
1267 return false;
1268
1269 if ( !mMeshEditor->reindex( renumber ) )
1270 return false;
1271
1272 mTriangularMeshes.clear();
1273 mTriangularMeshes.emplace_back( new QgsTriangularMesh );
1274 mTriangularMeshes.at( 0 )->update( mNativeMesh.get(), transform );
1275 mRendererCache.reset( new QgsMeshLayerRendererCache() );
1276 mMeshEditor->resetTriangularMesh( mTriangularMeshes.at( 0 ).get() );
1277
1278 return true;
1279}
1280
1282{
1284
1285 return mMeshEditor;
1286}
1287
1289{
1291
1292 if ( mMeshEditor )
1293 return mMeshEditor->isModified();
1294
1295 return false;
1296}
1297
1299{
1301
1302 switch ( type )
1303 {
1305 return meshVertexCount() != 0;
1307 return meshEdgeCount() != 0;
1309 return meshFaceCount() != 0;
1310 }
1311 return false;
1312}
1313
1315{
1317
1318 if ( mMeshEditor )
1319 return mMeshEditor->validVerticesCount();
1320 else if ( mDataProvider )
1321 return mDataProvider->vertexCount();
1322 else return 0;
1323}
1324
1326{
1328
1329 if ( mMeshEditor )
1330 return mMeshEditor->validFacesCount();
1331 else if ( mDataProvider )
1332 return mDataProvider->faceCount();
1333 else return 0;
1334}
1335
1337{
1339
1340 if ( mMeshEditor )
1341 return mNativeMesh->edgeCount();
1342 else if ( mDataProvider )
1343 return mDataProvider->edgeCount();
1344 else return 0;
1345}
1346
1347void QgsMeshLayer::updateActiveDatasetGroups()
1348{
1350
1351 QgsMeshDatasetGroupTreeItem *treeItem = mDatasetGroupStore->datasetGroupTreeItem();
1352
1353 if ( !mDatasetGroupStore->datasetGroupTreeItem() )
1354 return;
1355
1357 const int oldActiveScalar = settings.activeScalarDatasetGroup();
1358 const int oldActiveVector = settings.activeVectorDatasetGroup();
1359
1360 QgsMeshDatasetGroupTreeItem *activeScalarItem =
1361 treeItem->childFromDatasetGroupIndex( oldActiveScalar );
1362
1363 if ( !activeScalarItem && treeItem->childCount() > 0 && oldActiveScalar != -1 )
1364 activeScalarItem = treeItem->child( 0 );
1365
1366 if ( activeScalarItem && !activeScalarItem->isEnabled() )
1367 {
1368 for ( int i = 0; i < treeItem->childCount(); ++i )
1369 {
1370 activeScalarItem = treeItem->child( i );
1371 if ( activeScalarItem->isEnabled() )
1372 break;
1373 else
1374 activeScalarItem = nullptr;
1375 }
1376 }
1377
1378 if ( activeScalarItem )
1379 settings.setActiveScalarDatasetGroup( activeScalarItem->datasetGroupIndex() );
1380 else
1381 settings.setActiveScalarDatasetGroup( -1 );
1382
1383 QgsMeshDatasetGroupTreeItem *activeVectorItem =
1384 treeItem->childFromDatasetGroupIndex( oldActiveVector );
1385
1386 if ( !( activeVectorItem && activeVectorItem->isEnabled() ) )
1387 settings.setActiveVectorDatasetGroup( -1 );
1388
1389 setRendererSettings( settings );
1390
1391 if ( oldActiveScalar != settings.activeScalarDatasetGroup() )
1393 if ( oldActiveVector != settings.activeVectorDatasetGroup() )
1395}
1396
1397QgsMeshRendererSettings QgsMeshLayer::accordSymbologyWithGroupName( const QgsMeshRendererSettings &settings, const QMap<QString, int> &nameToIndex )
1398{
1399 QString activeScalarName;
1400 QString activeVectorName;
1401 QgsMeshRendererSettings consistentSettings = settings;
1402 int activeScalar = consistentSettings.activeScalarDatasetGroup();
1403 int activeVector = consistentSettings.activeVectorDatasetGroup();
1404
1405 for ( auto it = nameToIndex.constBegin(); it != nameToIndex.constEnd(); ++it )
1406 {
1407 int index = it.value();
1408 const QString name = it.key() ;
1409 int globalIndex = mDatasetGroupStore->indexFromGroupName( name );
1410 if ( globalIndex >= 0 )
1411 {
1412 QgsMeshRendererScalarSettings scalarSettings = settings.scalarSettings( index );
1413 consistentSettings.setScalarSettings( globalIndex, scalarSettings );
1414 if ( settings.hasVectorSettings( it.value() ) && mDatasetGroupStore->datasetGroupMetadata( globalIndex ).isVector() )
1415 {
1416 QgsMeshRendererVectorSettings vectorSettings = settings.vectorSettings( index );
1417 consistentSettings.setVectorSettings( globalIndex, vectorSettings );
1418 }
1419 }
1420 else
1421 {
1422 consistentSettings.removeScalarSettings( index );
1423 if ( settings.hasVectorSettings( it.value() ) )
1424 consistentSettings.removeVectorSettings( index );
1425 }
1426
1427 if ( index == activeScalar )
1428 activeScalarName = name;
1429 if ( index == activeVector )
1430 activeVectorName = name;
1431 }
1432
1433 const QList<int> globalIndexes = datasetGroupsIndexes();
1434 for ( int globalIndex : globalIndexes )
1435 {
1436 const QString name = mDatasetGroupStore->groupName( globalIndex );
1437 if ( !nameToIndex.contains( name ) )
1438 {
1439 consistentSettings.setScalarSettings( globalIndex, mRendererSettings.scalarSettings( globalIndex ) );
1440 if ( mDatasetGroupStore->datasetGroupMetadata( globalIndex ).isVector() )
1441 {
1442 consistentSettings.setVectorSettings( globalIndex, mRendererSettings.vectorSettings( globalIndex ) );
1443 }
1444 }
1445 }
1446
1447 if ( !activeScalarName.isEmpty() )
1448 consistentSettings.setActiveScalarDatasetGroup( mDatasetGroupStore->indexFromGroupName( activeScalarName ) );
1449 if ( !activeVectorName.isEmpty() )
1450 consistentSettings.setActiveVectorDatasetGroup( mDatasetGroupStore->indexFromGroupName( activeVectorName ) );
1451
1452 return consistentSettings;
1453}
1454
1455void QgsMeshLayer::setDataSourcePrivate( const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, Qgis::DataProviderReadFlags flags )
1456{
1458
1459 mDataSource = dataSource;
1460 mLayerName = baseName;
1461 setProviderType( provider );
1462
1463 if ( !mDataSource.isEmpty() && !provider.isEmpty() )
1464 setDataProvider( provider, options, flags );
1465}
1466
1467QgsPointXY QgsMeshLayer::snapOnElement( QgsMesh::ElementType elementType, const QgsPointXY &point, double searchRadius )
1468{
1470
1471 switch ( elementType )
1472 {
1473 case QgsMesh::Vertex:
1474 return snapOnVertex( point, searchRadius );
1475 case QgsMesh::Edge:
1476 return snapOnEdge( point, searchRadius );
1477 case QgsMesh::Face:
1478 return snapOnFace( point, searchRadius );
1479 }
1480 return QgsPointXY(); // avoid warnings
1481}
1482
1484{
1486
1487 if ( !mNativeMesh )
1488 {
1489 // lazy loading of mesh data
1490 fillNativeMesh();
1491 }
1492
1493 QList<int> ret;
1494
1495 if ( !mNativeMesh )
1496 return ret;
1497
1498 QgsExpressionContext context;
1499 std::unique_ptr<QgsExpressionContextScope> expScope( QgsExpressionContextUtils::meshExpressionScope( QgsMesh::Vertex ) );
1500 context.appendScope( expScope.release() );
1501 context.lastScope()->setVariable( QStringLiteral( "_native_mesh" ), QVariant::fromValue( *mNativeMesh ) );
1502
1503 expression.prepare( &context );
1504
1505 for ( int i = 0; i < mNativeMesh->vertexCount(); ++i )
1506 {
1507 context.lastScope()->setVariable( QStringLiteral( "_mesh_vertex_index" ), i, false );
1508
1509 if ( expression.evaluate( &context ).toBool() )
1510 ret.append( i );
1511 }
1512
1513 return ret;
1514}
1515
1517{
1519
1520 if ( !mNativeMesh )
1521 {
1522 // lazy loading of mesh data
1523 fillNativeMesh();
1524 }
1525
1526 QList<int> ret;
1527
1528 if ( !mNativeMesh )
1529 return ret;
1530
1531 QgsExpressionContext context;
1532 std::unique_ptr<QgsExpressionContextScope> expScope( QgsExpressionContextUtils::meshExpressionScope( QgsMesh::Face ) );
1533 context.appendScope( expScope.release() );
1534 context.lastScope()->setVariable( QStringLiteral( "_native_mesh" ), QVariant::fromValue( *mNativeMesh ) );
1535
1536 expression.prepare( &context );
1537
1538 for ( int i = 0; i < mNativeMesh->faceCount(); ++i )
1539 {
1540 context.lastScope()->setVariable( QStringLiteral( "_mesh_face_index" ), i, false );
1541
1542 if ( expression.evaluate( &context ).toBool() )
1543 ret.append( i );
1544 }
1545
1546 return ret;
1547}
1548
1550{
1552
1553 return QgsMeshDatasetIndex( group >= 0 ? group : mRendererSettings.activeScalarDatasetGroup(), mStaticScalarDatasetIndex );
1554}
1555
1557{
1559
1560 const int oldActiveVector = mRendererSettings.activeVectorDatasetGroup();
1561
1562 mStaticVectorDatasetIndex = staticVectorDatasetIndex.dataset();
1564
1565 if ( oldActiveVector != mRendererSettings.activeVectorDatasetGroup() )
1567}
1568
1570{
1572
1573 const int oldActiveScalar = mRendererSettings.activeScalarDatasetGroup();
1574
1575 mStaticScalarDatasetIndex = staticScalarDatasetIndex.dataset();
1577
1578 if ( oldActiveScalar != mRendererSettings.activeScalarDatasetGroup() )
1580}
1581
1588
1590{
1592
1593 mSimplificationSettings = simplifySettings;
1594}
1595
1596static QgsColorRamp *_createDefaultColorRamp()
1597{
1598 QgsColorRamp *ramp = QgsStyle::defaultStyle()->colorRamp( QStringLiteral( "Plasma" ) );
1599 if ( ramp )
1600 return ramp;
1601
1602 // definition of "Plasma" color ramp (in case it is not available in the style for some reason)
1603 QVariantMap props;
1604 props["color1"] = "13,8,135,255";
1605 props["color2"] = "240,249,33,255";
1606 props["stops"] =
1607 "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:"
1608 "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:"
1609 "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:"
1610 "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:"
1611 "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:"
1612 "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:"
1613 "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:"
1614 "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:"
1615 "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:"
1616 "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";
1617 return QgsGradientColorRamp::create( props );
1618}
1619
1620void QgsMeshLayer::assignDefaultStyleToDatasetGroup( int groupIndex )
1621{
1623
1625 const double groupMin = metadata.minimum();
1626 const double groupMax = metadata.maximum();
1627
1628 QgsColorRampShader fcn( groupMin, groupMax, _createDefaultColorRamp() );
1629 fcn.classifyColorRamp( 5, -1, QgsRectangle(), nullptr );
1630
1631 QgsMeshRendererScalarSettings scalarSettings;
1632 scalarSettings.setClassificationMinimumMaximum( groupMin, groupMax );
1633 scalarSettings.setColorRampShader( fcn );
1634 QgsInterpolatedLineWidth edgeStrokeWidth;
1635 edgeStrokeWidth.setMinimumValue( groupMin );
1636 edgeStrokeWidth.setMaximumValue( groupMax );
1637 const QgsInterpolatedLineColor edgeStrokeColor( fcn );
1638 const QgsInterpolatedLineRenderer edgeStrokePen;
1639 scalarSettings.setEdgeStrokeWidth( edgeStrokeWidth );
1640 mRendererSettings.setScalarSettings( groupIndex, scalarSettings );
1641
1642 if ( metadata.isVector() )
1643 {
1644 QgsMeshRendererVectorSettings vectorSettings;
1645 vectorSettings.setColorRampShader( fcn );
1646 mRendererSettings.setVectorSettings( groupIndex, vectorSettings );
1647 }
1648}
1649
1651{
1653
1654 // Triangular mesh
1655 updateTriangularMesh( rendererContext.coordinateTransform() );
1656
1657 // Build overview triangular meshes if needed
1658 createSimplifiedMeshes();
1659
1660 // Cache
1661 if ( !mRendererCache )
1662 mRendererCache.reset( new QgsMeshLayerRendererCache() );
1663
1664 return new QgsMeshLayerRenderer( this, rendererContext );
1665}
1666
1673
1674void QgsMeshLayer::checkSymbologyConsistency()
1675{
1677
1678 const QList<int> groupIndexes = mDatasetGroupStore->datasetGroupIndexes();
1679 if ( !groupIndexes.contains( mRendererSettings.activeScalarDatasetGroup() ) &&
1680 mRendererSettings.activeScalarDatasetGroup() != -1 )
1681 {
1682 if ( !groupIndexes.empty() )
1683 mRendererSettings.setActiveScalarDatasetGroup( groupIndexes.first() );
1684 else
1685 mRendererSettings.setActiveScalarDatasetGroup( -1 );
1686 }
1687
1688 if ( !groupIndexes.contains( mRendererSettings.activeVectorDatasetGroup() ) &&
1689 mRendererSettings.activeVectorDatasetGroup() != -1 )
1690 {
1691 mRendererSettings.setActiveVectorDatasetGroup( -1 );
1692 }
1693}
1694
1695bool QgsMeshLayer::readSymbology( const QDomNode &node, QString &errorMessage,
1697{
1699
1700 Q_UNUSED( errorMessage )
1701 // TODO: implement categories for raster layer
1702
1703 const QDomElement elem = node.toElement();
1704
1705 readCommonStyle( elem, context, categories );
1706
1708 const QDomElement elemRendererSettings = elem.firstChildElement( "mesh-renderer-settings" );
1709 if ( !elemRendererSettings.isNull() )
1710 rendererSettings.readXml( elemRendererSettings, context );
1711
1712 QMap<QString, int> groupNameToGlobalIndex;
1713 QDomElement nameToIndexElem = elem.firstChildElement( "name-to-global-index" );
1714 while ( !nameToIndexElem.isNull() )
1715 {
1716 const QString name = nameToIndexElem.attribute( QStringLiteral( "name" ) );
1717 int globalIndex = nameToIndexElem.attribute( QStringLiteral( "global-index" ) ).toInt();
1718 groupNameToGlobalIndex.insert( name, globalIndex );
1719 nameToIndexElem = nameToIndexElem.nextSiblingElement( QStringLiteral( "name-to-global-index" ) );
1720 }
1721
1722 mRendererSettings = accordSymbologyWithGroupName( rendererSettings, groupNameToGlobalIndex );
1723
1724 checkSymbologyConsistency();
1725
1726 const QDomElement elemSimplifySettings = elem.firstChildElement( "mesh-simplify-settings" );
1727 if ( !elemSimplifySettings.isNull() )
1728 mSimplificationSettings.readXml( elemSimplifySettings, context );
1729
1730 // get and set the blend mode if it exists
1731 const QDomNode blendModeNode = node.namedItem( QStringLiteral( "blendMode" ) );
1732 if ( !blendModeNode.isNull() )
1733 {
1734 const QDomElement e = blendModeNode.toElement();
1735 setBlendMode( QgsPainting::getCompositionMode( static_cast< Qgis::BlendMode >( e.text().toInt() ) ) );
1736 }
1737
1738 // read labeling definition
1739 if ( categories.testFlag( Labeling ) )
1740 {
1741 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Labeling" ) );
1742
1743 QDomElement labelingElement = node.firstChildElement( QStringLiteral( "labeling" ) );
1744 if ( !labelingElement.isNull() )
1745 {
1747 mLabelsEnabled = node.toElement().attribute( QStringLiteral( "labelsEnabled" ), QStringLiteral( "0" ) ).toInt();
1749 }
1750 }
1751
1752 // get and set the layer transparency
1753 if ( categories.testFlag( Rendering ) )
1754 {
1755 const QDomNode layerOpacityNode = node.namedItem( QStringLiteral( "layerOpacity" ) );
1756 if ( !layerOpacityNode.isNull() )
1757 {
1758 const QDomElement e = layerOpacityNode.toElement();
1759 setOpacity( e.text().toDouble() );
1760 }
1761 }
1762
1763 return true;
1764}
1765
1766bool QgsMeshLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage,
1767 const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1768{
1770
1771 Q_UNUSED( errorMessage )
1772 // TODO: implement categories for raster layer
1773
1774 QDomElement elem = node.toElement();
1775
1776 writeCommonStyle( elem, doc, context, categories );
1777
1778 const QDomElement elemRendererSettings = mRendererSettings.writeXml( doc, context );
1779 elem.appendChild( elemRendererSettings );
1780
1781 const QList<int> groupIndexes = datasetGroupsIndexes();
1782 // we store the relation between name and indexes to be able to retrieve the consistency between name and symbology
1783 for ( int index : groupIndexes )
1784 {
1785 QDomElement elemNameToIndex = doc.createElement( QStringLiteral( "name-to-global-index" ) );
1786 elemNameToIndex.setAttribute( QStringLiteral( "name" ), mDatasetGroupStore->groupName( index ) );
1787 elemNameToIndex.setAttribute( QStringLiteral( "global-index" ), index );
1788 elem.appendChild( elemNameToIndex );
1789 }
1790
1791 const QDomElement elemSimplifySettings = mSimplificationSettings.writeXml( doc, context );
1792 elem.appendChild( elemSimplifySettings );
1793
1794 // add blend mode node
1795 QDomElement blendModeElement = doc.createElement( QStringLiteral( "blendMode" ) );
1796 const QDomText blendModeText = doc.createTextNode( QString::number( static_cast< int >( QgsPainting::getBlendModeEnum( blendMode() ) ) ) );
1797 blendModeElement.appendChild( blendModeText );
1798 node.appendChild( blendModeElement );
1799
1800 if ( categories.testFlag( Labeling ) )
1801 {
1802 if ( mLabeling )
1803 {
1804 QDomElement labelingElement = mLabeling->save( doc, context );
1805 elem.appendChild( labelingElement );
1806 }
1807 elem.setAttribute( QStringLiteral( "labelsEnabled" ), mLabelsEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
1808 }
1809
1810 // add the layer opacity
1811 if ( categories.testFlag( Rendering ) )
1812 {
1813 QDomElement layerOpacityElem = doc.createElement( QStringLiteral( "layerOpacity" ) );
1814 const QDomText layerOpacityText = doc.createTextNode( QString::number( opacity() ) );
1815 layerOpacityElem.appendChild( layerOpacityText );
1816 node.appendChild( layerOpacityElem );
1817 }
1818
1819 return true;
1820}
1821
1822bool QgsMeshLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1823{
1825
1826 return writeSymbology( node, doc, errorMessage, context, categories );
1827}
1828
1829bool QgsMeshLayer::readStyle( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
1830{
1832
1833 return readSymbology( node, errorMessage, context, categories );
1834}
1835
1836QString QgsMeshLayer::decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const
1837{
1839
1840 return QgsProviderRegistry::instance()->relativeToAbsoluteUri( provider, source, context );
1841}
1842
1843QString QgsMeshLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
1844{
1846
1848}
1849
1850bool QgsMeshLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &context )
1851{
1853
1854 QgsDebugMsgLevel( QStringLiteral( "Datasource in QgsMeshLayer::readXml: %1" ).arg( mDataSource.toLocal8Bit().data() ), 3 );
1855
1856 //process provider key
1857 const QDomNode pkeyNode = layer_node.namedItem( QStringLiteral( "provider" ) );
1858
1859 if ( pkeyNode.isNull() )
1860 {
1861 mProviderKey.clear();
1862 }
1863 else
1864 {
1865 const QDomElement pkeyElt = pkeyNode.toElement();
1866 mProviderKey = pkeyElt.text();
1867 }
1868
1870 {
1871 return false;
1872 }
1873
1874 const QgsDataProvider::ProviderOptions providerOptions;
1876
1877 const QDomElement elemExtraDatasets = layer_node.firstChildElement( QStringLiteral( "extra-datasets" ) );
1878 if ( !elemExtraDatasets.isNull() )
1879 {
1880 QDomElement elemUri = elemExtraDatasets.firstChildElement( QStringLiteral( "uri" ) );
1881 while ( !elemUri.isNull() )
1882 {
1883 const QString uri = context.pathResolver().readPath( elemUri.text() );
1884 mExtraDatasetUri.append( uri );
1885 elemUri = elemUri.nextSiblingElement( QStringLiteral( "uri" ) );
1886 }
1887 }
1888
1889 if ( pkeyNode.toElement().hasAttribute( QStringLiteral( "time-unit" ) ) )
1890 mTemporalUnit = static_cast<Qgis::TemporalUnit>( pkeyNode.toElement().attribute( QStringLiteral( "time-unit" ) ).toInt() );
1891
1892 // read dataset group store
1893 const QDomElement elemDatasetGroupsStore = layer_node.firstChildElement( QStringLiteral( "mesh-dataset-groups-store" ) );
1894 if ( elemDatasetGroupsStore.isNull() )
1896 else
1897 mDatasetGroupStore->readXml( elemDatasetGroupsStore, context );
1898
1899 setDataProvider( mProviderKey, providerOptions, flags );
1900
1901 QString errorMsg;
1902 readSymbology( layer_node, errorMsg, context );
1903
1904 if ( !mTemporalProperties->timeExtent().begin().isValid() || mTemporalProperties->alwaysLoadReferenceTimeFromSource() )
1906
1907 // read static dataset
1908 const QDomElement elemStaticDataset = layer_node.firstChildElement( QStringLiteral( "static-active-dataset" ) );
1909 if ( elemStaticDataset.hasAttribute( QStringLiteral( "scalar" ) ) )
1910 {
1911 mStaticScalarDatasetIndex = elemStaticDataset.attribute( QStringLiteral( "scalar" ) ).toInt();
1912 }
1913 if ( elemStaticDataset.hasAttribute( QStringLiteral( "vector" ) ) )
1914 {
1915 mStaticVectorDatasetIndex = elemStaticDataset.attribute( QStringLiteral( "vector" ) ).toInt();
1916 }
1917
1918 return isValid(); // should be true if read successfully
1919}
1920
1921bool QgsMeshLayer::writeXml( QDomNode &layer_node, QDomDocument &document, const QgsReadWriteContext &context ) const
1922{
1924
1925 // first get the layer element so that we can append the type attribute
1926 QDomElement mapLayerNode = layer_node.toElement();
1927
1928 if ( mapLayerNode.isNull() || ( QLatin1String( "maplayer" ) != mapLayerNode.nodeName() ) )
1929 {
1930 QgsDebugMsgLevel( QStringLiteral( "can't find <maplayer>" ), 2 );
1931 return false;
1932 }
1933
1934 mapLayerNode.setAttribute( QStringLiteral( "type" ), QgsMapLayerFactory::typeToString( Qgis::LayerType::Mesh ) );
1935
1936 // add provider node
1937 if ( mDataProvider )
1938 {
1939 QDomElement provider = document.createElement( QStringLiteral( "provider" ) );
1940 const QDomText providerText = document.createTextNode( providerType() );
1941 provider.appendChild( providerText );
1942 layer_node.appendChild( provider );
1943 provider.setAttribute( QStringLiteral( "time-unit" ), static_cast< int >( mDataProvider->temporalCapabilities()->temporalUnit() ) );
1944
1945 const QStringList extraDatasetUris = mDataProvider->extraDatasets();
1946 QDomElement elemExtraDatasets = document.createElement( QStringLiteral( "extra-datasets" ) );
1947 for ( const QString &uri : extraDatasetUris )
1948 {
1949 const QString path = context.pathResolver().writePath( uri );
1950 QDomElement elemUri = document.createElement( QStringLiteral( "uri" ) );
1951 elemUri.appendChild( document.createTextNode( path ) );
1952 elemExtraDatasets.appendChild( elemUri );
1953 }
1954 layer_node.appendChild( elemExtraDatasets );
1955 }
1956
1957 QDomElement elemStaticDataset = document.createElement( QStringLiteral( "static-active-dataset" ) );
1958 elemStaticDataset.setAttribute( QStringLiteral( "scalar" ), mStaticScalarDatasetIndex );
1959 elemStaticDataset.setAttribute( QStringLiteral( "vector" ), mStaticVectorDatasetIndex );
1960 layer_node.appendChild( elemStaticDataset );
1961
1962 // write dataset group store if not in edting mode
1963 if ( !isEditable() )
1964 layer_node.appendChild( mDatasetGroupStore->writeXml( document, context ) );
1965
1966 // renderer specific settings
1967 QString errorMsg;
1968 return writeSymbology( layer_node, document, errorMsg, context );
1969}
1970
1972{
1974
1975 if ( !mMeshEditor && mDataProvider && mDataProvider->isValid() )
1976 {
1977 mDataProvider->reloadData();
1978 mDatasetGroupStore->setPersistentProvider( mDataProvider, QStringList() ); //extra dataset are already loaded
1979
1980 //reload the mesh structure
1981 if ( !mNativeMesh )
1982 mNativeMesh.reset( new QgsMesh );
1983
1984 dataProvider()->populateMesh( mNativeMesh.get() );
1985
1986 if ( mTemporalProperties->alwaysLoadReferenceTimeFromSource() )
1987 mTemporalProperties->setDefaultsFromDataProviderTemporalCapabilities( mDataProvider->temporalCapabilities() );
1988
1989 //clear the TriangularMeshes
1990 mTriangularMeshes.clear();
1991
1992 //clear the rendererCache
1993 mRendererCache.reset( new QgsMeshLayerRendererCache() );
1994
1995 checkSymbologyConsistency();
1996
1997 emit reloaded();
1998 }
1999}
2000
2001QStringList QgsMeshLayer::subLayers() const
2002{
2004
2005 if ( mDataProvider )
2006 return mDataProvider->subLayers();
2007 else
2008 return QStringList();
2009}
2010
2012{
2014
2015 const QgsLayerMetadataFormatter htmlFormatter( metadata() );
2016 QString myMetadata = QStringLiteral( "<html>\n<body>\n" );
2017
2018 myMetadata += generalHtmlMetadata();
2019
2020 // Begin Provider section
2021 myMetadata += QStringLiteral( "<h1>" ) + tr( "Information from provider" ) + QStringLiteral( "</h1>\n<hr>\n" );
2022 myMetadata += QLatin1String( "<table class=\"list-view\">\n" );
2023
2024 // Extent
2025 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Extent" ) + QStringLiteral( "</td><td>" ) + extent().toString() + QStringLiteral( "</td></tr>\n" );
2026
2027 // feature count
2028 QLocale locale = QLocale();
2029 locale.setNumberOptions( locale.numberOptions() &= ~QLocale::NumberOption::OmitGroupSeparator );
2030
2031 if ( const QgsMeshDataProvider *provider = dataProvider() )
2032 {
2033 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
2034 + tr( "Vertex count" ) + QStringLiteral( "</td><td>" )
2035 + ( locale.toString( static_cast<qlonglong>( meshVertexCount() ) ) )
2036 + QStringLiteral( "</td></tr>\n" );
2037 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
2038 + tr( "Face count" ) + QStringLiteral( "</td><td>" )
2039 + ( locale.toString( static_cast<qlonglong>( meshFaceCount() ) ) )
2040 + QStringLiteral( "</td></tr>\n" );
2041 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
2042 + tr( "Edge count" ) + QStringLiteral( "</td><td>" )
2043 + ( locale.toString( static_cast<qlonglong>( meshEdgeCount() ) ) )
2044 + QStringLiteral( "</td></tr>\n" );
2045 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
2046 + tr( "Dataset groups count" ) + QStringLiteral( "</td><td>" )
2047 + ( locale.toString( static_cast<qlonglong>( datasetGroupCount() ) ) )
2048 + QStringLiteral( "</td></tr>\n" );
2049 myMetadata += provider->htmlMetadata();
2050 }
2051
2052 // End Provider section
2053 myMetadata += QLatin1String( "</table>\n<br><br>" );
2054
2055 // CRS
2056 myMetadata += crsHtmlMetadata();
2057
2058 // identification section
2059 myMetadata += QStringLiteral( "<h1>" ) + tr( "Identification" ) + QStringLiteral( "</h1>\n<hr>\n" );
2060 myMetadata += htmlFormatter.identificationSectionHtml( );
2061 myMetadata += QLatin1String( "<br><br>\n" );
2062
2063 // extent section
2064 myMetadata += QStringLiteral( "<h1>" ) + tr( "Extent" ) + QStringLiteral( "</h1>\n<hr>\n" );
2065 myMetadata += htmlFormatter.extentSectionHtml( isSpatial() );
2066 myMetadata += QLatin1String( "<br><br>\n" );
2067
2068 // Start the Access section
2069 myMetadata += QStringLiteral( "<h1>" ) + tr( "Access" ) + QStringLiteral( "</h1>\n<hr>\n" );
2070 myMetadata += htmlFormatter.accessSectionHtml( );
2071 myMetadata += QLatin1String( "<br><br>\n" );
2072
2073 // Start the contacts section
2074 myMetadata += QStringLiteral( "<h1>" ) + tr( "Contacts" ) + QStringLiteral( "</h1>\n<hr>\n" );
2075 myMetadata += htmlFormatter.contactsSectionHtml( );
2076 myMetadata += QLatin1String( "<br><br>\n" );
2077
2078 // Start the links section
2079 myMetadata += QStringLiteral( "<h1>" ) + tr( "Links" ) + QStringLiteral( "</h1>\n<hr>\n" );
2080 myMetadata += htmlFormatter.linksSectionHtml( );
2081 myMetadata += QLatin1String( "<br><br>\n" );
2082
2083 // Start the history section
2084 myMetadata += QStringLiteral( "<h1>" ) + tr( "History" ) + QStringLiteral( "</h1>\n<hr>\n" );
2085 myMetadata += htmlFormatter.historySectionHtml( );
2086 myMetadata += QLatin1String( "<br><br>\n" );
2087
2088 myMetadata += customPropertyHtmlMetadata();
2089
2090 myMetadata += QLatin1String( "\n</body>\n</html>\n" );
2091 return myMetadata;
2092}
2093
2095{
2097
2098 return mMeshEditor;
2099}
2100
2101bool QgsMeshLayer::setDataProvider( QString const &provider, const QgsDataProvider::ProviderOptions &options, Qgis::DataProviderReadFlags flags )
2102{
2104
2105 mDatasetGroupStore->setPersistentProvider( nullptr, QStringList() );
2106
2107 delete mDataProvider;
2108 mProviderKey = provider;
2109 const QString dataSource = mDataSource;
2110
2111 if ( mPreloadedProvider )
2112 {
2113 mDataProvider = qobject_cast< QgsMeshDataProvider * >( mPreloadedProvider.release() );
2114 }
2115 else
2116 {
2117 std::unique_ptr< QgsScopedRuntimeProfile > profile;
2118 if ( QgsApplication::profiler()->groupIsActive( QStringLiteral( "projectload" ) ) )
2119 profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Create %1 provider" ).arg( provider ), QStringLiteral( "projectload" ) );
2120
2121 mDataProvider = qobject_cast<QgsMeshDataProvider *>( QgsProviderRegistry::instance()->createProvider( provider, dataSource, options, flags ) );
2122 }
2123
2124 if ( !mDataProvider )
2125 {
2126 QgsDebugMsgLevel( QStringLiteral( "Unable to get mesh data provider" ), 2 );
2127 return false;
2128 }
2129
2130 mDataProvider->setParent( this );
2131 QgsDebugMsgLevel( QStringLiteral( "Instantiated the mesh data provider plugin" ), 2 );
2132
2133 setValid( mDataProvider->isValid() );
2134 if ( !isValid() )
2135 {
2136 QgsDebugMsgLevel( QStringLiteral( "Invalid mesh provider plugin %1" ).arg( QString( mDataSource.toUtf8() ) ), 2 );
2137 return false;
2138 }
2139
2140 if ( !mTemporalProperties->isValid() )
2141 {
2142 mTemporalProperties->setDefaultsFromDataProviderTemporalCapabilities( dataProvider()->temporalCapabilities() );
2143 }
2144
2145 mDataProvider->setTemporalUnit( mTemporalUnit );
2146
2147 mDatasetGroupStore->setPersistentProvider( mDataProvider, mExtraDatasetUri );
2148
2149 setCrs( mDataProvider->crs() );
2150
2151 if ( provider == QLatin1String( "mesh_memory" ) )
2152 {
2153 // required so that source differs between memory layers
2154 mDataSource = mDataSource + QStringLiteral( "&uid=%1" ).arg( QUuid::createUuid().toString() );
2155 }
2156
2157 // set default style if required by flags or if the dataset group does not has a style yet
2158 for ( int i = 0; i < mDataProvider->datasetGroupCount(); ++i )
2159 {
2160 int globalIndex = mDatasetGroupStore->globalDatasetGroupIndexInSource( mDataProvider, i );
2161 if ( globalIndex != -1 &&
2162 ( !mRendererSettings.hasSettings( globalIndex ) || ( flags & Qgis::DataProviderReadFlag::LoadDefaultStyle ) ) )
2163 assignDefaultStyleToDatasetGroup( globalIndex );
2164 }
2165
2166 emit rendererChanged();
2168
2169 connect( mDataProvider, &QgsMeshDataProvider::dataChanged, this, &QgsMeshLayer::dataChanged );
2170
2171 return true;
2172}
2173
2180
2187
2189{
2191
2192 return mLabelsEnabled && static_cast< bool >( mLabeling );
2193}
2194
2196{
2198
2199 mLabelsEnabled = enabled;
2200}
2201
2203{
2205
2206 if ( mLabeling == labeling )
2207 return;
2208
2209 delete mLabeling;
2210 mLabeling = labeling;
2212}
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:4586
TemporalUnit
Temporal units.
Definition qgis.h:4815
@ 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 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.
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 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...
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.
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...
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.
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.
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.
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.