QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgsalgorithmdrape.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsalgorithmdrape.cpp
3 ---------------------
4 begin : November 2017
5 copyright : (C) 2017 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
18#include "qgsalgorithmdrape.h"
19#include "qgsvectorlayer.h"
20
22
23
24QString QgsDrapeAlgorithmBase::group() const
25{
26 return QObject::tr( "Vector geometry" );
27}
28
29QString QgsDrapeAlgorithmBase::groupId() const
30{
31 return QStringLiteral( "vectorgeometry" );
32}
33
34QString QgsDrapeAlgorithmBase::outputName() const
35{
36 return QObject::tr( "Draped" );
37}
38
39void QgsDrapeAlgorithmBase::initParameters( const QVariantMap & )
40{
41 addParameter( new QgsProcessingParameterRasterLayer( QStringLiteral( "RASTER" ),
42 QObject::tr( "Raster layer" ) ) );
43 addParameter( new QgsProcessingParameterBand( QStringLiteral( "BAND" ),
44 QObject::tr( "Band number" ), 1, QStringLiteral( "RASTER" ) ) );
45
46 // nodata value
47 std::unique_ptr< QgsProcessingParameterNumber > nodata = std::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "NODATA" ),
48 QObject::tr( "Value for NoData or non-intersecting vertices" ), Qgis::ProcessingNumberParameterType::Double,
49 0.0 );
50 nodata->setIsDynamic( true );
51 nodata->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "NODATA" ), QObject::tr( "Value for NoData or non-intersecting vertices" ), QgsPropertyDefinition::Double ) );
52 nodata->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
53 addParameter( nodata.release() );
54
55 auto scaleParam = std::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "SCALE" ), QObject::tr( "Scale factor" ), Qgis::ProcessingNumberParameterType::Double, 1.0, false, 0.0 );
56 scaleParam->setIsDynamic( true );
57 scaleParam->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "SCALE" ), QObject::tr( "Scale factor" ), QgsPropertyDefinition::Double ) );
58 scaleParam->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
59 addParameter( scaleParam.release() );
60
61 auto offsetParam = std::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "OFFSET" ), QObject::tr( "Offset" ), Qgis::ProcessingNumberParameterType::Double, 0.0 );
62 offsetParam->setIsDynamic( true );
63 offsetParam->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "OFFSET" ), QObject::tr( "Offset" ), QgsPropertyDefinition::Double ) );
64 offsetParam->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
65 addParameter( offsetParam.release() );
66}
67
68bool QgsDrapeAlgorithmBase::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
69{
70 mNoData = parameterAsDouble( parameters, QStringLiteral( "NODATA" ), context );
71 mDynamicNoData = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "NODATA" ) );
72 if ( mDynamicNoData )
73 mNoDataProperty = parameters.value( QStringLiteral( "NODATA" ) ).value< QgsProperty >();
74
75 mScale = parameterAsDouble( parameters, QStringLiteral( "SCALE" ), context );
76 mDynamicScale = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "SCALE" ) );
77 if ( mDynamicScale )
78 mScaleProperty = parameters.value( QStringLiteral( "SCALE" ) ).value< QgsProperty >();
79
80 mOffset = parameterAsDouble( parameters, QStringLiteral( "OFFSET" ), context );
81 mDynamicOffset = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "OFFSET" ) );
82 if ( mDynamicOffset )
83 mOffsetProperty = parameters.value( QStringLiteral( "OFFSET" ) ).value< QgsProperty >();
84
85 QgsRasterLayer *layer = parameterAsRasterLayer( parameters, QStringLiteral( "RASTER" ), context );
86
87 if ( !layer )
88 throw QgsProcessingException( invalidRasterError( parameters, QStringLiteral( "RASTER" ) ) );
89
90 mBand = parameterAsInt( parameters, QStringLiteral( "BAND" ), context );
91 if ( mBand < 1 || mBand > layer->bandCount() )
92 throw QgsProcessingException( QObject::tr( "Invalid band number for BAND (%1): Valid values for input raster are 1 to %2" ).arg( mBand )
93 .arg( layer->bandCount() ) );
94 mRasterExtent = layer->extent();
95
96 std::unique_ptr< QgsRasterInterface > provider( layer->dataProvider()->clone() );
97 QgsRasterDataProvider *dp = dynamic_cast< QgsRasterDataProvider * >( provider.get() );
98 if ( !dp )
99 throw QgsProcessingException( invalidRasterError( parameters, QStringLiteral( "RASTER" ) ) );
100
101 mRasterProvider.reset( dp );
102 provider.release();
103
104 return true;
105}
106
107QgsFeatureList QgsDrapeAlgorithmBase::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
108{
109 if ( !mCreatedTransform )
110 {
111 mCreatedTransform = true;
112 mTransform = QgsCoordinateTransform( sourceCrs(), mRasterProvider->crs(), context.transformContext() );
113
114 // transform the raster extent back to the vector's crs, so that we can test
115 // whether individual vector geometries are actually covered by the raster
116 try
117 {
118 mRasterExtent = mTransform.transform( mRasterExtent, Qgis::TransformDirection::Reverse );
119 }
120 catch ( QgsCsException & )
121 {
122 mRasterExtent = QgsRectangle();
123 }
124 }
125
126 QgsFeature f = feature;
127 if ( f.hasGeometry() )
128 {
129 QgsGeometry geometry = f.geometry();
130
131 double nodata = mNoData;
132 if ( mDynamicNoData )
133 nodata = mNoDataProperty.valueAsDouble( context.expressionContext(), nodata );
134
135 double scale = mScale;
136 if ( mDynamicScale )
137 scale = mScaleProperty.valueAsDouble( context.expressionContext(), scale );
138
139 double offset = mOffset;
140 if ( mDynamicOffset )
141 offset = mOffsetProperty.valueAsDouble( context.expressionContext(), offset );
142
143 prepareGeometry( geometry, nodata );
144
145 // only do the "draping" if the geometry intersects the raster - otherwise skip
146 // a pointless iteration over all vertices
147 if ( !mRasterExtent.isNull() && geometry.boundingBoxIntersects( mRasterExtent ) )
148 {
149 geometry.transformVertices( [ = ]( const QgsPoint & p )->QgsPoint
150 {
151 QgsPointXY t;
152 double val = nodata;
153 try
154 {
155 t = mTransform.transform( p );
156 bool ok = false;
157 val = mRasterProvider->sample( t, mBand, &ok );
158 if ( !ok )
159 val = nodata;
160 else
161 {
162 val *= scale;
163 val += offset;
164 }
165 }
166 catch ( QgsCsException & )
167 {
168 feedback->reportError( QObject::tr( "Transform error while reprojecting feature {}" ).arg( f.id() ) );
169 }
170
171 return drapeVertex( p, val );
172 } );
173 }
174
175 f.setGeometry( geometry );
176 }
177 return QgsFeatureList() << f;
178}
179
180
181//
182// QgsDrapeToZAlgorithm
183//
184
185QString QgsDrapeToZAlgorithm::name() const
186{
187 return QStringLiteral( "setzfromraster" );
188}
189
190QString QgsDrapeToZAlgorithm::displayName() const
191{
192 return QObject::tr( "Drape (set Z value from raster)" );
193}
194
195QStringList QgsDrapeToZAlgorithm::tags() const
196{
197 return QObject::tr( "3d,vertex,vertices,elevation,height,sample,dem,update,feature" ).split( ',' );
198}
199
200QString QgsDrapeToZAlgorithm::shortHelpString() const
201{
202 return QObject::tr( "This algorithm sets the z value of every vertex in the feature geometry to a value sampled from a band within a raster layer." )
203 + QStringLiteral( "\n\n" )
204 + QObject::tr( "The raster values can optionally be scaled by a preset amount and an offset can be algebraically added." );
205}
206
207QString QgsDrapeToZAlgorithm::shortDescription() const
208{
209 return QObject::tr( "Sets the z value for vertices to values sampled from a raster layer." );
210}
211
212QgsDrapeToZAlgorithm *QgsDrapeToZAlgorithm::createInstance() const
213{
214 return new QgsDrapeToZAlgorithm();
215}
216
217bool QgsDrapeToZAlgorithm::supportInPlaceEdit( const QgsMapLayer *l ) const
218{
219 const QgsVectorLayer *layer = qobject_cast< const QgsVectorLayer * >( l );
220 if ( !layer )
221 return false;
222
223 if ( ! QgsDrapeAlgorithmBase::supportInPlaceEdit( layer ) )
224 return false;
225 return QgsWkbTypes::hasZ( layer->wkbType() );
226}
227
228Qgis::WkbType QgsDrapeToZAlgorithm::outputWkbType( Qgis::WkbType inputWkbType ) const
229{
230 const Qgis::WkbType wkb = inputWkbType;
231 return QgsWkbTypes::addZ( wkb );
232}
233
234void QgsDrapeToZAlgorithm::prepareGeometry( QgsGeometry &geometry, double defaultVal ) const
235{
236 geometry.get()->addZValue( defaultVal );
237}
238
239QgsPoint QgsDrapeToZAlgorithm::drapeVertex( const QgsPoint &p, double rasterVal ) const
240{
241 return QgsPoint( p.wkbType(), p.x(), p.y(), rasterVal, p.m() );
242}
243
244//
245// QgsDrapeToMAlgorithm
246//
247
248QString QgsDrapeToMAlgorithm::name() const
249{
250 return QStringLiteral( "setmfromraster" );
251}
252
253QString QgsDrapeToMAlgorithm::displayName() const
254{
255 return QObject::tr( "Set M value from raster" );
256}
257
258QStringList QgsDrapeToMAlgorithm::tags() const
259{
260 return QObject::tr( "drape,vertex,vertices,sample,dem,update,feature,measure" ).split( ',' );
261}
262
263QString QgsDrapeToMAlgorithm::shortHelpString() const
264{
265 return QObject::tr( "This algorithm sets the M value for every vertex in the feature geometry to a value sampled from a band within a raster layer." )
266 + QStringLiteral( "\n\n" )
267 + QObject::tr( "The raster values can optionally be scaled by a preset amount and an offset can be algebraically added." );
268}
269
270QString QgsDrapeToMAlgorithm::shortDescription() const
271{
272 return QObject::tr( "Sets the M value for vertices to values sampled from a raster layer." );
273}
274
275QgsDrapeToMAlgorithm *QgsDrapeToMAlgorithm::createInstance() const
276{
277 return new QgsDrapeToMAlgorithm();
278}
279
280bool QgsDrapeToMAlgorithm::supportInPlaceEdit( const QgsMapLayer *l ) const
281{
282 const QgsVectorLayer *layer = qobject_cast< const QgsVectorLayer * >( l );
283 if ( !layer )
284 return false;
285
286 if ( ! QgsDrapeAlgorithmBase::supportInPlaceEdit( layer ) )
287 return false;
288 return QgsWkbTypes::hasM( layer->wkbType() );
289}
290
291Qgis::WkbType QgsDrapeToMAlgorithm::outputWkbType( Qgis::WkbType inputWkbType ) const
292{
293 const Qgis::WkbType wkb = inputWkbType;
294 return QgsWkbTypes::addM( wkb );
295}
296
297void QgsDrapeToMAlgorithm::prepareGeometry( QgsGeometry &geometry, double defaultVal ) const
298{
299 geometry.get()->addMValue( defaultVal );
300}
301
302QgsPoint QgsDrapeToMAlgorithm::drapeVertex( const QgsPoint &p, double rasterVal ) const
303{
304 return QgsPoint( p.wkbType(), p.x(), p.y(), p.z(), rasterVal );
305}
306
307
309
310
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition: qgis.h:182
@ Reverse
Reverse/inverse transform (from destination to source)
virtual bool addZValue(double zValue=0)=0
Adds a z-dimension to the geometry, initialized to a preset value.
virtual bool addMValue(double mValue=0)=0
Adds a measure to the geometry, initialized to a preset value.
Qgis::WkbType wkbType() const
Returns the WKB type of the geometry.
Class for doing transforms between two map coordinate systems.
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:67
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QgsGeometry geometry
Definition: qgsfeature.h:67
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:230
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:167
Q_GADGET QgsFeatureId id
Definition: qgsfeature.h:64
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:162
bool boundingBoxIntersects(const QgsRectangle &rectangle) const
Returns true if the bounding box of this geometry intersects with a rectangle.
void transformVertices(const std::function< QgsPoint(const QgsPoint &) > &transform)
Transforms the vertices from the geometry in place, applying the transform function to every vertex.
QgsAbstractGeometry * get()
Returns a modifiable (non-const) reference to the underlying abstract geometry primitive.
Base class for all map layer types.
Definition: qgsmaplayer.h:75
A class to represent a 2D point.
Definition: qgspointxy.h:60
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:49
Q_GADGET double x
Definition: qgspoint.h:52
double z
Definition: qgspoint.h:54
double m
Definition: qgspoint.h:55
double y
Definition: qgspoint.h:53
Contains information about the context in which a processing algorithm is executed.
QgsExpressionContext & expressionContext()
Returns the expression context.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
Custom exception class for processing related exceptions.
Definition: qgsexception.h:83
Base class for providing feedback from a processing algorithm.
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
A raster band parameter for Processing algorithms.
A raster layer parameter for processing algorithms.
static bool isDynamic(const QVariantMap &parameters, const QString &name)
Returns true if the parameter with matching name is a dynamic parameter, and must be evaluated once f...
Definition for a property.
Definition: qgsproperty.h:45
@ Double
Double value (including negative values)
Definition: qgsproperty.h:55
A store for object properties.
Definition: qgsproperty.h:228
double valueAsDouble(const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property and interprets it as a double.
Base class for raster data providers.
Represents a raster layer.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
Represents a vector layer which manages a vector based data sets.
Q_INVOKABLE Qgis::WkbType wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
static Qgis::WkbType addM(Qgis::WkbType type)
Adds the m dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1092
static Qgis::WkbType addZ(Qgis::WkbType type)
Adds the z dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1068
static bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:973
static bool hasM(Qgis::WkbType type)
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:1023
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:917