QGIS API Documentation 3.43.0-Master (e01d6d7c4c0)
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#include "qgsfileutils.h"
20#include "qgsprovidermetadata.h"
21#include "qgsproviderregistry.h"
24#include "qgsmeshlayer.h"
25#include "qgis.h"
26
28
29QString QgsTinMeshCreationAlgorithm::group() const
30{
31 return QObject::tr( "Mesh" );
32}
33
34QString QgsTinMeshCreationAlgorithm::groupId() const
35{
36 return QStringLiteral( "mesh" );
37}
38
39QString QgsTinMeshCreationAlgorithm::shortDescription() const
40{
41 return QObject::tr( "Creates a TIN mesh layer from vector layers." );
42}
43
44QString QgsTinMeshCreationAlgorithm::shortHelpString() const
45{
46 return QObject::tr( "This algorithm creates a TIN mesh layer from vector layers." );
47}
48
49QStringList QgsTinMeshCreationAlgorithm::tags() const
50{
51 return QObject::tr( "tin,mesh,vector,triangulation,irregular,network" ).split( ',' );
52}
53
54QString QgsTinMeshCreationAlgorithm::name() const
55{
56 return QStringLiteral( "tinmeshcreation" );
57}
58
59QString QgsTinMeshCreationAlgorithm::displayName() const
60{
61 return QObject::tr( "TIN Mesh Creation" );
62}
63
64QgsProcessingAlgorithm *QgsTinMeshCreationAlgorithm::createInstance() const
65{
66 return new QgsTinMeshCreationAlgorithm();
67}
68
69void QgsTinMeshCreationAlgorithm::initAlgorithm( const QVariantMap &configuration )
70{
71 Q_UNUSED( configuration );
72 addParameter( new QgsProcessingParameterTinInputLayers( QStringLiteral( "SOURCE_DATA" ), QObject::tr( "Input layers" ) ) );
73
74 QgsProviderMetadata *meta = QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "mdal" ) );
75
76 QList<QgsMeshDriverMetadata> driverList;
77 if ( meta )
78 driverList = meta->meshDriversMetadata();
79
80 for ( const QgsMeshDriverMetadata &driverMeta : std::as_const( driverList ) )
81 if ( driverMeta.capabilities() & QgsMeshDriverMetadata::CanWriteMeshData )
82 {
83 const QString name = driverMeta.name();
84 mDriverSuffix[name] = driverMeta.writeMeshFrameOnFileSuffix();
85 mAvailableFormat.append( name );
86 }
87
88 addParameter( new QgsProcessingParameterEnum( QStringLiteral( "MESH_FORMAT" ), QObject::tr( "Output format" ), mAvailableFormat, false, 0 ) );
89 addParameter( new QgsProcessingParameterCrs( QStringLiteral( "CRS_OUTPUT" ), QObject::tr( "Output coordinate system" ), QVariant(), true ) );
90 addParameter( new QgsProcessingParameterFileDestination( QStringLiteral( "OUTPUT_MESH" ), QObject::tr( "Output file" ) ) );
91}
92
93bool QgsTinMeshCreationAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
94{
95 const QVariant layersVariant = parameters.value( parameterDefinition( QStringLiteral( "SOURCE_DATA" ) )->name() );
96 if ( layersVariant.userType() != QMetaType::Type::QVariantList )
97 return false;
98
99 const QVariantList layersList = layersVariant.toList();
100
101 QgsCoordinateReferenceSystem destinationCrs = parameterAsCrs( parameters, QStringLiteral( "CRS_OUTPUT" ), context );
102 if ( !destinationCrs.isValid() && context.project() )
103 destinationCrs = context.project()->crs();
104
105 for ( const QVariant &layer : layersList )
106 {
107 if ( feedback && feedback->isCanceled() )
108 return false;
109
110 if ( layer.userType() != QMetaType::Type::QVariantMap )
111 continue;
112 const QVariantMap layerMap = layer.toMap();
113 const QString layerSource = layerMap.value( QStringLiteral( "source" ) ).toString();
114 const Qgis::ProcessingTinInputLayerType type = static_cast<Qgis::ProcessingTinInputLayerType>( layerMap.value( QStringLiteral( "type" ) ).toInt() );
115 const int attributeIndex = layerMap.value( QStringLiteral( "attributeIndex" ) ).toInt();
116
117 std::unique_ptr<QgsProcessingFeatureSource> featureSource( QgsProcessingUtils::variantToSource( layerSource, context ) );
118
119 if ( !featureSource )
120 continue;
121
122 const QgsCoordinateTransform transform( featureSource->sourceCrs(), destinationCrs, context.transformContext() );
123 const long long featureCount = featureSource->featureCount();
124 switch ( type )
125 {
127 mVerticesLayer.append( { featureSource->getFeatures(), transform, attributeIndex, featureCount } );
128 break;
130 mBreakLinesLayer.append( { featureSource->getFeatures(), transform, attributeIndex, featureCount } );
131 break;
132 default:
133 break;
134 }
135 }
136
137 if ( mVerticesLayer.isEmpty() && mBreakLinesLayer.isEmpty() )
138 return false;
139
140 return true;
141}
142
143QVariantMap QgsTinMeshCreationAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
144{
145 QgsMeshTriangulation triangulation;
146 QgsCoordinateReferenceSystem destinationCrs = parameterAsCrs( parameters, QStringLiteral( "CRS_OUTPUT" ), context );
147 if ( !destinationCrs.isValid() && context.project() )
148 destinationCrs = context.project()->crs();
149 triangulation.setCrs( destinationCrs );
150
151 if ( !mVerticesLayer.isEmpty() && feedback )
152 feedback->setProgressText( QObject::tr( "Adding vertices layer(s) to the triangulation" ) );
153 for ( Layer &l : mVerticesLayer )
154 {
155 if ( feedback && feedback->isCanceled() )
156 break;
157 triangulation.addVertices( l.fit, l.attributeIndex, l.transform, feedback, l.featureCount );
158 }
159
160 if ( !mBreakLinesLayer.isEmpty() && feedback )
161 feedback->setProgressText( QObject::tr( "Adding break lines layer(s) to the triangulation" ) );
162 for ( Layer &l : mBreakLinesLayer )
163 {
164 if ( feedback && feedback->isCanceled() )
165 break;
166 triangulation.addBreakLines( l.fit, l.attributeIndex, l.transform, feedback, l.featureCount );
167 }
168
169 if ( feedback && feedback->isCanceled() )
170 return QVariantMap();
171
172 QString fileName = parameterAsFile( parameters, QStringLiteral( "OUTPUT_MESH" ), context );
173 const int driverIndex = parameterAsEnum( parameters, QStringLiteral( "MESH_FORMAT" ), context );
174 const QString driver = mAvailableFormat.at( driverIndex );
175 if ( feedback )
176 feedback->setProgressText( QObject::tr( "Creating mesh from triangulation" ) );
177 const QgsMesh mesh = triangulation.triangulatedMesh( feedback );
178
179 if ( feedback && feedback->isCanceled() )
180 return QVariantMap();
181
182 const QgsProviderMetadata *providerMetadata = QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "mdal" ) );
183
184 fileName = QgsFileUtils::ensureFileNameHasExtension( fileName, QStringList() << mDriverSuffix.value( driver ) );
185
186 if ( feedback )
187 feedback->setProgressText( QObject::tr( "Saving mesh to file" ) );
188 if ( providerMetadata )
189 providerMetadata->createMeshData( mesh, fileName, driver, destinationCrs );
190
192
193 //SELAFIN format doesn't support saving Z value on mesh vertices, so create a specific dataset group
194 if ( driver == "SELAFIN" )
195 {
196 addZValueDataset( fileName, mesh, driver );
197 }
198
199 QVariantMap ret;
200 ret[QStringLiteral( "OUTPUT_MESH" )] = fileName;
201
202 return ret;
203}
204
205void QgsTinMeshCreationAlgorithm::addZValueDataset( const QString &fileName, const QgsMesh &mesh, const QString &driver )
206{
207 auto tempLayer = std::make_unique<QgsMeshLayer>( fileName, "temp", "mdal" );
208 QgsMeshZValueDatasetGroup *zValueDatasetGroup = new QgsMeshZValueDatasetGroup( QObject::tr( "Terrain Elevation" ), mesh );
209 tempLayer->addDatasets( zValueDatasetGroup );
210 const int datasetGroupIndex = tempLayer->datasetGroupCount() - 1;
211 tempLayer->saveDataset( fileName, datasetGroupIndex, driver );
212}
213
214bool QgsTinMeshCreationAlgorithm::canExecute( QString *errorMessage ) const
215{
216 if ( mAvailableFormat.count() == 0 )
217 {
218 *errorMessage = QObject::tr( "MDAL not available" );
219 return false;
220 }
221
222 return true;
223}
224
ProcessingTinInputLayerType
Defines the type of input layer for a Processing TIN input.
Definition qgis.h:3744
@ BreakLines
Input that adds vertices and break lines.
@ Vertices
Input that adds only vertices.
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.
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:112
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.