QGIS API Documentation 4.3.0-Master (45633be667c)
Loading...
Searching...
No Matches
qgsalgorithmtininterpolation.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsalgorithmtininterpolation.cpp
3 -----------------------------------
4 begin : August 2026
5 copyright : (C) 2026 by Nyall Dawson
6 email : nyall dot dawson 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
20#include "qgsgridfilewriter.h"
23#include "qgsprocessingutils.h"
24#include "qgstininterpolator.h"
25
26#include <QString>
27
28using namespace Qt::StringLiterals;
29
31QgsTinInterpolationAlgorithm::QgsTinInterpolationAlgorithm() = default;
32
33QString QgsTinInterpolationAlgorithm::name() const
34{
35 return u"tininterpolation"_s;
36}
37
38QString QgsTinInterpolationAlgorithm::displayName() const
39{
40 return QObject::tr( "TIN interpolation" );
41}
42
43QStringList QgsTinInterpolationAlgorithm::tags() const
44{
45 return QObject::tr( "tin,triangulated,irregular,network,delaunay,interpolation,surface,breaklines,breaks,structures" ).split( ',' );
46}
47
48QString QgsTinInterpolationAlgorithm::group() const
49{
50 return QObject::tr( "Interpolation" );
51}
52
53QString QgsTinInterpolationAlgorithm::groupId() const
54{
55 return u"interpolation"_s;
56}
57
58QString QgsTinInterpolationAlgorithm::shortDescription() const
59{
60 return QObject::tr( "Generates a Triangulated Irregular Network (TIN) interpolation from vector layers." );
61}
62
63QString QgsTinInterpolationAlgorithm::shortHelpString() const
64{
65 return QObject::tr(
66 "This algorithm generates a Triangulated Irregular Network (TIN) interpolation surface raster from one or more vector layers.\n\n"
67 "The TIN method constructs a Delaunay triangulation network from sample features. Surfaces within the constructed triangles "
68 "are interpolated using either Linear or Clough-Tocher (cubic) methods. To do this, circumcircles around selected "
69 "sample points are created and their intersections are connected to a network of non overlapping and as compact "
70 "as possible triangles.\n\n"
71 "Input layers can supply sample values from feature attributes or feature Z coordinates. Features can be specified as discrete "
72 "points, structure lines, or breaklines.\n\n"
73 "Optionally, the algorithm can also output a vector line layer representing the triangulation network boundaries."
74 );
75}
76
77QgsTinInterpolationAlgorithm *QgsTinInterpolationAlgorithm::createInstance() const
78{
79 return new QgsTinInterpolationAlgorithm();
80}
81
82void QgsTinInterpolationAlgorithm::initAlgorithm( const QVariantMap & )
83{
84 auto dataParam = std::make_unique<QgsProcessingParameterInterpolationSource>( u"INTERPOLATION_DATA"_s, QObject::tr( "Input layer(s)" ) );
85 dataParam->setHelp( QObject::tr( "Vector layers to use for triangulation along with their attributes and source types." ) );
86 addParameter( dataParam.release() );
87
88 const QStringList methods = { QObject::tr( "Linear" ), QObject::tr( "Clough-Toucher (cubic)" ) };
89 auto methodParam = std::make_unique<QgsProcessingParameterEnum>( u"METHOD"_s, QObject::tr( "Interpolation method" ), methods, false, 0 );
90 methodParam->setHelp( QObject::tr( "Method used to interpolate values within constructed triangles." ) );
91 addParameter( methodParam.release() );
92
93 auto extentParam = std::make_unique<QgsProcessingParameterExtent>( u"EXTENT"_s, QObject::tr( "Extent" ), QVariant(), false );
94 extentParam->setHelp( QObject::tr( "Bounding box defining output raster extent." ) );
95 addParameter( extentParam.release() );
96
97 auto pixelSizeParam = std::make_unique<QgsProcessingParameterInterpolationPixelSize>( u"PIXEL_SIZE"_s, QObject::tr( "Output raster size" ), u"INTERPOLATION_DATA"_s, u"EXTENT"_s, 0.1 );
98 pixelSizeParam->setHelp( QObject::tr( "Pixel size in layer units used to calculate output grid dimensions." ) );
99 addParameter( pixelSizeParam.release() );
100
101 auto colsParam = std::make_unique<QgsProcessingParameterNumber>( u"COLUMNS"_s, QObject::tr( "Number of columns" ), Qgis::ProcessingNumberParameterType::Integer, QVariant(), true, 0, 10000000 );
102 colsParam->setFlags( colsParam->flags() | Qgis::ProcessingParameterFlag::Hidden );
103 addParameter( colsParam.release() );
104
105 auto rowsParam = std::make_unique<QgsProcessingParameterNumber>( u"ROWS"_s, QObject::tr( "Number of rows" ), Qgis::ProcessingNumberParameterType::Integer, QVariant(), true, 0, 10000000 );
106 rowsParam->setFlags( rowsParam->flags() | Qgis::ProcessingParameterFlag::Hidden );
107 addParameter( rowsParam.release() );
108
109 auto outputNodataParam = std::make_unique<QgsProcessingParameterNumber>( u"NODATA"_s, QObject::tr( "Output NoData value" ), Qgis::ProcessingNumberParameterType::Double, -9999.0 );
110 outputNodataParam->setHelp( QObject::tr( "The NODATA value to use in the output raster." ) );
111 outputNodataParam->setFlags( outputNodataParam->flags() | Qgis::ProcessingParameterFlag::Advanced );
112 addParameter( outputNodataParam.release() );
113
114 auto creationOptsParam = std::make_unique<QgsProcessingParameterString>( u"CREATION_OPTIONS"_s, QObject::tr( "Creation options" ), QVariant(), false, true );
115 creationOptsParam->setHelp( QObject::tr( "The raster creation options for the output raster. These options control things like colorimetry, compression, etc." ) );
116 creationOptsParam->setMetadata( QVariantMap( { { u"widget_wrapper"_s, QVariantMap( { { u"widget_type"_s, u"rasteroptions"_s } } ) } } ) );
117 creationOptsParam->setFlags( creationOptsParam->flags() | Qgis::ProcessingParameterFlag::Advanced );
118 addParameter( creationOptsParam.release() );
119
120 auto outputParam = std::make_unique<QgsProcessingParameterRasterDestination>( u"OUTPUT"_s, QObject::tr( "Interpolated" ) );
121 addParameter( outputParam.release() );
122
123 auto triangulationParam = std::make_unique<QgsProcessingParameterFeatureSink>( u"TRIANGULATION"_s, QObject::tr( "Triangulation" ), Qgis::ProcessingSourceType::VectorLine, QVariant(), true );
124 triangulationParam->setCreateByDefault( false );
125 triangulationParam->setHelp( QObject::tr( "Optional output vector layer to save triangulation network lines." ) );
126 addParameter( triangulationParam.release() );
127}
128
129QVariantMap QgsTinInterpolationAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
130{
131 QGS_MARK_ALGORITHM_SOURCE
132
133 const QString interpolationData = parameterAsString( parameters, u"INTERPOLATION_DATA"_s, context );
134 const int method = parameterAsEnum( parameters, u"METHOD"_s, context );
135 const QgsRectangle boundingBox = parameterAsExtent( parameters, u"EXTENT"_s, context );
136 const double pixelSize = parameterAsDouble( parameters, u"PIXEL_SIZE"_s, context );
137 const QString creationOptions = parameterAsString( parameters, u"CREATION_OPTIONS"_s, context ).trimmed();
138 const double outputNodata = parameterAsDouble( parameters, u"NODATA"_s, context );
139 const QString output = parameterAsOutputLayer( parameters, u"OUTPUT"_s, context );
140
141 int columns = parameterAsInt( parameters, u"COLUMNS"_s, context );
142 int rows = parameterAsInt( parameters, u"ROWS"_s, context );
143 if ( columns == 0 )
144 {
145 columns = std::max( static_cast<int>( std::ceil( boundingBox.width() / pixelSize ) ), 1 );
146 }
147 if ( rows == 0 )
148 {
149 rows = std::max( static_cast<int>( std::ceil( boundingBox.height() / pixelSize ) ), 1 );
150 }
151
152 if ( interpolationData.isEmpty() )
153 {
154 throw QgsProcessingException( QObject::tr( "At least one input layer must be specified." ) );
155 }
156
157 QList<QgsInterpolator::LayerData> layerDataList;
158 std::vector<std::unique_ptr<QgsFeatureSource>> sourceHolders;
160
161 const QStringList layerRows = interpolationData.split( "::|::"_L1, Qt::SkipEmptyParts );
162 for ( const QString &row : std::as_const( layerRows ) )
163 {
164 const QStringList tokens = row.split( "::~::"_L1 );
165 if ( tokens.size() < 4 )
166 {
167 continue;
168 }
169
171 std::unique_ptr<QgsProcessingFeatureSource> source( QgsProcessingUtils::variantToSource( tokens.at( 0 ), context ) );
172
173 if ( !source )
174 {
175 throw QgsProcessingException( QObject::tr( "Could not load source layer for input %1." ).arg( tokens.at( 0 ) ) );
176 }
177
178 data.source = source.get();
179 data.transformContext = context.transformContext();
180
181 if ( !layerCrs.isValid() )
182 {
183 layerCrs = source->sourceCrs();
184 }
185
186 data.valueSource = static_cast<Qgis::InterpolationValueSource>( tokens.at( 1 ).toInt() );
187
188 bool intOk = false;
189 data.interpolationAttribute = tokens.at( 2 ).toInt( &intOk );
190
192 {
193 if ( !intOk )
194 {
195 data.interpolationAttribute = source->fields().lookupField( tokens.at( 2 ) );
196 if ( data.interpolationAttribute < 0 )
197 {
198 throw QgsProcessingException( QObject::tr( "Field %1 does not exist in layer %2." ).arg( tokens.at( 2 ), source->sourceName() ) );
199 }
200 }
201 else if ( data.interpolationAttribute < 0 )
202 {
203 throw QgsProcessingException( QObject::tr( "Layer %1 is set to use a value attribute, but no attribute was set." ).arg( source->sourceName() ) );
204 }
205 else if ( data.interpolationAttribute >= source->fields().size() )
206 {
207 throw QgsProcessingException( QObject::tr( "Layer %1 is set to use an invalid attribute." ).arg( source->sourceName() ) );
208 }
209 }
210
211 data.sourceType = static_cast<Qgis::InterpolationSourceType>( tokens.at( 3 ).toInt() );
212
213 layerDataList.append( data );
214 sourceHolders.push_back( std::move( source ) );
215 }
216
217 const QgsTinInterpolator::TinInterpolation tinMethod = ( method == 0 ) ? QgsTinInterpolator::TinInterpolation::Linear : QgsTinInterpolator::TinInterpolation::CloughTocher;
218
219 QString triangulationDestinationId;
220 std::unique_ptr<QgsFeatureSink> triangulationSink(
221 parameterAsSink( parameters, u"TRIANGULATION"_s, context, triangulationDestinationId, QgsTinInterpolator::triangulationFields(), Qgis::WkbType::LineString, layerCrs )
222 );
223
224 QgsTinInterpolator interpolator( layerDataList, tinMethod, feedback );
225 if ( triangulationSink )
226 {
227 interpolator.setTriangulationSink( triangulationSink.get() );
228 }
229
230 QgsGridFileWriter writer( &interpolator, output, boundingBox, columns, rows );
231 if ( !creationOptions.isEmpty() )
232 {
233 writer.setCreationOptions( creationOptions.split( '|' ) );
234 }
235 writer.setNoDataValue( outputNodata );
236 writer.writeFile( feedback );
237
238 if ( triangulationSink )
239 {
240 triangulationSink->finalize();
241 if ( feedback )
242 {
243 feedback->featureSinkFinalized( u"TRIANGULATION"_s );
244 }
245 }
246
247 QVariantMap outputs;
248 outputs.insert( u"OUTPUT"_s, output );
249 if ( triangulationSink )
250 {
251 outputs.insert( u"TRIANGULATION"_s, triangulationDestinationId );
252 }
253 return outputs;
254}
@ VectorLine
Vector line layers.
Definition qgis.h:3753
InterpolationSourceType
Interpolation source types.
Definition qgis.h:6756
InterpolationValueSource
Source for interpolated values from features.
Definition qgis.h:6769
@ Attribute
Take value from feature's attribute.
Definition qgis.h:6770
@ LineString
LineString.
Definition qgis.h:297
@ Hidden
Parameter is hidden and should not be shown to users.
Definition qgis.h:4007
@ Advanced
Parameter is an advanced parameter which should be hidden from users by default.
Definition qgis.h:4006
@ Double
Double/float values.
Definition qgis.h:4047
Represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Handles interpolation to a grid and writes the results to a raster grid file.
Contains information about the context in which a processing algorithm is executed.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
void featureSinkFinalized(const QString &output)
Reports that a feature sink has been finalized.
static QgsProcessingFeatureSource * variantToSource(const QVariant &value, QgsProcessingContext &context, const QVariant &fallbackValue=QVariant())
Converts a variant value to a new feature source.
A rectangle specified with double values.
Interpolation in a triangular irregular network.
static QgsFields triangulationFields()
Returns the fields output by features when saving the triangulation.
TinInterpolation
Indicates the type of interpolation to be performed.
A source together with the information about interpolation attribute / z-coordinate interpolation and...
QgsFeatureSource * source
Feature source.
Qgis::InterpolationSourceType sourceType
Source type.
QgsCoordinateTransformContext transformContext
Coordinate transform context.
int interpolationAttribute
Index of feature attribute to use for interpolation.
Qgis::InterpolationValueSource valueSource
Source for feature values to interpolate.