---
title: "Merging route networks"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Merging route networks}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  # # Uncomment to speed-up build
  eval = FALSE,
  comment = "#>",
  echo = TRUE,
  message = FALSE,
  warning = FALSE
)
# devtools::load_all()
sf::sf_use_s2(FALSE)
```

```{r setup}
# library(stplanr)
devtools::load_all()
library(dplyr)
library(tmap)
library(ggplot2)
library(tmaptools)
rnet_x = sf::read_sf("https://github.com/ropensci/stplanr/releases/download/v1.0.2/rnet_x_ed.geojson")
rnet_y = sf::read_sf("https://github.com/ropensci/stplanr/releases/download/v1.0.2/rnet_y_ed.geojson")
# dups = duplicated(rnet_x$geometry)
# summary(dups)
# rnet_x = rnet_x |>
#   filter(!dups)
# sf::write_sf(rnet_x, "~/github/ropensci/stplanr/rnet_x_ed.geojson", delete_dsn = TRUE)
```

# Target network preprocessing

We pre-processed the input simple geometry to make it even simpler as shown below.

```{r, out.width="50%", fig.width=8, fig.height=6, fig.show='hold'}
# tmap_mode("view")
# nrow(rnet_x)
# summary(sf::st_length(rnet_x))
plot(sf::st_geometry(rnet_x))
rnet_x = rnet_subset(rnet_x, rnet_y, dist = 20)
# nrow(rnet_x)
# plot(sf::st_geometry(rnet_x))
rnet_x = rnet_subset(rnet_x, rnet_y, dist = 20, min_length = 5)
# summary(sf::st_length(rnet_x))
# nrow(rnet_x)
# plot(sf::st_geometry(rnet_x))
rnet_x = rnet_subset(rnet_x, rnet_y, dist = 20, rm_disconnected = TRUE)
# nrow(rnet_x)
plot(sf::st_geometry(rnet_x))
```

The initial merged result was as follows (original data on left)

```{r}
funs = list(value = sum, Quietness = mean)
brks = c(0, 100, 500, 1000, 5000)
system.time({
  rnet_merged = rnet_merge(rnet_x, rnet_y, dist = 10, segment_length = 20, funs = funs)
})
m1 = tm_shape(rnet_y) + tm_lines("value", palette = "viridis", lwd = 5, breaks = brks)  +
  tm_scale_bar()
