QGIS API Documentation 3.39.0-Master (47f7b3a4989)
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 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:201
@ 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: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
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.
Base class for raster data providers.
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