Generating consistently-dimensioned polygons in mm units?
Your algorithm makes sense, but it seems that your problem is due to a rounding error when you divide by 2000 (divide by integer, which explains why a number smaller than two gives 0, and all distances are rounded to even values)
You should change the integer division with a float division
l = length / 2000
should be
l = length / 2000. # the . makes sure that you divide by a decimal value
or
l = float(length) / 2000
Note that this gives you the exact dimensions entered by the form, but you could decide to round the size of your parcels at one meter if you prefer:
l = float(length/1000) / 2
Note that you should also check the rounding at the start coordinates, but I do not know if this rounding is on purpose.
start_x = bbox.xMinimum() + float(distance_x) / 2
Thanks to @radouxju, here is the final code which also takes into account the horizontal and vertical distances being zero:
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)])
# Define variables
fid = 0
start_x = 0
start_y = 0
state_x = False
state_y = False
# Ensure polygons are not created 'within each other' if distance is zero;
# Instead they will align on the bounding box
if distance_x == 0:
distance_x = (length / 1000)
state_x = True
if distance_y == 0:
distance_y = (width / 1000)
state_y = True
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)
if state_x == False:
start_x += distance_x + (length / 1000)
else:
start_x += distance_x
start_x = bbox.xMinimum() + float(distance_x / 2)
if state_y == False:
start_y += distance_y + (width / 1000)
else:
start_y += distance_y
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 = float(length) / 2000
w = float(width) / 2000
return QgsGeometry.fromRect(QgsRectangle(x - l, y - w, x + l, y + w))
Using
generate_pv_panels(5500, 5000, 20, 1)
:
Using
generate_pv_panels(5500, 5000, 20, 0)
: