1 /***************************************************************************
2                          qgsalgorithmsnaptogrid.cpp
3                          --------------------------
4     begin                : October 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 "qgsalgorithmsnaptogrid.h"
19 
20 ///@cond PRIVATE
21 
name() const22 QString QgsSnapToGridAlgorithm::name() const
23 {
24   return QStringLiteral( "snappointstogrid" );
25 }
26 
displayName() const27 QString QgsSnapToGridAlgorithm::displayName() const
28 {
29   return QObject::tr( "Snap points to grid" );
30 }
31 
tags() const32 QStringList QgsSnapToGridAlgorithm::tags() const
33 {
34   return QObject::tr( "snapped,grid,simplify,round,precision" ).split( ',' );
35 }
36 
group() const37 QString QgsSnapToGridAlgorithm::group() const
38 {
39   return QObject::tr( "Vector geometry" );
40 }
41 
groupId() const42 QString QgsSnapToGridAlgorithm::groupId() const
43 {
44   return QStringLiteral( "vectorgeometry" );
45 }
46 
outputName() const47 QString QgsSnapToGridAlgorithm::outputName() const
48 {
49   return QObject::tr( "Snapped" );
50 }
51 
shortHelpString() const52 QString QgsSnapToGridAlgorithm::shortHelpString() const
53 {
54   return QObject::tr( "This algorithm modifies the coordinates of geometries in a vector layer, so that all points "
55                       "or vertices are snapped to the closest point of the grid.\n\n"
56                       "If the snapped geometry cannot be calculated (or is totally collapsed) the feature's "
57                       "geometry will be cleared.\n\n"
58                       "Note that snapping to grid may generate an invalid geometry in some corner cases.\n\n"
59                       "Snapping can be performed on the X, Y, Z or M axis. A grid spacing of 0 for any axis will "
60                       "disable snapping for that axis." );
61 }
62 
createInstance() const63 QgsSnapToGridAlgorithm *QgsSnapToGridAlgorithm::createInstance() const
64 {
65   return new QgsSnapToGridAlgorithm();
66 }
67 
initParameters(const QVariantMap &)68 void QgsSnapToGridAlgorithm::initParameters( const QVariantMap & )
69 {
70   std::unique_ptr< QgsProcessingParameterDistance> hSpacing = qgis::make_unique< QgsProcessingParameterDistance >( QStringLiteral( "HSPACING" ),
71       QObject::tr( "X Grid Spacing" ), 1, QStringLiteral( "INPUT" ), false, 0 );
72   hSpacing->setIsDynamic( true );
73   hSpacing->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "HSPACING" ), QObject::tr( "X Grid Spacing" ), QgsPropertyDefinition::DoublePositive ) );
74   hSpacing->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
75   addParameter( hSpacing.release() );
76 
77   std::unique_ptr< QgsProcessingParameterDistance> vSpacing = qgis::make_unique< QgsProcessingParameterDistance >( QStringLiteral( "VSPACING" ),
78       QObject::tr( "Y Grid Spacing" ), 1, QStringLiteral( "INPUT" ), false, 0 );
79   vSpacing->setIsDynamic( true );
80   vSpacing->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "VSPACING" ), QObject::tr( "Y Grid Spacing" ), QgsPropertyDefinition::DoublePositive ) );
81   vSpacing->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
82   addParameter( vSpacing.release() );
83 
84   std::unique_ptr< QgsProcessingParameterNumber > zSpacing = qgis::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "ZSPACING" ),
85       QObject::tr( "Z Grid Spacing" ), QgsProcessingParameterNumber::Double,
86       0, false, 0 );
87   zSpacing->setIsDynamic( true );
88   zSpacing->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "ZSPACING" ), QObject::tr( "Z Grid Spacing" ), QgsPropertyDefinition::DoublePositive ) );
89   zSpacing->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
90   addParameter( zSpacing.release() );
91 
92   std::unique_ptr< QgsProcessingParameterNumber > mSpacing = qgis::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "MSPACING" ),
93       QObject::tr( "M Grid Spacing" ), QgsProcessingParameterNumber::Double,
94       0, false, 0 );
95   mSpacing->setIsDynamic( true );
96   mSpacing->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "MSPACING" ), QObject::tr( "M Grid Spacing" ), QgsPropertyDefinition::DoublePositive ) );
97   mSpacing->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
98   addParameter( mSpacing.release() );
99 }
100 
prepareAlgorithm(const QVariantMap & parameters,QgsProcessingContext & context,QgsProcessingFeedback *)101 bool QgsSnapToGridAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
102 {
103   mIntervalX = parameterAsDouble( parameters, QStringLiteral( "HSPACING" ), context );
104   mDynamicIntervalX = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "HSPACING" ) );
105   if ( mDynamicIntervalX )
106     mIntervalXProperty = parameters.value( QStringLiteral( "HSPACING" ) ).value< QgsProperty >();
107 
108   mIntervalY = parameterAsDouble( parameters, QStringLiteral( "VSPACING" ), context );
109   mDynamicIntervalY = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "VSPACING" ) );
110   if ( mDynamicIntervalY )
111     mIntervalYProperty = parameters.value( QStringLiteral( "VSPACING" ) ).value< QgsProperty >();
112 
113   mIntervalZ = parameterAsDouble( parameters, QStringLiteral( "ZSPACING" ), context );
114   mDynamicIntervalZ = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "ZSPACING" ) );
115   if ( mDynamicIntervalZ )
116     mIntervalZProperty = parameters.value( QStringLiteral( "ZSPACING" ) ).value< QgsProperty >();
117 
118   mIntervalM = parameterAsDouble( parameters, QStringLiteral( "MSPACING" ), context );
119   mDynamicIntervalM = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "MSPACING" ) );
120   if ( mDynamicIntervalM )
121     mIntervalMProperty = parameters.value( QStringLiteral( "MSPACING" ) ).value< QgsProperty >();
122 
123   return true;
124 }
125 
processFeature(const QgsFeature & feature,QgsProcessingContext & context,QgsProcessingFeedback * feedback)126 QgsFeatureList QgsSnapToGridAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
127 {
128   QgsFeature f = feature;
129   if ( f.hasGeometry() )
130   {
131     double intervalX = mIntervalX;
132     if ( mDynamicIntervalX )
133       intervalX = mIntervalXProperty.valueAsDouble( context.expressionContext(), intervalX );
134 
135     double intervalY = mIntervalY;
136     if ( mDynamicIntervalY )
137       intervalY = mIntervalYProperty.valueAsDouble( context.expressionContext(), intervalY );
138 
139     double intervalZ = mIntervalZ;
140     if ( mDynamicIntervalZ )
141       intervalZ = mIntervalZProperty.valueAsDouble( context.expressionContext(), intervalZ );
142 
143     double intervalM = mIntervalM;
144     if ( mDynamicIntervalM )
145       intervalM = mIntervalMProperty.valueAsDouble( context.expressionContext(), intervalM );
146 
147     QgsGeometry outputGeometry = f.geometry().snappedToGrid( intervalX, intervalY, intervalZ, intervalM );
148     if ( outputGeometry.isNull() )
149     {
150       feedback->reportError( QObject::tr( "Error snapping geometry %1" ).arg( feature.id() ) );
151     }
152     f.setGeometry( outputGeometry );
153   }
154   return QgsFeatureList() << f;
155 }
156 
sourceFlags() const157 QgsProcessingFeatureSource::Flag QgsSnapToGridAlgorithm::sourceFlags() const
158 {
159   return QgsProcessingFeatureSource::FlagSkipGeometryValidityChecks;
160 }
161 
162 ///@endcond
163 
164 
165