6

I have a layer with polygons and a layer with polylines.

I am looking for the list of polygons crossed by the polylines.

Just here it's relatively simple: intersection function.

That said, the layout of the line is not perfect, so I would like to exclude polygon for which the line only touches the polygon contour or does not fit more than 1m into the polygon.

2
  • have you been able to make it work?
    – geozelot
    Sep 5, 2018 at 10:33
  • unfortunately, the result of the query does not take into account the tolerance. I have the same result as with a simple intersection. On the other hand, I found another solution which consisted in applying beforehand a negative buffer zone of 1m on the polygons
    – tdeleye
    Sep 6, 2018 at 5:50

2 Answers 2

6

I'd go for SQL (QGIS natively supports the SpatiaLite 4.3.0 dialect for any layer query) and check for the spatial relation with the negative buffered polygons:

  • QGIS | DB Manager

    • connect to Virtual Layers (double-click) in the left panel (make sure your layers are loaded in the project)
    • open the SQL Window (second icon to the left)

      • in the top panel, run (Execute)

        SELECT a.<id>,
               group_concat(b.<id>) AS its_lines,
               a.geometry 
        FROM <polygon_layer> AS a
        JOIN <line_layer> AS b
          ON ST_Relate(ST_Buffer(a.geometry, -1), b.geometry, 'T********')
        GROUP BY a.id;
        
      • load the produced table as a layer to the project by ticking the Load as new layer checkbox and fill in the fields

The above query will return a table with all polygon <id>s (paste the actual id field name here), their geometries and a concatenated string of line <id>s (same here) that intersect, but not touch, the negative buffered polygons of your layer.

Important:
Since you asked for meters, I put -1 in ST_Buffer. However, the function will treat the passed number in CRS units; here, this implies that you are working with a CRS whose units are in meter! If you are working in LatLon, e.g. EPSG:4326, the parameter in ST_Buffer will be treated as degrees...and thus makes no sense. In that case, a transformation into an appropriate projection is necessary; you can do that with
... ST_Buffer(ST_Transform(a.geometry, <srid_of_metric_CRS>), -1) ...

2
  • Unfortunately, the result of the query does not take into account the tolerance. I have the same result as with a simple intersection. On the other hand, I found another solution which consisted in applying beforehand a negative buffer zone of 1m on the polygons
    – tdeleye
    Sep 6, 2018 at 5:50
  • @tdeleye that is exactly what this query does...
    – geozelot
    Sep 6, 2018 at 5:54
5

Meanwhile (since QGIS 3.16 with the new overlay_crosses function) you can use QGIS expressions to automatically calculate what you want. The expression to use on the lines layer and referring to the polygon layer (replace polygon with the name of your polygon layer) looks like this - see below for an explanation. You can use this expression with field calculator. If you create a virtual field, the value will update automatically if you change the geometries of the lines or polygons or add new features - quite handy! You might also use the expression for visual purposes only when pasting it as a label (as done in the screenshot below).

array_length (
    array_remove_all( 
        array_foreach (
            overlay_crosses( 
                'polygon', 
                $geometry
            ),
            if (
                length (
                    intersection( 
                        $geometry ,
                        @element
                    )
                )<5,
                0,
                1
            )
        ), 
        0
    )
)

Screenshot: the line is labeled with the expression from above. As you see, some intersections are not counted (red circles) because the line is too short (<5). As well, if a line intersects more than once the same polygon (red arrows), it is counted just once: enter image description here

  1. overlay_crosses('polygon', $geometry) gets all the geometries from the layer polygon - thus applied on the line-layer, you access all the polygons, collected in an array.

  2. array_foreach (): for each element of the array (=for each polygon), perform an operation.

  3. The operation to perform: A) intersect the current feature (line) with each element from the array (in the array_foreach clause, refer to it with @element); B) get the length of this intersecting line with length (); C) inside an if()-clause: if this length is smaller than 5 (or every value you define here on line 15), return 0, otherwise 1.

  4. From the resulting array, remove all 0 values with array_remove_all( ), that means: all lines that are shorter than 5. For each polygon your line crosses for 5 or more meters, you get a value of 1 in the array - thus if the line crosses 3 polygons for more than 5 meters and 2 polygons for just 1 or 2 meters, the result will be: [1,1,1].

  5. Return the number of remaining elements in the array with array_length (). In the example from step 4, the result would be: 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.