import numpy as np
Ojective to reach in meters squared
OBJECTIVE_METER_SQUARED = 14000.
Tolerance in meter squared of the objective to accept calculated result
TOLERANCE = 1.
Angle of the conic angled lines to the polygon centerline
centerline : northest point -> centroid point -> southest point
Check that the input polygon doesn't cross the two outer lines
if the input polygon crosses line, increase ANGLE_CONIC_CURVE
ANGLE_CONIC_CURVE = 30
Name of the polygon layer name in legend
POLY_NAME = "poly"
Get input polygon
poly_layer = QgsProject.instance().mapLayersByName(POLY_NAME)[0]
geom_poly = list(poly_layer.getFeatures())[0].geometry()
polygon = geom_poly.asPolygon()
Create centerline and conic curved outer lines
Find northest point and southest point
northest_point = None
southest_point = None
ymax = None
ymin = None
for list_poly_pt in polygon:
for pt in list_poly_pt:
if ymax is None or pt.y() > ymax:
ymax = pt.y()
northest_point = pt
if ymin is None or pt.y() < ymin:
ymin = pt.y()
southest_point = pt
centroid_point = geom_poly.centroid().asPoint()
Create the curved center line
curve_part = QgsCircularString()
curve_part.setPoints([
QgsPoint(northest_point),
QgsPoint(centroid_point),
QgsPoint(southest_point)
])
curve_feat = QgsFeature()
geom_curve = QgsGeometry(curve_part)
curve_feat.setGeometry(geom_curve)
Create the curved outer line 1
curve_feat_minus_angle = QgsFeature()
geom_minus_angle = QgsGeometry(geom_curve)
geom_minus_angle.rotate(ANGLE_CONIC_CURVE, northest_point)
curve_feat_minus_angle.setGeometry(geom_minus_angle)
Create the curved outer line 2
curve_feat_plus_angle = QgsFeature()
geom_plus_angle = QgsGeometry(geom_curve)
geom_plus_angle.rotate(-ANGLE_CONIC_CURVE, northest_point)
curve_feat_plus_angle.setGeometry(geom_plus_angle)
Export to legend the curved lines
curve_layer = QgsVectorLayer(
"LineString?crs=epsg:4326&index=yes",
"temporary_curve",
"memory"
)
curve_layer.setCrs(poly_layer.crs())
curve_layer.dataProvider().addFeatures([
curve_feat,
curve_feat_minus_angle,
curve_feat_plus_angle,
])
QgsProject.instance().addMapLayer(curve_layer)
Creates a curved cone shaped polygon that follow x pourcent of the
distance of the three curved lines passed in the parameters
def get_geom_interpolated_poly(curve0, curve1, curve2, pourcent):
dist0 = min(curve0.length()/100. * pourcent, curve0.length())
dist1 = min(curve1.length()/100. * pourcent, curve1.length())
dist2 = min(curve2.length()/100. * pourcent, curve2.length())
pt_start = curve0.constGet().startPoint()
pt0 = curve0.interpolate(dist0).asPoint()
pt1 = curve1.interpolate(dist1).asPoint()
pt_half1 = curve1.interpolate(dist1/2).asPoint()
pt2 = curve2.interpolate(dist2).asPoint()
pt_half2 = curve2.interpolate(dist2/2).asPoint()
line = QgsLineString([])
curve_part1 = QgsCircularString()
curve_part1.setPoints([
pt_start,
QgsPoint(pt_half1),
QgsPoint(pt1)
])
curve_part0 = QgsCircularString()
curve_part0.setPoints([
QgsPoint(pt1),
QgsPoint(pt0),
QgsPoint(pt2)
])
curve_part2 = QgsCircularString()
curve_part2.setPoints([
QgsPoint(pt2),
QgsPoint(pt_half2),
pt_start,
])
curve = line.toCurveType()
curve.addCurve(curve_part1)
curve.addCurve(curve_part0)
curve.addCurve(curve_part2)
polygon = QgsPolygon()
polygon.setExteriorRing(curve)
return QgsGeometry(polygon)
def calculate_area(poly_ori, poly_cur):
inter = poly_ori.intersection(poly_cur)
return inter, inter.area()
pourcent_change = 10
current_area = None
current_geom = None
dif_area = None
under = (OBJECTIVE_METER_SQUARED - TOLERANCE)
over = (OBJECTIVE_METER_SQUARED + TOLERANCE)
pourcent_under = 0
pourcent_over = 100
While the current area calculated is not close enough to the objective
the pourcent_change gets smaller and smaller unter the area calulated
is under the tolerance from the objective area
while current_area is None or not (under <= current_area <= over):
for pourcent in np.arange(pourcent_under, pourcent_over+1, pourcent_change):
cur_geom = get_geom_interpolated_poly(
geom_curve,
geom_minus_angle,
geom_plus_angle,
pourcent
)
current_geom , current_area = calculate_area(geom_poly, cur_geom)
if current_area <= OBJECTIVE_METER_SQUARED:
pourcent_under = pourcent
else:
pourcent_over = pourcent
break
pourcent_change /= 10
Create polygon feature
poly_feat = QgsFeature()
poly_feat.setGeometry(current_geom)
Create a memory layer
layer_out = QgsVectorLayer(
"Polygon?crs=epsg:4326&index=yes",
"Output Polygon",
"memory"
)
layer_out.setCrs(poly_layer.crs())
layer_out.dataProvider().addFeatures([poly_feat])
QgsProject.instance().addMapLayer(layer_out)