QGIS API Documentation 3.41.0-Master (af5edcb665c)
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" ), QObject::tr( "Raster layer" ) ) );
42 addParameter( new QgsProcessingParameterBand( QStringLiteral( "BAND" ), QObject::tr( "Band number" ), 1, QStringLiteral( "RASTER" ) ) );
43
44 // nodata value
45 std::unique_ptr<QgsProcessingParameterNumber> 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.
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