QGIS API Documentation  3.20.0-Odense (decaadbb31)
qgsalgorithmgrid.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsalgorithmgrid.cpp
3  ---------------------
4  begin : August 2019
5  copyright : (C) 2019 by Clemens Raffler
6  email : clemens dot raffler 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 //Disclaimer:This feature was developed by: Michael Minn, 2010
19 
20 #include "qgsalgorithmgrid.h"
21 #include "qgslinestring.h"
22 #include "qgswkbtypes.h"
23 #include "qgsvectorlayer.h"
24 #include "qgspolygon.h"
25 
27 
28 QString QgsGridAlgorithm::name() const
29 {
30  return QStringLiteral( "creategrid" );
31 }
32 
33 QString QgsGridAlgorithm::displayName() const
34 {
35  return QObject::tr( "Create grid" );
36 }
37 
38 QStringList QgsGridAlgorithm::tags() const
39 {
40  return QObject::tr( "grid,lines,polygons,vector,create,fishnet,diamond,hexagon" ).split( ',' );
41 }
42 
43 QString QgsGridAlgorithm::group() const
44 {
45  return QObject::tr( "Vector creation" );
46 }
47 
48 QString QgsGridAlgorithm::groupId() const
49 {
50  return QStringLiteral( "vectorcreation" );
51 }
52 
53 void QgsGridAlgorithm::initAlgorithm( const QVariantMap & )
54 {
55  addParameter( new QgsProcessingParameterEnum( QStringLiteral( "TYPE" ), QObject::tr( "Grid type" ), QStringList() << QObject::tr( "Point" ) << QObject::tr( "Line" ) << QObject::tr( "Rectangle (Polygon)" ) << QObject::tr( "Diamond (Polygon)" ) << QObject::tr( "Hexagon (Polygon)" ), false, 0 ) );
56 
57  addParameter( new QgsProcessingParameterExtent( QStringLiteral( "EXTENT" ), QObject::tr( "Grid extent" ) ) );
58 
59  addParameter( new QgsProcessingParameterDistance( QStringLiteral( "HSPACING" ), QObject::tr( "Horizontal spacing" ), 1, QStringLiteral( "CRS" ), false, 0, 1000000000.0 ) );
60  addParameter( new QgsProcessingParameterDistance( QStringLiteral( "VSPACING" ), QObject::tr( "Vertical spacing" ), 1, QStringLiteral( "CRS" ), false, 0, 1000000000.0 ) );
61 
62  addParameter( new QgsProcessingParameterDistance( QStringLiteral( "HOVERLAY" ), QObject::tr( "Horizontal overlay" ), 0, QStringLiteral( "CRS" ), false, 0, 1000000000.0 ) );
63  addParameter( new QgsProcessingParameterDistance( QStringLiteral( "VOVERLAY" ), QObject::tr( "Vertical overlay" ), 0, QStringLiteral( "CRS" ), false, 0, 1000000000.0 ) );
64 
65  addParameter( new QgsProcessingParameterCrs( QStringLiteral( "CRS" ), QObject::tr( "Grid CRS" ), QStringLiteral( "ProjectCrs" ) ) );
66 
67  addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Grid" ), QgsProcessing::TypeVectorPolygon ) );
68 }
69 
70 QString QgsGridAlgorithm::shortHelpString() const
71 {
72  return QObject::tr( "This algorithm creates a vector layer with a grid covering a given extent. "
73  "Elements in the grid can be points, lines or polygons. The size and/or "
74  "placement of each element in the grid is defined using a horizontal and "
75  "vertical spacing. The CRS of the output layer must be defined. The grid extent "
76  "and the spacing values must be expressed in the coordinates and units of "
77  "this CRS. The top-left point (minX, maxY) is used as the reference point. "
78  "That means that, at that point, an element is guaranteed to be placed. "
79  "Unless the width and height of the selected extent is a multiple of the "
80  "selected spacing, that is not true for the other points that define that extent."
81  );
82 }
83 
84 QgsGridAlgorithm *QgsGridAlgorithm::createInstance() const
85 {
86  return new QgsGridAlgorithm();
87 }
88 
89 bool QgsGridAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
90 {
91  mIdx = parameterAsEnum( parameters, QStringLiteral( "TYPE" ), context );
92  mHSpacing = parameterAsDouble( parameters, QStringLiteral( "HSPACING" ), context );
93  mVSpacing = parameterAsDouble( parameters, QStringLiteral( "VSPACING" ), context );
94  mHOverlay = parameterAsDouble( parameters, QStringLiteral( "HOVERLAY" ), context );
95  mVOverlay = parameterAsDouble( parameters, QStringLiteral( "VOVERLAY" ), context );
96  mCrs = parameterAsCrs( parameters, QStringLiteral( "CRS" ), context );
97  mGridExtent = parameterAsExtent( parameters, QStringLiteral( "EXTENT" ), context, mCrs );
98 
99  return true;
100 }
101 
102 QVariantMap QgsGridAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
103 {
104  if ( mHSpacing <= 0 || mVSpacing <= 0 )
105  throw QgsProcessingException( QObject::tr( "Invalid grid spacing. horizontal: '%1', vertical: '%2'" ).arg( mHSpacing ).arg( mVSpacing ) );
106 
107  if ( mGridExtent.width() < mHSpacing ) //check if grid extent is smaller than horizontal spacing
108  throw QgsProcessingException( QObject::tr( "Horizontal spacing is too large for the covered area." ) );
109 
110  if ( mGridExtent.height() < mVSpacing ) //check if grid extent is smaller than vertical spacing
111  throw QgsProcessingException( QObject::tr( "Vertical spacing is too large for the covered area." ) );
112 
113  if ( mHSpacing <= mHOverlay || mVSpacing <= mVOverlay )
114  throw QgsProcessingException( QObject::tr( "Invalid overlay: horizontal: '%1', vertical: '%2'" ).arg( mHOverlay ).arg( mVOverlay ) );
115 
116  QgsFields fields = QgsFields();
117  fields.append( QgsField( QStringLiteral( "id" ), QVariant::LongLong ) );
118  fields.append( QgsField( QStringLiteral( "left" ), QVariant::Double ) );
119  fields.append( QgsField( QStringLiteral( "top" ), QVariant::Double ) );
120  fields.append( QgsField( QStringLiteral( "right" ), QVariant::Double ) );
121  fields.append( QgsField( QStringLiteral( "bottom" ), QVariant::Double ) );
122 
124  switch ( mIdx )
125  {
126  case 0:
127  outputWkb = QgsWkbTypes::Point;
128  break;
129  case 1:
130  outputWkb = QgsWkbTypes::LineString;
131  break;
132  }
133 
134  QString dest;
135  std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields, outputWkb, mCrs ) );
136  if ( !sink )
137  throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
138 
139  feedback->setProgress( 0 );
140 
141  switch ( mIdx )
142  {
143  case 0: //point
144  createPointGrid( sink, feedback );
145  break;
146  case 1: //line
147  createLineGrid( sink, feedback );
148  break;
149  case 2: //rectangle
150  createRectangleGrid( sink, feedback );
151  break;
152  case 3: //diamond
153  createDiamondGrid( sink, feedback );
154  break;
155  case 4: //hexagon
156  createHexagonGrid( sink, feedback );
157  break;
158  }
159 
160 
161  QVariantMap outputs;
162  outputs.insert( QStringLiteral( "OUTPUT" ), dest );
163  return outputs;
164 }
165 
166 void QgsGridAlgorithm::createPointGrid( std::unique_ptr< QgsFeatureSink > &sink, QgsProcessingFeedback *feedback )
167 {
168  QgsFeature f = QgsFeature();
169 
170  long long cols = static_cast<long long>( std::ceil( mGridExtent.width() / ( mHSpacing - mHOverlay ) ) );
171  long long rows = static_cast<long long>( std::ceil( mGridExtent.height() / ( mVSpacing - mVOverlay ) ) );
172 
173  long long id = 1;
174  long long cnt = 0;
175  long long cellcnt = rows * cols;
176 
177  int thisProgress = 0;
178  int lastProgress = 0;
179 
180  for ( long long col = 0; col < cols; col++ )
181  {
182  double x = mGridExtent.xMinimum() + ( col * mHSpacing - col * mHOverlay );
183 
184  for ( long long row = 0; row < rows; row++ )
185  {
186  double y = mGridExtent.yMaximum() - ( row * mVSpacing - row * mVOverlay );
187 
188  f.setGeometry( QgsGeometry( new QgsPoint( x, y ) ) );
189  f.setAttributes( QgsAttributes() << id << x << y << x + mHSpacing << y + mVSpacing );
190  sink->addFeature( f, QgsFeatureSink::FastInsert );
191 
192  id++;
193  cnt++;
194 
195  thisProgress = static_cast<int>( ( static_cast<double>( cnt ) / static_cast<double>( cellcnt ) ) * 100 );
196  if ( thisProgress != lastProgress )
197  {
198  lastProgress = thisProgress;
199  feedback->setProgress( lastProgress );
200  }
201 
202  if ( feedback && feedback->isCanceled() )
203  break;
204  }
205  if ( feedback && feedback->isCanceled() )
206  break;
207  }
208 }
209 
210 void QgsGridAlgorithm::createLineGrid( std::unique_ptr< QgsFeatureSink > &sink, QgsProcessingFeedback *feedback )
211 {
212  QgsFeature f = QgsFeature();
213 
214  double hSpace[2];
215  if ( mHOverlay > 0 )
216  {
217  hSpace[0] = mHSpacing - mHOverlay;
218  hSpace[1] = mHOverlay;
219  }
220  else
221  {
222  hSpace[0] = mHSpacing;
223  hSpace[1] = mHSpacing;
224  }
225 
226  double vSpace[2];
227  if ( mVOverlay > 0 )
228  {
229  vSpace[0] = mVSpacing - mVOverlay;
230  vSpace[1] = mVOverlay;
231  }
232  else
233  {
234  vSpace[0] = mVSpacing;
235  vSpace[1] = mVSpacing;
236  }
237 
238  long long cnt = 0;
239  long long id = 1;
240 
241  //latitude lines
242  double cntMax = mGridExtent.height() / mVSpacing;
243 
244  int thisProgress = 0;
245  int lastProgress = 0;
246 
247  double y = mGridExtent.yMaximum();
248 
249  while ( y >= mGridExtent.yMinimum() )
250  {
251  if ( feedback && feedback->isCanceled() )
252  break;
253 
254  QgsPoint pt1 = QgsPoint( mGridExtent.xMinimum(), y );
255  QgsPoint pt2 = QgsPoint( mGridExtent.xMaximum(), y );
256 
257  f.setGeometry( QgsGeometry( new QgsLineString( pt1, pt2 ) ) );
258  f.setAttributes( QgsAttributes() << id << mGridExtent.xMinimum() << y << mGridExtent.xMaximum() << y );
259  sink->addFeature( f, QgsFeatureSink::FastInsert );
260  y = y - vSpace[cnt % 2];
261 
262  id++;
263  cnt++;
264 
265  //use 50 as count multiplicator because only half of the features are processed at this point
266  thisProgress = static_cast<int>( ( static_cast<double>( cnt ) / cntMax ) * 50 );
267  if ( thisProgress != lastProgress )
268  {
269  lastProgress = thisProgress;
270  feedback->setProgress( lastProgress );
271  }
272 
273  }
274  //set progress to 50 manually in case the division doesn't amount to 50.
275  feedback->setProgress( 50 );
276 
277  //longitude lines
278  cnt = 0;
279 
280  //latitude lines
281  cntMax = mGridExtent.width() / mHSpacing;
282 
283  lastProgress = 50;
284 
285  double x = mGridExtent.xMinimum();
286 
287  while ( x <= mGridExtent.xMaximum() )
288  {
289  if ( feedback->isCanceled() )
290  break;
291 
292  QgsPoint pt1 = QgsPoint( x, mGridExtent.yMaximum() );
293  QgsPoint pt2 = QgsPoint( x, mGridExtent.yMinimum() );
294  f.setGeometry( QgsGeometry( new QgsLineString( pt1, pt2 ) ) );
295  f.setAttributes( QgsAttributes() << id << x << mGridExtent.yMaximum() << x << mGridExtent.yMinimum() );
296  sink->addFeature( f, QgsFeatureSink::FastInsert );
297  x = x + hSpace[cnt % 2];
298 
299  id++;
300  cnt++;
301 
302  thisProgress = static_cast<int>( static_cast<double>( 50 ) + ( static_cast<double>( cnt ) / cntMax ) * 100 );
303  if ( thisProgress != lastProgress )
304  {
305  lastProgress = thisProgress;
306  feedback->setProgress( lastProgress );
307  }
308  }
309  feedback->setProgress( 100 );
310 }
311 
312 void QgsGridAlgorithm::createRectangleGrid( std::unique_ptr< QgsFeatureSink > &sink, QgsProcessingFeedback *feedback )
313 {
314  QgsFeature f = QgsFeature();
315 
316  long long cols = static_cast<long long>( std::ceil( mGridExtent.width() / ( mHSpacing - mHOverlay ) ) );
317  long long rows = static_cast<long long>( std::ceil( mGridExtent.height() / ( mVSpacing - mVOverlay ) ) );
318 
319  long long id = 1;
320  long long cnt = 0;
321  long long cellcnt = rows * cols;
322 
323  int thisProgress = 0;
324  int lastProgress = 0;
325  QVector< double > ringX( 5 );
326  QVector< double > ringY( 5 );
327 
328  for ( long long col = 0; col < cols; col++ )
329  {
330  if ( feedback && feedback->isCanceled() )
331  break;
332 
333  const double x1 = mGridExtent.xMinimum() + ( col * mHSpacing - col * mHOverlay );
334  const double x2 = x1 + mHSpacing;
335 
336  for ( long long row = 0; row < rows; row++ )
337  {
338  const double y1 = mGridExtent.yMaximum() - ( row * mVSpacing - row * mVOverlay );
339  const double y2 = y1 - mVSpacing;
340 
341  ringX = { x1, x2, x2, x1, x1 };
342  ringY = { y1, y1, y2, y2, y1 };
343  std::unique_ptr< QgsPolygon > poly = std::make_unique< QgsPolygon >();
344  poly->setExteriorRing( new QgsLineString( ringX, ringY ) );
345  f.setGeometry( std::move( poly ) );
346  f.setAttributes( QgsAttributes() << id << x1 << y1 << x2 << y2 );
347  sink->addFeature( f, QgsFeatureSink::FastInsert );
348 
349  id++;
350  cnt++;
351 
352  thisProgress = static_cast<int>( ( static_cast<double>( cnt ) / static_cast<double>( cellcnt ) ) * 100 );
353  if ( thisProgress != lastProgress )
354  {
355  lastProgress = thisProgress;
356  feedback->setProgress( lastProgress );
357  }
358 
359  if ( feedback && feedback->isCanceled() )
360  break;
361  }
362  }
363 }
364 
365 void QgsGridAlgorithm::createDiamondGrid( std::unique_ptr< QgsFeatureSink > &sink, QgsProcessingFeedback *feedback )
366 {
367  QgsFeature f = QgsFeature();
368 
369  double halfHSpacing = mHSpacing / 2;
370  double halfVSpacing = mVSpacing / 2;
371 
372  double halfHOverlay = mHOverlay / 2;
373  double halfVOverlay = mVOverlay / 2;
374 
375  long long cols = static_cast<long long>( std::ceil( mGridExtent.width() / ( halfHSpacing - halfHOverlay ) ) );
376  long long rows = static_cast<long long>( std::ceil( mGridExtent.height() / ( mVSpacing - halfVOverlay ) ) );
377 
378  long long id = 1;
379  long long cnt = 0;
380  long long cellcnt = rows * cols;
381 
382  int thisProgress = 0;
383  int lastProgress = 0;
384  QVector< double > ringX( 5 );
385  QVector< double > ringY( 5 );
386 
387  for ( long long col = 0; col < cols; col++ )
388  {
389  if ( feedback && feedback->isCanceled() )
390  break;
391 
392  double x = mGridExtent.xMinimum() - ( col * halfHOverlay );
393  double x1 = x + ( ( col + 0 ) * halfHSpacing );
394  double x2 = x + ( ( col + 1 ) * halfHSpacing );
395  double x3 = x + ( ( col + 2 ) * halfHSpacing );
396 
397  for ( long long row = 0; row < rows; row++ )
398  {
399  double y = mGridExtent.yMaximum() + ( row * halfVOverlay );
400 
401  double y1;
402  double y2;
403  double y3;
404 
405  if ( ( col % 2 ) == 0 )
406  {
407  y1 = y - ( ( ( row * 2 ) + 0 ) * halfVSpacing );
408  y2 = y - ( ( ( row * 2 ) + 1 ) * halfVSpacing );
409  y3 = y - ( ( ( row * 2 ) + 2 ) * halfVSpacing );
410  }
411  else
412  {
413  y1 = y - ( ( ( row * 2 ) + 1 ) * halfVSpacing );
414  y2 = y - ( ( ( row * 2 ) + 2 ) * halfVSpacing );
415  y3 = y - ( ( ( row * 2 ) + 3 ) * halfVSpacing );
416  }
417 
418  ringX = { x1, x2, x3, x2, x1 };
419  ringY = { y2, y1, y2, y3, y2 };
420  std::unique_ptr< QgsPolygon > poly = std::make_unique< QgsPolygon >();
421  poly->setExteriorRing( new QgsLineString( ringX, ringY ) );
422  f.setGeometry( std::move( poly ) );
423  f.setAttributes( QgsAttributes() << id << x1 << y1 << x3 << y3 );
424  sink->addFeature( f, QgsFeatureSink::FastInsert );
425 
426  id++;
427  cnt++;
428 
429  thisProgress = static_cast<int>( ( static_cast<double>( cnt ) / static_cast<double>( cellcnt ) ) * 100 );
430  if ( thisProgress != lastProgress )
431  {
432  lastProgress = thisProgress;
433  feedback->setProgress( lastProgress );
434  }
435 
436  if ( feedback && feedback->isCanceled() )
437  break;
438  }
439  }
440 }
441 
442 void QgsGridAlgorithm::createHexagonGrid( std::unique_ptr<QgsFeatureSink> &sink, QgsProcessingFeedback *feedback )
443 {
444  QgsFeature f = QgsFeature();
445 
446  // To preserve symmetry, hspacing is fixed relative to vspacing
447  double xVertexLo = 0.288675134594813 * mVSpacing;
448  double xVertexHi = 0.577350269189626 * mVSpacing;
449 
450  mHSpacing = xVertexLo + xVertexHi;
451 
452  mHOverlay = mHSpacing - mHOverlay;
453 
454  if ( mHOverlay < 0 )
455  {
456  throw QgsProcessingException( QObject::tr( "To preserve symmetry, hspacing is fixed relative to vspacing\n hspacing is fixed at: %1 and hoverlay is fixed at: %2 hoverlay cannot be negative. Increase hoverlay." ).arg( mHSpacing ).arg( mHOverlay ) );
457  }
458 
459  double halfVSpacing = mVSpacing / 2;
460 
461  long long cols = static_cast<long long>( std::ceil( mGridExtent.width() / ( mHOverlay ) ) );
462  long long rows = static_cast<long long>( std::ceil( mGridExtent.height() / ( mVSpacing - mVOverlay ) ) );
463 
464  long long id = 1;
465  long long cnt = 0;
466  long long cellcnt = rows * cols;
467 
468  int thisProgress = 0;
469  int lastProgress = 0;
470 
471  QVector< double > ringX( 7 );
472  QVector< double > ringY( 7 );
473  for ( long long col = 0; col < cols; col++ )
474  {
475  if ( feedback && feedback->isCanceled() )
476  break;
477 
478  // (column + 1) and (row + 1) calculation is used to maintain
479  // topology between adjacent shapes and avoid overlaps/holes
480  // due to rounding errors
481 
482  double x1 = mGridExtent.xMinimum() + ( col * mHOverlay );
483  double x2 = x1 + ( xVertexHi - xVertexLo );
484  double x3 = mGridExtent.xMinimum() + ( col * mHOverlay ) + mHSpacing;
485  double x4 = x3 + ( xVertexHi - xVertexLo );
486 
487  for ( long long row = 0; row < rows; row++ )
488  {
489  double y1;
490  double y2;
491  double y3;
492 
493  if ( ( col % 2 ) == 0 )
494  {
495  y1 = mGridExtent.yMaximum() + ( row * mVOverlay ) - ( ( ( row * 2 ) + 0 ) * halfVSpacing );
496  y2 = mGridExtent.yMaximum() + ( row * mVOverlay ) - ( ( ( row * 2 ) + 1 ) * halfVSpacing );
497  y3 = mGridExtent.yMaximum() + ( row * mVOverlay ) - ( ( ( row * 2 ) + 2 ) * halfVSpacing );
498  }
499  else
500  {
501  y1 = mGridExtent.yMaximum() + ( row * mVOverlay ) - ( ( ( row * 2 ) + 1 ) * halfVSpacing );
502  y2 = mGridExtent.yMaximum() + ( row * mVOverlay ) - ( ( ( row * 2 ) + 2 ) * halfVSpacing );
503  y3 = mGridExtent.yMaximum() + ( row * mVOverlay ) - ( ( ( row * 2 ) + 3 ) * halfVSpacing );
504  }
505 
506  ringX = { x1, x2, x3, x4, x3, x2, x1 };
507  ringY = { y2, y1, y1, y2, y3, y3, y2 };
508  std::unique_ptr< QgsPolygon > poly = std::make_unique< QgsPolygon >();
509  poly->setExteriorRing( new QgsLineString( ringX, ringY ) );
510  f.setGeometry( std::move( poly ) );
511  f.setAttributes( QgsAttributes() << id << x1 << y1 << x4 << y3 );
512  sink->addFeature( f, QgsFeatureSink::FastInsert );
513 
514  id++;
515  cnt++;
516 
517  thisProgress = static_cast<int>( ( static_cast<double>( cnt ) / static_cast<double>( cellcnt ) ) * 100 );
518  if ( thisProgress != lastProgress )
519  {
520  lastProgress = thisProgress;
521  feedback->setProgress( lastProgress );
522  }
523 
524  if ( feedback && feedback->isCanceled() )
525  break;
526  }
527  }
528 }
529 
A vector of attributes.
Definition: qgsattributes.h:58
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
Definition: qgsfeature.cpp:135
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:145
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:63
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:51
Container of fields for a vector layer.
Definition: qgsfields.h:45
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false)
Definition: qgsfields.cpp:59
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:44
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:49
Contains information about the context in which a processing algorithm is executed.
Custom exception class for processing related exceptions.
Definition: qgsexception.h:83
Base class for providing feedback from a processing algorithm.
A coordinate reference system parameter for processing algorithms.
A double numeric parameter for distance values.
An enum based parameter for processing algorithms, allowing for selection from predefined values.
A rectangular map extent parameter for processing algorithms.
A feature sink output for processing algorithms.
@ TypeVectorPolygon
Vector polygon layers.
Definition: qgsprocessing.h:51
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:70