Skip to main content
7 of 7
deleted 13 characters in body
Babel
  • 80.4k
  • 15
  • 97
  • 245

A vector based solution how to draw the shortest connecting linestring from point A to point B, but not crossing a barrier. At the very end of this solution, you find an expression for Geometry generator that shows the result in realtime when you move around points/change barrier lines.

Basic idea: create a convex hull around start/destination points and all nodes of the barrier, than use routing (shortest path algorithm) on the edges of the hull. Details below.

See the result in the screenshot. The connecting lines (black) touch, but do not cross, the barrier (red line). If you want the connecting line to have a certain distance from the barrier, you could easily do that by adding a buffer around the barrier: see last screenshot at the bottom.

enter image description here

First a step by step description, below how to implement it:

  1. Create the direct, connecting lines between start and destination points.

  2. Only keep lines that do not cross a barrier.

  3. Where the line crosses a barrier, create the convex hull from the geometry collection, containing: A) start point, B) destination point, C) all nodes (vertices) of the barrier line.

  4. Get the boundary of the convex hull.

  5. Use shortest path algorithm from start to destination, using the boundary from step 4 as network.

Steps 1 to 4: Start points (blue), destination points (red); red lines: barrier; the black lines connect each blue point to the red point with same @id, avoiding crossing the barrier: enter image description here

For steps 1 to 4, use this expression:

with_variable( 'connection', make_line ( $geometry, geometry ( get_feature_by_id ('destination',@id) ) ), case when intersects ( @connection, aggregate( 'barrier', 'collect', @geometry ) ) then boundary ( convex_hull( collect_geometries( array( @geometry, geometry ( get_feature_by_id ('destination',@id) ), collect_geometries( overlay_nearest ( 'barrier', nodes_to_points (@geometry) -- or nodes_to_points (buffer (@geometry,30)) if you want to create a buffer around the barrier, change buffer size of 30 to fit your needs ) ) ) ) ) ) else @connection end ) 

For step 5, I created the lines from steps 1 to 4 using Geometry by expression with the expression above, creating the output layer Modefied Geometry. Then I used Shortest path (point to point) in batch mode to connect each start point to destination point using these lines from Modefied Geometry as network. See screenshot:

enter image description here

See the result:

enter image description here

Version with a buffer (light blue) around the barrier; to create the buffer, in the expression above modify 10th last line according to the comment there:

enter image description here

Expression for geometry generator that directly (in one step) shows the shortest connection:

enter image description here

with_variable( 'connection', make_line ( $geometry, geometry ( get_feature_by_id ('destination',@id) ) ), with_variable( 'splitbuffer', length(@connection) / 1000000, case when intersects ( @connection, aggregate( 'barrier', 'collect', @geometry ) ) then difference ( with_variable( 'res', boundary( difference( convex_hull( collect_geometries( array( @geometry, geometry ( get_feature_by_id ('destination',@id) ), collect_geometries( overlay_nearest ( 'barrier', nodes_to_points (@geometry) ) ) ) ) ), buffer (@connection, @splitbuffer) ) ), if ( length (geometries_to_array(@res)[0]) > length (geometries_to_array(@res)[1]), geometries_to_array(@res)[1], geometries_to_array(@res)[0] ) ), buffer (@connection, @splitbuffer * 1.1) ) else @connection end )) 
Babel
  • 80.4k
  • 15
  • 97
  • 245