Branch data Line data Source code
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 : :
18 : : #include "qgsalgorithmaffinetransform.h"
19 : : #include "qgsvectorlayer.h"
20 : :
21 : : ///@cond PRIVATE
22 : :
23 : 0 : QString QgsAffineTransformationAlgorithm::name() const
24 : : {
25 : 0 : return QStringLiteral( "affinetransform" );
26 : : }
27 : :
28 : 0 : QString QgsAffineTransformationAlgorithm::displayName() const
29 : : {
30 : 0 : return QObject::tr( "Affine transform" );
31 : : }
32 : :
33 : 0 : QStringList QgsAffineTransformationAlgorithm::tags() const
34 : : {
35 : 0 : return QObject::tr( "move,shift,transform,affine,scale,rotate,resize,matrix" ).split( ',' );
36 : 0 : }
37 : :
38 : 0 : QString QgsAffineTransformationAlgorithm::group() const
39 : : {
40 : 0 : return QObject::tr( "Vector geometry" );
41 : : }
42 : :
43 : 0 : QString QgsAffineTransformationAlgorithm::groupId() const
44 : : {
45 : 0 : return QStringLiteral( "vectorgeometry" );
46 : : }
47 : :
48 : 0 : QString QgsAffineTransformationAlgorithm::outputName() const
49 : : {
50 : 0 : return QObject::tr( "Transformed" );
51 : : }
52 : :
53 : 0 : QString QgsAffineTransformationAlgorithm::shortHelpString() const
54 : : {
55 : 0 : 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 : 0 : + QStringLiteral( "\n\n" )
58 : 0 : + QObject::tr( "Z and M values present in the geometry can also be translated and scaled independently." );
59 : 0 : }
60 : :
61 : 0 : QString QgsAffineTransformationAlgorithm::shortDescription() const
62 : : {
63 : 0 : return QObject::tr( "Applies an affine transformation to geometries." );
64 : : }
65 : :
66 : 0 : QgsAffineTransformationAlgorithm *QgsAffineTransformationAlgorithm::createInstance() const
67 : : {
68 : 0 : return new QgsAffineTransformationAlgorithm();
69 : 0 : }
70 : :
71 : 0 : void QgsAffineTransformationAlgorithm::initParameters( const QVariantMap & )
72 : : {
73 : 0 : std::unique_ptr< QgsProcessingParameterDistance > xOffset = std::make_unique< QgsProcessingParameterDistance >( QStringLiteral( "DELTA_X" ),
74 : 0 : QObject::tr( "Translation (x-axis)" ),
75 : 0 : 0.0, QStringLiteral( "INPUT" ) );
76 : 0 : xOffset->setIsDynamic( true );
77 : 0 : xOffset->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "DELTA_X" ), QObject::tr( "Offset distance (x-axis)" ), QgsPropertyDefinition::Double ) );
78 : 0 : xOffset->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
79 : 0 : addParameter( xOffset.release() );
80 : :
81 : 0 : std::unique_ptr< QgsProcessingParameterDistance > yOffset = std::make_unique< QgsProcessingParameterDistance >( QStringLiteral( "DELTA_Y" ),
82 : 0 : QObject::tr( "Translation (y-axis)" ),
83 : 0 : 0.0, QStringLiteral( "INPUT" ) );
84 : 0 : yOffset->setIsDynamic( true );
85 : 0 : yOffset->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "DELTA_Y" ), QObject::tr( "Offset distance (y-axis)" ), QgsPropertyDefinition::Double ) );
86 : 0 : yOffset->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
87 : 0 : addParameter( yOffset.release() );
88 : :
89 : 0 : std::unique_ptr< QgsProcessingParameterNumber > zOffset = std::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "DELTA_Z" ),
90 : 0 : QObject::tr( "Translation (z-axis)" ), QgsProcessingParameterNumber::Double,
91 : 0 : 0.0 );
92 : 0 : zOffset->setIsDynamic( true );
93 : 0 : zOffset->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "DELTA_Z" ), QObject::tr( "Offset distance (z-axis)" ), QgsPropertyDefinition::Double ) );
94 : 0 : zOffset->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
95 : 0 : addParameter( zOffset.release() );
96 : :
97 : 0 : std::unique_ptr< QgsProcessingParameterNumber > mOffset = std::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "DELTA_M" ),
98 : 0 : QObject::tr( "Translation (m values)" ), QgsProcessingParameterNumber::Double,
99 : 0 : 0.0 );
100 : 0 : mOffset->setIsDynamic( true );
101 : 0 : mOffset->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "DELTA_M" ), QObject::tr( "Offset distance (m values)" ), QgsPropertyDefinition::Double ) );
102 : 0 : mOffset->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
103 : 0 : addParameter( mOffset.release() );
104 : :
105 : 0 : std::unique_ptr< QgsProcessingParameterNumber > xScale = std::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "SCALE_X" ),
106 : 0 : QObject::tr( "Scale factor (x-axis)" ), QgsProcessingParameterNumber::Double,
107 : 0 : 1.0 );
108 : 0 : xScale->setIsDynamic( true );
109 : 0 : xScale->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "SCALE_X" ), QObject::tr( "Scale factor (x-axis)" ), QgsPropertyDefinition::Double ) );
110 : 0 : xScale->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
111 : 0 : addParameter( xScale.release() );
112 : :
113 : 0 : std::unique_ptr< QgsProcessingParameterNumber > yScale = std::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "SCALE_Y" ),
114 : 0 : QObject::tr( "Scale factor (y-axis)" ), QgsProcessingParameterNumber::Double,
115 : 0 : 1.0 );
116 : 0 : yScale->setIsDynamic( true );
117 : 0 : yScale->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "SCALE_Y" ), QObject::tr( "Scale factor (y-axis)" ), QgsPropertyDefinition::Double ) );
118 : 0 : yScale->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
119 : 0 : addParameter( yScale.release() );
120 : :
121 : 0 : std::unique_ptr< QgsProcessingParameterNumber > zScale = std::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "SCALE_Z" ),
122 : 0 : QObject::tr( "Scale factor (z-axis)" ), QgsProcessingParameterNumber::Double,
123 : 0 : 1.0 );
124 : 0 : zScale->setIsDynamic( true );
125 : 0 : zScale->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "SCALE_Z" ), QObject::tr( "Scale factor (z-axis)" ), QgsPropertyDefinition::Double ) );
126 : 0 : zScale->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
127 : 0 : addParameter( zScale.release() );
128 : :
129 : 0 : std::unique_ptr< QgsProcessingParameterNumber > mScale = std::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "SCALE_M" ),
130 : 0 : QObject::tr( "Scale factor (m values)" ), QgsProcessingParameterNumber::Double,
131 : 0 : 1.0 );
132 : 0 : mScale->setIsDynamic( true );
133 : 0 : mScale->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "SCALE_M" ), QObject::tr( "Scale factor (m values)" ), QgsPropertyDefinition::Double ) );
134 : 0 : mScale->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
135 : 0 : addParameter( mScale.release() );
136 : :
137 : 0 : std::unique_ptr< QgsProcessingParameterNumber > rotation = std::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "ROTATION_Z" ),
138 : 0 : QObject::tr( "Rotation around z-axis (degrees counter-clockwise)" ), QgsProcessingParameterNumber::Double,
139 : 0 : 0.0 );
140 : 0 : rotation->setIsDynamic( true );
141 : 0 : rotation->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "ROTATION_Z" ), QObject::tr( "Rotation around z-axis (degrees counter-clockwise)" ), QgsPropertyDefinition::Double ) );
142 : 0 : rotation->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
143 : 0 : addParameter( rotation.release() );
144 : 0 : }
145 : :
146 : 0 : bool QgsAffineTransformationAlgorithm::prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback * )
147 : : {
148 : 0 : mDeltaX = parameterAsDouble( parameters, QStringLiteral( "DELTA_X" ), context );
149 : 0 : mDynamicDeltaX = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DELTA_X" ) );
150 : 0 : if ( mDynamicDeltaX )
151 : 0 : mDeltaXProperty = parameters.value( QStringLiteral( "DELTA_X" ) ).value< QgsProperty >();
152 : :
153 : 0 : mDeltaY = parameterAsDouble( parameters, QStringLiteral( "DELTA_Y" ), context );
154 : 0 : mDynamicDeltaY = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DELTA_Y" ) );
155 : 0 : if ( mDynamicDeltaY )
156 : 0 : mDeltaYProperty = parameters.value( QStringLiteral( "DELTA_Y" ) ).value< QgsProperty >();
157 : :
158 : 0 : mDeltaZ = parameterAsDouble( parameters, QStringLiteral( "DELTA_Z" ), context );
159 : 0 : mDynamicDeltaZ = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DELTA_Z" ) );
160 : 0 : if ( mDynamicDeltaZ )
161 : 0 : mDeltaZProperty = parameters.value( QStringLiteral( "DELTA_Z" ) ).value< QgsProperty >();
162 : :
163 : 0 : mDeltaM = parameterAsDouble( parameters, QStringLiteral( "DELTA_M" ), context );
164 : 0 : mDynamicDeltaM = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DELTA_M" ) );
165 : 0 : if ( mDynamicDeltaM )
166 : 0 : mDeltaMProperty = parameters.value( QStringLiteral( "DELTA_M" ) ).value< QgsProperty >();
167 : :
168 : 0 : mScaleX = parameterAsDouble( parameters, QStringLiteral( "SCALE_X" ), context );
169 : 0 : mDynamicScaleX = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "SCALE_X" ) );
170 : 0 : if ( mDynamicScaleX )
171 : 0 : mScaleXProperty = parameters.value( QStringLiteral( "SCALE_X" ) ).value< QgsProperty >();
172 : :
173 : 0 : mScaleY = parameterAsDouble( parameters, QStringLiteral( "SCALE_Y" ), context );
174 : 0 : mDynamicScaleY = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "SCALE_Y" ) );
175 : 0 : if ( mDynamicScaleY )
176 : 0 : mScaleYProperty = parameters.value( QStringLiteral( "SCALE_Y" ) ).value< QgsProperty >();
177 : :
178 : 0 : mScaleZ = parameterAsDouble( parameters, QStringLiteral( "SCALE_Z" ), context );
179 : 0 : mDynamicScaleZ = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "SCALE_Z" ) );
180 : 0 : if ( mDynamicScaleZ )
181 : 0 : mScaleZProperty = parameters.value( QStringLiteral( "SCALE_Z" ) ).value< QgsProperty >();
182 : :
183 : 0 : mScaleM = parameterAsDouble( parameters, QStringLiteral( "SCALE_M" ), context );
184 : 0 : mDynamicScaleM = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "SCALE_M" ) );
185 : 0 : if ( mDynamicScaleM )
186 : 0 : mScaleMProperty = parameters.value( QStringLiteral( "SCALE_M" ) ).value< QgsProperty >();
187 : :
188 : 0 : mRotationZ = parameterAsDouble( parameters, QStringLiteral( "ROTATION_Z" ), context );
189 : 0 : mDynamicRotationZ = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "ROTATION_Z" ) );
190 : 0 : if ( mDynamicRotationZ )
191 : 0 : mRotationZProperty = parameters.value( QStringLiteral( "ROTATION_Z" ) ).value< QgsProperty >();
192 : :
193 : 0 : return true;
194 : 0 : }
195 : :
196 : 0 : QgsFeatureList QgsAffineTransformationAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback * )
197 : : {
198 : 0 : QgsFeature f = feature;
199 : 0 : if ( f.hasGeometry() )
200 : : {
201 : 0 : QgsGeometry geometry = f.geometry();
202 : :
203 : 0 : double deltaX = mDeltaX;
204 : 0 : if ( mDynamicDeltaX )
205 : 0 : deltaX = mDeltaXProperty.valueAsDouble( context.expressionContext(), deltaX );
206 : 0 : double deltaY = mDeltaY;
207 : 0 : if ( mDynamicDeltaY )
208 : 0 : deltaY = mDeltaYProperty.valueAsDouble( context.expressionContext(), deltaY );
209 : 0 : double deltaZ = mDeltaZ;
210 : 0 : if ( mDynamicDeltaZ )
211 : 0 : deltaZ = mDeltaZProperty.valueAsDouble( context.expressionContext(), deltaZ );
212 : 0 : double deltaM = mDeltaM;
213 : 0 : if ( mDynamicDeltaM )
214 : 0 : deltaM = mDeltaMProperty.valueAsDouble( context.expressionContext(), deltaM );
215 : :
216 : 0 : if ( deltaZ != 0.0 && !geometry.constGet()->is3D() )
217 : 0 : geometry.get()->addZValue( 0 );
218 : 0 : if ( deltaM != 0.0 && !geometry.constGet()->isMeasure() )
219 : 0 : geometry.get()->addMValue( 0 );
220 : :
221 : 0 : double scaleX = mScaleX;
222 : 0 : if ( mDynamicScaleX )
223 : 0 : scaleX = mScaleXProperty.valueAsDouble( context.expressionContext(), scaleX );
224 : 0 : double scaleY = mScaleY;
225 : 0 : if ( mDynamicScaleY )
226 : 0 : scaleY = mScaleYProperty.valueAsDouble( context.expressionContext(), scaleY );
227 : 0 : double scaleZ = mScaleZ;
228 : 0 : if ( mDynamicScaleZ )
229 : 0 : scaleZ = mScaleZProperty.valueAsDouble( context.expressionContext(), scaleZ );
230 : 0 : double scaleM = mScaleM;
231 : 0 : if ( mDynamicScaleM )
232 : 0 : scaleM = mScaleMProperty.valueAsDouble( context.expressionContext(), scaleM );
233 : :
234 : 0 : double rotationZ = mRotationZ;
235 : 0 : if ( mDynamicRotationZ )
236 : 0 : rotationZ = mRotationZProperty.valueAsDouble( context.expressionContext(), rotationZ );
237 : :
238 : 0 : QTransform transform;
239 : 0 : transform.translate( deltaX, deltaY );
240 : 0 : transform.rotate( rotationZ );
241 : 0 : transform.scale( scaleX, scaleY );
242 : :
243 : 0 : geometry.transform( transform, deltaZ, scaleZ, deltaM, scaleM );
244 : 0 : f.setGeometry( geometry );
245 : 0 : }
246 : 0 : return QgsFeatureList() << f;
247 : 0 : }
248 : :
249 : 0 : QgsWkbTypes::Type QgsAffineTransformationAlgorithm::outputWkbType( QgsWkbTypes::Type inputWkbType ) const
250 : : {
251 : 0 : QgsWkbTypes::Type wkb = inputWkbType;
252 : 0 : if ( mDeltaZ != 0.0 )
253 : 0 : wkb = QgsWkbTypes::addZ( wkb );
254 : 0 : if ( mDeltaM != 0.0 )
255 : 0 : wkb = QgsWkbTypes::addM( wkb );
256 : 0 : return wkb;
257 : : }
258 : :
259 : :
260 : 0 : bool QgsAffineTransformationAlgorithm::supportInPlaceEdit( const QgsMapLayer *l ) const
261 : : {
262 : 0 : const QgsVectorLayer *layer = qobject_cast< const QgsVectorLayer * >( l );
263 : 0 : if ( !layer )
264 : 0 : return false;
265 : :
266 : 0 : if ( ! QgsProcessingFeatureBasedAlgorithm::supportInPlaceEdit( layer ) )
267 : 0 : return false;
268 : :
269 : : // If the type differs there is no sense in executing the algorithm and drop the result
270 : 0 : QgsWkbTypes::Type inPlaceWkbType = layer->wkbType();
271 : 0 : return inPlaceWkbType == outputWkbType( inPlaceWkbType );
272 : 0 : }
273 : : ///@endcond
274 : :
275 : :
|