273 lines
10 KiB
Python
Raw Normal View History

2014-10-03 09:49:29 +03:00
# -*- coding: utf-8 -*-
"""
***************************************************************************
Grid.py
2014-10-03 09:49:29 +03:00
---------------------
Date : May 2010
Copyright : (C) 2010 by Michael Minn
Email : pyqgis at michaelminn dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
"""
__author__ = 'Michael Minn'
__date__ = 'May 2010'
__copyright__ = '(C) 2010, Michael Minn'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
2014-10-04 14:02:29 +03:00
import math
2014-10-03 09:49:29 +03:00
from PyQt4.QtCore import *
from qgis.core import *
from processing.core.GeoAlgorithm import GeoAlgorithm
from processing.core.GeoAlgorithmExecutionException import \
GeoAlgorithmExecutionException
from processing.core.parameters import ParameterExtent
2014-10-03 09:49:29 +03:00
from processing.core.parameters import ParameterNumber
from processing.core.parameters import ParameterCrs
from processing.core.parameters import ParameterSelection
from processing.core.outputs import OutputVector
class Grid(GeoAlgorithm):
TYPE = 'TYPE'
EXTENT = 'EXTENT'
2014-10-03 09:49:29 +03:00
WIDTH = 'WIDTH'
HEIGHT = 'HEIGHT'
HSPACING = 'HSPACING'
VSPACING = 'VSPACING'
CENTERX = 'CENTERX'
CENTERY = 'CENTERY'
CRS = 'CRS'
OUTPUT = 'OUTPUT'
TYPES = ['Rectangle (line)',
'Rectangle (polygon)',
'Diamond (polygon)',
'Hexagon (polygon)'
]
def defineCharacteristics(self):
self.name = 'Create grid'
self.group = 'Vector creation tools'
2015-01-15 20:41:15 +02:00
self.addParameter(ParameterSelection(self.TYPE,
self.tr('Grid type'), self.TYPES))
self.addParameter(ParameterExtent(self.EXTENT,
self.tr('Grid extent')))
self.addParameter(ParameterNumber(self.HSPACING,
self.tr('Horizontal spacing'), default=10.0))
self.addParameter(ParameterNumber(self.VSPACING,
self.tr('Vertical spacing'), default=10.0))
2014-10-03 09:49:29 +03:00
2015-01-15 20:41:15 +02:00
self.addOutput(OutputVector(self.OUTPUT, self.tr('Output')))
2014-10-03 09:49:29 +03:00
def processAlgorithm(self, progress):
idx = self.getParameterValue(self.TYPE)
extent = self.getParameterValue(self.EXTENT).split(',')
2014-10-03 09:49:29 +03:00
hSpacing = self.getParameterValue(self.HSPACING)
vSpacing = self.getParameterValue(self.VSPACING)
bbox = QgsRectangle(float(extent[0]), float(extent[2]),
float(extent[1]), float(extent[3]))
width = bbox.width()
height = bbox.height()
centerX = bbox.center().x()
centerY = bbox.center().y()
2014-10-03 09:49:29 +03:00
originX = centerX - width / 2.0
originY = centerY - height / 2.0
crs = QgsCoordinateReferenceSystem(self.getParameterValue(self.CRS))
if hSpacing <= 0 or vSpacing <= 0:
raise GeoAlgorithmExecutionException(
2015-01-15 20:41:15 +02:00
self.tr('Invalid grid spacing: %s/%s' % (hSpacing, vSpacing)))
2014-10-03 09:49:29 +03:00
if width < hSpacing:
raise GeoAlgorithmExecutionException(
2015-01-15 20:41:15 +02:00
self.tr('Horizontal spacing is too small for the covered area'))
2014-10-03 09:49:29 +03:00
if height < vSpacing:
raise GeoAlgorithmExecutionException(
2015-01-15 20:41:15 +02:00
self.tr('Vertical spacing is too small for the covered area'))
2014-10-03 09:49:29 +03:00
if self.TYPES[idx].find('polygon') >= 0:
geometryType = QGis.WKBPolygon
else:
geometryType = QGis.WKBLineString
fields = [QgsField('left', QVariant.Double, '', 24, 16),
QgsField('top', QVariant.Double, '', 24, 16),
QgsField('right', QVariant.Double, '', 24, 16),
QgsField('bottom', QVariant.Double, '', 24, 16)
2014-10-03 09:49:29 +03:00
]
writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields,
geometryType, crs)
if idx == 0:
self._rectangleGridLine(
writer, width, height, originX, originY, hSpacing, vSpacing)
elif idx == 1:
self._rectangleGridPoly(
writer, width, height, originX, originY, hSpacing, vSpacing)
elif idx == 2:
self._diamondGrid(
writer, width, height, originX, originY, hSpacing, vSpacing)
elif idx == 3:
self._hexagonGrid(
writer, width, height, originX, originY, hSpacing, vSpacing)
del writer
def _rectangleGridLine(self, writer, width, height, originX, originY,
hSpacing, vSpacing):
2014-10-03 09:49:29 +03:00
ft = QgsFeature()
2014-10-04 14:02:29 +03:00
columns = int(math.floor(float(width) / hSpacing))
rows = int(math.floor(float(height) / vSpacing))
2014-10-03 09:49:29 +03:00
# Longitude lines
for col in xrange(0, columns + 1):
polyline = []
x = originX + (col * hSpacing)
for row in xrange(0, rows + 1):
y = originY + (row * vSpacing)
2014-10-03 09:49:29 +03:00
polyline.append(QgsPoint(x, y))
ft.setGeometry(QgsGeometry.fromPolyline(polyline))
ft.setAttributes([x, originY, x, originY + (rows * vSpacing)])
2014-10-03 09:49:29 +03:00
writer.addFeature(ft)
# Latitude lines
for row in xrange(0, rows + 1):
2014-10-03 09:49:29 +03:00
polyline = []
y = originY + (row * vSpacing)
for col in xrange(0, columns + 1):
x = originX + (col * hSpacing)
2014-10-03 09:49:29 +03:00
polyline.append(QgsPoint(x, y))
ft.setGeometry(QgsGeometry.fromPolyline(polyline))
ft.setAttributes([originX, y, originX + (col * hSpacing), y])
writer.addFeature(ft)
2014-10-03 09:49:29 +03:00
def _rectangleGridPoly(self, writer, width, height, originX, originY,
hSpacing, vSpacing):
2014-10-03 09:49:29 +03:00
ft = QgsFeature()
2014-10-04 14:02:29 +03:00
columns = int(math.floor(float(width) / hSpacing))
rows = int(math.floor(float(height) / vSpacing))
for col in xrange(0, columns):
# (column + 1) and (row + 1) calculation is used to maintain
# topology between adjacent shapes and avoid overlaps/holes
# due to rounding errors
x1 = originX + (col * hSpacing)
x2 = originX + ((col + 1) * hSpacing)
for row in xrange(0, rows):
y1 = originY + (row * vSpacing)
y2 = originY + ((row + 1) * vSpacing)
2014-10-03 09:49:29 +03:00
polyline = []
polyline.append(QgsPoint(x1, y1))
polyline.append(QgsPoint(x2, y1))
polyline.append(QgsPoint(x2, y2))
polyline.append(QgsPoint(x1, y2))
polyline.append(QgsPoint(x1, y1))
2014-10-03 09:49:29 +03:00
ft.setGeometry(QgsGeometry.fromPolygon([polyline]))
ft.setAttributes([x1, y1, x2, y2])
2014-10-03 09:49:29 +03:00
writer.addFeature(ft)
def _diamondGrid(self, writer, width, height, originX, originY,
hSpacing, vSpacing):
2014-10-03 09:49:29 +03:00
ft = QgsFeature()
halfHSpacing = hSpacing / 2
halfVSpacing = vSpacing / 2
2014-10-04 14:02:29 +03:00
columns = int(math.floor(float(width) / halfHSpacing))
rows = int(math.floor(float(height) / vSpacing))
for col in xrange(0, columns):
x1 = originX + ((col + 0) * halfHSpacing)
x2 = originX + ((col + 1) * halfHSpacing)
x3 = originX + ((col + 2) * halfHSpacing)
for row in xrange(0, rows):
if (col % 2) == 0:
y1 = originY + (((row * 2) + 0) * halfVSpacing)
y2 = originY + (((row * 2) + 1) * halfVSpacing)
y3 = originY + (((row * 2) + 2) * halfVSpacing)
else:
y1 = originY + (((row * 2) + 1) * halfVSpacing)
y2 = originY + (((row * 2) + 2) * halfVSpacing)
y3 = originY + (((row * 2) + 3) * halfVSpacing)
2014-10-03 09:49:29 +03:00
polyline = []
polyline.append(QgsPoint(x1, y2))
polyline.append(QgsPoint(x2, y1))
polyline.append(QgsPoint(x3, y2))
polyline.append(QgsPoint(x2, y3))
polyline.append(QgsPoint(x1, y2))
2014-10-03 09:49:29 +03:00
ft.setGeometry(QgsGeometry.fromPolygon([polyline]))
ft.setAttributes([x1, y1, x3, y3])
2014-10-03 09:49:29 +03:00
writer.addFeature(ft)
def _hexagonGrid(self, writer, width, height, originX, originY,
hSpacing, vSpacing):
2014-10-03 09:49:29 +03:00
ft = QgsFeature()
# To preserve symmetry, hspacing is fixed relative to vspacing
xVertexLo = 0.288675134594813 * vSpacing;
xVertexHi = 0.577350269189626 * vSpacing;
2014-10-03 09:49:29 +03:00
hSpacing = xVertexLo + xVertexHi
halfVSpacing = vSpacing / 2
2014-10-04 14:02:29 +03:00
columns = int(math.floor(float(width) / hSpacing))
rows = int(math.floor(float(height) / vSpacing))
for col in xrange(0, columns):
# (column + 1) and (row + 1) calculation is used to maintain
# topology between adjacent shapes and avoid overlaps/holes
# due to rounding errors
x1 = originX + (col * hSpacing) # far left
x2 = x1 + (xVertexHi - xVertexLo) # left
x3 = originX + ((col + 1) * hSpacing) # right
x4 = x3 + (xVertexHi - xVertexLo) # far right
for row in xrange(0, rows):
if (col % 2) == 0:
y1 = originY + (((row * 2) + 0) * halfVSpacing) # hi
y2 = originY + (((row * 2) + 1) * halfVSpacing) # mid
y3 = originY + (((row * 2) + 2) * halfVSpacing) # lo
else:
y1 = originY + (((row * 2) + 1) * halfVSpacing) # hi
y2 = originY + (((row * 2) + 2) * halfVSpacing) # mid
y3 = originY + (((row * 2) + 3) * halfVSpacing) # lo
2014-10-03 09:49:29 +03:00
polyline = []
polyline.append(QgsPoint(x1, y2))
polyline.append(QgsPoint(x2, y1))
polyline.append(QgsPoint(x3, y1))
polyline.append(QgsPoint(x4, y2))
polyline.append(QgsPoint(x3, y3))
polyline.append(QgsPoint(x2, y3))
polyline.append(QgsPoint(x1, y2))
2014-10-03 09:49:29 +03:00
ft.setGeometry(QgsGeometry.fromPolygon([polyline]))
ft.setAttributes([x1, y1, x4, y3])
2014-10-03 09:49:29 +03:00
writer.addFeature(ft)