QGIS API Documentation  3.23.0-Master (7c4a6de034)
qgsalgorithmrectanglesovalsdiamonds.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsalgorithmrectanglesovalsdiamonds.cpp
3  ---------------------
4  begin : January 2020
5  copyright : (C) 2020 by Alexander Bruy
6  email : alexander dot bruy 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 "qgsapplication.h"
20 #include "qgslinestring.h"
21 #include "qgspolygon.h"
22 
24 
25 QString QgsRectanglesOvalsDiamondsAlgorithm::name() const
26 {
27  return QStringLiteral( "rectanglesovalsdiamonds" );
28 }
29 
30 QString QgsRectanglesOvalsDiamondsAlgorithm::displayName() const
31 {
32  return QObject::tr( "Rectangles, ovals, diamonds" );
33 }
34 
35 QStringList QgsRectanglesOvalsDiamondsAlgorithm::tags() const
36 {
37  return QObject::tr( "buffer,grow,fixed,variable,distance,rectangle,oval,diamond,point" ).split( ',' );
38 }
39 
40 QString QgsRectanglesOvalsDiamondsAlgorithm::group() const
41 {
42  return QObject::tr( "Vector geometry" );
43 }
44 
45 QString QgsRectanglesOvalsDiamondsAlgorithm::groupId() const
46 {
47  return QStringLiteral( "vectorgeometry" );
48 }
49 
50 QString QgsRectanglesOvalsDiamondsAlgorithm::shortHelpString() const
51 {
52  return QObject::tr( "Creates rectangle, oval or diamond-shaped polygons from the input point layer using "
53  "specified width, height and (optional) rotation values. Multipart inputs should be promoted "
54  "to singleparts first." );
55 }
56 
57 QString QgsRectanglesOvalsDiamondsAlgorithm::outputName() const
58 {
59  return QObject::tr( "Polygon" );
60 }
61 
62 QList<int> QgsRectanglesOvalsDiamondsAlgorithm::inputLayerTypes() const
63 {
64  return QList<int>() << QgsProcessing::TypeVectorPoint;
65 }
66 
67 QgsProcessing::SourceType QgsRectanglesOvalsDiamondsAlgorithm::outputLayerType() const
68 {
70 }
71 
72 QgsWkbTypes::Type QgsRectanglesOvalsDiamondsAlgorithm::outputWkbType( QgsWkbTypes::Type inputWkbType ) const
73 {
75  if ( QgsWkbTypes::hasM( inputWkbType ) )
76  {
77  outputWkbType = QgsWkbTypes::addM( outputWkbType );
78  }
79  if ( QgsWkbTypes::hasZ( inputWkbType ) )
80  {
81  outputWkbType = QgsWkbTypes::addZ( outputWkbType );
82  }
83 
84  return outputWkbType;
85 }
86 
87 QgsRectanglesOvalsDiamondsAlgorithm *QgsRectanglesOvalsDiamondsAlgorithm::createInstance() const
88 {
89  return new QgsRectanglesOvalsDiamondsAlgorithm();
90 }
91 
92 void QgsRectanglesOvalsDiamondsAlgorithm::initParameters( const QVariantMap & )
93 {
94  addParameter( new QgsProcessingParameterEnum( QStringLiteral( "SHAPE" ), QObject::tr( "Shape" ), QStringList() << QObject::tr( "Rectangle" ) << QObject::tr( "Diamond" ) << QObject::tr( "Oval" ), false, 0 ) );
95 
96  auto widthParam = std::make_unique < QgsProcessingParameterDistance >( QStringLiteral( "WIDTH" ), QObject::tr( "Width" ), 1.0, QStringLiteral( "INPUT" ), false, 0.0 );
97  widthParam->setIsDynamic( true );
98  widthParam->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "Width" ), QObject::tr( "Width" ), QgsPropertyDefinition::DoublePositive ) );
99  widthParam->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
100  addParameter( widthParam.release() );
101 
102  auto heightParam = std::make_unique < QgsProcessingParameterDistance >( QStringLiteral( "HEIGHT" ), QObject::tr( "Height" ), 1.0, QStringLiteral( "INPUT" ), false, 0.0 );
103  heightParam->setIsDynamic( true );
104  heightParam->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "Height" ), QObject::tr( "Height" ), QgsPropertyDefinition::DoublePositive ) );
105  heightParam->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
106  addParameter( heightParam.release() );
107 
108  auto rotationParam = std::make_unique < QgsProcessingParameterNumber >( QStringLiteral( "ROTATION" ), QObject::tr( "Rotation" ), QgsProcessingParameterNumber::Double, 0.0, true, -360.0, 360.0 );
109  rotationParam->setIsDynamic( true );
110  rotationParam->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "Rotation" ), QObject::tr( "Rotation" ), QgsPropertyDefinition::Double ) );
111  rotationParam->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
112  addParameter( rotationParam.release() );
113 
114  addParameter( new QgsProcessingParameterNumber( QStringLiteral( "SEGMENTS" ), QObject::tr( "Segments" ), QgsProcessingParameterNumber::Integer, 5, false, 1 ) );
115 }
116 
117 bool QgsRectanglesOvalsDiamondsAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
118 {
119  mShape = parameterAsEnum( parameters, QStringLiteral( "SHAPE" ), context );
120 
121  mWidth = parameterAsDouble( parameters, QStringLiteral( "WIDTH" ), context );
122  mDynamicWidth = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "WIDTH" ) );
123  if ( mDynamicWidth )
124  mWidthProperty = parameters.value( QStringLiteral( "WIDTH" ) ).value< QgsProperty >();
125 
126  mHeight = parameterAsDouble( parameters, QStringLiteral( "HEIGHT" ), context );
127  mDynamicHeight = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "HEIGHT" ) );
128  if ( mDynamicHeight )
129  mHeightProperty = parameters.value( QStringLiteral( "HEIGHT" ) ).value< QgsProperty >();
130 
131  mRotation = parameterAsDouble( parameters, QStringLiteral( "ROTATION" ), context );
132  mDynamicRotation = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "ROTATION" ) );
133  if ( mDynamicRotation )
134  mRotationProperty = parameters.value( QStringLiteral( "ROTATION" ) ).value< QgsProperty >();
135 
136  mSegments = parameterAsDouble( parameters, QStringLiteral( "SEGMENTS" ), context );
137 
138  return true;
139 }
140 
141 QgsFeatureList QgsRectanglesOvalsDiamondsAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback * )
142 {
143  QgsFeature outFeature = feature;
144  if ( outFeature.hasGeometry() )
145  {
146  const QgsGeometry geometry = outFeature.geometry();
147  if ( geometry.isMultipart() )
148  {
149  throw QgsProcessingException( QObject::tr( "Multipart geometry. Please promote input layer to singleparts first." ) );
150  }
151 
152  double width = mWidth;
153  if ( mDynamicWidth )
154  width = mWidthProperty.valueAsDouble( context.expressionContext(), width );
155 
156  double height = mHeight;
157  if ( mDynamicHeight )
158  height = mHeightProperty.valueAsDouble( context.expressionContext(), height );
159 
160  double rotation = mRotation;
161  if ( mDynamicRotation )
162  rotation = mRotationProperty.valueAsDouble( context.expressionContext(), rotation );
163 
164  if ( width == 0 || height == 0 )
165  {
166  throw QgsProcessingException( QObject::tr( "Width and height should be greater than 0." ) );
167  }
168 
169  const double phi = rotation * M_PI / 180;
170  const double xOffset = width / 2.0;
171  const double yOffset = height / 2.0;
172  const QgsPointXY point = geometry.asPoint();
173  const double x = point.x();
174  const double y = point.y();
175 
176  QVector< double > ringX( 5 );
177  QVector< double > ringY( 5 );
178 
179  switch ( mShape )
180  {
181  case 0:
182  // rectangle
183  ringX = { -xOffset + x, -xOffset + x, xOffset + x, xOffset + x, -xOffset + x };
184  ringY = { -yOffset + y, yOffset + y, yOffset + y, -yOffset + y, -yOffset + y };
185  break;
186  case 1:
187  // diamond
188  ringX = { x, -xOffset + x, x, xOffset + x, x };
189  ringY = { -yOffset + y, y, yOffset + y, y, -yOffset + y };
190  break;
191  case 2:
192  // oval
193  ringX.resize( mSegments + 1 );
194  ringY.resize( mSegments + 1 );
195  for ( int i = 0; i < mSegments; i ++ )
196  {
197  const double t = ( 2 * M_PI ) / mSegments * i;
198  ringX[ i ] = xOffset * cos( t ) + x;
199  ringY[ i ] = yOffset * sin( t ) + y;
200  }
201  ringX[ mSegments ] = ringX.at( 0 );
202  ringY[ mSegments ] = ringY.at( 0 );
203  break;
204  }
205 
206  if ( phi != 0 )
207  {
208  for ( int i = 0; i < ringX.size(); ++i )
209  {
210  const double px = ringX.at( i );
211  const double py = ringY.at( i );
212  ringX[ i ] = ( px - x ) * cos( phi ) + ( py - y ) * sin( phi ) + x;
213  ringY[ i ] = -( px - x ) * sin( phi ) + ( py - y ) * cos( phi ) + y;
214  }
215  }
216 
217  std::unique_ptr< QgsPolygon > poly = std::make_unique< QgsPolygon >();
218  poly->setExteriorRing( new QgsLineString( ringX, ringY ) );
219 
220  if ( geometry.constGet()->is3D() )
221  {
222  poly->addZValue( static_cast< const QgsPoint * >( geometry.constGet() )->z() );
223  }
224  if ( geometry.constGet()->isMeasure() )
225  {
226  poly->addMValue( static_cast< const QgsPoint * >( geometry.constGet() )->m() );
227  }
228 
229  outFeature.setGeometry( std::move( poly ) );
230  }
231 
232  return QgsFeatureList() << outFeature;
233 }
234 
bool is3D() const SIP_HOLDGIL
Returns true if the geometry is 3D and contains a z-value.
bool isMeasure() const SIP_HOLDGIL
Returns true if the geometry contains m values.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QgsGeometry geometry
Definition: qgsfeature.h:67
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:223
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:163
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:125
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
bool isMultipart() const SIP_HOLDGIL
Returns true if WKB of the geometry is of WKBMulti* type.
QgsPointXY asPoint() const
Returns the contents of the geometry as a 2-dimensional point.
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:44
A class to represent a 2D point.
Definition: qgspointxy.h:59
double y
Definition: qgspointxy.h:63
Q_GADGET double x
Definition: qgspointxy.h:62
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:49
double z
Definition: qgspoint.h:54
double m
Definition: qgspoint.h:55
Contains information about the context in which a processing algorithm is executed.
QgsExpressionContext & expressionContext()
Returns the expression context.
Custom exception class for processing related exceptions.
Definition: qgsexception.h:83
Base class for providing feedback from a processing algorithm.
An enum based parameter for processing algorithms, allowing for selection from predefined values.
A numeric 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...
SourceType
Data source types enum.
Definition: qgsprocessing.h:46
@ TypeVectorPolygon
Vector polygon layers.
Definition: qgsprocessing.h:51
@ TypeVectorPoint
Vector point layers.
Definition: qgsprocessing.h:49
Definition for a property.
Definition: qgsproperty.h:47
@ Double
Double value (including negative values)
Definition: qgsproperty.h:57
@ DoublePositive
Positive double value (including 0)
Definition: qgsproperty.h:58
A store for object properties.
Definition: qgsproperty.h:231
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.
static bool hasM(Type type) SIP_HOLDGIL
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:1130
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:70
static Type addZ(Type type) SIP_HOLDGIL
Adds the z dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1176
static bool hasZ(Type type) SIP_HOLDGIL
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:1080
static Type addM(Type type) SIP_HOLDGIL
Adds the m dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1201
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:882