QGIS API Documentation 3.99.0-Master (26c88405ac0)
Loading...
Searching...
No Matches
qgsalgorithmtinmeshcreation.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsalgorithmtinmeshcreation.cpp
3 ---------------------------
4 begin : August 2020
5 copyright : (C) 2020 by Vincent Cloarec
6 email : vcloarec 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
19
20#include "qgis.h"
21#include "qgsfileutils.h"
22#include "qgsmeshlayer.h"
25#include "qgsprovidermetadata.h"
26#include "qgsproviderregistry.h"
27
29
30QString QgsTinMeshCreationAlgorithm::group() const
31{
32 return QObject::tr( "Mesh" );
33}
34
35QString QgsTinMeshCreationAlgorithm::groupId() const
36{
37 return QStringLiteral( "mesh" );
38}
39
40QString QgsTinMeshCreationAlgorithm::shortDescription() const
41{
42 return QObject::tr( "Creates a TIN mesh layer from vector layers." );
43}
44
45QString QgsTinMeshCreationAlgorithm::shortHelpString() const
46{
47 return QObject::tr( "This algorithm creates a TIN mesh layer from vector layers." );
48}
49
50QStringList QgsTinMeshCreationAlgorithm::tags() const
51{
52 return QObject::tr( "tin,mesh,vector,triangulation,irregular,network" ).split( ',' );
53}
54
55QString QgsTinMeshCreationAlgorithm::name() const
56{
57 return QStringLiteral( "tinmeshcreation" );
58}
59
60QString QgsTinMeshCreationAlgorithm::displayName() const
61{
62 return QObject::tr( "TIN Mesh Creation" );
63}
64
65QgsProcessingAlgorithm *QgsTinMeshCreationAlgorithm::createInstance() const
66{
67 return new QgsTinMeshCreationAlgorithm();
68}
69
70void QgsTinMeshCreationAlgorithm::initAlgorithm( const QVariantMap &configuration )
71{
72 Q_UNUSED( configuration );
73 addParameter( new QgsProcessingParameterTinInputLayers( QStringLiteral( "SOURCE_DATA" ), QObject::tr( "Input layers" ) ) );
74
75 QgsProviderMetadata *meta = QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "mdal" ) );
76
77 QList<QgsMeshDriverMetadata> driverList;
78 if ( meta )
79 driverList = meta->meshDriversMetadata();
80
81 for ( const QgsMeshDriverMetadata &driverMeta : std::as_const( driverList ) )
82 if ( driverMeta.capabilities() & QgsMeshDriverMetadata::CanWriteMeshData )
83 {
84 const QString name = driverMeta.name();
85 mDriverSuffix[name] = driverMeta.writeMeshFrameOnFileSuffix();
86 mAvailableFormat.append( name );
87 }
88
89 addParameter( new QgsProcessingParameterEnum( QStringLiteral( "MESH_FORMAT" ), QObject::tr( "Output format" ), mAvailableFormat, false, 0 ) );
90 addParameter( new QgsProcessingParameterCrs( QStringLiteral( "CRS_OUTPUT" ), QObject::tr( "Output coordinate system" ), QVariant(), true ) );
91 addParameter( new QgsProcessingParameterFileDestination( QStringLiteral( "OUTPUT_MESH" ), QObject::tr( "Output file" ) ) );
92}
93
94bool QgsTinMeshCreationAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
95{
96 const QVariant layersVariant = parameters.value( parameterDefinition( QStringLiteral( "SOURCE_DATA" ) )->name() );
97 if ( layersVariant.userType() != QMetaType::Type::QVariantList )
98 return false;
99
100 const QVariantList layersList = layersVariant.toList();
101
102 QgsCoordinateReferenceSystem destinationCrs = parameterAsCrs( parameters, QStringLiteral( "CRS_OUTPUT" ), context );
103 if ( !destinationCrs.isValid() && context.project() )
104 destinationCrs = context.project()->crs();
105
106 for ( const QVariant &layer : layersList )
107 {
108 if ( feedback && feedback->isCanceled() )
109 return false;
110
111 if ( layer.userType() != QMetaType::Type::QVariantMap )
112 continue;
113 const QVariantMap layerMap = layer.toMap();
114 const QString layerSource = layerMap.value( QStringLiteral( "source" ) ).toString();
115 const Qgis::ProcessingTinInputLayerType type = static_cast<Qgis::ProcessingTinInputLayerType>( layerMap.value( QStringLiteral( "type" ) ).toInt() );
116 const int attributeIndex = layerMap.value( QStringLiteral( "attributeIndex" ) ).toInt();
117
118 std::unique_ptr<QgsProcessingFeatureSource> featureSource( QgsProcessingUtils::variantToSource( layerSource, context ) );
119
120 if ( !featureSource )
121 continue;
122
123 const QgsCoordinateTransform transform( featureSource->sourceCrs(), destinationCrs, context.transformContext() );
124 const long long featureCount = featureSource->featureCount();
125 switch ( type )
126 {
128 mVerticesLayer.append( { featureSource->getFeatures(), transform, attributeIndex, featureCount } );
129 break;
131 mBreakLinesLayer.append( { featureSource->getFeatures(), transform, attributeIndex, featureCount } );
132 break;
133 default:
134 break;
135 }
136 }
137
138 if ( mVerticesLayer.isEmpty() && mBreakLinesLayer.isEmpty() )
139 return false;
140
141 return true;
142}
143
144QVariantMap QgsTinMeshCreationAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
145{
146 QgsMeshTriangulation triangulation;
147 QgsCoordinateReferenceSystem destinationCrs = parameterAsCrs( parameters, QStringLiteral( "CRS_OUTPUT" ), context );
148 if ( !destinationCrs.isValid() && context.project() )
149 destinationCrs = context.project()->crs();
150 triangulation.setCrs( destinationCrs );
151
152 if ( !mVerticesLayer.isEmpty() && feedback )
153 feedback->setProgressText( QObject::tr( "Adding vertices layer(s) to the triangulation" ) );
154 for ( Layer &l : mVerticesLayer )
155 {
156 if ( feedback && feedback->isCanceled() )
157 break;
158 triangulation.addVertices( l.fit, l.attributeIndex, l.transform, feedback, l.featureCount );
159 }
160
161 if ( !mBreakLinesLayer.isEmpty() && feedback )
162 feedback->setProgressText( QObject::tr( "Adding break lines layer(s) to the triangulation" ) );
163 for ( Layer &l : mBreakLinesLayer )
164 {
165 if ( feedback && feedback->isCanceled() )
166 break;
167 triangulation.addBreakLines( l.fit, l.attributeIndex, l.transform, feedback, l.featureCount );
168 }
169
170 if ( feedback && feedback->isCanceled() )
171 return QVariantMap();
172
173 QString fileName = parameterAsFile( parameters, QStringLiteral( "OUTPUT_MESH" ), context );
174 const int driverIndex = parameterAsEnum( parameters, QStringLiteral( "MESH_FORMAT" ), context );
175 const QString driver = mAvailableFormat.at( driverIndex );
176 if ( feedback )
177 feedback->setProgressText( QObject::tr( "Creating mesh from triangulation" ) );
178 const QgsMesh mesh = triangulation.triangulatedMesh( feedback );
179
180 if ( feedback && feedback->isCanceled() )
181 return QVariantMap();
182
183 const QgsProviderMetadata *providerMetadata = QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "mdal" ) );
184
185 fileName = QgsFileUtils::ensureFileNameHasExtension( fileName, QStringList() << mDriverSuffix.value( driver ) );
186
187 if ( feedback )
188 feedback->setProgressText( QObject::tr( "Saving mesh to file" ) );
189 if ( providerMetadata )
190 providerMetadata->createMeshData( mesh, fileName, driver, destinationCrs );
191
193
194 //SELAFIN format doesn't support saving Z value on mesh vertices, so create a specific dataset group
195 if ( driver == "SELAFIN" )
196 {
197 addZValueDataset( fileName, mesh, driver );
198 }
199
200 QVariantMap ret;
201 ret[QStringLiteral( "OUTPUT_MESH" )] = fileName;
202
203 return ret;
204}
205
206void QgsTinMeshCreationAlgorithm::addZValueDataset( const QString &fileName, const QgsMesh &mesh, const QString &driver )
207{
208 auto tempLayer = std::make_unique<QgsMeshLayer>( fileName, "temp", "mdal" );
209 QgsMeshZValueDatasetGroup *zValueDatasetGroup = new QgsMeshZValueDatasetGroup( QObject::tr( "Terrain Elevation" ), mesh );
210 tempLayer->addDatasets( zValueDatasetGroup );
211 const int datasetGroupIndex = tempLayer->datasetGroupCount() - 1;
212 tempLayer->saveDataset( fileName, datasetGroupIndex, driver );
213}
214
215bool QgsTinMeshCreationAlgorithm::canExecute( QString *errorMessage ) const
216{
217 if ( mAvailableFormat.count() == 0 )
218 {
219 *errorMessage = QObject::tr( "MDAL not available" );
220 return false;
221 }
222
223 return true;
224}
225
ProcessingTinInputLayerType
Defines the type of input layer for a Processing TIN input.
Definition qgis.h:3878
@ BreakLines
Input that adds vertices and break lines.
Definition qgis.h:3881
@ Vertices
Input that adds only vertices.
Definition qgis.h:3879
Represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Handles coordinate transforms between two coordinate systems.
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:53
static QString ensureFileNameHasExtension(const QString &fileName, const QStringList &extensions)
Ensures that a fileName ends with an extension from the provided list of extensions.
Holds metadata about mesh drivers.
@ CanWriteMeshData
If the driver can write mesh data on file.
Handles mesh creation with Delaunay constrained triangulation.
bool addBreakLines(QgsFeatureIterator &lineFeatureIterator, int valueAttribute, const QgsCoordinateTransform &transformContext, QgsFeedback *feedback=nullptr, long featureCount=1)
Adds break lines from a vector layer, return true if successful.
void setCrs(const QgsCoordinateReferenceSystem &crs)
Sets the coordinate reference system used for the triangulation.
bool addVertices(QgsFeatureIterator &vertexFeatureIterator, int valueAttribute, const QgsCoordinateTransform &transform, QgsFeedback *feedback=nullptr, long featureCount=1)
Adds vertices to the triangulation from a feature iterator, return true if successful.
QgsMesh triangulatedMesh(QgsFeedback *feedback=nullptr) const
Returns the triangulated mesh.
Convenience class that can be used to obtain a dataset group on vertices that represents the Z value ...
Abstract base class for processing algorithms.
Details for layers to load into projects.
Contains information about the context in which a processing algorithm is executed.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
void addLayerToLoadOnCompletion(const QString &layer, const QgsProcessingContext::LayerDetails &details)
Adds a layer to load (by ID or datasource) into the canvas upon completion of the algorithm or model.
QgsProject * project() const
Returns the project in which the algorithm is being executed.
Base class for providing feedback from a processing algorithm.
virtual void setProgressText(const QString &text)
Sets a progress report text string.
A coordinate reference system parameter for processing algorithms.
An enum based parameter for processing algorithms, allowing for selection from predefined values.
A generic file based destination parameter, for specifying the destination path for a file (non-map l...
A parameter for processing algorithms that need a list of input vector layers to construct a TIN.
@ Mesh
Mesh layer type, since QGIS 3.6.
static QgsProcessingFeatureSource * variantToSource(const QVariant &value, QgsProcessingContext &context, const QVariant &fallbackValue=QVariant())
Converts a variant value to a new feature source.
QgsCoordinateReferenceSystem crs
Definition qgsproject.h:115
Holds data provider key, description, and associated shared library file or function pointer informat...
virtual bool createMeshData(const QgsMesh &mesh, const QString &fileName, const QString &driverName, const QgsCoordinateReferenceSystem &crs, const QMap< QString, QString > &metadata=QMap< QString, QString >()) const
Creates mesh data source from a file name fileName and a driver driverName, that is the mesh frame st...
virtual QList< QgsMeshDriverMetadata > meshDriversMetadata()
Builds the list of available mesh drivers metadata.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
QgsProviderMetadata * providerMetadata(const QString &providerKey) const
Returns metadata of the provider or nullptr if not found.
Mesh - vertices, edges and faces.