QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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
49QString QgsTinMeshCreationAlgorithm::name() const
50{
51 return QStringLiteral( "tinmeshcreation" );
52}
53
54QString QgsTinMeshCreationAlgorithm::displayName() const
55{
56 return QObject::tr( "TIN Mesh Creation" );
57}
58
59QgsProcessingAlgorithm *QgsTinMeshCreationAlgorithm::createInstance() const
60{
61 return new QgsTinMeshCreationAlgorithm();
62}
63
64void QgsTinMeshCreationAlgorithm::initAlgorithm( const QVariantMap &configuration )
65{
66 Q_UNUSED( configuration );
67 addParameter( new QgsProcessingParameterTinInputLayers( QStringLiteral( "SOURCE_DATA" ), QObject::tr( "Input layers" ) ) );
68
69 QgsProviderMetadata *meta = QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "mdal" ) );
70
71 QList<QgsMeshDriverMetadata> driverList;
72 if ( meta )
73 driverList = meta->meshDriversMetadata();
74
75 for ( const QgsMeshDriverMetadata &driverMeta : std::as_const( driverList ) )
76 if ( driverMeta.capabilities() & QgsMeshDriverMetadata::CanWriteMeshData )
77 {
78 const QString name = driverMeta.name();
79 mDriverSuffix[name] = driverMeta.writeMeshFrameOnFileSuffix();
80 mAvailableFormat.append( name );
81 }
82
83 addParameter( new QgsProcessingParameterEnum( QStringLiteral( "MESH_FORMAT" ), QObject::tr( "Output format" ), mAvailableFormat, false, 0 ) );
84 addParameter( new QgsProcessingParameterCrs( QStringLiteral( "CRS_OUTPUT" ), QObject::tr( "Output coordinate system" ), QVariant(), true ) );
85 addParameter( new QgsProcessingParameterFileDestination( QStringLiteral( "OUTPUT_MESH" ), QObject::tr( "Output file" ) ) );
86}
87
88bool QgsTinMeshCreationAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
89{
90 const QVariant layersVariant = parameters.value( parameterDefinition( QStringLiteral( "SOURCE_DATA" ) )->name() );
91 if ( layersVariant.type() != QVariant::List )
92 return false;
93
94 const QVariantList layersList = layersVariant.toList();
95
96 QgsCoordinateReferenceSystem destinationCrs = parameterAsCrs( parameters, QStringLiteral( "CRS_OUTPUT" ), context );
97 if ( !destinationCrs.isValid() && context.project() )
98 destinationCrs = context.project()->crs();
99
100 for ( const QVariant &layer : layersList )
101 {
102 if ( feedback && feedback->isCanceled() )
103 return false;
104
105 if ( layer.type() != QVariant::Map )
106 continue;
107 const QVariantMap layerMap = layer.toMap();
108 const QString layerSource = layerMap.value( QStringLiteral( "source" ) ).toString();
110 static_cast<QgsProcessingParameterTinInputLayers::Type>( layerMap.value( QStringLiteral( "type" ) ).toInt() );
111 const int attributeIndex = layerMap.value( QStringLiteral( "attributeIndex" ) ).toInt();
112
113 std::unique_ptr<QgsProcessingFeatureSource> featureSource( QgsProcessingUtils::variantToSource( layerSource, context ) );
114
115 if ( !featureSource )
116 continue;
117
118 const QgsCoordinateTransform transform( featureSource->sourceCrs(), destinationCrs, context.transformContext() );
119 const long long featureCount = featureSource->featureCount();
120 switch ( type )
121 {
123 mVerticesLayer.append( {featureSource->getFeatures(), transform, attributeIndex, featureCount} );
124 break;
126 mBreakLinesLayer.append( {featureSource->getFeatures(), transform, attributeIndex, featureCount} );
127 break;
128 default:
129 break;
130 }
131 }
132
133 if ( mVerticesLayer.isEmpty() && mBreakLinesLayer.isEmpty() )
134 return false;
135
136 return true;
137}
138
139QVariantMap QgsTinMeshCreationAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
140{
141 QgsMeshTriangulation triangulation;
142 QgsCoordinateReferenceSystem destinationCrs = parameterAsCrs( parameters, QStringLiteral( "CRS_OUTPUT" ), context );
143 if ( !destinationCrs.isValid() && context.project() )
144 destinationCrs = context.project()->crs();
145 triangulation.setCrs( destinationCrs );
146
147 if ( !mVerticesLayer.isEmpty() && feedback )
148 feedback->setProgressText( QObject::tr( "Adding vertices layer(s) to the triangulation" ) );
149 for ( Layer &l : mVerticesLayer )
150 {
151 if ( feedback && feedback->isCanceled() )
152 break;
153 triangulation.addVertices( l.fit, l.attributeIndex, l.transform, feedback, l.featureCount );
154 }
155
156 if ( !mBreakLinesLayer.isEmpty() && feedback )
157 feedback->setProgressText( QObject::tr( "Adding break lines layer(s) to the triangulation" ) );
158 for ( Layer &l : mBreakLinesLayer )
159 {
160 if ( feedback && feedback->isCanceled() )
161 break;
162 triangulation.addBreakLines( l.fit, l.attributeIndex, l.transform, feedback, l.featureCount );
163 }
164
165 if ( feedback && feedback->isCanceled() )
166 return QVariantMap();
167
168 QString fileName = parameterAsFile( parameters, QStringLiteral( "OUTPUT_MESH" ), context );
169 const int driverIndex = parameterAsEnum( parameters, QStringLiteral( "MESH_FORMAT" ), context );
170 const QString driver = mAvailableFormat.at( driverIndex );
171 if ( feedback )
172 feedback->setProgressText( QObject::tr( "Creating mesh from triangulation" ) );
173 const QgsMesh mesh = triangulation.triangulatedMesh( feedback );
174
175 if ( feedback && feedback->isCanceled() )
176 return QVariantMap();
177
178 const QgsProviderMetadata *providerMetadata = QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "mdal" ) );
179
180 fileName = QgsFileUtils::ensureFileNameHasExtension( fileName, QStringList() << mDriverSuffix.value( driver ) );
181
182 if ( feedback )
183 feedback->setProgressText( QObject::tr( "Saving mesh to file" ) );
184 if ( providerMetadata )
185 providerMetadata->createMeshData( mesh, fileName, driver, destinationCrs );
186
188 context.project(),
189 "TIN",
191
192 //SELAFIN format doesn't support saving Z value on mesh vertices, so create a specific dataset group
193 if ( driver == "SELAFIN" )
194 {
195 addZValueDataset( fileName, mesh, driver );
196 }
197
198 QVariantMap ret;
199 ret[QStringLiteral( "OUTPUT_MESH" )] = fileName;
200
201 return ret;
202}
203
204void QgsTinMeshCreationAlgorithm::addZValueDataset( const QString &fileName, const QgsMesh &mesh, const QString &driver )
205{
206 std::unique_ptr<QgsMeshLayer> tempLayer = std::make_unique<QgsMeshLayer>( fileName, "temp", "mdal" );
207 QgsMeshZValueDatasetGroup *zValueDatasetGroup = new QgsMeshZValueDatasetGroup( QObject::tr( "Terrain Elevation" ), mesh );
208 tempLayer->addDatasets( zValueDatasetGroup );
209 const int datasetGroupIndex = tempLayer->datasetGroupCount() - 1;
210 tempLayer->saveDataset( fileName, datasetGroupIndex, driver );
211}
212
213bool QgsTinMeshCreationAlgorithm::canExecute( QString *errorMessage ) const
214{
215 if ( mAvailableFormat.count() == 0 )
216 {
217 *errorMessage = QObject::tr( "MDAL not available" );
218 return false;
219 }
220
221 return true;
222}
223
This class represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Class for doing transforms between two map coordinate systems.
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
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 driver.
@ CanWriteMeshData
If the driver can write mesh data on file.
Class that 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.
Convenient class that can be used to obtain a datasetgroup on vertices that represents the Z value of...
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.
@ BreakLines
Input that adds vertices and break lines.
@ 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:109
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
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.