QGIS API Documentation 3.41.0-Master (3440c17df1d)
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#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 mRasterProvider.reset( layer->dataProvider()->clone() );
97 if ( !mRasterProvider )
98 throw QgsProcessingException( invalidRasterError( parameters, QStringLiteral( "RASTER" ) ) );
99
100 return true;
101}
102
103QgsFeatureList QgsDrapeAlgorithmBase::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
104{
105 if ( !mCreatedTransform )
106 {
107 mCreatedTransform = true;
108 mTransform = QgsCoordinateTransform( sourceCrs(), mRasterProvider->crs(), context.transformContext() );
109
110 // transform the raster extent back to the vector's crs, so that we can test
111 // whether individual vector geometries are actually covered by the raster
112 try
113 {
114 mRasterExtent = mTransform.transform( mRasterExtent, Qgis::TransformDirection::Reverse );
115 }
116 catch ( QgsCsException & )
117 {
118 mRasterExtent = QgsRectangle();
119 }
120 }
121
122 QgsFeature f = feature;
123 if ( f.hasGeometry() )
124 {
125 QgsGeometry geometry = f.geometry();
126
127 double nodata = mNoData;
128 if ( mDynamicNoData )
129 nodata = mNoDataProperty.valueAsDouble( context.expressionContext(), nodata );
130
131 double scale = mScale;
132 if ( mDynamicScale )
133 scale = mScaleProperty.valueAsDouble( context.expressionContext(), scale );
134
135 double offset = mOffset;
136 if ( mDynamicOffset )
137 offset = mOffsetProperty.valueAsDouble( context.expressionContext(), offset );
138
139 prepareGeometry( geometry, nodata );
140
141 // only do the "draping" if the geometry intersects the raster - otherwise skip
142 // a pointless iteration over all vertices
143 if ( !mRasterExtent.isNull() && geometry.boundingBoxIntersects( mRasterExtent ) )
144 {
145 geometry.transformVertices( [ = ]( const QgsPoint & p )->QgsPoint
146 {
147 QgsPointXY t;
148 double val = nodata;
149 try
150 {
151 t = mTransform.transform( p );
152 bool ok = false;
153 val = mRasterProvider->sample( t, mBand, &ok );
154 if ( !ok )
155 val = nodata;
156 else
157 {
158 val *= scale;
159 val += offset;
160 }
161 }
162 catch ( QgsCsException & )
163 {
164 feedback->reportError( QObject::tr( "Transform error while reprojecting feature {}" ).arg( f.id() ) );
165 }
166
167 return drapeVertex( p, val );
168 } );
169 }
170
171 f.setGeometry( geometry );
172 }
173 return QgsFeatureList() << f;
174}
175
176
177//
178// QgsDrapeToZAlgorithm
179//
180
181QString QgsDrapeToZAlgorithm::name() const
182{
183 return QStringLiteral( "setzfromraster" );
184}
185
186QString QgsDrapeToZAlgorithm::displayName() const
187{
188 return QObject::tr( "Drape (set Z value from raster)" );
189}
190
191QStringList QgsDrapeToZAlgorithm::tags() const
192{
193 return QObject::tr( "3d,vertex,vertices,elevation,height,sample,dem,update,feature" ).split( ',' );
194}
195
196QString QgsDrapeToZAlgorithm::shortHelpString() const
197{
198 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." )
199 + QStringLiteral( "\n\n" )
200 + QObject::tr( "The raster values can optionally be scaled by a preset amount and an offset can be algebraically added." );
201}
202
203QString QgsDrapeToZAlgorithm::shortDescription() const
204{
205 return QObject::tr( "Sets the z value for vertices to values sampled from a raster layer." );
206}
207
208QgsDrapeToZAlgorithm *QgsDrapeToZAlgorithm::createInstance() const
209{
210 return new QgsDrapeToZAlgorithm();
211}
212
213bool QgsDrapeToZAlgorithm::supportInPlaceEdit( const QgsMapLayer *l ) const
214{
215 const QgsVectorLayer *layer = qobject_cast< const QgsVectorLayer * >( l );
216 if ( !layer )
217 return false;
218
219 if ( ! QgsDrapeAlgorithmBase::supportInPlaceEdit( layer ) )
220 return false;
221 return QgsWkbTypes::hasZ( layer->wkbType() );
222}
223
224Qgis::WkbType QgsDrapeToZAlgorithm::outputWkbType( Qgis::WkbType inputWkbType ) const
225{
226 const Qgis::WkbType wkb = inputWkbType;
227 return QgsWkbTypes::addZ( wkb );
228}
229
230void QgsDrapeToZAlgorithm::prepareGeometry( QgsGeometry &geometry, double defaultVal ) const
231{
232 geometry.get()->addZValue( defaultVal );
233}
234
235QgsPoint QgsDrapeToZAlgorithm::drapeVertex( const QgsPoint &p, double rasterVal ) const
236{
237 return QgsPoint( p.wkbType(), p.x(), p.y(), rasterVal, p.m() );
238}
239
240//
241// QgsDrapeToMAlgorithm
242//
243
244QString QgsDrapeToMAlgorithm::name() const
245{
246 return QStringLiteral( "setmfromraster" );
247}
248
249QString QgsDrapeToMAlgorithm::displayName() const
250{
251 return QObject::tr( "Set M value from raster" );
252}
253
254QStringList QgsDrapeToMAlgorithm::tags() const
255{
256 return QObject::tr( "drape,vertex,vertices,sample,dem,update,feature,measure" ).split( ',' );
257}
258
259QString QgsDrapeToMAlgorithm::shortHelpString() const
260{
261 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." )
262 + QStringLiteral( "\n\n" )
263 + QObject::tr( "The raster values can optionally be scaled by a preset amount and an offset can be algebraically added." );
264}
265
266QString QgsDrapeToMAlgorithm::shortDescription() const
267{
268 return QObject::tr( "Sets the M value for vertices to values sampled from a raster layer." );
269}
270
271QgsDrapeToMAlgorithm *QgsDrapeToMAlgorithm::createInstance() const
272{
273 return new QgsDrapeToMAlgorithm();
274}
275
276bool QgsDrapeToMAlgorithm::supportInPlaceEdit( const QgsMapLayer *l ) const
277{
278 const QgsVectorLayer *layer = qobject_cast< const QgsVectorLayer * >( l );
279 if ( !layer )
280 return false;
281
282 if ( ! QgsDrapeAlgorithmBase::supportInPlaceEdit( layer ) )
283 return false;
284 return QgsWkbTypes::hasM( layer->wkbType() );
285}
286
287Qgis::WkbType QgsDrapeToMAlgorithm::outputWkbType( Qgis::WkbType inputWkbType ) const
288{
289 const Qgis::WkbType wkb = inputWkbType;
290 return QgsWkbTypes::addM( wkb );
291}
292
293void QgsDrapeToMAlgorithm::prepareGeometry( QgsGeometry &geometry, double defaultVal ) const
294{
295 geometry.get()->addMValue( defaultVal );
296}
297
298QgsPoint QgsDrapeToMAlgorithm::drapeVertex( const QgsPoint &p, double rasterVal ) const
299{
300 return QgsPoint( p.wkbType(), p.x(), p.y(), p.z(), rasterVal );
301}
302
303
305
306
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.
Class for doing transforms between two map 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:76
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
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 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.
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