QGIS API Documentation 3.99.0-Master (357b655ed83)
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
22#include <QString>
23
24using namespace Qt::StringLiterals;
25
27
28
29QString QgsDrapeAlgorithmBase::group() const
30{
31 return QObject::tr( "Vector geometry" );
32}
33
34QString QgsDrapeAlgorithmBase::groupId() const
35{
36 return u"vectorgeometry"_s;
37}
38
39QString QgsDrapeAlgorithmBase::outputName() const
40{
41 return QObject::tr( "Draped" );
42}
43
44void QgsDrapeAlgorithmBase::initParameters( const QVariantMap & )
45{
46 addParameter( new QgsProcessingParameterRasterLayer( u"RASTER"_s, QObject::tr( "Raster layer" ) ) );
47 addParameter( new QgsProcessingParameterBand( u"BAND"_s, QObject::tr( "Band number" ), 1, u"RASTER"_s ) );
48
49 // nodata value
50 auto nodata = std::make_unique<QgsProcessingParameterNumber>( u"NODATA"_s, QObject::tr( "Value for NoData or non-intersecting vertices" ), Qgis::ProcessingNumberParameterType::Double, 0.0 );
51 nodata->setIsDynamic( true );
52 nodata->setDynamicPropertyDefinition( QgsPropertyDefinition( u"NODATA"_s, QObject::tr( "Value for NoData or non-intersecting vertices" ), QgsPropertyDefinition::Double ) );
53 nodata->setDynamicLayerParameterName( u"INPUT"_s );
54 addParameter( nodata.release() );
55
56 auto scaleParam = std::make_unique<QgsProcessingParameterNumber>( u"SCALE"_s, QObject::tr( "Scale factor" ), Qgis::ProcessingNumberParameterType::Double, 1.0, false, 0.0 );
57 scaleParam->setIsDynamic( true );
58 scaleParam->setDynamicPropertyDefinition( QgsPropertyDefinition( u"SCALE"_s, QObject::tr( "Scale factor" ), QgsPropertyDefinition::Double ) );
59 scaleParam->setDynamicLayerParameterName( u"INPUT"_s );
60 addParameter( scaleParam.release() );
61
62 auto offsetParam = std::make_unique<QgsProcessingParameterNumber>( u"OFFSET"_s, QObject::tr( "Offset" ), Qgis::ProcessingNumberParameterType::Double, 0.0 );
63 offsetParam->setIsDynamic( true );
64 offsetParam->setDynamicPropertyDefinition( QgsPropertyDefinition( u"OFFSET"_s, QObject::tr( "Offset" ), QgsPropertyDefinition::Double ) );
65 offsetParam->setDynamicLayerParameterName( u"INPUT"_s );
66 addParameter( offsetParam.release() );
67}
68
69bool QgsDrapeAlgorithmBase::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
70{
71 mNoData = parameterAsDouble( parameters, u"NODATA"_s, context );
72 mDynamicNoData = QgsProcessingParameters::isDynamic( parameters, u"NODATA"_s );
73 if ( mDynamicNoData )
74 mNoDataProperty = parameters.value( u"NODATA"_s ).value<QgsProperty>();
75
76 mScale = parameterAsDouble( parameters, u"SCALE"_s, context );
77 mDynamicScale = QgsProcessingParameters::isDynamic( parameters, u"SCALE"_s );
78 if ( mDynamicScale )
79 mScaleProperty = parameters.value( u"SCALE"_s ).value<QgsProperty>();
80
81 mOffset = parameterAsDouble( parameters, u"OFFSET"_s, context );
82 mDynamicOffset = QgsProcessingParameters::isDynamic( parameters, u"OFFSET"_s );
83 if ( mDynamicOffset )
84 mOffsetProperty = parameters.value( u"OFFSET"_s ).value<QgsProperty>();
85
86 QgsRasterLayer *layer = parameterAsRasterLayer( parameters, u"RASTER"_s, context );
87
88 if ( !layer )
89 throw QgsProcessingException( invalidRasterError( parameters, u"RASTER"_s ) );
90
91 mBand = parameterAsInt( parameters, u"BAND"_s, context );
92 if ( mBand < 1 || mBand > layer->bandCount() )
93 throw QgsProcessingException( QObject::tr( "Invalid band number for BAND (%1): Valid values for input raster are 1 to %2" ).arg( mBand ).arg( layer->bandCount() ) );
94 mRasterExtent = layer->extent();
95
96 mRasterProvider.reset( layer->dataProvider()->clone() );
97 if ( !mRasterProvider )
98 throw QgsProcessingException( invalidRasterError( parameters, u"RASTER"_s ) );
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( [this, nodata, scale, offset, feedback, &f]( const QgsPoint &p ) -> QgsPoint {
146 QgsPointXY t;
147 double val = nodata;
148 try
149 {
150 t = mTransform.transform( p );
151 bool ok = false;
152 val = mRasterProvider->sample( t, mBand, &ok );
153 if ( !ok )
154 val = nodata;
155 else
156 {
157 val *= scale;
158 val += offset;
159 }
160 }
161 catch ( QgsCsException & )
162 {
163 feedback->reportError( QObject::tr( "Transform error while reprojecting feature {}" ).arg( f.id() ) );
164 }
165
166 return drapeVertex( p, val );
167 } );
168 }
169
170 f.setGeometry( geometry );
171 }
172 return QgsFeatureList() << f;
173}
174
175
176//
177// QgsDrapeToZAlgorithm
178//
179
180QString QgsDrapeToZAlgorithm::name() const
181{
182 return u"setzfromraster"_s;
183}
184
185QString QgsDrapeToZAlgorithm::displayName() const
186{
187 return QObject::tr( "Drape (set Z value from raster)" );
188}
189
190QStringList QgsDrapeToZAlgorithm::tags() const
191{
192 return QObject::tr( "3d,vertex,vertices,elevation,height,sample,dem,update,feature" ).split( ',' );
193}
194
195QString QgsDrapeToZAlgorithm::shortHelpString() const
196{
197 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." )
198 + u"\n\n"_s
199 + QObject::tr( "The raster values can optionally be scaled by a preset amount and an offset can be algebraically added." );
200}
201
202QString QgsDrapeToZAlgorithm::shortDescription() const
203{
204 return QObject::tr( "Sets the z value for vertices to values sampled from a raster layer." );
205}
206
207QgsDrapeToZAlgorithm *QgsDrapeToZAlgorithm::createInstance() const
208{
209 return new QgsDrapeToZAlgorithm();
210}
211
212bool QgsDrapeToZAlgorithm::supportInPlaceEdit( const QgsMapLayer *l ) const
213{
214 const QgsVectorLayer *layer = qobject_cast<const QgsVectorLayer *>( l );
215 if ( !layer )
216 return false;
217
218 if ( !QgsDrapeAlgorithmBase::supportInPlaceEdit( layer ) )
219 return false;
220 return QgsWkbTypes::hasZ( layer->wkbType() );
221}
222
223Qgis::WkbType QgsDrapeToZAlgorithm::outputWkbType( Qgis::WkbType inputWkbType ) const
224{
225 const Qgis::WkbType wkb = inputWkbType;
226 return QgsWkbTypes::addZ( wkb );
227}
228
229void QgsDrapeToZAlgorithm::prepareGeometry( QgsGeometry &geometry, double defaultVal ) const
230{
231 geometry.get()->addZValue( defaultVal );
232}
233
234QgsPoint QgsDrapeToZAlgorithm::drapeVertex( const QgsPoint &p, double rasterVal ) const
235{
236 return QgsPoint( p.wkbType(), p.x(), p.y(), rasterVal, p.m() );
237}
238
239//
240// QgsDrapeToMAlgorithm
241//
242
243QString QgsDrapeToMAlgorithm::name() const
244{
245 return u"setmfromraster"_s;
246}
247
248QString QgsDrapeToMAlgorithm::displayName() const
249{
250 return QObject::tr( "Set M value from raster" );
251}
252
253QStringList QgsDrapeToMAlgorithm::tags() const
254{
255 return QObject::tr( "drape,vertex,vertices,sample,dem,update,feature,measure" ).split( ',' );
256}
257
258QString QgsDrapeToMAlgorithm::shortHelpString() const
259{
260 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." )
261 + u"\n\n"_s
262 + QObject::tr( "The raster values can optionally be scaled by a preset amount and an offset can be algebraically added." );
263}
264
265QString QgsDrapeToMAlgorithm::shortDescription() const
266{
267 return QObject::tr( "Sets the M value for vertices to values sampled from a raster layer." );
268}
269
270QgsDrapeToMAlgorithm *QgsDrapeToMAlgorithm::createInstance() const
271{
272 return new QgsDrapeToMAlgorithm();
273}
274
275bool QgsDrapeToMAlgorithm::supportInPlaceEdit( const QgsMapLayer *l ) const
276{
277 const QgsVectorLayer *layer = qobject_cast<const QgsVectorLayer *>( l );
278 if ( !layer )
279 return false;
280
281 if ( !QgsDrapeAlgorithmBase::supportInPlaceEdit( layer ) )
282 return false;
283 return QgsWkbTypes::hasM( layer->wkbType() );
284}
285
286Qgis::WkbType QgsDrapeToMAlgorithm::outputWkbType( Qgis::WkbType inputWkbType ) const
287{
288 const Qgis::WkbType wkb = inputWkbType;
289 return QgsWkbTypes::addM( wkb );
290}
291
292void QgsDrapeToMAlgorithm::prepareGeometry( QgsGeometry &geometry, double defaultVal ) const
293{
294 geometry.get()->addMValue( defaultVal );
295}
296
297QgsPoint QgsDrapeToMAlgorithm::drapeVertex( const QgsPoint &p, double rasterVal ) const
298{
299 return QgsPoint( p.wkbType(), p.x(), p.y(), p.z(), rasterVal );
300}
301
302
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:280
@ Reverse
Reverse/inverse transform (from destination to source).
Definition qgis.h:2731
@ Double
Double/float values.
Definition qgis.h:3875
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:60
QgsFeatureId id
Definition qgsfeature.h:68
QgsGeometry geometry
Definition qgsfeature.h:71
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:83
Represents a 2D point.
Definition qgspointxy.h:62
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:53
double z
Definition qgspoint.h:58
double x
Definition qgspoint.h:56
double m
Definition qgspoint.h:59
double y
Definition qgspoint.h:57
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:47
@ Double
Double value (including negative values).
Definition qgsproperty.h:57
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