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