You can use function snapPointsToLines
from the package maptools
. It will not only snap the fish location to the nearest river, but also give you the id of the nearest river.
snappedFish <- snapPointsToLines(fish, rivers)
snappedFish$nearest_line_id
Than, you can calculate stationing of point on that line
# function to decide, if point is on the line segment
pointOnLine <- function(point,line_start,line_end){ # each of parameters is pair x;z
if(identical(point,line_start) | identical(point,line_end)){return(TRUE)}
if(point[1]>max(c(line_start[1],line_end[1])) | point[1]<min(c(line_start[1],line_end[1])) | point[2]>max(c(line_start[2],line_end[2])) | point[2]<min(c(line_start[2],line_end[2]))){
return(FALSE)
}
if(line_start[2]==line_end[2]){
slope<-0
} else if(line_start[1]==line_end[1]){
return(T)
} else {
slope <- (line_start[2]-line_end[2])/(line_start[1]-line_end[1])
}
intercept <- -slope*line_start[1] + line_start[2]
onLine <- round(point[2],digits=0)==round((slope*point[1]+intercept),digits=0)
return(onLine)
}
#### here is just a pseudocode, you will have to iterate through all fish locations
pointCrds <- coordinates(fishLocation)
# get the river a fish location is on
coords <- coordinates(nearestRiver)[[1]][[1]]
position <- 0
# calculate stationing from the start
d <- 0
for(j in 2:nrow(coords)){
onLine <- pointOnLine(point=pointCrds,line_start=coords[j-1,],line_end=coords[j,])
if(onLine){
d0 <- sqrt((pointCrds[1]-coords[j-1,1])^2 + (pointCrds[2]-coords[j-1,2])^2)
position <- round(d+d0)
break
}
d <- d + sqrt((coords[j,1]-coords[j-1,1])^2 + (coords[j,2]-coords[j-1,2])^2)
}
#d is the distance of fish location from the start on given river
The second task is to decide, whether that nearest river is upstream or downstream, which is more difficult and the approach would depend on the structure of your data.