Branch data Line data Source code
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 : :
26 : : ///@cond PRIVATE
27 : :
28 : 0 : QString QgsGridAlgorithm::name() const
29 : : {
30 : 0 : return QStringLiteral( "creategrid" );
31 : : }
32 : :
33 : 0 : QString QgsGridAlgorithm::displayName() const
34 : : {
35 : 0 : return QObject::tr( "Create grid" );
36 : : }
37 : :
38 : 0 : QStringList QgsGridAlgorithm::tags() const
39 : : {
40 : 0 : return QObject::tr( "grid,lines,polygons,vector,create,fishnet,diamond,hexagon" ).split( ',' );
41 : 0 : }
42 : :
43 : 0 : QString QgsGridAlgorithm::group() const
44 : : {
45 : 0 : return QObject::tr( "Vector creation" );
46 : : }
47 : :
48 : 0 : QString QgsGridAlgorithm::groupId() const
49 : : {
50 : 0 : return QStringLiteral( "vectorcreation" );
51 : : }
52 : :
53 : 0 : void QgsGridAlgorithm::initAlgorithm( const QVariantMap & )
54 : : {
55 : 0 : 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 : 0 : addParameter( new QgsProcessingParameterExtent( QStringLiteral( "EXTENT" ), QObject::tr( "Grid extent" ) ) );
58 : :
59 : 0 : addParameter( new QgsProcessingParameterDistance( QStringLiteral( "HSPACING" ), QObject::tr( "Horizontal spacing" ), 1, QStringLiteral( "CRS" ), false, 0, 1000000000.0 ) );
60 : 0 : addParameter( new QgsProcessingParameterDistance( QStringLiteral( "VSPACING" ), QObject::tr( "Vertical spacing" ), 1, QStringLiteral( "CRS" ), false, 0, 1000000000.0 ) );
61 : :
62 : 0 : addParameter( new QgsProcessingParameterDistance( QStringLiteral( "HOVERLAY" ), QObject::tr( "Horizontal overlay" ), 0, QStringLiteral( "CRS" ), false, 0, 1000000000.0 ) );
63 : 0 : addParameter( new QgsProcessingParameterDistance( QStringLiteral( "VOVERLAY" ), QObject::tr( "Vertical overlay" ), 0, QStringLiteral( "CRS" ), false, 0, 1000000000.0 ) );
64 : :
65 : 0 : addParameter( new QgsProcessingParameterCrs( QStringLiteral( "CRS" ), QObject::tr( "Grid CRS" ), QStringLiteral( "ProjectCrs" ) ) );
66 : :
67 : 0 : addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Grid" ), QgsProcessing::TypeVectorPolygon ) );
68 : 0 : }
69 : :
70 : 0 : QString QgsGridAlgorithm::shortHelpString() const
71 : : {
72 : 0 : 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 : 0 : QgsGridAlgorithm *QgsGridAlgorithm::createInstance() const
85 : : {
86 : 0 : return new QgsGridAlgorithm();
87 : 0 : }
88 : :
89 : 0 : bool QgsGridAlgorithm::prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback * )
90 : : {
91 : 0 : mIdx = parameterAsEnum( parameters, QStringLiteral( "TYPE" ), context );
92 : 0 : mHSpacing = parameterAsDouble( parameters, QStringLiteral( "HSPACING" ), context );
93 : 0 : mVSpacing = parameterAsDouble( parameters, QStringLiteral( "VSPACING" ), context );
94 : 0 : mHOverlay = parameterAsDouble( parameters, QStringLiteral( "HOVERLAY" ), context );
95 : 0 : mVOverlay = parameterAsDouble( parameters, QStringLiteral( "VOVERLAY" ), context );
96 : 0 : mCrs = parameterAsCrs( parameters, QStringLiteral( "CRS" ), context );
97 : 0 : mGridExtent = parameterAsExtent( parameters, QStringLiteral( "EXTENT" ), context, mCrs );
98 : :
99 : 0 : return true;
100 : 0 : }
101 : :
102 : 0 : QVariantMap QgsGridAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
103 : : {
104 : 0 : if ( mHSpacing <= 0 || mVSpacing <= 0 )
105 : 0 : throw QgsProcessingException( QObject::tr( "Invalid grid spacing. horizontal: '%1', vertical: '%2'" ).arg( mHSpacing ).arg( mVSpacing ) );
106 : :
107 : 0 : if ( mGridExtent.width() < mHSpacing ) //check if grid extent is smaller than horizontal spacing
108 : 0 : throw QgsProcessingException( QObject::tr( "Horizontal spacing is too large for the covered area." ) );
109 : :
110 : 0 : if ( mGridExtent.height() < mVSpacing ) //check if grid extent is smaller than vertical spacing
111 : 0 : throw QgsProcessingException( QObject::tr( "Vertical spacing is too large for the covered area." ) );
112 : :
113 : 0 : if ( mHSpacing <= mHOverlay || mVSpacing <= mVOverlay )
114 : 0 : throw QgsProcessingException( QObject::tr( "Invalid overlay: horizontal: '%1', vertical: '%2'" ).arg( mHOverlay ).arg( mVOverlay ) );
115 : :
116 : 0 : QgsFields fields = QgsFields();
117 : 0 : fields.append( QgsField( QStringLiteral( "id" ), QVariant::LongLong ) );
118 : 0 : fields.append( QgsField( QStringLiteral( "left" ), QVariant::Double ) );
119 : 0 : fields.append( QgsField( QStringLiteral( "top" ), QVariant::Double ) );
120 : 0 : fields.append( QgsField( QStringLiteral( "right" ), QVariant::Double ) );
121 : 0 : fields.append( QgsField( QStringLiteral( "bottom" ), QVariant::Double ) );
122 : :
123 : 0 : QgsWkbTypes::Type outputWkb = QgsWkbTypes::Polygon;
124 : 0 : switch ( mIdx )
125 : : {
126 : : case 0:
127 : 0 : outputWkb = QgsWkbTypes::Point;
128 : 0 : break;
129 : : case 1:
130 : 0 : outputWkb = QgsWkbTypes::LineString;
131 : 0 : break;
132 : : }
133 : :
134 : 0 : QString dest;
135 : 0 : std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields, outputWkb, mCrs ) );
136 : 0 : if ( !sink )
137 : 0 : throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
138 : :
139 : 0 : feedback->setProgress( 0 );
140 : :
141 : 0 : switch ( mIdx )
142 : : {
143 : : case 0: //point
144 : 0 : createPointGrid( sink, feedback );
145 : 0 : break;
146 : : case 1: //line
147 : 0 : createLineGrid( sink, feedback );
148 : 0 : break;
149 : : case 2: //rectangle
150 : 0 : createRectangleGrid( sink, feedback );
151 : 0 : break;
152 : : case 3: //diamond
153 : 0 : createDiamondGrid( sink, feedback );
154 : 0 : break;
155 : : case 4: //hexagon
156 : 0 : createHexagonGrid( sink, feedback );
157 : 0 : break;
158 : : }
159 : :
160 : :
161 : 0 : QVariantMap outputs;
162 : 0 : outputs.insert( QStringLiteral( "OUTPUT" ), dest );
163 : 0 : return outputs;
164 : 0 : }
165 : :
166 : 0 : void QgsGridAlgorithm::createPointGrid( std::unique_ptr< QgsFeatureSink > &sink, QgsProcessingFeedback *feedback )
167 : : {
168 : 0 : QgsFeature f = QgsFeature();
169 : :
170 : 0 : long long cols = static_cast<long long>( std::ceil( mGridExtent.width() / ( mHSpacing - mHOverlay ) ) );
171 : 0 : long long rows = static_cast<long long>( std::ceil( mGridExtent.height() / ( mVSpacing - mVOverlay ) ) );
172 : :
173 : 0 : long long id = 1;
174 : 0 : long long cnt = 0;
175 : 0 : long long cellcnt = rows * cols;
176 : :
177 : 0 : int thisProgress = 0;
178 : 0 : int lastProgress = 0;
179 : :
180 : 0 : for ( long long col = 0; col < cols; col++ )
181 : : {
182 : 0 : double x = mGridExtent.xMinimum() + ( col * mHSpacing - col * mHOverlay );
183 : :
184 : 0 : for ( long long row = 0; row < rows; row++ )
185 : : {
186 : 0 : double y = mGridExtent.yMaximum() - ( row * mVSpacing - row * mVOverlay );
187 : :
188 : 0 : f.setGeometry( QgsGeometry( new QgsPoint( x, y ) ) );
189 : 0 : f.setAttributes( QgsAttributes() << id << x << y << x + mHSpacing << y + mVSpacing );
190 : 0 : sink->addFeature( f, QgsFeatureSink::FastInsert );
191 : :
192 : 0 : id++;
193 : 0 : cnt++;
194 : :
195 : 0 : thisProgress = static_cast<int>( ( static_cast<double>( cnt ) / static_cast<double>( cellcnt ) ) * 100 );
196 : 0 : if ( thisProgress != lastProgress )
197 : : {
198 : 0 : lastProgress = thisProgress;
199 : 0 : feedback->setProgress( lastProgress );
200 : 0 : }
201 : :
202 : 0 : if ( feedback && feedback->isCanceled() )
203 : 0 : break;
204 : 0 : }
205 : 0 : if ( feedback && feedback->isCanceled() )
206 : 0 : break;
207 : 0 : }
208 : 0 : }
209 : :
210 : 0 : void QgsGridAlgorithm::createLineGrid( std::unique_ptr< QgsFeatureSink > &sink, QgsProcessingFeedback *feedback )
211 : : {
212 : 0 : QgsFeature f = QgsFeature();
213 : :
214 : : double hSpace[2];
215 : 0 : if ( mHOverlay > 0 )
216 : : {
217 : 0 : hSpace[0] = mHSpacing - mHOverlay;
218 : 0 : hSpace[1] = mHOverlay;
219 : 0 : }
220 : : else
221 : : {
222 : 0 : hSpace[0] = mHSpacing;
223 : 0 : hSpace[1] = mHSpacing;
224 : : }
225 : :
226 : : double vSpace[2];
227 : 0 : if ( mVOverlay > 0 )
228 : : {
229 : 0 : vSpace[0] = mVSpacing - mVOverlay;
230 : 0 : vSpace[1] = mVOverlay;
231 : 0 : }
232 : : else
233 : : {
234 : 0 : vSpace[0] = mVSpacing;
235 : 0 : vSpace[1] = mVSpacing;
236 : : }
237 : :
238 : 0 : long long cnt = 0;
239 : 0 : long long id = 1;
240 : :
241 : : //latitude lines
242 : 0 : double cntMax = mGridExtent.height() / mVSpacing;
243 : :
244 : 0 : int thisProgress = 0;
245 : 0 : int lastProgress = 0;
246 : :
247 : 0 : double y = mGridExtent.yMaximum();
248 : :
249 : 0 : while ( y >= mGridExtent.yMinimum() )
250 : : {
251 : 0 : if ( feedback && feedback->isCanceled() )
252 : 0 : break;
253 : :
254 : 0 : QgsPoint pt1 = QgsPoint( mGridExtent.xMinimum(), y );
255 : 0 : QgsPoint pt2 = QgsPoint( mGridExtent.xMaximum(), y );
256 : :
257 : 0 : f.setGeometry( QgsGeometry( new QgsLineString( pt1, pt2 ) ) );
258 : 0 : f.setAttributes( QgsAttributes() << id << mGridExtent.xMinimum() << y << mGridExtent.xMaximum() << y );
259 : 0 : sink->addFeature( f, QgsFeatureSink::FastInsert );
260 : 0 : y = y - vSpace[cnt % 2];
261 : :
262 : 0 : id++;
263 : 0 : cnt++;
264 : :
265 : : //use 50 as count multiplicator because only half of the features are processed at this point
266 : 0 : thisProgress = static_cast<int>( ( static_cast<double>( cnt ) / cntMax ) * 50 );
267 : 0 : if ( thisProgress != lastProgress )
268 : : {
269 : 0 : lastProgress = thisProgress;
270 : 0 : feedback->setProgress( lastProgress );
271 : 0 : }
272 : :
273 : 0 : }
274 : : //set progress to 50 manually in case the division doesn't amount to 50.
275 : 0 : feedback->setProgress( 50 );
276 : :
277 : : //longitude lines
278 : 0 : cnt = 0;
279 : :
280 : : //latitude lines
281 : 0 : cntMax = mGridExtent.width() / mHSpacing;
282 : :
283 : 0 : lastProgress = 50;
284 : :
285 : 0 : double x = mGridExtent.xMinimum();
286 : :
287 : 0 : while ( x <= mGridExtent.xMaximum() )
288 : : {
289 : 0 : if ( feedback->isCanceled() )
290 : 0 : break;
291 : :
292 : 0 : QgsPoint pt1 = QgsPoint( x, mGridExtent.yMaximum() );
293 : 0 : QgsPoint pt2 = QgsPoint( x, mGridExtent.yMinimum() );
294 : 0 : f.setGeometry( QgsGeometry( new QgsLineString( pt1, pt2 ) ) );
295 : 0 : f.setAttributes( QgsAttributes() << id << x << mGridExtent.yMaximum() << x << mGridExtent.yMinimum() );
296 : 0 : sink->addFeature( f, QgsFeatureSink::FastInsert );
297 : 0 : x = x + hSpace[cnt % 2];
298 : :
299 : 0 : id++;
300 : 0 : cnt++;
301 : :
302 : 0 : thisProgress = static_cast<int>( static_cast<double>( 50 ) + ( static_cast<double>( cnt ) / cntMax ) * 100 );
303 : 0 : if ( thisProgress != lastProgress )
304 : : {
305 : 0 : lastProgress = thisProgress;
306 : 0 : feedback->setProgress( lastProgress );
307 : 0 : }
308 : 0 : }
309 : 0 : feedback->setProgress( 100 );
310 : 0 : }
311 : :
312 : 0 : void QgsGridAlgorithm::createRectangleGrid( std::unique_ptr< QgsFeatureSink > &sink, QgsProcessingFeedback *feedback )
313 : : {
314 : 0 : QgsFeature f = QgsFeature();
315 : :
316 : 0 : long long cols = static_cast<long long>( std::ceil( mGridExtent.width() / ( mHSpacing - mHOverlay ) ) );
317 : 0 : long long rows = static_cast<long long>( std::ceil( mGridExtent.height() / ( mVSpacing - mVOverlay ) ) );
318 : :
319 : 0 : long long id = 1;
320 : 0 : long long cnt = 0;
321 : 0 : long long cellcnt = rows * cols;
322 : :
323 : 0 : int thisProgress = 0;
324 : 0 : int lastProgress = 0;
325 : 0 : QVector< double > ringX( 5 );
326 : 0 : QVector< double > ringY( 5 );
327 : :
328 : 0 : for ( long long col = 0; col < cols; col++ )
329 : : {
330 : 0 : if ( feedback && feedback->isCanceled() )
331 : 0 : break;
332 : :
333 : 0 : const double x1 = mGridExtent.xMinimum() + ( col * mHSpacing - col * mHOverlay );
334 : 0 : const double x2 = x1 + mHSpacing;
335 : :
336 : 0 : for ( long long row = 0; row < rows; row++ )
337 : : {
338 : 0 : const double y1 = mGridExtent.yMaximum() - ( row * mVSpacing - row * mVOverlay );
339 : 0 : const double y2 = y1 - mVSpacing;
340 : :
341 : 0 : ringX = { x1, x2, x2, x1, x1 };
342 : 0 : ringY = { y1, y1, y2, y2, y1 };
343 : 0 : std::unique_ptr< QgsPolygon > poly = std::make_unique< QgsPolygon >();
344 : 0 : poly->setExteriorRing( new QgsLineString( ringX, ringY ) );
345 : 0 : f.setGeometry( std::move( poly ) );
346 : 0 : f.setAttributes( QgsAttributes() << id << x1 << y1 << x2 << y2 );
347 : 0 : sink->addFeature( f, QgsFeatureSink::FastInsert );
348 : :
349 : 0 : id++;
350 : 0 : cnt++;
351 : :
352 : 0 : thisProgress = static_cast<int>( ( static_cast<double>( cnt ) / static_cast<double>( cellcnt ) ) * 100 );
353 : 0 : if ( thisProgress != lastProgress )
354 : : {
355 : 0 : lastProgress = thisProgress;
356 : 0 : feedback->setProgress( lastProgress );
357 : 0 : }
358 : :
359 : 0 : if ( feedback && feedback->isCanceled() )
360 : 0 : break;
361 : 0 : }
362 : 0 : }
363 : 0 : }
364 : :
365 : 0 : void QgsGridAlgorithm::createDiamondGrid( std::unique_ptr< QgsFeatureSink > &sink, QgsProcessingFeedback *feedback )
366 : : {
367 : 0 : QgsFeature f = QgsFeature();
368 : :
369 : 0 : double halfHSpacing = mHSpacing / 2;
370 : 0 : double halfVSpacing = mVSpacing / 2;
371 : :
372 : 0 : double halfHOverlay = mHOverlay / 2;
373 : 0 : double halfVOverlay = mVOverlay / 2;
374 : :
375 : 0 : long long cols = static_cast<long long>( std::ceil( mGridExtent.width() / ( halfHSpacing - halfHOverlay ) ) );
376 : 0 : long long rows = static_cast<long long>( std::ceil( mGridExtent.height() / ( mVSpacing - halfVOverlay ) ) );
377 : :
378 : 0 : long long id = 1;
379 : 0 : long long cnt = 0;
380 : 0 : long long cellcnt = rows * cols;
381 : :
382 : 0 : int thisProgress = 0;
383 : 0 : int lastProgress = 0;
384 : 0 : QVector< double > ringX( 5 );
385 : 0 : QVector< double > ringY( 5 );
386 : :
387 : 0 : for ( long long col = 0; col < cols; col++ )
388 : : {
389 : 0 : if ( feedback && feedback->isCanceled() )
390 : 0 : break;
391 : :
392 : 0 : double x = mGridExtent.xMinimum() - ( col * halfHOverlay );
393 : 0 : double x1 = x + ( ( col + 0 ) * halfHSpacing );
394 : 0 : double x2 = x + ( ( col + 1 ) * halfHSpacing );
395 : 0 : double x3 = x + ( ( col + 2 ) * halfHSpacing );
396 : :
397 : 0 : for ( long long row = 0; row < rows; row++ )
398 : : {
399 : 0 : double y = mGridExtent.yMaximum() + ( row * halfVOverlay );
400 : :
401 : : double y1;
402 : : double y2;
403 : : double y3;
404 : :
405 : 0 : if ( ( col % 2 ) == 0 )
406 : : {
407 : 0 : y1 = y - ( ( ( row * 2 ) + 0 ) * halfVSpacing );
408 : 0 : y2 = y - ( ( ( row * 2 ) + 1 ) * halfVSpacing );
409 : 0 : y3 = y - ( ( ( row * 2 ) + 2 ) * halfVSpacing );
410 : 0 : }
411 : : else
412 : : {
413 : 0 : y1 = y - ( ( ( row * 2 ) + 1 ) * halfVSpacing );
414 : 0 : y2 = y - ( ( ( row * 2 ) + 2 ) * halfVSpacing );
415 : 0 : y3 = y - ( ( ( row * 2 ) + 3 ) * halfVSpacing );
416 : : }
417 : :
418 : 0 : ringX = { x1, x2, x3, x2, x1 };
419 : 0 : ringY = { y2, y1, y2, y3, y2 };
420 : 0 : std::unique_ptr< QgsPolygon > poly = std::make_unique< QgsPolygon >();
421 : 0 : poly->setExteriorRing( new QgsLineString( ringX, ringY ) );
422 : 0 : f.setGeometry( std::move( poly ) );
423 : 0 : f.setAttributes( QgsAttributes() << id << x1 << y1 << x3 << y3 );
424 : 0 : sink->addFeature( f, QgsFeatureSink::FastInsert );
425 : :
426 : 0 : id++;
427 : 0 : cnt++;
428 : :
429 : 0 : thisProgress = static_cast<int>( ( static_cast<double>( cnt ) / static_cast<double>( cellcnt ) ) * 100 );
430 : 0 : if ( thisProgress != lastProgress )
431 : : {
432 : 0 : lastProgress = thisProgress;
433 : 0 : feedback->setProgress( lastProgress );
434 : 0 : }
435 : :
436 : 0 : if ( feedback && feedback->isCanceled() )
437 : 0 : break;
438 : 0 : }
439 : 0 : }
440 : 0 : }
441 : :
442 : 0 : void QgsGridAlgorithm::createHexagonGrid( std::unique_ptr<QgsFeatureSink> &sink, QgsProcessingFeedback *feedback )
443 : : {
444 : 0 : QgsFeature f = QgsFeature();
445 : :
446 : : // To preserve symmetry, hspacing is fixed relative to vspacing
447 : 0 : double xVertexLo = 0.288675134594813 * mVSpacing;
448 : 0 : double xVertexHi = 0.577350269189626 * mVSpacing;
449 : :
450 : 0 : mHSpacing = xVertexLo + xVertexHi;
451 : :
452 : 0 : mHOverlay = mHSpacing - mHOverlay;
453 : :
454 : 0 : if ( mHOverlay < 0 )
455 : : {
456 : 0 : 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 : 0 : double halfVSpacing = mVSpacing / 2;
460 : :
461 : 0 : long long cols = static_cast<long long>( std::ceil( mGridExtent.width() / ( mHOverlay ) ) );
462 : 0 : long long rows = static_cast<long long>( std::ceil( mGridExtent.height() / ( mVSpacing - mVOverlay ) ) );
463 : :
464 : 0 : long long id = 1;
465 : 0 : long long cnt = 0;
466 : 0 : long long cellcnt = rows * cols;
467 : :
468 : 0 : int thisProgress = 0;
469 : 0 : int lastProgress = 0;
470 : :
471 : 0 : QVector< double > ringX( 7 );
472 : 0 : QVector< double > ringY( 7 );
473 : 0 : for ( long long col = 0; col < cols; col++ )
474 : : {
475 : 0 : if ( feedback && feedback->isCanceled() )
476 : 0 : 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 : 0 : double x1 = mGridExtent.xMinimum() + ( col * mHOverlay );
483 : 0 : double x2 = x1 + ( xVertexHi - xVertexLo );
484 : 0 : double x3 = mGridExtent.xMinimum() + ( col * mHOverlay ) + mHSpacing;
485 : 0 : double x4 = x3 + ( xVertexHi - xVertexLo );
486 : :
487 : 0 : for ( long long row = 0; row < rows; row++ )
488 : : {
489 : : double y1;
490 : : double y2;
491 : : double y3;
492 : :
493 : 0 : if ( ( col % 2 ) == 0 )
494 : : {
495 : 0 : y1 = mGridExtent.yMaximum() + ( row * mVOverlay ) - ( ( ( row * 2 ) + 0 ) * halfVSpacing );
496 : 0 : y2 = mGridExtent.yMaximum() + ( row * mVOverlay ) - ( ( ( row * 2 ) + 1 ) * halfVSpacing );
497 : 0 : y3 = mGridExtent.yMaximum() + ( row * mVOverlay ) - ( ( ( row * 2 ) + 2 ) * halfVSpacing );
498 : 0 : }
499 : : else
500 : : {
501 : 0 : y1 = mGridExtent.yMaximum() + ( row * mVOverlay ) - ( ( ( row * 2 ) + 1 ) * halfVSpacing );
502 : 0 : y2 = mGridExtent.yMaximum() + ( row * mVOverlay ) - ( ( ( row * 2 ) + 2 ) * halfVSpacing );
503 : 0 : y3 = mGridExtent.yMaximum() + ( row * mVOverlay ) - ( ( ( row * 2 ) + 3 ) * halfVSpacing );
504 : : }
505 : :
506 : 0 : ringX = { x1, x2, x3, x4, x3, x2, x1 };
507 : 0 : ringY = { y2, y1, y1, y2, y3, y3, y2 };
508 : 0 : std::unique_ptr< QgsPolygon > poly = std::make_unique< QgsPolygon >();
509 : 0 : poly->setExteriorRing( new QgsLineString( ringX, ringY ) );
510 : 0 : f.setGeometry( std::move( poly ) );
511 : 0 : f.setAttributes( QgsAttributes() << id << x1 << y1 << x4 << y3 );
512 : 0 : sink->addFeature( f, QgsFeatureSink::FastInsert );
513 : :
514 : 0 : id++;
515 : 0 : cnt++;
516 : :
517 : 0 : thisProgress = static_cast<int>( ( static_cast<double>( cnt ) / static_cast<double>( cellcnt ) ) * 100 );
518 : 0 : if ( thisProgress != lastProgress )
519 : : {
520 : 0 : lastProgress = thisProgress;
521 : 0 : feedback->setProgress( lastProgress );
522 : 0 : }
523 : :
524 : 0 : if ( feedback && feedback->isCanceled() )
525 : 0 : break;
526 : 0 : }
527 : 0 : }
528 : 0 : }
529 : :
530 : : ///@endcond
|