6

I need to calculate the distance between the furthest vertex of a Voronoi polygon and the point that generated it. I need to calculate this distance for all Voronoi polygons.

Is there a way to do it automatically using QGIS?

I attach an image to give the idea, in which I would like to calculate the length of the highlighted yellow line. I also report some sample data from my layer containing the Voronoi polygons (TOPOIETI + IMP) and from the layer of the points from which they were generated (NODI TOPOIETI).

enter image description here

enter image description here

enter image description here

  • this should be possible using the expression engine, but will be pretty complicated as you will need to get the point that intersects with each polygon, then extract the nodes of that polygon, then calculate an array of distances to each node and then get the maximum value of that array. all of that in a single expression. not impossible, but very complicated. – Dror Bogin May 24 at 6:12
  • Thanks for your answer, for now I have just extracted the vertices of the polygons and from the attribute table I know which points belong to a given polygon, at this point should I calculate a Distance Matrix from my layer of internal points? Thanks for your help. – Enrico Lochi May 24 at 9:24
  • I try to use the GRASS v.distance function and and the algorithm identifies the distances but not respect to all the vertices of each polygon, do you know how I can improve the result? thank you so much for your help. – Enrico Lochi May 24 at 9:36
  • you can do something like this in the field calculator to get a distance matrix for each vertex distance( nodes_to_points( layer_property( 'polygon layer',$geometry),$geometry) – Dror Bogin May 24 at 11:04
  • Thanks for your suggestion, I tried to insert your expression as a field inside the layer containing the vertices of the polygons, but I get the error "distance function is called with wrong number of arguments. Expected 2 but got 1". Sorry for the inconvenience and thank you for your help. – Enrico Lochi May 24 at 12:10
5

You can use the following script. Paste the script into QGIS Python Editor. Change layers' name in the first two lines and common field name and run.

# get layers
Voronoi = QgsProject.instance().mapLayersByName("Voronoi")[0]
Points = QgsProject.instance().mapLayersByName("Points")[0]

def to_geom(vertex): # for creating QgsGeometry from vertex
    return QgsGeometry.fromPointXY(QgsPointXY(vertex))

Voronoi.startEditing()

# add "max_dist" field if it doesn't exist
if Voronoi.fields().indexFromName('max_dist') == -1: 
    Voronoi.addAttribute(QgsField('max_dist', 6, len=10, prec=3)) # 6 means Double

for vor in Voronoi.getFeatures():    
    # get Voronoi cell point geometry. there is only one point
    request = "POINT_ID = '{0}'".format(vor["POINT_ID"]) # POINT_ID is a string here
    point = list(Points.getFeatures(request))[0].geometry()

    # vertices of Voronoi polygon
    vx = vor.geometry().vertices() 

    # distances to all vertices from point
    distances = [point.distance(to_geom(v)) for v in vx]
    vor['max_dist'] = max(distances)

    Voronoi.updateFeature(vor)

Voronoi.commitChanges()

Result:

enter image description here

| improve this answer | |
  • Thank you very much for your help, it gives me the error "IndexError: list index out of range", I replaced the names of the two layers in the first two lines as you indicated, the max_dist field is created correctly within my layer of polygons but is empty. By chance can you tell me where I'm wrong? thank you very much. – Enrico Lochi May 24 at 16:57
  • Maybe the POINT_ID field must be numeric? in my case it's a string – Enrico Lochi May 24 at 17:08
  • if I turn the POINT_ID field into an integer I don't get any more errors, but unfortunately the max_dist field shows all 0. Thanks for the help. – Enrico Lochi May 24 at 17:22
  • Could you share some sample points and related voronoi polygons from your data to understand what we are missing? – Kadir Şahbaz May 24 at 18:02
  • I modified the initial post by inserting two screenshots of the two layers, the one containing the Voronoi polygons and the one containing the points. In your script I also modified the "POINT_ID" field by inserting the correct one in my case, that is "ID_NODO". Thanks for your help – Enrico Lochi May 24 at 18:18
2

To add a second possible solution at your request, using only the Field Calculator, you can calculate the maximum distance between the furthest vertex of a Voronoi polygon and the point that generated it using the following expression on the Voronoi polygon layer:

array_max(
    array_foreach(
        array_foreach(
        generate_series(1,num_geometries( nodes_to_points($geometry))),
        make_line(
            geometry_n(nodes_to_points($geometry),@element),
            aggregate('point','array_agg',$geometry,"id" = attribute(@parent,'id'))
            )
        ), length(@element)
    )
)

The expression will create a label (or a new field) with the maximum requested value.

NB. array_sum is not yet part of the QGIS core. To use it, you need to install the plugin arrayPlus that integrate some more arrays into your Field calculator.

In your case, the expression to use will be

array_max(
    array_foreach(
        array_foreach(
        generate_series(1,num_geometries( nodes_to_points($geometry))),
        make_line(
            geometry_n(nodes_to_points($geometry),@element),
            aggregate('NODI TOPOIETI','array_agg',$geometry,"ID_NODO" = 
            attribute(@parent,'ID_NODO'))
            )
        ), length(@element)
    )
)

An example in the figure below, where are also shown the lines used to do the calculation, created by Geometry Generator using the expression

collect_geometries(
    array_foreach(
        generate_series(1,num_geometries( nodes_to_points( $geometry))),
            make_line(
            geometry_n(nodes_to_points($geometry),@element),
            aggregate('point','array_agg',$geometry,    "id" = attribute (@parent,'id'))
            )
    )
)

enter image description here

| improve this answer | |
  • Thank you for the solution, but I get the error that the array_max function is not known, does it require the installation of some additional plugins? Thanks so much – Enrico Lochi May 25 at 8:48
  • Yes, sorry. I will edit my answer. You need to install the plugin [arrayPlus] (plugins.qgis.org/plugins/arrayplus ) that integrate some more arrays no yet part of the core. – Val P May 25 at 8:57
  • By installing the plugin that you suggested to me, the field returns a preview value, but when I apply I get an Evaluation Error: '>' not supported between instances of 'NoneType' and 'NoneType'. Could it be because the ID_NODO field in both two layers is of the string type? thanks for your help – Enrico Lochi May 25 at 11:16
  • I have tried to replicate your problem. In my case, also using a string type field the expression works properly. Stupid question: are you using capital letters in the expression? – Val P May 25 at 11:56
  • I copied exactly the code you suggested to me as I saw that you entered the correct fields in capital letters, but I still receive the same Evaluation Error. Thanks – Enrico Lochi May 25 at 13:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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