Prepare your data: Make sure the polygon layer contains a uniqe identifyer attribute called
id. Do not use the
fid field if working with Geopackage: after step 2, this field will not be unique any more and you can't save it as Geopackage.
Convert the polygons to lines.
Create a new attribute field namend
bound with field calculator to identify each line segment (polygon side):
inner if it borders to a neighboring polygon,
outer if not. Use this expression:
if (overlay_contains( @layer),'inner','outer') (
overlay_contains is available since QGIS 3.16).
Screenshot: see the exploded lines labeled with the output (black); blue labels represent the
id of each polygon:
In step 3, we calculated for each line segment (each side of the polygon) if it borders on another polygon (
inner) or not (
outer). Now let's create another value: each side of the polygon is connected to two other sides (lines) of the same polygon (at start- and end-points: the corners of the polygon). So now let's calculate for each line/side how many of the two connected lines/sides are
outer, too. Create a new field
neighboring_outer, using this expression in the field calculator:
) = id
) = 'outer',
Screenshot showing the result by labeling each line with the value calculated: the number of neighboring line with
outer values each line has:
- The distribution of these values now can be used to differentiate between different categories of polygons, based on two characteristics:
- sum of
'outer' sides per polygon (how many sides of the polygon are
- highest value per polygon of
'outer' values for neighboring sides (
Thus calculate a new field
cat_code with this expression:
filter:= attribute (@parent, 'id') = id
filter:= attribute ( @parent, 'id') = id
Screenshot: the blue labels are the result of the calculation. The value of the blue label is simply a concatenation of the
sum of black values per polygon with the
highest black value per polygon (black values as above):
- Copy the created
cat_code from the exploded line- back to the original polygon layer. Create there a field, called
cat_code as well using this expression:
- We have 6 different cases, coded with these numbers: 0, 21, 41, 42, 62, 82 (the higher the number, the more outside sides the polygon has). We can convert these numbers to a descriptive text, creating a new field
category with this expression:
when "cat_code" = 0 then 'enclosed'
when "cat_code" = 21 then 'inside'
when "cat_code" = 41 then 'corner'
when "cat_code" = 42 then 'front/back'
when "cat_code" = 62 then 'exposed'
when "cat_code" = 82 then 'isolated'
And this is how the result looks like:
You might remark a problem with polygons no. 16, 17 and 18 (see next screenshot below for identification): here, the results are wrong (see last two screenshots above). That's because in this case, the southern side of polygon 16 borders on two different polygons. For polygon 16, we have one straight line, northern line of polygon 17 and 18 are shorter lines. Because of that, in step 3, these lines are not recognized by
overlay_contains() as being contained in each other (16 is not contained in 17 nor in 18; 17 and 18 are not contained in 16).
In this case, the problem can easily be avoided by adding a vertex in the polygon on the southern line of polygon 16 where it meets the corners of polygons 17 and 18.
Screenshot with additional vertex (red arrow) that affects the results for polygons 16 to 18 that are now correctly categorized: