Branch data Line data Source code
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 : :
18 : : #include "qgsalgorithmrectanglesovalsdiamonds.h"
19 : : #include "qgsapplication.h"
20 : : #include "qgslinestring.h"
21 : : #include "qgspolygon.h"
22 : :
23 : : ///@cond PRIVATE
24 : :
25 : 0 : QString QgsRectanglesOvalsDiamondsAlgorithm::name() const
26 : : {
27 : 0 : return QStringLiteral( "rectanglesovalsdiamonds" );
28 : : }
29 : :
30 : 0 : QString QgsRectanglesOvalsDiamondsAlgorithm::displayName() const
31 : : {
32 : 0 : return QObject::tr( "Rectangles, ovals, diamonds" );
33 : : }
34 : :
35 : 0 : QStringList QgsRectanglesOvalsDiamondsAlgorithm::tags() const
36 : : {
37 : 0 : return QObject::tr( "buffer,grow,fixed,variable,distance,rectangle,oval,diamond,point" ).split( ',' );
38 : 0 : }
39 : :
40 : 0 : QString QgsRectanglesOvalsDiamondsAlgorithm::group() const
41 : : {
42 : 0 : return QObject::tr( "Vector geometry" );
43 : : }
44 : :
45 : 0 : QString QgsRectanglesOvalsDiamondsAlgorithm::groupId() const
46 : : {
47 : 0 : return QStringLiteral( "vectorgeometry" );
48 : : }
49 : :
50 : 0 : QString QgsRectanglesOvalsDiamondsAlgorithm::shortHelpString() const
51 : : {
52 : 0 : 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 : 0 : QString QgsRectanglesOvalsDiamondsAlgorithm::outputName() const
58 : : {
59 : 0 : return QObject::tr( "Polygon" );
60 : : }
61 : :
62 : 0 : QList<int> QgsRectanglesOvalsDiamondsAlgorithm::inputLayerTypes() const
63 : : {
64 : 0 : return QList<int>() << QgsProcessing::TypeVectorPoint;
65 : 0 : }
66 : :
67 : 0 : QgsProcessing::SourceType QgsRectanglesOvalsDiamondsAlgorithm::outputLayerType() const
68 : : {
69 : 0 : return QgsProcessing::TypeVectorPolygon;
70 : : }
71 : :
72 : 0 : QgsWkbTypes::Type QgsRectanglesOvalsDiamondsAlgorithm::outputWkbType( QgsWkbTypes::Type inputWkbType ) const
73 : : {
74 : 0 : QgsWkbTypes::Type outputWkbType = QgsWkbTypes::Polygon;
75 : 0 : if ( QgsWkbTypes::hasM( inputWkbType ) )
76 : : {
77 : 0 : outputWkbType = QgsWkbTypes::addM( outputWkbType );
78 : 0 : }
79 : 0 : if ( QgsWkbTypes::hasZ( inputWkbType ) )
80 : : {
81 : 0 : outputWkbType = QgsWkbTypes::addZ( outputWkbType );
82 : 0 : }
83 : :
84 : 0 : return outputWkbType;
85 : : }
86 : :
87 : 0 : QgsRectanglesOvalsDiamondsAlgorithm *QgsRectanglesOvalsDiamondsAlgorithm::createInstance() const
88 : : {
89 : 0 : return new QgsRectanglesOvalsDiamondsAlgorithm();
90 : 0 : }
91 : :
92 : 0 : void QgsRectanglesOvalsDiamondsAlgorithm::initParameters( const QVariantMap & )
93 : : {
94 : 0 : addParameter( new QgsProcessingParameterEnum( QStringLiteral( "SHAPE" ), QObject::tr( "Shape" ), QStringList() << QObject::tr( "Rectangle" ) << QObject::tr( "Diamond" ) << QObject::tr( "Oval" ), false, 0 ) );
95 : :
96 : 0 : auto widthParam = std::make_unique < QgsProcessingParameterDistance >( QStringLiteral( "WIDTH" ), QObject::tr( "Width" ), 1.0, QStringLiteral( "INPUT" ), false, 0.0 );
97 : 0 : widthParam->setIsDynamic( true );
98 : 0 : widthParam->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "Width" ), QObject::tr( "Width" ), QgsPropertyDefinition::DoublePositive ) );
99 : 0 : widthParam->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
100 : 0 : addParameter( widthParam.release() );
101 : :
102 : 0 : auto heightParam = std::make_unique < QgsProcessingParameterDistance >( QStringLiteral( "HEIGHT" ), QObject::tr( "Height" ), 1.0, QStringLiteral( "INPUT" ), false, 0.0 );
103 : 0 : heightParam->setIsDynamic( true );
104 : 0 : heightParam->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "Height" ), QObject::tr( "Height" ), QgsPropertyDefinition::DoublePositive ) );
105 : 0 : heightParam->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
106 : 0 : addParameter( heightParam.release() );
107 : :
108 : 0 : auto rotationParam = std::make_unique < QgsProcessingParameterNumber >( QStringLiteral( "ROTATION" ), QObject::tr( "Rotation" ), QgsProcessingParameterNumber::Double, 0.0, true, -360.0, 360.0 );
109 : 0 : rotationParam->setIsDynamic( true );
110 : 0 : rotationParam->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "Rotation" ), QObject::tr( "Rotation" ), QgsPropertyDefinition::Double ) );
111 : 0 : rotationParam->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
112 : 0 : addParameter( rotationParam.release() );
113 : :
114 : 0 : addParameter( new QgsProcessingParameterNumber( QStringLiteral( "SEGMENTS" ), QObject::tr( "Segments" ), QgsProcessingParameterNumber::Integer, 5, false, 1 ) );
115 : 0 : }
116 : :
117 : 0 : bool QgsRectanglesOvalsDiamondsAlgorithm::prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback * )
118 : : {
119 : 0 : mShape = parameterAsEnum( parameters, QStringLiteral( "SHAPE" ), context );
120 : :
121 : 0 : mWidth = parameterAsDouble( parameters, QStringLiteral( "WIDTH" ), context );
122 : 0 : mDynamicWidth = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "WIDTH" ) );
123 : 0 : if ( mDynamicWidth )
124 : 0 : mWidthProperty = parameters.value( QStringLiteral( "WIDTH" ) ).value< QgsProperty >();
125 : :
126 : 0 : mHeight = parameterAsDouble( parameters, QStringLiteral( "HEIGHT" ), context );
127 : 0 : mDynamicHeight = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "HEIGHT" ) );
128 : 0 : if ( mDynamicHeight )
129 : 0 : mHeightProperty = parameters.value( QStringLiteral( "HEIGHT" ) ).value< QgsProperty >();
130 : :
131 : 0 : mRotation = parameterAsDouble( parameters, QStringLiteral( "ROTATION" ), context );
132 : 0 : mDynamicRotation = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "ROTATION" ) );
133 : 0 : if ( mDynamicRotation )
134 : 0 : mRotationProperty = parameters.value( QStringLiteral( "ROTATION" ) ).value< QgsProperty >();
135 : :
136 : 0 : mSegments = parameterAsDouble( parameters, QStringLiteral( "SEGMENTS" ), context );
137 : :
138 : 0 : return true;
139 : 0 : }
140 : :
141 : 0 : QgsFeatureList QgsRectanglesOvalsDiamondsAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback * )
142 : : {
143 : 0 : QgsFeature outFeature = feature;
144 : 0 : if ( outFeature.hasGeometry() )
145 : : {
146 : 0 : QgsGeometry geometry = outFeature.geometry();
147 : 0 : if ( geometry.isMultipart() )
148 : : {
149 : 0 : throw QgsProcessingException( QObject::tr( "Multipart geometry. Please promote input layer to singleparts first." ) );
150 : : }
151 : :
152 : 0 : double width = mWidth;
153 : 0 : if ( mDynamicWidth )
154 : 0 : width = mWidthProperty.valueAsDouble( context.expressionContext(), width );
155 : :
156 : 0 : double height = mHeight;
157 : 0 : if ( mDynamicHeight )
158 : 0 : height = mHeightProperty.valueAsDouble( context.expressionContext(), height );
159 : :
160 : 0 : double rotation = mRotation;
161 : 0 : if ( mDynamicRotation )
162 : 0 : rotation = mRotationProperty.valueAsDouble( context.expressionContext(), rotation );
163 : :
164 : 0 : if ( width == 0 || height == 0 )
165 : : {
166 : 0 : throw QgsProcessingException( QObject::tr( "Width and height should be greater than 0." ) );
167 : : }
168 : :
169 : 0 : double phi = rotation * M_PI / 180;
170 : 0 : double xOffset = width / 2.0;
171 : 0 : double yOffset = height / 2.0;
172 : 0 : QgsPointXY point = geometry.asPoint();
173 : 0 : double x = point.x();
174 : 0 : double y = point.y();
175 : :
176 : 0 : QVector< double > ringX( 5 );
177 : 0 : QVector< double > ringY( 5 );
178 : :
179 : 0 : switch ( mShape )
180 : : {
181 : : case 0:
182 : : // rectangle
183 : 0 : ringX = { -xOffset + x, -xOffset + x, xOffset + x, xOffset + x, -xOffset + x };
184 : 0 : ringY = { -yOffset + y, yOffset + y, yOffset + y, -yOffset + y, -yOffset + y };
185 : 0 : break;
186 : : case 1:
187 : : // diamond
188 : 0 : ringX = { x, -xOffset + x, x, xOffset + x, x };
189 : 0 : ringY = { -yOffset + y, y, yOffset + y, y, -yOffset + y };
190 : 0 : break;
191 : : case 2:
192 : : // oval
193 : 0 : ringX.resize( mSegments + 1 );
194 : 0 : ringY.resize( mSegments + 1 );
195 : 0 : for ( int i = 0; i < mSegments; i ++ )
196 : : {
197 : 0 : double t = ( 2 * M_PI ) / mSegments * i;
198 : 0 : ringX[ i ] = xOffset * cos( t ) + x;
199 : 0 : ringY[ i ] = yOffset * sin( t ) + y;
200 : 0 : }
201 : 0 : ringX[ mSegments ] = ringX.at( 0 );
202 : 0 : ringY[ mSegments ] = ringY.at( 0 );
203 : 0 : break;
204 : : }
205 : :
206 : 0 : if ( phi != 0 )
207 : : {
208 : 0 : for ( int i = 0; i < ringX.size(); ++i )
209 : : {
210 : 0 : double px = ringX.at( i );
211 : 0 : double py = ringY.at( i );
212 : 0 : ringX[ i ] = ( px - x ) * cos( phi ) + ( py - y ) * sin( phi ) + x;
213 : 0 : ringY[ i ] = -( px - x ) * sin( phi ) + ( py - y ) * cos( phi ) + y;
214 : 0 : }
215 : 0 : }
216 : :
217 : 0 : std::unique_ptr< QgsPolygon > poly = std::make_unique< QgsPolygon >();
218 : 0 : poly->setExteriorRing( new QgsLineString( ringX, ringY ) );
219 : :
220 : 0 : if ( geometry.constGet()->is3D() )
221 : : {
222 : 0 : poly->addZValue( static_cast< const QgsPoint * >( geometry.constGet() )->z() );
223 : 0 : }
224 : 0 : if ( geometry.constGet()->isMeasure() )
225 : : {
226 : 0 : poly->addMValue( static_cast< const QgsPoint * >( geometry.constGet() )->m() );
227 : 0 : }
228 : :
229 : 0 : outFeature.setGeometry( std::move( poly ) );
230 : 0 : }
231 : :
232 : 0 : return QgsFeatureList() << outFeature;
233 : 0 : }
234 : :
235 : : ///@endcond
|