1

I have a network project in QGIS:

network project screenshot

Where arcs is a LineString layer, but all the arcs must be connected. I was able to detect subnetworks using the Disconnected Islands plugin which populates a NetworkGrp field.

The nodes layer is just the output of Extract Vertices algorithm, and wanted layer is what i need.

The conditions are:

  • If there are 3 subnetworks, i need 2 lines connecting them. In general, one line less than the number of groups is needed.
  • The lines can go from nearest points of each subnetwork group, without the need of a node there (preferred way, but they can go from one node to another one). Next to find the lines, i can clean the topology to add the required nodes and break the arcs accordingly.
  • I need to solve this for a lot of unconnected networks, so i can't do it manually.
  • I want to solve it in QGIS (using 3.22 right now), but can use GRASS GIS if needed. Python solutions are also welcome.
  • There isn't a distance threshold, i just need to connect all groups in a layer. But i don't want to connect arcs or nodes of the same network subgroup.
  • I need new arcs, but if a snap method is the only solution i can accept it.

The arcs layer to test can be downloaded from this link.

PolyGeo
  • 65,136
  • 29
  • 109
  • 338
Gabriel De Luca
  • 14,289
  • 3
  • 20
  • 51

1 Answers1

1
  1. Aggregate your lines to create multipart lines, based on subnetworks: each subnetwork consists of one feature. Use Menu Processing > Toolbox > Aggregate for this.

  2. For each line, find the nearest line and on this, create the closest point to the current feature.

  3. Create the shortest line from this closest point to the current geometry. You're done.

Steps 2 and 3 can be done at once using the following expression with Geometry generator or Geometry by expression.

Initial lines and the small red lines created by the expression, connecting the gaps: enter image description here

This is the expression you can use for the data you provided with settings made for your layer and attribute names:

with_variable (
    'point',
with_variable (
    'group',
    "NetworkGrp",  -- use your attribute name
array_foreach (
    eval ('overlay_nearest (
        ''arcs'',  -- use your layer name
        $geometry,
        filter:= NetworkGrp<>' || @group || ')' -- use your attribute name
    ),
    closest_point (
        @element,
        $geometry
    )
))[0],
make_line (
    @point,
    closest_point (
        $geometry, 
        @point
    )
))
Babel
  • 71,072
  • 14
  • 78
  • 208
  • Thank you. I don't know why, but it doesn't work in my case. I replaced "group" with "NetworkGrp", replaced @layer with ''arcs'', replaced filter:=group<>' with filter:=NetworkGrp<>' and replaced all the case ... end sentence with @line to return all the lines, but it returns features without geometry. Also, I don't understand something like filter:=NetworkGrp <> "NetworkGrp" can return something different to False. – Gabriel De Luca Dec 21 '22 at 00:17
  • 2
    I understand now, it works like filter:=NetworkGrp <> 0 if my current feature is in that group. But I think overlay_nearest function can't be used against the same layer (https://github.com/qgis/QGIS/issues/47201), because it does not evaluate a feature after being the current one? I will try against a copy. – Gabriel De Luca Dec 21 '22 at 00:41
  • I don't know, it seems like only work for the first group. I don't know if this is a Geometry by Expression limitation: https://i.stack.imgur.com/ETrOW.jpg. I will attach the layer in the question. – Gabriel De Luca Dec 21 '22 at 01:38
  • overlay_nearest works on the same layer, for this I added the limit:=10 part. Depending on how many features you have, you might want to change that. As you see in the screenshot, in my case it works - also when using Geometry by expression. Can't test right now with your data, will come back later. – Babel Dec 21 '22 at 06:06
  • Maybe duplicating the layer for the overlay function would be an option? – Babel Dec 21 '22 at 06:07
  • I tested your dataset and it works. Be sure to replace attribute field name also in filter:=group<>' with filter:=NetworkGrp<>'. When you then use a value apt for your data in the case condition of 13000 (when length(@line) < 13000), then you get exactly two connecting line - see updated expression to match exactly your use case. It works for me in Geometry generator as well as Geometry by expression, see updated screenshot in the answer. – Babel Dec 21 '22 at 07:33
  • Once again updated my answer. In fact, it's much easier if you first create multipart lines so that each subnetwork is just one feature. Then you don't have to make manual adaptions for the line lengths and don't need any settings for limit in the overlay_nearest function. It will automatically create the correct lines. Tested with your dataset in Geoemtry Generator (screenshot) as well as Geometry by Expression: both work. – Babel Dec 21 '22 at 07:56
  • 1
    Thank you very much, it works. I have a problem with real data that I did not take into account when creating the sample data, which is that there are subgroups that are close to each other but far from the rest of the network. However, being able to draw all the lines is already progress. Thanks! – Gabriel De Luca Dec 21 '22 at 21:49