QGIS API Documentation 3.37.0-Master (684a802617f)
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"
33#include "qgsmeshlayerutils.h"
34#include "qgsmeshtimesettings.h"
35#include "qgspainting.h"
36#include "qgsproviderregistry.h"
37#include "qgsreadwritecontext.h"
38#include "qgsstyle.h"
39#include "qgstriangularmesh.h"
40#include "qgsmesh3daveraging.h"
42#include "qgsmesheditor.h"
43#include "qgsmessagelog.h"
47#include "qgsthreadingutils.h"
48#include "qgsapplication.h"
49#include "qgsruntimeprofiler.h"
51
52QgsMeshLayer::QgsMeshLayer( const QString &meshLayerPath,
53 const QString &baseName,
54 const QString &providerKey,
55 const QgsMeshLayer::LayerOptions &options )
56 : QgsMapLayer( Qgis::LayerType::Mesh, baseName, meshLayerPath )
57 , mDatasetGroupStore( new QgsMeshDatasetGroupStore( this ) )
58 , mTemporalProperties( new QgsMeshLayerTemporalProperties( this ) )
59 , mElevationProperties( new QgsMeshLayerElevationProperties( this ) )
60{
62
63 const QgsDataProvider::ProviderOptions providerOptions { options.transformContext };
65 if ( options.loadDefaultStyle )
66 {
68 }
69 QgsMeshLayer::setDataSourcePrivate( meshLayerPath, baseName, providerKey, providerOptions, flags );
72
73 if ( isValid() && options.loadDefaultStyle )
74 {
75 bool result = false;
76 loadDefaultStyle( result );
77 }
78
79 connect( mDatasetGroupStore.get(), &QgsMeshDatasetGroupStore::datasetGroupsAdded, this, &QgsMeshLayer::onDatasetGroupsAdded );
80}
81
82void QgsMeshLayer::createSimplifiedMeshes()
83{
85
86 if ( mSimplificationSettings.isEnabled() && !hasSimplifiedMeshes() )
87 {
88 const double reductionFactor = mSimplificationSettings.reductionFactor();
89
90 QVector<QgsTriangularMesh *> simplifyMeshes =
91 mTriangularMeshes[0]->simplifyMesh( reductionFactor );
92
93 for ( int i = 0; i < simplifyMeshes.count() ; ++i )
94 {
95 mTriangularMeshes.emplace_back( simplifyMeshes[i] );
96 }
97 }
98}
99
100bool QgsMeshLayer::hasSimplifiedMeshes() const
101{
103
104 //First mesh is the base mesh, so if size>1, there is no simplified meshes
105 return ( mTriangularMeshes.size() > 1 );
106}
107
109{
110 delete mLabeling;
111 delete mDataProvider;
112}
113
120
122{
124
125 return mDataProvider;
126}
127
129{
131
133 if ( mDataProvider )
134 {
135 options.transformContext = mDataProvider->transformContext();
136 }
137 QgsMeshLayer *layer = new QgsMeshLayer( source(), name(), mProviderKey, options );
138 QgsMapLayer::clone( layer );
139
140 layer->mElevationProperties = mElevationProperties->clone();
141 layer->mElevationProperties->setParent( layer );
142
143 if ( auto *lLabeling = labeling() )
144 {
145 layer->setLabeling( lLabeling->clone() );
146 }
148
149 return layer;
150}
151
153{
155
156 if ( mMeshEditor )
157 return mMeshEditor->extent();
158
159 if ( mDataProvider )
160 return mDataProvider->extent();
161 else
162 {
163 QgsRectangle rec;
164 rec.setNull();
165 return rec;
166 }
167}
168
175
177{
179
180 if ( !mDataProvider )
181 return false;
182
183 if ( mMeshEditor )
184 return true;
185
186 const QgsMeshDriverMetadata driverMetadata = mDataProvider->driverMetadata();
187
189}
190
191QString QgsMeshLayer::loadDefaultStyle( bool &resultFlag )
192{
194
195 const QList<int> groupsList = datasetGroupsIndexes();
196
197 for ( const int index : groupsList )
198 assignDefaultStyleToDatasetGroup( index );
199
200
201 QgsMeshRendererMeshSettings meshSettings;
202 if ( !groupsList.isEmpty() )
203 {
204 // Show data from the first dataset group
205 mRendererSettings.setActiveScalarDatasetGroup( 0 );
206 // If the first dataset group has nan min/max, display the mesh to avoid nothing displayed
208 if ( meta.maximum() == std::numeric_limits<double>::quiet_NaN() &&
209 meta.minimum() == std::numeric_limits<double>::quiet_NaN() )
210 meshSettings.setEnabled( true );
211 }
212 else
213 {
214 // show at least the mesh by default
215 meshSettings.setEnabled( true );
216 }
217
218 mRendererSettings.setNativeMeshSettings( meshSettings );
219
220 for ( const int i : groupsList )
221 {
222 assignDefaultStyleToDatasetGroup( i );
223
224 // Sets default resample method for scalar dataset
226 QgsMeshRendererScalarSettings scalarSettings = mRendererSettings.scalarSettings( i );
227 switch ( meta.dataType() )
228 {
230 case QgsMeshDatasetGroupMetadata::DataOnVolumes: // data on volumes are averaged to 2D data on faces
232 break;
235 break;
237 break;
238 }
239
240 //override color ramp if the values in the dataset group are classified
241 applyClassificationOnScalarSettings( meta, scalarSettings );
242
243 mRendererSettings.setScalarSettings( i, scalarSettings );
244 }
245
246 if ( !groupsList.isEmpty() )
247 {
248 emit rendererChanged();
250 }
251
252 return QgsMapLayer::loadDefaultStyle( resultFlag );
253}
254
255bool QgsMeshLayer::addDatasets( const QString &path, const QDateTime &defaultReferenceTime )
256{
258
260 const bool isTemporalBefore = temporalCapabilities->hasTemporalCapabilities();
261 if ( mDatasetGroupStore->addPersistentDatasets( path ) )
262 {
263 mExtraDatasetUri.append( path );
264 QgsMeshLayerTemporalProperties *temporalProperties = qobject_cast< QgsMeshLayerTemporalProperties * >( mTemporalProperties );
265 if ( !isTemporalBefore && temporalCapabilities->hasTemporalCapabilities() )
266 {
268 temporalCapabilities );
269
270 if ( ! temporalProperties->referenceTime().isValid() )
271 {
272 QDateTime referenceTime = defaultReferenceTime;
273 if ( !defaultReferenceTime.isValid() ) // If project reference time is invalid, use current date
274 referenceTime = QDateTime( QDate::currentDate(), QTime( 0, 0, 0 ), Qt::UTC );
275 temporalProperties->setReferenceTime( referenceTime, temporalCapabilities );
276 }
277
278 mTemporalProperties->setIsActive( true );
279 }
280 emit dataSourceChanged();
281 return true;
282 }
283
284 return false;
285}
286
288{
290
291 if ( mDatasetGroupStore->addDatasetGroup( datasetGroup ) )
292 {
293 emit dataChanged();
294 return true;
295 }
296 return false;
297}
298
299bool QgsMeshLayer::saveDataset( const QString &path, int datasetGroupIndex, QString driver )
300{
302
303 return mDatasetGroupStore->saveDatasetGroup( path, datasetGroupIndex, driver );
304}
305
307{
309
310 return mNativeMesh.get();
311}
312
314{
316
317 return mNativeMesh.get();
318}
319
320QgsTriangularMesh *QgsMeshLayer::triangularMesh( double minimumTriangleSize ) const
321{
323
324 for ( const std::unique_ptr<QgsTriangularMesh> &lod : mTriangularMeshes )
325 {
326 if ( lod && lod->averageTriangleSize() > minimumTriangleSize )
327 return lod.get();
328 }
329
330 if ( !mTriangularMeshes.empty() )
331 return mTriangularMeshes.back().get();
332 else
333 return nullptr;
334}
335
337{
339
340 return mTriangularMeshes.size();
341}
342
344{
346
347 if ( mTriangularMeshes.empty() )
348 return nullptr;
349 if ( lodIndex < 0 )
350 return mTriangularMeshes.front().get();
351
352 if ( lodIndex >= int( mTriangularMeshes.size() ) )
353 return mTriangularMeshes.back().get();
354
355 return mTriangularMeshes.at( lodIndex ).get();
356}
357
359{
361
362 // Native mesh
363 if ( !mNativeMesh )
364 {
365 // lazy loading of mesh data
366 fillNativeMesh();
367 }
368
369 // Triangular mesh
370 if ( mTriangularMeshes.empty() )
371 {
372 QgsTriangularMesh *baseMesh = new QgsTriangularMesh;
373 mTriangularMeshes.emplace_back( baseMesh );
374 }
375
376 if ( mTriangularMeshes[0].get()->update( mNativeMesh.get(), transform ) )
377 mTriangularMeshes.resize( 1 ); //if the base triangular mesh is effectivly updated, remove simplified meshes
378
379 createSimplifiedMeshes();
380}
381
382QgsMeshLayerRendererCache *QgsMeshLayer::rendererCache()
383{
385
386 return mRendererCache.get();
387}
388
395
397{
399
400 const int oldActiveScalar = mRendererSettings.activeScalarDatasetGroup();
401 const int oldActiveVector = mRendererSettings.activeVectorDatasetGroup();
402 mRendererSettings = settings;
403
404 if ( oldActiveScalar != mRendererSettings.activeScalarDatasetGroup() )
406
407 if ( oldActiveVector != mRendererSettings.activeVectorDatasetGroup() )
409
410 emit rendererChanged();
412}
413
420
422{
424
425 mTimeSettings = settings;
426 emit timeSettingsChanged();
427}
428
429QString QgsMeshLayer::formatTime( double hours )
430{
432
433 if ( dataProvider() && dataProvider()->temporalCapabilities()->hasReferenceTime() )
434 return QgsMeshLayerUtils::formatTime( hours, mTemporalProperties->referenceTime(), mTimeSettings );
435 else
436 return QgsMeshLayerUtils::formatTime( hours, QDateTime(), mTimeSettings );
437}
438
440{
442
443 return mDatasetGroupStore->datasetGroupCount();
444}
445
447{
449
450 return mDatasetGroupStore->extraDatasetGroupCount();
451}
452
454{
456
457 return mDatasetGroupStore->datasetGroupIndexes();
458}
459
461{
463
464 return mDatasetGroupStore->enabledDatasetGroupIndexes();
465}
466
468{
470
471 return mDatasetGroupStore->datasetGroupMetadata( index );
472}
473
475{
477
478 return mDatasetGroupStore->datasetCount( index.group() );
479}
480
482{
484
485 return mDatasetGroupStore->datasetMetadata( index );
486}
487
489{
491
492 return mDatasetGroupStore->datasetValue( index, valueIndex );
493}
494
495QgsMeshDataBlock QgsMeshLayer::datasetValues( const QgsMeshDatasetIndex &index, int valueIndex, int count ) const
496{
498
499 return mDatasetGroupStore->datasetValues( index, valueIndex, count );
500}
501
502QgsMesh3DDataBlock QgsMeshLayer::dataset3dValues( const QgsMeshDatasetIndex &index, int faceIndex, int count ) const
503{
505
506 return mDatasetGroupStore->dataset3dValues( index, faceIndex, count );
507}
508
509QgsMeshDataBlock QgsMeshLayer::areFacesActive( const QgsMeshDatasetIndex &index, int faceIndex, int count ) const
510{
512
513 return mDatasetGroupStore->areFacesActive( index, faceIndex, count );
514}
515
516bool QgsMeshLayer::isFaceActive( const QgsMeshDatasetIndex &index, int faceIndex ) const
517{
519
520 return mDatasetGroupStore->isFaceActive( index, faceIndex );
521}
522
523QgsMeshDatasetValue QgsMeshLayer::datasetValue( const QgsMeshDatasetIndex &index, const QgsPointXY &point, double searchRadius ) const
524{
526
528 const QgsTriangularMesh *mesh = triangularMesh();
529
530 if ( mesh && index.isValid() )
531 {
533 {
534 const QgsRectangle searchRectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
535 return dataset1dValue( index, point, searchRadius );
536 }
537 const int faceIndex = mesh->faceIndexForPoint_v2( point ) ;
538 if ( faceIndex >= 0 )
539 {
540 const int nativeFaceIndex = mesh->trianglesToNativeFaces().at( faceIndex );
542 if ( isFaceActive( index, nativeFaceIndex ) )
543 {
544 switch ( dataType )
545 {
547 {
548 value = datasetValue( index, nativeFaceIndex );
549 }
550 break;
551
553 {
554 const QgsMeshFace &face = mesh->triangles()[faceIndex];
555 const int v1 = face[0], v2 = face[1], v3 = face[2];
556 const QgsPoint p1 = mesh->vertices()[v1], p2 = mesh->vertices()[v2], p3 = mesh->vertices()[v3];
557 const QgsMeshDatasetValue val1 = datasetValue( index, v1 );
558 const QgsMeshDatasetValue val2 = datasetValue( index, v2 );
559 const QgsMeshDatasetValue val3 = datasetValue( index, v3 );
560 const double x = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.x(), val2.x(), val3.x(), point );
561 double y = std::numeric_limits<double>::quiet_NaN();
562 const bool isVector = datasetGroupMetadata( index ).isVector();
563 if ( isVector )
564 y = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.y(), val2.y(), val3.y(), point );
565
566 value = QgsMeshDatasetValue( x, y );
567 }
568 break;
569
571 {
572 const QgsMesh3DAveragingMethod *avgMethod = mRendererSettings.averagingMethod();
573 if ( avgMethod )
574 {
575 const QgsMesh3DDataBlock block3d = dataset3dValues( index, nativeFaceIndex, 1 );
576 const QgsMeshDataBlock block2d = avgMethod->calculate( block3d );
577 if ( block2d.isValid() )
578 {
579 value = block2d.value( 0 );
580 }
581 }
582 }
583 break;
584
585 default:
586 break;
587 }
588 }
589 }
590 }
591
592 return value;
593}
594
596{
598
599 QgsMesh3DDataBlock block3d;
600
601 const QgsTriangularMesh *baseTriangularMesh = triangularMesh();
602
603 if ( baseTriangularMesh && dataProvider() && dataProvider()->isValid() && index.isValid() )
604 {
607 {
608 const int faceIndex = baseTriangularMesh->faceIndexForPoint_v2( point );
609 if ( faceIndex >= 0 )
610 {
611 const int nativeFaceIndex = baseTriangularMesh->trianglesToNativeFaces().at( faceIndex );
612 block3d = dataset3dValues( index, nativeFaceIndex, 1 );
613 }
614 }
615 }
616 return block3d;
617}
618
619QgsMeshDatasetValue QgsMeshLayer::dataset1dValue( const QgsMeshDatasetIndex &index, const QgsPointXY &point, double searchRadius ) const
620{
622
624 QgsPointXY projectedPoint;
625 const int selectedIndex = closestEdge( point, searchRadius, projectedPoint );
626 const QgsTriangularMesh *mesh = triangularMesh();
627 if ( selectedIndex >= 0 )
628 {
630 switch ( dataType )
631 {
633 {
634 value = datasetValue( index, selectedIndex );
635 }
636 break;
637
639 {
640 const QgsMeshEdge &edge = mesh->edges()[selectedIndex];
641 const int v1 = edge.first, v2 = edge.second;
642 const QgsPoint p1 = mesh->vertices()[v1], p2 = mesh->vertices()[v2];
643 const QgsMeshDatasetValue val1 = datasetValue( index, v1 );
644 const QgsMeshDatasetValue val2 = datasetValue( index, v2 );
645 const double edgeLength = p1.distance( p2 );
646 const double dist1 = p1.distance( projectedPoint.x(), projectedPoint.y() );
647 value = QgsMeshLayerUtils::interpolateFromVerticesData( dist1 / edgeLength, val1, val2 );
648 }
649 break;
650 default:
651 break;
652 }
653 }
654
655 return value;
656}
657
659{
661
662 if ( mDataProvider )
663 mDataProvider->setTransformContext( transformContext );
665}
666
667QgsMeshDatasetIndex QgsMeshLayer::datasetIndexAtTime( const QgsDateTimeRange &timeRange, int datasetGroupIndex ) const
668{
670
671 if ( ! mTemporalProperties->isActive() )
672 return QgsMeshDatasetIndex( datasetGroupIndex, -1 );
673
674 const QDateTime layerReferenceTime = mTemporalProperties->referenceTime();
675 QDateTime utcTime = timeRange.begin();
676 if ( utcTime.timeSpec() != Qt::UTC )
677 utcTime.setTimeSpec( Qt::UTC );
678 const qint64 startTime = layerReferenceTime.msecsTo( utcTime );
679
680 return mDatasetGroupStore->datasetIndexAtTime( startTime, datasetGroupIndex, mTemporalProperties->matchingMethod() );
681}
682
683QgsMeshDatasetIndex QgsMeshLayer::datasetIndexAtRelativeTime( const QgsInterval &relativeTime, int datasetGroupIndex ) const
684{
686
687 return mDatasetGroupStore->datasetIndexAtTime( relativeTime.seconds() * 1000, datasetGroupIndex, mTemporalProperties->matchingMethod() );
688}
689
690QList<QgsMeshDatasetIndex> QgsMeshLayer::datasetIndexInRelativeTimeInterval( const QgsInterval &startRelativeTime, const QgsInterval &endRelativeTime, int datasetGroupIndex ) const
691{
693
694 qint64 usedRelativeTime1 = startRelativeTime.seconds() * 1000;
695 qint64 usedRelativeTime2 = endRelativeTime.seconds() * 1000;
696
697 //adjust relative time if layer reference time is different from provider reference time
698 if ( mTemporalProperties->referenceTime().isValid() &&
699 mDataProvider &&
700 mDataProvider->isValid() &&
701 mTemporalProperties->referenceTime() != mDataProvider->temporalCapabilities()->referenceTime() )
702 {
703 usedRelativeTime1 = usedRelativeTime1 + mTemporalProperties->referenceTime().msecsTo( mDataProvider->temporalCapabilities()->referenceTime() );
704 usedRelativeTime2 = usedRelativeTime2 + mTemporalProperties->referenceTime().msecsTo( mDataProvider->temporalCapabilities()->referenceTime() );
705 }
706
707 return mDatasetGroupStore->datasetIndexInTimeInterval( usedRelativeTime1, usedRelativeTime2, datasetGroupIndex );
708}
709
710void QgsMeshLayer::applyClassificationOnScalarSettings( const QgsMeshDatasetGroupMetadata &meta, QgsMeshRendererScalarSettings &scalarSettings ) const
711{
713
714 if ( meta.extraOptions().contains( QStringLiteral( "classification" ) ) )
715 {
716 QgsColorRampShader colorRampShader = scalarSettings.colorRampShader();
717 QgsColorRamp *colorRamp = colorRampShader.sourceColorRamp();
718 const QStringList classes = meta.extraOptions()[QStringLiteral( "classification" )].split( QStringLiteral( ";;" ) );
719
720 QString units;
721 if ( meta.extraOptions().contains( QStringLiteral( "units" ) ) )
722 units = meta.extraOptions()[ QStringLiteral( "units" )];
723
724 QVector<QVector<double>> bounds;
725 for ( const QString &classe : classes )
726 {
727 const QStringList boundsStr = classe.split( ',' );
728 QVector<double> bound;
729 for ( const QString &boundStr : boundsStr )
730 bound.append( boundStr.toDouble() );
731 bounds.append( bound );
732 }
733
734 if ( ( bounds.count() == 1 && bounds.first().count() > 2 ) || // at least a class with two value
735 ( bounds.count() > 1 ) ) // or at least two classes
736 {
737 const QVector<double> firstClass = bounds.first();
738 const QVector<double> lastClass = bounds.last();
739 const double minValue = firstClass.count() > 1 ? ( firstClass.first() + firstClass.last() ) / 2 : firstClass.first();
740 const double maxValue = lastClass.count() > 1 ? ( lastClass.first() + lastClass.last() ) / 2 : lastClass.first();
741 const double diff = maxValue - minValue;
742 QList<QgsColorRampShader::ColorRampItem> colorRampItemlist;
743 for ( int i = 0; i < bounds.count(); ++i )
744 {
745 const QVector<double> &boundClass = bounds.at( i );
747 item.value = i + 1;
748 if ( !boundClass.isEmpty() )
749 {
750 const double scalarValue = ( boundClass.first() + boundClass.last() ) / 2;
751 item.color = colorRamp->color( ( scalarValue - minValue ) / diff );
752 if ( i != 0 && i < bounds.count() - 1 ) //The first and last labels are treated after
753 {
754 item.label = QString( ( "%1 - %2 %3" ) ).
755 arg( QString::number( boundClass.first() ) ).
756 arg( QString::number( boundClass.last() ) ).
757 arg( units );
758 }
759 }
760 colorRampItemlist.append( item );
761 }
762 //treat first and last labels
763 if ( firstClass.count() == 1 )
764 colorRampItemlist.first().label = QObject::tr( "below %1 %2" ).
765 arg( QString::number( firstClass.first() ) ).
766 arg( units );
767 else
768 {
769 colorRampItemlist.first().label = QString( ( "%1 - %2 %3" ) ).
770 arg( QString::number( firstClass.first() ) ).
771 arg( QString::number( firstClass.last() ) ).
772 arg( units );
773 }
774
775 if ( lastClass.count() == 1 )
776 colorRampItemlist.last().label = QObject::tr( "above %1 %2" ).
777 arg( QString::number( lastClass.first() ) ).
778 arg( units );
779 else
780 {
781 colorRampItemlist.last().label = QString( ( "%1 - %2 %3" ) ).
782 arg( QString::number( lastClass.first() ) ).
783 arg( QString::number( lastClass.last() ) ).
784 arg( units );
785 }
786
787 colorRampShader.setMinimumValue( 0 );
788 colorRampShader.setMaximumValue( colorRampItemlist.count() - 1 );
789 scalarSettings.setClassificationMinimumMaximum( 0, colorRampItemlist.count() - 1 );
790 colorRampShader.setColorRampItemList( colorRampItemlist );
793 }
794
795 scalarSettings.setColorRampShader( colorRampShader );
797 }
798}
799
801{
803
804 if ( mTemporalProperties->isActive() )
805 return datasetIndexAtTime( timeRange, group >= 0 ? group : mRendererSettings.activeScalarDatasetGroup() );
806 else
807 return QgsMeshDatasetIndex( group >= 0 ? group : mRendererSettings.activeScalarDatasetGroup(), mStaticScalarDatasetIndex );
808}
809
811{
813
814 if ( mTemporalProperties->isActive() )
815 return datasetIndexAtTime( timeRange, group >= 0 ? group : mRendererSettings.activeVectorDatasetGroup() );
816 else
817 return QgsMeshDatasetIndex( group >= 0 ? group : mRendererSettings.activeVectorDatasetGroup(), mStaticVectorDatasetIndex );
818}
819
820void QgsMeshLayer::fillNativeMesh()
821{
823
824 Q_ASSERT( !mNativeMesh );
825
826 mNativeMesh.reset( new QgsMesh() );
827
828 if ( !( dataProvider() && dataProvider()->isValid() ) )
829 return;
830
831 dataProvider()->populateMesh( mNativeMesh.get() );
832}
833
834void QgsMeshLayer::onDatasetGroupsAdded( const QList<int> &datasetGroupIndexes )
835{
837
838 // assign default style to new dataset groups
839 for ( int datasetGroupIndex : datasetGroupIndexes )
840 {
841 if ( !mRendererSettings.hasSettings( datasetGroupIndex ) )
842 assignDefaultStyleToDatasetGroup( datasetGroupIndex );
843 }
844
845 temporalProperties()->setIsActive( mDatasetGroupStore->hasTemporalCapabilities() );
846 emit rendererChanged();
847}
848
849void QgsMeshLayer::onMeshEdited()
850{
852
853 mRendererCache.reset( new QgsMeshLayerRendererCache() );
854 emit layerModified();
857}
858
860{
862
863 return mDatasetGroupStore->datasetGroupTreeItem();
864}
865
867{
869
870 mDatasetGroupStore->setDatasetGroupTreeItem( rootItem );
871 updateActiveDatasetGroups();
872}
873
874int QgsMeshLayer::closestEdge( const QgsPointXY &point, double searchRadius, QgsPointXY &projectedPoint ) const
875{
877
878 const QgsRectangle searchRectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
879 const QgsTriangularMesh *mesh = triangularMesh();
880 // search for the closest edge in search area from point
881 const QList<int> edgeIndexes = mesh->edgeIndexesForRectangle( searchRectangle );
882 int selectedIndex = -1;
883 if ( mesh->contains( QgsMesh::Edge ) &&
884 mDataProvider->isValid() )
885 {
886 double sqrMaxDistFromPoint = pow( searchRadius, 2 );
887 for ( const int edgeIndex : edgeIndexes )
888 {
889 const QgsMeshEdge &edge = mesh->edges().at( edgeIndex );
890 const QgsMeshVertex &vertex1 = mesh->vertices()[edge.first];
891 const QgsMeshVertex &vertex2 = mesh->vertices()[edge.second];
892 QgsPointXY projPoint;
893 const double sqrDist = point.sqrDistToSegment( vertex1.x(), vertex1.y(), vertex2.x(), vertex2.y(), projPoint, 0 );
894 if ( sqrDist < sqrMaxDistFromPoint )
895 {
896 selectedIndex = edgeIndex;
897 projectedPoint = projPoint;
898 sqrMaxDistFromPoint = sqrDist;
899 }
900 }
901 }
902
903 return selectedIndex;
904}
905
907{
909
910 return QgsMeshDatasetIndex( group >= 0 ? group : mRendererSettings.activeVectorDatasetGroup(), mStaticVectorDatasetIndex );
911}
912
913void QgsMeshLayer::setReferenceTime( const QDateTime &referenceTime )
914{
916
917 if ( auto *lDataProvider = dataProvider() )
918 mTemporalProperties->setReferenceTime( referenceTime, lDataProvider->temporalCapabilities() );
919 else
920 mTemporalProperties->setReferenceTime( referenceTime, nullptr );
921}
922
929
930QgsPointXY QgsMeshLayer::snapOnVertex( const QgsPointXY &point, double searchRadius )
931{
933
934 const QgsTriangularMesh *mesh = triangularMesh();
935 QgsPointXY exactPosition;
936 if ( !mesh )
937 return exactPosition;
938 const QgsRectangle rectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
939 double maxDistance = searchRadius;
940 //attempt to snap on edges's vertices
941 const QList<int> edgeIndexes = mesh->edgeIndexesForRectangle( rectangle );
942 for ( const int edgeIndex : edgeIndexes )
943 {
944 const QgsMeshEdge &edge = mesh->edges().at( edgeIndex );
945 const QgsMeshVertex &vertex1 = mesh->vertices()[edge.first];
946 const QgsMeshVertex &vertex2 = mesh->vertices()[edge.second];
947 const double dist1 = point.distance( vertex1 );
948 const double dist2 = point.distance( vertex2 );
949 if ( dist1 < maxDistance )
950 {
951 maxDistance = dist1;
952 exactPosition = vertex1;
953 }
954 if ( dist2 < maxDistance )
955 {
956 maxDistance = dist2;
957 exactPosition = vertex2;
958 }
959 }
960
961 //attempt to snap on face's vertices
962 const QList<int> faceIndexes = mesh->faceIndexesForRectangle( rectangle );
963 for ( const int faceIndex : faceIndexes )
964 {
965 const QgsMeshFace &face = mesh->triangles().at( faceIndex );
966 for ( int i = 0; i < 3; ++i )
967 {
968 const QgsMeshVertex &vertex = mesh->vertices()[face.at( i )];
969 const double dist = point.distance( vertex );
970 if ( dist < maxDistance )
971 {
972 maxDistance = dist;
973 exactPosition = vertex;
974 }
975 }
976 }
977
978 return exactPosition;
979}
980
981QgsPointXY QgsMeshLayer::snapOnEdge( const QgsPointXY &point, double searchRadius )
982{
984
985 QgsPointXY projectedPoint;
986 closestEdge( point, searchRadius, projectedPoint );
987
988 return projectedPoint;
989}
990
991QgsPointXY QgsMeshLayer::snapOnFace( const QgsPointXY &point, double searchRadius )
992{
994
995 const QgsTriangularMesh *mesh = triangularMesh();
996 QgsPointXY centroidPosition;
997 if ( !mesh )
998 return centroidPosition;
999 const QgsRectangle rectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
1000 double maxDistance = std::numeric_limits<double>::max();
1001
1002 const QList<int> faceIndexes = mesh->faceIndexesForRectangle( rectangle );
1003 for ( const int faceIndex : faceIndexes )
1004 {
1005 const int nativefaceIndex = mesh->trianglesToNativeFaces().at( faceIndex );
1006 if ( nativefaceIndex < 0 && nativefaceIndex >= mesh->faceCentroids().count() )
1007 continue;
1008 const QgsPointXY centroid = mesh->faceCentroids()[nativefaceIndex];
1009 const double dist = point.distance( centroid );
1010 if ( dist < maxDistance )
1011 {
1012 maxDistance = dist;
1013 centroidPosition = centroid;
1014 }
1015 }
1016
1017 return centroidPosition;
1018}
1019
1021{
1023
1024 mDatasetGroupStore->resetDatasetGroupTreeItem();
1025 updateActiveDatasetGroups();
1026}
1027
1029{
1031
1032 if ( !mDataProvider )
1033 return QgsInterval();
1034 const int groupCount = mDataProvider->datasetGroupCount();
1035 for ( int i = 0; i < groupCount; ++i )
1036 {
1037 const qint64 timeStep = mDataProvider->temporalCapabilities()->firstTimeStepDuration( i );
1038 if ( timeStep > 0 )
1040 }
1041
1042 return QgsInterval();
1043}
1044
1046{
1048
1049 const qint64 time = mDatasetGroupStore->datasetRelativeTime( index );
1050
1051 if ( time == INVALID_MESHLAYER_TIME )
1052 return QgsInterval();
1053 else
1055}
1056
1058{
1060
1061 return mDatasetGroupStore->datasetRelativeTime( index );
1062}
1063
1064static QString detailsErrorMessage( const QgsMeshEditingError &error )
1065{
1066 QString message;
1067
1068 switch ( error.errorType )
1069 {
1071 break;
1073 message = QObject::tr( "Face %1 invalid" ).arg( error.elementIndex );
1074 break;
1076 message = QObject::tr( "Too many vertices for face %1" ).arg( error.elementIndex );
1077 break;
1079 message = QObject::tr( "Face %1 is flat" ).arg( error.elementIndex );
1080 break;
1082 message = QObject::tr( "Vertex %1 is a unique shared vertex" ).arg( error.elementIndex );
1083 break;
1085 message = QObject::tr( "Vertex %1 is invalid" ).arg( error.elementIndex );
1086 break;
1088 message = QObject::tr( "Face %1 is manifold" ).arg( error.elementIndex );
1089 break;
1090 }
1091
1092 return message;
1093}
1094
1096{
1098
1100 return startFrameEditing( transform, error, false );
1101}
1102
1104{
1106
1107 if ( !supportsEditing() )
1108 {
1109 QgsMessageLog::logMessage( QObject::tr( "Mesh layer \"%1\" not support mesh editing" ).arg( name() ) );
1110 return false;
1111 }
1112
1113 if ( mMeshEditor )
1114 {
1115 QgsMessageLog::logMessage( QObject::tr( "Mesh layer \"%1\" already in editing mode" ).arg( name() ) );
1116 return false;
1117 }
1118
1119 mSimplificationSettings.setEnabled( false );
1120
1121 updateTriangularMesh( transform );
1122
1123 mMeshEditor = new QgsMeshEditor( this );
1124
1125 if ( fixErrors )
1126 {
1127 mRendererCache.reset(); // fixing errors could lead to remove faces/vertices
1128 error = mMeshEditor->initializeWithErrorsFix();
1129 }
1130 else
1131 error = mMeshEditor->initialize();
1132
1133 if ( error.errorType != Qgis::MeshEditingErrorType::NoError )
1134 {
1135 mMeshEditor->deleteLater();
1136 mMeshEditor = nullptr;
1137
1138 QgsMessageLog::logMessage( QObject::tr( "Unable to start editing of mesh layer \"%1\": %2" ).
1139 arg( name(), detailsErrorMessage( error ) ), QString(), Qgis::MessageLevel::Critical );
1140 return false;
1141 }
1142
1143 // During editing, we don't need anymore the provider data. Mesh frame data is stored in the mesh editor.
1144 mDataProvider->close();
1145
1146 // All dataset group are removed and replace by a unique virtual dataset group that provide vertices elevation value.
1147 mExtraDatasetUri.clear();
1148 mDatasetGroupStore.reset( new QgsMeshDatasetGroupStore( this ) );
1149
1150 std::unique_ptr<QgsMeshDatasetGroup> zValueDatasetGroup( mMeshEditor->createZValueDatasetGroup() );
1151 if ( mDatasetGroupStore->addDatasetGroup( zValueDatasetGroup.get() ) )
1152 zValueDatasetGroup.release();
1153
1155
1156 connect( mMeshEditor, &QgsMeshEditor::meshEdited, this, &QgsMeshLayer::onMeshEdited );
1157
1158 emit dataChanged();
1159 emit editingStarted();
1160
1161 return true;
1162}
1163
1164bool QgsMeshLayer::commitFrameEditing( const QgsCoordinateTransform &transform, bool continueEditing )
1165{
1167
1169 QString detailsError;
1170 if ( !mMeshEditor->checkConsistency( error ) )
1171 {
1172 if ( error.errorType == Qgis::MeshEditingErrorType::NoError )
1173 detailsError = tr( "Unknown inconsistent mesh error" );
1174 }
1175 else
1176 {
1177 error = QgsTopologicalMesh::checkTopology( *mNativeMesh, mMeshEditor->maximumVerticesPerFace() );
1178 detailsError = detailsErrorMessage( error );
1179 }
1180
1181 if ( !detailsError.isEmpty() )
1182 {
1183 QgsMessageLog::logMessage( QObject::tr( "Edited mesh layer \"%1\" can't be save due to an error: %2" ).
1184 arg( name(), detailsError ), QString(), Qgis::MessageLevel::Critical );
1185 return false;
1186 }
1187
1188 stopFrameEditing( transform );
1189
1190 if ( !mDataProvider )
1191 return false;
1192
1193 const bool res = mDataProvider->saveMeshFrame( *mNativeMesh.get() );
1194
1195 if ( continueEditing )
1196 {
1197 mMeshEditor->initialize();
1198 emit layerModified();
1199 return res;
1200 }
1201
1202 mMeshEditor->deleteLater();
1203 mMeshEditor = nullptr;
1204 emit editingStopped();
1205
1206 mDataProvider->reloadData();
1207 mDataProvider->populateMesh( mNativeMesh.get() );
1208 mDatasetGroupStore.reset( new QgsMeshDatasetGroupStore( this ) );
1209 mDatasetGroupStore->setPersistentProvider( mDataProvider, QStringList() );
1211 return true;
1212}
1213
1214bool QgsMeshLayer::rollBackFrameEditing( const QgsCoordinateTransform &transform, bool continueEditing )
1215{
1217
1218 stopFrameEditing( transform );
1219
1220 if ( !mDataProvider )
1221 return false;
1222
1223 mTriangularMeshes.clear();
1224 mDataProvider->reloadData();
1225 mDataProvider->populateMesh( mNativeMesh.get() );
1226 updateTriangularMesh( transform );
1227 mRendererCache.reset( new QgsMeshLayerRendererCache() );
1229
1230 if ( continueEditing )
1231 {
1232 mMeshEditor->resetTriangularMesh( triangularMesh() );
1233 return mMeshEditor->initialize() == QgsMeshEditingError();
1234 }
1235 else
1236 {
1237 mMeshEditor->deleteLater();
1238 mMeshEditor = nullptr;
1239 emit editingStopped();
1240
1241 mDatasetGroupStore.reset( new QgsMeshDatasetGroupStore( this ) );
1242 mDatasetGroupStore->setPersistentProvider( mDataProvider, QStringList() );
1244 emit dataChanged();
1245 return true;
1246 }
1247}
1248
1250{
1252
1253 if ( !mMeshEditor )
1254 return;
1255
1256 mMeshEditor->stopEditing();
1257 mTriangularMeshes.at( 0 )->update( mNativeMesh.get(), transform );
1258 mRendererCache.reset( new QgsMeshLayerRendererCache() );
1259}
1260
1261bool QgsMeshLayer::reindex( const QgsCoordinateTransform &transform, bool renumber )
1262{
1264
1265 if ( !mMeshEditor )
1266 return false;
1267
1268 if ( !mMeshEditor->reindex( renumber ) )
1269 return false;
1270
1271 mTriangularMeshes.clear();
1272 mTriangularMeshes.emplace_back( new QgsTriangularMesh );
1273 mTriangularMeshes.at( 0 )->update( mNativeMesh.get(), transform );
1274 mRendererCache.reset( new QgsMeshLayerRendererCache() );
1275 mMeshEditor->resetTriangularMesh( mTriangularMeshes.at( 0 ).get() );
1276
1277 return true;
1278}
1279
1281{
1283
1284 return mMeshEditor;
1285}
1286
1288{
1290
1291 if ( mMeshEditor )
1292 return mMeshEditor->isModified();
1293
1294 return false;
1295}
1296
1298{
1300
1301 switch ( type )
1302 {
1304 return meshVertexCount() != 0;
1306 return meshEdgeCount() != 0;
1308 return meshFaceCount() != 0;
1309 }
1310 return false;
1311}
1312
1314{
1316
1317 if ( mMeshEditor )
1318 return mMeshEditor->validVerticesCount();
1319 else if ( mDataProvider )
1320 return mDataProvider->vertexCount();
1321 else return 0;
1322}
1323
1325{
1327
1328 if ( mMeshEditor )
1329 return mMeshEditor->validFacesCount();
1330 else if ( mDataProvider )
1331 return mDataProvider->faceCount();
1332 else return 0;
1333}
1334
1336{
1338
1339 if ( mMeshEditor )
1340 return mNativeMesh->edgeCount();
1341 else if ( mDataProvider )
1342 return mDataProvider->edgeCount();
1343 else return 0;
1344}
1345
1346void QgsMeshLayer::updateActiveDatasetGroups()
1347{
1349
1350 QgsMeshDatasetGroupTreeItem *treeItem = mDatasetGroupStore->datasetGroupTreeItem();
1351
1352 if ( !mDatasetGroupStore->datasetGroupTreeItem() )
1353 return;
1354
1356 const int oldActiveScalar = settings.activeScalarDatasetGroup();
1357 const int oldActiveVector = settings.activeVectorDatasetGroup();
1358
1359 QgsMeshDatasetGroupTreeItem *activeScalarItem =
1360 treeItem->childFromDatasetGroupIndex( oldActiveScalar );
1361
1362 if ( !activeScalarItem && treeItem->childCount() > 0 && oldActiveScalar != -1 )
1363 activeScalarItem = treeItem->child( 0 );
1364
1365 if ( activeScalarItem && !activeScalarItem->isEnabled() )
1366 {
1367 for ( int i = 0; i < treeItem->childCount(); ++i )
1368 {
1369 activeScalarItem = treeItem->child( i );
1370 if ( activeScalarItem->isEnabled() )
1371 break;
1372 else
1373 activeScalarItem = nullptr;
1374 }
1375 }
1376
1377 if ( activeScalarItem )
1378 settings.setActiveScalarDatasetGroup( activeScalarItem->datasetGroupIndex() );
1379 else
1380 settings.setActiveScalarDatasetGroup( -1 );
1381
1382 QgsMeshDatasetGroupTreeItem *activeVectorItem =
1383 treeItem->childFromDatasetGroupIndex( oldActiveVector );
1384
1385 if ( !( activeVectorItem && activeVectorItem->isEnabled() ) )
1386 settings.setActiveVectorDatasetGroup( -1 );
1387
1388 setRendererSettings( settings );
1389
1390 if ( oldActiveScalar != settings.activeScalarDatasetGroup() )
1392 if ( oldActiveVector != settings.activeVectorDatasetGroup() )
1394}
1395
1396QgsMeshRendererSettings QgsMeshLayer::accordSymbologyWithGroupName( const QgsMeshRendererSettings &settings, const QMap<QString, int> &nameToIndex )
1397{
1398 QString activeScalarName;
1399 QString activeVectorName;
1400 QgsMeshRendererSettings consistentSettings = settings;
1401 int activeScalar = consistentSettings.activeScalarDatasetGroup();
1402 int activeVector = consistentSettings.activeVectorDatasetGroup();
1403
1404 for ( auto it = nameToIndex.constBegin(); it != nameToIndex.constEnd(); ++it )
1405 {
1406 int index = it.value();
1407 const QString name = it.key() ;
1408 int globalIndex = mDatasetGroupStore->indexFromGroupName( name );
1409 if ( globalIndex >= 0 )
1410 {
1411 QgsMeshRendererScalarSettings scalarSettings = settings.scalarSettings( index );
1412 consistentSettings.setScalarSettings( globalIndex, scalarSettings );
1413 if ( settings.hasVectorSettings( it.value() ) && mDatasetGroupStore->datasetGroupMetadata( globalIndex ).isVector() )
1414 {
1415 QgsMeshRendererVectorSettings vectorSettings = settings.vectorSettings( index );
1416 consistentSettings.setVectorSettings( globalIndex, vectorSettings );
1417 }
1418 }
1419 else
1420 {
1421 consistentSettings.removeScalarSettings( index );
1422 if ( settings.hasVectorSettings( it.value() ) )
1423 consistentSettings.removeVectorSettings( index );
1424 }
1425
1426 if ( index == activeScalar )
1427 activeScalarName = name;
1428 if ( index == activeVector )
1429 activeVectorName = name;
1430 }
1431
1432 const QList<int> globalIndexes = datasetGroupsIndexes();
1433 for ( int globalIndex : globalIndexes )
1434 {
1435 const QString name = mDatasetGroupStore->groupName( globalIndex );
1436 if ( !nameToIndex.contains( name ) )
1437 {
1438 consistentSettings.setScalarSettings( globalIndex, mRendererSettings.scalarSettings( globalIndex ) );
1439 if ( mDatasetGroupStore->datasetGroupMetadata( globalIndex ).isVector() )
1440 {
1441 consistentSettings.setVectorSettings( globalIndex, mRendererSettings.vectorSettings( globalIndex ) );
1442 }
1443 }
1444 }
1445
1446 if ( !activeScalarName.isEmpty() )
1447 consistentSettings.setActiveScalarDatasetGroup( mDatasetGroupStore->indexFromGroupName( activeScalarName ) );
1448 if ( !activeVectorName.isEmpty() )
1449 consistentSettings.setActiveVectorDatasetGroup( mDatasetGroupStore->indexFromGroupName( activeVectorName ) );
1450
1451 return consistentSettings;
1452}
1453
1454void QgsMeshLayer::setDataSourcePrivate( const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags )
1455{
1457
1458 mDataSource = dataSource;
1459 mLayerName = baseName;
1460 setProviderType( provider );
1461
1462 if ( !mDataSource.isEmpty() && !provider.isEmpty() )
1463 setDataProvider( provider, options, flags );
1464}
1465
1466QgsPointXY QgsMeshLayer::snapOnElement( QgsMesh::ElementType elementType, const QgsPointXY &point, double searchRadius )
1467{
1469
1470 switch ( elementType )
1471 {
1472 case QgsMesh::Vertex:
1473 return snapOnVertex( point, searchRadius );
1474 case QgsMesh::Edge:
1475 return snapOnEdge( point, searchRadius );
1476 case QgsMesh::Face:
1477 return snapOnFace( point, searchRadius );
1478 }
1479 return QgsPointXY(); // avoid warnings
1480}
1481
1483{
1485
1486 if ( !mNativeMesh )
1487 {
1488 // lazy loading of mesh data
1489 fillNativeMesh();
1490 }
1491
1492 QList<int> ret;
1493
1494 if ( !mNativeMesh )
1495 return ret;
1496
1497 QgsExpressionContext context;
1498 std::unique_ptr<QgsExpressionContextScope> expScope( QgsExpressionContextUtils::meshExpressionScope( QgsMesh::Vertex ) );
1499 context.appendScope( expScope.release() );
1500 context.lastScope()->setVariable( QStringLiteral( "_native_mesh" ), QVariant::fromValue( *mNativeMesh ) );
1501
1502 expression.prepare( &context );
1503
1504 for ( int i = 0; i < mNativeMesh->vertexCount(); ++i )
1505 {
1506 context.lastScope()->setVariable( QStringLiteral( "_mesh_vertex_index" ), i, false );
1507
1508 if ( expression.evaluate( &context ).toBool() )
1509 ret.append( i );
1510 }
1511
1512 return ret;
1513}
1514
1516{
1518
1519 if ( !mNativeMesh )
1520 {
1521 // lazy loading of mesh data
1522 fillNativeMesh();
1523 }
1524
1525 QList<int> ret;
1526
1527 if ( !mNativeMesh )
1528 return ret;
1529
1530 QgsExpressionContext context;
1531 std::unique_ptr<QgsExpressionContextScope> expScope( QgsExpressionContextUtils::meshExpressionScope( QgsMesh::Face ) );
1532 context.appendScope( expScope.release() );
1533 context.lastScope()->setVariable( QStringLiteral( "_native_mesh" ), QVariant::fromValue( *mNativeMesh ) );
1534
1535 expression.prepare( &context );
1536
1537 for ( int i = 0; i < mNativeMesh->faceCount(); ++i )
1538 {
1539 context.lastScope()->setVariable( QStringLiteral( "_mesh_face_index" ), i, false );
1540
1541 if ( expression.evaluate( &context ).toBool() )
1542 ret.append( i );
1543 }
1544
1545 return ret;
1546}
1547
1549{
1551
1552 return QgsMeshDatasetIndex( group >= 0 ? group : mRendererSettings.activeScalarDatasetGroup(), mStaticScalarDatasetIndex );
1553}
1554
1556{
1558
1559 const int oldActiveVector = mRendererSettings.activeVectorDatasetGroup();
1560
1561 mStaticVectorDatasetIndex = staticVectorDatasetIndex.dataset();
1563
1564 if ( oldActiveVector != mRendererSettings.activeVectorDatasetGroup() )
1566}
1567
1569{
1571
1572 const int oldActiveScalar = mRendererSettings.activeScalarDatasetGroup();
1573
1574 mStaticScalarDatasetIndex = staticScalarDatasetIndex.dataset();
1576
1577 if ( oldActiveScalar != mRendererSettings.activeScalarDatasetGroup() )
1579}
1580
1587
1589{
1591
1592 mSimplificationSettings = simplifySettings;
1593}
1594
1595static QgsColorRamp *_createDefaultColorRamp()
1596{
1597 QgsColorRamp *ramp = QgsStyle::defaultStyle()->colorRamp( QStringLiteral( "Plasma" ) );
1598 if ( ramp )
1599 return ramp;
1600
1601 // definition of "Plasma" color ramp (in case it is not available in the style for some reason)
1602 QVariantMap props;
1603 props["color1"] = "13,8,135,255";
1604 props["color2"] = "240,249,33,255";
1605 props["stops"] =
1606 "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:"
1607 "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:"
1608 "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:"
1609 "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:"
1610 "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:"
1611 "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:"
1612 "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:"
1613 "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:"
1614 "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:"
1615 "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";
1616 return QgsGradientColorRamp::create( props );
1617}
1618
1619void QgsMeshLayer::assignDefaultStyleToDatasetGroup( int groupIndex )
1620{
1622
1624 const double groupMin = metadata.minimum();
1625 const double groupMax = metadata.maximum();
1626
1627 QgsColorRampShader fcn( groupMin, groupMax, _createDefaultColorRamp() );
1628 fcn.classifyColorRamp( 5, -1, QgsRectangle(), nullptr );
1629
1630 QgsMeshRendererScalarSettings scalarSettings;
1631 scalarSettings.setClassificationMinimumMaximum( groupMin, groupMax );
1632 scalarSettings.setColorRampShader( fcn );
1633 QgsInterpolatedLineWidth edgeStrokeWidth;
1634 edgeStrokeWidth.setMinimumValue( groupMin );
1635 edgeStrokeWidth.setMaximumValue( groupMax );
1636 const QgsInterpolatedLineColor edgeStrokeColor( fcn );
1637 const QgsInterpolatedLineRenderer edgeStrokePen;
1638 scalarSettings.setEdgeStrokeWidth( edgeStrokeWidth );
1639 mRendererSettings.setScalarSettings( groupIndex, scalarSettings );
1640
1641 if ( metadata.isVector() )
1642 {
1643 QgsMeshRendererVectorSettings vectorSettings;
1644 vectorSettings.setColorRampShader( fcn );
1645 mRendererSettings.setVectorSettings( groupIndex, vectorSettings );
1646 }
1647}
1648
1650{
1652
1653 // Triangular mesh
1654 updateTriangularMesh( rendererContext.coordinateTransform() );
1655
1656 // Build overview triangular meshes if needed
1657 createSimplifiedMeshes();
1658
1659 // Cache
1660 if ( !mRendererCache )
1661 mRendererCache.reset( new QgsMeshLayerRendererCache() );
1662
1663 return new QgsMeshLayerRenderer( this, rendererContext );
1664}
1665
1672
1673void QgsMeshLayer::checkSymbologyConsistency()
1674{
1676
1677 const QList<int> groupIndexes = mDatasetGroupStore->datasetGroupIndexes();
1678 if ( !groupIndexes.contains( mRendererSettings.activeScalarDatasetGroup() ) &&
1679 mRendererSettings.activeScalarDatasetGroup() != -1 )
1680 {
1681 if ( !groupIndexes.empty() )
1682 mRendererSettings.setActiveScalarDatasetGroup( groupIndexes.first() );
1683 else
1684 mRendererSettings.setActiveScalarDatasetGroup( -1 );
1685 }
1686
1687 if ( !groupIndexes.contains( mRendererSettings.activeVectorDatasetGroup() ) &&
1688 mRendererSettings.activeVectorDatasetGroup() != -1 )
1689 {
1690 mRendererSettings.setActiveVectorDatasetGroup( -1 );
1691 }
1692}
1693
1694bool QgsMeshLayer::readSymbology( const QDomNode &node, QString &errorMessage,
1696{
1698
1699 Q_UNUSED( errorMessage )
1700 // TODO: implement categories for raster layer
1701
1702 const QDomElement elem = node.toElement();
1703
1704 readCommonStyle( elem, context, categories );
1705
1707 const QDomElement elemRendererSettings = elem.firstChildElement( "mesh-renderer-settings" );
1708 if ( !elemRendererSettings.isNull() )
1709 rendererSettings.readXml( elemRendererSettings, context );
1710
1711 QMap<QString, int> groupNameToGlobalIndex;
1712 QDomElement nameToIndexElem = elem.firstChildElement( "name-to-global-index" );
1713 while ( !nameToIndexElem.isNull() )
1714 {
1715 const QString name = nameToIndexElem.attribute( QStringLiteral( "name" ) );
1716 int globalIndex = nameToIndexElem.attribute( QStringLiteral( "global-index" ) ).toInt();
1717 groupNameToGlobalIndex.insert( name, globalIndex );
1718 nameToIndexElem = nameToIndexElem.nextSiblingElement( QStringLiteral( "name-to-global-index" ) );
1719 }
1720
1721 mRendererSettings = accordSymbologyWithGroupName( rendererSettings, groupNameToGlobalIndex );
1722
1723 checkSymbologyConsistency();
1724
1725 const QDomElement elemSimplifySettings = elem.firstChildElement( "mesh-simplify-settings" );
1726 if ( !elemSimplifySettings.isNull() )
1727 mSimplificationSettings.readXml( elemSimplifySettings, context );
1728
1729 // get and set the blend mode if it exists
1730 const QDomNode blendModeNode = node.namedItem( QStringLiteral( "blendMode" ) );
1731 if ( !blendModeNode.isNull() )
1732 {
1733 const QDomElement e = blendModeNode.toElement();
1734 setBlendMode( QgsPainting::getCompositionMode( static_cast< Qgis::BlendMode >( e.text().toInt() ) ) );
1735 }
1736
1737 // read labeling definition
1738 if ( categories.testFlag( Labeling ) )
1739 {
1740 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Labeling" ) );
1741
1742 QDomElement labelingElement = node.firstChildElement( QStringLiteral( "labeling" ) );
1743 if ( !labelingElement.isNull() )
1744 {
1746 mLabelsEnabled = node.toElement().attribute( QStringLiteral( "labelsEnabled" ), QStringLiteral( "0" ) ).toInt();
1748 }
1749 }
1750
1751 // get and set the layer transparency
1752 if ( categories.testFlag( Rendering ) )
1753 {
1754 const QDomNode layerOpacityNode = node.namedItem( QStringLiteral( "layerOpacity" ) );
1755 if ( !layerOpacityNode.isNull() )
1756 {
1757 const QDomElement e = layerOpacityNode.toElement();
1758 setOpacity( e.text().toDouble() );
1759 }
1760 }
1761
1762 return true;
1763}
1764
1765bool QgsMeshLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage,
1766 const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1767{
1769
1770 Q_UNUSED( errorMessage )
1771 // TODO: implement categories for raster layer
1772
1773 QDomElement elem = node.toElement();
1774
1775 writeCommonStyle( elem, doc, context, categories );
1776
1777 const QDomElement elemRendererSettings = mRendererSettings.writeXml( doc, context );
1778 elem.appendChild( elemRendererSettings );
1779
1780 const QList<int> groupIndexes = datasetGroupsIndexes();
1781 // we store the relation between name and indexes to be able to retrieve the consistency between name and symbology
1782 for ( int index : groupIndexes )
1783 {
1784 QDomElement elemNameToIndex = doc.createElement( QStringLiteral( "name-to-global-index" ) );
1785 elemNameToIndex.setAttribute( QStringLiteral( "name" ), mDatasetGroupStore->groupName( index ) );
1786 elemNameToIndex.setAttribute( QStringLiteral( "global-index" ), index );
1787 elem.appendChild( elemNameToIndex );
1788 }
1789
1790 const QDomElement elemSimplifySettings = mSimplificationSettings.writeXml( doc, context );
1791 elem.appendChild( elemSimplifySettings );
1792
1793 // add blend mode node
1794 QDomElement blendModeElement = doc.createElement( QStringLiteral( "blendMode" ) );
1795 const QDomText blendModeText = doc.createTextNode( QString::number( static_cast< int >( QgsPainting::getBlendModeEnum( blendMode() ) ) ) );
1796 blendModeElement.appendChild( blendModeText );
1797 node.appendChild( blendModeElement );
1798
1799 if ( categories.testFlag( Labeling ) )
1800 {
1801 if ( mLabeling )
1802 {
1803 QDomElement labelingElement = mLabeling->save( doc, context );
1804 elem.appendChild( labelingElement );
1805 }
1806 elem.setAttribute( QStringLiteral( "labelsEnabled" ), mLabelsEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
1807 }
1808
1809 // add the layer opacity
1810 if ( categories.testFlag( Rendering ) )
1811 {
1812 QDomElement layerOpacityElem = doc.createElement( QStringLiteral( "layerOpacity" ) );
1813 const QDomText layerOpacityText = doc.createTextNode( QString::number( opacity() ) );
1814 layerOpacityElem.appendChild( layerOpacityText );
1815 node.appendChild( layerOpacityElem );
1816 }
1817
1818 return true;
1819}
1820
1821bool QgsMeshLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1822{
1824
1825 return writeSymbology( node, doc, errorMessage, context, categories );
1826}
1827
1828bool QgsMeshLayer::readStyle( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
1829{
1831
1832 return readSymbology( node, errorMessage, context, categories );
1833}
1834
1835QString QgsMeshLayer::decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const
1836{
1838
1839 return QgsProviderRegistry::instance()->relativeToAbsoluteUri( provider, source, context );
1840}
1841
1842QString QgsMeshLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
1843{
1845
1847}
1848
1849bool QgsMeshLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &context )
1850{
1852
1853 QgsDebugMsgLevel( QStringLiteral( "Datasource in QgsMeshLayer::readXml: %1" ).arg( mDataSource.toLocal8Bit().data() ), 3 );
1854
1855 //process provider key
1856 const QDomNode pkeyNode = layer_node.namedItem( QStringLiteral( "provider" ) );
1857
1858 if ( pkeyNode.isNull() )
1859 {
1860 mProviderKey.clear();
1861 }
1862 else
1863 {
1864 const QDomElement pkeyElt = pkeyNode.toElement();
1865 mProviderKey = pkeyElt.text();
1866 }
1867
1869 {
1870 return false;
1871 }
1872
1873 const QgsDataProvider::ProviderOptions providerOptions;
1875
1876 const QDomElement elemExtraDatasets = layer_node.firstChildElement( QStringLiteral( "extra-datasets" ) );
1877 if ( !elemExtraDatasets.isNull() )
1878 {
1879 QDomElement elemUri = elemExtraDatasets.firstChildElement( QStringLiteral( "uri" ) );
1880 while ( !elemUri.isNull() )
1881 {
1882 const QString uri = context.pathResolver().readPath( elemUri.text() );
1883 mExtraDatasetUri.append( uri );
1884 elemUri = elemUri.nextSiblingElement( QStringLiteral( "uri" ) );
1885 }
1886 }
1887
1888 if ( pkeyNode.toElement().hasAttribute( QStringLiteral( "time-unit" ) ) )
1889 mTemporalUnit = static_cast<Qgis::TemporalUnit>( pkeyNode.toElement().attribute( QStringLiteral( "time-unit" ) ).toInt() );
1890
1891 // read dataset group store
1892 const QDomElement elemDatasetGroupsStore = layer_node.firstChildElement( QStringLiteral( "mesh-dataset-groups-store" ) );
1893 if ( elemDatasetGroupsStore.isNull() )
1895 else
1896 mDatasetGroupStore->readXml( elemDatasetGroupsStore, context );
1897
1898 setDataProvider( mProviderKey, providerOptions, flags );
1899
1900 QString errorMsg;
1901 readSymbology( layer_node, errorMsg, context );
1902
1903 if ( !mTemporalProperties->timeExtent().begin().isValid() || mTemporalProperties->alwaysLoadReferenceTimeFromSource() )
1905
1906 // read static dataset
1907 const QDomElement elemStaticDataset = layer_node.firstChildElement( QStringLiteral( "static-active-dataset" ) );
1908 if ( elemStaticDataset.hasAttribute( QStringLiteral( "scalar" ) ) )
1909 {
1910 mStaticScalarDatasetIndex = elemStaticDataset.attribute( QStringLiteral( "scalar" ) ).toInt();
1911 }
1912 if ( elemStaticDataset.hasAttribute( QStringLiteral( "vector" ) ) )
1913 {
1914 mStaticVectorDatasetIndex = elemStaticDataset.attribute( QStringLiteral( "vector" ) ).toInt();
1915 }
1916
1917 return isValid(); // should be true if read successfully
1918}
1919
1920bool QgsMeshLayer::writeXml( QDomNode &layer_node, QDomDocument &document, const QgsReadWriteContext &context ) const
1921{
1923
1924 // first get the layer element so that we can append the type attribute
1925 QDomElement mapLayerNode = layer_node.toElement();
1926
1927 if ( mapLayerNode.isNull() || ( QLatin1String( "maplayer" ) != mapLayerNode.nodeName() ) )
1928 {
1929 QgsDebugMsgLevel( QStringLiteral( "can't find <maplayer>" ), 2 );
1930 return false;
1931 }
1932
1933 mapLayerNode.setAttribute( QStringLiteral( "type" ), QgsMapLayerFactory::typeToString( Qgis::LayerType::Mesh ) );
1934
1935 // add provider node
1936 if ( mDataProvider )
1937 {
1938 QDomElement provider = document.createElement( QStringLiteral( "provider" ) );
1939 const QDomText providerText = document.createTextNode( providerType() );
1940 provider.appendChild( providerText );
1941 layer_node.appendChild( provider );
1942 provider.setAttribute( QStringLiteral( "time-unit" ), static_cast< int >( mDataProvider->temporalCapabilities()->temporalUnit() ) );
1943
1944 const QStringList extraDatasetUris = mDataProvider->extraDatasets();
1945 QDomElement elemExtraDatasets = document.createElement( QStringLiteral( "extra-datasets" ) );
1946 for ( const QString &uri : extraDatasetUris )
1947 {
1948 const QString path = context.pathResolver().writePath( uri );
1949 QDomElement elemUri = document.createElement( QStringLiteral( "uri" ) );
1950 elemUri.appendChild( document.createTextNode( path ) );
1951 elemExtraDatasets.appendChild( elemUri );
1952 }
1953 layer_node.appendChild( elemExtraDatasets );
1954 }
1955
1956 QDomElement elemStaticDataset = document.createElement( QStringLiteral( "static-active-dataset" ) );
1957 elemStaticDataset.setAttribute( QStringLiteral( "scalar" ), mStaticScalarDatasetIndex );
1958 elemStaticDataset.setAttribute( QStringLiteral( "vector" ), mStaticVectorDatasetIndex );
1959 layer_node.appendChild( elemStaticDataset );
1960
1961 // write dataset group store if not in edting mode
1962 if ( !isEditable() )
1963 layer_node.appendChild( mDatasetGroupStore->writeXml( document, context ) );
1964
1965 // renderer specific settings
1966 QString errorMsg;
1967 return writeSymbology( layer_node, document, errorMsg, context );
1968}
1969
1971{
1973
1974 if ( !mMeshEditor && mDataProvider && mDataProvider->isValid() )
1975 {
1976 mDataProvider->reloadData();
1977 mDatasetGroupStore->setPersistentProvider( mDataProvider, QStringList() ); //extra dataset are already loaded
1978
1979 //reload the mesh structure
1980 if ( !mNativeMesh )
1981 mNativeMesh.reset( new QgsMesh );
1982
1983 dataProvider()->populateMesh( mNativeMesh.get() );
1984
1985 if ( mTemporalProperties->alwaysLoadReferenceTimeFromSource() )
1986 mTemporalProperties->setDefaultsFromDataProviderTemporalCapabilities( mDataProvider->temporalCapabilities() );
1987
1988 //clear the TriangularMeshes
1989 mTriangularMeshes.clear();
1990
1991 //clear the rendererCache
1992 mRendererCache.reset( new QgsMeshLayerRendererCache() );
1993
1994 checkSymbologyConsistency();
1995
1996 emit reloaded();
1997 }
1998}
1999
2000QStringList QgsMeshLayer::subLayers() const
2001{
2003
2004 if ( mDataProvider )
2005 return mDataProvider->subLayers();
2006 else
2007 return QStringList();
2008}
2009
2011{
2013
2014 const QgsLayerMetadataFormatter htmlFormatter( metadata() );
2015 QString myMetadata = QStringLiteral( "<html>\n<body>\n" );
2016
2017 myMetadata += generalHtmlMetadata();
2018
2019 // Begin Provider section
2020 myMetadata += QStringLiteral( "<h1>" ) + tr( "Information from provider" ) + QStringLiteral( "</h1>\n<hr>\n" );
2021 myMetadata += QLatin1String( "<table class=\"list-view\">\n" );
2022
2023 // Extent
2024 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Extent" ) + QStringLiteral( "</td><td>" ) + extent().toString() + QStringLiteral( "</td></tr>\n" );
2025
2026 // feature count
2027 QLocale locale = QLocale();
2028 locale.setNumberOptions( locale.numberOptions() &= ~QLocale::NumberOption::OmitGroupSeparator );
2029
2030 if ( const QgsMeshDataProvider *provider = dataProvider() )
2031 {
2032 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
2033 + tr( "Vertex count" ) + QStringLiteral( "</td><td>" )
2034 + ( locale.toString( static_cast<qlonglong>( meshVertexCount() ) ) )
2035 + QStringLiteral( "</td></tr>\n" );
2036 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
2037 + tr( "Face count" ) + QStringLiteral( "</td><td>" )
2038 + ( locale.toString( static_cast<qlonglong>( meshFaceCount() ) ) )
2039 + QStringLiteral( "</td></tr>\n" );
2040 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
2041 + tr( "Edge count" ) + QStringLiteral( "</td><td>" )
2042 + ( locale.toString( static_cast<qlonglong>( meshEdgeCount() ) ) )
2043 + QStringLiteral( "</td></tr>\n" );
2044 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
2045 + tr( "Dataset groups count" ) + QStringLiteral( "</td><td>" )
2046 + ( locale.toString( static_cast<qlonglong>( datasetGroupCount() ) ) )
2047 + QStringLiteral( "</td></tr>\n" );
2048 myMetadata += provider->htmlMetadata();
2049 }
2050
2051 // End Provider section
2052 myMetadata += QLatin1String( "</table>\n<br><br>" );
2053
2054 // CRS
2055 myMetadata += crsHtmlMetadata();
2056
2057 // identification section
2058 myMetadata += QStringLiteral( "<h1>" ) + tr( "Identification" ) + QStringLiteral( "</h1>\n<hr>\n" );
2059 myMetadata += htmlFormatter.identificationSectionHtml( );
2060 myMetadata += QLatin1String( "<br><br>\n" );
2061
2062 // extent section
2063 myMetadata += QStringLiteral( "<h1>" ) + tr( "Extent" ) + QStringLiteral( "</h1>\n<hr>\n" );
2064 myMetadata += htmlFormatter.extentSectionHtml( isSpatial() );
2065 myMetadata += QLatin1String( "<br><br>\n" );
2066
2067 // Start the Access section
2068 myMetadata += QStringLiteral( "<h1>" ) + tr( "Access" ) + QStringLiteral( "</h1>\n<hr>\n" );
2069 myMetadata += htmlFormatter.accessSectionHtml( );
2070 myMetadata += QLatin1String( "<br><br>\n" );
2071
2072 // Start the contacts section
2073 myMetadata += QStringLiteral( "<h1>" ) + tr( "Contacts" ) + QStringLiteral( "</h1>\n<hr>\n" );
2074 myMetadata += htmlFormatter.contactsSectionHtml( );
2075 myMetadata += QLatin1String( "<br><br>\n" );
2076
2077 // Start the links section
2078 myMetadata += QStringLiteral( "<h1>" ) + tr( "Links" ) + QStringLiteral( "</h1>\n<hr>\n" );
2079 myMetadata += htmlFormatter.linksSectionHtml( );
2080 myMetadata += QLatin1String( "<br><br>\n" );
2081
2082 // Start the history section
2083 myMetadata += QStringLiteral( "<h1>" ) + tr( "History" ) + QStringLiteral( "</h1>\n<hr>\n" );
2084 myMetadata += htmlFormatter.historySectionHtml( );
2085 myMetadata += QLatin1String( "<br><br>\n" );
2086
2087 myMetadata += QLatin1String( "\n</body>\n</html>\n" );
2088 return myMetadata;
2089}
2090
2092{
2094
2095 return mMeshEditor != nullptr;
2096}
2097
2098bool QgsMeshLayer::setDataProvider( QString const &provider, const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags )
2099{
2101
2102 mDatasetGroupStore->setPersistentProvider( nullptr, QStringList() );
2103
2104 delete mDataProvider;
2105 mProviderKey = provider;
2106 const QString dataSource = mDataSource;
2107
2108 if ( mPreloadedProvider )
2109 {
2110 mDataProvider = qobject_cast< QgsMeshDataProvider * >( mPreloadedProvider.release() );
2111 }
2112 else
2113 {
2114 std::unique_ptr< QgsScopedRuntimeProfile > profile;
2115 if ( QgsApplication::profiler()->groupIsActive( QStringLiteral( "projectload" ) ) )
2116 profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Create %1 provider" ).arg( provider ), QStringLiteral( "projectload" ) );
2117
2118 mDataProvider = qobject_cast<QgsMeshDataProvider *>( QgsProviderRegistry::instance()->createProvider( provider, dataSource, options, flags ) );
2119 }
2120
2121 if ( !mDataProvider )
2122 {
2123 QgsDebugMsgLevel( QStringLiteral( "Unable to get mesh data provider" ), 2 );
2124 return false;
2125 }
2126
2127 mDataProvider->setParent( this );
2128 QgsDebugMsgLevel( QStringLiteral( "Instantiated the mesh data provider plugin" ), 2 );
2129
2130 setValid( mDataProvider->isValid() );
2131 if ( !isValid() )
2132 {
2133 QgsDebugMsgLevel( QStringLiteral( "Invalid mesh provider plugin %1" ).arg( QString( mDataSource.toUtf8() ) ), 2 );
2134 return false;
2135 }
2136
2137 if ( !mTemporalProperties->isValid() )
2138 {
2139 mTemporalProperties->setDefaultsFromDataProviderTemporalCapabilities( dataProvider()->temporalCapabilities() );
2140 }
2141
2142 mDataProvider->setTemporalUnit( mTemporalUnit );
2143
2144 mDatasetGroupStore->setPersistentProvider( mDataProvider, mExtraDatasetUri );
2145
2146 setCrs( mDataProvider->crs() );
2147
2148 if ( provider == QLatin1String( "mesh_memory" ) )
2149 {
2150 // required so that source differs between memory layers
2151 mDataSource = mDataSource + QStringLiteral( "&uid=%1" ).arg( QUuid::createUuid().toString() );
2152 }
2153
2154 // set default style if required by flags or if the dataset group does not has a style yet
2155 for ( int i = 0; i < mDataProvider->datasetGroupCount(); ++i )
2156 {
2157 int globalIndex = mDatasetGroupStore->globalDatasetGroupIndexInSource( mDataProvider, i );
2158 if ( globalIndex != -1 &&
2159 ( !mRendererSettings.hasSettings( globalIndex ) || ( flags & QgsDataProvider::FlagLoadDefaultStyle ) ) )
2160 assignDefaultStyleToDatasetGroup( globalIndex );
2161 }
2162
2163 emit rendererChanged();
2165
2166 connect( mDataProvider, &QgsMeshDataProvider::dataChanged, this, &QgsMeshLayer::dataChanged );
2167
2168 return true;
2169}
2170
2177
2184
2186{
2188
2189 return mLabelsEnabled && static_cast< bool >( mLabeling );
2190}
2191
2193{
2195
2196 mLabelsEnabled = enabled;
2197}
2198
2200{
2202
2203 if ( mLabeling == labeling )
2204 return;
2205
2206 delete mLabeling;
2207 mLabeling = labeling;
2209}
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:102
@ 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:4275
TemporalUnit
Temporal units.
Definition qgis.h:4465
@ Milliseconds
Milliseconds.
@ EqualInterval
Uses equal interval.
@ Mesh
Mesh layer. Added in QGIS 3.2.
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.
@ FlagLoadDefaultStyle
Reset the layer's style to the default for the datasource.
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'...
QFlags< ReadFlag > ReadFlags
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:75
QString name
Definition qgsmaplayer.h:79
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.
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:81
Qgis::LayerType type
Definition qgsmaplayer.h:85
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:87
@ 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 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.
static QgsDataProvider::ReadFlags providerReadFlags(const QDomNode &layerNode, QgsMapLayer::ReadFlags layerReadFlags)
Returns provider read flag deduced from layer read flags layerReadFlags and a dom node layerNode that...
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:207
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:494
static QgsStyle * defaultStyle(bool initialize=true)
Returns the default application-wide style.
Definition qgsstyle.cpp:145
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.