QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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  int 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 = qgis::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
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.