m2 = tm_shape(rnet_merged) + tm_lines("value", palette = "viridis", lwd = 5, breaks = brks)
tmap_arrange(m1, m2, sync = TRUE, nrow = 1)
```

Speed-up the results by transforming to a projected coordinate system:

```{r}
rnet_x = sf::st_transform(rnet_x, 27700)
rnet_y = sf::st_transform(rnet_y, 27700)
```

```{r}
rnet_y_segmented = line_segment(rnet_y, segment_length = 20, use_rsgeo = TRUE)
system.time({
  rnet_merged2 = rnet_merge(rnet_x, rnet_y, dist = 10, segment_length = 20, funs = funs)
})
```

Let's check the results:

```{r}
names(rnet_merged)
summary(rnet_merged$value)
summary(rnet_y$value)
sum(rnet_merged$value * sf::st_length(rnet_merged), na.rm = TRUE)
sum(rnet_y$value * sf::st_length(rnet_y), na.rm = TRUE)
```

We can more reduce the minimum segment length to ensure fewer NA values in the outputs:

```{r}
rnet_merged = rnet_merge(rnet_x, rnet_y, dist = 20, segment_length = 10, funs = funs)
m1 = tm_shape(rnet_y) + tm_lines("value", palette = "viridis", lwd = 5, breaks = brks)
m2 = tm_shape(rnet_merged) + tm_lines("value", palette = "viridis", lwd = 5, breaks = brks)
tmap_arrange(m1, m2, sync = TRUE, nrow = 1)
```

As shown in the results, some sideroad values have unrealistically high values:

![](https://user-images.githubusercontent.com/1825120/267946945-d89dfb99-fb60-4db5-ab39-168773ef01ad.png)

Let's see the results again:

```{r}
summary(rnet_merged$value)
summary(rnet_y$value)
sum(rnet_merged$value * sf::st_length(rnet_merged), na.rm = TRUE)
sum(rnet_y$value * sf::st_length(rnet_y), na.rm = TRUE)
```

The good news: the number of NAs is down to only 21 compared with the previous 100+.
Bad news: sideroads have been assigned values from the main roads.

We can fix this with the `max_angle_diff` argument:

```{r}
rnet_merged = rnet_merge(rnet_x, rnet_y, dist = 20, segment_length = 10, funs = funs, max_angle_diff = 20)
m1 = tm_shape(rnet_y) + tm_lines("value", palette = "viridis", lwd = 5, breaks = brks)
m2 = tm_shape(rnet_merged) + tm_lines("value", palette = "viridis", lwd = 5, breaks = brks)
tmap_arrange(m1, m2, sync = TRUE, nrow = 1)
```

As shown in the results, the sideroad values are fixed:

![](https://user-images.githubusercontent.com/1825120/267955054-3bd393a7-1fdd-44a4-8717-7933199c6f37.png)

Let's see the results again:

```{r}
summary(rnet_merged$value)
summary(rnet_y$value)
sum(rnet_merged$value * sf::st_length(rnet_merged), na.rm = TRUE)
sum(rnet_y$value * sf::st_length(rnet_y), na.rm = TRUE)
```

It also works with charaster strings:

```{r}
rnet_y$char = paste0("road", sample(1:3, nrow(rnet_y), replace = TRUE))
most_common = function(x) {
  ux = unique(x)
  ux[which.max(tabulate(match(x, ux)))]
}
funs = list(char = most_common)
system.time({
  rnet_merged = rnet_merge(rnet_x, rnet_y, dist = 10, segment_length = 20, funs = funs)
})
plot(rnet_y["char"])
plot(rnet_merged["char"])

```

Now let's testing on 3km dataset

```{r}
rnet_x = sf::read_sf("https://github.com/nptscot/networkmerge/releases/download/v0.1/os_3km.geojson")
rnet_y = sf::read_sf("https://github.com/nptscot/npt/releases/download/rnet_3km_buffer/rnet_3km_buffer.geojson")
```

Read columns from rnet_y to assign functions to them
```{r}
# Extract column names from the rnet_x data frame
name_list <- names(rnet_y)
name_list
# Initialize an empty list
funs <- list()

# Loop through each name and assign it a function based on specific conditions
for (name in name_list) {
  if (name == "geometry") {
    next  # Skip the current iteration
  } else if (name %in% c("Gradient", "Quietness")) {
    funs[[name]] <- mean
  } else {
    funs[[name]] <- sum
  }
}
```

```{r, eval = FALSE}
brks = c(0, 100, 500, 1000, 5000,10000)
colors <- c("green", "yellow", "blue", "purple", "red")
rnet_merged = rnet_merge(rnet_x, rnet_y, dist = 20, segment_length = 10, funs = funs, max_angle_diff = 20)
# st_write(rnet_merged, "data-raw/3km_exmaple_merged.geojson", driver = "GeoJSON")
rnet_merged <- st_make_valid(rnet_merged)
m1 = tm_shape(rnet_y) + tm_lines("all_fastest_bicycle", palette = "viridis", lwd = 5, breaks = brks)
m2 = tm_shape(rnet_merged) + tm_lines("all_fastest_bicycle", palette = "viridis", lwd = 5, breaks = brks)
tmap_arrange(m1, m2, sync = TRUE, nrow = 1)
```
Read 3km_exmaple_merged from github
```{r}
exmaple_3km = sf::read_sf("https://github.com/nptscot/networkmerge/releases/download/v0.1/3km_exmaple_merged.geojson")
names(rnet_y)

summary(rnet_y$all_fastest_bicycle)
summary(exmaple_3km$all_fastest_bicycle)
sum(exmaple_3km$all_fastest_bicycle * sf::st_length(exmaple_3km), na.rm = TRUE)
sum(rnet_y$all_fastest_bicycle * sf::st_length(rnet_y), na.rm = TRUE)
```
