I have a function which creates Solar Photovolatic panels represented as polygons. Essentially, it creates a rectangular grid where the user can specify the following parameters:
- Length
- Width
- Horizontal distance
- Vertical distance
The code is based on the plugin FeatureGridCreator but focusing only on the polygon aspect. It works well for the most part, especially when creating polygons with large dimensions (e.g. 10m length and width; 10m horizontal and vertical distances).
But I noticed a couple of issues:
When specifying polygons for dimensions less than 2m for both length and width, no polygons were created.
When specifying polygons with differing dimensions (e.g. 5m length and 7m width), the dimensions were not the same when measured with the Measure Line tool. For these dimensions, the length and width were shown to be 4m and 6m respectively.
The CRS used for both the projection and layer is EPSG:27700 although I wouldn't have thought this would be a problem.
So does anyone have any idea what could be causing these issues? I am also open to suggestions as to how the code could be improved or even replaced with a better alternative.
Here is the code which can be reproduced in the Python Console, a polygon layer must be selected with a relevant CRS before running the function:
from PyQt4.QtCore import QVariant
from math import ceil
def generate_pv_panels(length, width, distance_x, distance_y):
# Define layer properties
layer = iface.activeLayer()
crs = layer.crs()
memory_lyr = QgsVectorLayer("Polygon?crs=epsg:" + unicode(crs.postgisSrid()) + "&index=yes", "PV panels for " + str(layer.name()), "memory")
QgsMapLayerRegistry.instance().addMapLayer(memory_lyr)
memory_lyr.startEditing()
provider = memory_lyr.dataProvider()
provider.addAttributes([QgsField("ID", QVariant.Int)])
fid = 0
start_x = 0
start_y = 0
# Ensure polygons are not created 'within each other'
if distance_x < (length / 1000):
distance_x = (length / 1000)
if distance_y < (width / 1000):
distance_y = (width / 1000)
fts = []
for f in layer.getFeatures():
fid += 1
bbox = f.geometry().boundingBox()
start_x = bbox.xMinimum() + float(distance_x / 2)
start_y = bbox.yMinimum() + float(distance_y / 2)
for row in range(0, int(ceil(bbox.height() / distance_y))):
for column in range(0, int(ceil(bbox.width() / distance_x))):
fet = QgsFeature()
geom_type = pv_panel_size(length, width, start_x, start_y)
if f.geometry().contains(geom_type):
fet.setGeometry(geom_type)
fet.setAttributes([fid])
fts.append(fet)
start_x += distance_x + (length / 1000)
start_x = bbox.xMinimum() + float(distance_x / 2)
start_y += distance_y + (width / 1000)
provider.addFeatures(fts)
memory_lyr.updateFields()
memory_lyr.commitChanges()
def pv_panel_size(length, width, x, y):
# Length & width measured in mm; x & y measured in m
l = length / 2000
w = width / 2000
return QgsGeometry.fromRect(QgsRectangle(x - l, y - w, x + l, y + w))
generate_pv_panels(10000, 10000, 100, 100)