QGIS API Documentation 3.43.0-Master (b60ef06885e)
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" ), QObject::tr( "Raster layer" ) ) );
42 addParameter( new QgsProcessingParameterBand( QStringLiteral( "BAND" ), QObject::tr( "Band number" ), 1, QStringLiteral( "RASTER" ) ) );
43
44 // nodata value
45 auto nodata = std::make_unique<QgsProcessingParameterNumber>( QStringLiteral( "NODATA" ), QObject::tr( "Value for NoData or non-intersecting vertices" ), Qgis::ProcessingNumberParameterType::Double, 0.0 );
46 nodata->setIsDynamic( true );
47 nodata->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "NODATA" ), QObject::tr( "Value for NoData or non-intersecting vertices" ), QgsPropertyDefinition::Double ) );
48 nodata->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
49 addParameter( nodata.release() );
50
51 auto scaleParam = std::make_unique<QgsProcessingParameterNumber>( QStringLiteral( "SCALE" ), QObject::tr( "Scale factor" ), Qgis::ProcessingNumberParameterType::Double, 1.0, false, 0.0 );
52 scaleParam->setIsDynamic( true );
53 scaleParam->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "SCALE" ), QObject::tr( "Scale factor" ), QgsPropertyDefinition::Double ) );
54 scaleParam->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
55 addParameter( scaleParam.release() );
56
57 auto offsetParam = std::make_unique<QgsProcessingParameterNumber>( QStringLiteral( "OFFSET" ), QObject::tr( "Offset" ), Qgis::ProcessingNumberParameterType::Double, 0.0 );
58 offsetParam->setIsDynamic( true );
59 offsetParam->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "OFFSET" ), QObject::tr( "Offset" ), QgsPropertyDefinition::Double ) );
60 offsetParam->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
61 addParameter( offsetParam.release() );
62}
63
64bool QgsDrapeAlgorithmBase::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
65{
66 mNoData = parameterAsDouble( parameters, QStringLiteral( "NODATA" ), context );
67 mDynamicNoData = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "NODATA" ) );
68 if ( mDynamicNoData )
69 mNoDataProperty = parameters.value( QStringLiteral( "NODATA" ) ).value<QgsProperty>();
70
71 mScale = parameterAsDouble( parameters, QStringLiteral( "SCALE" ), context );
72 mDynamicScale = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "SCALE" ) );
73 if ( mDynamicScale )
74 mScaleProperty = parameters.value( QStringLiteral( "SCALE" ) ).value<QgsProperty>();
75
76 mOffset = parameterAsDouble( parameters, QStringLiteral( "OFFSET" ), context );
77 mDynamicOffset = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "OFFSET" ) );
78 if ( mDynamicOffset )
79 mOffsetProperty = parameters.value( QStringLiteral( "OFFSET" ) ).value<QgsProperty>();
80
81 QgsRasterLayer *layer = parameterAsRasterLayer( parameters, QStringLiteral( "RASTER" ), context );
82
83 if ( !layer )
84 throw QgsProcessingException( invalidRasterError( parameters, QStringLiteral( "RASTER" ) ) );
85
86 mBand = parameterAsInt( parameters, QStringLiteral( "BAND" ), context );
87 if ( mBand < 1 || mBand > layer->bandCount() )
88 throw QgsProcessingException( QObject::tr( "Invalid band number for BAND (%1): Valid values for input raster are 1 to %2" ).arg( mBand ).arg( layer->bandCount() ) );
89 mRasterExtent = layer->extent();
90
91 mRasterProvider.reset( layer->dataProvider()->clone() );
92 if ( !mRasterProvider )
93 throw QgsProcessingException( invalidRasterError( parameters, QStringLiteral( "RASTER" ) ) );
94
95 return true;
96}
97
98QgsFeatureList QgsDrapeAlgorithmBase::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
99{
100 if ( !mCreatedTransform )
101 {
102 mCreatedTransform = true;
103 mTransform = QgsCoordinateTransform( sourceCrs(), mRasterProvider->crs(), context.transformContext() );
104
105 // transform the raster extent back to the vector's crs, so that we can test
106 // whether individual vector geometries are actually covered by the raster
107 try
108 {
109 mRasterExtent = mTransform.transform( mRasterExtent, Qgis::TransformDirection::Reverse );
110 }
111 catch ( QgsCsException & )
112 {
113 mRasterExtent = QgsRectangle();
114 }
115 }
116
117 QgsFeature f = feature;
118 if ( f.hasGeometry() )
119 {
120 QgsGeometry geometry = f.geometry();
121
122 double nodata = mNoData;
123 if ( mDynamicNoData )
124 nodata = mNoDataProperty.valueAsDouble( context.expressionContext(), nodata );
125
126 double scale = mScale;
127 if ( mDynamicScale )
128 scale = mScaleProperty.valueAsDouble( context.expressionContext(), scale );
129
130 double offset = mOffset;
131 if ( mDynamicOffset )
132 offset = mOffsetProperty.valueAsDouble( context.expressionContext(), offset );
133
134 prepareGeometry( geometry, nodata );
135
136 // only do the "draping" if the geometry intersects the raster - otherwise skip
137 // a pointless iteration over all vertices
138 if ( !mRasterExtent.isNull() && geometry.boundingBoxIntersects( mRasterExtent ) )
139 {
140 geometry.transformVertices( [=]( const QgsPoint &p ) -> QgsPoint {
141 QgsPointXY t;
142 double val = nodata;
143 try
144 {
145 t = mTransform.transform( p );
146 bool ok = false;
147 val = mRasterProvider->sample( t, mBand, &ok );
148 if ( !ok )
149 val = nodata;
150 else
151 {
152 val *= scale;
153 val += offset;
154 }
155 }
156 catch ( QgsCsException & )
157 {
158 feedback->reportError( QObject::tr( "Transform error while reprojecting feature {}" ).arg( f.id() ) );
159 }
160
161 return drapeVertex( p, val );
162 } );
163 }
164
165 f.setGeometry( geometry );
166 }
167 return QgsFeatureList() << f;
168}
169
170
171//
172// QgsDrapeToZAlgorithm
173//
174
175QString QgsDrapeToZAlgorithm::name() const
176{
177 return QStringLiteral( "setzfromraster" );
178}
179
180QString QgsDrapeToZAlgorithm::displayName() const
181{
182 return QObject::tr( "Drape (set Z value from raster)" );
183}
184
185QStringList QgsDrapeToZAlgorithm::tags() const
186{
187 return QObject::tr( "3d,vertex,vertices,elevation,height,sample,dem,update,feature" ).split( ',' );
188}
189
190QString QgsDrapeToZAlgorithm::shortHelpString() const
191{
192 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." )
193 + QStringLiteral( "\n\n" )
194 + QObject::tr( "The raster values can optionally be scaled by a preset amount and an offset can be algebraically added." );
195}
196
197QString QgsDrapeToZAlgorithm::shortDescription() const
198{
199 return QObject::tr( "Sets the z value for vertices to values sampled from a raster layer." );
200}
201
202QgsDrapeToZAlgorithm *QgsDrapeToZAlgorithm::createInstance() const
203{
204 return new QgsDrapeToZAlgorithm();
205}
206
207bool QgsDrapeToZAlgorithm::supportInPlaceEdit( const QgsMapLayer *l ) const
208{
209 const QgsVectorLayer *layer = qobject_cast<const QgsVectorLayer *>( l );
210 if ( !layer )
211 return false;
212
213 if ( !QgsDrapeAlgorithmBase::supportInPlaceEdit( layer ) )
214 return false;
215 return QgsWkbTypes::hasZ( layer->wkbType() );
216}
217
218Qgis::WkbType QgsDrapeToZAlgorithm::outputWkbType( Qgis::WkbType inputWkbType ) const
219{
220 const Qgis::WkbType wkb = inputWkbType;
221 return QgsWkbTypes::addZ( wkb );
222}
223
224void QgsDrapeToZAlgorithm::prepareGeometry( QgsGeometry &geometry, double defaultVal ) const
225{
226 geometry.get()->addZValue( defaultVal );
227}
228
229QgsPoint QgsDrapeToZAlgorithm::drapeVertex( const QgsPoint &p, double rasterVal ) const
230{
231 return QgsPoint( p.wkbType(), p.x(), p.y(), rasterVal, p.m() );
232}
233
234//
235// QgsDrapeToMAlgorithm
236//
237
238QString QgsDrapeToMAlgorithm::name() const
239{
240 return QStringLiteral( "setmfromraster" );
241}
242
243QString QgsDrapeToMAlgorithm::displayName() const
244{
245 return QObject::tr( "Set M value from raster" );
246}
247
248QStringList QgsDrapeToMAlgorithm::tags() const
249{
250 return QObject::tr( "drape,vertex,vertices,sample,dem,update,feature,measure" ).split( ',' );
251}
252
253QString QgsDrapeToMAlgorithm::shortHelpString() const
254{
255 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." )
256 + QStringLiteral( "\n\n" )
257 + QObject::tr( "The raster values can optionally be scaled by a preset amount and an offset can be algebraically added." );
258}
259
260QString QgsDrapeToMAlgorithm::shortDescription() const
261{
262 return QObject::tr( "Sets the M value for vertices to values sampled from a raster layer." );
263}
264
265QgsDrapeToMAlgorithm *QgsDrapeToMAlgorithm::createInstance() const
266{
267 return new QgsDrapeToMAlgorithm();
268}
269
270bool QgsDrapeToMAlgorithm::supportInPlaceEdit( const QgsMapLayer *l ) const
271{
272 const QgsVectorLayer *layer = qobject_cast<const QgsVectorLayer *>( l );
273 if ( !layer )
274 return false;
275
276 if ( !QgsDrapeAlgorithmBase::supportInPlaceEdit( layer ) )
277 return false;
278 return QgsWkbTypes::hasM( layer->wkbType() );
279}
280
281Qgis::WkbType QgsDrapeToMAlgorithm::outputWkbType( Qgis::WkbType inputWkbType ) const
282{
283 const Qgis::WkbType wkb = inputWkbType;
284 return QgsWkbTypes::addM( wkb );
285}
286
287void QgsDrapeToMAlgorithm::prepareGeometry( QgsGeometry &geometry, double defaultVal ) const
288{
289 geometry.get()->addMValue( defaultVal );
290}
291
292QgsPoint QgsDrapeToMAlgorithm::drapeVertex( const QgsPoint &p, double rasterVal ) const
293{
294 return QgsPoint( p.wkbType(), p.x(), p.y(), p.z(), rasterVal );
295}
296
297
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:256
@ 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.
Handles coordinate transforms between two coordinate systems.
Custom exception class for Coordinate Reference System related exceptions.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
QgsFeatureId id
Definition qgsfeature.h:66
QgsGeometry geometry
Definition qgsfeature.h:69
bool hasGeometry() const
Returns true if the feature has an associated geometry.
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
A geometry is the spatial representation of a feature.
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:77
Represents a 2D point.
Definition qgspointxy.h:60
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:49
double z
Definition qgspoint.h:54
double x
Definition qgspoint.h:52
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.
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.
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.
Represents a raster layer.
A rectangle specified with double values.
Represents a vector layer which manages a vector based dataset.
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.
static Qgis::WkbType addZ(Qgis::WkbType type)
Adds the z dimension to a WKB type and returns the new type.
static bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
static bool hasM(Qgis::WkbType type)
Tests whether a WKB type contains m values.
QList< QgsFeature > QgsFeatureList