rspatialmultilinestringsfnetwork

creating an sfn_network first merging linestrings


I am working on creating a spatial network in R where I need to consider several connected LINESTRINGs as a single line in the network. Each LINESTRING represents a segment of a rail network, and they are connected end-to-end. My goal is to simplify these connections so that the entire sequence of connected lines is treated as a single LINESTRING from start to end point.

Here is what my LINESTRINGs look like (each color represents a different LINESTRING):

enter image description here

However they have grouping Variable indicating which linestrings belong together (they touch each other at the ends)

enter image description here

So my aim is, that as sfn_network() not every single LINESTRING is considerered (with corresponding nodes) but at the end, the only the START/ END of the grouped LINESTRINGs are considered as nodes.

I tried something like:

rails1 <- rails %>% group_by(GROUP) %>% 
  summarise(do_union =TRUE)%>% 
  ungroup() %>% 
  st_cast("MULTILINESTRING") %>% 
  st_cast("LINESTRING")



 structure(list(id = c(1, 1, 1, 1, 1, 6, 7), ID_1 = c(1, 2, 3, 
4, 5, 6, 7), GROUP = c(1, 1, 1, 2, 2, 3, 3), geometry = structure(list(
    structure(c(9.49750923562068, 9.25766974945376, 51.3143637469628, 
    51.1041822177009), dim = c(2L, 2L), class = c("XY", "LINESTRING", 
    "sfg")), structure(c(9.25766974945376, 8.943977955227, 51.1041822177009, 
    51.0783319880388), dim = c(2L, 2L), class = c("XY", "LINESTRING", 
    "sfg")), structure(c(8.943977955227, 8.773918358099, 51.0783319880388, 
    51.1867877726016), dim = c(2L, 2L), class = c("XY", "LINESTRING", 
    "sfg")), structure(c(8.773918358099, 8.57243470497997, 51.1867877726016, 
    51.1786769084193), dim = c(2L, 2L), class = c("XY", "LINESTRING", 
    "sfg")), structure(c(8.57243470497997, 8.56919987568677, 
    51.1786769084193, 51.144914596165), dim = c(2L, 2L), class = c("XY", 
    "LINESTRING", "sfg")), structure(c(9.25766974945376, 9.36450576334242, 
    51.1041822177009, 50.9477904259333), dim = c(2L, 2L), class = c("XY", 
    "LINESTRING", "sfg")), structure(c(9.36450576334242, 9.21755208973725, 
    50.9477904259333, 50.9058462470297), dim = c(2L, 2L), class = c("XY", 
    "LINESTRING", "sfg"))), n_empty = 0L, crs = structure(list(
    input = "WGS 84", wkt = "GEOGCRS[\"WGS 84\",\n    DATUM[\"World Geodetic System 1984\",\n        ELLIPSOID[\"WGS 84\",6378137,298.257223563,\n            LENGTHUNIT[\"metre\",1]]],\n    PRIMEM[\"Greenwich\",0,\n        ANGLEUNIT[\"degree\",0.0174532925199433]],\n    CS[ellipsoidal,2],\n        AXIS[\"latitude\",north,\n            ORDER[1],\n            ANGLEUNIT[\"degree\",0.0174532925199433]],\n        AXIS[\"longitude\",east,\n            ORDER[2],\n            ANGLEUNIT[\"degree\",0.0174532925199433]],\n    ID[\"EPSG\",4326]]"), class = "crs"), class = c("sfc_LINESTRING", 
"sfc"), precision = 0, bbox = structure(c(xmin = 8.56919987568677, 
ymin = 50.9058462470297, xmax = 9.49750923562068, ymax = 51.3143637469628
), class = "bbox"))), row.names = c(NA, -7L), class = c("sf", 
"data.frame"), sf_column = "geometry", agr = structure(c(id = NA_integer_, 
ID_1 = NA_integer_, GROUP = NA_integer_), class = "factor", levels = c("constant", 
"aggregate", "identity")))

Solution

  • A combination of dplyr::summarise() and sf::st_line_merge() will achieve your desired outcome. Including directed = TRUE ensures only lines in the same direction (within each group in this reprex) are merged.

    library(sf)
    library(dplyr)
    library(ggplot2)
    
    
    rails1 <- rails |>
      summarise(geometry = st_combine(geometry), .by = GROUP) |>
      st_line_merge(directed = TRUE) |>
      st_cast("LINESTRING")
    
    rails1
    # Simple feature collection with 3 features and 1 field
    # Geometry type: LINESTRING
    # Dimension:     XY
    # Bounding box:  xmin: 8.5692 ymin: 50.90585 xmax: 9.497509 ymax: 51.31436
    # Geodetic CRS:  WGS 84
    #   GROUP                       geometry
    # 1     1 LINESTRING (9.497509 51.314...
    # 2     2 LINESTRING (8.773918 51.186...
    # 3     3 LINESTRING (9.25767 51.1041...
    
    ggplot() +
      geom_sf(data = rails1, aes(colour = factor(GROUP))) +
      labs(colour = "GROUP") +
      theme_void()
    

    1