QGIS API Documentation 3.99.0-Master (d270888f95f)
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 "qgsmeshlayer.h"
19
20#include <cstddef>
21#include <limits>
22#include <memory>
23
24#include "qgsapplication.h"
25#include "qgscolorrampimpl.h"
28#include "qgslogger.h"
29#include "qgsmaplayerfactory.h"
30#include "qgsmaplayerlegend.h"
31#include "qgsmesh3daveraging.h"
32#include "qgsmeshdataprovider.h"
34#include "qgsmesheditor.h"
40#include "qgsmeshlayerutils.h"
41#include "qgsmeshtimesettings.h"
42#include "qgsmessagelog.h"
43#include "qgspainting.h"
44#include "qgsproviderregistry.h"
45#include "qgsreadwritecontext.h"
46#include "qgsruntimeprofiler.h"
47#include "qgsstyle.h"
48#include "qgsthreadingutils.h"
49#include "qgstriangularmesh.h"
50
51#include <QString>
52#include <QUrl>
53#include <QUuid>
54
55#include "moc_qgsmeshlayer.cpp"
56
57using namespace Qt::StringLiterals;
58
59QgsMeshLayer::QgsMeshLayer( const QString &meshLayerPath,
60 const QString &baseName,
61 const QString &providerKey,
62 const QgsMeshLayer::LayerOptions &options )
63 : QgsMapLayer( Qgis::LayerType::Mesh, baseName, meshLayerPath )
64 , mDatasetGroupStore( new QgsMeshDatasetGroupStore( this ) )
65 , mTemporalProperties( new QgsMeshLayerTemporalProperties( this ) )
66 , mElevationProperties( new QgsMeshLayerElevationProperties( this ) )
67{
69
70 const QgsDataProvider::ProviderOptions providerOptions { options.transformContext };
72 if ( options.loadDefaultStyle )
73 {
74 flags |= Qgis::DataProviderReadFlag::LoadDefaultStyle;
75 }
76 QgsMeshLayer::setDataSourcePrivate( meshLayerPath, baseName, providerKey, providerOptions, flags );
79
80 if ( isValid() && options.loadDefaultStyle )
81 {
82 bool result = false;
83 loadDefaultStyle( result );
84 }
85
86 connect( mDatasetGroupStore.get(), &QgsMeshDatasetGroupStore::datasetGroupsAdded, this, &QgsMeshLayer::onDatasetGroupsAdded );
87}
88
89void QgsMeshLayer::createSimplifiedMeshes()
90{
92
93 if ( mSimplificationSettings.isEnabled() && !hasSimplifiedMeshes() )
94 {
95 const double reductionFactor = mSimplificationSettings.reductionFactor();
96
97 QVector<QgsTriangularMesh *> simplifyMeshes =
98 mTriangularMeshes[0]->simplifyMesh( reductionFactor );
99
100 for ( int i = 0; i < simplifyMeshes.count() ; ++i )
101 {
102 mTriangularMeshes.emplace_back( simplifyMeshes[i] );
103 }
104 }
105}
106
107bool QgsMeshLayer::hasSimplifiedMeshes() const
108{
110
111 //First mesh is the base mesh, so if size>1, there is no simplified meshes
112 return ( mTriangularMeshes.size() > 1 );
113}
114
116{
117 delete mLabeling;
118 delete mDataProvider;
119}
120
127
129{
131
132 return mDataProvider;
133}
134
136{
138
140 if ( mDataProvider )
141 {
142 options.transformContext = mDataProvider->transformContext();
143 }
144 QgsMeshLayer *layer = new QgsMeshLayer( source(), name(), mProviderKey, options );
145 QgsMapLayer::clone( layer );
146
147 layer->mElevationProperties = mElevationProperties->clone();
148 layer->mElevationProperties->setParent( layer );
149
150 if ( auto *lLabeling = labeling() )
151 {
152 layer->setLabeling( lLabeling->clone() );
153 }
155
156 for ( const QString &extraDataset : mExtraDatasetUri )
157 {
158 layer->addDatasets( extraDataset );
159 }
160
161 layer->setRendererSettings( mRendererSettings );
162
163 return layer;
164}
165
167{
169
170 if ( mMeshEditor )
171 return mMeshEditor->extent();
172
173 if ( mDataProvider )
174 return mDataProvider->extent();
175 else
176 {
177 QgsRectangle rec;
178 rec.setNull();
179 return rec;
180 }
181}
182
184{
186
187 if ( !mDataProvider )
188 return false;
189
190 if ( mMeshEditor )
191 return true;
192
193 const QgsMeshDriverMetadata driverMetadata = mDataProvider->driverMetadata();
194
196}
197
198QString QgsMeshLayer::loadDefaultStyle( bool &resultFlag )
199{
201
202 const QList<int> groupsList = datasetGroupsIndexes();
203
204 for ( const int index : groupsList )
205 assignDefaultStyleToDatasetGroup( index );
206
207
208 QgsMeshRendererMeshSettings meshSettings;
209 if ( !groupsList.isEmpty() )
210 {
211 // Show data from the first dataset group
212 mRendererSettings.setActiveScalarDatasetGroup( 0 );
213 // If the first dataset group has nan min/max, display the mesh to avoid nothing displayed
215 if ( meta.maximum() == std::numeric_limits<double>::quiet_NaN() &&
216 meta.minimum() == std::numeric_limits<double>::quiet_NaN() )
217 meshSettings.setEnabled( true );
218 }
219 else
220 {
221 // show at least the mesh by default
222 meshSettings.setEnabled( true );
223 }
224
225 mRendererSettings.setNativeMeshSettings( meshSettings );
226
227 for ( const int i : groupsList )
228 {
229 assignDefaultStyleToDatasetGroup( i );
230
231 // Sets default resample method for scalar dataset
233 QgsMeshRendererScalarSettings scalarSettings = mRendererSettings.scalarSettings( i );
234 switch ( meta.dataType() )
235 {
237 case QgsMeshDatasetGroupMetadata::DataOnVolumes: // data on volumes are averaged to 2D data on faces
239 break;
242 break;
244 break;
245 }
246
247 //override color ramp if the values in the dataset group are classified
248 applyClassificationOnScalarSettings( meta, scalarSettings );
249
250 mRendererSettings.setScalarSettings( i, scalarSettings );
251 }
252
253 if ( !groupsList.isEmpty() )
254 {
255 emit rendererChanged();
257 }
258
259 return QgsMapLayer::loadDefaultStyle( resultFlag );
260}
261
262bool QgsMeshLayer::removeDatasets( const QString &name )
263{
264 const int index = mDatasetGroupStore->indexFromGroupName( name );
265
266 if ( index == -1 )
267 {
268 return false;
269 }
270
271 const QgsMeshDatasetGroupMetadata groupMetadata = datasetGroupMetadata( index );
272
273 mDatasetGroupStore->removeDatasetGroup( index );
274
275 if ( mExtraDatasetUri.contains( groupMetadata.uri() ) )
276 {
277 mExtraDatasetUri.removeOne( groupMetadata.uri() );
278 }
279
281
282 emit dataSourceChanged();
283 return true;
284}
285
286bool QgsMeshLayer::addDatasets( const QString &path, const QDateTime &defaultReferenceTime )
287{
289
291 const bool isTemporalBefore = temporalCapabilities->hasTemporalCapabilities();
292 if ( mDatasetGroupStore->addPersistentDatasets( path ) )
293 {
294 mExtraDatasetUri.append( path );
295 QgsMeshLayerTemporalProperties *temporalProperties = qobject_cast< QgsMeshLayerTemporalProperties * >( mTemporalProperties );
296 if ( !isTemporalBefore && temporalCapabilities->hasTemporalCapabilities() )
297 {
298 mTemporalProperties->setDefaultsFromDataProviderTemporalCapabilities(
299 temporalCapabilities );
300
301 if ( ! temporalProperties->referenceTime().isValid() )
302 {
303 QDateTime referenceTime = defaultReferenceTime;
304 if ( !defaultReferenceTime.isValid() ) // If project reference time is invalid, use current date
305 referenceTime = QDateTime( QDate::currentDate(), QTime( 0, 0, 0 ), Qt::UTC );
306 temporalProperties->setReferenceTime( referenceTime, temporalCapabilities );
307 }
308
309 mTemporalProperties->setIsActive( true );
310 }
311 emit dataSourceChanged();
312 return true;
313 }
314
315 return false;
316}
317
319{
321
322 if ( mDatasetGroupStore->addDatasetGroup( std::unique_ptr< QgsMeshDatasetGroup >( datasetGroup ) ) )
323 {
324 emit dataChanged();
325 return true;
326 }
327 return false;
328}
329
330bool QgsMeshLayer::saveDataset( const QString &path, int datasetGroupIndex, QString driver )
331{
333
334 return mDatasetGroupStore->saveDatasetGroup( path, datasetGroupIndex, driver );
335}
336
338{
340
341 return mNativeMesh.get();
342}
343
345{
347
348 return mNativeMesh.get();
349}
350
351QgsTriangularMesh *QgsMeshLayer::triangularMesh( double minimumTriangleSize ) const
352{
354
355 for ( const std::unique_ptr<QgsTriangularMesh> &lod : mTriangularMeshes )
356 {
357 if ( lod && lod->averageTriangleSize() > minimumTriangleSize )
358 return lod.get();
359 }
360
361 if ( !mTriangularMeshes.empty() )
362 return mTriangularMeshes.back().get();
363 else
364 return nullptr;
365}
366
368{
370
371 return mTriangularMeshes.size();
372}
373
375{
377
378 if ( mTriangularMeshes.empty() )
379 return nullptr;
380 if ( lodIndex < 0 )
381 return mTriangularMeshes.front().get();
382
383 if ( lodIndex >= int( mTriangularMeshes.size() ) )
384 return mTriangularMeshes.back().get();
385
386 return mTriangularMeshes.at( lodIndex ).get();
387}
388
390{
392
393 // Native mesh
394 if ( !mNativeMesh )
395 {
396 // lazy loading of mesh data
397 fillNativeMesh();
398 }
399
400 // Triangular mesh
401 if ( mTriangularMeshes.empty() )
402 {
403 QgsTriangularMesh *baseMesh = new QgsTriangularMesh;
404 mTriangularMeshes.emplace_back( baseMesh );
405 }
406
407 if ( mTriangularMeshes[0].get()->update( mNativeMesh.get(), transform ) )
408 mTriangularMeshes.resize( 1 ); //if the base triangular mesh is effectivly updated, remove simplified meshes
409
410 createSimplifiedMeshes();
411}
412
413QgsMeshLayerRendererCache *QgsMeshLayer::rendererCache()
414{
416
417 return mRendererCache.get();
418}
419
426
427void QgsMeshLayer::setRendererSettings( const QgsMeshRendererSettings &settings, const bool repaint )
428{
430
431 const int oldActiveScalar = mRendererSettings.activeScalarDatasetGroup();
432 const int oldActiveVector = mRendererSettings.activeVectorDatasetGroup();
433 mRendererSettings = settings;
434
435 if ( oldActiveScalar != mRendererSettings.activeScalarDatasetGroup() )
436 emit activeScalarDatasetGroupChanged( mRendererSettings.activeScalarDatasetGroup() );
437
438 if ( oldActiveVector != mRendererSettings.activeVectorDatasetGroup() )
439 emit activeVectorDatasetGroupChanged( mRendererSettings.activeVectorDatasetGroup() );
440
441 emit rendererChanged();
442
443 if ( repaint )
444 {
446 }
447}
448
455
457{
459
460 mTimeSettings = settings;
461 emit timeSettingsChanged();
462}
463
464QString QgsMeshLayer::formatTime( double hours )
465{
467
468 if ( dataProvider() && dataProvider()->temporalCapabilities()->hasReferenceTime() )
469 return QgsMeshLayerUtils::formatTime( hours, mTemporalProperties->referenceTime(), mTimeSettings );
470 else
471 return QgsMeshLayerUtils::formatTime( hours, QDateTime(), mTimeSettings );
472}
473
475{
477
478 return mDatasetGroupStore->datasetGroupCount();
479}
480
482{
484
485 return mDatasetGroupStore->extraDatasetGroupCount();
486}
487
489{
491
492 return mDatasetGroupStore->datasetGroupIndexes();
493}
494
496{
498
499 return mDatasetGroupStore->enabledDatasetGroupIndexes();
500}
501
503{
505
506 return mDatasetGroupStore->datasetGroupMetadata( index );
507}
508
510{
512
513 return mDatasetGroupStore->datasetCount( index.group() );
514}
515
517{
519
520 return mDatasetGroupStore->datasetMetadata( index );
521}
522
524{
526
527 return mDatasetGroupStore->datasetValue( index, valueIndex );
528}
529
530QgsMeshDataBlock QgsMeshLayer::datasetValues( const QgsMeshDatasetIndex &index, int valueIndex, int count ) const
531{
533
534 return mDatasetGroupStore->datasetValues( index, valueIndex, count );
535}
536
537QgsMesh3DDataBlock QgsMeshLayer::dataset3dValues( const QgsMeshDatasetIndex &index, int faceIndex, int count ) const
538{
540
541 return mDatasetGroupStore->dataset3dValues( index, faceIndex, count );
542}
543
544QgsMeshDataBlock QgsMeshLayer::areFacesActive( const QgsMeshDatasetIndex &index, int faceIndex, int count ) const
545{
547
548 return mDatasetGroupStore->areFacesActive( index, faceIndex, count );
549}
550
551bool QgsMeshLayer::isFaceActive( const QgsMeshDatasetIndex &index, int faceIndex ) const
552{
554
555 return mDatasetGroupStore->isFaceActive( index, faceIndex );
556}
557
558QgsMeshDatasetValue QgsMeshLayer::datasetValue( const QgsMeshDatasetIndex &index, const QgsPointXY &point, double searchRadius ) const
559{
561
563 const QgsTriangularMesh *mesh = triangularMesh();
564
565 if ( mesh && index.isValid() )
566 {
568 {
569 const QgsRectangle searchRectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
570 return dataset1dValue( index, point, searchRadius );
571 }
572 const int faceIndex = mesh->faceIndexForPoint_v2( point ) ;
573 if ( faceIndex >= 0 )
574 {
575 const int nativeFaceIndex = mesh->trianglesToNativeFaces().at( faceIndex );
577 if ( isFaceActive( index, nativeFaceIndex ) )
578 {
579 switch ( dataType )
580 {
582 {
583 value = datasetValue( index, nativeFaceIndex );
584 }
585 break;
586
588 {
589 const QgsMeshFace &face = mesh->triangles()[faceIndex];
590 const int v1 = face[0], v2 = face[1], v3 = face[2];
591 const QgsPoint p1 = mesh->vertices()[v1], p2 = mesh->vertices()[v2], p3 = mesh->vertices()[v3];
592 const QgsMeshDatasetValue val1 = datasetValue( index, v1 );
593 const QgsMeshDatasetValue val2 = datasetValue( index, v2 );
594 const QgsMeshDatasetValue val3 = datasetValue( index, v3 );
595 const double x = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.x(), val2.x(), val3.x(), point );
596 double y = std::numeric_limits<double>::quiet_NaN();
597 const bool isVector = datasetGroupMetadata( index ).isVector();
598 if ( isVector )
599 y = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.y(), val2.y(), val3.y(), point );
600
601 value = QgsMeshDatasetValue( x, y );
602 }
603 break;
604
606 {
607 const QgsMesh3DAveragingMethod *avgMethod = mRendererSettings.averagingMethod();
608 if ( avgMethod )
609 {
610 const QgsMesh3DDataBlock block3d = dataset3dValues( index, nativeFaceIndex, 1 );
611 const QgsMeshDataBlock block2d = avgMethod->calculate( block3d );
612 if ( block2d.isValid() )
613 {
614 value = block2d.value( 0 );
615 }
616 }
617 }
618 break;
619
620 default:
621 break;
622 }
623 }
624 }
625 }
626
627 return value;
628}
629
631{
633
634 QgsMesh3DDataBlock block3d;
635
636 const QgsTriangularMesh *baseTriangularMesh = triangularMesh();
637
638 if ( baseTriangularMesh && dataProvider() && dataProvider()->isValid() && index.isValid() )
639 {
642 {
643 const int faceIndex = baseTriangularMesh->faceIndexForPoint_v2( point );
644 if ( faceIndex >= 0 )
645 {
646 const int nativeFaceIndex = baseTriangularMesh->trianglesToNativeFaces().at( faceIndex );
647 block3d = dataset3dValues( index, nativeFaceIndex, 1 );
648 }
649 }
650 }
651 return block3d;
652}
653
654QgsMeshDatasetValue QgsMeshLayer::dataset1dValue( const QgsMeshDatasetIndex &index, const QgsPointXY &point, double searchRadius ) const
655{
657
659 QgsPointXY projectedPoint;
660 const int selectedIndex = closestEdge( point, searchRadius, projectedPoint );
661 const QgsTriangularMesh *mesh = triangularMesh();
662 if ( selectedIndex >= 0 )
663 {
665 switch ( dataType )
666 {
668 {
669 value = datasetValue( index, selectedIndex );
670 }
671 break;
672
674 {
675 const QgsMeshEdge &edge = mesh->edges()[selectedIndex];
676 const int v1 = edge.first, v2 = edge.second;
677 const QgsPoint p1 = mesh->vertices()[v1], p2 = mesh->vertices()[v2];
678 const QgsMeshDatasetValue val1 = datasetValue( index, v1 );
679 const QgsMeshDatasetValue val2 = datasetValue( index, v2 );
680 const double edgeLength = p1.distance( p2 );
681 const double dist1 = p1.distance( projectedPoint.x(), projectedPoint.y() );
682 value = QgsMeshLayerUtils::interpolateFromVerticesData( dist1 / edgeLength, val1, val2 );
683 }
684 break;
685 default:
686 break;
687 }
688 }
689
690 return value;
691}
692
694{
696
697 if ( mDataProvider )
698 mDataProvider->setTransformContext( transformContext );
700}
701
702QgsMeshDatasetIndex QgsMeshLayer::datasetIndexAtTime( const QgsDateTimeRange &timeRange, int datasetGroupIndex ) const
703{
705
706 if ( ! mTemporalProperties->isActive() )
707 return QgsMeshDatasetIndex( datasetGroupIndex, -1 );
708
709 const QDateTime layerReferenceTime = mTemporalProperties->referenceTime();
710 QDateTime utcTime = timeRange.begin();
711 if ( utcTime.timeSpec() != Qt::UTC )
712 utcTime.setTimeSpec( Qt::UTC );
713 const qint64 startTime = layerReferenceTime.msecsTo( utcTime );
714
715 return mDatasetGroupStore->datasetIndexAtTime( startTime, datasetGroupIndex, mTemporalProperties->matchingMethod() );
716}
717
718QgsMeshDatasetIndex QgsMeshLayer::datasetIndexAtRelativeTime( const QgsInterval &relativeTime, int datasetGroupIndex ) const
719{
721
722 return mDatasetGroupStore->datasetIndexAtTime( relativeTime.seconds() * 1000, datasetGroupIndex, mTemporalProperties->matchingMethod() );
723}
724
725QList<QgsMeshDatasetIndex> QgsMeshLayer::datasetIndexInRelativeTimeInterval( const QgsInterval &startRelativeTime, const QgsInterval &endRelativeTime, int datasetGroupIndex ) const
726{
728
729 qint64 usedRelativeTime1 = startRelativeTime.seconds() * 1000;
730 qint64 usedRelativeTime2 = endRelativeTime.seconds() * 1000;
731
732 //adjust relative time if layer reference time is different from provider reference time
733 if ( mTemporalProperties->referenceTime().isValid() &&
734 mDataProvider &&
735 mDataProvider->isValid() &&
736 mTemporalProperties->referenceTime() != mDataProvider->temporalCapabilities()->referenceTime() )
737 {
738 usedRelativeTime1 = usedRelativeTime1 + mTemporalProperties->referenceTime().msecsTo( mDataProvider->temporalCapabilities()->referenceTime() );
739 usedRelativeTime2 = usedRelativeTime2 + mTemporalProperties->referenceTime().msecsTo( mDataProvider->temporalCapabilities()->referenceTime() );
740 }
741
742 return mDatasetGroupStore->datasetIndexInTimeInterval( usedRelativeTime1, usedRelativeTime2, datasetGroupIndex );
743}
744
745void QgsMeshLayer::applyClassificationOnScalarSettings( const QgsMeshDatasetGroupMetadata &meta, QgsMeshRendererScalarSettings &scalarSettings ) const
746{
748
749 if ( meta.extraOptions().contains( u"classification"_s ) )
750 {
751 QgsColorRampShader colorRampShader = scalarSettings.colorRampShader();
752 QgsColorRamp *colorRamp = colorRampShader.sourceColorRamp();
753 const QStringList classes = meta.extraOptions()[u"classification"_s].split( u";;"_s );
754
755 QString units;
756 if ( meta.extraOptions().contains( u"units"_s ) )
757 units = meta.extraOptions()[ u"units"_s];
758
759 QVector<QVector<double>> bounds;
760 for ( const QString &classe : classes )
761 {
762 const QStringList boundsStr = classe.split( ',' );
763 QVector<double> bound;
764 for ( const QString &boundStr : boundsStr )
765 bound.append( boundStr.toDouble() );
766 bounds.append( bound );
767 }
768
769 if ( ( bounds.count() == 1 && bounds.first().count() > 2 ) || // at least a class with two value
770 ( bounds.count() > 1 ) ) // or at least two classes
771 {
772 const QVector<double> firstClass = bounds.first();
773 const QVector<double> lastClass = bounds.last();
774 const double minValue = firstClass.count() > 1 ? ( firstClass.first() + firstClass.last() ) / 2 : firstClass.first();
775 const double maxValue = lastClass.count() > 1 ? ( lastClass.first() + lastClass.last() ) / 2 : lastClass.first();
776 const double diff = maxValue - minValue;
777 QList<QgsColorRampShader::ColorRampItem> colorRampItemlist;
778 for ( int i = 0; i < bounds.count(); ++i )
779 {
780 const QVector<double> &boundClass = bounds.at( i );
781 QgsColorRampShader::ColorRampItem item;
782 item.value = i + 1;
783 if ( !boundClass.isEmpty() )
784 {
785 const double scalarValue = ( boundClass.first() + boundClass.last() ) / 2;
786 item.color = colorRamp->color( ( scalarValue - minValue ) / diff );
787 if ( i != 0 && i < bounds.count() - 1 ) //The first and last labels are treated after
788 {
789 item.label = QString( ( "%1 - %2 %3" ) ).
790 arg( QString::number( boundClass.first() ) ).
791 arg( QString::number( boundClass.last() ) ).
792 arg( units );
793 }
794 }
795 colorRampItemlist.append( item );
796 }
797 //treat first and last labels
798 if ( firstClass.count() == 1 )
799 colorRampItemlist.first().label = QObject::tr( "below %1 %2" ).
800 arg( QString::number( firstClass.first() ) ).
801 arg( units );
802 else
803 {
804 colorRampItemlist.first().label = QString( ( "%1 - %2 %3" ) ).
805 arg( QString::number( firstClass.first() ) ).
806 arg( QString::number( firstClass.last() ) ).
807 arg( units );
808 }
809
810 if ( lastClass.count() == 1 )
811 colorRampItemlist.last().label = QObject::tr( "above %1 %2" ).
812 arg( QString::number( lastClass.first() ) ).
813 arg( units );
814 else
815 {
816 colorRampItemlist.last().label = QString( ( "%1 - %2 %3" ) ).
817 arg( QString::number( lastClass.first() ) ).
818 arg( QString::number( lastClass.last() ) ).
819 arg( units );
820 }
821
822 colorRampShader.setMinimumValue( 0 );
823 colorRampShader.setMaximumValue( colorRampItemlist.count() - 1 );
824 scalarSettings.setClassificationMinimumMaximum( 0, colorRampItemlist.count() - 1 );
825 colorRampShader.setColorRampItemList( colorRampItemlist );
828 }
829
830 scalarSettings.setColorRampShader( colorRampShader );
832 }
833}
834
836{
838
839 if ( mTemporalProperties->isActive() )
840 return datasetIndexAtTime( timeRange, group >= 0 ? group : mRendererSettings.activeScalarDatasetGroup() );
841 else
842 return QgsMeshDatasetIndex( group >= 0 ? group : mRendererSettings.activeScalarDatasetGroup(), mStaticScalarDatasetIndex );
843}
844
846{
848
849 if ( mTemporalProperties->isActive() )
850 return datasetIndexAtTime( timeRange, group >= 0 ? group : mRendererSettings.activeVectorDatasetGroup() );
851 else
852 return QgsMeshDatasetIndex( group >= 0 ? group : mRendererSettings.activeVectorDatasetGroup(), mStaticVectorDatasetIndex );
853}
854
855void QgsMeshLayer::fillNativeMesh()
856{
858
859 Q_ASSERT( !mNativeMesh );
860
861 mNativeMesh = std::make_unique<QgsMesh>( );
862
863 if ( !( dataProvider() && dataProvider()->isValid() ) )
864 return;
865
866 dataProvider()->populateMesh( mNativeMesh.get() );
867}
868
869void QgsMeshLayer::onDatasetGroupsAdded( const QList<int> &datasetGroupIndexes )
870{
872
873 // assign default style to new dataset groups
874 for ( int datasetGroupIndex : datasetGroupIndexes )
875 {
876 if ( !mRendererSettings.hasSettings( datasetGroupIndex ) )
877 assignDefaultStyleToDatasetGroup( datasetGroupIndex );
878 }
879
880 temporalProperties()->setIsActive( mDatasetGroupStore->hasTemporalCapabilities() );
881 emit rendererChanged();
882}
883
884void QgsMeshLayer::onMeshEdited()
885{
887
888 mRendererCache = std::make_unique<QgsMeshLayerRendererCache>( );
889 emit layerModified();
892}
893
895{
897
898 return mDatasetGroupStore->datasetGroupTreeItem();
899}
900
902{
904
905 mDatasetGroupStore->setDatasetGroupTreeItem( rootItem );
906 updateActiveDatasetGroups();
907}
908
910{
912
913 return QgsMeshDatasetIndex( group >= 0 ? group : mRendererSettings.activeVectorDatasetGroup(), mStaticVectorDatasetIndex );
914}
915
916void QgsMeshLayer::setReferenceTime( const QDateTime &referenceTime )
917{
919
920 if ( auto *lDataProvider = dataProvider() )
921 mTemporalProperties->setReferenceTime( referenceTime, lDataProvider->temporalCapabilities() );
922 else
923 mTemporalProperties->setReferenceTime( referenceTime, nullptr );
924}
925
927{
929
930 mTemporalProperties->setMatchingMethod( matchingMethod );
931}
932
933int QgsMeshLayer::closestEdge( const QgsPointXY &point, double searchRadius, QgsPointXY &projectedPoint ) const
934{
936
937 const QgsRectangle searchRectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
938 const QgsTriangularMesh *mesh = triangularMesh();
939 // search for the closest edge in search area from point
940 const QList<int> edgeIndexes = mesh->edgeIndexesForRectangle( searchRectangle );
941 int selectedIndex = -1;
942 projectedPoint = QgsPointXY();
943 if ( mesh->contains( QgsMesh::Edge ) &&
944 mDataProvider->isValid() )
945 {
946 double sqrMaxDistFromPoint = pow( searchRadius, 2 );
947 for ( const int edgeIndex : edgeIndexes )
948 {
949 const QgsMeshEdge &edge = mesh->edges().at( edgeIndex );
950 const QgsMeshVertex &vertex1 = mesh->vertices()[edge.first];
951 const QgsMeshVertex &vertex2 = mesh->vertices()[edge.second];
952 QgsPointXY projPoint;
953 const double sqrDist = point.sqrDistToSegment( vertex1.x(), vertex1.y(), vertex2.x(), vertex2.y(), projPoint, 0 );
954 if ( sqrDist < sqrMaxDistFromPoint )
955 {
956 selectedIndex = edgeIndex;
957 projectedPoint = projPoint;
958 sqrMaxDistFromPoint = sqrDist;
959 }
960 }
961 }
962
963 return selectedIndex;
964}
965
966int QgsMeshLayer::closestVertex( const QgsPointXY &point, double searchRadius, QgsPointXY &projectedPoint ) const
967{
969
970 const QgsTriangularMesh *mesh = triangularMesh();
971 int selectedIndex = -1;
972 projectedPoint = QgsPointXY();
973 if ( !mesh )
974 return selectedIndex;
975
976 const QgsRectangle rectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
977 double maxDistance = searchRadius;
978 //attempt to snap on edges's vertices
979 const QList<int> edgeIndexes = mesh->edgeIndexesForRectangle( rectangle );
980 for ( const int edgeIndex : edgeIndexes )
981 {
982 const QgsMeshEdge &edge = mesh->edges().at( edgeIndex );
983 const QgsMeshVertex &vertex1 = mesh->vertices()[edge.first];
984 const QgsMeshVertex &vertex2 = mesh->vertices()[edge.second];
985 const double dist1 = point.distance( vertex1 );
986 const double dist2 = point.distance( vertex2 );
987 if ( dist1 < maxDistance )
988 {
989 maxDistance = dist1;
990 projectedPoint = vertex1;
991 selectedIndex = edge.first;
992 }
993 if ( dist2 < maxDistance )
994 {
995 maxDistance = dist2;
996 projectedPoint = vertex2;
997 selectedIndex = edge.second;
998 }
999 }
1000
1001 //attempt to snap on face's vertices
1002 const QList<int> faceIndexes = mesh->faceIndexesForRectangle( rectangle );
1003 for ( const int faceIndex : faceIndexes )
1004 {
1005 const QgsMeshFace &face = mesh->triangles().at( faceIndex );
1006 for ( int i = 0; i < 3; ++i )
1007 {
1008 const QgsMeshVertex &vertex = mesh->vertices()[face.at( i )];
1009 const double dist = point.distance( vertex );
1010 if ( dist < maxDistance )
1011 {
1012 maxDistance = dist;
1013 projectedPoint = vertex;
1014 selectedIndex = face.at( i );
1015 }
1016 }
1017 }
1018
1019 return selectedIndex;
1020}
1021
1022int QgsMeshLayer::closestFace( const QgsPointXY &point, double searchRadius, QgsPointXY &projectedPoint ) const
1023{
1025
1026 const QgsTriangularMesh *mesh = triangularMesh();
1027 int selectedIndex = -1;
1028 projectedPoint = QgsPointXY();
1029 if ( !mesh )
1030 return selectedIndex;
1031
1032 const QgsRectangle rectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
1033 double maxDistance = std::numeric_limits<double>::max();
1034
1035 const QList<int> faceIndexes = mesh->faceIndexesForRectangle( rectangle );
1036 for ( const int faceIndex : faceIndexes )
1037 {
1038 const int nativefaceIndex = mesh->trianglesToNativeFaces().at( faceIndex );
1039 if ( nativefaceIndex < 0 && nativefaceIndex >= mesh->faceCentroids().count() )
1040 continue;
1041 const QgsPointXY centroid = mesh->faceCentroids()[nativefaceIndex];
1042 const double dist = point.distance( centroid );
1043 if ( dist < maxDistance )
1044 {
1045 maxDistance = dist;
1046 projectedPoint = centroid;
1047 selectedIndex = nativefaceIndex;
1048 }
1049 }
1050
1051 return selectedIndex;
1052}
1053
1055{
1057
1058 mDatasetGroupStore->resetDatasetGroupTreeItem();
1059 updateActiveDatasetGroups();
1060}
1061
1063{
1065
1066 if ( !mDataProvider )
1067 return QgsInterval();
1068 const int groupCount = mDataProvider->datasetGroupCount();
1069 for ( int i = 0; i < groupCount; ++i )
1070 {
1071 const qint64 timeStep = mDataProvider->temporalCapabilities()->firstTimeStepDuration( i );
1072 if ( timeStep > 0 )
1074 }
1075
1076 return QgsInterval();
1077}
1078
1080{
1082
1083 const qint64 time = mDatasetGroupStore->datasetRelativeTime( index );
1084
1085 if ( time == INVALID_MESHLAYER_TIME )
1086 return QgsInterval();
1087 else
1089}
1090
1092{
1094
1095 return mDatasetGroupStore->datasetRelativeTime( index );
1096}
1097
1098static QString detailsErrorMessage( const QgsMeshEditingError &error )
1099{
1100 QString message;
1101
1102 switch ( error.errorType )
1103 {
1105 break;
1107 message = QObject::tr( "Face %1 invalid" ).arg( error.elementIndex );
1108 break;
1110 message = QObject::tr( "Too many vertices for face %1" ).arg( error.elementIndex );
1111 break;
1113 message = QObject::tr( "Face %1 is flat" ).arg( error.elementIndex );
1114 break;
1116 message = QObject::tr( "Vertex %1 is a unique shared vertex" ).arg( error.elementIndex );
1117 break;
1119 message = QObject::tr( "Vertex %1 is invalid" ).arg( error.elementIndex );
1120 break;
1122 message = QObject::tr( "Face %1 is manifold" ).arg( error.elementIndex );
1123 break;
1124 }
1125
1126 return message;
1127}
1128
1130{
1132
1134 return startFrameEditing( transform, error, false );
1135}
1136
1138{
1140
1141 if ( !supportsEditing() )
1142 {
1143 QgsMessageLog::logMessage( QObject::tr( "Mesh layer \"%1\" not support mesh editing" ).arg( name() ) );
1144 return false;
1145 }
1146
1147 if ( mMeshEditor )
1148 {
1149 QgsMessageLog::logMessage( QObject::tr( "Mesh layer \"%1\" already in editing mode" ).arg( name() ) );
1150 return false;
1151 }
1152
1153 mSimplificationSettings.setEnabled( false );
1154
1155 updateTriangularMesh( transform );
1156
1157 mMeshEditor = new QgsMeshEditor( this );
1158
1159 if ( fixErrors )
1160 {
1161 mRendererCache.reset(); // fixing errors could lead to remove faces/vertices
1162 error = mMeshEditor->initializeWithErrorsFix();
1163 }
1164 else
1165 error = mMeshEditor->initialize();
1166
1167 if ( error.errorType != Qgis::MeshEditingErrorType::NoError )
1168 {
1169 mMeshEditor->deleteLater();
1170 mMeshEditor = nullptr;
1171
1172 QgsMessageLog::logMessage( QObject::tr( "Unable to start editing of mesh layer \"%1\": %2" ).
1173 arg( name(), detailsErrorMessage( error ) ), QString(), Qgis::MessageLevel::Critical );
1174 return false;
1175 }
1176
1177 // During editing, we don't need anymore the provider data. Mesh frame data is stored in the mesh editor.
1178 mDataProvider->close();
1179
1180 // All dataset group are removed and replace by a unique virtual dataset group that provide vertices elevation value.
1181 mExtraDatasetUri.clear();
1182 mDatasetGroupStore = std::make_unique<QgsMeshDatasetGroupStore>( this );
1183
1184 mDatasetGroupStore->addDatasetGroup( mMeshEditor->createZValueDatasetGroup() );
1185
1187
1188 connect( mMeshEditor, &QgsMeshEditor::meshEdited, this, &QgsMeshLayer::onMeshEdited );
1189
1190 emit dataChanged();
1191 emit editingStarted();
1192
1193 return true;
1194}
1195
1196bool QgsMeshLayer::commitFrameEditing( const QgsCoordinateTransform &transform, bool continueEditing )
1197{
1199
1201 QString detailsError;
1202 if ( !mMeshEditor->checkConsistency( error ) )
1203 {
1204 if ( error.errorType == Qgis::MeshEditingErrorType::NoError )
1205 detailsError = tr( "Unknown inconsistent mesh error" );
1206 }
1207 else
1208 {
1209 error = QgsTopologicalMesh::checkTopology( *mNativeMesh, mMeshEditor->maximumVerticesPerFace() );
1210 detailsError = detailsErrorMessage( error );
1211 }
1212
1213 if ( !detailsError.isEmpty() )
1214 {
1215 QgsMessageLog::logMessage( QObject::tr( "Edited mesh layer \"%1\" can't be save due to an error: %2" ).
1216 arg( name(), detailsError ), QString(), Qgis::MessageLevel::Critical );
1217 return false;
1218 }
1219
1220 stopFrameEditing( transform );
1221
1222 if ( !mDataProvider )
1223 return false;
1224
1225 const bool res = mDataProvider->saveMeshFrame( *mNativeMesh.get() );
1226
1227 if ( continueEditing )
1228 {
1229 mMeshEditor->initialize();
1230 emit layerModified();
1231 return res;
1232 }
1233
1234 mMeshEditor->deleteLater();
1235 mMeshEditor = nullptr;
1236 emit editingStopped();
1237
1238 mDataProvider->reloadData();
1239 mDataProvider->populateMesh( mNativeMesh.get() );
1240 mDatasetGroupStore = std::make_unique<QgsMeshDatasetGroupStore>( this );
1241 mDatasetGroupStore->setPersistentProvider( mDataProvider, QStringList() );
1243 return true;
1244}
1245
1246bool QgsMeshLayer::rollBackFrameEditing( const QgsCoordinateTransform &transform, bool continueEditing )
1247{
1249
1250 stopFrameEditing( transform );
1251
1252 if ( !mDataProvider )
1253 return false;
1254
1255 mTriangularMeshes.clear();
1256 mDataProvider->reloadData();
1257 mDataProvider->populateMesh( mNativeMesh.get() );
1258 updateTriangularMesh( transform );
1259 mRendererCache = std::make_unique<QgsMeshLayerRendererCache>( );
1261
1262 if ( continueEditing )
1263 {
1264 mMeshEditor->resetTriangularMesh( triangularMesh() );
1265 return mMeshEditor->initialize() == QgsMeshEditingError();
1266 }
1267 else
1268 {
1269 mMeshEditor->deleteLater();
1270 mMeshEditor = nullptr;
1271 emit editingStopped();
1272
1273 mDatasetGroupStore = std::make_unique<QgsMeshDatasetGroupStore>( this );
1274 mDatasetGroupStore->setPersistentProvider( mDataProvider, QStringList() );
1276 emit dataChanged();
1277 return true;
1278 }
1279}
1280
1282{
1284
1285 if ( !mMeshEditor )
1286 return;
1287
1288 mMeshEditor->stopEditing();
1289 mTriangularMeshes.at( 0 )->update( mNativeMesh.get(), transform );
1290 mRendererCache = std::make_unique<QgsMeshLayerRendererCache>( );
1291}
1292
1293bool QgsMeshLayer::reindex( const QgsCoordinateTransform &transform, bool renumber )
1294{
1296
1297 if ( !mMeshEditor )
1298 return false;
1299
1300 if ( !mMeshEditor->reindex( renumber ) )
1301 return false;
1302
1303 mTriangularMeshes.clear();
1304 mTriangularMeshes.emplace_back( new QgsTriangularMesh );
1305 mTriangularMeshes.at( 0 )->update( mNativeMesh.get(), transform );
1306 mRendererCache = std::make_unique<QgsMeshLayerRendererCache>( );
1307 mMeshEditor->resetTriangularMesh( mTriangularMeshes.at( 0 ).get() );
1308
1309 return true;
1310}
1311
1313{
1315
1316 return mMeshEditor;
1317}
1318
1320{
1322
1323 if ( mMeshEditor )
1324 return mMeshEditor->isModified();
1325
1326 return false;
1327}
1328
1330{
1332
1333 switch ( type )
1334 {
1336 return meshVertexCount() != 0;
1338 return meshEdgeCount() != 0;
1340 return meshFaceCount() != 0;
1341 }
1342 return false;
1343}
1344
1346{
1348
1349 if ( mMeshEditor )
1350 return mMeshEditor->validVerticesCount();
1351 else if ( mDataProvider )
1352 return mDataProvider->vertexCount();
1353 else return 0;
1354}
1355
1357{
1359
1360 if ( mMeshEditor )
1361 return mMeshEditor->validFacesCount();
1362 else if ( mDataProvider )
1363 return mDataProvider->faceCount();
1364 else return 0;
1365}
1366
1368{
1370
1371 if ( mMeshEditor )
1372 return mNativeMesh->edgeCount();
1373 else if ( mDataProvider )
1374 return mDataProvider->edgeCount();
1375 else return 0;
1376}
1377
1378void QgsMeshLayer::updateActiveDatasetGroups()
1379{
1381
1382 QgsMeshDatasetGroupTreeItem *treeItem = mDatasetGroupStore->datasetGroupTreeItem();
1383
1384 if ( !mDatasetGroupStore->datasetGroupTreeItem() )
1385 return;
1386
1388 const int oldActiveScalar = settings.activeScalarDatasetGroup();
1389 const int oldActiveVector = settings.activeVectorDatasetGroup();
1390
1391 QgsMeshDatasetGroupTreeItem *activeScalarItem =
1392 treeItem->childFromDatasetGroupIndex( oldActiveScalar );
1393
1394 if ( !activeScalarItem && treeItem->childCount() > 0 && oldActiveScalar != -1 )
1395 activeScalarItem = treeItem->child( 0 );
1396
1397 if ( activeScalarItem && !activeScalarItem->isEnabled() )
1398 {
1399 for ( int i = 0; i < treeItem->childCount(); ++i )
1400 {
1401 activeScalarItem = treeItem->child( i );
1402 if ( activeScalarItem->isEnabled() )
1403 break;
1404 else
1405 activeScalarItem = nullptr;
1406 }
1407 }
1408
1409 if ( activeScalarItem )
1410 settings.setActiveScalarDatasetGroup( activeScalarItem->datasetGroupIndex() );
1411 else
1412 settings.setActiveScalarDatasetGroup( -1 );
1413
1414 QgsMeshDatasetGroupTreeItem *activeVectorItem =
1415 treeItem->childFromDatasetGroupIndex( oldActiveVector );
1416
1417 if ( !( activeVectorItem && activeVectorItem->isEnabled() ) )
1418 settings.setActiveVectorDatasetGroup( -1 );
1419
1420 setRendererSettings( settings );
1421
1422 if ( oldActiveScalar != settings.activeScalarDatasetGroup() )
1424 if ( oldActiveVector != settings.activeVectorDatasetGroup() )
1426}
1427
1428QgsMeshRendererSettings QgsMeshLayer::accordSymbologyWithGroupName( const QgsMeshRendererSettings &settings, const QMap<QString, int> &nameToIndex )
1429{
1430 QString activeScalarName;
1431 QString activeVectorName;
1432 QgsMeshRendererSettings consistentSettings = settings;
1433 int activeScalar = consistentSettings.activeScalarDatasetGroup();
1434 int activeVector = consistentSettings.activeVectorDatasetGroup();
1435
1436 for ( auto it = nameToIndex.constBegin(); it != nameToIndex.constEnd(); ++it )
1437 {
1438 int index = it.value();
1439 const QString name = it.key() ;
1440 int globalIndex = mDatasetGroupStore->indexFromGroupName( name );
1441 if ( globalIndex >= 0 )
1442 {
1443 QgsMeshRendererScalarSettings scalarSettings = settings.scalarSettings( index );
1444 consistentSettings.setScalarSettings( globalIndex, scalarSettings );
1445 if ( settings.hasVectorSettings( it.value() ) && mDatasetGroupStore->datasetGroupMetadata( globalIndex ).isVector() )
1446 {
1447 QgsMeshRendererVectorSettings vectorSettings = settings.vectorSettings( index );
1448 consistentSettings.setVectorSettings( globalIndex, vectorSettings );
1449 }
1450 }
1451 else
1452 {
1453 consistentSettings.removeScalarSettings( index );
1454 if ( settings.hasVectorSettings( it.value() ) )
1455 consistentSettings.removeVectorSettings( index );
1456 }
1457
1458 if ( index == activeScalar )
1459 activeScalarName = name;
1460 if ( index == activeVector )
1461 activeVectorName = name;
1462 }
1463
1464 const QList<int> globalIndexes = datasetGroupsIndexes();
1465 for ( int globalIndex : globalIndexes )
1466 {
1467 const QString name = mDatasetGroupStore->groupName( globalIndex );
1468 if ( !nameToIndex.contains( name ) )
1469 {
1470 consistentSettings.setScalarSettings( globalIndex, mRendererSettings.scalarSettings( globalIndex ) );
1471 if ( mDatasetGroupStore->datasetGroupMetadata( globalIndex ).isVector() )
1472 {
1473 consistentSettings.setVectorSettings( globalIndex, mRendererSettings.vectorSettings( globalIndex ) );
1474 }
1475 }
1476 }
1477
1478 if ( !activeScalarName.isEmpty() )
1479 consistentSettings.setActiveScalarDatasetGroup( mDatasetGroupStore->indexFromGroupName( activeScalarName ) );
1480 if ( !activeVectorName.isEmpty() )
1481 consistentSettings.setActiveVectorDatasetGroup( mDatasetGroupStore->indexFromGroupName( activeVectorName ) );
1482
1483 return consistentSettings;
1484}
1485
1486void QgsMeshLayer::setDataSourcePrivate( const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, Qgis::DataProviderReadFlags flags )
1487{
1489
1490 mDataSource = dataSource;
1491 mLayerName = baseName;
1492 setProviderType( provider );
1493
1494 if ( !mDataSource.isEmpty() && !provider.isEmpty() )
1495 setDataProvider( provider, options, flags );
1496}
1497
1498QgsPointXY QgsMeshLayer::snapOnElement( QgsMesh::ElementType elementType, const QgsPointXY &point, double searchRadius )
1499{
1501
1502 QgsPointXY projectedPoint;
1503 closestElement( elementType, point, searchRadius, projectedPoint );
1504 return projectedPoint;
1505}
1506
1507int QgsMeshLayer::closestElement( QgsMesh::ElementType elementType, const QgsPointXY &point, double searchRadius, QgsPointXY &projectedPoint ) const
1508{
1510
1511 switch ( elementType )
1512 {
1513 case QgsMesh::Vertex:
1514 return closestVertex( point, searchRadius, projectedPoint );
1515 case QgsMesh::Edge:
1516 return closestEdge( point, searchRadius, projectedPoint );
1517 case QgsMesh::Face:
1518 return closestFace( point, searchRadius, projectedPoint );
1519 }
1520 return -1;
1521}
1522
1524{
1526
1527 if ( !mNativeMesh )
1528 {
1529 // lazy loading of mesh data
1530 fillNativeMesh();
1531 }
1532
1533 QList<int> ret;
1534
1535 if ( !mNativeMesh )
1536 return ret;
1537
1538 QgsExpressionContext context;
1539 std::unique_ptr<QgsExpressionContextScope> expScope( QgsExpressionContextUtils::meshExpressionScope( QgsMesh::Vertex ) );
1540 context.appendScope( expScope.release() );
1541 context.lastScope()->setVariable( u"_native_mesh"_s, QVariant::fromValue( *mNativeMesh ) );
1542
1543 expression.prepare( &context );
1544
1545 for ( int i = 0; i < mNativeMesh->vertexCount(); ++i )
1546 {
1547 context.lastScope()->setVariable( u"_mesh_vertex_index"_s, i, false );
1548
1549 if ( expression.evaluate( &context ).toBool() )
1550 ret.append( i );
1551 }
1552
1553 return ret;
1554}
1555
1557{
1559
1560 if ( !mNativeMesh )
1561 {
1562 // lazy loading of mesh data
1563 fillNativeMesh();
1564 }
1565
1566 QList<int> ret;
1567
1568 if ( !mNativeMesh )
1569 return ret;
1570
1571 QgsExpressionContext context;
1572 std::unique_ptr<QgsExpressionContextScope> expScope( QgsExpressionContextUtils::meshExpressionScope( QgsMesh::Face ) );
1573 context.appendScope( expScope.release() );
1574 context.lastScope()->setVariable( u"_native_mesh"_s, QVariant::fromValue( *mNativeMesh ) );
1575
1576 expression.prepare( &context );
1577
1578 for ( int i = 0; i < mNativeMesh->faceCount(); ++i )
1579 {
1580 context.lastScope()->setVariable( u"_mesh_face_index"_s, i, false );
1581
1582 if ( expression.evaluate( &context ).toBool() )
1583 ret.append( i );
1584 }
1585
1586 return ret;
1587}
1588
1590{
1592
1593 return QgsMeshDatasetIndex( group >= 0 ? group : mRendererSettings.activeScalarDatasetGroup(), mStaticScalarDatasetIndex );
1594}
1595
1597{
1599
1600 const int oldActiveVector = mRendererSettings.activeVectorDatasetGroup();
1601
1602 mStaticVectorDatasetIndex = staticVectorDatasetIndex.dataset();
1603 mRendererSettings.setActiveVectorDatasetGroup( staticVectorDatasetIndex.group() );
1604
1605 if ( oldActiveVector != mRendererSettings.activeVectorDatasetGroup() )
1606 emit activeVectorDatasetGroupChanged( mRendererSettings.activeVectorDatasetGroup() );
1607}
1608
1610{
1612
1613 const int oldActiveScalar = mRendererSettings.activeScalarDatasetGroup();
1614
1615 mStaticScalarDatasetIndex = staticScalarDatasetIndex.dataset();
1616 mRendererSettings.setActiveScalarDatasetGroup( staticScalarDatasetIndex.group() );
1617
1618 if ( oldActiveScalar != mRendererSettings.activeScalarDatasetGroup() )
1619 emit activeScalarDatasetGroupChanged( mRendererSettings.activeScalarDatasetGroup() );
1620}
1621
1628
1630{
1632
1633 mSimplificationSettings = simplifySettings;
1634}
1635
1636static QgsColorRamp *_createDefaultColorRamp()
1637{
1638 QgsColorRamp *ramp = QgsStyle::defaultStyle()->colorRamp( u"Plasma"_s );
1639 if ( ramp )
1640 return ramp;
1641
1642 // definition of "Plasma" color ramp (in case it is not available in the style for some reason)
1643 QVariantMap props;
1644 props["color1"] = "13,8,135,255";
1645 props["color2"] = "240,249,33,255";
1646 props["stops"] =
1647 "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:"
1648 "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:"
1649 "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:"
1650 "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:"
1651 "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:"
1652 "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:"
1653 "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:"
1654 "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:"
1655 "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:"
1656 "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";
1657 return QgsGradientColorRamp::create( props );
1658}
1659
1660void QgsMeshLayer::assignDefaultStyleToDatasetGroup( int groupIndex )
1661{
1663
1664 const QgsMeshDatasetGroupMetadata metadata = datasetGroupMetadata( groupIndex );
1665 const double groupMin = metadata.minimum();
1666 const double groupMax = metadata.maximum();
1667
1668 QgsColorRampShader fcn( groupMin, groupMax, _createDefaultColorRamp() );
1669 fcn.classifyColorRamp( 5, -1, QgsRectangle(), nullptr );
1670
1671 QgsMeshRendererScalarSettings scalarSettings;
1672 scalarSettings.setClassificationMinimumMaximum( groupMin, groupMax );
1673 scalarSettings.setColorRampShader( fcn );
1674 QgsInterpolatedLineWidth edgeStrokeWidth;
1675 edgeStrokeWidth.setMinimumValue( groupMin );
1676 edgeStrokeWidth.setMaximumValue( groupMax );
1677 const QgsInterpolatedLineColor edgeStrokeColor( fcn );
1678 const QgsInterpolatedLineRenderer edgeStrokePen;
1679 scalarSettings.setEdgeStrokeWidth( edgeStrokeWidth );
1680 mRendererSettings.setScalarSettings( groupIndex, scalarSettings );
1681
1682 if ( metadata.isVector() )
1683 {
1684 QgsMeshRendererVectorSettings vectorSettings;
1685 vectorSettings.setColorRampShader( fcn );
1686 mRendererSettings.setVectorSettings( groupIndex, vectorSettings );
1687 }
1688}
1689
1691{
1693
1694 // Triangular mesh
1695 updateTriangularMesh( rendererContext.coordinateTransform() );
1696
1697 // Build overview triangular meshes if needed
1698 createSimplifiedMeshes();
1699
1700 // Cache
1701 if ( !mRendererCache )
1702 mRendererCache = std::make_unique<QgsMeshLayerRendererCache>( );
1703
1704 return new QgsMeshLayerRenderer( this, rendererContext );
1705}
1706
1708{
1709 if ( rendererContext.isTemporal() )
1710 return activeScalarDatasetAtTime( rendererContext.temporalRange(), mRendererSettings.activeScalarDatasetGroup() );
1711 else
1712 return staticScalarDatasetIndex( mRendererSettings.activeScalarDatasetGroup() );
1713}
1714
1715bool QgsMeshLayer::minimumMaximumActiveScalarDataset( const QgsRectangle &extent, const QgsMeshDatasetIndex &datasetIndex, double &min, double &max )
1716{
1717
1718 if ( extent.isNull() || !this->extent().intersects( extent ) )
1719 return false;
1720
1722
1723 if ( ! tMesh )
1724 {
1725 return false;
1726 }
1727
1728 QVector<double> scalarDatasetValues;
1730
1731 if ( !metadata.isScalar() )
1732 {
1733 return false;
1734 }
1735
1736 QgsMeshDatasetGroupMetadata::DataType scalarDataType = QgsMeshLayerUtils::datasetValuesType( metadata.dataType() );
1737
1738 if ( !datasetIndex.isValid() )
1739 {
1740 return false;
1741 }
1742
1743 // populate scalar values
1744 const int count = QgsMeshLayerUtils::datasetValuesCount( mNativeMesh.get(), scalarDataType );
1745 const QgsMeshDataBlock vals = QgsMeshLayerUtils::datasetValues(
1746 this,
1747 datasetIndex,
1748 0,
1749 count );
1750
1751 if ( vals.isValid() )
1752 {
1753 // vals could be scalar or vectors, for contour rendering we want always magnitude
1754 scalarDatasetValues = QgsMeshLayerUtils::calculateMagnitudes( vals );
1755 }
1756 else
1757 {
1758 scalarDatasetValues = QVector<double>( count, std::numeric_limits<double>::quiet_NaN() );
1759 }
1760
1761 QList<int> intersectedFacesIndices = tMesh->faceIndexesForRectangle( extent );
1762
1763 if ( intersectedFacesIndices.isEmpty() )
1764 {
1765 return false;
1766 }
1767
1768 min = std::numeric_limits<double>::max();
1769 max = -std::numeric_limits<double>::max();
1770
1771 double value;
1772
1773 for ( int intersectedFaceIndex : intersectedFacesIndices )
1774 {
1775 QgsMeshFace face = tMesh->triangles().at( intersectedFaceIndex );
1776
1778 {
1779 value = scalarDatasetValues.at( tMesh->trianglesToNativeFaces().at( intersectedFaceIndex ) );
1780 min = std::min( min, value );
1781 max = std::max( max, value );
1782 }
1784 {
1785 QgsMeshVertex vertex;
1786
1787 for ( int vertexIndex : face )
1788 {
1789 value = scalarDatasetValues.at( vertexIndex );
1790 min = std::min( min, value );
1791 max = std::max( max, value );
1792 }
1793 }
1794 }
1795
1796 return true;
1797}
1798
1805
1806void QgsMeshLayer::checkSymbologyConsistency()
1807{
1809
1810 const QList<int> groupIndexes = mDatasetGroupStore->datasetGroupIndexes();
1811 if ( !groupIndexes.contains( mRendererSettings.activeScalarDatasetGroup() ) &&
1812 mRendererSettings.activeScalarDatasetGroup() != -1 )
1813 {
1814 if ( !groupIndexes.empty() )
1815 mRendererSettings.setActiveScalarDatasetGroup( groupIndexes.first() );
1816 else
1817 mRendererSettings.setActiveScalarDatasetGroup( -1 );
1818 }
1819
1820 if ( !groupIndexes.contains( mRendererSettings.activeVectorDatasetGroup() ) &&
1821 mRendererSettings.activeVectorDatasetGroup() != -1 )
1822 {
1823 mRendererSettings.setActiveVectorDatasetGroup( -1 );
1824 }
1825}
1826
1827bool QgsMeshLayer::readSymbology( const QDomNode &node, QString &errorMessage,
1829{
1831
1832 Q_UNUSED( errorMessage )
1833 // TODO: implement categories for raster layer
1834
1835 const QDomElement elem = node.toElement();
1836
1837 readCommonStyle( elem, context, categories );
1838
1840 const QDomElement elemRendererSettings = elem.firstChildElement( "mesh-renderer-settings" );
1841 if ( !elemRendererSettings.isNull() )
1842 rendererSettings.readXml( elemRendererSettings, context );
1843
1844 QMap<QString, int> groupNameToGlobalIndex;
1845 QDomElement nameToIndexElem = elem.firstChildElement( "name-to-global-index" );
1846 while ( !nameToIndexElem.isNull() )
1847 {
1848 const QString name = nameToIndexElem.attribute( u"name"_s );
1849 int globalIndex = nameToIndexElem.attribute( u"global-index"_s ).toInt();
1850 groupNameToGlobalIndex.insert( name, globalIndex );
1851 nameToIndexElem = nameToIndexElem.nextSiblingElement( u"name-to-global-index"_s );
1852 }
1853
1854 mRendererSettings = accordSymbologyWithGroupName( rendererSettings, groupNameToGlobalIndex );
1855
1856 checkSymbologyConsistency();
1857
1858 const QDomElement elemSimplifySettings = elem.firstChildElement( "mesh-simplify-settings" );
1859 if ( !elemSimplifySettings.isNull() )
1860 mSimplificationSettings.readXml( elemSimplifySettings, context );
1861
1862 // get and set the blend mode if it exists
1863 const QDomNode blendModeNode = node.namedItem( u"blendMode"_s );
1864 if ( !blendModeNode.isNull() )
1865 {
1866 const QDomElement e = blendModeNode.toElement();
1867 setBlendMode( QgsPainting::getCompositionMode( static_cast< Qgis::BlendMode >( e.text().toInt() ) ) );
1868 }
1869
1870 // read labeling definition
1871 if ( categories.testFlag( Labeling ) )
1872 {
1873 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Labeling" ) );
1874
1875 QDomElement labelingElement = node.firstChildElement( u"labeling"_s );
1876 if ( !labelingElement.isNull() )
1877 {
1879 mLabelsEnabled = node.toElement().attribute( u"labelsEnabled"_s, u"0"_s ).toInt();
1881 }
1882 }
1883
1884 // get and set the layer transparency
1885 if ( categories.testFlag( Rendering ) )
1886 {
1887 const QDomNode layerOpacityNode = node.namedItem( u"layerOpacity"_s );
1888 if ( !layerOpacityNode.isNull() )
1889 {
1890 const QDomElement e = layerOpacityNode.toElement();
1891 setOpacity( e.text().toDouble() );
1892 }
1893 }
1894
1895 if ( categories.testFlag( Legend ) )
1896 {
1897 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Legend" ) );
1898
1899 const QDomElement legendElem = node.firstChildElement( u"legend"_s );
1900 if ( QgsMapLayerLegend *l = legend(); !legendElem.isNull() )
1901 {
1902 l->readXml( legendElem, context );
1903 }
1904 }
1905
1906 return true;
1907}
1908
1909bool QgsMeshLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage,
1910 const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1911{
1913
1914 Q_UNUSED( errorMessage )
1915 // TODO: implement categories for raster layer
1916
1917 QDomElement elem = node.toElement();
1918
1919 writeCommonStyle( elem, doc, context, categories );
1920
1921 const QDomElement elemRendererSettings = mRendererSettings.writeXml( doc, context );
1922 elem.appendChild( elemRendererSettings );
1923
1924 const QList<int> groupIndexes = datasetGroupsIndexes();
1925 // we store the relation between name and indexes to be able to retrieve the consistency between name and symbology
1926 for ( int index : groupIndexes )
1927 {
1928 QDomElement elemNameToIndex = doc.createElement( u"name-to-global-index"_s );
1929 elemNameToIndex.setAttribute( u"name"_s, mDatasetGroupStore->groupName( index ) );
1930 elemNameToIndex.setAttribute( u"global-index"_s, index );
1931 elem.appendChild( elemNameToIndex );
1932 }
1933
1934 const QDomElement elemSimplifySettings = mSimplificationSettings.writeXml( doc, context );
1935 elem.appendChild( elemSimplifySettings );
1936
1937 // add blend mode node
1938 QDomElement blendModeElement = doc.createElement( u"blendMode"_s );
1939 const QDomText blendModeText = doc.createTextNode( QString::number( static_cast< int >( QgsPainting::getBlendModeEnum( blendMode() ) ) ) );
1940 blendModeElement.appendChild( blendModeText );
1941 node.appendChild( blendModeElement );
1942
1943 if ( categories.testFlag( Labeling ) )
1944 {
1945 if ( mLabeling )
1946 {
1947 QDomElement labelingElement = mLabeling->save( doc, context );
1948 elem.appendChild( labelingElement );
1949 }
1950 elem.setAttribute( u"labelsEnabled"_s, mLabelsEnabled ? u"1"_s : u"0"_s );
1951 }
1952
1953 // add the layer opacity
1954 if ( categories.testFlag( Rendering ) )
1955 {
1956 QDomElement layerOpacityElem = doc.createElement( u"layerOpacity"_s );
1957 const QDomText layerOpacityText = doc.createTextNode( QString::number( opacity() ) );
1958 layerOpacityElem.appendChild( layerOpacityText );
1959 node.appendChild( layerOpacityElem );
1960 }
1961
1962 if ( categories.testFlag( Legend ) && legend() )
1963 {
1964 QDomElement legendElement = legend()->writeXml( doc, context );
1965 if ( !legendElement.isNull() )
1966 node.appendChild( legendElement );
1967 }
1968
1969 return true;
1970}
1971
1972bool QgsMeshLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1973{
1975
1976 return writeSymbology( node, doc, errorMessage, context, categories );
1977}
1978
1979bool QgsMeshLayer::readStyle( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
1980{
1982
1983 return readSymbology( node, errorMessage, context, categories );
1984}
1985
1986QString QgsMeshLayer::decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const
1987{
1989
1990 return QgsProviderRegistry::instance()->relativeToAbsoluteUri( provider, source, context );
1991}
1992
1993QString QgsMeshLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
1994{
1996
1998}
1999
2000bool QgsMeshLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &context )
2001{
2003
2004 QgsDebugMsgLevel( u"Datasource in QgsMeshLayer::readXml: %1"_s.arg( mDataSource.toLocal8Bit().data() ), 3 );
2005
2006 //process provider key
2007 const QDomNode pkeyNode = layer_node.namedItem( u"provider"_s );
2008
2009 if ( pkeyNode.isNull() )
2010 {
2011 mProviderKey.clear();
2012 }
2013 else
2014 {
2015 const QDomElement pkeyElt = pkeyNode.toElement();
2016 mProviderKey = pkeyElt.text();
2017 }
2018
2020 {
2021 return false;
2022 }
2023
2024 const QgsDataProvider::ProviderOptions providerOptions;
2026
2027 const QDomElement elemExtraDatasets = layer_node.firstChildElement( u"extra-datasets"_s );
2028 if ( !elemExtraDatasets.isNull() )
2029 {
2030 QDomElement elemUri = elemExtraDatasets.firstChildElement( u"uri"_s );
2031 while ( !elemUri.isNull() )
2032 {
2033 const QString uri = context.pathResolver().readPath( elemUri.text() );
2034 mExtraDatasetUri.append( uri );
2035 elemUri = elemUri.nextSiblingElement( u"uri"_s );
2036 }
2037 }
2038
2039 if ( pkeyNode.toElement().hasAttribute( u"time-unit"_s ) )
2040 mTemporalUnit = static_cast<Qgis::TemporalUnit>( pkeyNode.toElement().attribute( u"time-unit"_s ).toInt() );
2041
2042 // read dataset group store
2043 const QDomElement elemDatasetGroupsStore = layer_node.firstChildElement( u"mesh-dataset-groups-store"_s );
2044 if ( elemDatasetGroupsStore.isNull() )
2046 else
2047 mDatasetGroupStore->readXml( elemDatasetGroupsStore, context );
2048
2049 setDataProvider( mProviderKey, providerOptions, flags );
2050
2051 QString errorMsg;
2052 readSymbology( layer_node, errorMsg, context );
2053
2054 if ( !mTemporalProperties->timeExtent().begin().isValid() || mTemporalProperties->alwaysLoadReferenceTimeFromSource() )
2056
2057 // read static dataset
2058 const QDomElement elemStaticDataset = layer_node.firstChildElement( u"static-active-dataset"_s );
2059 if ( elemStaticDataset.hasAttribute( u"scalar"_s ) )
2060 {
2061 mStaticScalarDatasetIndex = elemStaticDataset.attribute( u"scalar"_s ).toInt();
2062 }
2063 if ( elemStaticDataset.hasAttribute( u"vector"_s ) )
2064 {
2065 mStaticVectorDatasetIndex = elemStaticDataset.attribute( u"vector"_s ).toInt();
2066 }
2067
2068 return isValid(); // should be true if read successfully
2069}
2070
2071bool QgsMeshLayer::writeXml( QDomNode &layer_node, QDomDocument &document, const QgsReadWriteContext &context ) const
2072{
2074
2075 // first get the layer element so that we can append the type attribute
2076 QDomElement mapLayerNode = layer_node.toElement();
2077
2078 if ( mapLayerNode.isNull() || ( "maplayer"_L1 != mapLayerNode.nodeName() ) )
2079 {
2080 QgsDebugMsgLevel( u"can't find <maplayer>"_s, 2 );
2081 return false;
2082 }
2083
2084 mapLayerNode.setAttribute( u"type"_s, QgsMapLayerFactory::typeToString( Qgis::LayerType::Mesh ) );
2085
2086 // add provider node
2087 if ( mDataProvider )
2088 {
2089 QDomElement provider = document.createElement( u"provider"_s );
2090 const QDomText providerText = document.createTextNode( providerType() );
2091 provider.appendChild( providerText );
2092 layer_node.appendChild( provider );
2093 provider.setAttribute( u"time-unit"_s, static_cast< int >( mDataProvider->temporalCapabilities()->temporalUnit() ) );
2094
2095 const QStringList extraDatasetUris = mDataProvider->extraDatasets();
2096 QDomElement elemExtraDatasets = document.createElement( u"extra-datasets"_s );
2097 for ( const QString &uri : extraDatasetUris )
2098 {
2099 const QString path = context.pathResolver().writePath( uri );
2100 QDomElement elemUri = document.createElement( u"uri"_s );
2101 elemUri.appendChild( document.createTextNode( path ) );
2102 elemExtraDatasets.appendChild( elemUri );
2103 }
2104 layer_node.appendChild( elemExtraDatasets );
2105 }
2106
2107 QDomElement elemStaticDataset = document.createElement( u"static-active-dataset"_s );
2108 elemStaticDataset.setAttribute( u"scalar"_s, mStaticScalarDatasetIndex );
2109 elemStaticDataset.setAttribute( u"vector"_s, mStaticVectorDatasetIndex );
2110 layer_node.appendChild( elemStaticDataset );
2111
2112 // write dataset group store if not in edting mode
2113 if ( !isEditable() )
2114 layer_node.appendChild( mDatasetGroupStore->writeXml( document, context ) );
2115
2116 // renderer specific settings
2117 QString errorMsg;
2118 return writeSymbology( layer_node, document, errorMsg, context );
2119}
2120
2122{
2124
2125 if ( !mMeshEditor && mDataProvider && mDataProvider->isValid() )
2126 {
2127 mDataProvider->reloadData();
2128 mDatasetGroupStore->setPersistentProvider( mDataProvider, QStringList() ); //extra dataset are already loaded
2129
2130 //reload the mesh structure
2131 if ( !mNativeMesh )
2132 mNativeMesh = std::make_unique<QgsMesh>( );
2133
2134 dataProvider()->populateMesh( mNativeMesh.get() );
2135
2136 if ( mTemporalProperties->alwaysLoadReferenceTimeFromSource() )
2137 mTemporalProperties->setDefaultsFromDataProviderTemporalCapabilities( mDataProvider->temporalCapabilities() );
2138
2139 //clear the TriangularMeshes
2140 mTriangularMeshes.clear();
2141
2142 //clear the rendererCache
2143 mRendererCache = std::make_unique<QgsMeshLayerRendererCache>( );
2144
2145 checkSymbologyConsistency();
2146
2147 emit reloaded();
2148 }
2149}
2150
2151QStringList QgsMeshLayer::subLayers() const
2152{
2154
2155 if ( mDataProvider )
2156 return mDataProvider->subLayers();
2157 else
2158 return QStringList();
2159}
2160
2162{
2164
2165 const QgsLayerMetadataFormatter htmlFormatter( metadata() );
2166 QString myMetadata = u"<html>\n<body>\n"_s;
2167
2168 myMetadata += generalHtmlMetadata();
2169
2170 // Begin Provider section
2171 myMetadata += u"<h1>"_s + tr( "Information from provider" ) + u"</h1>\n<hr>\n"_s;
2172 myMetadata += "<table class=\"list-view\">\n"_L1;
2173
2174 // Extent
2175 myMetadata += u"<tr><td class=\"highlight\">"_s + tr( "Extent" ) + u"</td><td>"_s + extent().toString() + u"</td></tr>\n"_s;
2176
2177 // feature count
2178 QLocale locale = QLocale();
2179 locale.setNumberOptions( locale.numberOptions() &= ~QLocale::NumberOption::OmitGroupSeparator );
2180
2181 if ( const QgsMeshDataProvider *provider = dataProvider() )
2182 {
2183 myMetadata += u"<tr><td class=\"highlight\">"_s
2184 + tr( "Vertex count" ) + u"</td><td>"_s
2185 + ( locale.toString( static_cast<qlonglong>( meshVertexCount() ) ) )
2186 + u"</td></tr>\n"_s;
2187 myMetadata += u"<tr><td class=\"highlight\">"_s
2188 + tr( "Face count" ) + u"</td><td>"_s
2189 + ( locale.toString( static_cast<qlonglong>( meshFaceCount() ) ) )
2190 + u"</td></tr>\n"_s;
2191 myMetadata += u"<tr><td class=\"highlight\">"_s
2192 + tr( "Edge count" ) + u"</td><td>"_s
2193 + ( locale.toString( static_cast<qlonglong>( meshEdgeCount() ) ) )
2194 + u"</td></tr>\n"_s;
2195 myMetadata += u"<tr><td class=\"highlight\">"_s
2196 + tr( "Dataset groups count" ) + u"</td><td>"_s
2197 + ( locale.toString( static_cast<qlonglong>( datasetGroupCount() ) ) )
2198 + u"</td></tr>\n"_s;
2199 myMetadata += provider->htmlMetadata();
2200 }
2201
2202 // End Provider section
2203 myMetadata += "</table>\n<br><br>"_L1;
2204
2205 // CRS
2206 myMetadata += crsHtmlMetadata();
2207
2208 // identification section
2209 myMetadata += u"<h1>"_s + tr( "Identification" ) + u"</h1>\n<hr>\n"_s;
2210 myMetadata += htmlFormatter.identificationSectionHtml( );
2211 myMetadata += "<br><br>\n"_L1;
2212
2213 // extent section
2214 myMetadata += u"<h1>"_s + tr( "Extent" ) + u"</h1>\n<hr>\n"_s;
2215 myMetadata += htmlFormatter.extentSectionHtml( isSpatial() );
2216 myMetadata += "<br><br>\n"_L1;
2217
2218 // Start the Access section
2219 myMetadata += u"<h1>"_s + tr( "Access" ) + u"</h1>\n<hr>\n"_s;
2220 myMetadata += htmlFormatter.accessSectionHtml( );
2221 myMetadata += "<br><br>\n"_L1;
2222
2223 // Start the contacts section
2224 myMetadata += u"<h1>"_s + tr( "Contacts" ) + u"</h1>\n<hr>\n"_s;
2225 myMetadata += htmlFormatter.contactsSectionHtml( );
2226 myMetadata += "<br><br>\n"_L1;
2227
2228 // Start the links section
2229 myMetadata += u"<h1>"_s + tr( "Links" ) + u"</h1>\n<hr>\n"_s;
2230 myMetadata += htmlFormatter.linksSectionHtml( );
2231 myMetadata += "<br><br>\n"_L1;
2232
2233 // Start the history section
2234 myMetadata += u"<h1>"_s + tr( "History" ) + u"</h1>\n<hr>\n"_s;
2235 myMetadata += htmlFormatter.historySectionHtml( );
2236 myMetadata += "<br><br>\n"_L1;
2237
2238 myMetadata += customPropertyHtmlMetadata();
2239
2240 myMetadata += "\n</body>\n</html>\n"_L1;
2241 return myMetadata;
2242}
2243
2245{
2247
2248 return mMeshEditor;
2249}
2250
2251bool QgsMeshLayer::setDataProvider( QString const &provider, const QgsDataProvider::ProviderOptions &options, Qgis::DataProviderReadFlags flags )
2252{
2254
2255 mDatasetGroupStore->setPersistentProvider( nullptr, QStringList() );
2256
2257 delete mDataProvider;
2258 mProviderKey = provider;
2259 const QString dataSource = mDataSource;
2260
2261 if ( mPreloadedProvider )
2262 {
2263 mDataProvider = qobject_cast< QgsMeshDataProvider * >( mPreloadedProvider.release() );
2264 }
2265 else
2266 {
2267 std::unique_ptr< QgsScopedRuntimeProfile > profile;
2268 if ( QgsApplication::profiler()->groupIsActive( u"projectload"_s ) )
2269 profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Create %1 provider" ).arg( provider ), u"projectload"_s );
2270
2271 mDataProvider = qobject_cast<QgsMeshDataProvider *>( QgsProviderRegistry::instance()->createProvider( provider, dataSource, options, flags ) );
2272 }
2273
2274 if ( !mDataProvider )
2275 {
2276 QgsDebugMsgLevel( u"Unable to get mesh data provider"_s, 2 );
2277 return false;
2278 }
2279
2280 mDataProvider->setParent( this );
2281 QgsDebugMsgLevel( u"Instantiated the mesh data provider plugin"_s, 2 );
2282
2283 setValid( mDataProvider->isValid() );
2284 if ( !isValid() )
2285 {
2286 QgsDebugMsgLevel( u"Invalid mesh provider plugin %1"_s.arg( QString( mDataSource.toUtf8() ) ), 2 );
2287 return false;
2288 }
2289
2290 if ( !mTemporalProperties->isValid() )
2291 {
2292 mTemporalProperties->setDefaultsFromDataProviderTemporalCapabilities( dataProvider()->temporalCapabilities() );
2293 }
2294
2295 mDataProvider->setTemporalUnit( mTemporalUnit );
2296
2297 mDatasetGroupStore->setPersistentProvider( mDataProvider, mExtraDatasetUri );
2298
2299 setCrs( mDataProvider->crs() );
2300
2301 if ( provider == "mesh_memory"_L1 )
2302 {
2303 // required so that source differs between memory layers
2304 mDataSource = mDataSource + u"&uid=%1"_s.arg( QUuid::createUuid().toString() );
2305 }
2306
2307 // set default style if required by flags or if the dataset group does not has a style yet
2308 for ( int i = 0; i < mDataProvider->datasetGroupCount(); ++i )
2309 {
2310 int globalIndex = mDatasetGroupStore->globalDatasetGroupIndexInSource( mDataProvider, i );
2311 if ( globalIndex != -1 &&
2312 ( !mRendererSettings.hasSettings( globalIndex ) || ( flags & Qgis::DataProviderReadFlag::LoadDefaultStyle ) ) )
2313 assignDefaultStyleToDatasetGroup( globalIndex );
2314 }
2315
2316 emit rendererChanged();
2318
2319 connect( mDataProvider, &QgsMeshDataProvider::dataChanged, this, &QgsMeshLayer::dataChanged );
2320
2321 return true;
2322}
2323
2330
2337
2339{
2341
2342 return mLabelsEnabled && static_cast< bool >( mLabeling );
2343}
2344
2346{
2348
2349 mLabelsEnabled = enabled;
2350}
2351
2353{
2355
2356 if ( mLabeling == labeling )
2357 return;
2358
2359 delete mLabeling;
2360 mLabeling = labeling;
2362}
2363
2364bool QgsMeshLayer::datasetsPathUnique( const QString &path )
2365{
2366 if ( ! mDataProvider )
2367 {
2368 QgsDebugMsgLevel( u"Unable to get mesh data provider"_s, 2 );
2369 return false;
2370 }
2371
2372 if ( mDataProvider->dataSourceUri().contains( path ) )
2373 return false;
2374
2375 return !mExtraDatasetUri.contains( path );
2376}
Provides global constants and enumerations for use throughout the application.
Definition qgis.h:59
@ Exact
Assigns the color of the exact matching value in the color ramp item list.
Definition qgis.h:1486
@ Critical
Critical/error message.
Definition qgis.h:162
@ TooManyVerticesInFace
A face has more vertices than the maximum number supported per face.
Definition qgis.h:1720
@ InvalidFace
An error occurs due to an invalid face (for example, vertex indexes are unordered).
Definition qgis.h:1719
@ UniqueSharedVertex
A least two faces share only one vertices.
Definition qgis.h:1722
@ ManifoldFace
ManifoldFace.
Definition qgis.h:1724
@ InvalidVertex
An error occurs due to an invalid vertex (for example, vertex index is out of range the available ver...
Definition qgis.h:1723
@ FlatFace
A flat face is present.
Definition qgis.h:1721
BlendMode
Blending modes defining the available composition modes that can be used when painting.
Definition qgis.h:5002
TemporalUnit
Temporal units.
Definition qgis.h:5231
@ Milliseconds
Milliseconds.
Definition qgis.h:5232
QFlags< DataProviderReadFlag > DataProviderReadFlags
Flags which control data provider construction.
Definition qgis.h:505
@ EqualInterval
Uses equal interval.
Definition qgis.h:1500
@ Mesh
Mesh layer. Added in QGIS 3.2.
Definition qgis.h:197
@ LoadDefaultStyle
Reset the layer's style to the default for the datasource.
Definition qgis.h:489
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.
Abstract base class for objects which generate elevation profiles.
static QgsRuntimeProfiler * profiler()
Returns the application runtime profiler.
A ramp shader will color a raster pixel based on a list of values ranges in a ramp.
void setClassificationMode(Qgis::ShaderClassificationMethod classificationMode)
Sets the classification mode.
QgsColorRamp * sourceColorRamp() const
Returns the source color ramp.
void setColorRampType(Qgis::ShaderInterpolationMethod colorRampType)
Sets the color ramp interpolation method.
void setColorRampItemList(const QList< QgsColorRampShader::ColorRampItem > &list)
Sets a custom color map.
Abstract base class for color ramps.
virtual QColor color(double value) const =0
Returns the color corresponding to a specified value.
Contains information about the context in which a coordinate transform is executed.
Handles coordinate transforms between two coordinate systems.
Base class for handling properties relating to a data provider's temporal capabilities.
bool hasTemporalCapabilities() const
Returns true if the provider has temporal capabilities available.
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.
void setVariable(const QString &name, const QVariant &value, bool isStatic=false)
Convenience method for setting a variable in the context scope by name name and value.
static QgsExpressionContextScope * meshExpressionScope(QgsMesh::ElementType elementType)
Creates a new scope which contains functions relating to mesh layer element elementType.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QgsExpressionContextScope * lastScope()
Returns the last scope added to the context.
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
Handles parsing and evaluation of expressions (formerly called "search strings").
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
QVariant evaluate()
Evaluate the feature and return the result.
static QgsColorRamp * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsColorRamp from a map of properties.
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:50
double seconds() const
Returns the interval duration in seconds.
Formats layer metadata into HTML.
Base class for storage of map layer elevation properties.
static QString typeToString(Qgis::LayerType type)
Converts a map layer type to a string value.
An abstract interface for implementations of legends for one map layer.
static QgsMapLayerLegend * defaultMeshLegend(QgsMeshLayer *ml)
Create new legend implementation for mesh layer.
virtual QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Writes configuration to a DOM element, to be used later with readXml().
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...
QString name
Definition qgsmaplayer.h:87
virtual bool isSpatial() const
Returns true if the layer is considered a spatial layer, ie it has some form of geometry associated w...
QgsMapLayerLegend * legend() const
Can be nullptr.
void editingStopped()
Emitted when edited changes have been successfully written to the data provider.
QString source() const
Returns the source for the layer.
QString providerType() const
Returns the provider type (provider key) for this layer.
void setBlendMode(QPainter::CompositionMode blendMode)
Set the blending mode used for rendering a layer.
void trigger3DUpdate()
Will advise any 3D maps that this layer requires to be updated in the scene.
static Qgis::DataProviderReadFlags providerReadFlags(const QDomNode &layerNode, QgsMapLayer::ReadFlags layerReadFlags)
Returns provider read flag deduced from layer read flags layerReadFlags and a dom node layerNode that...
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:89
QgsMapLayer(Qgis::LayerType type=Qgis::LayerType::Vector, const QString &name=QString(), const QString &source=QString())
Constructor for QgsMapLayer.
Qgis::LayerType type
Definition qgsmaplayer.h:93
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.
QgsMapLayer::LayerFlags flags
Definition qgsmaplayer.h:99
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:95
@ Rendering
Rendering: scale visibility, simplify method, opacity.
@ Legend
Legend settings.
@ Labeling
Labeling.
void layerModified()
Emitted when modifications has been done on layer.
void setProviderType(const QString &providerType)
Sets the providerType (provider key).
QString customPropertyHtmlMetadata() const
Returns an HTML fragment containing custom property information, for use in the htmlMetadata() method...
QString generalHtmlMetadata() const
Returns an HTML fragment containing general metadata information, for use in the htmlMetadata() metho...
void writeCommonStyle(QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) const
Write style data common to all layer types.
void invalidateWgs84Extent()
Invalidates the WGS84 extent.
bool mShouldValidateCrs
true if the layer's CRS should be validated and invalid CRSes are not permitted.
void setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer's spatial reference system.
Abstract class for interpolating 3d stacked mesh data to 2d data.
QgsMeshDataBlock calculate(const QgsMesh3DDataBlock &block3d, QgsFeedback *feedback=nullptr) const
Calculated 2d block values from 3d stacked mesh values.
A block of 3d stacked mesh data related N faces defined on base mesh frame.
A block of integers/doubles from a mesh dataset.
QgsMeshDatasetValue value(int index) const
Returns a value represented by the index For active flag the behavior is undefined.
bool isValid() const
Whether the block is valid.
MatchingTemporalDatasetMethod
Method for selection of temporal mesh dataset from a range time.
Base class for providing data for QgsMeshLayer.
QgsMeshDataProviderTemporalCapabilities * temporalCapabilities() override
Returns the provider's temporal capabilities.
virtual void populateMesh(QgsMesh *mesh) const =0
Populates the mesh vertices, edges and faces.
A collection of dataset group metadata such as whether the data is vector or scalar,...
QMap< QString, QString > extraOptions() const
Returns extra metadata options, for example description.
bool isVector() const
Returns whether dataset group has vector data.
DataType dataType() const
Returns whether dataset group data is defined on vertices or faces or volumes.
double minimum() const
Returns minimum scalar value/vector magnitude present for whole dataset group.
double maximum() const
Returns maximum scalar value/vector magnitude present for whole dataset group.
DataType
Location of where data is specified for datasets in the dataset group.
@ DataOnEdges
Data is defined on edges.
@ DataOnFaces
Data is defined on faces.
@ DataOnVertices
Data is defined on vertices.
@ DataOnVolumes
Data is defined on volumes.
QString uri() const
Returns the uri of the source.
Registers and accesses all the dataset groups related to a mesh layer.
void datasetGroupsAdded(QList< int > indexes)
Emitted after dataset groups are added.
Tree item for display of the mesh dataset groups.
int datasetGroupIndex() const
Returns the dataset group index.
QgsMeshDatasetGroupTreeItem * childFromDatasetGroupIndex(int index)
Returns the child with dataset group index Searches as depper as needed on the child hierarchy.
bool isEnabled() const
Returns true if the item is enabled, i.e.
QgsMeshDatasetGroupTreeItem * child(int row) const
Returns a child.
Abstract class that represents a dataset group.
An index that identifies the dataset group (e.g.
bool isValid() const
Returns whether index is valid, ie at least groups is set.
int group() const
Returns a group index.
Represents mesh dataset metadata, such as whether the data is valid or the associated time.
Represents a single mesh dataset value.
double y() const
Returns y value.
double x() const
Returns x value.
Holds metadata about mesh drivers.
@ CanWriteMeshData
If the driver can write mesh data on file.
MeshDriverCapabilities capabilities() const
Returns the capabilities for this driver.
Represents an error which occurred during mesh editing.
Qgis::MeshEditingErrorType errorType
Handles edit operations on a mesh layer.
void meshEdited()
Emitted when the mesh is edited.
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.
int closestElement(QgsMesh::ElementType elementType, const QgsPointXY &point, double searchRadius, QgsPointXY &projectedPoint) const
Returns the index of the snapped point on the mesh element closest to point intersecting with the sea...
~QgsMeshLayer() override
QList< int > selectVerticesByExpression(QgsExpression expression)
Returns a list of vertex indexes that meet the condition defined by expression with the context expre...
void setMeshSimplificationSettings(const QgsMeshSimplificationSettings &meshSimplificationSettings)
Sets mesh simplification settings.
int datasetCount(const QgsMeshDatasetIndex &index) const
Returns the dataset count in the dataset groups.
QList< int > datasetGroupsIndexes() const
Returns the list of indexes of dataset groups handled by the layer.
void stopFrameEditing(const QgsCoordinateTransform &transform)
Stops editing of the mesh, re-indexes the faces and vertices, rebuilds the triangular mesh and its sp...
QgsRectangle extent() const override
Returns the extent of the layer.
void setStaticVectorDatasetIndex(const QgsMeshDatasetIndex &staticVectorDatasetIndex)
Sets the static vector dataset index that is rendered if the temporal properties is not active.
void setStaticScalarDatasetIndex(const QgsMeshDatasetIndex &staticScalarDatasetIndex)
Sets the static scalar dataset index that is rendered if the temporal properties is not active.
bool contains(const QgsMesh::ElementType &type) const
Returns whether the mesh contains at mesh elements of given type.
QgsMeshRendererSettings rendererSettings() const
Returns renderer settings.
QgsMeshDatasetIndex activeScalarDatasetIndex(QgsRenderContext &rendererContext)
Returns current active scalar dataset index for current renderer context.
QgsMeshDatasetIndex activeVectorDatasetAtTime(const QgsDateTimeRange &timeRange, int group=-1) const
Returns dataset index from active vector group depending on the time range If the temporal properties...
QList< QgsMeshDatasetIndex > datasetIndexInRelativeTimeInterval(const QgsInterval &startRelativeTime, const QgsInterval &endRelativeTime, int datasetGroupIndex) const
Returns a list of dataset indexes from datasets group that are in a interval time from the layer refe...
void activeScalarDatasetGroupChanged(int index)
Emitted when active scalar group dataset is changed.
int datasetGroupCount() const
Returns the dataset groups count handle by the layer.
void updateTriangularMesh(const QgsCoordinateTransform &transform=QgsCoordinateTransform())
Gets native mesh and updates (creates if it doesn't exist) the base triangular mesh.
bool addDatasets(const QString &path, const QDateTime &defaultReferenceTime=QDateTime())
Adds datasets to the mesh from file with path.
bool isModified() const override
Returns whether the mesh frame has been modified since the last save.
void activeVectorDatasetGroupChanged(int index)
Emitted when active vector group dataset is changed.
void reload() override
Synchronises with changes in the datasource.
QgsPointXY snapOnElement(QgsMesh::ElementType elementType, const QgsPointXY &point, double searchRadius)
Returns the position of the snapped point on the mesh element closest to point intersecting with the ...
bool readXml(const QDomNode &layer_node, QgsReadWriteContext &context) override
Called by readLayerXML(), used by children to read state specific to them from project files.
QStringList subLayers() const override
Returns the sublayers of this layer.
QgsMeshEditor * meshEditor()
Returns a pointer to the mesh editor own by the mesh layer.
const QgsAbstractMeshLayerLabeling * labeling() const
Access to const labeling configuration.
void setDatasetGroupTreeRootItem(QgsMeshDatasetGroupTreeItem *rootItem)
Sets the root items of the dataset group tree item.
QgsMeshDatasetValue dataset1dValue(const QgsMeshDatasetIndex &index, const QgsPointXY &point, double searchRadius) const
Returns the value of 1D mesh dataset defined on edge that are in the search area defined by point ans...
QgsMeshDatasetIndex staticVectorDatasetIndex(int group=-1) const
Returns the static vector dataset index that is rendered if the temporal properties is not active.
QgsMesh * nativeMesh()
Returns native mesh (nullptr before rendering or calling to updateMesh).
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.
QStringList extraDatasetUris() const
Returns the list of extra dataset URIs associated with this layer.
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.
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...
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...
QgsMeshLayer(const QString &path=QString(), const QString &baseName=QString(), const QString &providerLib=u"mesh_memory"_s, const QgsMeshLayer::LayerOptions &options=QgsMeshLayer::LayerOptions())
Constructor - creates a mesh layer.
QgsMeshTimeSettings timeSettings() const
Returns time format settings.
QgsMapLayerTemporalProperties * temporalProperties() override
Returns the layer's temporal properties.
bool writeSymbology(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) const override
Write the style for the layer into the document provided.
int meshVertexCount() const
Returns the vertices count of the mesh frame.
bool labelsEnabled() const
Returns whether the layer contains labels which are enabled and should be drawn.
void setReferenceTime(const QDateTime &referenceTime)
Sets the reference time of the layer.
bool readStyle(const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) override
Read the style for the current layer from the DOM node supplied.
int extraDatasetGroupCount() const
Returns the extra dataset groups count handle by the layer.
bool datasetsPathUnique(const QString &path)
Checks whether that datasets path is already added to this mesh layer.
qint64 datasetRelativeTimeInMilliseconds(const QgsMeshDatasetIndex &index)
Returns the relative time (in milliseconds) of the dataset from the reference time of its group.
QgsMeshDatasetIndex activeScalarDatasetAtTime(const QgsDateTimeRange &timeRange, int group=-1) const
Returns dataset index from active scalar group depending on the time range.
QgsTriangularMesh * triangularMesh(double minimumTriangleSize=0) const
Returns triangular mesh (nullptr before rendering or calling to updateMesh).
QgsMeshDatasetIndex staticScalarDatasetIndex(int group=-1) const
Returns the static scalar dataset index that is rendered if the temporal properties is not active.
void setTemporalMatchingMethod(const QgsMeshDataProviderTemporalCapabilities::MatchingTemporalDatasetMethod &matchingMethod)
Sets the method used to match the temporal dataset from a requested time, see activeVectorDatasetAtTi...
bool removeDatasets(const QString &name)
Removes datasets from the mesh with given name.
QgsMeshDatasetGroupTreeItem * datasetGroupTreeRootItem() const
Returns the root items of the dataset group tree item.
QgsMesh3DDataBlock dataset3dValues(const QgsMeshDatasetIndex &index, int faceIndex, int count) const
Returns N vector/scalar values from the face index from the dataset for 3d stacked meshes.
QgsMesh3DDataBlock dataset3dValue(const QgsMeshDatasetIndex &index, const QgsPointXY &point) const
Returns the 3d values of stacked 3d mesh defined by the given point.
bool readSymbology(const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) override
Read the symbology for the current layer from the DOM node supplied.
QString decodedSource(const QString &source, const QString &provider, const QgsReadWriteContext &context) const override
Called by readLayerXML(), used by derived classes to decode provider's specific data source from proj...
void reloaded()
Emitted when the mesh layer is reloaded, see reload().
QString formatTime(double hours)
Returns (date) time in hours formatted to human readable form.
QgsMeshDatasetGroupMetadata datasetGroupMetadata(const QgsMeshDatasetIndex &index) const
Returns the dataset groups metadata.
QgsMeshLayerRendererCache * rendererCache()
Returns native mesh (nullptr before rendering).
void setTimeSettings(const QgsMeshTimeSettings &settings)
Sets time format settings.
Represents a mesh renderer settings for mesh objects.
void setEnabled(bool enabled)
Sets whether mesh structure rendering is enabled.
Represents a mesh renderer settings for scalar datasets.
void setClassificationMinimumMaximum(double minimum, double maximum)
Sets min/max values used for creation of the color ramp shader.
void setColorRampShader(const QgsColorRampShader &shader)
Sets color ramp shader function.
QgsColorRampShader colorRampShader() const
Returns color ramp shader function.
@ NoResampling
Does not use resampling.
@ NeighbourAverage
Does a simple average of values defined for all surrounding faces/vertices.
void setEdgeStrokeWidth(const QgsInterpolatedLineWidth &strokeWidth)
Sets the stroke width used to render edges scalar dataset.
void setDataResamplingMethod(const DataResamplingMethod &dataResamplingMethod)
Sets data interpolation method.
Represents all mesh renderer settings.
void setActiveVectorDatasetGroup(int activeVectorDatasetGroup)
Sets the active vector dataset group.
QgsMeshRendererScalarSettings scalarSettings(int groupIndex) const
Returns renderer settings.
int activeVectorDatasetGroup() const
Returns the active vector dataset group.
bool hasVectorSettings(int groupIndex) const
Returns whether groupIndex has existing vector settings.
bool removeVectorSettings(int groupIndex)
Removes vector settings for groupIndex.
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 setVectorSettings(int groupIndex, const QgsMeshRendererVectorSettings &settings)
Sets new renderer settings.
bool removeScalarSettings(int groupIndex)
Removes scalar settings with groupIndex.
void setScalarSettings(int groupIndex, const QgsMeshRendererScalarSettings &settings)
Sets new renderer settings.
void setColorRampShader(const QgsColorRampShader &colorRampShader)
Returns the color ramp shader used to render vector datasets.
Represents an overview renderer settings.
double reductionFactor() const
Returns the reduction factor used to build simplified mesh.
bool isEnabled() const
Returns if the overview is active.
Represents a mesh time settings for mesh datasets.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
static Qgis::BlendMode getBlendModeEnum(QPainter::CompositionMode blendMode)
Returns a Qgis::BlendMode corresponding to a QPainter::CompositionMode.
static QPainter::CompositionMode getCompositionMode(Qgis::BlendMode blendMode)
Returns a QPainter::CompositionMode corresponding to a Qgis::BlendMode.
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
QString readPath(const QString &filename) const
Turn filename read from the project file to an absolute path.
Represents a 2D point.
Definition qgspointxy.h:62
double distance(double x, double y) const
Returns the distance between this point and a specified x, y coordinate.
Definition qgspointxy.h:208
double y
Definition qgspointxy.h:66
double x
Definition qgspointxy.h:65
double sqrDistToSegment(double x1, double y1, double x2, double y2, QgsPointXY &minDistPoint, double epsilon=Qgis::DEFAULT_SEGMENT_EPSILON) const
Returns the minimum distance between this point and a segment.
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:53
double x
Definition qgspoint.h:56
double distance(double x, double y) const
Returns the Cartesian 2D distance between this point and a specified x, y coordinate.
Definition qgspoint.h:391
double y
Definition qgspoint.h:57
Encapsulates properties and constraints relating to fetching elevation profiles from different source...
QString absoluteToRelativeUri(const QString &providerKey, const QString &uri, const QgsReadWriteContext &context) const
Converts absolute path(s) to relative path(s) in the given provider-specific URI.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
QString relativeToAbsoluteUri(const QString &providerKey, const QString &uri, const QgsReadWriteContext &context) const
Converts relative path(s) to absolute path(s) in the given provider-specific URI.
virtual void setMaximumValue(double value)
Sets the maximum value for the raster shader.
virtual void setMinimumValue(double value)
Sets the minimum value for the raster shader.
Allows entering a context category and takes care of leaving this category on deletion of the class.
A container for the context for various read/write operations on objects.
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:499
static QgsStyle * defaultStyle(bool initialize=true)
Returns the default application-wide style.
Definition qgsstyle.cpp:150
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:449
static QgsMeshEditingError checkTopology(const QgsMesh &mesh, int maxVerticesPerFace)
Checks the topology of the mesh mesh, if error occurs, this mesh can't be edited.
A triangular/derived mesh with vertices in map coordinates.
const QVector< QgsMeshFace > & triangles() const
Returns triangles.
QList< int > edgeIndexesForRectangle(const QgsRectangle &rectangle) const
Finds indexes of edges intersecting given bounding box It uses spatial indexing.
const QVector< QgsMeshVertex > & vertices() const
Returns vertices in map coordinate system.
const QVector< QgsMeshEdge > & edges() const
Returns edges.
bool contains(const QgsMesh::ElementType &type) const
Returns whether the mesh contains mesh elements of given type.
const QVector< int > & trianglesToNativeFaces() const
Returns mapping between triangles and original faces.
QList< int > faceIndexesForRectangle(const QgsRectangle &rectangle) const
Finds indexes of triangles intersecting given bounding box It uses spatial indexing.
int faceIndexForPoint_v2(const QgsPointXY &point) const
Finds index of triangle at given point It uses spatial indexing and don't use geos to be faster.
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:63
QVector< int > QgsMeshFace
List of vertex indexes.
QPair< int, int > QgsMeshEdge
Edge is a straight line seqment between 2 points.
QgsPoint QgsMeshVertex
xyz coords of vertex
QgsTemporalRange< QDateTime > QgsDateTimeRange
QgsRange which stores a range of date times.
Definition qgsrange.h:764
#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.