QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
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"
23 #include "qgsmeshtriangulation.h"
24 #include "qgsmeshlayer.h"
25 #include "qgis.h"
26 
28 
29 QString QgsTinMeshCreationAlgorithm::group() const
30 {
31  return QObject::tr( "Mesh" );
32 }
33 
34 QString QgsTinMeshCreationAlgorithm::groupId() const
35 {
36  return QStringLiteral( "mesh" );
37 }
38 
39 QString QgsTinMeshCreationAlgorithm::shortDescription() const
40 {
41  return QObject::tr( "Creates a TIN mesh layer from vector layers" );
42 }
43 
44 QString QgsTinMeshCreationAlgorithm::shortHelpString() const
45 {
46  return QObject::tr( "This algorithm creates a TIN mesh layer from vector layers." );
47 }
48 
49 QString QgsTinMeshCreationAlgorithm::name() const
50 {
51  return QStringLiteral( "tinmeshcreation" );
52 }
53 
54 QString QgsTinMeshCreationAlgorithm::displayName() const
55 {
56  return QObject::tr( "TIN Mesh Creation" );
57 }
58 
59 QgsProcessingAlgorithm *QgsTinMeshCreationAlgorithm::createInstance() const
60 {
61  return new QgsTinMeshCreationAlgorithm();
62 }
63 
64 void 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 
88 bool 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 
139 QVariantMap 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 
187  context.addLayerToLoadOnCompletion( fileName, QgsProcessingContext::LayerDetails( "TIN Mesh",
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 
204 void 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 
213 bool 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 
QgsProcessingFeedback::setProgressText
virtual void setProgressText(const QString &text)
Sets a progress report text string.
Definition: qgsprocessingfeedback.cpp:35
qgsalgorithmtinmeshcreation.h
QgsProcessingParameterTinInputLayers::Type
Type
Defines the type of input layer.
Definition: qgsprocessingparametertininputlayers.h:54
QgsProcessingUtils::variantToSource
static QgsProcessingFeatureSource * variantToSource(const QVariant &value, QgsProcessingContext &context, const QVariant &fallbackValue=QVariant())
Converts a variant value to a new feature source.
Definition: qgsprocessingutils.cpp:412
qgsprocessingparametertininputlayers.h
QgsProcessingContext::project
QgsProject * project() const
Returns the project in which the algorithm is being executed.
Definition: qgsprocessingcontext.h:121
QgsMeshDriverMetadata::CanWriteMeshData
@ CanWriteMeshData
If the driver can write mesh data on file.
Definition: qgsprovidermetadata.h:71
QgsProcessingFeedback
Base class for providing feedback from a processing algorithm.
Definition: qgsprocessingfeedback.h:37
QgsProcessingParameterTinInputLayers
A parameter for processing algorithms that need a list of input vector layers to construct a TIN.
Definition: qgsprocessingparametertininputlayers.h:36
QgsFeedback::isCanceled
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:67
qgis.h
QgsMesh
Mesh - vertices, edges and faces.
Definition: qgsmeshdataprovider.h:58
QgsMeshDriverMetadata
Holds metadata about mesh driver.
Definition: qgsprovidermetadata.h:57
QgsProcessingUtils::LayerHint::Mesh
@ Mesh
Mesh layer type, since QGIS 3.6.
qgsprovidermetadata.h
qgsproviderregistry.h
QgsProcessingParameterCrs
A coordinate reference system parameter for processing algorithms.
Definition: qgsprocessingparameters.h:1740
QgsProcessingContext
Contains information about the context in which a processing algorithm is executed.
Definition: qgsprocessingcontext.h:46
QgsProcessingParameterFileDestination
A generic file based destination parameter, for specifying the destination path for a file (non-map l...
Definition: qgsprocessingparameters.h:3451
QgsProcessingParameterTinInputLayers::Vertices
@ Vertices
Input that adds only vertices.
Definition: qgsprocessingparametertininputlayers.h:69
QgsCoordinateReferenceSystem::isValid
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Definition: qgscoordinatereferencesystem.cpp:977
QgsProcessingContext::transformContext
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
Definition: qgsprocessingcontext.h:165
QgsProviderRegistry::providerMetadata
QgsProviderMetadata * providerMetadata(const QString &providerKey) const
Returns metadata of the provider or nullptr if not found.
Definition: qgsproviderregistry.cpp:873
QgsMeshTriangulation::addBreakLines
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.
Definition: qgsmeshtriangulation.cpp:62
QgsMeshTriangulation::triangulatedMesh
QgsMesh triangulatedMesh(QgsFeedback *feedback=nullptr) const
Returns the triangulated mesh.
Definition: qgsmeshtriangulation.cpp:103
QgsProcessingParameterTinInputLayers::BreakLines
@ BreakLines
Input that adds vertices and break lines.
Definition: qgsprocessingparametertininputlayers.h:71
QgsMeshTriangulation
Class that handles mesh creation with Delaunay constrained triangulation.
Definition: qgsmeshtriangulation.h:42
QgsProcessingContext::LayerDetails
Details for layers to load into projects.
Definition: qgsprocessingcontext.h:262
QgsMeshZValueDatasetGroup
Convenient class that can be used to obtain a datasetgroup on vertices that represents the Z value of...
Definition: qgsmeshtriangulation.h:141
qgsfileutils.h
QgsCoordinateReferenceSystem
This class represents a coordinate reference system (CRS).
Definition: qgscoordinatereferencesystem.h:211
QgsProviderMetadata
Holds data provider key, description, and associated shared library file or function pointer informat...
Definition: qgsprovidermetadata.h:177
qgsmeshlayer.h
QgsMeshTriangulation::addVertices
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.
Definition: qgsmeshtriangulation.cpp:38
QgsProviderMetadata::createMeshData
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...
Definition: qgsprovidermetadata.cpp:205
QgsFileUtils::ensureFileNameHasExtension
static QString ensureFileNameHasExtension(const QString &fileName, const QStringList &extensions)
Ensures that a fileName ends with an extension from the provided list of extensions.
Definition: qgsfileutils.cpp:111
QgsProcessingContext::addLayerToLoadOnCompletion
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.
Definition: qgsprocessingcontext.cpp:54
QgsProcessingAlgorithm
Abstract base class for processing algorithms.
Definition: qgsprocessingalgorithm.h:52
qgsmeshtriangulation.h
QgsMeshTriangulation::setCrs
void setCrs(const QgsCoordinateReferenceSystem &crs)
Sets the coordinate reference system used for the triangulation.
Definition: qgsmeshtriangulation.cpp:108
QgsProcessingParameterEnum
An enum based parameter for processing algorithms, allowing for selection from predefined values.
Definition: qgsprocessingparameters.h:2540
QgsProviderMetadata::meshDriversMetadata
virtual QList< QgsMeshDriverMetadata > meshDriversMetadata()
Builds the list of available mesh drivers metadata.
Definition: qgsprovidermetadata.cpp:100
QgsCoordinateTransform
Class for doing transforms between two map coordinate systems.
Definition: qgscoordinatetransform.h:57
QgsProviderRegistry::instance
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
Definition: qgsproviderregistry.cpp:73
QgsProject::crs
QgsCoordinateReferenceSystem crs
Definition: qgsproject.h:109