I want to calculate the "diameter" of polygons in QGIS. The "diameter" is defined as the distance between the two most distant points of the polygon.
I couldn't find a fitting solution in the Field Calculator.
Maybe you have some ideas?
I want to calculate the "diameter" of polygons in QGIS. The "diameter" is defined as the distance between the two most distant points of the polygon.
I couldn't find a fitting solution in the Field Calculator.
Maybe you have some ideas?
You can use PyQGIS to measure the distances between all vertices of each polygon and find max:
import itertools
layer = iface.activeLayer() #Click layer in tree
for feat in layer.getFeatures():
verts = [v for v in feat.geometry().vertices()] #List all vertices
maxdistance = max([p1.distance(p2) for p1,p2 in itertools.combinations(verts, 2)]) #Find max distance for all combinations of vertices (https://stackoverflow.com/questions/464864/how-to-get-all-possible-combinations-of-a-list-s-elements)
print('Polygon: {0}, max distance: {1}'.format(feat.id(), round(maxdistance,0))) #Print results
To save max distances in a field:
import itertools
layer = iface.activeLayer() #Click layer in tree
field_to_save_maxdistance_in = 'maxdist' #Change maxdist to the name of your field
fields = layer.fields()
fx = fields.indexFromName(field_to_save_maxdistance_in)
with edit(layer):
for feat in layer.getFeatures():
verts = [v for v in feat.geometry().convexHull().vertices()] #List all vertices
maxdistance = max([p1.distance(p2) for p1,p2 in itertools.combinations(verts, 2)]) #Find max distance for all combinations of vertices
layer.changeAttributeValue(feat.id(), fx, maxdistance)
You can also create a line layer:
import itertools
layer = iface.activeLayer() #Click layer in tree
#Create line layer
vl = QgsVectorLayer("LineString?crs={}&index=yes".format(layer.crs().authid()), "myLayer", "memory")
provider = vl.dataProvider()
#For each polygon find the two points most far apart
for feat in layer.getFeatures():
all_points = []
verts = [v for v in feat.geometry().vertices()] #List all vertices
for p1,p2 in itertools.combinations(verts, 2):
all_points.append([p1,p2])
#Create a line feature
pointpair_most_far_apart = max(all_points, key=lambda x: x[0].distance(x[1]))
gLine = QgsGeometry.fromPolyline(pointpair_most_far_apart)
f = QgsFeature()
f.setGeometry(gLine)
provider.addFeature(f)
QgsProject.instance().addMapLayer(vl)
Bear in mind that someone correctly pointed out very soon in comments that I had misread the question. My answer gives the diameter of the minimal circle but this does not always correspond to the longest distance between vertices in a polygon. As soon as more than two vertices touch the circle or if the vertices defining the circle are adjacent, the values can differ. I left it there as it provides an answer for a similar problem but even I agree it should not be the accepted answer.
It is possible to do this with simple expressions in the Field Calculator (at least in QGIS 3.12.x). Take for example these two polygons. The symbology shows four things (using the Geometry Generator, for explanation purposes):
minimal_circle()
functioncentroid()
function of the minimal circlepoint_n()
function of the minimal circle's first vertexSo to get the diameter of the minimal circle containing the polygon, go to the field calculator and use this expression in a new decimal field:
distance(centroid(minimal_circle($geometry)), point_n(minimal_circle($geometry), 1)) * 2
This will calculate the distance between the centroid and the first vertex along the circle (the radius), then multiply it by two.
Let's assume there is a polygon layer 'Layer_A' (blue) with its corresponding attribute table accordingly, see the image below.
Step 1. Apply the "Polygons to lines" geoalgorithm
Step 2. Proceed with "Points along geometry". Mind that the distance affects the quality of the final result and the efficiency of the Virtual Layer in Step 3.
Step 3. By means of a "Virtual Layer" through Layer > Add Layer > Add/Edit Virtual Layer...
use this query
SELECT p1.id,
setsrid(make_line(p1.geometry, p2.geometry), 'put your srid here'),
max(st_length(make_line(p1.geometry, p2.geometry))) AS length
FROM "Points" AS p1
JOIN "Points" AS p2 ON p1.id = p2.id
WHERE NOT st_equals(p1.geometry, p2.geometry)
GROUP BY p1.id
P.S. if you are interested in the longest distances between vertices, then extract vertices from the polygon via "Extract vertices" and go directly to Step 3.
If you have your data in PostGIS you can use these functions:
ST_MinimumBoundingCircle()
: https://postgis.net/docs/ST_MinimumBoundingCircle.html
Returns the smallest circle polygon that can fully contain a geometry.
ST_MinimumBoundingRadius()
: https://postgis.net/docs/ST_MinimumBoundingRadius.html
Returns a record containing the center point and radius of the smallest circle that can fully contain a geometry.