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