I have a polygon layer where there may be polygons and circular arcs as in the image.
How can I identify the polygons which have those arcs parts?
Working on the assumption that in an arc like in the posted screenshot, the distance between vertices will be very similar and the azimuth from one vertex to the next will change at a fairly constant rate, I cobbled together this messy code in the Python Console to test the idea:
lyr = iface.activeLayer()
for f in lyr.selectedFeatures():
geom = f.geometry()
for p in geom.parts():
verts = p.vertices()
p0 = verts.next()
p1 = verts.next()
dist = p0.distance(p1)
az = p0.azimuth(p1)
dev = 0
tol = 0.1
angular_tol_max = 10
angular_tol_min = 0.01
in_arc = False
for v in verts:
d = p1.distance(v)
a = p1.azimuth(v)
if((abs(d-dist)/dist) > tol):
dist = d
in_arc = False
else:
if (angular_tol_min < abs(az-a) < angular_tol_max) and dev != 0:
#print ("this might be an arc",((az-a)/dev))
if( (-tol) < ((az-a)/dev) > (tol)):
#print ("this realy might be an arc")
if in_arc == False:
rb = QgsRubberBand(iface.mapCanvas())
rb.setColor(QColor(255, 0, 0))
rb.setWidth(3)
rb.addPoint(QgsPointXY(p0.x(), p0.y()))
rb.addPoint(QgsPointXY(p1.x(), p1.y()))
rb.addPoint(QgsPointXY(v.x(), v.y()))
in_arc = True
else:
in_arc = False
else:
in_arc = False
p0 = p1
p1 = v
dev = az - a
az = a
It iterates through the vertices comparing the distance and azimuth to the previous vertex, when it detects a segment with a similar length and change in direction as the previous segment it assumes they are part of the arc. The tolerance can be changed by the value of the tol
variable (current value of 0.1 means up to 10% difference in segment length) and the angular_tol_max
and angular_tol_min
currently 10 and 0.01 meaning the azimuth change must be at less than 10 degrees and at at least 0.01 degrees.
It seems to work OK, I expect it would fail where the azimuth of adjacent segments changes from slightly less than 360 to slightly more than zero.
geom.wkbType()
return?