QGIS API Documentation 3.99.0-Master (26c88405ac0)
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 <QUrl>
52#include <QUuid>
53
54#include "moc_qgsmeshlayer.cpp"
55
56QgsMeshLayer::QgsMeshLayer( const QString &meshLayerPath,
57 const QString &baseName,
58 const QString &providerKey,
59 const QgsMeshLayer::LayerOptions &options )
60 : QgsMapLayer( Qgis::LayerType::Mesh, baseName, meshLayerPath )
61 , mDatasetGroupStore( new QgsMeshDatasetGroupStore( this ) )
62 , mTemporalProperties( new QgsMeshLayerTemporalProperties( this ) )
63 , mElevationProperties( new QgsMeshLayerElevationProperties( this ) )
64{
66
67 const QgsDataProvider::ProviderOptions providerOptions { options.transformContext };
69 if ( options.loadDefaultStyle )
70 {
71 flags |= Qgis::DataProviderReadFlag::LoadDefaultStyle;
72 }
73 QgsMeshLayer::setDataSourcePrivate( meshLayerPath, baseName, providerKey, providerOptions, flags );
76
77 if ( isValid() && options.loadDefaultStyle )
78 {
79 bool result = false;
80 loadDefaultStyle( result );
81 }
82
83 connect( mDatasetGroupStore.get(), &QgsMeshDatasetGroupStore::datasetGroupsAdded, this, &QgsMeshLayer::onDatasetGroupsAdded );
84}
85
86void QgsMeshLayer::createSimplifiedMeshes()
87{
89
90 if ( mSimplificationSettings.isEnabled() && !hasSimplifiedMeshes() )
91 {
92 const double reductionFactor = mSimplificationSettings.reductionFactor();
93
94 QVector<QgsTriangularMesh *> simplifyMeshes =
95 mTriangularMeshes[0]->simplifyMesh( reductionFactor );
96
97 for ( int i = 0; i < simplifyMeshes.count() ; ++i )
98 {
99 mTriangularMeshes.emplace_back( simplifyMeshes[i] );
100 }
101 }
102}
103
104bool QgsMeshLayer::hasSimplifiedMeshes() const
105{
107
108 //First mesh is the base mesh, so if size>1, there is no simplified meshes
109 return ( mTriangularMeshes.size() > 1 );
110}
111
113{
114 delete mLabeling;
115 delete mDataProvider;
116}
117
124
126{
128
129 return mDataProvider;
130}
131
133{
135
137 if ( mDataProvider )
138 {
139 options.transformContext = mDataProvider->transformContext();
140 }
141 QgsMeshLayer *layer = new QgsMeshLayer( source(), name(), mProviderKey, options );
142 QgsMapLayer::clone( layer );
143
144 layer->mElevationProperties = mElevationProperties->clone();
145 layer->mElevationProperties->setParent( layer );
146
147 if ( auto *lLabeling = labeling() )
148 {
149 layer->setLabeling( lLabeling->clone() );
150 }
152
153 for ( const QString &extraDataset : mExtraDatasetUri )
154 {
155 layer->addDatasets( extraDataset );
156 }
157
158 layer->setRendererSettings( mRendererSettings );
159
160 return layer;
161}
162
164{
166
167 if ( mMeshEditor )
168 return mMeshEditor->extent();
169
170 if ( mDataProvider )
171 return mDataProvider->extent();
172 else
173 {
174 QgsRectangle rec;
175 rec.setNull();
176 return rec;
177 }
178}
179
181{
183
184 if ( !mDataProvider )
185 return false;
186
187 if ( mMeshEditor )
188 return true;
189
190 const QgsMeshDriverMetadata driverMetadata = mDataProvider->driverMetadata();
191
193}
194
195QString QgsMeshLayer::loadDefaultStyle( bool &resultFlag )
196{
198
199 const QList<int> groupsList = datasetGroupsIndexes();
200
201 for ( const int index : groupsList )
202 assignDefaultStyleToDatasetGroup( index );
203
204
205 QgsMeshRendererMeshSettings meshSettings;
206 if ( !groupsList.isEmpty() )
207 {
208 // Show data from the first dataset group
209 mRendererSettings.setActiveScalarDatasetGroup( 0 );
210 // If the first dataset group has nan min/max, display the mesh to avoid nothing displayed
212 if ( meta.maximum() == std::numeric_limits<double>::quiet_NaN() &&
213 meta.minimum() == std::numeric_limits<double>::quiet_NaN() )
214 meshSettings.setEnabled( true );
215 }
216 else
217 {
218 // show at least the mesh by default
219 meshSettings.setEnabled( true );
220 }
221
222 mRendererSettings.setNativeMeshSettings( meshSettings );
223
224 for ( const int i : groupsList )
225 {
226 assignDefaultStyleToDatasetGroup( i );
227
228 // Sets default resample method for scalar dataset
230 QgsMeshRendererScalarSettings scalarSettings = mRendererSettings.scalarSettings( i );
231 switch ( meta.dataType() )
232 {
234 case QgsMeshDatasetGroupMetadata::DataOnVolumes: // data on volumes are averaged to 2D data on faces
236 break;
239 break;
241 break;
242 }
243
244 //override color ramp if the values in the dataset group are classified
245 applyClassificationOnScalarSettings( meta, scalarSettings );
246
247 mRendererSettings.setScalarSettings( i, scalarSettings );
248 }
249
250 if ( !groupsList.isEmpty() )
251 {
252 emit rendererChanged();
254 }
255
256 return QgsMapLayer::loadDefaultStyle( resultFlag );
257}
258
259bool QgsMeshLayer::removeDatasets( const QString &name )
260{
261 const int index = mDatasetGroupStore->indexFromGroupName( name );
262
263 if ( index == -1 )
264 {
265 return false;
266 }
267
268 const QgsMeshDatasetGroupMetadata groupMetadata = datasetGroupMetadata( index );
269
270 mDatasetGroupStore->removeDatasetGroup( index );
271
272 if ( mExtraDatasetUri.contains( groupMetadata.uri() ) )
273 {
274 mExtraDatasetUri.removeOne( groupMetadata.uri() );
275 }
276
278
279 emit dataSourceChanged();
280 return true;
281}
282
283bool QgsMeshLayer::addDatasets( const QString &path, const QDateTime &defaultReferenceTime )
284{
286
288 const bool isTemporalBefore = temporalCapabilities->hasTemporalCapabilities();
289 if ( mDatasetGroupStore->addPersistentDatasets( path ) )
290 {
291 mExtraDatasetUri.append( path );
292 QgsMeshLayerTemporalProperties *temporalProperties = qobject_cast< QgsMeshLayerTemporalProperties * >( mTemporalProperties );
293 if ( !isTemporalBefore && temporalCapabilities->hasTemporalCapabilities() )
294 {
295 mTemporalProperties->setDefaultsFromDataProviderTemporalCapabilities(
296 temporalCapabilities );
297
298 if ( ! temporalProperties->referenceTime().isValid() )
299 {
300 QDateTime referenceTime = defaultReferenceTime;
301 if ( !defaultReferenceTime.isValid() ) // If project reference time is invalid, use current date
302 referenceTime = QDateTime( QDate::currentDate(), QTime( 0, 0, 0 ), Qt::UTC );
303 temporalProperties->setReferenceTime( referenceTime, temporalCapabilities );
304 }
305
306 mTemporalProperties->setIsActive( true );
307 }
308 emit dataSourceChanged();
309 return true;
310 }
311
312 return false;
313}
314
316{
318
319 if ( mDatasetGroupStore->addDatasetGroup( std::unique_ptr< QgsMeshDatasetGroup >( datasetGroup ) ) )
320 {
321 emit dataChanged();
322 return true;
323 }
324 return false;
325}
326
327bool QgsMeshLayer::saveDataset( const QString &path, int datasetGroupIndex, QString driver )
328{
330
331 return mDatasetGroupStore->saveDatasetGroup( path, datasetGroupIndex, driver );
332}
333
335{
337
338 return mNativeMesh.get();
339}
340
342{
344
345 return mNativeMesh.get();
346}
347
348QgsTriangularMesh *QgsMeshLayer::triangularMesh( double minimumTriangleSize ) const
349{
351
352 for ( const std::unique_ptr<QgsTriangularMesh> &lod : mTriangularMeshes )
353 {
354 if ( lod && lod->averageTriangleSize() > minimumTriangleSize )
355 return lod.get();
356 }
357
358 if ( !mTriangularMeshes.empty() )
359 return mTriangularMeshes.back().get();
360 else
361 return nullptr;
362}
363
365{
367
368 return mTriangularMeshes.size();
369}
370
372{
374
375 if ( mTriangularMeshes.empty() )
376 return nullptr;
377 if ( lodIndex < 0 )
378 return mTriangularMeshes.front().get();
379
380 if ( lodIndex >= int( mTriangularMeshes.size() ) )
381 return mTriangularMeshes.back().get();
382
383 return mTriangularMeshes.at( lodIndex ).get();
384}
385
387{
389
390 // Native mesh
391 if ( !mNativeMesh )
392 {
393 // lazy loading of mesh data
394 fillNativeMesh();
395 }
396
397 // Triangular mesh
398 if ( mTriangularMeshes.empty() )
399 {
400 QgsTriangularMesh *baseMesh = new QgsTriangularMesh;
401 mTriangularMeshes.emplace_back( baseMesh );
402 }
403
404 if ( mTriangularMeshes[0].get()->update( mNativeMesh.get(), transform ) )
405 mTriangularMeshes.resize( 1 ); //if the base triangular mesh is effectivly updated, remove simplified meshes
406
407 createSimplifiedMeshes();
408}
409
410QgsMeshLayerRendererCache *QgsMeshLayer::rendererCache()
411{
413
414 return mRendererCache.get();
415}
416
423
424void QgsMeshLayer::setRendererSettings( const QgsMeshRendererSettings &settings, const bool repaint )
425{
427
428 const int oldActiveScalar = mRendererSettings.activeScalarDatasetGroup();
429 const int oldActiveVector = mRendererSettings.activeVectorDatasetGroup();
430 mRendererSettings = settings;
431
432 if ( oldActiveScalar != mRendererSettings.activeScalarDatasetGroup() )
433 emit activeScalarDatasetGroupChanged( mRendererSettings.activeScalarDatasetGroup() );
434
435 if ( oldActiveVector != mRendererSettings.activeVectorDatasetGroup() )
436 emit activeVectorDatasetGroupChanged( mRendererSettings.activeVectorDatasetGroup() );
437
438 emit rendererChanged();
439
440 if ( repaint )
441 {
443 }
444}
445
452
454{
456
457 mTimeSettings = settings;
458 emit timeSettingsChanged();
459}
460
461QString QgsMeshLayer::formatTime( double hours )
462{
464
465 if ( dataProvider() && dataProvider()->temporalCapabilities()->hasReferenceTime() )
466 return QgsMeshLayerUtils::formatTime( hours, mTemporalProperties->referenceTime(), mTimeSettings );
467 else
468 return QgsMeshLayerUtils::formatTime( hours, QDateTime(), mTimeSettings );
469}
470
472{
474
475 return mDatasetGroupStore->datasetGroupCount();
476}
477
479{
481
482 return mDatasetGroupStore->extraDatasetGroupCount();
483}
484
486{
488
489 return mDatasetGroupStore->datasetGroupIndexes();
490}
491
493{
495
496 return mDatasetGroupStore->enabledDatasetGroupIndexes();
497}
498
500{
502
503 return mDatasetGroupStore->datasetGroupMetadata( index );
504}
505
507{
509
510 return mDatasetGroupStore->datasetCount( index.group() );
511}
512
514{
516
517 return mDatasetGroupStore->datasetMetadata( index );
518}
519
521{
523
524 return mDatasetGroupStore->datasetValue( index, valueIndex );
525}
526
527QgsMeshDataBlock QgsMeshLayer::datasetValues( const QgsMeshDatasetIndex &index, int valueIndex, int count ) const
528{
530
531 return mDatasetGroupStore->datasetValues( index, valueIndex, count );
532}
533
534QgsMesh3DDataBlock QgsMeshLayer::dataset3dValues( const QgsMeshDatasetIndex &index, int faceIndex, int count ) const
535{
537
538 return mDatasetGroupStore->dataset3dValues( index, faceIndex, count );
539}
540
541QgsMeshDataBlock QgsMeshLayer::areFacesActive( const QgsMeshDatasetIndex &index, int faceIndex, int count ) const
542{
544
545 return mDatasetGroupStore->areFacesActive( index, faceIndex, count );
546}
547
548bool QgsMeshLayer::isFaceActive( const QgsMeshDatasetIndex &index, int faceIndex ) const
549{
551
552 return mDatasetGroupStore->isFaceActive( index, faceIndex );
553}
554
555QgsMeshDatasetValue QgsMeshLayer::datasetValue( const QgsMeshDatasetIndex &index, const QgsPointXY &point, double searchRadius ) const
556{
558
560 const QgsTriangularMesh *mesh = triangularMesh();
561
562 if ( mesh && index.isValid() )
563 {
565 {
566 const QgsRectangle searchRectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
567 return dataset1dValue( index, point, searchRadius );
568 }
569 const int faceIndex = mesh->faceIndexForPoint_v2( point ) ;
570 if ( faceIndex >= 0 )
571 {
572 const int nativeFaceIndex = mesh->trianglesToNativeFaces().at( faceIndex );
574 if ( isFaceActive( index, nativeFaceIndex ) )
575 {
576 switch ( dataType )
577 {
579 {
580 value = datasetValue( index, nativeFaceIndex );
581 }
582 break;
583
585 {
586 const QgsMeshFace &face = mesh->triangles()[faceIndex];
587 const int v1 = face[0], v2 = face[1], v3 = face[2];
588 const QgsPoint p1 = mesh->vertices()[v1], p2 = mesh->vertices()[v2], p3 = mesh->vertices()[v3];
589 const QgsMeshDatasetValue val1 = datasetValue( index, v1 );
590 const QgsMeshDatasetValue val2 = datasetValue( index, v2 );
591 const QgsMeshDatasetValue val3 = datasetValue( index, v3 );
592 const double x = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.x(), val2.x(), val3.x(), point );
593 double y = std::numeric_limits<double>::quiet_NaN();
594 const bool isVector = datasetGroupMetadata( index ).isVector();
595 if ( isVector )
596 y = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.y(), val2.y(), val3.y(), point );
597
598 value = QgsMeshDatasetValue( x, y );
599 }
600 break;
601
603 {
604 const QgsMesh3DAveragingMethod *avgMethod = mRendererSettings.averagingMethod();
605 if ( avgMethod )
606 {
607 const QgsMesh3DDataBlock block3d = dataset3dValues( index, nativeFaceIndex, 1 );
608 const QgsMeshDataBlock block2d = avgMethod->calculate( block3d );
609 if ( block2d.isValid() )
610 {
611 value = block2d.value( 0 );
612 }
613 }
614 }
615 break;
616
617 default:
618 break;
619 }
620 }
621 }
622 }
623
624 return value;
625}
626
628{
630
631 QgsMesh3DDataBlock block3d;
632
633 const QgsTriangularMesh *baseTriangularMesh = triangularMesh();
634
635 if ( baseTriangularMesh && dataProvider() && dataProvider()->isValid() && index.isValid() )
636 {
639 {
640 const int faceIndex = baseTriangularMesh->faceIndexForPoint_v2( point );
641 if ( faceIndex >= 0 )
642 {
643 const int nativeFaceIndex = baseTriangularMesh->trianglesToNativeFaces().at( faceIndex );
644 block3d = dataset3dValues( index, nativeFaceIndex, 1 );
645 }
646 }
647 }
648 return block3d;
649}
650
651QgsMeshDatasetValue QgsMeshLayer::dataset1dValue( const QgsMeshDatasetIndex &index, const QgsPointXY &point, double searchRadius ) const
652{
654
656 QgsPointXY projectedPoint;
657 const int selectedIndex = closestEdge( point, searchRadius, projectedPoint );
658 const QgsTriangularMesh *mesh = triangularMesh();
659 if ( selectedIndex >= 0 )
660 {
662 switch ( dataType )
663 {
665 {
666 value = datasetValue( index, selectedIndex );
667 }
668 break;
669
671 {
672 const QgsMeshEdge &edge = mesh->edges()[selectedIndex];
673 const int v1 = edge.first, v2 = edge.second;
674 const QgsPoint p1 = mesh->vertices()[v1], p2 = mesh->vertices()[v2];
675 const QgsMeshDatasetValue val1 = datasetValue( index, v1 );
676 const QgsMeshDatasetValue val2 = datasetValue( index, v2 );
677 const double edgeLength = p1.distance( p2 );
678 const double dist1 = p1.distance( projectedPoint.x(), projectedPoint.y() );
679 value = QgsMeshLayerUtils::interpolateFromVerticesData( dist1 / edgeLength, val1, val2 );
680 }
681 break;
682 default:
683 break;
684 }
685 }
686
687 return value;
688}
689
691{
693
694 if ( mDataProvider )
695 mDataProvider->setTransformContext( transformContext );
697}
698
699QgsMeshDatasetIndex QgsMeshLayer::datasetIndexAtTime( const QgsDateTimeRange &timeRange, int datasetGroupIndex ) const
700{
702
703 if ( ! mTemporalProperties->isActive() )
704 return QgsMeshDatasetIndex( datasetGroupIndex, -1 );
705
706 const QDateTime layerReferenceTime = mTemporalProperties->referenceTime();
707 QDateTime utcTime = timeRange.begin();
708 if ( utcTime.timeSpec() != Qt::UTC )
709 utcTime.setTimeSpec( Qt::UTC );
710 const qint64 startTime = layerReferenceTime.msecsTo( utcTime );
711
712 return mDatasetGroupStore->datasetIndexAtTime( startTime, datasetGroupIndex, mTemporalProperties->matchingMethod() );
713}
714
715QgsMeshDatasetIndex QgsMeshLayer::datasetIndexAtRelativeTime( const QgsInterval &relativeTime, int datasetGroupIndex ) const
716{
718
719 return mDatasetGroupStore->datasetIndexAtTime( relativeTime.seconds() * 1000, datasetGroupIndex, mTemporalProperties->matchingMethod() );
720}
721
722QList<QgsMeshDatasetIndex> QgsMeshLayer::datasetIndexInRelativeTimeInterval( const QgsInterval &startRelativeTime, const QgsInterval &endRelativeTime, int datasetGroupIndex ) const
723{
725
726 qint64 usedRelativeTime1 = startRelativeTime.seconds() * 1000;
727 qint64 usedRelativeTime2 = endRelativeTime.seconds() * 1000;
728
729 //adjust relative time if layer reference time is different from provider reference time
730 if ( mTemporalProperties->referenceTime().isValid() &&
731 mDataProvider &&
732 mDataProvider->isValid() &&
733 mTemporalProperties->referenceTime() != mDataProvider->temporalCapabilities()->referenceTime() )
734 {
735 usedRelativeTime1 = usedRelativeTime1 + mTemporalProperties->referenceTime().msecsTo( mDataProvider->temporalCapabilities()->referenceTime() );
736 usedRelativeTime2 = usedRelativeTime2 + mTemporalProperties->referenceTime().msecsTo( mDataProvider->temporalCapabilities()->referenceTime() );
737 }
738
739 return mDatasetGroupStore->datasetIndexInTimeInterval( usedRelativeTime1, usedRelativeTime2, datasetGroupIndex );
740}
741
742void QgsMeshLayer::applyClassificationOnScalarSettings( const QgsMeshDatasetGroupMetadata &meta, QgsMeshRendererScalarSettings &scalarSettings ) const
743{
745
746 if ( meta.extraOptions().contains( QStringLiteral( "classification" ) ) )
747 {
748 QgsColorRampShader colorRampShader = scalarSettings.colorRampShader();
749 QgsColorRamp *colorRamp = colorRampShader.sourceColorRamp();
750 const QStringList classes = meta.extraOptions()[QStringLiteral( "classification" )].split( QStringLiteral( ";;" ) );
751
752 QString units;
753 if ( meta.extraOptions().contains( QStringLiteral( "units" ) ) )
754 units = meta.extraOptions()[ QStringLiteral( "units" )];
755
756 QVector<QVector<double>> bounds;
757 for ( const QString &classe : classes )
758 {
759 const QStringList boundsStr = classe.split( ',' );
760 QVector<double> bound;
761 for ( const QString &boundStr : boundsStr )
762 bound.append( boundStr.toDouble() );
763 bounds.append( bound );
764 }
765
766 if ( ( bounds.count() == 1 && bounds.first().count() > 2 ) || // at least a class with two value
767 ( bounds.count() > 1 ) ) // or at least two classes
768 {
769 const QVector<double> firstClass = bounds.first();
770 const QVector<double> lastClass = bounds.last();
771 const double minValue = firstClass.count() > 1 ? ( firstClass.first() + firstClass.last() ) / 2 : firstClass.first();
772 const double maxValue = lastClass.count() > 1 ? ( lastClass.first() + lastClass.last() ) / 2 : lastClass.first();
773 const double diff = maxValue - minValue;
774 QList<QgsColorRampShader::ColorRampItem> colorRampItemlist;
775 for ( int i = 0; i < bounds.count(); ++i )
776 {
777 const QVector<double> &boundClass = bounds.at( i );
778 QgsColorRampShader::ColorRampItem item;
779 item.value = i + 1;
780 if ( !boundClass.isEmpty() )
781 {
782 const double scalarValue = ( boundClass.first() + boundClass.last() ) / 2;
783 item.color = colorRamp->color( ( scalarValue - minValue ) / diff );
784 if ( i != 0 && i < bounds.count() - 1 ) //The first and last labels are treated after
785 {
786 item.label = QString( ( "%1 - %2 %3" ) ).
787 arg( QString::number( boundClass.first() ) ).
788 arg( QString::number( boundClass.last() ) ).
789 arg( units );
790 }
791 }
792 colorRampItemlist.append( item );
793 }
794 //treat first and last labels
795 if ( firstClass.count() == 1 )
796 colorRampItemlist.first().label = QObject::tr( "below %1 %2" ).
797 arg( QString::number( firstClass.first() ) ).
798 arg( units );
799 else
800 {
801 colorRampItemlist.first().label = QString( ( "%1 - %2 %3" ) ).
802 arg( QString::number( firstClass.first() ) ).
803 arg( QString::number( firstClass.last() ) ).
804 arg( units );
805 }
806
807 if ( lastClass.count() == 1 )
808 colorRampItemlist.last().label = QObject::tr( "above %1 %2" ).
809 arg( QString::number( lastClass.first() ) ).
810 arg( units );
811 else
812 {
813 colorRampItemlist.last().label = QString( ( "%1 - %2 %3" ) ).
814 arg( QString::number( lastClass.first() ) ).
815 arg( QString::number( lastClass.last() ) ).
816 arg( units );
817 }
818
819 colorRampShader.setMinimumValue( 0 );
820 colorRampShader.setMaximumValue( colorRampItemlist.count() - 1 );
821 scalarSettings.setClassificationMinimumMaximum( 0, colorRampItemlist.count() - 1 );
822 colorRampShader.setColorRampItemList( colorRampItemlist );
825 }
826
827 scalarSettings.setColorRampShader( colorRampShader );
829 }
830}
831
833{
835
836 if ( mTemporalProperties->isActive() )
837 return datasetIndexAtTime( timeRange, group >= 0 ? group : mRendererSettings.activeScalarDatasetGroup() );
838 else
839 return QgsMeshDatasetIndex( group >= 0 ? group : mRendererSettings.activeScalarDatasetGroup(), mStaticScalarDatasetIndex );
840}
841
843{
845
846 if ( mTemporalProperties->isActive() )
847 return datasetIndexAtTime( timeRange, group >= 0 ? group : mRendererSettings.activeVectorDatasetGroup() );
848 else
849 return QgsMeshDatasetIndex( group >= 0 ? group : mRendererSettings.activeVectorDatasetGroup(), mStaticVectorDatasetIndex );
850}
851
852void QgsMeshLayer::fillNativeMesh()
853{
855
856 Q_ASSERT( !mNativeMesh );
857
858 mNativeMesh = std::make_unique<QgsMesh>( );
859
860 if ( !( dataProvider() && dataProvider()->isValid() ) )
861 return;
862
863 dataProvider()->populateMesh( mNativeMesh.get() );
864}
865
866void QgsMeshLayer::onDatasetGroupsAdded( const QList<int> &datasetGroupIndexes )
867{
869
870 // assign default style to new dataset groups
871 for ( int datasetGroupIndex : datasetGroupIndexes )
872 {
873 if ( !mRendererSettings.hasSettings( datasetGroupIndex ) )
874 assignDefaultStyleToDatasetGroup( datasetGroupIndex );
875 }
876
877 temporalProperties()->setIsActive( mDatasetGroupStore->hasTemporalCapabilities() );
878 emit rendererChanged();
879}
880
881void QgsMeshLayer::onMeshEdited()
882{
884
885 mRendererCache = std::make_unique<QgsMeshLayerRendererCache>( );
886 emit layerModified();
889}
890
892{
894
895 return mDatasetGroupStore->datasetGroupTreeItem();
896}
897
899{
901
902 mDatasetGroupStore->setDatasetGroupTreeItem( rootItem );
903 updateActiveDatasetGroups();
904}
905
907{
909
910 return QgsMeshDatasetIndex( group >= 0 ? group : mRendererSettings.activeVectorDatasetGroup(), mStaticVectorDatasetIndex );
911}
912
913void QgsMeshLayer::setReferenceTime( const QDateTime &referenceTime )
914{
916
917 if ( auto *lDataProvider = dataProvider() )
918 mTemporalProperties->setReferenceTime( referenceTime, lDataProvider->temporalCapabilities() );
919 else
920 mTemporalProperties->setReferenceTime( referenceTime, nullptr );
921}
922
924{
926
927 mTemporalProperties->setMatchingMethod( matchingMethod );
928}
929
930int QgsMeshLayer::closestEdge( const QgsPointXY &point, double searchRadius, QgsPointXY &projectedPoint ) const
931{
933
934 const QgsRectangle searchRectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
935 const QgsTriangularMesh *mesh = triangularMesh();
936 // search for the closest edge in search area from point
937 const QList<int> edgeIndexes = mesh->edgeIndexesForRectangle( searchRectangle );
938 int selectedIndex = -1;
939 projectedPoint = QgsPointXY();
940 if ( mesh->contains( QgsMesh::Edge ) &&
941 mDataProvider->isValid() )
942 {
943 double sqrMaxDistFromPoint = pow( searchRadius, 2 );
944 for ( const int edgeIndex : edgeIndexes )
945 {
946 const QgsMeshEdge &edge = mesh->edges().at( edgeIndex );
947 const QgsMeshVertex &vertex1 = mesh->vertices()[edge.first];
948 const QgsMeshVertex &vertex2 = mesh->vertices()[edge.second];
949 QgsPointXY projPoint;
950 const double sqrDist = point.sqrDistToSegment( vertex1.x(), vertex1.y(), vertex2.x(), vertex2.y(), projPoint, 0 );
951 if ( sqrDist < sqrMaxDistFromPoint )
952 {
953 selectedIndex = edgeIndex;
954 projectedPoint = projPoint;
955 sqrMaxDistFromPoint = sqrDist;
956 }
957 }
958 }
959
960 return selectedIndex;
961}
962
963int QgsMeshLayer::closestVertex( const QgsPointXY &point, double searchRadius, QgsPointXY &projectedPoint ) const
964{
966
967 const QgsTriangularMesh *mesh = triangularMesh();
968 int selectedIndex = -1;
969 projectedPoint = QgsPointXY();
970 if ( !mesh )
971 return selectedIndex;
972
973 const QgsRectangle rectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
974 double maxDistance = searchRadius;
975 //attempt to snap on edges's vertices
976 const QList<int> edgeIndexes = mesh->edgeIndexesForRectangle( rectangle );
977 for ( const int edgeIndex : edgeIndexes )
978 {
979 const QgsMeshEdge &edge = mesh->edges().at( edgeIndex );
980 const QgsMeshVertex &vertex1 = mesh->vertices()[edge.first];
981 const QgsMeshVertex &vertex2 = mesh->vertices()[edge.second];
982 const double dist1 = point.distance( vertex1 );
983 const double dist2 = point.distance( vertex2 );
984 if ( dist1 < maxDistance )
985 {
986 maxDistance = dist1;
987 projectedPoint = vertex1;
988 selectedIndex = edge.first;
989 }
990 if ( dist2 < maxDistance )
991 {
992 maxDistance = dist2;
993 projectedPoint = vertex2;
994 selectedIndex = edge.second;
995 }
996 }
997
998 //attempt to snap on face's vertices
999 const QList<int> faceIndexes = mesh->faceIndexesForRectangle( rectangle );
1000 for ( const int faceIndex : faceIndexes )
1001 {
1002 const QgsMeshFace &face = mesh->triangles().at( faceIndex );
1003 for ( int i = 0; i < 3; ++i )
1004 {
1005 const QgsMeshVertex &vertex = mesh->vertices()[face.at( i )];
1006 const double dist = point.distance( vertex );
1007 if ( dist < maxDistance )
1008 {
1009 maxDistance = dist;
1010 projectedPoint = vertex;
1011 selectedIndex = face.at( i );
1012 }
1013 }
1014 }
1015
1016 return selectedIndex;
1017}
1018
1019int QgsMeshLayer::closestFace( const QgsPointXY &point, double searchRadius, QgsPointXY &projectedPoint ) const
1020{
1022
1023 const QgsTriangularMesh *mesh = triangularMesh();
1024 int selectedIndex = -1;
1025 projectedPoint = QgsPointXY();
1026 if ( !mesh )
1027 return selectedIndex;
1028
1029 const QgsRectangle rectangle( point.x() - searchRadius, point.y() - searchRadius, point.x() + searchRadius, point.y() + searchRadius );
1030 double maxDistance = std::numeric_limits<double>::max();
1031
1032 const QList<int> faceIndexes = mesh->faceIndexesForRectangle( rectangle );
1033 for ( const int faceIndex : faceIndexes )
1034 {
1035 const int nativefaceIndex = mesh->trianglesToNativeFaces().at( faceIndex );
1036 if ( nativefaceIndex < 0 && nativefaceIndex >= mesh->faceCentroids().count() )
1037 continue;
1038 const QgsPointXY centroid = mesh->faceCentroids()[nativefaceIndex];
1039 const double dist = point.distance( centroid );
1040 if ( dist < maxDistance )
1041 {
1042 maxDistance = dist;
1043 projectedPoint = centroid;
1044 selectedIndex = nativefaceIndex;
1045 }
1046 }
1047
1048 return selectedIndex;
1049}
1050
1052{
1054
1055 mDatasetGroupStore->resetDatasetGroupTreeItem();
1056 updateActiveDatasetGroups();
1057}
1058
1060{
1062
1063 if ( !mDataProvider )
1064 return QgsInterval();
1065 const int groupCount = mDataProvider->datasetGroupCount();
1066 for ( int i = 0; i < groupCount; ++i )
1067 {
1068 const qint64 timeStep = mDataProvider->temporalCapabilities()->firstTimeStepDuration( i );
1069 if ( timeStep > 0 )
1071 }
1072
1073 return QgsInterval();
1074}
1075
1077{
1079
1080 const qint64 time = mDatasetGroupStore->datasetRelativeTime( index );
1081
1082 if ( time == INVALID_MESHLAYER_TIME )
1083 return QgsInterval();
1084 else
1086}
1087
1089{
1091
1092 return mDatasetGroupStore->datasetRelativeTime( index );
1093}
1094
1095static QString detailsErrorMessage( const QgsMeshEditingError &error )
1096{
1097 QString message;
1098
1099 switch ( error.errorType )
1100 {
1102 break;
1104 message = QObject::tr( "Face %1 invalid" ).arg( error.elementIndex );
1105 break;
1107 message = QObject::tr( "Too many vertices for face %1" ).arg( error.elementIndex );
1108 break;
1110 message = QObject::tr( "Face %1 is flat" ).arg( error.elementIndex );
1111 break;
1113 message = QObject::tr( "Vertex %1 is a unique shared vertex" ).arg( error.elementIndex );
1114 break;
1116 message = QObject::tr( "Vertex %1 is invalid" ).arg( error.elementIndex );
1117 break;
1119 message = QObject::tr( "Face %1 is manifold" ).arg( error.elementIndex );
1120 break;
1121 }
1122
1123 return message;
1124}
1125
1127{
1129
1131 return startFrameEditing( transform, error, false );
1132}
1133
1135{
1137
1138 if ( !supportsEditing() )
1139 {
1140 QgsMessageLog::logMessage( QObject::tr( "Mesh layer \"%1\" not support mesh editing" ).arg( name() ) );
1141 return false;
1142 }
1143
1144 if ( mMeshEditor )
1145 {
1146 QgsMessageLog::logMessage( QObject::tr( "Mesh layer \"%1\" already in editing mode" ).arg( name() ) );
1147 return false;
1148 }
1149
1150 mSimplificationSettings.setEnabled( false );
1151
1152 updateTriangularMesh( transform );
1153
1154 mMeshEditor = new QgsMeshEditor( this );
1155
1156 if ( fixErrors )
1157 {
1158 mRendererCache.reset(); // fixing errors could lead to remove faces/vertices
1159 error = mMeshEditor->initializeWithErrorsFix();
1160 }
1161 else
1162 error = mMeshEditor->initialize();
1163
1164 if ( error.errorType != Qgis::MeshEditingErrorType::NoError )
1165 {
1166 mMeshEditor->deleteLater();
1167 mMeshEditor = nullptr;
1168
1169 QgsMessageLog::logMessage( QObject::tr( "Unable to start editing of mesh layer \"%1\": %2" ).
1170 arg( name(), detailsErrorMessage( error ) ), QString(), Qgis::MessageLevel::Critical );
1171 return false;
1172 }
1173
1174 // During editing, we don't need anymore the provider data. Mesh frame data is stored in the mesh editor.
1175 mDataProvider->close();
1176
1177 // All dataset group are removed and replace by a unique virtual dataset group that provide vertices elevation value.
1178 mExtraDatasetUri.clear();
1179 mDatasetGroupStore = std::make_unique<QgsMeshDatasetGroupStore>( this );
1180
1181 mDatasetGroupStore->addDatasetGroup( mMeshEditor->createZValueDatasetGroup() );
1182
1184
1185 connect( mMeshEditor, &QgsMeshEditor::meshEdited, this, &QgsMeshLayer::onMeshEdited );
1186
1187 emit dataChanged();
1188 emit editingStarted();
1189
1190 return true;
1191}
1192
1193bool QgsMeshLayer::commitFrameEditing( const QgsCoordinateTransform &transform, bool continueEditing )
1194{
1196
1198 QString detailsError;
1199 if ( !mMeshEditor->checkConsistency( error ) )
1200 {
1201 if ( error.errorType == Qgis::MeshEditingErrorType::NoError )
1202 detailsError = tr( "Unknown inconsistent mesh error" );
1203 }
1204 else
1205 {
1206 error = QgsTopologicalMesh::checkTopology( *mNativeMesh, mMeshEditor->maximumVerticesPerFace() );
1207 detailsError = detailsErrorMessage( error );
1208 }
1209
1210 if ( !detailsError.isEmpty() )
1211 {
1212 QgsMessageLog::logMessage( QObject::tr( "Edited mesh layer \"%1\" can't be save due to an error: %2" ).
1213 arg( name(), detailsError ), QString(), Qgis::MessageLevel::Critical );
1214 return false;
1215 }
1216
1217 stopFrameEditing( transform );
1218
1219 if ( !mDataProvider )
1220 return false;
1221
1222 const bool res = mDataProvider->saveMeshFrame( *mNativeMesh.get() );
1223
1224 if ( continueEditing )
1225 {
1226 mMeshEditor->initialize();
1227 emit layerModified();
1228 return res;
1229 }
1230
1231 mMeshEditor->deleteLater();
1232 mMeshEditor = nullptr;
1233 emit editingStopped();
1234
1235 mDataProvider->reloadData();
1236 mDataProvider->populateMesh( mNativeMesh.get() );
1237 mDatasetGroupStore = std::make_unique<QgsMeshDatasetGroupStore>( this );
1238 mDatasetGroupStore->setPersistentProvider( mDataProvider, QStringList() );
1240 return true;
1241}
1242
1243bool QgsMeshLayer::rollBackFrameEditing( const QgsCoordinateTransform &transform, bool continueEditing )
1244{
1246
1247 stopFrameEditing( transform );
1248
1249 if ( !mDataProvider )
1250 return false;
1251
1252 mTriangularMeshes.clear();
1253 mDataProvider->reloadData();
1254 mDataProvider->populateMesh( mNativeMesh.get() );
1255 updateTriangularMesh( transform );
1256 mRendererCache = std::make_unique<QgsMeshLayerRendererCache>( );
1258
1259 if ( continueEditing )
1260 {
1261 mMeshEditor->resetTriangularMesh( triangularMesh() );
1262 return mMeshEditor->initialize() == QgsMeshEditingError();
1263 }
1264 else
1265 {
1266 mMeshEditor->deleteLater();
1267 mMeshEditor = nullptr;
1268 emit editingStopped();
1269
1270 mDatasetGroupStore = std::make_unique<QgsMeshDatasetGroupStore>( this );
1271 mDatasetGroupStore->setPersistentProvider( mDataProvider, QStringList() );
1273 emit dataChanged();
1274 return true;
1275 }
1276}
1277
1279{
1281
1282 if ( !mMeshEditor )
1283 return;
1284
1285 mMeshEditor->stopEditing();
1286 mTriangularMeshes.at( 0 )->update( mNativeMesh.get(), transform );
1287 mRendererCache = std::make_unique<QgsMeshLayerRendererCache>( );
1288}
1289
1290bool QgsMeshLayer::reindex( const QgsCoordinateTransform &transform, bool renumber )
1291{
1293
1294 if ( !mMeshEditor )
1295 return false;
1296
1297 if ( !mMeshEditor->reindex( renumber ) )
1298 return false;
1299
1300 mTriangularMeshes.clear();
1301 mTriangularMeshes.emplace_back( new QgsTriangularMesh );
1302 mTriangularMeshes.at( 0 )->update( mNativeMesh.get(), transform );
1303 mRendererCache = std::make_unique<QgsMeshLayerRendererCache>( );
1304 mMeshEditor->resetTriangularMesh( mTriangularMeshes.at( 0 ).get() );
1305
1306 return true;
1307}
1308
1310{
1312
1313 return mMeshEditor;
1314}
1315
1317{
1319
1320 if ( mMeshEditor )
1321 return mMeshEditor->isModified();
1322
1323 return false;
1324}
1325
1327{
1329
1330 switch ( type )
1331 {
1333 return meshVertexCount() != 0;
1335 return meshEdgeCount() != 0;
1337 return meshFaceCount() != 0;
1338 }
1339 return false;
1340}
1341
1343{
1345
1346 if ( mMeshEditor )
1347 return mMeshEditor->validVerticesCount();
1348 else if ( mDataProvider )
1349 return mDataProvider->vertexCount();
1350 else return 0;
1351}
1352
1354{
1356
1357 if ( mMeshEditor )
1358 return mMeshEditor->validFacesCount();
1359 else if ( mDataProvider )
1360 return mDataProvider->faceCount();
1361 else return 0;
1362}
1363
1365{
1367
1368 if ( mMeshEditor )
1369 return mNativeMesh->edgeCount();
1370 else if ( mDataProvider )
1371 return mDataProvider->edgeCount();
1372 else return 0;
1373}
1374
1375void QgsMeshLayer::updateActiveDatasetGroups()
1376{
1378
1379 QgsMeshDatasetGroupTreeItem *treeItem = mDatasetGroupStore->datasetGroupTreeItem();
1380
1381 if ( !mDatasetGroupStore->datasetGroupTreeItem() )
1382 return;
1383
1385 const int oldActiveScalar = settings.activeScalarDatasetGroup();
1386 const int oldActiveVector = settings.activeVectorDatasetGroup();
1387
1388 QgsMeshDatasetGroupTreeItem *activeScalarItem =
1389 treeItem->childFromDatasetGroupIndex( oldActiveScalar );
1390
1391 if ( !activeScalarItem && treeItem->childCount() > 0 && oldActiveScalar != -1 )
1392 activeScalarItem = treeItem->child( 0 );
1393
1394 if ( activeScalarItem && !activeScalarItem->isEnabled() )
1395 {
1396 for ( int i = 0; i < treeItem->childCount(); ++i )
1397 {
1398 activeScalarItem = treeItem->child( i );
1399 if ( activeScalarItem->isEnabled() )
1400 break;
1401 else
1402 activeScalarItem = nullptr;
1403 }
1404 }
1405
1406 if ( activeScalarItem )
1407 settings.setActiveScalarDatasetGroup( activeScalarItem->datasetGroupIndex() );
1408 else
1409 settings.setActiveScalarDatasetGroup( -1 );
1410
1411 QgsMeshDatasetGroupTreeItem *activeVectorItem =
1412 treeItem->childFromDatasetGroupIndex( oldActiveVector );
1413
1414 if ( !( activeVectorItem && activeVectorItem->isEnabled() ) )
1415 settings.setActiveVectorDatasetGroup( -1 );
1416
1417 setRendererSettings( settings );
1418
1419 if ( oldActiveScalar != settings.activeScalarDatasetGroup() )
1421 if ( oldActiveVector != settings.activeVectorDatasetGroup() )
1423}
1424
1425QgsMeshRendererSettings QgsMeshLayer::accordSymbologyWithGroupName( const QgsMeshRendererSettings &settings, const QMap<QString, int> &nameToIndex )
1426{
1427 QString activeScalarName;
1428 QString activeVectorName;
1429 QgsMeshRendererSettings consistentSettings = settings;
1430 int activeScalar = consistentSettings.activeScalarDatasetGroup();
1431 int activeVector = consistentSettings.activeVectorDatasetGroup();
1432
1433 for ( auto it = nameToIndex.constBegin(); it != nameToIndex.constEnd(); ++it )
1434 {
1435 int index = it.value();
1436 const QString name = it.key() ;
1437 int globalIndex = mDatasetGroupStore->indexFromGroupName( name );
1438 if ( globalIndex >= 0 )
1439 {
1440 QgsMeshRendererScalarSettings scalarSettings = settings.scalarSettings( index );
1441 consistentSettings.setScalarSettings( globalIndex, scalarSettings );
1442 if ( settings.hasVectorSettings( it.value() ) && mDatasetGroupStore->datasetGroupMetadata( globalIndex ).isVector() )
1443 {
1444 QgsMeshRendererVectorSettings vectorSettings = settings.vectorSettings( index );
1445 consistentSettings.setVectorSettings( globalIndex, vectorSettings );
1446 }
1447 }
1448 else
1449 {
1450 consistentSettings.removeScalarSettings( index );
1451 if ( settings.hasVectorSettings( it.value() ) )
1452 consistentSettings.removeVectorSettings( index );
1453 }
1454
1455 if ( index == activeScalar )
1456 activeScalarName = name;
1457 if ( index == activeVector )
1458 activeVectorName = name;
1459 }
1460
1461 const QList<int> globalIndexes = datasetGroupsIndexes();
1462 for ( int globalIndex : globalIndexes )
1463 {
1464 const QString name = mDatasetGroupStore->groupName( globalIndex );
1465 if ( !nameToIndex.contains( name ) )
1466 {
1467 consistentSettings.setScalarSettings( globalIndex, mRendererSettings.scalarSettings( globalIndex ) );
1468 if ( mDatasetGroupStore->datasetGroupMetadata( globalIndex ).isVector() )
1469 {
1470 consistentSettings.setVectorSettings( globalIndex, mRendererSettings.vectorSettings( globalIndex ) );
1471 }
1472 }
1473 }
1474
1475 if ( !activeScalarName.isEmpty() )
1476 consistentSettings.setActiveScalarDatasetGroup( mDatasetGroupStore->indexFromGroupName( activeScalarName ) );
1477 if ( !activeVectorName.isEmpty() )
1478 consistentSettings.setActiveVectorDatasetGroup( mDatasetGroupStore->indexFromGroupName( activeVectorName ) );
1479
1480 return consistentSettings;
1481}
1482
1483void QgsMeshLayer::setDataSourcePrivate( const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, Qgis::DataProviderReadFlags flags )
1484{
1486
1487 mDataSource = dataSource;
1488 mLayerName = baseName;
1489 setProviderType( provider );
1490
1491 if ( !mDataSource.isEmpty() && !provider.isEmpty() )
1492 setDataProvider( provider, options, flags );
1493}
1494
1495QgsPointXY QgsMeshLayer::snapOnElement( QgsMesh::ElementType elementType, const QgsPointXY &point, double searchRadius )
1496{
1498
1499 QgsPointXY projectedPoint;
1500 closestElement( elementType, point, searchRadius, projectedPoint );
1501 return projectedPoint;
1502}
1503
1504int QgsMeshLayer::closestElement( QgsMesh::ElementType elementType, const QgsPointXY &point, double searchRadius, QgsPointXY &projectedPoint ) const
1505{
1507
1508 switch ( elementType )
1509 {
1510 case QgsMesh::Vertex:
1511 return closestVertex( point, searchRadius, projectedPoint );
1512 case QgsMesh::Edge:
1513 return closestEdge( point, searchRadius, projectedPoint );
1514 case QgsMesh::Face:
1515 return closestFace( point, searchRadius, projectedPoint );
1516 }
1517 return -1;
1518}
1519
1521{
1523
1524 if ( !mNativeMesh )
1525 {
1526 // lazy loading of mesh data
1527 fillNativeMesh();
1528 }
1529
1530 QList<int> ret;
1531
1532 if ( !mNativeMesh )
1533 return ret;
1534
1535 QgsExpressionContext context;
1536 std::unique_ptr<QgsExpressionContextScope> expScope( QgsExpressionContextUtils::meshExpressionScope( QgsMesh::Vertex ) );
1537 context.appendScope( expScope.release() );
1538 context.lastScope()->setVariable( QStringLiteral( "_native_mesh" ), QVariant::fromValue( *mNativeMesh ) );
1539
1540 expression.prepare( &context );
1541
1542 for ( int i = 0; i < mNativeMesh->vertexCount(); ++i )
1543 {
1544 context.lastScope()->setVariable( QStringLiteral( "_mesh_vertex_index" ), i, false );
1545
1546 if ( expression.evaluate( &context ).toBool() )
1547 ret.append( i );
1548 }
1549
1550 return ret;
1551}
1552
1554{
1556
1557 if ( !mNativeMesh )
1558 {
1559 // lazy loading of mesh data
1560 fillNativeMesh();
1561 }
1562
1563 QList<int> ret;
1564
1565 if ( !mNativeMesh )
1566 return ret;
1567
1568 QgsExpressionContext context;
1569 std::unique_ptr<QgsExpressionContextScope> expScope( QgsExpressionContextUtils::meshExpressionScope( QgsMesh::Face ) );
1570 context.appendScope( expScope.release() );
1571 context.lastScope()->setVariable( QStringLiteral( "_native_mesh" ), QVariant::fromValue( *mNativeMesh ) );
1572
1573 expression.prepare( &context );
1574
1575 for ( int i = 0; i < mNativeMesh->faceCount(); ++i )
1576 {
1577 context.lastScope()->setVariable( QStringLiteral( "_mesh_face_index" ), i, false );
1578
1579 if ( expression.evaluate( &context ).toBool() )
1580 ret.append( i );
1581 }
1582
1583 return ret;
1584}
1585
1587{
1589
1590 return QgsMeshDatasetIndex( group >= 0 ? group : mRendererSettings.activeScalarDatasetGroup(), mStaticScalarDatasetIndex );
1591}
1592
1594{
1596
1597 const int oldActiveVector = mRendererSettings.activeVectorDatasetGroup();
1598
1599 mStaticVectorDatasetIndex = staticVectorDatasetIndex.dataset();
1600 mRendererSettings.setActiveVectorDatasetGroup( staticVectorDatasetIndex.group() );
1601
1602 if ( oldActiveVector != mRendererSettings.activeVectorDatasetGroup() )
1603 emit activeVectorDatasetGroupChanged( mRendererSettings.activeVectorDatasetGroup() );
1604}
1605
1607{
1609
1610 const int oldActiveScalar = mRendererSettings.activeScalarDatasetGroup();
1611
1612 mStaticScalarDatasetIndex = staticScalarDatasetIndex.dataset();
1613 mRendererSettings.setActiveScalarDatasetGroup( staticScalarDatasetIndex.group() );
1614
1615 if ( oldActiveScalar != mRendererSettings.activeScalarDatasetGroup() )
1616 emit activeScalarDatasetGroupChanged( mRendererSettings.activeScalarDatasetGroup() );
1617}
1618
1625
1627{
1629
1630 mSimplificationSettings = simplifySettings;
1631}
1632
1633static QgsColorRamp *_createDefaultColorRamp()
1634{
1635 QgsColorRamp *ramp = QgsStyle::defaultStyle()->colorRamp( QStringLiteral( "Plasma" ) );
1636 if ( ramp )
1637 return ramp;
1638
1639 // definition of "Plasma" color ramp (in case it is not available in the style for some reason)
1640 QVariantMap props;
1641 props["color1"] = "13,8,135,255";
1642 props["color2"] = "240,249,33,255";
1643 props["stops"] =
1644 "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:"
1645 "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:"
1646 "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:"
1647 "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:"
1648 "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:"
1649 "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:"
1650 "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:"
1651 "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:"
1652 "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:"
1653 "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";
1654 return QgsGradientColorRamp::create( props );
1655}
1656
1657void QgsMeshLayer::assignDefaultStyleToDatasetGroup( int groupIndex )
1658{
1660
1661 const QgsMeshDatasetGroupMetadata metadata = datasetGroupMetadata( groupIndex );
1662 const double groupMin = metadata.minimum();
1663 const double groupMax = metadata.maximum();
1664
1665 QgsColorRampShader fcn( groupMin, groupMax, _createDefaultColorRamp() );
1666 fcn.classifyColorRamp( 5, -1, QgsRectangle(), nullptr );
1667
1668 QgsMeshRendererScalarSettings scalarSettings;
1669 scalarSettings.setClassificationMinimumMaximum( groupMin, groupMax );
1670 scalarSettings.setColorRampShader( fcn );
1671 QgsInterpolatedLineWidth edgeStrokeWidth;
1672 edgeStrokeWidth.setMinimumValue( groupMin );
1673 edgeStrokeWidth.setMaximumValue( groupMax );
1674 const QgsInterpolatedLineColor edgeStrokeColor( fcn );
1675 const QgsInterpolatedLineRenderer edgeStrokePen;
1676 scalarSettings.setEdgeStrokeWidth( edgeStrokeWidth );
1677 mRendererSettings.setScalarSettings( groupIndex, scalarSettings );
1678
1679 if ( metadata.isVector() )
1680 {
1681 QgsMeshRendererVectorSettings vectorSettings;
1682 vectorSettings.setColorRampShader( fcn );
1683 mRendererSettings.setVectorSettings( groupIndex, vectorSettings );
1684 }
1685}
1686
1688{
1690
1691 // Triangular mesh
1692 updateTriangularMesh( rendererContext.coordinateTransform() );
1693
1694 // Build overview triangular meshes if needed
1695 createSimplifiedMeshes();
1696
1697 // Cache
1698 if ( !mRendererCache )
1699 mRendererCache = std::make_unique<QgsMeshLayerRendererCache>( );
1700
1701 return new QgsMeshLayerRenderer( this, rendererContext );
1702}
1703
1705{
1706 if ( rendererContext.isTemporal() )
1707 return activeScalarDatasetAtTime( rendererContext.temporalRange(), mRendererSettings.activeScalarDatasetGroup() );
1708 else
1709 return staticScalarDatasetIndex( mRendererSettings.activeScalarDatasetGroup() );
1710}
1711
1712bool QgsMeshLayer::minimumMaximumActiveScalarDataset( const QgsRectangle &extent, const QgsMeshDatasetIndex &datasetIndex, double &min, double &max )
1713{
1714
1715 if ( extent.isNull() || !this->extent().intersects( extent ) )
1716 return false;
1717
1719
1720 if ( ! tMesh )
1721 {
1722 return false;
1723 }
1724
1725 QVector<double> scalarDatasetValues;
1727
1728 if ( !metadata.isScalar() )
1729 {
1730 return false;
1731 }
1732
1733 QgsMeshDatasetGroupMetadata::DataType scalarDataType = QgsMeshLayerUtils::datasetValuesType( metadata.dataType() );
1734
1735 if ( !datasetIndex.isValid() )
1736 {
1737 return false;
1738 }
1739
1740 // populate scalar values
1741 const int count = QgsMeshLayerUtils::datasetValuesCount( mNativeMesh.get(), scalarDataType );
1742 const QgsMeshDataBlock vals = QgsMeshLayerUtils::datasetValues(
1743 this,
1744 datasetIndex,
1745 0,
1746 count );
1747
1748 if ( vals.isValid() )
1749 {
1750 // vals could be scalar or vectors, for contour rendering we want always magnitude
1751 scalarDatasetValues = QgsMeshLayerUtils::calculateMagnitudes( vals );
1752 }
1753 else
1754 {
1755 scalarDatasetValues = QVector<double>( count, std::numeric_limits<double>::quiet_NaN() );
1756 }
1757
1758 QList<int> intersectedFacesIndices = tMesh->faceIndexesForRectangle( extent );
1759
1760 if ( intersectedFacesIndices.isEmpty() )
1761 {
1762 return false;
1763 }
1764
1765 min = std::numeric_limits<double>::max();
1766 max = -std::numeric_limits<double>::max();
1767
1768 double value;
1769
1770 for ( int intersectedFaceIndex : intersectedFacesIndices )
1771 {
1772 QgsMeshFace face = tMesh->triangles().at( intersectedFaceIndex );
1773
1775 {
1776 value = scalarDatasetValues.at( tMesh->trianglesToNativeFaces().at( intersectedFaceIndex ) );
1777 min = std::min( min, value );
1778 max = std::max( max, value );
1779 }
1781 {
1782 QgsMeshVertex vertex;
1783
1784 for ( int vertexIndex : face )
1785 {
1786 value = scalarDatasetValues.at( vertexIndex );
1787 min = std::min( min, value );
1788 max = std::max( max, value );
1789 }
1790 }
1791 }
1792
1793 return true;
1794}
1795
1802
1803void QgsMeshLayer::checkSymbologyConsistency()
1804{
1806
1807 const QList<int> groupIndexes = mDatasetGroupStore->datasetGroupIndexes();
1808 if ( !groupIndexes.contains( mRendererSettings.activeScalarDatasetGroup() ) &&
1809 mRendererSettings.activeScalarDatasetGroup() != -1 )
1810 {
1811 if ( !groupIndexes.empty() )
1812 mRendererSettings.setActiveScalarDatasetGroup( groupIndexes.first() );
1813 else
1814 mRendererSettings.setActiveScalarDatasetGroup( -1 );
1815 }
1816
1817 if ( !groupIndexes.contains( mRendererSettings.activeVectorDatasetGroup() ) &&
1818 mRendererSettings.activeVectorDatasetGroup() != -1 )
1819 {
1820 mRendererSettings.setActiveVectorDatasetGroup( -1 );
1821 }
1822}
1823
1824bool QgsMeshLayer::readSymbology( const QDomNode &node, QString &errorMessage,
1826{
1828
1829 Q_UNUSED( errorMessage )
1830 // TODO: implement categories for raster layer
1831
1832 const QDomElement elem = node.toElement();
1833
1834 readCommonStyle( elem, context, categories );
1835
1837 const QDomElement elemRendererSettings = elem.firstChildElement( "mesh-renderer-settings" );
1838 if ( !elemRendererSettings.isNull() )
1839 rendererSettings.readXml( elemRendererSettings, context );
1840
1841 QMap<QString, int> groupNameToGlobalIndex;
1842 QDomElement nameToIndexElem = elem.firstChildElement( "name-to-global-index" );
1843 while ( !nameToIndexElem.isNull() )
1844 {
1845 const QString name = nameToIndexElem.attribute( QStringLiteral( "name" ) );
1846 int globalIndex = nameToIndexElem.attribute( QStringLiteral( "global-index" ) ).toInt();
1847 groupNameToGlobalIndex.insert( name, globalIndex );
1848 nameToIndexElem = nameToIndexElem.nextSiblingElement( QStringLiteral( "name-to-global-index" ) );
1849 }
1850
1851 mRendererSettings = accordSymbologyWithGroupName( rendererSettings, groupNameToGlobalIndex );
1852
1853 checkSymbologyConsistency();
1854
1855 const QDomElement elemSimplifySettings = elem.firstChildElement( "mesh-simplify-settings" );
1856 if ( !elemSimplifySettings.isNull() )
1857 mSimplificationSettings.readXml( elemSimplifySettings, context );
1858
1859 // get and set the blend mode if it exists
1860 const QDomNode blendModeNode = node.namedItem( QStringLiteral( "blendMode" ) );
1861 if ( !blendModeNode.isNull() )
1862 {
1863 const QDomElement e = blendModeNode.toElement();
1864 setBlendMode( QgsPainting::getCompositionMode( static_cast< Qgis::BlendMode >( e.text().toInt() ) ) );
1865 }
1866
1867 // read labeling definition
1868 if ( categories.testFlag( Labeling ) )
1869 {
1870 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Labeling" ) );
1871
1872 QDomElement labelingElement = node.firstChildElement( QStringLiteral( "labeling" ) );
1873 if ( !labelingElement.isNull() )
1874 {
1876 mLabelsEnabled = node.toElement().attribute( QStringLiteral( "labelsEnabled" ), QStringLiteral( "0" ) ).toInt();
1878 }
1879 }
1880
1881 // get and set the layer transparency
1882 if ( categories.testFlag( Rendering ) )
1883 {
1884 const QDomNode layerOpacityNode = node.namedItem( QStringLiteral( "layerOpacity" ) );
1885 if ( !layerOpacityNode.isNull() )
1886 {
1887 const QDomElement e = layerOpacityNode.toElement();
1888 setOpacity( e.text().toDouble() );
1889 }
1890 }
1891
1892 if ( categories.testFlag( Legend ) )
1893 {
1894 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Legend" ) );
1895
1896 const QDomElement legendElem = node.firstChildElement( QStringLiteral( "legend" ) );
1897 if ( QgsMapLayerLegend *l = legend(); !legendElem.isNull() )
1898 {
1899 l->readXml( legendElem, context );
1900 }
1901 }
1902
1903 return true;
1904}
1905
1906bool QgsMeshLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage,
1907 const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1908{
1910
1911 Q_UNUSED( errorMessage )
1912 // TODO: implement categories for raster layer
1913
1914 QDomElement elem = node.toElement();
1915
1916 writeCommonStyle( elem, doc, context, categories );
1917
1918 const QDomElement elemRendererSettings = mRendererSettings.writeXml( doc, context );
1919 elem.appendChild( elemRendererSettings );
1920
1921 const QList<int> groupIndexes = datasetGroupsIndexes();
1922 // we store the relation between name and indexes to be able to retrieve the consistency between name and symbology
1923 for ( int index : groupIndexes )
1924 {
1925 QDomElement elemNameToIndex = doc.createElement( QStringLiteral( "name-to-global-index" ) );
1926 elemNameToIndex.setAttribute( QStringLiteral( "name" ), mDatasetGroupStore->groupName( index ) );
1927 elemNameToIndex.setAttribute( QStringLiteral( "global-index" ), index );
1928 elem.appendChild( elemNameToIndex );
1929 }
1930
1931 const QDomElement elemSimplifySettings = mSimplificationSettings.writeXml( doc, context );
1932 elem.appendChild( elemSimplifySettings );
1933
1934 // add blend mode node
1935 QDomElement blendModeElement = doc.createElement( QStringLiteral( "blendMode" ) );
1936 const QDomText blendModeText = doc.createTextNode( QString::number( static_cast< int >( QgsPainting::getBlendModeEnum( blendMode() ) ) ) );
1937 blendModeElement.appendChild( blendModeText );
1938 node.appendChild( blendModeElement );
1939
1940 if ( categories.testFlag( Labeling ) )
1941 {
1942 if ( mLabeling )
1943 {
1944 QDomElement labelingElement = mLabeling->save( doc, context );
1945 elem.appendChild( labelingElement );
1946 }
1947 elem.setAttribute( QStringLiteral( "labelsEnabled" ), mLabelsEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
1948 }
1949
1950 // add the layer opacity
1951 if ( categories.testFlag( Rendering ) )
1952 {
1953 QDomElement layerOpacityElem = doc.createElement( QStringLiteral( "layerOpacity" ) );
1954 const QDomText layerOpacityText = doc.createTextNode( QString::number( opacity() ) );
1955 layerOpacityElem.appendChild( layerOpacityText );
1956 node.appendChild( layerOpacityElem );
1957 }
1958
1959 if ( categories.testFlag( Legend ) && legend() )
1960 {
1961 QDomElement legendElement = legend()->writeXml( doc, context );
1962 if ( !legendElement.isNull() )
1963 node.appendChild( legendElement );
1964 }
1965
1966 return true;
1967}
1968
1969bool QgsMeshLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1970{
1972
1973 return writeSymbology( node, doc, errorMessage, context, categories );
1974}
1975
1976bool QgsMeshLayer::readStyle( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
1977{
1979
1980 return readSymbology( node, errorMessage, context, categories );
1981}
1982
1983QString QgsMeshLayer::decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const
1984{
1986
1987 return QgsProviderRegistry::instance()->relativeToAbsoluteUri( provider, source, context );
1988}
1989
1990QString QgsMeshLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
1991{
1993
1995}
1996
1997bool QgsMeshLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &context )
1998{
2000
2001 QgsDebugMsgLevel( QStringLiteral( "Datasource in QgsMeshLayer::readXml: %1" ).arg( mDataSource.toLocal8Bit().data() ), 3 );
2002
2003 //process provider key
2004 const QDomNode pkeyNode = layer_node.namedItem( QStringLiteral( "provider" ) );
2005
2006 if ( pkeyNode.isNull() )
2007 {
2008 mProviderKey.clear();
2009 }
2010 else
2011 {
2012 const QDomElement pkeyElt = pkeyNode.toElement();
2013 mProviderKey = pkeyElt.text();
2014 }
2015
2017 {
2018 return false;
2019 }
2020
2021 const QgsDataProvider::ProviderOptions providerOptions;
2023
2024 const QDomElement elemExtraDatasets = layer_node.firstChildElement( QStringLiteral( "extra-datasets" ) );
2025 if ( !elemExtraDatasets.isNull() )
2026 {
2027 QDomElement elemUri = elemExtraDatasets.firstChildElement( QStringLiteral( "uri" ) );
2028 while ( !elemUri.isNull() )
2029 {
2030 const QString uri = context.pathResolver().readPath( elemUri.text() );
2031 mExtraDatasetUri.append( uri );
2032 elemUri = elemUri.nextSiblingElement( QStringLiteral( "uri" ) );
2033 }
2034 }
2035
2036 if ( pkeyNode.toElement().hasAttribute( QStringLiteral( "time-unit" ) ) )
2037 mTemporalUnit = static_cast<Qgis::TemporalUnit>( pkeyNode.toElement().attribute( QStringLiteral( "time-unit" ) ).toInt() );
2038
2039 // read dataset group store
2040 const QDomElement elemDatasetGroupsStore = layer_node.firstChildElement( QStringLiteral( "mesh-dataset-groups-store" ) );
2041 if ( elemDatasetGroupsStore.isNull() )
2043 else
2044 mDatasetGroupStore->readXml( elemDatasetGroupsStore, context );
2045
2046 setDataProvider( mProviderKey, providerOptions, flags );
2047
2048 QString errorMsg;
2049 readSymbology( layer_node, errorMsg, context );
2050
2051 if ( !mTemporalProperties->timeExtent().begin().isValid() || mTemporalProperties->alwaysLoadReferenceTimeFromSource() )
2053
2054 // read static dataset
2055 const QDomElement elemStaticDataset = layer_node.firstChildElement( QStringLiteral( "static-active-dataset" ) );
2056 if ( elemStaticDataset.hasAttribute( QStringLiteral( "scalar" ) ) )
2057 {
2058 mStaticScalarDatasetIndex = elemStaticDataset.attribute( QStringLiteral( "scalar" ) ).toInt();
2059 }
2060 if ( elemStaticDataset.hasAttribute( QStringLiteral( "vector" ) ) )
2061 {
2062 mStaticVectorDatasetIndex = elemStaticDataset.attribute( QStringLiteral( "vector" ) ).toInt();
2063 }
2064
2065 return isValid(); // should be true if read successfully
2066}
2067
2068bool QgsMeshLayer::writeXml( QDomNode &layer_node, QDomDocument &document, const QgsReadWriteContext &context ) const
2069{
2071
2072 // first get the layer element so that we can append the type attribute
2073 QDomElement mapLayerNode = layer_node.toElement();
2074
2075 if ( mapLayerNode.isNull() || ( QLatin1String( "maplayer" ) != mapLayerNode.nodeName() ) )
2076 {
2077 QgsDebugMsgLevel( QStringLiteral( "can't find <maplayer>" ), 2 );
2078 return false;
2079 }
2080
2081 mapLayerNode.setAttribute( QStringLiteral( "type" ), QgsMapLayerFactory::typeToString( Qgis::LayerType::Mesh ) );
2082
2083 // add provider node
2084 if ( mDataProvider )
2085 {
2086 QDomElement provider = document.createElement( QStringLiteral( "provider" ) );
2087 const QDomText providerText = document.createTextNode( providerType() );
2088 provider.appendChild( providerText );
2089 layer_node.appendChild( provider );
2090 provider.setAttribute( QStringLiteral( "time-unit" ), static_cast< int >( mDataProvider->temporalCapabilities()->temporalUnit() ) );
2091
2092 const QStringList extraDatasetUris = mDataProvider->extraDatasets();
2093 QDomElement elemExtraDatasets = document.createElement( QStringLiteral( "extra-datasets" ) );
2094 for ( const QString &uri : extraDatasetUris )
2095 {
2096 const QString path = context.pathResolver().writePath( uri );
2097 QDomElement elemUri = document.createElement( QStringLiteral( "uri" ) );
2098 elemUri.appendChild( document.createTextNode( path ) );
2099 elemExtraDatasets.appendChild( elemUri );
2100 }
2101 layer_node.appendChild( elemExtraDatasets );
2102 }
2103
2104 QDomElement elemStaticDataset = document.createElement( QStringLiteral( "static-active-dataset" ) );
2105 elemStaticDataset.setAttribute( QStringLiteral( "scalar" ), mStaticScalarDatasetIndex );
2106 elemStaticDataset.setAttribute( QStringLiteral( "vector" ), mStaticVectorDatasetIndex );
2107 layer_node.appendChild( elemStaticDataset );
2108
2109 // write dataset group store if not in edting mode
2110 if ( !isEditable() )
2111 layer_node.appendChild( mDatasetGroupStore->writeXml( document, context ) );
2112
2113 // renderer specific settings
2114 QString errorMsg;
2115 return writeSymbology( layer_node, document, errorMsg, context );
2116}
2117
2119{
2121
2122 if ( !mMeshEditor && mDataProvider && mDataProvider->isValid() )
2123 {
2124 mDataProvider->reloadData();
2125 mDatasetGroupStore->setPersistentProvider( mDataProvider, QStringList() ); //extra dataset are already loaded
2126
2127 //reload the mesh structure
2128 if ( !mNativeMesh )
2129 mNativeMesh = std::make_unique<QgsMesh>( );
2130
2131 dataProvider()->populateMesh( mNativeMesh.get() );
2132
2133 if ( mTemporalProperties->alwaysLoadReferenceTimeFromSource() )
2134 mTemporalProperties->setDefaultsFromDataProviderTemporalCapabilities( mDataProvider->temporalCapabilities() );
2135
2136 //clear the TriangularMeshes
2137 mTriangularMeshes.clear();
2138
2139 //clear the rendererCache
2140 mRendererCache = std::make_unique<QgsMeshLayerRendererCache>( );
2141
2142 checkSymbologyConsistency();
2143
2144 emit reloaded();
2145 }
2146}
2147
2148QStringList QgsMeshLayer::subLayers() const
2149{
2151
2152 if ( mDataProvider )
2153 return mDataProvider->subLayers();
2154 else
2155 return QStringList();
2156}
2157
2159{
2161
2162 const QgsLayerMetadataFormatter htmlFormatter( metadata() );
2163 QString myMetadata = QStringLiteral( "<html>\n<body>\n" );
2164
2165 myMetadata += generalHtmlMetadata();
2166
2167 // Begin Provider section
2168 myMetadata += QStringLiteral( "<h1>" ) + tr( "Information from provider" ) + QStringLiteral( "</h1>\n<hr>\n" );
2169 myMetadata += QLatin1String( "<table class=\"list-view\">\n" );
2170
2171 // Extent
2172 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Extent" ) + QStringLiteral( "</td><td>" ) + extent().toString() + QStringLiteral( "</td></tr>\n" );
2173
2174 // feature count
2175 QLocale locale = QLocale();
2176 locale.setNumberOptions( locale.numberOptions() &= ~QLocale::NumberOption::OmitGroupSeparator );
2177
2178 if ( const QgsMeshDataProvider *provider = dataProvider() )
2179 {
2180 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
2181 + tr( "Vertex count" ) + QStringLiteral( "</td><td>" )
2182 + ( locale.toString( static_cast<qlonglong>( meshVertexCount() ) ) )
2183 + QStringLiteral( "</td></tr>\n" );
2184 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
2185 + tr( "Face count" ) + QStringLiteral( "</td><td>" )
2186 + ( locale.toString( static_cast<qlonglong>( meshFaceCount() ) ) )
2187 + QStringLiteral( "</td></tr>\n" );
2188 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
2189 + tr( "Edge count" ) + QStringLiteral( "</td><td>" )
2190 + ( locale.toString( static_cast<qlonglong>( meshEdgeCount() ) ) )
2191 + QStringLiteral( "</td></tr>\n" );
2192 myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
2193 + tr( "Dataset groups count" ) + QStringLiteral( "</td><td>" )
2194 + ( locale.toString( static_cast<qlonglong>( datasetGroupCount() ) ) )
2195 + QStringLiteral( "</td></tr>\n" );
2196 myMetadata += provider->htmlMetadata();
2197 }
2198
2199 // End Provider section
2200 myMetadata += QLatin1String( "</table>\n<br><br>" );
2201
2202 // CRS
2203 myMetadata += crsHtmlMetadata();
2204
2205 // identification section
2206 myMetadata += QStringLiteral( "<h1>" ) + tr( "Identification" ) + QStringLiteral( "</h1>\n<hr>\n" );
2207 myMetadata += htmlFormatter.identificationSectionHtml( );
2208 myMetadata += QLatin1String( "<br><br>\n" );
2209
2210 // extent section
2211 myMetadata += QStringLiteral( "<h1>" ) + tr( "Extent" ) + QStringLiteral( "</h1>\n<hr>\n" );
2212 myMetadata += htmlFormatter.extentSectionHtml( isSpatial() );
2213 myMetadata += QLatin1String( "<br><br>\n" );
2214
2215 // Start the Access section
2216 myMetadata += QStringLiteral( "<h1>" ) + tr( "Access" ) + QStringLiteral( "</h1>\n<hr>\n" );
2217 myMetadata += htmlFormatter.accessSectionHtml( );
2218 myMetadata += QLatin1String( "<br><br>\n" );
2219
2220 // Start the contacts section
2221 myMetadata += QStringLiteral( "<h1>" ) + tr( "Contacts" ) + QStringLiteral( "</h1>\n<hr>\n" );
2222 myMetadata += htmlFormatter.contactsSectionHtml( );
2223 myMetadata += QLatin1String( "<br><br>\n" );
2224
2225 // Start the links section
2226 myMetadata += QStringLiteral( "<h1>" ) + tr( "Links" ) + QStringLiteral( "</h1>\n<hr>\n" );
2227 myMetadata += htmlFormatter.linksSectionHtml( );
2228 myMetadata += QLatin1String( "<br><br>\n" );
2229
2230 // Start the history section
2231 myMetadata += QStringLiteral( "<h1>" ) + tr( "History" ) + QStringLiteral( "</h1>\n<hr>\n" );
2232 myMetadata += htmlFormatter.historySectionHtml( );
2233 myMetadata += QLatin1String( "<br><br>\n" );
2234
2235 myMetadata += customPropertyHtmlMetadata();
2236
2237 myMetadata += QLatin1String( "\n</body>\n</html>\n" );
2238 return myMetadata;
2239}
2240
2242{
2244
2245 return mMeshEditor;
2246}
2247
2248bool QgsMeshLayer::setDataProvider( QString const &provider, const QgsDataProvider::ProviderOptions &options, Qgis::DataProviderReadFlags flags )
2249{
2251
2252 mDatasetGroupStore->setPersistentProvider( nullptr, QStringList() );
2253
2254 delete mDataProvider;
2255 mProviderKey = provider;
2256 const QString dataSource = mDataSource;
2257
2258 if ( mPreloadedProvider )
2259 {
2260 mDataProvider = qobject_cast< QgsMeshDataProvider * >( mPreloadedProvider.release() );
2261 }
2262 else
2263 {
2264 std::unique_ptr< QgsScopedRuntimeProfile > profile;
2265 if ( QgsApplication::profiler()->groupIsActive( QStringLiteral( "projectload" ) ) )
2266 profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Create %1 provider" ).arg( provider ), QStringLiteral( "projectload" ) );
2267
2268 mDataProvider = qobject_cast<QgsMeshDataProvider *>( QgsProviderRegistry::instance()->createProvider( provider, dataSource, options, flags ) );
2269 }
2270
2271 if ( !mDataProvider )
2272 {
2273 QgsDebugMsgLevel( QStringLiteral( "Unable to get mesh data provider" ), 2 );
2274 return false;
2275 }
2276
2277 mDataProvider->setParent( this );
2278 QgsDebugMsgLevel( QStringLiteral( "Instantiated the mesh data provider plugin" ), 2 );
2279
2280 setValid( mDataProvider->isValid() );
2281 if ( !isValid() )
2282 {
2283 QgsDebugMsgLevel( QStringLiteral( "Invalid mesh provider plugin %1" ).arg( QString( mDataSource.toUtf8() ) ), 2 );
2284 return false;
2285 }
2286
2287 if ( !mTemporalProperties->isValid() )
2288 {
2289 mTemporalProperties->setDefaultsFromDataProviderTemporalCapabilities( dataProvider()->temporalCapabilities() );
2290 }
2291
2292 mDataProvider->setTemporalUnit( mTemporalUnit );
2293
2294 mDatasetGroupStore->setPersistentProvider( mDataProvider, mExtraDatasetUri );
2295
2296 setCrs( mDataProvider->crs() );
2297
2298 if ( provider == QLatin1String( "mesh_memory" ) )
2299 {
2300 // required so that source differs between memory layers
2301 mDataSource = mDataSource + QStringLiteral( "&uid=%1" ).arg( QUuid::createUuid().toString() );
2302 }
2303
2304 // set default style if required by flags or if the dataset group does not has a style yet
2305 for ( int i = 0; i < mDataProvider->datasetGroupCount(); ++i )
2306 {
2307 int globalIndex = mDatasetGroupStore->globalDatasetGroupIndexInSource( mDataProvider, i );
2308 if ( globalIndex != -1 &&
2309 ( !mRendererSettings.hasSettings( globalIndex ) || ( flags & Qgis::DataProviderReadFlag::LoadDefaultStyle ) ) )
2310 assignDefaultStyleToDatasetGroup( globalIndex );
2311 }
2312
2313 emit rendererChanged();
2315
2316 connect( mDataProvider, &QgsMeshDataProvider::dataChanged, this, &QgsMeshLayer::dataChanged );
2317
2318 return true;
2319}
2320
2327
2334
2336{
2338
2339 return mLabelsEnabled && static_cast< bool >( mLabeling );
2340}
2341
2343{
2345
2346 mLabelsEnabled = enabled;
2347}
2348
2350{
2352
2353 if ( mLabeling == labeling )
2354 return;
2355
2356 delete mLabeling;
2357 mLabeling = labeling;
2359}
2360
2361bool QgsMeshLayer::datasetsPathUnique( const QString &path )
2362{
2363 if ( ! mDataProvider )
2364 {
2365 QgsDebugMsgLevel( QStringLiteral( "Unable to get mesh data provider" ), 2 );
2366 return false;
2367 }
2368
2369 if ( mDataProvider->dataSourceUri().contains( path ) )
2370 return false;
2371
2372 return !mExtraDatasetUri.contains( path );
2373}
Provides global constants and enumerations for use throughout the application.
Definition qgis.h:56
@ Exact
Assigns the color of the exact matching value in the color ramp item list.
Definition qgis.h:1428
@ Critical
Critical/error message.
Definition qgis.h:159
@ TooManyVerticesInFace
A face has more vertices than the maximum number supported per face.
Definition qgis.h:1662
@ InvalidFace
An error occurs due to an invalid face (for example, vertex indexes are unordered).
Definition qgis.h:1661
@ UniqueSharedVertex
A least two faces share only one vertices.
Definition qgis.h:1664
@ ManifoldFace
ManifoldFace.
Definition qgis.h:1666
@ InvalidVertex
An error occurs due to an invalid vertex (for example, vertex index is out of range the available ver...
Definition qgis.h:1665
@ FlatFace
A flat face is present.
Definition qgis.h:1663
BlendMode
Blending modes defining the available composition modes that can be used when painting.
Definition qgis.h:4930
TemporalUnit
Temporal units.
Definition qgis.h:5159
@ Milliseconds
Milliseconds.
Definition qgis.h:5160
QFlags< DataProviderReadFlag > DataProviderReadFlags
Flags which control data provider construction.
Definition qgis.h:486
@ EqualInterval
Uses equal interval.
Definition qgis.h:1442
@ Mesh
Mesh layer. Added in QGIS 3.2.
Definition qgis.h:194
@ LoadDefaultStyle
Reset the layer's style to the default for the datasource.
Definition qgis.h:470
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:47
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:84
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:86
QgsMapLayer(Qgis::LayerType type=Qgis::LayerType::Vector, const QString &name=QString(), const QString &source=QString())
Constructor for QgsMapLayer.
Qgis::LayerType type
Definition qgsmaplayer.h:90
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:96
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:92
@ 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.
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...
QgsMeshTimeSettings timeSettings() const
Returns time format settings.
QgsMapLayerTemporalProperties * temporalProperties() override
Returns the layer's temporal properties.
bool writeSymbology(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) const override
Write the style for the layer into the document provided.
int meshVertexCount() const
Returns the vertices count of the mesh frame.
bool labelsEnabled() const
Returns whether the layer contains labels which are enabled and should be drawn.
void setReferenceTime(const QDateTime &referenceTime)
Sets the reference time of the layer.
bool readStyle(const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) override
Read the style for the current layer from the DOM node supplied.
int extraDatasetGroupCount() const
Returns the extra dataset groups count handle by the layer.
bool datasetsPathUnique(const QString &path)
Checks whether that datasets path is already added to this mesh layer.
qint64 datasetRelativeTimeInMilliseconds(const QgsMeshDatasetIndex &index)
Returns the relative time (in milliseconds) of the dataset from the reference time of its group.
QgsMeshDatasetIndex activeScalarDatasetAtTime(const QgsDateTimeRange &timeRange, int group=-1) const
Returns dataset index from active scalar group depending on the time range.
QgsTriangularMesh * triangularMesh(double minimumTriangleSize=0) const
Returns triangular mesh (nullptr before rendering or calling to updateMesh).
QgsMeshDatasetIndex staticScalarDatasetIndex(int group=-1) const
Returns the static scalar dataset index that is rendered if the temporal properties is not active.
void setTemporalMatchingMethod(const QgsMeshDataProviderTemporalCapabilities::MatchingTemporalDatasetMethod &matchingMethod)
Sets the method used to match the temporal dataset from a requested time, see activeVectorDatasetAtTi...
bool removeDatasets(const QString &name)
Removes datasets from the mesh with given name.
QgsMeshDatasetGroupTreeItem * datasetGroupTreeRootItem() const
Returns the root items of the dataset group tree item.
QgsMesh3DDataBlock dataset3dValues(const QgsMeshDatasetIndex &index, int faceIndex, int count) const
Returns N vector/scalar values from the face index from the dataset for 3d stacked meshes.
QgsMesh3DDataBlock dataset3dValue(const QgsMeshDatasetIndex &index, const QgsPointXY &point) const
Returns the 3d values of stacked 3d mesh defined by the given point.
bool readSymbology(const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) override
Read the symbology for the current layer from the DOM node supplied.
QString decodedSource(const QString &source, const QString &provider, const QgsReadWriteContext &context) const override
Called by readLayerXML(), used by derived classes to decode provider's specific data source from proj...
void reloaded()
Emitted when the mesh layer is reloaded, see reload().
QString formatTime(double hours)
Returns (date) time in hours formatted to human readable form.
QgsMeshDatasetGroupMetadata datasetGroupMetadata(const QgsMeshDatasetIndex &index) const
Returns the dataset groups metadata.
QgsMeshLayerRendererCache * rendererCache()
Returns native mesh (nullptr before rendering).
void setTimeSettings(const QgsMeshTimeSettings &settings)
Sets time format settings.
QgsMeshLayer(const QString &path=QString(), const QString &baseName=QString(), const QString &providerLib=QStringLiteral("mesh_memory"), const QgsMeshLayer::LayerOptions &options=QgsMeshLayer::LayerOptions())
Constructor - creates a mesh layer.
Represents a mesh renderer settings for mesh objects.
void setEnabled(bool enabled)
Sets whether mesh structure rendering is enabled.
Represents a mesh renderer settings for scalar datasets.
void setClassificationMinimumMaximum(double minimum, double maximum)
Sets min/max values used for creation of the color ramp shader.
void setColorRampShader(const QgsColorRampShader &shader)
Sets color ramp shader function.
QgsColorRampShader colorRampShader() const
Returns color ramp shader function.
@ NoResampling
Does not use resampling.
@ NeighbourAverage
Does a simple average of values defined for all surrounding faces/vertices.
void setEdgeStrokeWidth(const QgsInterpolatedLineWidth &strokeWidth)
Sets the stroke width used to render edges scalar dataset.
void setDataResamplingMethod(const DataResamplingMethod &dataResamplingMethod)
Sets data interpolation method.
Represents all mesh renderer settings.
void setActiveVectorDatasetGroup(int activeVectorDatasetGroup)
Sets the active vector dataset group.
QgsMeshRendererScalarSettings scalarSettings(int groupIndex) const
Returns renderer settings.
int activeVectorDatasetGroup() const
Returns the active vector dataset group.
bool hasVectorSettings(int groupIndex) const
Returns whether groupIndex has existing vector settings.
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:60
double distance(double x, double y) const
Returns the distance between this point and a specified x, y coordinate.
Definition qgspointxy.h:206
double y
Definition qgspointxy.h:64
double x
Definition qgspointxy.h:63
double sqrDistToSegment(double x1, double y1, double x2, double y2, QgsPointXY &minDistPoint, double epsilon=Qgis::DEFAULT_SEGMENT_EPSILON) const
Returns the minimum distance between this point and a segment.
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:49
double x
Definition qgspoint.h:52
double distance(double x, double y) const
Returns the Cartesian 2D distance between this point and a specified x, y coordinate.
Definition qgspoint.h:387
double y
Definition qgspoint.h:53
Encapsulates properties and constraints relating to fetching elevation profiles from different source...
QString absoluteToRelativeUri(const QString &providerKey, const QString &uri, const QgsReadWriteContext &context) const
Converts absolute path(s) to relative path(s) in the given provider-specific URI.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
QString relativeToAbsoluteUri(const QString &providerKey, const QString &uri, const QgsReadWriteContext &context) const
Converts relative path(s) to absolute path(s) in the given provider-specific URI.
virtual void setMaximumValue(double value)
Sets the maximum value for the raster shader.
virtual void setMinimumValue(double value)
Sets the minimum value for the raster shader.
Allows entering a context category and takes care of leaving this category on deletion of the class.
A container for the context for various read/write operations on objects.
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:502
static QgsStyle * defaultStyle(bool initialize=true)
Returns the default application-wide style.
Definition qgsstyle.cpp:147
void setIsActive(bool active)
Sets whether the temporal property is active.
const QgsDateTimeRange & temporalRange() const
Returns the datetime range for the object.
bool isTemporal() const
Returns true if the object's temporal range is enabled, and the object will be filtered when renderin...
T begin() const
Returns the beginning of the range.
Definition qgsrange.h:446
static QgsMeshEditingError checkTopology(const QgsMesh &mesh, int maxVerticesPerFace)
Checks the topology of the mesh mesh, if error occurs, this mesh can't be edited.
A triangular/derived mesh with vertices in map coordinates.
const QVector< QgsMeshFace > & triangles() const
Returns triangles.
QList< int > edgeIndexesForRectangle(const QgsRectangle &rectangle) const
Finds indexes of edges intersecting given bounding box It uses spatial indexing.
const QVector< QgsMeshVertex > & vertices() const
Returns vertices in map coordinate system.
const QVector< QgsMeshEdge > & edges() const
Returns edges.
bool contains(const QgsMesh::ElementType &type) const
Returns whether the mesh contains mesh elements of given type.
const QVector< int > & trianglesToNativeFaces() const
Returns mapping between triangles and original faces.
QList< int > faceIndexesForRectangle(const QgsRectangle &rectangle) const
Finds indexes of triangles intersecting given bounding box It uses spatial indexing.
int faceIndexForPoint_v2(const QgsPointXY &point) const
Finds index of triangle at given point It uses spatial indexing and don't use geos to be faster.
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:61
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:761
#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.