QGIS API Documentation  3.22.4-Białowieża (ce8e65e95e)
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 
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.
QgsProject * project() const
Returns the project in which the algorithm is being executed.
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.
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:106
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.