14

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?

2
  • 2
    Conceptually thinking: get the smallest possible bounding box (tool), then you should be able to calculate the length of the diagonal using area & perimeter.
    – Erik
    Commented May 13, 2020 at 13:36
  • Please, do not forget about "What should I do when someone answers my question?"
    – Taras
    Commented Jul 24, 2023 at 9:37

4 Answers 4

14

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

example1

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)

example2

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)

enter image description here

3
  • This seems like exactly what I want to do! Since I am not familiar with Python and pyqgis: is there a way to save the maximum distance that the console is showing me as a column in my layer? So I can continue using it for my following calculations. Commented May 13, 2020 at 13:55
  • Somehow the newest code doesn't work. I get a "SyntaxError: invalid syntax" error or QGIS just shuts down while trying to run it. The first one you posted without saving it to my layer worked perfectly. Commented May 13, 2020 at 14:23
  • 1
    Added it as a real type. But now it somehow worked. QGIS shut down again and when I restarted it, the column was there and the results seem correct. Weird indeed! But anyways, thank you! This has helped me a lot already! Commented May 13, 2020 at 14:34
13

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):

  • Red outline of the true polygon
  • Semi-transparent orange circle resulting from the minimal_circle() function
  • Blue point resulting from the centroid() function of the minimal circle
  • White point resulting from the point_n() function of the minimal circle's first vertex

enter image description here

So 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.

12
  • 1
    @Jan-PieterVanParys There we go. Expressions have received a LOT of love since then.
    – Gabriel
    Commented May 13, 2020 at 15:37
  • 1
    @Jan-PieterVanParys You can go with the current LTR, 3.10.5. It should be quite stable although you will probably need a little bit of adjusting to the new UI and ways of doing things.
    – Gabriel
    Commented May 13, 2020 at 15:41
  • 1
    What about an Equilateral triangle? I think the diameter of the circle is bigger than the longest edge of the triangle... Your solution works only for polygons for which the smallest circle touches only two vertices.
    – Legisey
    Commented May 25, 2020 at 11:54
  • 1
    @Legisey Yes, triangles don't work well. That's something to keep in mind, but I've observed that they aren't very common in the datasets I've had to use. It could be possible to aggregate the distances from the centroid to each vertex then build a minimal circle from the two largest value points. I'll try that out. edit Also I think it was maybe a problem with the question as asked as the diameter (minimal circle) can often be different from the distance between the two most distant vertices.
    – Gabriel
    Commented May 25, 2020 at 12:58
  • 1
    @GabrielC. so you're not looking for the "the distance between the two most distant points of the polygon" as stated in the question? Are you looking for the diameter of the smallest circle that fully contains the shape? It's not the same thing, even though in some cases (like the ones of this answer) it will be the same. It's not only in triangles that there is a difference, it is also the case with most shapes that have more than two vertices that touches the circle. I think this is not a correct answer to the question. So either you asked the wrong question, or accepted the wrong answer.
    – Legisey
    Commented May 26, 2020 at 8:34
5

Let's assume there is a polygon layer 'Layer_A' (blue) with its corresponding attribute table accordingly, see the image below.

input

Step 1. Apply the "Polygons to lines" geoalgorithm

step_1

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_2

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

result

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.

step_1_2_alternative

4
  • I just tried this and unfortunately QGIS can't finish the third step. It runs for a long time already, but never ends. Commented May 13, 2020 at 15:10
  • How many points did you generate ? How many polygons do you have ?
    – Taras
    Commented May 13, 2020 at 18:01
  • I have more than 400 polygons and I've got 371939 points. Maybe those are too many? Commented May 23, 2020 at 11:51
  • yes, you are right
    – Taras
    Commented Jun 26, 2020 at 9:35
5

If you have your data in PostGIS you can use these functions:

  1. ST_MinimumBoundingCircle() : https://postgis.net/docs/ST_MinimumBoundingCircle.html

    Returns the smallest circle polygon that can fully contain a geometry.

  2. 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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.