Modifying polygons to be more rectangular using PyQGIS
Next code uses analytical geometry to change each polygon quasi rectangular in rectangular and it could be used:
layer = iface.activeLayer()
feats = [ feat for feat in layer.getFeatures() ]
n = len(feats)
crs = layer.crs()
epsg = crs.postgisSrid()
uri = "Polygon?crs=epsg:" + str(epsg) + "&field=id:integer""&index=yes"
mem_layer = QgsVectorLayer(uri,
'rectangle',
'memory')
prov = mem_layer.dataProvider()
for feature in feats:
geom = feature.geometry()
xmin, ymin, xmax, ymax = geom.boundingBox().toRectF().getCoords()
points = feature.geometry().asPolygon()[0]
for i in range(len(points)-1):
if points[i][1] == ymax and points[i+1][1] < points[i][1]:
idx = i
if points[i][1] == ymax and points[i-1][1] < points[i][1]:
idx = i-1
rectangle = []
#x,y coordinates of first point
x1 = points[idx][0]
y1 = points[idx][1]
rectangle.append(QgsPoint(x1,y1))
#x,y coordinates of second point
x2 = points[idx+1][0]
y2 = points[idx+1][1]
rectangle.append(QgsPoint(x2,y2))
#slope for first line
m1 = (y2 - y1) / (x2 - x1)
#intercept at origin for first line
int1 = y1 - m1 * x1
#slope for second line
m2 = m1
#x,y coordinates of third point
x3 = points[idx+2][0]
y3 = points[idx+2][1]
#intercept at origin for second line
int2 = y3 - m2 * x3
#first perpendicular
m3 = -1/m1
#intercept at origin for second line
int3 = y2 - m3 * x2
#intersect point
x4 = (int3 - int2)/(m2 - m3)
y4 = m3*x4 + int3
rectangle.append(QgsPoint(x4, y4))
#second perpendicular
m4 = -1/m1
#intercept at origin for second perpendicular
int4 = y1 - m4 * x1
#intersect point
x5 = (int4 - int2)/(m2 - m4)
y5 = m4*x5 + int4
rectangle.extend([QgsPoint(x5, y5),QgsPoint(x1, y1)])
polygon = []
polygon.append(rectangle)
geom = QgsGeometry.fromPolygon(polygon)
feat = QgsFeature()
feat.setAttributes([i])
feat.setGeometry(geom)
prov.addFeatures( [feat] )
QgsMapLayerRegistry.instance().addMapLayer(mem_layer)
I tried it out with shapefile of next image:
After running the code at the Python Console of QGIS I got:
You can try to use the following approach that changes the geometry based on the bounding box and the angle of the first digitized edge. You can of course alter the angle with the one from the longest edge or something. Only works well when your polygons are near rectangular already (as it looks like).
Input in the console in Qgis and the layer needs to be selected and editable:
import shapely
from shapely import affinity
from shapely.wkb import loads
layer = qgis.utils.iface.activeLayer()
for feature in layer.getFeatures():
azimuth = feature.geometry().vertexAt(0).azimuth(feature.geometry().vertexAt(1))
bbox = QgsGeometry.fromRect(feature.geometry().boundingBox())
input = loads(bbox.asWkb())
shape = shapely.geometry.asShape(input)
rotated = affinity.rotate(shape, azimuth-90.0)
new_geom = QgsGeometry.fromWkt(rotated.wkt)
layer.changeGeometry(feature.id(),new_geom)