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