-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTripPlanner.Rmd
141 lines (120 loc) · 4.29 KB
/
TripPlanner.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
---
title: "Trip Planner"
output:
flexdashboard::flex_dashboard:
source_code: embed
runtime: shiny
---
```{r global, include=FALSE}
# Required Libraries
library(shiny)
library(leaflet)
library(sf)
library(TSP)
library(DT)
# Function to generate 20 random locations on Grand Bank of Newfoundland
generate_random_locations <- function(n = 20) {
set.seed(123)
# Approximate latitude and longitude boundaries of Grand Bank
lat_range <- c(43.5, 46)
lon_range <- c(-52, -49)
# Generate random latitudes and longitudes within bounds
data.frame(
set = 1:n,
latitude = runif(n, min = lat_range[1], max = lat_range[2]),
longitude = runif(n, min = lon_range[1], max = lon_range[2])
)
}
# Function to read CSV or generate random data
get_locations <- function(file) {
if (is.null(file)) {
generate_random_locations()
} else {
read.csv(file$datapath)
}
}
# Function to convert lat/lon to UTM using sf
convert_to_utm <- function(data) {
coordinates <- st_as_sf(data, coords = c("longitude", "latitude"), crs = 4326)
utm_coords <- st_transform(coordinates, crs = 32621) # UTM Zone 21N for Newfoundland
utm_coords_df <- as.data.frame(st_coordinates(utm_coords))
return(cbind(data, utm_coords_df))
}
# Function to solve TSP
solve_tsp <- function(data, method = NULL) {
dist_matrix <- dist(data[, c("X", "Y")])
tsp <- TSP(dist_matrix)
solution <- solve_TSP(tsp, method = method, control = list(start = 1))
data[solution, ]
}
```
Column {.sidebar}
-----------------------------------------------------------------------
This application helps you plan efficient travel routes by suggesting the shortest distance path through a series of locations. The app applies [Traveling Salesman Problem (TSP)](https://en.wikipedia.org/wiki/Travelling_salesman_problem) algorithms to calculate and display the optimal route. See [Hahsler and Hornik (2007)](https://doi.org/10.18637/jss.v023.i02) for detailed methods.
---
Please upload a CSV file with the following columns: `set`, `latitude`, `longitude`.
If no file is uploaded, random data will be generated.
```{r}
fileInput("file", "Upload CSV", accept = c(".csv"))
selectInput("method", "Select TSP method",
choices = c("nearest_insertion",
"farthest_insertion",
"cheapest_insertion",
"arbitrary_insertion",
"nn",
"repetitive_nn",
"two_opt"),
selected = "farthest_insertion")
get_locs <- reactive({
file <- input$file
locs <- get_locations(file)
locs_utm <- convert_to_utm(locs) # Convert to UTM
tsp_solution <- solve_tsp(locs_utm, method = input$method) # Solve TSP for optimal path
# Calculate distances between consecutive points (nautical miles)
tsp_solution$distance <- c(NA, round(sqrt(rowSums(diff(as.matrix(tsp_solution[, c("X", "Y")]))^2)), 2)) / 1000 * 0.539957
tsp_solution
})
renderText({
locs <- get_locs()
paste("Total distance:", round(sum(locs$distance, na.rm = TRUE)), "nm")
})
```
Column
-----------------------------------------------------------------------
### Map of set locations and suggested path
```{r}
renderLeaflet({
locs <- get_locs()
leaflet(locs) %>%
addTiles() %>%
addCircleMarkers(
lng = ~longitude, lat = ~latitude,
radius = 2, color = "white", opacity = 1,
) %>%
addLabelOnlyMarkers(
lng = ~longitude, lat = ~latitude,
label = ~as.character(set),
labelOptions = labelOptions(noHide = TRUE, direction = "top", textOnly = TRUE,
style = list("color" = "white"))
) %>%
addPolylines(
lng = ~longitude, lat = ~latitude,
color = "white", weight = 2, opacity = 0.8
) %>%
addProviderTiles(providers$Esri.WorldImagery, group="Two")
})
```
Column
-----------------------------------------------------------------------
### Set order and distances
```{r}
renderDT({
locs <- get_locs()
datatable(locs[, c("set", "latitude", "longitude", "distance")],
options = list(pageLength = 100, dom = "t", ordering = F),
colnames = c("Set", "Latitude", "Longitude", "Distance (nm)"),
rownames = FALSE,
editable = "cell") |>
formatRound(columns = c("latitude", "longitude", "distance"), digits = 3)
})
```