QGIS API Documentation 3.43.0-Master (56aa1fd18d7)
qgsmeshlayer.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsmeshlayer.cpp
3 ----------------
4 begin : April 2018
5 copyright : (C) 2018 by Peter Petrik
6 email : zilolv at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18#include <cstddef>
19#include <limits>
20
21#include <QUuid>
22#include <QUrl>
23
24#include "qgscolorrampimpl.h"
25#include "qgslogger.h"
26#include "qgsmaplayerlegend.h"
27#include "qgsmaplayerfactory.h"
28#include "qgsmeshdataprovider.h"
30#include "qgsmeshlayer.h"
31#include "moc_qgsmeshlayer.cpp"
34#include "qgsmeshlayerutils.h"
35#include "qgsmeshtimesettings.h"
36#include "qgspainting.h"
37#include "qgsproviderregistry.h"
38#include "qgsreadwritecontext.h"
39#include "qgsstyle.h"
40#include "qgstriangularmesh.h"
41#include "qgsmesh3daveraging.h"
43#include "qgsmesheditor.h"
44#include "qgsmessagelog.h"
48#include "qgsthreadingutils.h"
49#include "qgsapplication.h"
50#include "qgsruntimeprofiler.h"
52
53QgsMeshLayer::QgsMeshLayer( const QString &meshLayerPath,
54 const QString &baseName,
55 const QString &providerKey,
56 const QgsMeshLayer::LayerOptions &options )
57 : QgsMapLayer( Qgis::LayerType::Mesh, baseName, meshLayerPath )
58 , mDatasetGroupStore( new QgsMeshDatasetGroupStore( this ) )
59 , mTemporalProperties( new QgsMeshLayerTemporalProperties( this ) )
60 , mElevationProperties( new QgsMeshLayerElevationProperties( this ) )
61{
63
64 const QgsDataProvider::ProviderOptions providerOptions { options.transformContext };
66 if ( options.loadDefaultStyle )
67 {
69 }
70 QgsMeshLayer::setDataSourcePrivate( meshLayerPath, baseName, providerKey, providerOptions, flags );
73
74 if ( isValid() && options.loadDefaultStyle )
75 {
76 bool result = false;
77 loadDefaultStyle( result );
78 }
79
80 connect( mDatasetGroupStore.get(), &QgsMeshDatasetGroupStore::datasetGroupsAdded, this, &QgsMeshLayer::onDatasetGroupsAdded );
81}
82
83void QgsMeshLayer::createSimplifiedMeshes()
84{
86
87 if ( mSimplificationSettings.isEnabled() && !hasSimplifiedMeshes() )
88 {
89 const double reductionFactor = mSimplificationSettings.reductionFactor();
90
91 QVector<QgsTriangularMesh *> simplifyMeshes =
92 mTriangularMeshes[0]->simplifyMesh( reductionFactor );
93
94 for ( int i = 0; i < simplifyMeshes.count() ; ++i )
95 {
96 mTriangularMeshes.emplace_back( simplifyMeshes[i] );
97 }
98 }
99}
100
101bool QgsMeshLayer::hasSimplifiedMeshes() const
102{
104
105 //First mesh is the base mesh, so if size>1, there is no simplified meshes
106 return ( mTriangularMeshes.size() > 1 );
107}
108
110{
111 delete mLabeling;
112 delete mDataProvider;
113}
114
121
123{
125
126 return mDataProvider;
127}
128
130{
132
134 if ( mDataProvider )
135 {
136 options.transformContext = mDataProvider->transformContext();
137 }
138 QgsMeshLayer *layer = new QgsMeshLayer( source(), name(), mProviderKey, options );
139 QgsMapLayer::clone( layer );
140
141 layer->mElevationProperties = mElevationProperties->clone();
142 layer->mElevationProperties->setParent( layer );
143
144 if ( auto *lLabeling = labeling() )
145 {
146 layer->setLabeling( lLabeling->clone() );
147 }
149
150 return layer;
151}
152
154{
156
157 if ( mMeshEditor )
158 return mMeshEditor->extent();
159
160 if ( mDataProvider )
161 return mDataProvider->extent();
162 else
163 {
164 QgsRectangle rec;
165 rec.setNull();
166 return rec;
167 }
168}
169
171{
173
174 if ( !mDataProvider )
175 return false;
176
177 if ( mMeshEditor )
178 return true;
179
180 const QgsMeshDriverMetadata driverMetadata = mDataProvider->driverMetadata();
181
183}
184
185QString QgsMeshLayer::loadDefaultStyle( bool &resultFlag )
186{
188
189 const QList<int> groupsList = datasetGroupsIndexes();
190
191 for ( const int index : groupsList )
192 assignDefaultStyleToDatasetGroup( index );
193
194
195 QgsMeshRendererMeshSettings meshSettings;
196 if ( !groupsList.isEmpty() )
197 {
198 // Show data from the first dataset group
199 mRendererSettings.setActiveScalarDatasetGroup( 0 );
200 // If the first dataset group has nan min/max, display the mesh to avoid nothing displayed
202 if ( meta.maximum() == std::numeric_limits<double>::quiet_NaN() &&
203 meta.minimum() == std::numeric_limits<double>::quiet_NaN() )
204 meshSettings.setEnabled( true );
205 }
206 else
207 {
208 // show at least the mesh by default
209 meshSettings.setEnabled( true );
210 }
211
212 mRendererSettings.setNativeMeshSettings( meshSettings );
213
214 for ( const int i : groupsList )
215 {
216 assignDefaultStyleToDatasetGroup( i );
217
218 // Sets default resample method for scalar dataset
220 QgsMeshRendererScalarSettings scalarSettings = mRendererSettings.scalarSettings( i );
221 switch ( meta.dataType() )
222 {
224 case QgsMeshDatasetGroupMetadata::DataOnVolumes: // data on volumes are averaged to 2D data on faces
226 break;
229 break;
231 break;
232 }
233
234 //override color ramp if the values in the dataset group are classified
235 applyClassificationOnScalarSettings( meta, scalarSettings );
236
237 mRendererSettings.setScalarSettings( i, scalarSettings );
238 }
239
240 if ( !groupsList.isEmpty() )
241 {
242 emit rendererChanged();
244 }
245
246 return QgsMapLayer::loadDefaultStyle( resultFlag );
247}
248
249bool QgsMeshLayer::removeDatasets( const QString &name )
250{
251 const int index = mDatasetGroupStore->indexFromGroupName( name );
252
253 if ( index == -1 )
254 {
255 return false;
256 }
257
258 const QgsMeshDatasetGroupMetadata groupMetadata = datasetGroupMetadata( index );
259
260 mDatasetGroupStore->removeDatasetGroup( index );
261
262 if ( mExtraDatasetUri.contains( groupMetadata.uri() ) )
263 {
264 mExtraDatasetUri.removeOne( groupMetadata.uri() );
265 }
266
268
269 emit dataSourceChanged();
270 return true;
271}
272
273bool QgsMeshLayer::addDatasets( const QString &path, const QDateTime &defaultReferenceTime )
274{
276
278 const bool isTemporalBefore = temporalCapabilities->hasTemporalCapabilities();
279 if ( mDatasetGroupStore->addPersistentDatasets( path ) )
280 {
281 mExtraDatasetUri.append( path );
282 QgsMeshLayerTemporalProperties *temporalProperties = qobject_cast< QgsMeshLayerTemporalProperties * >( mTemporalProperties );
283 if ( !isTemporalBefore && temporalCapabilities->hasTemporalCapabilities() )
284 {
286 temporalCapabilities );
287
288 if ( ! temporalProperties->referenceTime().isValid() )
289 {
290 QDateTime referenceTime = defaultReferenceTime;
291 if ( !defaultReferenceTime.isValid() ) // If project reference time is invalid, use current date
292 referenceTime = QDateTime( QDate::currentDate(), QTime( 0, 0, 0 ), Qt::UTC );
293 temporalProperties->setReferenceTime( referenceTime, temporalCapabilities );
294 }
295
296 mTemporalProperties->setIsActive( true );
297 }
298 emit dataSourceChanged();
299 return true;
300 }
301
302 return false;
303}
304
306{
308
309 if ( mDatasetGroupStore->addDatasetGroup( datasetGroup ) )
310 {
311 emit dataChanged();
312 return true;
313 }
314 return false;
315}
316
317bool QgsMeshLayer::saveDataset( const QString &path, int datasetGroupIndex, QString driver )
318{
320
321 return mDatasetGroupStore->saveDatasetGroup( path, datasetGroupIndex, driver );
322}
323
325{
327
328 return mNativeMesh.get();
329}
330
332{
334
335 return mNativeMesh.get();
336}
337
338QgsTriangularMesh *QgsMeshLayer::triangularMesh( double minimumTriangleSize ) const
339{
341
342 for ( const std::unique_ptr<QgsTriangularMesh> &lod : mTriangularMeshes )
343 {
344 if ( lod && lod->averageTriangleSize() > minimumTriangleSize )
345 return lod.get();
346 }
347
348 if ( !mTriangularMeshes.empty() )
349 return mTriangularMeshes.back().get();
350 else
351 return nullptr;
352}
353
355{
357
358 return mTriangularMeshes.size();
359}
360
362{
364
365 if ( mTriangularMeshes.empty() )
366 return nullptr;
367 if ( lodIndex < 0 )
368 return mTriangularMeshes.front().get();
369
370 if ( lodIndex >= int( mTriangularMeshes.size() ) )
371 return mTriangularMeshes.back().get();
372
373 return mTriangularMeshes.at( lodIndex ).get();
374}
375
377{
379
380 // Native mesh
381 if ( !mNativeMesh )
382 {
383 // lazy loading of mesh data
384 fillNativeMesh();
385 }
386
387 // Triangular mesh
388 if ( mTriangularMeshes.empty() )
389 {
390 QgsTriangularMesh *baseMesh = new QgsTriangularMesh;
391 mTriangularMeshes.emplace_back( baseMesh );
392 }
393
394 if ( mTriangularMeshes[0].get()->update( mNativeMesh.get(), transform ) )
395 mTriangularMeshes.resize( 1 ); //if the base triangular mesh is effectivly updated, remove simplified meshes
396
397 createSimplifiedMeshes();
398}
399
400QgsMeshLayerRendererCache *QgsMeshLayer::rendererCache()
401{
403
404 return mRendererCache.get();
405}
406
413
414void QgsMeshLayer::setRendererSettings( const QgsMeshRendererSettings &settings, const bool repaint )
415{
417
418 const int oldActiveScalar = mRendererSettings.activeScalarDatasetGroup();
419 const int oldActiveVector = mRendererSettings.activeVectorDatasetGroup();
420 mRendererSettings = settings;
421
422 if ( oldActiveScalar != mRendererSettings.activeScalarDatasetGroup() )
424
425 if ( oldActiveVector != mRendererSettings.activeVectorDatasetGroup() )
427
428 emit rendererChanged();
429
430 if ( repaint )
431 {
433 }
434}
435
442
444{
446
447 mTimeSettings = settings;
448 emit timeSettingsChanged();
449}
450
451QString QgsMeshLayer::formatTime( double hours )
452{
454
455 if ( dataProvider() && dataProvider()->temporalCapabilities()->hasReferenceTime() )
456 return QgsMeshLayerUtils::formatTime( hours, mTemporalProperties->referenceTime(), mTimeSettings );
457 else
458 return QgsMeshLayerUtils::formatTime( hours, QDateTime(), mTimeSettings );
459}
460
462{
464
465 return mDatasetGroupStore->datasetGroupCount();
466}
467
469{
471
472 return mDatasetGroupStore->extraDatasetGroupCount();
473}
474
476{
478
479 return mDatasetGroupStore->datasetGroupIndexes();
480}
481
483{
485
486 return mDatasetGroupStore->enabledDatasetGroupIndexes();
487}
488
490{
492
493 return mDatasetGroupStore->datasetGroupMetadata( index );
494}
495
497{
499
500 return mDatasetGroupStore->datasetCount( index.group() );
501}
502
504{
506
507 return mDatasetGroupStore->datasetMetadata( index );
508}
509
511{
513
514 return mDatasetGroupStore->datasetValue( index, valueIndex );
515}
516
517QgsMeshDataBlock QgsMeshLayer::datasetValues( const QgsMeshDatasetIndex &index, int valueIndex, int count ) const
518{
520
521 return mDatasetGroupStore->datasetValues( index, valueIndex, count );
522}
523
524QgsMesh3DDataBlock QgsMeshLayer::dataset3dValues( const QgsMeshDatasetIndex &index, int faceIndex, int count ) const
525{
527
528 return mDatasetGroupStore->dataset3dValues( index, faceIndex, count );
529}
530
531QgsMeshDataBlock QgsMeshLayer::areFacesActive( const QgsMeshDatasetIndex &index, int faceIndex, int count ) const
532{
534
535 return mDatasetGroupStore->areFacesActive( index, faceIndex, count );
536}
537
538bool QgsMeshLayer::isFaceActive( const QgsMeshDatasetIndex &index, int faceIndex ) const
539{
541
542 return mDatasetGroupStore->isFaceActive( index, faceIndex );
543}
544
545QgsMeshDatasetValue QgsMeshLayer::datasetValue( const QgsMeshDatasetIndex &index, const QgsPointXY &point, double searchRadius ) const
546{
548
550 const QgsTriangularMesh *mesh = triangularMesh();
551
552 if ( mesh && index.isValid() )
553 {
555 {
556 const QgsRectangle searchRectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
557 return dataset1dValue( index, point, searchRadius );
558 }
559 const int faceIndex = mesh->faceIndexForPoint_v2( point ) ;
560 if ( faceIndex >= 0 )
561 {
562 const int nativeFaceIndex = mesh->trianglesToNativeFaces().at( faceIndex );
564 if ( isFaceActive( index, nativeFaceIndex ) )
565 {
566 switch ( dataType )
567 {
569 {
570 value = datasetValue( index, nativeFaceIndex );
571 }
572 break;
573
575 {
576 const QgsMeshFace &face = mesh->triangles()[faceIndex];
577 const int v1 = face[0], v2 = face[1], v3 = face[2];
578 const QgsPoint p1 = mesh->vertices()[v1], p2 = mesh->vertices()[v2], p3 = mesh->vertices()[v3];
579 const QgsMeshDatasetValue val1 = datasetValue( index, v1 );
580 const QgsMeshDatasetValue val2 = datasetValue( index, v2 );
581 const QgsMeshDatasetValue val3 = datasetValue( index, v3 );
582 const double x = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.x(), val2.x(), val3.x(), point );
583 double y = std::numeric_limits<double>::quiet_NaN();
584 const bool isVector = datasetGroupMetadata( index ).isVector();
585 if ( isVector )
586 y = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.y(), val2.y(), val3.y(), point );
587
588 value = QgsMeshDatasetValue( x, y );
589 }
590 break;
591
593 {
594 const QgsMesh3DAveragingMethod *avgMethod = mRendererSettings.averagingMethod();
595 if ( avgMethod )
596 {
597 const QgsMesh3DDataBlock block3d = dataset3dValues( index, nativeFaceIndex, 1 );
598 const QgsMeshDataBlock block2d = avgMethod->calculate( block3d );
599 if ( block2d.isValid() )
600 {
601 value = block2d.value( 0 );
602 }
603 }
604 }
605 break;
606
607 default:
608 break;
609 }
610 }
611 }
612 }
613
614 return value;
615}
616
618{
620
621 QgsMesh3DDataBlock block3d;
622
623 const QgsTriangularMesh *baseTriangularMesh = triangularMesh();
624
625 if ( baseTriangularMesh && dataProvider() && dataProvider()->isValid() && index.isValid() )
626 {
629 {
630 const int faceIndex = baseTriangularMesh->faceIndexForPoint_v2( point );
631 if ( faceIndex >= 0 )
632 {
633 const int nativeFaceIndex = baseTriangularMesh->trianglesToNativeFaces().at( faceIndex );
634 block3d = dataset3dValues( index, nativeFaceIndex, 1 );
635 }
636 }
637 }
638 return block3d;
639}
640
641QgsMeshDatasetValue QgsMeshLayer::dataset1dValue( const QgsMeshDatasetIndex &index, const QgsPointXY &point, double searchRadius ) const
642{
644
646 QgsPointXY projectedPoint;
647 const int selectedIndex = closestEdge( point, searchRadius, projectedPoint );
648 const QgsTriangularMesh *mesh = triangularMesh();
649 if ( selectedIndex >= 0 )
650 {
652 switch ( dataType )
653 {
655 {
656 value = datasetValue( index, selectedIndex );
657 }
658 break;
659
661 {
662 const QgsMeshEdge &edge = mesh->edges()[selectedIndex];
663 const int v1 = edge.first, v2 = edge.second;
664 const QgsPoint p1 = mesh->vertices()[v1], p2 = mesh->vertices()[v2];
665 const QgsMeshDatasetValue val1 = datasetValue( index, v1 );
666 const QgsMeshDatasetValue val2 = datasetValue( index, v2 );
667 const double edgeLength = p1.distance( p2 );
668 const double dist1 = p1.distance( projectedPoint.x(), projectedPoint.y() );
669 value = QgsMeshLayerUtils::interpolateFromVerticesData( dist1 / edgeLength, val1, val2 );
670 }
671 break;
672 default:
673 break;
674 }
675 }
676
677 return value;
678}
679
681{
683
684 if ( mDataProvider )
685 mDataProvider->setTransformContext( transformContext );
687}
688
689QgsMeshDatasetIndex QgsMeshLayer::datasetIndexAtTime( const QgsDateTimeRange &timeRange, int datasetGroupIndex ) const
690{
692
693 if ( ! mTemporalProperties->isActive() )
694 return QgsMeshDatasetIndex( datasetGroupIndex, -1 );
695
696 const QDateTime layerReferenceTime = mTemporalProperties->referenceTime();
697 QDateTime utcTime = timeRange.begin();
698 if ( utcTime.timeSpec() != Qt::UTC )
699 utcTime.setTimeSpec( Qt::UTC );
700 const qint64 startTime = layerReferenceTime.msecsTo( utcTime );
701
702 return mDatasetGroupStore->datasetIndexAtTime( startTime, datasetGroupIndex, mTemporalProperties->matchingMethod() );
703}
704
705QgsMeshDatasetIndex QgsMeshLayer::datasetIndexAtRelativeTime( const QgsInterval &relativeTime, int datasetGroupIndex ) const
706{
708
709 return mDatasetGroupStore->datasetIndexAtTime( relativeTime.seconds() * 1000, datasetGroupIndex, mTemporalProperties->matchingMethod() );
710}
711
712QList<QgsMeshDatasetIndex> QgsMeshLayer::datasetIndexInRelativeTimeInterval( const QgsInterval &startRelativeTime, const QgsInterval &endRelativeTime, int datasetGroupIndex ) const
713{
715
716 qint64 usedRelativeTime1 = startRelativeTime.seconds() * 1000;
717 qint64 usedRelativeTime2 = endRelativeTime.seconds() * 1000;
718
719 //adjust relative time if layer reference time is different from provider reference time
720 if ( mTemporalProperties->referenceTime().isValid() &&
721 mDataProvider &&
722 mDataProvider->isValid() &&
723 mTemporalProperties->referenceTime() != mDataProvider->temporalCapabilities()->referenceTime() )
724 {
725 usedRelativeTime1 = usedRelativeTime1 + mTemporalProperties->referenceTime().msecsTo( mDataProvider->temporalCapabilities()->referenceTime() );
726 usedRelativeTime2 = usedRelativeTime2 + mTemporalProperties->referenceTime().msecsTo( mDataProvider->temporalCapabilities()->referenceTime() );
727 }
728
729 return mDatasetGroupStore->datasetIndexInTimeInterval( usedRelativeTime1, usedRelativeTime2, datasetGroupIndex );
730}
731
732void QgsMeshLayer::applyClassificationOnScalarSettings( const QgsMeshDatasetGroupMetadata &meta, QgsMeshRendererScalarSettings &scalarSettings ) const
733{
735
736 if ( meta.extraOptions().contains( QStringLiteral( "classification" ) ) )
737 {
738 QgsColorRampShader colorRampShader = scalarSettings.colorRampShader();
739 QgsColorRamp *colorRamp = colorRampShader.sourceColorRamp();
740 const QStringList classes = meta.extraOptions()[QStringLiteral( "classification" )].split( QStringLiteral( ";;" ) );
741
742 QString units;
743 if ( meta.extraOptions().contains( QStringLiteral( "units" ) ) )
744 units = meta.extraOptions()[ QStringLiteral( "units" )];
745
746 QVector<QVector<double>> bounds;
747 for ( const QString &classe : classes )
748 {
749 const QStringList boundsStr = classe.split( ',' );
750 QVector<double> bound;
751 for ( const QString &boundStr : boundsStr )
752 bound.append( boundStr.toDouble() );
753 bounds.append( bound );
754 }
755
756 if ( ( bounds.count() == 1 && bounds.first().count() > 2 ) || // at least a class with two value
757 ( bounds.count() > 1 ) ) // or at least two classes
758 {
759 const QVector<double> firstClass = bounds.first();
760 const QVector<double> lastClass = bounds.last();
761 const double minValue = firstClass.count() > 1 ? ( firstClass.first() + firstClass.last() ) / 2 : firstClass.first();
762 const double maxValue = lastClass.count() > 1 ? ( lastClass.first() + lastClass.last() ) / 2 : lastClass.first();
763 const double diff = maxValue - minValue;
764 QList<QgsColorRampShader::ColorRampItem> colorRampItemlist;
765 for ( int i = 0; i < bounds.count(); ++i )
766 {
767 const QVector<double> &boundClass = bounds.at( i );
769 item.value = i + 1;
770 if ( !boundClass.isEmpty() )
771 {
772 const double scalarValue = ( boundClass.first() + boundClass.last() ) / 2;
773 item.color = colorRamp->color( ( scalarValue - minValue ) / diff );
774 if ( i != 0 && i < bounds.count() - 1 ) //The first and last labels are treated after
775 {
776 item.label = QString( ( "%1 - %2 %3" ) ).
777 arg( QString::number( boundClass.first() ) ).
778 arg( QString::number( boundClass.last() ) ).
779 arg( units );
780 }
781 }
782 colorRampItemlist.append( item );
783 }
784 //treat first and last labels
785 if ( firstClass.count() == 1 )
786 colorRampItemlist.first().label = QObject::tr( "below %1 %2" ).
787 arg( QString::number( firstClass.first() ) ).
788 arg( units );
789 else
790 {
791 colorRampItemlist.first().label = QString( ( "%1 - %2 %3" ) ).
792 arg( QString::number( firstClass.first() ) ).
793 arg( QString::number( firstClass.last() ) ).
794 arg( units );
795 }
796
797 if ( lastClass.count() == 1 )
798 colorRampItemlist.last().label = QObject::tr( "above %1 %2" ).
799 arg( QString::number( lastClass.first() ) ).
800 arg( units );
801 else
802 {
803 colorRampItemlist.last().label = QString( ( "%1 - %2 %3" ) ).
804 arg( QString::number( lastClass.first() ) ).
805 arg( QString::number( lastClass.last() ) ).
806 arg( units );
807 }
808
809 colorRampShader.setMinimumValue( 0 );
810 colorRampShader.setMaximumValue( colorRampItemlist.count() - 1 );
811 scalarSettings.setClassificationMinimumMaximum( 0, colorRampItemlist.count() - 1 );
812 colorRampShader.setColorRampItemList( colorRampItemlist );
815 }
816
817 scalarSettings.setColorRampShader( colorRampShader );
819 }
820}
821
823{
825
826 if ( mTemporalProperties->isActive() )
827 return datasetIndexAtTime( timeRange, group >= 0 ? group : mRendererSettings.activeScalarDatasetGroup() );
828 else
829 return QgsMeshDatasetIndex( group >= 0 ? group : mRendererSettings.activeScalarDatasetGroup(), mStaticScalarDatasetIndex );
830}
831
833{
835
836 if ( mTemporalProperties->isActive() )
837 return datasetIndexAtTime( timeRange, group >= 0 ? group : mRendererSettings.activeVectorDatasetGroup() );
838 else
839 return QgsMeshDatasetIndex( group >= 0 ? group : mRendererSettings.activeVectorDatasetGroup(), mStaticVectorDatasetIndex );
840}
841
842void QgsMeshLayer::fillNativeMesh()
843{
845
846 Q_ASSERT( !mNativeMesh );
847
848 mNativeMesh.reset( new QgsMesh() );
849
850 if ( !( dataProvider() && dataProvider()->isValid() ) )
851 return;
852
853 dataProvider()->populateMesh( mNativeMesh.get() );
854}
855
856void QgsMeshLayer::onDatasetGroupsAdded( const QList<int> &datasetGroupIndexes )
857{
859
860 // assign default style to new dataset groups
861 for ( int datasetGroupIndex : datasetGroupIndexes )
862 {
863 if ( !mRendererSettings.hasSettings( datasetGroupIndex ) )
864 assignDefaultStyleToDatasetGroup( datasetGroupIndex );
865 }
866
867 temporalProperties()->setIsActive( mDatasetGroupStore->hasTemporalCapabilities() );
868 emit rendererChanged();
869}
870
871void QgsMeshLayer::onMeshEdited()
872{
874
875 mRendererCache.reset( new QgsMeshLayerRendererCache() );
876 emit layerModified();
879}
880
882{
884
885 return mDatasetGroupStore->datasetGroupTreeItem();
886}
887
889{
891
892 mDatasetGroupStore->setDatasetGroupTreeItem( rootItem );
893 updateActiveDatasetGroups();
894}
895
897{
899
900 return QgsMeshDatasetIndex( group >= 0 ? group : mRendererSettings.activeVectorDatasetGroup(), mStaticVectorDatasetIndex );
901}
902
903void QgsMeshLayer::setReferenceTime( const QDateTime &referenceTime )
904{
906
907 if ( auto *lDataProvider = dataProvider() )
908 mTemporalProperties->setReferenceTime( referenceTime, lDataProvider->temporalCapabilities() );
909 else
910 mTemporalProperties->setReferenceTime( referenceTime, nullptr );
911}
912
919
920int QgsMeshLayer::closestEdge( const QgsPointXY &point, double searchRadius, QgsPointXY &projectedPoint ) const
921{
923
924 const QgsRectangle searchRectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
925 const QgsTriangularMesh *mesh = triangularMesh();
926 // search for the closest edge in search area from point
927 const QList<int> edgeIndexes = mesh->edgeIndexesForRectangle( searchRectangle );
928 int selectedIndex = -1;
929 projectedPoint = QgsPointXY();
930 if ( mesh->contains( QgsMesh::Edge ) &&
931 mDataProvider->isValid() )
932 {
933 double sqrMaxDistFromPoint = pow( searchRadius, 2 );
934 for ( const int edgeIndex : edgeIndexes )
935 {
936 const QgsMeshEdge &edge = mesh->edges().at( edgeIndex );
937 const QgsMeshVertex &vertex1 = mesh->vertices()[edge.first];
938 const QgsMeshVertex &vertex2 = mesh->vertices()[edge.second];
939 QgsPointXY projPoint;
940 const double sqrDist = point.sqrDistToSegment( vertex1.x(), vertex1.y(), vertex2.x(), vertex2.y(), projPoint, 0 );
941 if ( sqrDist < sqrMaxDistFromPoint )
942 {
943 selectedIndex = edgeIndex;
944 projectedPoint = projPoint;
945 sqrMaxDistFromPoint = sqrDist;
946 }
947 }
948 }
949
950 return selectedIndex;
951}
952
953int QgsMeshLayer::closestVertex( const QgsPointXY &point, double searchRadius, QgsPointXY &projectedPoint ) const
954{
956
957 const QgsTriangularMesh *mesh = triangularMesh();
958 int selectedIndex = -1;
959 projectedPoint = QgsPointXY();
960 if ( !mesh )
961 return selectedIndex;
962
963 const QgsRectangle rectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
964 double maxDistance = searchRadius;
965 //attempt to snap on edges's vertices
966 const QList<int> edgeIndexes = mesh->edgeIndexesForRectangle( rectangle );
967 for ( const int edgeIndex : edgeIndexes )
968 {
969 const QgsMeshEdge &edge = mesh->edges().at( edgeIndex );
970 const QgsMeshVertex &vertex1 = mesh->vertices()[edge.first];
971 const QgsMeshVertex &vertex2 = mesh->vertices()[edge.second];
972 const double dist1 = point.distance( vertex1 );
973 const double dist2 = point.distance( vertex2 );
974 if ( dist1 < maxDistance )
975 {
976 maxDistance = dist1;
977 projectedPoint = vertex1;
978 selectedIndex = edge.first;
979 }
980 if ( dist2 < maxDistance )
981 {
982 maxDistance = dist2;
983 projectedPoint = vertex2;
984 selectedIndex = edge.second;
985 }
986 }
987
988 //attempt to snap on face's vertices
989 const QList<int> faceIndexes = mesh->faceIndexesForRectangle( rectangle );
990 for ( const int faceIndex : faceIndexes )
991 {
992 const QgsMeshFace &face = mesh->triangles().at( faceIndex );
993 for ( int i = 0; i < 3; ++i )
994 {
995 const QgsMeshVertex &vertex = mesh->vertices()[face.at( i )];
996 const double dist = point.distance( vertex );
997 if ( dist < maxDistance )
998 {
999 maxDistance = dist;
1000 projectedPoint = vertex;
1001 selectedIndex = face.at( i );
1002 }
1003 }
1004 }
1005
1006 return selectedIndex;
1007}
1008
1009int QgsMeshLayer::closestFace( const QgsPointXY &point, double searchRadius, QgsPointXY &projectedPoint ) const
1010{
1012
1013 const QgsTriangularMesh *mesh = triangularMesh();
1014 int selectedIndex = -1;
1015 projectedPoint = QgsPointXY();
1016 if ( !mesh )
1017 return selectedIndex;
1018
1019 const QgsRectangle rectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
1020 double maxDistance = std::numeric_limits<double>::max();
1021
1022 const QList<int> faceIndexes = mesh->faceIndexesForRectangle( rectangle );
1023 for ( const int faceIndex : faceIndexes )
1024 {
1025 const int nativefaceIndex = mesh->trianglesToNativeFaces().at( faceIndex );
1026 if ( nativefaceIndex < 0 && nativefaceIndex >= mesh->faceCentroids().count() )
1027 continue;
1028 const QgsPointXY centroid = mesh->faceCentroids()[nativefaceIndex];
1029 const double dist = point.distance( centroid );
1030 if ( dist < maxDistance )
1031 {
1032 maxDistance = dist;
1033 projectedPoint = centroid;
1034 selectedIndex = nativefaceIndex;
1035 }
1036 }
1037
1038 return selectedIndex;
1039}
1040
1042{
1044
1045 mDatasetGroupStore->resetDatasetGroupTreeItem();
1046 updateActiveDatasetGroups();
1047}
1048
1050{
1052
1053 if ( !mDataProvider )
1054 return QgsInterval();
1055 const int groupCount = mDataProvider->datasetGroupCount();
1056 for ( int i = 0; i < groupCount; ++i )
1057 {
1058 const qint64 timeStep = mDataProvider->temporalCapabilities()->firstTimeStepDuration( i );
1059 if ( timeStep > 0 )
1061 }
1062
1063 return QgsInterval();
1064}
1065
1067{
1069
1070 const qint64 time = mDatasetGroupStore->datasetRelativeTime( index );
1071
1072 if ( time == INVALID_MESHLAYER_TIME )
1073 return QgsInterval();
1074 else
1076}
1077
1079{
1081
1082 return mDatasetGroupStore->datasetRelativeTime( index );
1083}
1084
1085static QString detailsErrorMessage( const QgsMeshEditingError &error )
1086{
1087 QString message;
1088
1089 switch ( error.errorType )
1090 {
1092 break;
1094 message = QObject::tr( "Face %1 invalid" ).arg( error.elementIndex );
1095 break;
1097 message = QObject::tr( "Too many vertices for face %1" ).arg( error.elementIndex );
1098 break;
1100 message = QObject::tr( "Face %1 is flat" ).arg( error.elementIndex );
1101 break;
1103 message = QObject::tr( "Vertex %1 is a unique shared vertex" ).arg( error.elementIndex );
1104 break;
1106 message = QObject::tr( "Vertex %1 is invalid" ).arg( error.elementIndex );
1107 break;
1109 message = QObject::tr( "Face %1 is manifold" ).arg( error.elementIndex );
1110 break;
1111 }
1112
1113 return message;
1114}
1115
1117{
1119
1121 return startFrameEditing( transform, error, false );
1122}
1123
1125{
1127
1128 if ( !supportsEditing() )
1129 {
1130 QgsMessageLog::logMessage( QObject::tr( "Mesh layer \"%1\" not support mesh editing" ).arg( name() ) );
1131 return false;
1132 }
1133
1134 if ( mMeshEditor )
1135 {
1136 QgsMessageLog::logMessage( QObject::tr( "Mesh layer \"%1\" already in editing mode" ).arg( name() ) );
1137 return false;
1138 }
1139
1140 mSimplificationSettings.setEnabled( false );
1141
1142 updateTriangularMesh( transform );
1143
1144 mMeshEditor = new QgsMeshEditor( this );
1145
1146 if ( fixErrors )
1147 {
1148 mRendererCache.reset(); // fixing errors could lead to remove faces/vertices
1149 error = mMeshEditor->initializeWithErrorsFix();
1150 }
1151 else
1152 error = mMeshEditor->initialize();
1153
1154 if ( error.errorType != Qgis::MeshEditingErrorType::NoError )
1155 {
1156 mMeshEditor->deleteLater();
1157 mMeshEditor = nullptr;
1158
1159 QgsMessageLog::logMessage( QObject::tr( "Unable to start editing of mesh layer \"%1\": %2" ).
1160 arg( name(), detailsErrorMessage( error ) ), QString(), Qgis::MessageLevel::Critical );
1161 return false;
1162 }
1163
1164 // During editing, we don't need anymore the provider data. Mesh frame data is stored in the mesh editor.
1165 mDataProvider->close();
1166
1167 // All dataset group are removed and replace by a unique virtual dataset group that provide vertices elevation value.
1168 mExtraDatasetUri.clear();
1169 mDatasetGroupStore.reset( new QgsMeshDatasetGroupStore( this ) );
1170
1171 std::unique_ptr<QgsMeshDatasetGroup> zValueDatasetGroup( mMeshEditor->createZValueDatasetGroup() );
1172 if ( mDatasetGroupStore->addDatasetGroup( zValueDatasetGroup.get() ) )
1173 zValueDatasetGroup.release();
1174
1176
1177 connect( mMeshEditor, &QgsMeshEditor::meshEdited, this, &QgsMeshLayer::onMeshEdited );
1178
1179 emit dataChanged();
1180 emit editingStarted();
1181
1182 return true;
1183}
1184
1185bool QgsMeshLayer::commitFrameEditing( const QgsCoordinateTransform &transform, bool continueEditing )
1186{
1188
1190 QString detailsError;
1191 if ( !mMeshEditor->checkConsistency( error ) )
1192 {
1193 if ( error.errorType == Qgis::MeshEditingErrorType::NoError )
1194 detailsError = tr( "Unknown inconsistent mesh error" );
1195 }
1196 else
1197 {
1198 error = QgsTopologicalMesh::checkTopology( *mNativeMesh, mMeshEditor->maximumVerticesPerFace() );
1199 detailsError = detailsErrorMessage( error );
1200 }
1201
1202 if ( !detailsError.isEmpty() )
1203 {
1204 QgsMessageLog::logMessage( QObject::tr( "Edited mesh layer \"%1\" can't be save due to an error: %2" ).
1205 arg( name(), detailsError ), QString(), Qgis::MessageLevel::Critical );
1206 return false;
1207 }
1208
1209 stopFrameEditing( transform );
1210
1211 if ( !mDataProvider )
1212 return false;
1213
1214 const bool res = mDataProvider->saveMeshFrame( *mNativeMesh.get() );
1215
1216 if ( continueEditing )
1217 {
1218 mMeshEditor->initialize();
1219 emit layerModified();
1220 return res;
1221 }
1222
1223 mMeshEditor->deleteLater();
1224 mMeshEditor = nullptr;
1225 emit editingStopped();
1226
1227 mDataProvider->reloadData();
1228 mDataProvider->populateMesh( mNativeMesh.get() );
1229 mDatasetGroupStore.reset( new QgsMeshDatasetGroupStore( this ) );
1230 mDatasetGroupStore->setPersistentProvider( mDataProvider, QStringList() );
1232 return true;
1233}
1234
1235bool QgsMeshLayer::rollBackFrameEditing( const QgsCoordinateTransform &transform, bool continueEditing )
1236{
1238
1239 stopFrameEditing( transform );
1240
1241 if ( !mDataProvider )
1242 return false;
1243
1244 mTriangularMeshes.clear();
1245 mDataProvider->reloadData();
1246 mDataProvider->populateMesh( mNativeMesh.get() );
1247 updateTriangularMesh( transform );
1248 mRendererCache.reset( new QgsMeshLayerRendererCache() );
1250
1251 if ( continueEditing )
1252 {
1253 mMeshEditor->resetTriangularMesh( triangularMesh() );
1254 return mMeshEditor->initialize() == QgsMeshEditingError();
1255 }
1256 else
1257 {
1258 mMeshEditor->deleteLater();
1259 mMeshEditor = nullptr;
1260 emit editingStopped();
1261
1262 mDatasetGroupStore.reset( new QgsMeshDatasetGroupStore( this ) );
1263 mDatasetGroupStore->setPersistentProvider( mDataProvider, QStringList() );
1265 emit dataChanged();
1266 return true;
1267 }
1268}
1269
1271{
1273
1274 if ( !mMeshEditor )
1275 return;
1276
1277 mMeshEditor->stopEditing();
1278 mTriangularMeshes.at( 0 )->update( mNativeMesh.get(), transform );
1279 mRendererCache.reset( new QgsMeshLayerRendererCache() );
1280}
1281
1282bool QgsMeshLayer::reindex( const QgsCoordinateTransform &transform, bool renumber )
1283{
1285
1286 if ( !mMeshEditor )
1287 return false;
1288
1289 if ( !mMeshEditor->reindex( renumber ) )
1290 return false;
1291
1292 mTriangularMeshes.clear();
1293 mTriangularMeshes.emplace_back( new QgsTriangularMesh );
1294 mTriangularMeshes.at( 0 )->update( mNativeMesh.get(), transform );
1295 mRendererCache.reset( new QgsMeshLayerRendererCache() );
1296 mMeshEditor->resetTriangularMesh( mTriangularMeshes.at( 0 ).get() );
1297
1298 return true;
1299}
1300
1302{
1304
1305 return mMeshEditor;
1306}
1307
1309{
1311
1312 if ( mMeshEditor )
1313 return mMeshEditor->isModified();
1314
1315 return false;
1316}
1317
1319{
1321
1322 switch ( type )
1323 {
1325 return meshVertexCount() != 0;
1327 return meshEdgeCount() != 0;
1329 return meshFaceCount() != 0;
1330 }
1331 return false;
1332}
1333
1335{
1337
1338 if ( mMeshEditor )
1339 return mMeshEditor->validVerticesCount();
1340 else if ( mDataProvider )
1341 return mDataProvider->vertexCount();
1342 else return 0;
1343}
1344
1346{
1348
1349 if ( mMeshEditor )
1350 return mMeshEditor->validFacesCount();
1351 else if ( mDataProvider )
1352 return mDataProvider->faceCount();
1353 else return 0;
1354}
1355
1357{
1359
1360 if ( mMeshEditor )
1361 return mNativeMesh->edgeCount();
1362 else if ( mDataProvider )
1363 return mDataProvider->edgeCount();
1364 else return 0;
1365}
1366
1367void QgsMeshLayer::updateActiveDatasetGroups()
1368{
1370
1371 QgsMeshDatasetGroupTreeItem *treeItem = mDatasetGroupStore->datasetGroupTreeItem();
1372
1373 if ( !mDatasetGroupStore->datasetGroupTreeItem() )
1374 return;
1375
1377 const int oldActiveScalar = settings.activeScalarDatasetGroup();
1378 const int oldActiveVector = settings.activeVectorDatasetGroup();
1379
1380 QgsMeshDatasetGroupTreeItem *activeScalarItem =
1381 treeItem->childFromDatasetGroupIndex( oldActiveScalar );
1382
1383 if ( !activeScalarItem && treeItem->childCount() > 0 && oldActiveScalar != -1 )
1384 activeScalarItem = treeItem->child( 0 );
1385
1386 if ( activeScalarItem && !activeScalarItem->isEnabled() )
1387 {
1388 for ( int i = 0; i < treeItem->childCount(); ++i )
1389 {
1390 activeScalarItem = treeItem->child( i );
1391 if ( activeScalarItem->isEnabled() )
1392 break;
1393 else
1394 activeScalarItem = nullptr;
1395 }
1396 }
1397
1398 if ( activeScalarItem )
1399 settings.setActiveScalarDatasetGroup( activeScalarItem->datasetGroupIndex() );
1400 else
1401 settings.setActiveScalarDatasetGroup( -1 );
1402
1403 QgsMeshDatasetGroupTreeItem *activeVectorItem =
1404 treeItem->childFromDatasetGroupIndex( oldActiveVector );
1405
1406 if ( !( activeVectorItem && activeVectorItem->isEnabled() ) )
1407 settings.setActiveVectorDatasetGroup( -1 );
1408
1409 setRendererSettings( settings );
1410
1411 if ( oldActiveScalar != settings.activeScalarDatasetGroup() )
1413 if ( oldActiveVector != settings.activeVectorDatasetGroup() )
1415}
1416
1417QgsMeshRendererSettings QgsMeshLayer::accordSymbologyWithGroupName( const QgsMeshRendererSettings &settings, const QMap<QString, int> &nameToIndex )
1418{
1419 QString activeScalarName;
1420 QString activeVectorName;
1421 QgsMeshRendererSettings consistentSettings = settings;
1422 int activeScalar = consistentSettings.activeScalarDatasetGroup();
1423 int activeVector = consistentSettings.activeVectorDatasetGroup();
1424
1425 for ( auto it = nameToIndex.constBegin(); it != nameToIndex.constEnd(); ++it )
1426 {
1427 int index = it.value();
1428 const QString name = it.key() ;
1429 int globalIndex = mDatasetGroupStore->indexFromGroupName( name );
1430 if ( globalIndex >= 0 )
1431 {
1432 QgsMeshRendererScalarSettings scalarSettings = settings.scalarSettings( index );
1433 consistentSettings.setScalarSettings( globalIndex, scalarSettings );
1434 if ( settings.hasVectorSettings( it.value() ) && mDatasetGroupStore->datasetGroupMetadata( globalIndex ).isVector() )
1435 {
1436 QgsMeshRendererVectorSettings vectorSettings = settings.vectorSettings( index );
1437 consistentSettings.setVectorSettings( globalIndex, vectorSettings );
1438 }
1439 }
1440 else
1441 {
1442 consistentSettings.removeScalarSettings( index );
1443 if ( settings.hasVectorSettings( it.value() ) )
1444 consistentSettings.removeVectorSettings( index );
1445 }
1446
1447 if ( index == activeScalar )
1448 activeScalarName = name;
1449 if ( index == activeVector )
1450 activeVectorName = name;
1451 }
1452
1453 const QList<int> globalIndexes = datasetGroupsIndexes();
1454 for ( int globalIndex : globalIndexes )
1455 {
1456 const QString name = mDatasetGroupStore->groupName( globalIndex );
1457 if ( !nameToIndex.contains( name ) )
1458 {
1459 consistentSettings.setScalarSettings( globalIndex, mRendererSettings.scalarSettings( globalIndex ) );
1460 if ( mDatasetGroupStore->datasetGroupMetadata( globalIndex ).isVector() )
1461 {
1462 consistentSettings.setVectorSettings( globalIndex, mRendererSettings.vectorSettings( globalIndex ) );
1463 }
1464 }
1465 }
1466
1467 if ( !activeScalarName.isEmpty() )
1468 consistentSettings.setActiveScalarDatasetGroup( mDatasetGroupStore->indexFromGroupName( activeScalarName ) );
1469 if ( !activeVectorName.isEmpty() )
1470 consistentSettings.setActiveVectorDatasetGroup( mDatasetGroupStore->indexFromGroupName( activeVectorName ) );
1471
1472 return consistentSettings;
1473}
1474
1475void QgsMeshLayer::setDataSourcePrivate( const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, Qgis::DataProviderReadFlags flags )
1476{
1478
1479 mDataSource = dataSource;
1480 mLayerName = baseName;
1481 setProviderType( provider );
1482
1483 if ( !mDataSource.isEmpty() && !provider.isEmpty() )
1484 setDataProvider( provider, options, flags );
1485}
1486
1487QgsPointXY QgsMeshLayer::snapOnElement( QgsMesh::ElementType elementType, const QgsPointXY &point, double searchRadius )
1488{
1490
1491 QgsPointXY projectedPoint;
1492 closestElement( elementType, point, searchRadius, projectedPoint );
1493 return projectedPoint;
1494}
1495
1496int QgsMeshLayer::closestElement( QgsMesh::ElementType elementType, const QgsPointXY &point, double searchRadius, QgsPointXY &projectedPoint ) const
1497{
1499
1500 switch ( elementType )
1501 {
1502 case QgsMesh::Vertex:
1503 return closestVertex( point, searchRadius, projectedPoint );
1504 case QgsMesh::Edge:
1505 return closestEdge( point, searchRadius, projectedPoint );
1506 case QgsMesh::Face:
1507 return closestFace( point, searchRadius, projectedPoint );
1508 }
1509 return -1;
1510}
1511
1513{
1515
1516 if ( !mNativeMesh )
1517 {
1518 // lazy loading of mesh data
1519 fillNativeMesh();
1520 }
1521
1522 QList<int> ret;
1523
1524 if ( !mNativeMesh )
1525 return ret;
1526
1527 QgsExpressionContext context;
1528 std::unique_ptr<QgsExpressionContextScope> expScope( QgsExpressionContextUtils::meshExpressionScope( QgsMesh::Vertex ) );
1529 context.appendScope( expScope.release() );
1530 context.lastScope()->setVariable( QStringLiteral( "_native_mesh" ), QVariant::fromValue( *mNativeMesh ) );
1531
1532 expression.prepare( &context );
1533
1534 for ( int i = 0; i < mNativeMesh->vertexCount(); ++i )
1535 {
1536 context.lastScope()->setVariable( QStringLiteral( "_mesh_vertex_index" ), i, false );
1537
1538 if ( expression.evaluate( &context ).toBool() )
1539 ret.append( i );
1540 }
1541
1542 return ret;
1543}
1544
1546{
1548
1549 if ( !mNativeMesh )
1550 {
1551 // lazy loading of mesh data
1552 fillNativeMesh();
1553 }
1554
1555 QList<int> ret;
1556
1557 if ( !mNativeMesh )
1558 return ret;
1559
1560 QgsExpressionContext context;
1561 std::unique_ptr<QgsExpressionContextScope> expScope( QgsExpressionContextUtils::meshExpressionScope( QgsMesh::Face ) );
1562 context.appendScope( expScope.release() );
1563 context.lastScope()->setVariable( QStringLiteral( "_native_mesh" ), QVariant::fromValue( *mNativeMesh ) );
1564
1565 expression.prepare( &context );
1566
1567 for ( int i = 0; i < mNativeMesh->faceCount(); ++i )
1568 {
1569 context.lastScope()->setVariable( QStringLiteral( "_mesh_face_index" ), i, false );
1570
1571 if ( expression.evaluate( &context ).toBool() )
1572 ret.append( i );
1573 }
1574
1575 return ret;
1576}
1577
1579{
1581
1582 return QgsMeshDatasetIndex( group >= 0 ? group : mRendererSettings.activeScalarDatasetGroup(), mStaticScalarDatasetIndex );
1583}
1584
1586{
1588
1589 const int oldActiveVector = mRendererSettings.activeVectorDatasetGroup();
1590
1591 mStaticVectorDatasetIndex = staticVectorDatasetIndex.dataset();
1593
1594 if ( oldActiveVector != mRendererSettings.activeVectorDatasetGroup() )
1596}
1597
1599{
1601
1602 const int oldActiveScalar = mRendererSettings.activeScalarDatasetGroup();
1603
1604 mStaticScalarDatasetIndex = staticScalarDatasetIndex.dataset();
1606
1607 if ( oldActiveScalar != mRendererSettings.activeScalarDatasetGroup() )
1609}
1610
1617
1619{
1621
1622 mSimplificationSettings = simplifySettings;
1623}
1624
1625static QgsColorRamp *_createDefaultColorRamp()
1626{
1627 QgsColorRamp *ramp = QgsStyle::defaultStyle()->colorRamp( QStringLiteral( "Plasma" ) );
1628 if ( ramp )
1629 return ramp;
1630
1631 // definition of "Plasma" color ramp (in case it is not available in the style for some reason)
1632 QVariantMap props;
1633 props["color1"] = "13,8,135,255";
1634 props["color2"] = "240,249,33,255";
1635 props["stops"] =
1636 "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:"
1637 "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:"
1638 "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:"
1639 "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:"
1640 "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:"
1641 "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:"
1642 "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:"
1643 "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:"
1644 "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:"
1645 "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";
1646 return QgsGradientColorRamp::create( props );
1647}
1648
1649void QgsMeshLayer::assignDefaultStyleToDatasetGroup( int groupIndex )
1650{
1652
1654 const double groupMin = metadata.minimum();
1655 const double groupMax = metadata.maximum();
1656
1657 QgsColorRampShader fcn( groupMin, groupMax, _createDefaultColorRamp() );
1658 fcn.classifyColorRamp( 5, -1, QgsRectangle(), nullptr );
1659
1660 QgsMeshRendererScalarSettings scalarSettings;
1661 scalarSettings.setClassificationMinimumMaximum( groupMin, groupMax );
1662 scalarSettings.setColorRampShader( fcn );
1663 QgsInterpolatedLineWidth edgeStrokeWidth;
1664 edgeStrokeWidth.setMinimumValue( groupMin );
1665 edgeStrokeWidth.setMaximumValue( groupMax );
1666 const QgsInterpolatedLineColor edgeStrokeColor( fcn );
1667 const QgsInterpolatedLineRenderer edgeStrokePen;
1668 scalarSettings.setEdgeStrokeWidth( edgeStrokeWidth );
1669 mRendererSettings.setScalarSettings( groupIndex, scalarSettings );
1670
1671 if ( metadata.isVector() )
1672 {
1673 QgsMeshRendererVectorSettings vectorSettings;
1674 vectorSettings.setColorRampShader( fcn );
1675 mRendererSettings.setVectorSettings( groupIndex, vectorSettings );
1676 }
1677}
1678
1680{
1682
1683 // Triangular mesh
1684 updateTriangularMesh( rendererContext.coordinateTransform() );
1685
1686 // Build overview triangular meshes if needed
1687 createSimplifiedMeshes();
1688
1689 // Cache
1690 if ( !mRendererCache )
1691 mRendererCache.reset( new QgsMeshLayerRendererCache() );
1692
1693 return new QgsMeshLayerRenderer( this, rendererContext );
1694}
1695
1697{
1698 if ( rendererContext.isTemporal() )
1699 return activeScalarDatasetAtTime( rendererContext.temporalRange(), mRendererSettings.activeScalarDatasetGroup() );
1700 else
1701 return staticScalarDatasetIndex( mRendererSettings.activeScalarDatasetGroup() );
1702}
1703
1704bool QgsMeshLayer::minimumMaximumActiveScalarDataset( const QgsRectangle &extent, const QgsMeshDatasetIndex &datasetIndex, double &min, double &max )
1705{
1706
1707 if ( extent.isNull() || !this->extent().intersects( extent ) )
1708 return false;
1709
1711
1712 if ( ! tMesh )
1713 {
1714 return false;
1715 }
1716
1717 QVector<double> scalarDatasetValues;
1719
1720 if ( !metadata.isScalar() )
1721 {
1722 return false;
1723 }
1724
1725 QgsMeshDatasetGroupMetadata::DataType scalarDataType = QgsMeshLayerUtils::datasetValuesType( metadata.dataType() );
1726
1727 if ( !datasetIndex.isValid() )
1728 {
1729 return false;
1730 }
1731
1732 // populate scalar values
1733 const int count = QgsMeshLayerUtils::datasetValuesCount( mNativeMesh.get(), scalarDataType );
1734 const QgsMeshDataBlock vals = QgsMeshLayerUtils::datasetValues(
1735 this,
1736 datasetIndex,
1737 0,
1738 count );
1739
1740 if ( vals.isValid() )
1741 {
1742 // vals could be scalar or vectors, for contour rendering we want always magnitude
1743 scalarDatasetValues = QgsMeshLayerUtils::calculateMagnitudes( vals );
1744 }
1745 else
1746 {
1747 scalarDatasetValues = QVector<double>( count, std::numeric_limits<double>::quiet_NaN() );
1748 }
1749
1750 QList<int> intersectedFacesIndices = tMesh->faceIndexesForRectangle( extent );
1751
1752 if ( intersectedFacesIndices.isEmpty() )
1753 {
1754 return false;
1755 }
1756
1757 min = std::numeric_limits<double>::max();
1758 max = -std::numeric_limits<double>::max();
1759
1760 double value;
1761
1762 for ( int intersectedFaceIndex : intersectedFacesIndices )
1763 {
1764 QgsMeshFace face = tMesh->triangles().at( intersectedFaceIndex );
1765
1767 {
1768 value = scalarDatasetValues.at( tMesh->trianglesToNativeFaces().at( intersectedFaceIndex ) );
1769 min = std::min( min, value );
1770 max = std::max( max, value );
1771 }
1773 {
1774 QgsMeshVertex vertex;
1775
1776 for ( int vertexIndex : face )
1777 {
1778 value = scalarDatasetValues.at( vertexIndex );
1779 min = std::min( min, value );
1780 max = std::max( max, value );
1781 }
1782 }
1783 }
1784
1785 return true;
1786}
1787
1794
1795void QgsMeshLayer::checkSymbologyConsistency()
1796{
1798
1799 const QList<int> groupIndexes = mDatasetGroupStore->datasetGroupIndexes();
1800 if ( !groupIndexes.contains( mRendererSettings.activeScalarDatasetGroup() ) &&
1801 mRendererSettings.activeScalarDatasetGroup() != -1 )
1802 {
1803 if ( !groupIndexes.empty() )
1804 mRendererSettings.setActiveScalarDatasetGroup( groupIndexes.first() );
1805 else
1806 mRendererSettings.setActiveScalarDatasetGroup( -1 );
1807 }
1808
1809 if ( !groupIndexes.contains( mRendererSettings.activeVectorDatasetGroup() ) &&
1810 mRendererSettings.activeVectorDatasetGroup() != -1 )
1811 {
1812 mRendererSettings.setActiveVectorDatasetGroup( -1 );
1813 }
1814}
1815
1816bool QgsMeshLayer::readSymbology( const QDomNode &node, QString &errorMessage,
1818{
1820
1821 Q_UNUSED( errorMessage )
1822 // TODO: implement categories for raster layer
1823
1824 const QDomElement elem = node.toElement();
1825
1826 readCommonStyle( elem, context, categories );
1827
1829 const QDomElement elemRendererSettings = elem.firstChildElement( "mesh-renderer-settings" );
1830 if ( !elemRendererSettings.isNull() )
1831 rendererSettings.readXml( elemRendererSettings, context );
1832
1833 QMap<QString, int> groupNameToGlobalIndex;
1834 QDomElement nameToIndexElem = elem.firstChildElement( "name-to-global-index" );
1835 while ( !nameToIndexElem.isNull() )
1836 {
1837 const QString name = nameToIndexElem.attribute( QStringLiteral( "name" ) );
1838 int globalIndex = nameToIndexElem.attribute( QStringLiteral( "global-index" ) ).toInt();
1839 groupNameToGlobalIndex.insert( name, globalIndex );
1840 nameToIndexElem = nameToIndexElem.nextSiblingElement( QStringLiteral( "name-to-global-index" ) );
1841 }
1842
1843 mRendererSettings = accordSymbologyWithGroupName( rendererSettings, groupNameToGlobalIndex );
1844
1845 checkSymbologyConsistency();
1846
1847 const QDomElement elemSimplifySettings = elem.firstChildElement( "mesh-simplify-settings" );
1848 if ( !elemSimplifySettings.isNull() )
1849 mSimplificationSettings.readXml( elemSimplifySettings, context );
1850
1851 // get and set the blend mode if it exists
1852 const QDomNode blendModeNode = node.namedItem( QStringLiteral( "blendMode" ) );
1853 if ( !blendModeNode.isNull() )
1854 {
1855 const QDomElement e = blendModeNode.toElement();
1856 setBlendMode( QgsPainting::getCompositionMode( static_cast< Qgis::BlendMode >( e.text().toInt() ) ) );
1857 }
1858
1859 // read labeling definition
1860 if ( categories.testFlag( Labeling ) )
1861 {
1862 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Labeling" ) );
1863
1864 QDomElement labelingElement = node.firstChildElement( QStringLiteral( "labeling" ) );
1865 if ( !labelingElement.isNull() )
1866 {
1868 mLabelsEnabled = node.toElement().attribute( QStringLiteral( "labelsEnabled" ), QStringLiteral( "0" ) ).toInt();
1870 }
1871 }
1872
1873 // get and set the layer transparency
1874 if ( categories.testFlag( Rendering ) )
1875 {
1876 const QDomNode layerOpacityNode = node.namedItem( QStringLiteral( "layerOpacity" ) );
1877 if ( !layerOpacityNode.isNull() )
1878 {
1879 const QDomElement e = layerOpacityNode.toElement();
1880 setOpacity( e.text().toDouble() );
1881 }
1882 }
1883
1884 return true;
1885}
1886
1887bool QgsMeshLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage,
1888 const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1889{
1891
1892 Q_UNUSED( errorMessage )
1893 // TODO: implement categories for raster layer
1894
1895 QDomElement elem = node.toElement();
1896
1897 writeCommonStyle( elem, doc, context, categories );
1898
1899 const QDomElement elemRendererSettings = mRendererSettings.writeXml( doc, context );
1900 elem.appendChild( elemRendererSettings );
1901
1902 const QList<int> groupIndexes = datasetGroupsIndexes();
1903 // we store the relation between name and indexes to be able to retrieve the consistency between name and symbology
1904 for ( int index : groupIndexes )
1905 {
1906 QDomElement elemNameToIndex = doc.createElement( QStringLiteral( "name-to-global-index" ) );
1907 elemNameToIndex.setAttribute( QStringLiteral( "name" ), mDatasetGroupStore->groupName( index ) );
1908 elemNameToIndex.setAttribute( QStringLiteral( "global-index" ), index );
1909 elem.appendChild( elemNameToIndex );
1910 }
1911
1912 const QDomElement elemSimplifySettings = mSimplificationSettings.writeXml( doc, context );
1913 elem.appendChild( elemSimplifySettings );
1914
1915 // add blend mode node
1916 QDomElement blendModeElement = doc.createElement( QStringLiteral( "blendMode" ) );
1917 const QDomText blendModeText = doc.createTextNode( QString::number( static_cast< int >( QgsPainting::getBlendModeEnum( blendMode() ) ) ) );
1918 blendModeElement.appendChild( blendModeText );
1919 node.appendChild( blendModeElement );
1920
1921 if ( categories.testFlag( Labeling ) )
1922 {
1923 if ( mLabeling )
1924 {
1925 QDomElement labelingElement = mLabeling->save( doc, context );
1926 elem.appendChild( labelingElement );
1927 }
1928 elem.setAttribute( QStringLiteral( "labelsEnabled" ), mLabelsEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
1929 }
1930
1931 // add the layer opacity
1932 if ( categories.testFlag( Rendering ) )
1933 {
1934 QDomElement layerOpacityElem = doc.createElement( QStringLiteral( "layerOpacity" ) );
1935 const QDomText layerOpacityText = doc.createTextNode( QString::number( opacity() ) );
1936 layerOpacityElem.appendChild( layerOpacityText );
1937 node.appendChild( layerOpacityElem );
1938 }
1939
1940 return true;
1941}
1942
1943bool QgsMeshLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1944{
1946
1947 return writeSymbology( node, doc, errorMessage, context, categories );
1948}
1949
1950bool QgsMeshLayer::readStyle( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
1951{
1953
1954 return readSymbology( node, errorMessage, context, categories );
1955}
1956
1957QString QgsMeshLayer::decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const
1958{
1960
1961 return QgsProviderRegistry::instance()->relativeToAbsoluteUri( provider, source, context );
1962}
1963
1964QString QgsMeshLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
1965{
1967
1969}
1970
1971bool QgsMeshLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &context )
1972{
1974
1975 QgsDebugMsgLevel( QStringLiteral( "Datasource in QgsMeshLayer::readXml: %1" ).arg( mDataSource.toLocal8Bit().data() ), 3 );
1976
1977 //process provider key
1978 const QDomNode pkeyNode = layer_node.namedItem( QStringLiteral( "provider" ) );
1979
1980 if ( pkeyNode.isNull() )
1981 {
1982 mProviderKey.clear();
1983 }
1984 else
1985 {
1986 const QDomElement pkeyElt = pkeyNode.toElement();
1987 mProviderKey = pkeyElt.text();
1988 }
1989
1991 {
1992 return false;
1993 }
1994
1995 const QgsDataProvider::ProviderOptions providerOptions;
1997
1998 const QDomElement elemExtraDatasets = layer_node.firstChildElement( QStringLiteral( "extra-datasets" ) );
1999 if ( !elemExtraDatasets.isNull() )
2000 {
2001 QDomElement elemUri = elemExtraDatasets.firstChildElement( QStringLiteral( "uri" ) );
2002 while ( !elemUri.isNull() )
2003 {
2004 const QString uri = context.pathResolver().readPath( elemUri.text() );
2005 mExtraDatasetUri.append( uri );
2006 elemUri = elemUri.nextSiblingElement( QStringLiteral( "uri" ) );
2007 }
2008 }
2009
2010 if ( pkeyNode.toElement().hasAttribute( QStringLiteral( "time-unit" ) ) )
2011 mTemporalUnit = static_cast<Qgis::TemporalUnit>( pkeyNode.toElement().attribute( QStringLiteral( "time-unit" ) ).toInt() );
2012
2013 // read dataset group store
2014 const QDomElement elemDatasetGroupsStore = layer_node.firstChildElement( QStringLiteral( "mesh-dataset-groups-store" ) );
2015 if ( elemDatasetGroupsStore.isNull() )
2017 else
2018 mDatasetGroupStore->readXml( elemDatasetGroupsStore, context );
2019
2020 setDataProvider( mProviderKey, providerOptions, flags );
2021
2022 QString errorMsg;
2023 readSymbology( layer_node, errorMsg, context );
2024
2025 if ( !mTemporalProperties->timeExtent().begin().isValid() || mTemporalProperties->alwaysLoadReferenceTimeFromSource() )
2027
2028 // read static dataset
2029 const QDomElement elemStaticDataset = layer_node.firstChildElement( QStringLiteral( "static-active-dataset" ) );
2030 if ( elemStaticDataset.hasAttribute( QStringLiteral( "scalar" ) ) )
2031 {
2032 mStaticScalarDatasetIndex = elemStaticDataset.attribute( QStringLiteral( "scalar" ) ).toInt();
2033 }
2034 if ( elemStaticDataset.hasAttribute( QStringLiteral( "vector" ) ) )
2035 {
2036 mStaticVectorDatasetIndex = elemStaticDataset.attribute( QStringLiteral( "vector" ) ).toInt();
2037 }
2038
2039 return isValid(); // should be true if read successfully
2040}
2041
2042bool QgsMeshLayer::writeXml( QDomNode &layer_node, QDomDocument &document, const QgsReadWriteContext &context ) const
2043{
2045
2046 // first get the layer element so that we can append the type attribute
2047 QDomElement mapLayerNode = layer_node.toElement();
2048
2049 if ( mapLayerNode.isNull() || ( QLatin1String( "maplayer" ) != mapLayerNode.nodeName() ) )
2050 {
2051 QgsDebugMsgLevel( QStringLiteral( "can't find <maplayer>" ), 2 );
2052 return false;
2053 }
2054
2055 mapLayerNode.setAttribute( QStringLiteral( "type" ), QgsMapLayerFactory::typeToString( Qgis::LayerType::Mesh ) );
2056
2057 // add provider node
2058 if ( mDataProvider )
2059 {
2060 QDomElement provider = document.createElement( QStringLiteral( "provider" ) );
2061 const QDomText providerText = document.createTextNode( providerType() );
2062 provider.appendChild( providerText );
2063 layer_node.appendChild( provider );
2064 provider.setAttribute( QStringLiteral( "time-unit" ), static_cast< int >( mDataProvider->temporalCapabilities()->temporalUnit() ) );
2065
2066 const QStringList extraDatasetUris = mDataProvider->extraDatasets();
2067 QDomElement elemExtraDatasets = document.createElement( QStringLiteral( "extra-datasets" ) );
2068 for ( const QString &uri : extraDatasetUris )
2069 {
2070 const QString path = context.pathResolver().writePath( uri );
2071 QDomElement elemUri = document.createElement( QStringLiteral( "uri" ) );
2072 elemUri.appendChild( document.createTextNode( path ) );
2073 elemExtraDatasets.appendChild( elemUri );
2074 }
2075 layer_node.appendChild( elemExtraDatasets );
2076 }
2077
2078 QDomElement elemStaticDataset = document.createElement( QStringLiteral( "static-active-dataset" ) );
2079 elemStaticDataset.setAttribute( QStringLiteral( "scalar" ), mStaticScalarDatasetIndex );
2080 elemStaticDataset.setAttribute( QStringLiteral( "vector" ), mStaticVectorDatasetIndex );
2081 layer_node.appendChild( elemStaticDataset );
2082
2083 // write dataset group store if not in edting mode
2084 if ( !isEditable() )
2085 layer_node.appendChild( mDatasetGroupStore->writeXml( document, context ) );
2086
2087 // renderer specific settings
2088 QString errorMsg;
2089 return writeSymbology( layer_node, document, errorMsg, context );
2090}
2091
2093{
2095
2096 if ( !mMeshEditor && mDataProvider && mDataProvider->isValid() )
2097 {
2098 mDataProvider->reloadData();
2099 mDatasetGroupStore->setPersistentProvider( mDataProvider, QStringList() ); //extra dataset are already loaded
2100
2101 //reload the mesh structure
2102 if ( !mNativeMesh )
2103 mNativeMesh.reset( new QgsMesh );
2104
2105 dataProvider()->populateMesh( mNativeMesh.get() );
2106
2107 if ( mTemporalProperties->alwaysLoadReferenceTimeFromSource() )
2108 mTemporalProperties->setDefaultsFromDataProviderTemporalCapabilities( mDataProvider->temporalCapabilities() );
2109
2110 //clear the TriangularMeshes
2111 mTriangularMeshes.clear();
2112
2113 //clear the rendererCache
2114 mRendererCache.reset( new QgsMeshLayerRendererCache() );
2115
2116 checkSymbologyConsistency();
2117
2118 emit reloaded();
2119 }
2120}
2121
2122QStringList QgsMeshLayer::subLayers() const
2123{
2125
2126 if ( mDataProvider )
2127 return mDataProvider->subLayers();
2128 else
2129 return QStringList();
2130}
2131
2133{
2135
2136 const QgsLayerMetadataFormatter htmlFormatter( metadata() );
2137 QString myMetadata = QStringLiteral( "<html>\n<body>\n" );
2138
2139 myMetadata += generalHtmlMetadata();
2140
2141 // Begin Provider section
2142 myMetadata += QStringLiteral( "<h1>" ) + tr( "Information from provider" ) + QStringLiteral( "</h1>\n<hr>\n" );
2143 myMetadata += QLatin1String( "<table class=\"list-view\">\n" );
2144
2145 // Extent
2146 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Extent" ) + QStringLiteral( "</td><td>" ) + extent().toString() + QStringLiteral( "</td></tr>\n" );
2147
2148 // feature count
2149 QLocale locale = QLocale();
2150 locale.setNumberOptions( locale.numberOptions() &= ~QLocale::NumberOption::OmitGroupSeparator );
2151
2152 if ( const QgsMeshDataProvider *provider = dataProvider() )
2153 {
2154 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
2155 + tr( "Vertex count" ) + QStringLiteral( "</td><td>" )
2156 + ( locale.toString( static_cast<qlonglong>( meshVertexCount() ) ) )
2157 + QStringLiteral( "</td></tr>\n" );
2158 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
2159 + tr( "Face count" ) + QStringLiteral( "</td><td>" )
2160 + ( locale.toString( static_cast<qlonglong>( meshFaceCount() ) ) )
2161 + QStringLiteral( "</td></tr>\n" );
2162 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
2163 + tr( "Edge count" ) + QStringLiteral( "</td><td>" )
2164 + ( locale.toString( static_cast<qlonglong>( meshEdgeCount() ) ) )
2165 + QStringLiteral( "</td></tr>\n" );
2166 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
2167 + tr( "Dataset groups count" ) + QStringLiteral( "</td><td>" )
2168 + ( locale.toString( static_cast<qlonglong>( datasetGroupCount() ) ) )
2169 + QStringLiteral( "</td></tr>\n" );
2170 myMetadata += provider->htmlMetadata();
2171 }
2172
2173 // End Provider section
2174 myMetadata += QLatin1String( "</table>\n<br><br>" );
2175
2176 // CRS
2177 myMetadata += crsHtmlMetadata();
2178
2179 // identification section
2180 myMetadata += QStringLiteral( "<h1>" ) + tr( "Identification" ) + QStringLiteral( "</h1>\n<hr>\n" );
2181 myMetadata += htmlFormatter.identificationSectionHtml( );
2182 myMetadata += QLatin1String( "<br><br>\n" );
2183
2184 // extent section
2185 myMetadata += QStringLiteral( "<h1>" ) + tr( "Extent" ) + QStringLiteral( "</h1>\n<hr>\n" );
2186 myMetadata += htmlFormatter.extentSectionHtml( isSpatial() );
2187 myMetadata += QLatin1String( "<br><br>\n" );
2188
2189 // Start the Access section
2190 myMetadata += QStringLiteral( "<h1>" ) + tr( "Access" ) + QStringLiteral( "</h1>\n<hr>\n" );
2191 myMetadata += htmlFormatter.accessSectionHtml( );
2192 myMetadata += QLatin1String( "<br><br>\n" );
2193
2194 // Start the contacts section
2195 myMetadata += QStringLiteral( "<h1>" ) + tr( "Contacts" ) + QStringLiteral( "</h1>\n<hr>\n" );
2196 myMetadata += htmlFormatter.contactsSectionHtml( );
2197 myMetadata += QLatin1String( "<br><br>\n" );
2198
2199 // Start the links section
2200 myMetadata += QStringLiteral( "<h1>" ) + tr( "Links" ) + QStringLiteral( "</h1>\n<hr>\n" );
2201 myMetadata += htmlFormatter.linksSectionHtml( );
2202 myMetadata += QLatin1String( "<br><br>\n" );
2203
2204 // Start the history section
2205 myMetadata += QStringLiteral( "<h1>" ) + tr( "History" ) + QStringLiteral( "</h1>\n<hr>\n" );
2206 myMetadata += htmlFormatter.historySectionHtml( );
2207 myMetadata += QLatin1String( "<br><br>\n" );
2208
2209 myMetadata += customPropertyHtmlMetadata();
2210
2211 myMetadata += QLatin1String( "\n</body>\n</html>\n" );
2212 return myMetadata;
2213}
2214
2216{
2218
2219 return mMeshEditor;
2220}
2221
2222bool QgsMeshLayer::setDataProvider( QString const &provider, const QgsDataProvider::ProviderOptions &options, Qgis::DataProviderReadFlags flags )
2223{
2225
2226 mDatasetGroupStore->setPersistentProvider( nullptr, QStringList() );
2227
2228 delete mDataProvider;
2229 mProviderKey = provider;
2230 const QString dataSource = mDataSource;
2231
2232 if ( mPreloadedProvider )
2233 {
2234 mDataProvider = qobject_cast< QgsMeshDataProvider * >( mPreloadedProvider.release() );
2235 }
2236 else
2237 {
2238 std::unique_ptr< QgsScopedRuntimeProfile > profile;
2239 if ( QgsApplication::profiler()->groupIsActive( QStringLiteral( "projectload" ) ) )
2240 profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Create %1 provider" ).arg( provider ), QStringLiteral( "projectload" ) );
2241
2242 mDataProvider = qobject_cast<QgsMeshDataProvider *>( QgsProviderRegistry::instance()->createProvider( provider, dataSource, options, flags ) );
2243 }
2244
2245 if ( !mDataProvider )
2246 {
2247 QgsDebugMsgLevel( QStringLiteral( "Unable to get mesh data provider" ), 2 );
2248 return false;
2249 }
2250
2251 mDataProvider->setParent( this );
2252 QgsDebugMsgLevel( QStringLiteral( "Instantiated the mesh data provider plugin" ), 2 );
2253
2254 setValid( mDataProvider->isValid() );
2255 if ( !isValid() )
2256 {
2257 QgsDebugMsgLevel( QStringLiteral( "Invalid mesh provider plugin %1" ).arg( QString( mDataSource.toUtf8() ) ), 2 );
2258 return false;
2259 }
2260
2261 if ( !mTemporalProperties->isValid() )
2262 {
2263 mTemporalProperties->setDefaultsFromDataProviderTemporalCapabilities( dataProvider()->temporalCapabilities() );
2264 }
2265
2266 mDataProvider->setTemporalUnit( mTemporalUnit );
2267
2268 mDatasetGroupStore->setPersistentProvider( mDataProvider, mExtraDatasetUri );
2269
2270 setCrs( mDataProvider->crs() );
2271
2272 if ( provider == QLatin1String( "mesh_memory" ) )
2273 {
2274 // required so that source differs between memory layers
2275 mDataSource = mDataSource + QStringLiteral( "&uid=%1" ).arg( QUuid::createUuid().toString() );
2276 }
2277
2278 // set default style if required by flags or if the dataset group does not has a style yet
2279 for ( int i = 0; i < mDataProvider->datasetGroupCount(); ++i )
2280 {
2281 int globalIndex = mDatasetGroupStore->globalDatasetGroupIndexInSource( mDataProvider, i );
2282 if ( globalIndex != -1 &&
2283 ( !mRendererSettings.hasSettings( globalIndex ) || ( flags & Qgis::DataProviderReadFlag::LoadDefaultStyle ) ) )
2284 assignDefaultStyleToDatasetGroup( globalIndex );
2285 }
2286
2287 emit rendererChanged();
2289
2290 connect( mDataProvider, &QgsMeshDataProvider::dataChanged, this, &QgsMeshLayer::dataChanged );
2291
2292 return true;
2293}
2294
2301
2308
2310{
2312
2313 return mLabelsEnabled && static_cast< bool >( mLabeling );
2314}
2315
2317{
2319
2320 mLabelsEnabled = enabled;
2321}
2322
2324{
2326
2327 if ( mLabeling == labeling )
2328 return;
2329
2330 delete mLabeling;
2331 mLabeling = labeling;
2333}
2334
2335bool QgsMeshLayer::datasetsPathUnique( const QString &path )
2336{
2337 if ( ! mDataProvider )
2338 {
2339 QgsDebugMsgLevel( QStringLiteral( "Unable to get mesh data provider" ), 2 );
2340 return false;
2341 }
2342
2343 if ( mDataProvider->dataSourceUri().contains( path ) )
2344 return false;
2345
2346 return !mExtraDatasetUri.contains( path );
2347}
Provides global constants and enumerations for use throughout the application.
Definition qgis.h:54
@ Exact
Assigns the color of the exact matching value in the color ramp item list.
@ Critical
Critical/error message.
Definition qgis.h:157
@ TooManyVerticesInFace
A face has more vertices than the maximum number supported per face.
@ InvalidFace
An error occurs due to an invalid face (for example, vertex indexes are unordered)
@ UniqueSharedVertex
A least two faces share only one vertices.
@ ManifoldFace
ManifoldFace.
@ InvalidVertex
An error occurs due to an invalid vertex (for example, vertex index is out of range the available ver...
@ FlatFace
A flat face is present.
BlendMode
Blending modes defining the available composition modes that can be used when painting.
Definition qgis.h:4776
TemporalUnit
Temporal units.
Definition qgis.h:5005
@ Milliseconds
Milliseconds.
QFlags< DataProviderReadFlag > DataProviderReadFlags
Flags which control data provider construction.
Definition qgis.h:450
@ EqualInterval
Uses equal interval.
@ Mesh
Mesh layer. Added in QGIS 3.2.
@ LoadDefaultStyle
Reset the layer's style to the default for the datasource.
QgsVertexIterator vertices() const
Returns a read-only, Java-style iterator for traversal of vertices of all the geometry,...
Abstract base class - its implementations define different approaches to the labeling of a mesh layer...
static QgsAbstractMeshLayerLabeling * create(const QDomElement &element, const QgsReadWriteContext &context)
Try to create instance of an implementation based on the XML data.
virtual QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context) const =0
Returns labeling configuration as XML element.
Abstract base class for objects which generate elevation profiles.
static QgsRuntimeProfiler * profiler()
Returns the application runtime profiler.
A ramp shader will color a raster pixel based on a list of values ranges in a ramp.
void setClassificationMode(Qgis::ShaderClassificationMethod classificationMode)
Sets the classification mode.
QgsColorRamp * sourceColorRamp() const
Returns the source color ramp.
void setColorRampType(Qgis::ShaderInterpolationMethod colorRampType)
Sets the color ramp interpolation method.
void setColorRampItemList(const QList< QgsColorRampShader::ColorRampItem > &list)
Sets a custom color map.
Abstract base class for color ramps.
virtual QColor color(double value) const =0
Returns the color corresponding to a specified value.
Contains information about the context in which a coordinate transform is executed.
Handles coordinate transforms between two coordinate systems.
Base class for handling properties relating to a data provider's temporal capabilities.
bool hasTemporalCapabilities() const
Returns true if the provider has temporal capabilities available.
QgsCoordinateTransformContext transformContext() const
Returns data provider coordinate transform context.
virtual QgsCoordinateReferenceSystem crs() const =0
Returns the coordinate system for the data source.
void dataChanged()
Emitted whenever a change is made to the data provider which may have caused changes in the provider'...
virtual bool isValid() const =0
Returns true if this is a valid layer.
virtual QString dataSourceUri(bool expandAuthConfig=false) const
Gets the data source specification.
virtual QStringList subLayers() const
Sub-layers handled by this provider, in order from bottom to top.
virtual void reloadData()
Reloads the data from the source for providers with data caches to synchronize, changes in the data s...
virtual QgsRectangle extent() const =0
Returns the extent of the layer.
virtual void setTransformContext(const QgsCoordinateTransformContext &transformContext)
Sets data coordinate transform context to transformContext.
void setVariable(const QString &name, const QVariant &value, bool isStatic=false)
Convenience method for setting a variable in the context scope by name name and value.
static QgsExpressionContextScope * meshExpressionScope(QgsMesh::ElementType elementType)
Creates a new scope which contains functions relating to mesh layer element elementType.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QgsExpressionContextScope * lastScope()
Returns the last scope added to the context.
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
Handles 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.
Defines color interpolation for rendering mesh datasets.
Represents a simple line renderer with width and color varying depending on values.
Represents a width that 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.
Formats layer metadata into HTML.
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:77
QString name
Definition qgsmaplayer.h:81
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.
QString providerType() const
Returns the provider type (provider key) for this layer.
void setBlendMode(QPainter::CompositionMode blendMode)
Set the blending mode used for rendering a layer.
void trigger3DUpdate()
Will advise any 3D maps that this layer requires to be updated in the scene.
static Qgis::DataProviderReadFlags providerReadFlags(const QDomNode &layerNode, QgsMapLayer::ReadFlags layerReadFlags)
Returns provider read flag deduced from layer read flags layerReadFlags and a dom node layerNode that...
QgsMapLayer::LayerFlags flags() const
Returns the flags for this layer.
void editingStarted()
Emitted when editing on this layer has started.
virtual QString loadDefaultStyle(bool &resultFlag)
Retrieve the default style for this layer if one exists (either as a .qml file on disk or as a record...
QString mLayerName
Name of the layer - used for display.
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted.
QString crsHtmlMetadata() const
Returns a HTML fragment containing the layer's CRS metadata, for use in the htmlMetadata() method.
QgsLayerMetadata metadata
Definition qgsmaplayer.h:83
Qgis::LayerType type
Definition qgsmaplayer.h:87
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:89
@ Rendering
Rendering: scale visibility, simplify method, opacity.
@ Labeling
Labeling.
void layerModified()
Emitted when modifications has been done on layer.
void setProviderType(const QString &providerType)
Sets the providerType (provider key)
QString customPropertyHtmlMetadata() const
Returns an HTML fragment containing custom property information, for use in the htmlMetadata() method...
QString generalHtmlMetadata() const
Returns an HTML fragment containing general metadata information, for use in the htmlMetadata() metho...
void writeCommonStyle(QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) const
Write style data common to all layer types.
void invalidateWgs84Extent()
Invalidates the WGS84 extent.
bool mShouldValidateCrs
true if the layer's CRS should be validated and invalid CRSes are not permitted.
void setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer's spatial reference system.
Abstract class for interpolating 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.
A block of 3d stacked mesh data related N faces defined on base mesh frame.
A block of integers/doubles from a mesh dataset.
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.
A collection of dataset group metadata such as whether the data is vector or scalar,...
QMap< QString, QString > extraOptions() const
Returns extra metadata options, for example description.
bool isVector() const
Returns whether dataset group has vector data.
DataType dataType() const
Returns whether dataset group data is defined on vertices or faces or volumes.
double minimum() const
Returns minimum scalar value/vector magnitude present for whole dataset group.
double maximum() const
Returns maximum scalar value/vector magnitude present for whole dataset group.
DataType
Location of where data is specified for datasets in the dataset group.
@ DataOnEdges
Data is defined on edges.
@ DataOnFaces
Data is defined on faces.
@ DataOnVertices
Data is defined on vertices.
@ DataOnVolumes
Data is defined on volumes.
QString uri() const
Returns the uri of the source.
Registers and accesses all the dataset groups related to a mesh layer.
void datasetGroupsAdded(QList< int > indexes)
Emitted after dataset groups are added.
Tree item for display of the mesh dataset groups.
int datasetGroupIndex() const
Returns the dataset group index.
QgsMeshDatasetGroupTreeItem * childFromDatasetGroupIndex(int index)
Returns the child with dataset group index Searches as depper as needed on the child hierarchy.
bool isEnabled() const
Returns true if the item is enabled, i.e.
QgsMeshDatasetGroupTreeItem * child(int row) const
Returns a child.
Abstract class that represents a dataset group.
An 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()
Represents mesh dataset metadata, such as whether the data is valid or the associated time.
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.
Represents a single mesh dataset value.
double y() const
Returns y value.
double x() const
Returns x value.
Holds metadata about mesh drivers.
@ CanWriteMeshData
If the driver can write mesh data on file.
MeshDriverCapabilities capabilities() const
Returns the capabilities for this driver.
Represents an error which occurred during mesh editing.
Qgis::MeshEditingErrorType errorType
Handles edit operations on a mesh layer.
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.
int closestElement(QgsMesh::ElementType elementType, const QgsPointXY &point, double searchRadius, QgsPointXY &projectedPoint) const
Returns the index of the snapped point on the mesh element closest to point intersecting with the sea...
~QgsMeshLayer() override
QList< int > selectVerticesByExpression(QgsExpression expression)
Returns a list of vertex indexes that meet the condition defined by expression with the context expre...
void setMeshSimplificationSettings(const QgsMeshSimplificationSettings &meshSimplificationSettings)
Sets mesh simplification settings.
int datasetCount(const QgsMeshDatasetIndex &index) const
Returns the dataset count in the dataset groups.
QList< int > datasetGroupsIndexes() const
Returns the list of indexes of dataset groups handled by the layer.
void stopFrameEditing(const QgsCoordinateTransform &transform)
Stops editing of the mesh, re-indexes the faces and vertices, rebuilds the triangular mesh and its sp...
QgsRectangle extent() const override
Returns the extent of the layer.
void setStaticVectorDatasetIndex(const QgsMeshDatasetIndex &staticVectorDatasetIndex)
Sets the static vector dataset index that is rendered if the temporal properties is not active.
void setStaticScalarDatasetIndex(const QgsMeshDatasetIndex &staticScalarDatasetIndex)
Sets the static scalar dataset index that is rendered if the temporal properties is not active.
bool contains(const QgsMesh::ElementType &type) const
Returns whether the mesh contains at mesh elements of given type.
QgsMeshRendererSettings rendererSettings() const
Returns renderer settings.
QgsMeshDatasetIndex activeScalarDatasetIndex(QgsRenderContext &rendererContext)
Returns current active scalar dataset index for current renderer context.
QgsMeshDatasetIndex activeVectorDatasetAtTime(const QgsDateTimeRange &timeRange, int group=-1) const
Returns dataset index from active vector group depending on the time range If the temporal properties...
QList< QgsMeshDatasetIndex > datasetIndexInRelativeTimeInterval(const QgsInterval &startRelativeTime, const QgsInterval &endRelativeTime, int datasetGroupIndex) const
Returns a list of dataset indexes from datasets group that are in a interval time from the layer refe...
void activeScalarDatasetGroupChanged(int index)
Emitted when active scalar group dataset is changed.
int datasetGroupCount() const
Returns the dataset groups count handle by the layer.
void updateTriangularMesh(const QgsCoordinateTransform &transform=QgsCoordinateTransform())
Gets native mesh and updates (creates if it doesn't exist) the base triangular mesh.
bool addDatasets(const QString &path, const QDateTime &defaultReferenceTime=QDateTime())
Adds datasets to the mesh from file with path.
bool isModified() const override
Returns whether the mesh frame has been modified since the last save.
void activeVectorDatasetGroupChanged(int index)
Emitted when active vector group dataset is changed.
void reload() override
Synchronises with changes in the datasource.
QgsPointXY snapOnElement(QgsMesh::ElementType elementType, const QgsPointXY &point, double searchRadius)
Returns the position of the snapped point on the mesh element closest to point intersecting with the ...
bool readXml(const QDomNode &layer_node, QgsReadWriteContext &context) override
Called by readLayerXML(), used by children to read state specific to them from project files.
QStringList subLayers() const override
Returns the sublayers of this layer.
QgsMeshEditor * meshEditor()
Returns a pointer to the mesh editor own by the mesh layer.
const QgsAbstractMeshLayerLabeling * labeling() const
Access to const labeling configuration.
void setDatasetGroupTreeRootItem(QgsMeshDatasetGroupTreeItem *rootItem)
Sets the root items of the dataset group tree item.
QgsMeshDatasetValue dataset1dValue(const QgsMeshDatasetIndex &index, const QgsPointXY &point, double searchRadius) const
Returns the value of 1D mesh dataset defined on edge that are in the search area defined by point ans...
QgsMeshDatasetIndex staticVectorDatasetIndex(int group=-1) const
Returns the static vector dataset index that is rendered if the temporal properties is not active.
QgsMesh * nativeMesh()
Returns native mesh (nullptr before rendering or calling to updateMesh)
QString loadDefaultStyle(bool &resultFlag) FINAL
Retrieve the default style for this layer if one exists (either as a .qml file on disk or as a record...
bool minimumMaximumActiveScalarDataset(const QgsRectangle &extent, const QgsMeshDatasetIndex &datasetIndex, double &min, double &max)
Extracts minimum and maximum value for active scalar dataset on mesh faces.
QgsTriangularMesh * triangularMeshByLodIndex(int lodIndex) const
Returns triangular corresponding to the index of level of details.
QString htmlMetadata() const override
Obtain a formatted HTML string containing assorted metadata for this layer.
int meshFaceCount() const
Returns the faces count of the mesh frame.
QList< int > selectFacesByExpression(QgsExpression expression)
Returns a list of faces indexes that meet the condition defined by expression with the context expres...
void setRendererSettings(const QgsMeshRendererSettings &settings, const bool repaint=true)
Sets new renderer settings.
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.
bool datasetsPathUnique(const QString &path)
Checks whether that datasets path is already added to this mesh layer.
qint64 datasetRelativeTimeInMilliseconds(const QgsMeshDatasetIndex &index)
Returns the relative time (in milliseconds) of the dataset from the reference time of its group.
QgsMeshDatasetIndex activeScalarDatasetAtTime(const QgsDateTimeRange &timeRange, int group=-1) const
Returns dataset index from active scalar group depending on the time range.
QgsTriangularMesh * triangularMesh(double minimumTriangleSize=0) const
Returns triangular mesh (nullptr before rendering or calling to updateMesh).
QgsMeshDatasetIndex staticScalarDatasetIndex(int group=-1) const
Returns the static scalar dataset index that is rendered if the temporal properties is not active.
void setTemporalMatchingMethod(const QgsMeshDataProviderTemporalCapabilities::MatchingTemporalDatasetMethod &matchingMethod)
Sets the method used to match the temporal dataset from a requested time, see activeVectorDatasetAtTi...
bool removeDatasets(const QString &name)
Removes datasets from the mesh with given name.
QgsMeshDatasetGroupTreeItem * datasetGroupTreeRootItem() const
Returns the root items of the dataset group tree item.
QgsMesh3DDataBlock dataset3dValues(const QgsMeshDatasetIndex &index, int faceIndex, int count) const
Returns N vector/scalar values from the face index from the dataset for 3d stacked meshes.
QgsMesh3DDataBlock dataset3dValue(const QgsMeshDatasetIndex &index, const QgsPointXY &point) const
Returns the 3d values of stacked 3d mesh defined by the given point.
bool readSymbology(const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) override
Read the symbology for the current layer from the DOM node supplied.
QString 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 objects.
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, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
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.
Represents a 2D point.
Definition qgspointxy.h:60
double distance(double x, double y) const
Returns the distance between this point and a specified x, y coordinate.
Definition qgspointxy.h:206
double y
Definition qgspointxy.h:64
double x
Definition qgspointxy.h:63
double sqrDistToSegment(double x1, double y1, double x2, double y2, QgsPointXY &minDistPoint, double epsilon=Qgis::DEFAULT_SEGMENT_EPSILON) const
Returns the minimum distance between this point and a segment.
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:387
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.
A container for the context for various read/write operations on objects.
MAYBE_UNUSED NODISCARD QgsReadWriteContextCategoryPopper enterCategory(const QString &category, const QString &details=QString()) const
Push a category to the stack.
const QgsPathResolver & pathResolver() const
Returns path resolver for conversion between relative and absolute paths.
A rectangle specified with double values.
Q_INVOKABLE QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
void setNull()
Mark a rectangle as being null (holding no spatial information).
Contains information about the context of a rendering operation.
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
QgsColorRamp * colorRamp(const QString &name) const
Returns a new copy of the specified color ramp.
Definition qgsstyle.cpp:495
static QgsStyle * defaultStyle(bool initialize=true)
Returns the default application-wide style.
Definition qgsstyle.cpp:146
bool isActive() const
Returns true if the temporal property is active.
void setIsActive(bool active)
Sets whether the temporal property is active.
const QgsDateTimeRange & temporalRange() const
Returns the datetime range for the object.
bool isTemporal() const
Returns true if the object's temporal range is enabled, and the object will be filtered when renderin...
T begin() const
Returns the beginning of the range.
Definition qgsrange.h:446
static QgsMeshEditingError checkTopology(const QgsMesh &mesh, int maxVerticesPerFace)
Checks the topology of the mesh mesh, if error occurs, this mesh can't be edited.
A triangular/derived mesh with vertices in map coordinates.
const QVector< QgsMeshFace > & triangles() const
Returns triangles.
QList< int > edgeIndexesForRectangle(const QgsRectangle &rectangle) const
Finds indexes of edges intersecting given bounding box It uses spatial indexing.
const QVector< QgsMeshVertex > & vertices() const
Returns vertices in map coordinate system.
const QVector< QgsMeshEdge > & edges() const
Returns edges.
bool contains(const QgsMesh::ElementType &type) const
Returns whether the mesh contains mesh elements of given type.
const QVector< int > & trianglesToNativeFaces() const
Returns mapping between triangles and original faces.
QList< int > faceIndexesForRectangle(const QgsRectangle &rectangle) const
Finds indexes of triangles intersecting given bounding box It uses spatial indexing.
int faceIndexForPoint_v2(const QgsPointXY &point) const
Finds index of triangle at given point It uses spatial indexing and don't use geos to be faster.
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:41
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.