# Route networks with stplanr

    library(stplanr)
    library(sf)

# Introduction

Route networks represent the network of highways, cycleways, footways and other ways along which transport happens. You can get route network data from OpenStreetMap (e.g. via the `osmdata` R package) and other providers or transport network data.

# Creating route networks from overlapping routes

Unlike routes, each segment geometry in a route network can only appear once.

stplanr can be used to convert a series of routes into a route network, using the function `overline()`, as illustrated below:

    library(stplanr)
    library(sf)
    sample_routes <- routes_fast_sf[2:6, 1]
    sample_routes$value <- rep(1:3, length.out = 5)
    rnet <- overline(sample_routes, attrib = "value")
    plot(sample_routes["value"], lwd = sample_routes$value, main = "Routes")
    plot(rnet["value"], lwd = rnet$value, main = "Route network")

The above figure shows how `overline()` breaks the routes into segments with the same values and removes overlapping segments. It is a form of geographic aggregation.

# Identifying route network groups

Route networks can be represented as a graph. Usually all segments are connected together, meaning the graph is connected. We can show that very simple network above is connected as follows:

    touching_list = st_intersects(sample_routes)
    #> although coordinates are longitude/latitude, st_intersects assumes that they
    #> are planar
    g = igraph::graph.adjlist(touching_list)
    #> Warning: `graph.adjlist()` was deprecated in igraph 2.0.0.
    #> ℹ Please use `graph_from_adj_list()` instead.
    #> This warning is displayed once every 8 hours.
    #> Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
    #> generated.
    igraph::is_connected(g)
    #> [1] TRUE

A more complex network may not be connected in this way, as shown in the example below:

    # piggyback::pb_download_url("r_key_roads_test.Rds")
    u = "https://github.com/ropensci/stplanr/releases/download/0.6.0/r_key_roads_test.Rds"
    rnet_disconnected = readRDS(url(u))
    touching_list = sf::st_intersects(rnet_disconnected)
    g = igraph::graph.adjlist(touching_list)
    igraph::is_connected(g)
    #> [1] FALSE
    sf:::plot.sfc_LINESTRING(rnet_disconnected$geometry)

The elements of the network are clearly divided into groups. We can identify these groups as follows:

    rnet_disconnected$group = rnet_igroup(rnet_disconnected)

# Routing on route networks

    # plot(rnet$geometry)
    # plot(sln_nodes, add = TRUE)
    # xy_path <- sum_network_routes(sln = sln, start = xy_nodes[1], end = xy_nodes[2], sumvars = "length")
    # # xy_path = sum_network_links(sln = sln, start = xy_nodes[1], end = xy_nodes[2])
    # plot(rnet$geometry)
    # plot(xy_sf$geometry, add = TRUE)
    # plot(xy_path$geometry, add = TRUE, lwd = 5)

# Adding new nodes

New nodes can be added to the network, although this should be done before the graph representation is created. Imagine we want to create a point half way along the the most westerly route segment in the network, near the coordinates -1.540, 53.826:

    new_point_coordinates <- c(-1.540, 53.826)
    p <- sf::st_sf(geometry = sf::st_sfc(sf::st_point(new_point_coordinates)), crs = 4326)

# Other approaches

Other approaches to working with route networks include:

- sDNA, an open source C++ library for analysing route networks and estimating flows at segments across network segments
- sfnetworks, an R package that provides an alternative igraph/sf spatial network class
- dodgr, an R package providing functions for calculating distances on directed graphs
- cppRouting, a package for routing in C++
- Chapter 10 of Geocomputation with R, which provides context and demonstrates a transport planning workflow in R.