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