@@ -48,6 +48,8 @@ class GridPolygon(GeoAlgorithm):
4848 EXTENT = 'EXTENT'
4949 HSPACING = 'HSPACING'
5050 VSPACING = 'VSPACING'
51+ HOVERLAY = 'HOVERLAY'
52+ VOVERLAY = 'VOVERLAY'
5153 CRS = 'CRS'
5254 OUTPUT = 'OUTPUT'
5355
@@ -71,6 +73,10 @@ def defineCharacteristics(self):
7173 self .tr ('Horizontal spacing' ), 0.0 , 1000000000.0 , 0.0001 ))
7274 self .addParameter (ParameterNumber (self .VSPACING ,
7375 self .tr ('Vertical spacing' ), 0.0 , 1000000000.0 , 0.0001 ))
76+ self .addParameter (ParameterNumber (self .HOVERLAY ,
77+ self .tr ('Horizontal overlay' ), 0.0 , 1000000000.0 , 0.0 ))
78+ self .addParameter (ParameterNumber (self .VOVERLAY ,
79+ self .tr ('Vertical overlay' ), 0.0 , 1000000000.0 , 0.0 ))
7480 self .addParameter (ParameterCrs (self .CRS , 'Grid CRS' , 'EPSG:4326' ))
7581
7682 self .addOutput (OutputVector (self .OUTPUT , self .tr ('Grid' ), datatype = [dataobjects .TYPE_VECTOR_POLYGON ]))
@@ -80,6 +86,8 @@ def processAlgorithm(self, feedback):
8086 extent = self .getParameterValue (self .EXTENT ).split (',' )
8187 hSpacing = self .getParameterValue (self .HSPACING )
8288 vSpacing = self .getParameterValue (self .VSPACING )
89+ hOverlay = self .getParameterValue (self .HOVERLAY )
90+ vOverlay = self .getParameterValue (self .VOVERLAY )
8391 crs = QgsCoordinateReferenceSystem (self .getParameterValue (self .CRS ))
8492
8593 bbox = QgsRectangle (float (extent [0 ]), float (extent [2 ]),
@@ -98,6 +106,10 @@ def processAlgorithm(self, feedback):
98106 raise GeoAlgorithmExecutionException (
99107 self .tr ('Horizontal spacing is too small for the covered area' ))
100108
109+ if hSpacing <= hOverlay or vSpacing <= vOverlay :
110+ raise GeoAlgorithmExecutionException (
111+ self .tr ('Invalid overlay: %s/%s' % (hOverlay , vOverlay )))
112+
101113 if height < vSpacing :
102114 raise GeoAlgorithmExecutionException (
103115 self .tr ('Vertical spacing is too small for the covered area' ))
@@ -114,37 +126,36 @@ def processAlgorithm(self, feedback):
114126
115127 if idx == 0 :
116128 self ._rectangleGrid (
117- writer , width , height , originX , originY , hSpacing , vSpacing , feedback )
129+ writer , width , height , originX , originY , hSpacing , vSpacing , hOverlay , vOverlay , feedback )
118130 elif idx == 1 :
119131 self ._diamondGrid (
120- writer , width , height , originX , originY , hSpacing , vSpacing , feedback )
132+ writer , width , height , originX , originY , hSpacing , vSpacing , hOverlay , vOverlay , feedback )
121133 elif idx == 2 :
122134 self ._hexagonGrid (
123- writer , width , height , originX , originY , hSpacing , vSpacing , feedback )
135+ writer , width , height , originX , originY , hSpacing , vSpacing , hOverlay , vOverlay , feedback )
124136
125137 del writer
126138
127139 def _rectangleGrid (self , writer , width , height , originX , originY ,
128- hSpacing , vSpacing , feedback ):
140+ hSpacing , vSpacing , hOverlay , vOverlay , feedback ):
129141 ft = QgsFeature ()
130142
131- columns = int (math .ceil (float (width ) / hSpacing ))
132- rows = int (math .ceil (float (height ) / vSpacing ))
143+ columns = int (math .ceil (float (width ) / (hSpacing - hOverlay )))
144+ rows = int (math .ceil (float (height ) / (vSpacing - vOverlay )))
145+
133146 cells = rows * columns
134147 count_update = cells * 0.05
135148
136149 id = 1
137150 count = 0
138151
139152 for col in range (columns ):
140- # (column + 1) and (row + 1) calculation is used to maintain
141- # topology between adjacent shapes and avoid overlaps/holes
142- # due to rounding errors
143- x1 = originX + (col * hSpacing )
144- x2 = originX + ((col + 1 ) * hSpacing )
153+ x1 = originX + (col * hSpacing - col * hOverlay )
154+ x2 = x1 + hSpacing
155+
145156 for row in range (rows ):
146- y1 = originY - (row * vSpacing )
147- y2 = originY - (( row + 1 ) * vSpacing )
157+ y1 = originY - (row * vSpacing - row * vOverlay )
158+ y2 = y1 - vSpacing
148159
149160 polyline = []
150161 polyline .append (QgsPoint (x1 , y1 ))
@@ -156,20 +167,24 @@ def _rectangleGrid(self, writer, width, height, originX, originY,
156167 ft .setGeometry (QgsGeometry .fromPolygon ([polyline ]))
157168 ft .setAttributes ([x1 , y1 , x2 , y2 , id ])
158169 writer .addFeature (ft )
170+
159171 id += 1
160172 count += 1
161173 if int (math .fmod (count , count_update )) == 0 :
162174 feedback .setProgress (int (count / cells * 100 ))
163175
164176 def _diamondGrid (self , writer , width , height , originX , originY ,
165- hSpacing , vSpacing , feedback ):
177+ hSpacing , vSpacing , hOverlay , vOverlay , feedback ):
166178 ft = QgsFeature ()
167179
168180 halfHSpacing = hSpacing / 2
169181 halfVSpacing = vSpacing / 2
170182
171- columns = int (math .ceil (float (width ) / halfHSpacing ))
172- rows = int (math .ceil (float (height ) / vSpacing ))
183+ halfHOverlay = hOverlay / 2
184+ halfVOverlay = vOverlay / 2
185+
186+ columns = int (math .ceil (float (width ) / (halfHSpacing - halfHOverlay )))
187+ rows = int (math .ceil (float (height ) / (vSpacing - halfVOverlay )))
173188
174189 cells = rows * columns
175190 count_update = cells * 0.05
@@ -178,19 +193,21 @@ def _diamondGrid(self, writer, width, height, originX, originY,
178193 count = 0
179194
180195 for col in range (columns ):
181- x1 = originX + ((col + 0 ) * halfHSpacing )
182- x2 = originX + ((col + 1 ) * halfHSpacing )
183- x3 = originX + ((col + 2 ) * halfHSpacing )
196+ x = originX - (col * halfHOverlay )
197+ x1 = x + ((col + 0 ) * halfHSpacing )
198+ x2 = x + ((col + 1 ) * halfHSpacing )
199+ x3 = x + ((col + 2 ) * halfHSpacing )
184200
185201 for row in range (rows ):
202+ y = originY + (row * halfVOverlay )
186203 if (col % 2 ) == 0 :
187- y1 = originY - (((row * 2 ) + 0 ) * halfVSpacing )
188- y2 = originY - (((row * 2 ) + 1 ) * halfVSpacing )
189- y3 = originY - (((row * 2 ) + 2 ) * halfVSpacing )
204+ y1 = y - (((row * 2 ) + 0 ) * halfVSpacing )
205+ y2 = y - (((row * 2 ) + 1 ) * halfVSpacing )
206+ y3 = y - (((row * 2 ) + 2 ) * halfVSpacing )
190207 else :
191- y1 = originY - (((row * 2 ) + 1 ) * halfVSpacing )
192- y2 = originY - (((row * 2 ) + 2 ) * halfVSpacing )
193- y3 = originY - (((row * 2 ) + 3 ) * halfVSpacing )
208+ y1 = y - (((row * 2 ) + 1 ) * halfVSpacing )
209+ y2 = y - (((row * 2 ) + 2 ) * halfVSpacing )
210+ y3 = y - (((row * 2 ) + 3 ) * halfVSpacing )
194211
195212 polyline = []
196213 polyline .append (QgsPoint (x1 , y2 ))
@@ -208,18 +225,26 @@ def _diamondGrid(self, writer, width, height, originX, originY,
208225 feedback .setProgress (int (count / cells * 100 ))
209226
210227 def _hexagonGrid (self , writer , width , height , originX , originY ,
211- hSpacing , vSpacing , feedback ):
228+ hSpacing , vSpacing , hOverlay , vOverlay , feedback ):
212229 ft = QgsFeature ()
213230
214231 # To preserve symmetry, hspacing is fixed relative to vspacing
215232 xVertexLo = 0.288675134594813 * vSpacing
216233 xVertexHi = 0.577350269189626 * vSpacing
217234 hSpacing = xVertexLo + xVertexHi
218235
219- halfVSpacing = vSpacing / 2
236+ hOverlay = hSpacing - hOverlay
237+ if hOverlay < 0 :
238+ raise GeoAlgorithmExecutionException (
239+ self .tr ('To preserve symmetry, hspacing is fixed relative to vspacing\n \
240+ hspacing is fixed at: %s and hoverlay is fixed at: %s\n \
241+ hoverlay cannot be negative. Increase hoverlay.' % (hSpacing , hOverlay )))
242+
243+ halfHSpacing = hSpacing / 2.0
244+ halfVSpacing = vSpacing / 2.0
220245
221- columns = int (math .ceil (float (width ) / hSpacing ))
222- rows = int (math .ceil (float (height ) / vSpacing ))
246+ columns = int (math .ceil (float (width ) / hOverlay ))
247+ rows = int (math .ceil (float (height ) / ( vSpacing - vOverlay ) ))
223248
224249 cells = rows * columns
225250 count_update = cells * 0.05
@@ -231,20 +256,20 @@ def _hexagonGrid(self, writer, width, height, originX, originY,
231256 # (column + 1) and (row + 1) calculation is used to maintain
232257 # topology between adjacent shapes and avoid overlaps/holes
233258 # due to rounding errors
234- x1 = originX + (col * hSpacing ) # far left
235- x2 = x1 + (xVertexHi - xVertexLo ) # left
236- x3 = originX + (( col + 1 ) * hSpacing ) # right
237- x4 = x3 + (xVertexHi - xVertexLo ) # far right
259+ x1 = originX + (col * hOverlay ) # far left
260+ x2 = x1 + (xVertexHi - xVertexLo ) # left
261+ x3 = originX + (col * hOverlay ) + hSpacing # right
262+ x4 = x3 + (xVertexHi - xVertexLo ) # far right
238263
239264 for row in range (rows ):
240265 if (col % 2 ) == 0 :
241- y1 = originY - (((row * 2 ) + 0 ) * halfVSpacing ) # hi
242- y2 = originY - (((row * 2 ) + 1 ) * halfVSpacing ) # mid
243- y3 = originY - (((row * 2 ) + 2 ) * halfVSpacing ) # lo
266+ y1 = originY + ( row * vOverlay ) - (((row * 2 ) + 0 ) * halfVSpacing ) # hi
267+ y2 = originY + ( row * vOverlay ) - (((row * 2 ) + 1 ) * halfVSpacing ) # mid
268+ y3 = originY + ( row * vOverlay ) - (((row * 2 ) + 2 ) * halfVSpacing ) # lo
244269 else :
245- y1 = originY - (((row * 2 ) + 1 ) * halfVSpacing ) # hi
246- y2 = originY - (((row * 2 ) + 2 ) * halfVSpacing ) # mid
247- y3 = originY - (((row * 2 ) + 3 ) * halfVSpacing ) # lo
270+ y1 = originY + ( row * vOverlay ) - (((row * 2 ) + 1 ) * halfVSpacing ) # hi
271+ y2 = originY + ( row * vOverlay ) - (((row * 2 ) + 2 ) * halfVSpacing ) # mid
272+ y3 = originY + ( row * vOverlay ) - (((row * 2 ) + 3 ) * halfVSpacing ) # lo
248273
249274 polyline = []
250275 polyline .append (QgsPoint (x1 , y2 ))
0 commit comments