1 /***************************************************************************
2                          qgsalgorithmtranslate.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 "qgsalgorithmtranslate.h"
19 #include "qgsvectorlayer.h"
20 
21 ///@cond PRIVATE
22 
name() const23 QString QgsTranslateAlgorithm::name() const
24 {
25   return QStringLiteral( "translategeometry" );
26 }
27 
displayName() const28 QString QgsTranslateAlgorithm::displayName() const
29 {
30   return QObject::tr( "Translate" );
31 }
32 
tags() const33 QStringList QgsTranslateAlgorithm::tags() const
34 {
35   return QObject::tr( "move,shift,transform,z,m,values,add" ).split( ',' );
36 }
37 
group() const38 QString QgsTranslateAlgorithm::group() const
39 {
40   return QObject::tr( "Vector geometry" );
41 }
42 
groupId() const43 QString QgsTranslateAlgorithm::groupId() const
44 {
45   return QStringLiteral( "vectorgeometry" );
46 }
47 
outputName() const48 QString QgsTranslateAlgorithm::outputName() const
49 {
50   return QObject::tr( "Translated" );
51 }
52 
shortHelpString() const53 QString QgsTranslateAlgorithm::shortHelpString() const
54 {
55   return QObject::tr( "This algorithm moves the geometries within a layer, by offsetting them with a specified x and y displacement." )
56          + QStringLiteral( "\n\n" )
57          + QObject::tr( "Z and M values present in the geometry can also be translated." );
58 }
59 
createInstance() const60 QgsTranslateAlgorithm *QgsTranslateAlgorithm::createInstance() const
61 {
62   return new QgsTranslateAlgorithm();
63 }
64 
initParameters(const QVariantMap &)65 void QgsTranslateAlgorithm::initParameters( const QVariantMap & )
66 {
67   std::unique_ptr< QgsProcessingParameterDistance > xOffset = qgis::make_unique< QgsProcessingParameterDistance >( QStringLiteral( "DELTA_X" ),
68       QObject::tr( "Offset distance (x-axis)" ),
69       0.0, QStringLiteral( "INPUT" ) );
70   xOffset->setIsDynamic( true );
71   xOffset->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "DELTA_X" ), QObject::tr( "Offset distance (x-axis)" ), QgsPropertyDefinition::Double ) );
72   xOffset->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
73   addParameter( xOffset.release() );
74 
75   std::unique_ptr< QgsProcessingParameterDistance > yOffset = qgis::make_unique< QgsProcessingParameterDistance >( QStringLiteral( "DELTA_Y" ),
76       QObject::tr( "Offset distance (y-axis)" ),
77       0.0, QStringLiteral( "INPUT" ) );
78   yOffset->setIsDynamic( true );
79   yOffset->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "DELTA_Y" ), QObject::tr( "Offset distance (y-axis)" ), QgsPropertyDefinition::Double ) );
80   yOffset->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
81   addParameter( yOffset.release() );
82 
83   std::unique_ptr< QgsProcessingParameterNumber > zOffset = qgis::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "DELTA_Z" ),
84       QObject::tr( "Offset distance (z-axis)" ), QgsProcessingParameterNumber::Double,
85       0.0 );
86   zOffset->setIsDynamic( true );
87   zOffset->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "DELTA_Z" ), QObject::tr( "Offset distance (z-axis)" ), QgsPropertyDefinition::Double ) );
88   zOffset->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
89   addParameter( zOffset.release() );
90 
91   std::unique_ptr< QgsProcessingParameterNumber > mOffset = qgis::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "DELTA_M" ),
92       QObject::tr( "Offset distance (m values)" ), QgsProcessingParameterNumber::Double,
93       0.0 );
94   mOffset->setIsDynamic( true );
95   mOffset->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "DELTA_M" ), QObject::tr( "Offset distance (m values)" ), QgsPropertyDefinition::Double ) );
96   mOffset->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
97   addParameter( mOffset.release() );
98 }
99 
prepareAlgorithm(const QVariantMap & parameters,QgsProcessingContext & context,QgsProcessingFeedback *)100 bool QgsTranslateAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
101 {
102   mDeltaX = parameterAsDouble( parameters, QStringLiteral( "DELTA_X" ), context );
103   mDynamicDeltaX = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DELTA_X" ) );
104   if ( mDynamicDeltaX )
105     mDeltaXProperty = parameters.value( QStringLiteral( "DELTA_X" ) ).value< QgsProperty >();
106 
107   mDeltaY = parameterAsDouble( parameters, QStringLiteral( "DELTA_Y" ), context );
108   mDynamicDeltaY = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DELTA_Y" ) );
109   if ( mDynamicDeltaY )
110     mDeltaYProperty = parameters.value( QStringLiteral( "DELTA_Y" ) ).value< QgsProperty >();
111 
112   mDeltaZ = parameterAsDouble( parameters, QStringLiteral( "DELTA_Z" ), context );
113   mDynamicDeltaZ = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DELTA_Z" ) );
114   if ( mDynamicDeltaZ )
115     mDeltaZProperty = parameters.value( QStringLiteral( "DELTA_Z" ) ).value< QgsProperty >();
116 
117   mDeltaM = parameterAsDouble( parameters, QStringLiteral( "DELTA_M" ), context );
118   mDynamicDeltaM = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DELTA_M" ) );
119   if ( mDynamicDeltaM )
120     mDeltaMProperty = parameters.value( QStringLiteral( "DELTA_M" ) ).value< QgsProperty >();
121 
122   return true;
123 }
124 
processFeature(const QgsFeature & feature,QgsProcessingContext & context,QgsProcessingFeedback *)125 QgsFeatureList QgsTranslateAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback * )
126 {
127   QgsFeature f = feature;
128   if ( f.hasGeometry() )
129   {
130     QgsGeometry geometry = f.geometry();
131 
132     double deltaX = mDeltaX;
133     if ( mDynamicDeltaX )
134       deltaX = mDeltaXProperty.valueAsDouble( context.expressionContext(), deltaX );
135     double deltaY = mDeltaY;
136     if ( mDynamicDeltaY )
137       deltaY = mDeltaYProperty.valueAsDouble( context.expressionContext(), deltaY );
138     double deltaZ = mDeltaZ;
139     if ( mDynamicDeltaZ )
140       deltaZ = mDeltaZProperty.valueAsDouble( context.expressionContext(), deltaZ );
141     double deltaM = mDeltaM;
142     if ( mDynamicDeltaM )
143       deltaM = mDeltaMProperty.valueAsDouble( context.expressionContext(), deltaM );
144 
145     if ( deltaZ != 0.0 && !geometry.constGet()->is3D() )
146       geometry.get()->addZValue( 0 );
147     if ( deltaM != 0.0 && !geometry.constGet()->isMeasure() )
148       geometry.get()->addMValue( 0 );
149 
150     geometry.translate( deltaX, deltaY, deltaZ, deltaM );
151     f.setGeometry( geometry );
152   }
153   return QgsFeatureList() << f;
154 }
155 
outputWkbType(QgsWkbTypes::Type inputWkbType) const156 QgsWkbTypes::Type QgsTranslateAlgorithm::outputWkbType( QgsWkbTypes::Type inputWkbType ) const
157 {
158   QgsWkbTypes::Type wkb = inputWkbType;
159   if ( mDeltaZ != 0.0 )
160     wkb = QgsWkbTypes::addZ( wkb );
161   if ( mDeltaM != 0.0 )
162     wkb = QgsWkbTypes::addM( wkb );
163   return wkb;
164 }
165 
166 
supportInPlaceEdit(const QgsMapLayer * l) const167 bool QgsTranslateAlgorithm::supportInPlaceEdit( const QgsMapLayer *l ) const
168 {
169   const QgsVectorLayer *layer = qobject_cast< const QgsVectorLayer * >( l );
170   if ( !layer )
171     return false;
172 
173   if ( ! QgsProcessingFeatureBasedAlgorithm::supportInPlaceEdit( layer ) )
174     return false;
175 
176   // Check if we can drop Z/M and still have some work done
177   if ( mDeltaX != 0.0 || mDeltaY != 0.0 )
178     return true;
179 
180   // If the type differs there is no sense in executing the algorithm and drop the result
181   QgsWkbTypes::Type inPlaceWkbType = layer->wkbType();
182   return inPlaceWkbType == outputWkbType( inPlaceWkbType );
183 }
184 ///@endcond
185 
186 
187