-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsegments_cross_barrier.Rd
115 lines (95 loc) · 5.69 KB
/
segments_cross_barrier.Rd
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
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/spatial_tools.R
\name{segments_cross_barrier}
\alias{segments_cross_barrier}
\title{Determine if Euclidean path segments cross a barrier}
\usage{
segments_cross_barrier(start, end, barrier, distance = NULL, mobility = NULL)
}
\arguments{
\item{start}{A two-column matrix of coordinates that defines the `start' location of each segment.}
\item{end}{A two-column matrix of coordinates that defines the `end' location of each segment.}
\item{barrier}{A simple feature geometry that defines the barrier (see \code{\link[sf]{st_intersects}}).}
\item{distance}{(optional) A \code{\link[raster]{raster}} that defines distances from the \code{barrier}. If supplied, \code{mobility} is required (see below).}
\item{mobility}{(optional) If \code{distance} is supplied, \code{mobility} is a number that defines the distance threshold. Location pairs for which both locations are further than \code{mobility} from the \code{barrier} are assumed not to overlap with the \code{barrier}. If \code{start} and \code{end} are possible locations for an animal at a given pair of time steps, \code{mobility} is the distance that the individual could move between time steps (see \code{\link[flapper]{pf}}).}
}
\value{
The function returns a one-column matrix, with each row corresponding to a row in \code{start}/\code{end}, with a logical value that defines whether or not the Euclidean path segment connecting those two locations crosses the \code{barrier} (\code{TRUE}) or not (\code{FALSE}).
Edward Lavender
}
\description{
Given a sequence of `starting' and `ending' locations (\code{start} and \code{end}), this function determines whether or not the Euclidean path (`segment') between each location pair crosses a \code{barrier}.
}
\details{
This function was motivated by the need to support internal routines in \code{\link[flapper]{pf_simplify}}. Specifically, the function is used to minimise the number of shortest-distance calculations that are required by restricting calculations (if applicable) to particle pairs that require movement around a barrier, such as the coastline. (In these cases, Euclidean distances may be poor approximations of shortest distances that an aquatic animal must travel.)
The function implements a three-step approach to derive barrier overlaps:
\enumerate{
\item The function determines whether or not the minimum convex polygon (i.e., boundary box) around \code{start}/\code{end} intersects with \code{barrier}. If it does not, then no location segments can overlap with the barrier. This step is fast.
\item If the locations' minimum convex polygon intersects with the \code{barrier}, and if \code{distance} and \code{mobility} have been supplied, the function extracts the distance of each location in \code{start} and \code{end} from the \code{barrier}. Location pairs for which both locations are further than \code{mobility} from the \code{barrier} are dropped. This step is also fast.
\item For any remaining location pairs, the function links each \code{start} and \code{end} location and determines whether or not each linkage (`segment') intersects with the \code{barrier} using \code{\link[sf]{sf}} routines. This step can be slow for large numbers of locations (hence the first two filtering steps).
}
The following criteria apply to applications of this function:
\enumerate{
\item The number of observations in \code{start} and \code{end} must match.
\item The coordinate reference system for \code{start}, \code{end} and \code{barrier} must match.
\item If \code{distance} is supplied, \code{mobility} must also be supplied.
\item The function requires the \code{\link[sfheaders]{sf_linestring}} and \code{\link[sf]{st_intersects}} functions.
}
For speed in iterative applications, the function does not check whether or not these criteria are met.
}
\examples{
#### Plot example area and define barrier
raster::plot(dat_gebco)
raster::lines(dat_coast)
barrier <- sf::st_as_sf(dat_coast)
#### Example (1): Implement function using barrier only
## Define example starting and ending locations
start <- matrix(c(
701854.9, 6260399,
709202.5, 6258892
), ncol = 2, byrow = TRUE)
end <- matrix(c(
706753.3, 6264261,
709673.5, 6257102
), ncol = 2, byrow = TRUE)
## Visualise segments
# ... The first segment crosses the coastline (our barrier)
# ... The second segment does not cross the coastline (our barrier)
graphics::arrows(
x0 = start[1, 1], y0 = start[1, 2],
x1 = end[1, 1], y1 = end[1, 2]
)
graphics::arrows(
x0 = start[2, 1], y0 = start[2, 2],
x1 = end[2, 1], y1 = end[2, 2]
)
## Implement function
segments_cross_barrier(start, end, barrier = barrier)
#### Example (2): Implement function using barrier with distance and mobility
## Define distances from barrier
dat_dist <- raster::rasterize(dat_coast, dat_gebco)
dat_dist <- raster::distance(dat_dist)
## Implement function for a specified mobility parameter
segments_cross_barrier(start, end,
barrier = barrier,
distance = dat_dist, mobility = 500
)
#### Example (3): With many locations, supplying distance improves speed
## Sample a large number of random starting/ending locations
start <- raster::sampleRandom(dat_gebco, size = 3000, xy = TRUE)[, 1:2]
end <- raster::sampleRandom(dat_gebco, size = 3000, xy = TRUE)[, 1:2]
## Compare the duration of the function without/with distance included
# The first method without distance is much slower than the second method
# (~0.714 s versus 0.131 s for 3000 locations)
system.time(
int_1 <- segments_cross_barrier(start, end, barrier = barrier)
)
system.time(
int_2 <- segments_cross_barrier(start, end,
barrier = barrier,
distance = dat_dist, mobility = 500
)
)
## The two approaches return identical solutions:
identical(int_1, int_2)
}