I have a port database which contain nearly 10k port names and its corresponding locations.I want to find the distance between the ports.
Form my understanding using Google distance matrix API, we can only able to find distance between the two points for a set of specific travel modes like bicycle,driving,walking and internal transit.
But In my case I want to find the distance between two ports during the ship voyage. If anyone done Similar sort of work please share your knowledge...
Reference website : [http://www.portworld.com/map]
Thanks!
I was faced with the same problem and found a solution.
1) First you have to create a world map raster with all the parts where a ship can go one value and all the places where it can't go another value.
For this I started with a shape file of all countries borders, added the Suez and Panama canal manually using QGIS. Then I also added the Ice in the Artic.
The rest of the work I did in R using the packages rgdal, raster and gdistance.
install.packages("rgdal")
install.packages("raster")
install.packages("gdistance")
library(rgdal)
library(raster)
library(gdistance)
I first created an empty raster:
new <- raster(ncol=360*5, nrow= 180*5)
projection(new) <- "+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0"
(By changing the number of columns you make the raster more precise. When it is low the maps looks like it is build out of dots, while when it is very large it all looks very smooth. The "canals" you draw also disappear when you make the resolution too low. Because they can not be distinguished from the surroundings. However when the calculation time increases very strongly with the resolution of your raster!!)
#Import Shapefile
map <- readOGR(dsn = "location of shape file" , layer = "name shape file")
#Create map from shapefile and empty map
r <- rasterize(map, new)
#replace values to 1 and 99999
values(r)[is.na(values(r))] <- 1
values(r)[values(r)>1] <- 99999
Thus you end up with a map where all places that a ship can go equal to 1 and all places where a ship can't go are 99999.
2) Save the coordinates of the ports in a matrix named "ports". Where the first column are the longitude and the second column the latitude respectively.
Apply the transition needed to calculate the shortest path and apply the geo-correction more info on the geo-correction you can find here.
p <- transition(r, function(x){1/mean(x)}, 8)
p <- geoCorrection(p)
3) Run a loop to calculate the shortest path between all the ports. The length of the shortest paths are stored in a three column matrix called "results".
The whole loop is run in parallel to speed things up.
install.packages("doParallel")
install.packages("foreach")
library(foreach)
library(doParallel)
# Create cluster with number of cores of the system.
cl <- makeCluster(detectCores())
registerDoParallel(cl)
i <- 1
nrow_data <- nrow(ports)
results <- foreach(i=icount(nrow_data), .combine='rbind', .packages="gdistance") %dopar% {
A <- cbind(ports[i,1],ports[i,2])
r <- matrix(NA, ncol=3,nrow=nrow_data)
r[,1] <- i
j <- i+1
while(j<=nrow_data){
r[j,2] <- j
B <- cbind(ports[j,1],ports[j,2])
tryCatch({
path <- shortestPath(p, A,B, output = "SpatialLines")
r[j,3] <- SpatialLinesLengths(path ,longlat=TRUE)
}, error=function(e){})
j <- j+1
}
r[1:nrow_data,]
}
I added the "tryCatch" to eliminate the errors I sometimes received when two ports where located very close to each other. Because of the low resolution of the raster, it can not make a distinction between these two ports.
It is probably not the nicest way to do everything but it works very well for me!