QGIS API Documentation  3.17.0-Master (df2c9ff931)
qgsalgorithmaffinetransform.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsalgorithmaffinetransform.cpp
3  ---------------------
4  begin : December 2019
5  copyright : (C) 2019 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 
19 #include "qgsvectorlayer.h"
20 
22 
23 QString QgsAffineTransformationAlgorithm::name() const
24 {
25  return QStringLiteral( "affinetransform" );
26 }
27 
28 QString QgsAffineTransformationAlgorithm::displayName() const
29 {
30  return QObject::tr( "Affine transform" );
31 }
32 
33 QStringList QgsAffineTransformationAlgorithm::tags() const
34 {
35  return QObject::tr( "move,shift,transform,affine,scale,rotate,resize,matrix" ).split( ',' );
36 }
37 
38 QString QgsAffineTransformationAlgorithm::group() const
39 {
40  return QObject::tr( "Vector geometry" );
41 }
42 
43 QString QgsAffineTransformationAlgorithm::groupId() const
44 {
45  return QStringLiteral( "vectorgeometry" );
46 }
47 
48 QString QgsAffineTransformationAlgorithm::outputName() const
49 {
50  return QObject::tr( "Transformed" );
51 }
52 
53 QString QgsAffineTransformationAlgorithm::shortHelpString() const
54 {
55  return QObject::tr( "Applies an affine transformation to the geometries from a layer. Affine transformations can include "
56  "translation, scaling and rotation. The operations are performed in a scale, rotation, translation order." )
57  + QStringLiteral( "\n\n" )
58  + QObject::tr( "Z and M values present in the geometry can also be translated and scaled independently." );
59 }
60 
61 QString QgsAffineTransformationAlgorithm::shortDescription() const
62 {
63  return QObject::tr( "Applies an affine transformation to geometries." );
64 }
65 
66 QgsAffineTransformationAlgorithm *QgsAffineTransformationAlgorithm::createInstance() const
67 {
68  return new QgsAffineTransformationAlgorithm();
69 }
70 
71 void QgsAffineTransformationAlgorithm::initParameters( const QVariantMap & )
72 {
73  std::unique_ptr< QgsProcessingParameterDistance > xOffset = qgis::make_unique< QgsProcessingParameterDistance >( QStringLiteral( "DELTA_X" ),
74  QObject::tr( "Translation (x-axis)" ),
75  0.0, QStringLiteral( "INPUT" ) );
76  xOffset->setIsDynamic( true );
77  xOffset->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "DELTA_X" ), QObject::tr( "Offset distance (x-axis)" ), QgsPropertyDefinition::Double ) );
78  xOffset->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
79  addParameter( xOffset.release() );
80 
81  std::unique_ptr< QgsProcessingParameterDistance > yOffset = qgis::make_unique< QgsProcessingParameterDistance >( QStringLiteral( "DELTA_Y" ),
82  QObject::tr( "Translation (y-axis)" ),
83  0.0, QStringLiteral( "INPUT" ) );
84  yOffset->setIsDynamic( true );
85  yOffset->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "DELTA_Y" ), QObject::tr( "Offset distance (y-axis)" ), QgsPropertyDefinition::Double ) );
86  yOffset->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
87  addParameter( yOffset.release() );
88 
89  std::unique_ptr< QgsProcessingParameterNumber > zOffset = qgis::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "DELTA_Z" ),
90  QObject::tr( "Translation (z-axis)" ), QgsProcessingParameterNumber::Double,
91  0.0 );
92  zOffset->setIsDynamic( true );
93  zOffset->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "DELTA_Z" ), QObject::tr( "Offset distance (z-axis)" ), QgsPropertyDefinition::Double ) );
94  zOffset->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
95  addParameter( zOffset.release() );
96 
97  std::unique_ptr< QgsProcessingParameterNumber > mOffset = qgis::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "DELTA_M" ),
98  QObject::tr( "Translation (m values)" ), QgsProcessingParameterNumber::Double,
99  0.0 );
100  mOffset->setIsDynamic( true );
101  mOffset->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "DELTA_M" ), QObject::tr( "Offset distance (m values)" ), QgsPropertyDefinition::Double ) );
102  mOffset->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
103  addParameter( mOffset.release() );
104 
105  std::unique_ptr< QgsProcessingParameterNumber > xScale = qgis::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "SCALE_X" ),
106  QObject::tr( "Scale factor (x-axis)" ), QgsProcessingParameterNumber::Double,
107  1.0 );
108  xScale->setIsDynamic( true );
109  xScale->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "SCALE_X" ), QObject::tr( "Scale factor (x-axis)" ), QgsPropertyDefinition::Double ) );
110  xScale->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
111  addParameter( xScale.release() );
112 
113  std::unique_ptr< QgsProcessingParameterNumber > yScale = qgis::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "SCALE_Y" ),
114  QObject::tr( "Scale factor (y-axis)" ), QgsProcessingParameterNumber::Double,
115  1.0 );
116  yScale->setIsDynamic( true );
117  yScale->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "SCALE_Y" ), QObject::tr( "Scale factor (y-axis)" ), QgsPropertyDefinition::Double ) );
118  yScale->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
119  addParameter( yScale.release() );
120 
121  std::unique_ptr< QgsProcessingParameterNumber > zScale = qgis::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "SCALE_Z" ),
122  QObject::tr( "Scale factor (z-axis)" ), QgsProcessingParameterNumber::Double,
123  1.0 );
124  zScale->setIsDynamic( true );
125  zScale->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "SCALE_Z" ), QObject::tr( "Scale factor (z-axis)" ), QgsPropertyDefinition::Double ) );
126  zScale->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
127  addParameter( zScale.release() );
128 
129  std::unique_ptr< QgsProcessingParameterNumber > mScale = qgis::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "SCALE_M" ),
130  QObject::tr( "Scale factor (m values)" ), QgsProcessingParameterNumber::Double,
131  1.0 );
132  mScale->setIsDynamic( true );
133  mScale->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "SCALE_M" ), QObject::tr( "Scale factor (m values)" ), QgsPropertyDefinition::Double ) );
134  mScale->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
135  addParameter( mScale.release() );
136 
137  std::unique_ptr< QgsProcessingParameterNumber > rotation = qgis::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "ROTATION_Z" ),
138  QObject::tr( "Rotation around z-axis (degrees counter-clockwise)" ), QgsProcessingParameterNumber::Double,
139  0.0 );
140  rotation->setIsDynamic( true );
141  rotation->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "ROTATION_Z" ), QObject::tr( "Rotation around z-axis (degrees counter-clockwise)" ), QgsPropertyDefinition::Double ) );
142  rotation->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
143  addParameter( rotation.release() );
144 }
145 
146 bool QgsAffineTransformationAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
147 {
148  mDeltaX = parameterAsDouble( parameters, QStringLiteral( "DELTA_X" ), context );
149  mDynamicDeltaX = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DELTA_X" ) );
150  if ( mDynamicDeltaX )
151  mDeltaXProperty = parameters.value( QStringLiteral( "DELTA_X" ) ).value< QgsProperty >();
152 
153  mDeltaY = parameterAsDouble( parameters, QStringLiteral( "DELTA_Y" ), context );
154  mDynamicDeltaY = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DELTA_Y" ) );
155  if ( mDynamicDeltaY )
156  mDeltaYProperty = parameters.value( QStringLiteral( "DELTA_Y" ) ).value< QgsProperty >();
157 
158  mDeltaZ = parameterAsDouble( parameters, QStringLiteral( "DELTA_Z" ), context );
159  mDynamicDeltaZ = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DELTA_Z" ) );
160  if ( mDynamicDeltaZ )
161  mDeltaZProperty = parameters.value( QStringLiteral( "DELTA_Z" ) ).value< QgsProperty >();
162 
163  mDeltaM = parameterAsDouble( parameters, QStringLiteral( "DELTA_M" ), context );
164  mDynamicDeltaM = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DELTA_M" ) );
165  if ( mDynamicDeltaM )
166  mDeltaMProperty = parameters.value( QStringLiteral( "DELTA_M" ) ).value< QgsProperty >();
167 
168  mScaleX = parameterAsDouble( parameters, QStringLiteral( "SCALE_X" ), context );
169  mDynamicScaleX = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "SCALE_X" ) );
170  if ( mDynamicScaleX )
171  mScaleXProperty = parameters.value( QStringLiteral( "SCALE_X" ) ).value< QgsProperty >();
172 
173  mScaleY = parameterAsDouble( parameters, QStringLiteral( "SCALE_Y" ), context );
174  mDynamicScaleY = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "SCALE_Y" ) );
175  if ( mDynamicScaleY )
176  mScaleYProperty = parameters.value( QStringLiteral( "SCALE_Y" ) ).value< QgsProperty >();
177 
178  mScaleZ = parameterAsDouble( parameters, QStringLiteral( "SCALE_Z" ), context );
179  mDynamicScaleZ = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "SCALE_Z" ) );
180  if ( mDynamicScaleZ )
181  mScaleZProperty = parameters.value( QStringLiteral( "SCALE_Z" ) ).value< QgsProperty >();
182 
183  mScaleM = parameterAsDouble( parameters, QStringLiteral( "SCALE_M" ), context );
184  mDynamicScaleM = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "SCALE_M" ) );
185  if ( mDynamicScaleM )
186  mScaleMProperty = parameters.value( QStringLiteral( "SCALE_M" ) ).value< QgsProperty >();
187 
188  mRotationZ = parameterAsDouble( parameters, QStringLiteral( "ROTATION_Z" ), context );
189  mDynamicRotationZ = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "ROTATION_Z" ) );
190  if ( mDynamicRotationZ )
191  mRotationZProperty = parameters.value( QStringLiteral( "ROTATION_Z" ) ).value< QgsProperty >();
192 
193  return true;
194 }
195 
196 QgsFeatureList QgsAffineTransformationAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback * )
197 {
198  QgsFeature f = feature;
199  if ( f.hasGeometry() )
200  {
201  QgsGeometry geometry = f.geometry();
202 
203  double deltaX = mDeltaX;
204  if ( mDynamicDeltaX )
205  deltaX = mDeltaXProperty.valueAsDouble( context.expressionContext(), deltaX );
206  double deltaY = mDeltaY;
207  if ( mDynamicDeltaY )
208  deltaY = mDeltaYProperty.valueAsDouble( context.expressionContext(), deltaY );
209  double deltaZ = mDeltaZ;
210  if ( mDynamicDeltaZ )
211  deltaZ = mDeltaZProperty.valueAsDouble( context.expressionContext(), deltaZ );
212  double deltaM = mDeltaM;
213  if ( mDynamicDeltaM )
214  deltaM = mDeltaMProperty.valueAsDouble( context.expressionContext(), deltaM );
215 
216  if ( deltaZ != 0.0 && !geometry.constGet()->is3D() )
217  geometry.get()->addZValue( 0 );
218  if ( deltaM != 0.0 && !geometry.constGet()->isMeasure() )
219  geometry.get()->addMValue( 0 );
220 
221  double scaleX = mScaleX;
222  if ( mDynamicScaleX )
223  scaleX = mScaleXProperty.valueAsDouble( context.expressionContext(), scaleX );
224  double scaleY = mScaleY;
225  if ( mDynamicScaleY )
226  scaleY = mScaleYProperty.valueAsDouble( context.expressionContext(), scaleY );
227  double scaleZ = mScaleZ;
228  if ( mDynamicScaleZ )
229  scaleZ = mScaleZProperty.valueAsDouble( context.expressionContext(), scaleZ );
230  double scaleM = mScaleM;
231  if ( mDynamicScaleM )
232  scaleM = mScaleMProperty.valueAsDouble( context.expressionContext(), scaleM );
233 
234  double rotationZ = mRotationZ;
235  if ( mDynamicRotationZ )
236  rotationZ = mRotationZProperty.valueAsDouble( context.expressionContext(), rotationZ );
237 
238  QTransform transform;
239  transform.translate( deltaX, deltaY );
240  transform.rotate( rotationZ );
241  transform.scale( scaleX, scaleY );
242 
243  geometry.transform( transform, deltaZ, scaleZ, deltaM, scaleM );
244  f.setGeometry( geometry );
245  }
246  return QgsFeatureList() << f;
247 }
248 
249 QgsWkbTypes::Type QgsAffineTransformationAlgorithm::outputWkbType( QgsWkbTypes::Type inputWkbType ) const
250 {
251  QgsWkbTypes::Type wkb = inputWkbType;
252  if ( mDeltaZ != 0.0 )
253  wkb = QgsWkbTypes::addZ( wkb );
254  if ( mDeltaM != 0.0 )
255  wkb = QgsWkbTypes::addM( wkb );
256  return wkb;
257 }
258 
259 
260 bool QgsAffineTransformationAlgorithm::supportInPlaceEdit( const QgsMapLayer *l ) const
261 {
262  const QgsVectorLayer *layer = qobject_cast< const QgsVectorLayer * >( l );
263  if ( !layer )
264  return false;
265 
267  return false;
268 
269  // If the type differs there is no sense in executing the algorithm and drop the result
270  QgsWkbTypes::Type inPlaceWkbType = layer->wkbType();
271  return inPlaceWkbType == outputWkbType( inPlaceWkbType );
272 }
274 
275 
Base class for all map layer types.
Definition: qgsmaplayer.h:84
Base class for providing feedback from a processing algorithm.
OperationResult transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection direction=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
Q_INVOKABLE QgsWkbTypes::Type wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:614
virtual bool addMValue(double mValue=0)=0
Adds a measure to the geometry, initialized to a preset value.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:123
static Type addZ(Type type) SIP_HOLDGIL
Adds the z dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1146
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:204
static Type addM(Type type) SIP_HOLDGIL
Adds the m dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1171
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:69
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
A store for object properties.
Definition: qgsproperty.h:231
Double value (including negative values)
Definition: qgsproperty.h:58
QgsExpressionContext & expressionContext()
Returns the expression context.
Definition for a property.
Definition: qgsproperty.h:47
QgsAbstractGeometry * get()
Returns a modifiable (non-const) reference to the underlying abstract geometry primitive.
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.
bool isMeasure() const SIP_HOLDGIL
Returns true if the geometry contains m values.
bool is3D() const SIP_HOLDGIL
Returns true if the geometry is 3D and contains a z-value.
virtual bool addZValue(double zValue=0)=0
Adds a z-dimension to the geometry, initialized to a preset value.
void setGeometry(const QgsGeometry &geometry)
Set the feature&#39;s geometry.
Definition: qgsfeature.cpp:144
bool supportInPlaceEdit(const QgsMapLayer *layer) const override
Checks whether this algorithm supports in-place editing on the given layer Default implementation for...
QgsGeometry geometry
Definition: qgsfeature.h:67
Represents a vector layer which manages a vector based data sets.
Contains information about the context in which a processing algorithm is executed.
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...