7

I have a map consisting various district. How can I estimate the length of the common boundary shared by any two corresponding districts/polygons in QGIS?

For example if a polygon "A" shares a common boundary with polygons, "B", "C" and "D". Then what would be the length of the boundary between polygon "A-B", "A-C" and "A-D"?

I have calculated the neighboring polygon using the following in field calculator

aggregate( 
  layer:='file_districts',
  aggregate:='concatenate',
  expression:= DIST_ID,
  concatenator:=', ',
  filter:=touches($geometry, geometry(@parent))
)

Now i want to estimate the length of each of the neighbor polygon.

example

4
  • 1
    What have you tried so far and what does not work? Please also share images/screenshots of what you want to achieve. Commented May 6, 2020 at 10:38
  • Is this a display issue, or do you need the length for further processing?
    – Erik
    Commented May 6, 2020 at 10:43
  • I had already obtained the neighborhood of the polygon,need their length as a separate attribute Commented May 6, 2020 at 11:02
  • Please, do not forget about "What should I do when someone answers my question?"
    – Taras
    Commented Oct 13, 2021 at 10:36

3 Answers 3

7

Preamble: this solution was being written before the moment when the author demonstrated his efforts in the field calculator.

In QGIS I can suggest using a "Virtual Layer" through Layer > Add Layer > Add/Edit Virtual Layer....

Let's assume we have a layer 'units_1' (yellow) with its corresponding attribute tables accordingly, see image below.

input

Case 1. With aggregation

With the following query, it is possible to estimate the length of the common boundary shared by any two corresponding districts/polygons.

SELECT
    u11.*,
    GROUP_CONCAT(u12.id || ', len:' || round(st_length(st_intersection(u11.geometry, u12.geometry)), 4), "; ") AS "neighbor_info"
FROM
    "unit_1" AS u11, "unit_1" AS u12
WHERE
    st_intersects(u11.geometry, u12.geometry)
    AND u11.id <> u12.id
GROUP BY
    u11.id
ORDER BY
    u11.id ASC

The output Virtual Layer with its Attribute table will look as following

output1

Case 2. Without aggregation

In case if no aggregation has to be conducted then proceed with the following query

SELECT
    u11.*,
    u12.id || ', len:' || round(st_length(st_intersection(u11.geometry, u12.geometry)), 4) AS "neighbor_info"
FROM
    "unit_1" AS u11, "unit_1" AS u12
WHERE
    st_intersects(u11.geometry, u12.geometry)
    AND u11.id <> u12.id
ORDER BY
    u11.id ASC

Then the new output Virtual Layer with its Attribute table will look as following

output2

6

Similar to @Taras's answer, you can create a virtual layer to get the actual border lines, and then compute their length (or display them, or label them, or ...)

Go to the menu Layer > Add Layer > Add/Edit Virtual Layer... and enter the following query.

select a.id as poly1_id, b.id as poly2_id, 
      st_intersection(a.geometry, b.geometry) as geometry, 
      st_length(st_intersection(a.geometry, b.geometry)) as border_length
from my_layer a
    join my_layer b 
        ON st_intersects(a.geometry, b.geometry)
            AND a.id < b.id

enter image description here

Note that if your layer is in lat/longs (4326), the you should use st_length(st_intersection(a.geometry, b.geometry),true) as border_length instead. This version of st_length will return a distance in meters instead of degrees.

0
2

Calculate the length of the border the current polygon shares with all bordering polygons, use this expression that creates an array:


    array_foreach (
        overlay_touches (@layer, $geometry),
        length (intersection ($geometry, @element))  
    )

Convert it to a string with array_to_string(), add the $id to identify the polygons and add other modifications (see below).

A polygon layer with an expression-generated label, based on the expression from above, that generates a text-string list of length with all neighboring polygons (see below for the exact expression used here):

enter image description here

  • The expression used to generate the red line in the screenshot, using Geometry generator:

    if ($id = 1, intersection ( $geometry, overlay_touches (@layer, $geometry)[0]),'')
    
  • To generate the length of the common boundary line of polygons b and c, stored in the field named name, use this expression (change layer name and value in lines 2 and 6):

    if (
        name = 'b', 
        length(
            intersection ( 
                $geometry, 
                geometry (get_feature (@layer, 'name', 'c'))
            )
        ),
        ''
    )
    
  • The expression used to generate the label in the screenshot - can be used without changes on any polygon layer:

     'Length border of polygon '  || 
     $id || ' with: '  ||  '\n'  ||  
     array_to_string (
         array_foreach (
             overlay_touches (@layer, $id),
             '   - polygon'  || 
             @element || ': ' || 
             round (
                 length (
                     intersection (
                         $geometry, 
                         geometry (
                             get_feature_by_id (
                                 @layer, 
                                 @element
                             )
                         )
                     )
                 ), 
                 3
             ) 
         )
     )
    

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.