Skip to content

Commit 01cd784

Browse files
lbartolettinyalldawson
authored andcommitted
[FEATURE][processing] Add overlay option to GridLine and GridPolygon
1 parent 1f3c67f commit 01cd784

11 files changed

Lines changed: 1443 additions & 41 deletions

‎python/plugins/processing/algs/qgis/GridLine.py‎

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ class GridLine(GeoAlgorithm):
5454
EXTENT = 'EXTENT'
5555
HSPACING = 'HSPACING'
5656
VSPACING = 'VSPACING'
57+
HOVERLAY = 'HOVERLAY'
58+
VOVERLAY = 'VOVERLAY'
5759
CRS = 'CRS'
5860
OUTPUT = 'OUTPUT'
5961

@@ -71,6 +73,10 @@ def defineCharacteristics(self):
7173
self.tr('Horizontal spacing'), 0.0, 1000000000.0, default=0.0001))
7274
self.addParameter(ParameterNumber(self.VSPACING,
7375
self.tr('Vertical spacing'), 0.0, 1000000000.0, default=0.0001))
76+
self.addParameter(ParameterNumber(self.HOVERLAY,
77+
self.tr('Horizontal overlay'), 0.0, 1000000000.0, default=0.0))
78+
self.addParameter(ParameterNumber(self.VOVERLAY,
79+
self.tr('Vertical overlay'), 0.0, 1000000000.0, default=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_LINE]))
@@ -79,6 +85,8 @@ def processAlgorithm(self, feedback):
7985
extent = self.getParameterValue(self.EXTENT).split(',')
8086
hSpacing = self.getParameterValue(self.HSPACING)
8187
vSpacing = self.getParameterValue(self.VSPACING)
88+
hOverlay = self.getParameterValue(self.HOVERLAY)
89+
vOverlay = self.getParameterValue(self.VOVERLAY)
8290
crs = QgsCoordinateReferenceSystem(self.getParameterValue(self.CRS))
8391

8492
bbox = QgsRectangle(float(extent[0]), float(extent[2]),
@@ -91,6 +99,10 @@ def processAlgorithm(self, feedback):
9199
raise GeoAlgorithmExecutionException(
92100
self.tr('Invalid grid spacing: %s/%s' % (hSpacing, vSpacing)))
93101

102+
if hSpacing <= hOverlay or vSpacing <= vOverlay:
103+
raise GeoAlgorithmExecutionException(
104+
self.tr('Invalid overlay: %s/%s' % (hOverlay, vOverlay)))
105+
94106
if width < hSpacing:
95107
raise GeoAlgorithmExecutionException(
96108
self.tr('Horizontal spacing is too small for the covered area'))
@@ -110,6 +122,16 @@ def processAlgorithm(self, feedback):
110122
writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields,
111123
QgsWkbTypes.LineString, crs)
112124

125+
if hOverlay > 0:
126+
hSpace = [hSpacing - hOverlay, hOverlay]
127+
else:
128+
hSpace = [hSpacing, hSpacing]
129+
130+
if vOverlay > 0:
131+
vSpace = [vSpacing - vOverlay, vOverlay]
132+
else:
133+
vSpace = [vSpacing, vSpacing]
134+
113135
feat = QgsFeature()
114136
feat.initAttributes(len(fields))
115137

@@ -133,7 +155,7 @@ def processAlgorithm(self, feedback):
133155
id,
134156
y])
135157
writer.addFeature(feat)
136-
y = y - vSpacing
158+
y = y - vSpace[count % 2]
137159
id += 1
138160
count += 1
139161
if int(math.fmod(count, count_update)) == 0:
@@ -160,7 +182,7 @@ def processAlgorithm(self, feedback):
160182
id,
161183
x])
162184
writer.addFeature(feat)
163-
x = x + hSpacing
185+
x = x + hSpace[count % 2]
164186
id += 1
165187
count += 1
166188
if int(math.fmod(count, count_update)) == 0:

‎python/plugins/processing/algs/qgis/GridPolygon.py‎

Lines changed: 64 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -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))
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<GMLFeatureClassList>
2+
<GMLFeatureClass>
3+
<Name>grid_diamond_overlay</Name>
4+
<ElementPath>grid_diamond_overlay</ElementPath>
5+
<!--POLYGON-->
6+
<GeometryType>3</GeometryType>
7+
<SRSName>EPSG:4326</SRSName>
8+
<DatasetSpecificInfo>
9+
<FeatureCount>45</FeatureCount>
10+
<ExtentXMin>-1.00000</ExtentXMin>
11+
<ExtentXMax>16.00000</ExtentXMax>
12+
<ExtentYMin>-8.00000</ExtentYMin>
13+
<ExtentYMax>6.50000</ExtentYMax>
14+
</DatasetSpecificInfo>
15+
<PropertyDefn>
16+
<Name>left</Name>
17+
<ElementPath>left</ElementPath>
18+
<Type>Real</Type>
19+
</PropertyDefn>
20+
<PropertyDefn>
21+
<Name>top</Name>
22+
<ElementPath>top</ElementPath>
23+
<Type>Real</Type>
24+
</PropertyDefn>
25+
<PropertyDefn>
26+
<Name>right</Name>
27+
<ElementPath>right</ElementPath>
28+
<Type>Real</Type>
29+
</PropertyDefn>
30+
<PropertyDefn>
31+
<Name>bottom</Name>
32+
<ElementPath>bottom</ElementPath>
33+
<Type>Real</Type>
34+
</PropertyDefn>
35+
<PropertyDefn>
36+
<Name>id</Name>
37+
<ElementPath>id</ElementPath>
38+
<Type>Integer</Type>
39+
</PropertyDefn>
40+
</GMLFeatureClass>
41+
</GMLFeatureClassList>

0 commit comments

Comments
 (0)