|
1 |
| -#' get nearest points between pairs of geometries |
2 |
| -#' |
3 |
| -#' get nearest points between pairs of geometries |
4 |
| -#' @param x object of class \code{sfg}, \code{sfc} or \code{sf} |
5 |
| -#' @param y object of class \code{sfg}, \code{sfc} or \code{sf} |
6 |
| -#' @param pairwise logical; if \code{FALSE} (default) return nearest points between all pairs, if \code{TRUE}, return nearest points between subsequent pairs. |
7 |
| -#' @param ... ignored |
8 |
| -#' @seealso \link{st_nearest_feature} for finding the nearest feature |
9 |
| -#' @return an \link{sfc} object with all two-point \code{LINESTRING} geometries of point pairs from the first to the second geometry, of length x * y, with y cycling fastest. See examples for ideas how to convert these to \code{POINT} geometries. |
10 |
| -#' @details in case \code{x} lies inside \code{y}, when using S2, the end points |
11 |
| -#' are on polygon boundaries, when using GEOS the end point are identical to \code{x}. |
12 |
| -#' @examples |
13 |
| -#' r = sqrt(2)/10 |
14 |
| -#' pt1 = st_point(c(.1,.1)) |
15 |
| -#' pt2 = st_point(c(.9,.9)) |
16 |
| -#' pt3 = st_point(c(.9,.1)) |
17 |
| -#' b1 = st_buffer(pt1, r) |
18 |
| -#' b2 = st_buffer(pt2, r) |
19 |
| -#' b3 = st_buffer(pt3, r) |
20 |
| -#' (ls0 = st_nearest_points(b1, b2)) # sfg |
21 |
| -#' (ls = st_nearest_points(st_sfc(b1), st_sfc(b2, b3))) # sfc |
22 |
| -#' plot(b1, xlim = c(-.2,1.2), ylim = c(-.2,1.2), col = NA, border = 'green') |
23 |
| -#' plot(st_sfc(b2, b3), add = TRUE, col = NA, border = 'blue') |
24 |
| -#' plot(ls, add = TRUE, col = 'red') |
25 |
| -#' |
26 |
| -#' nc = st_read(system.file("gpkg/nc.gpkg", package="sf")) |
27 |
| -#' plot(st_geometry(nc)) |
28 |
| -#' ls = st_nearest_points(nc[1,], nc) |
29 |
| -#' plot(ls, col = 'red', add = TRUE) |
30 |
| -#' pts = st_cast(ls, "POINT") # gives all start & end points |
31 |
| -#' # starting, "from" points, corresponding to x: |
32 |
| -#' plot(pts[seq(1, 200, 2)], add = TRUE, col = 'blue') |
33 |
| -#' # ending, "to" points, corresponding to y: |
34 |
| -#' plot(pts[seq(2, 200, 2)], add = TRUE, col = 'green') |
35 |
| -#' |
36 |
| -#' @export |
37 |
| -st_nearest_points = function(x, y, ...) UseMethod("st_nearest_points") |
38 |
| - |
39 |
| -#' @export |
40 |
| -#' @name st_nearest_points |
41 |
| -st_nearest_points.sfc = function(x, y, ..., pairwise = FALSE) { |
42 |
| - stopifnot(st_crs(x) == st_crs(y)) |
43 |
| - longlat = isTRUE(st_is_longlat(x)) |
44 |
| - if (longlat && sf_use_s2()) { |
45 |
| - ret = if (pairwise) |
46 |
| - s2::s2_minimum_clearance_line_between(x, y) |
47 |
| - else |
48 |
| - do.call(c, lapply(x, s2::s2_minimum_clearance_line_between, y)) |
49 |
| - st_as_sfc(ret, crs = st_crs(x)) |
50 |
| - } else { |
51 |
| - if (longlat) |
52 |
| - message_longlat("st_nearest_points") |
53 |
| - st_sfc(CPL_geos_nearest_points(x, st_geometry(y), pairwise), crs = st_crs(x)) |
54 |
| - } |
55 |
| -} |
56 |
| - |
57 |
| -#' @export |
58 |
| -#' @name st_nearest_points |
59 |
| -st_nearest_points.sfg = function(x, y, ...) { |
60 |
| - st_nearest_points(st_geometry(x), st_geometry(y), ...) |
61 |
| -} |
62 |
| - |
63 |
| -#' @export |
64 |
| -#' @name st_nearest_points |
65 |
| -st_nearest_points.sf = function(x, y, ...) { |
66 |
| - st_nearest_points(st_geometry(x), st_geometry(y), ...) |
67 |
| -} |
68 |
| - |
69 |
| -#' get index of nearest feature |
70 |
| -#' |
71 |
| -#' get index of nearest feature |
72 |
| -#' @param x object of class \code{sfg}, \code{sfc} or \code{sf} |
73 |
| -#' @param y object of class \code{sfg}, \code{sfc} or \code{sf}; if missing, features in \code{x} will be compared to all remaining features in \code{x}. |
74 |
| -#' @param ... ignored |
75 |
| -#' @param check_crs logical; should \code{x} and \code{y} be checked for CRS equality? |
76 |
| -#' @param longlat logical; does \code{x} have ellipsoidal coordinates? |
77 |
| -#' @return for each feature (geometry) in \code{x} the index of the nearest feature (geometry) in |
78 |
| -#' set \code{y}, or in the remaining set of \code{x} if \code{y} is missing; |
79 |
| -#' empty geometries result in \code{NA} indexes |
80 |
| -#' @seealso \link{st_nearest_points} for finding the nearest points for pairs of feature geometries |
81 |
| -#' @export |
82 |
| -#' @examples |
83 |
| -#' ls1 = st_linestring(rbind(c(0,0), c(1,0))) |
84 |
| -#' ls2 = st_linestring(rbind(c(0,0.1), c(1,0.1))) |
85 |
| -#' ls3 = st_linestring(rbind(c(0,1), c(1,1))) |
86 |
| -#' (l = st_sfc(ls1, ls2, ls3)) |
87 |
| -#' |
88 |
| -#' p1 = st_point(c(0.1, -0.1)) |
89 |
| -#' p2 = st_point(c(0.1, 0.11)) |
90 |
| -#' p3 = st_point(c(0.1, 0.09)) |
91 |
| -#' p4 = st_point(c(0.1, 0.9)) |
92 |
| -#' |
93 |
| -#' (p = st_sfc(p1, p2, p3, p4)) |
94 |
| -#' try(st_nearest_feature(p, l)) |
95 |
| -#' try(st_nearest_points(p, l[st_nearest_feature(p,l)], pairwise = TRUE)) |
96 |
| -#' |
97 |
| -#' r = sqrt(2)/10 |
98 |
| -#' b1 = st_buffer(st_point(c(.1,.1)), r) |
99 |
| -#' b2 = st_buffer(st_point(c(.9,.9)), r) |
100 |
| -#' b3 = st_buffer(st_point(c(.9,.1)), r) |
101 |
| -#' circles = st_sfc(b1, b2, b3) |
102 |
| -#' plot(circles, col = NA, border = 2:4) |
103 |
| -#' pts = st_sfc(st_point(c(.3,.1)), st_point(c(.6,.2)), st_point(c(.6,.6)), st_point(c(.4,.8))) |
104 |
| -#' plot(pts, add = TRUE, col = 1) |
105 |
| -#' # draw points to nearest circle: |
106 |
| -#' nearest = try(st_nearest_feature(pts, circles)) |
107 |
| -#' if (inherits(nearest, "try-error")) # GEOS 3.6.1 not available |
108 |
| -#' nearest = c(1, 3, 2, 2) |
109 |
| -#' ls = st_nearest_points(pts, circles[nearest], pairwise = TRUE) |
110 |
| -#' plot(ls, col = 5:8, add = TRUE) |
111 |
| -#' # compute distance between pairs of nearest features: |
112 |
| -#' st_distance(pts, circles[nearest], by_element = TRUE) |
113 |
| -st_nearest_feature = function(x, y, ..., check_crs = TRUE, longlat = isTRUE(st_is_longlat(x))) { |
114 |
| - |
115 |
| - if (missing(y)) { # https://github.com/r-spatial/s2/issues/111#issuecomment-835306261 |
116 |
| - longlat = force(longlat) # evaluate only once |
117 |
| - x = st_geometry(x) |
118 |
| - ind <- vapply( |
119 |
| - seq_along(x), |
120 |
| - function(i) st_nearest_feature(x[i], x[-i], check_crs = FALSE, longlat = longlat), |
121 |
| - integer(1) |
122 |
| - ) |
123 |
| - ifelse(ind >= seq_along(x), ind + 1, ind) |
124 |
| - } else { |
125 |
| - if (check_crs) |
126 |
| - stopifnot(st_crs(x) == st_crs(y)) |
127 |
| - if (longlat && sf_use_s2()) |
128 |
| - s2::s2_closest_feature(x, y) |
129 |
| - else { |
130 |
| - if (longlat) |
131 |
| - message_longlat("st_nearest_feature") |
132 |
| - CPL_geos_nearest_feature(st_geometry(x), st_geometry(y)) |
133 |
| - } |
134 |
| - } |
135 |
| -} |
| 1 | +#' Get nearest points between pairs of geometries |
| 2 | +#' |
| 3 | +#' get nearest points between pairs of geometries |
| 4 | +#' @param x,y object of class \code{sfg}, \code{sfc} or \code{sf} |
| 5 | +#' @param pairwise logical; if \code{FALSE} (default) return nearest points between all pairs, |
| 6 | +#' if \code{TRUE}, return nearest points between subsequent pairs. |
| 7 | +#' @param ... passed on to methods. Currently, only `pairwise` is implemented. |
| 8 | +#' @seealso \link{st_nearest_feature} for finding the nearest feature |
| 9 | +#' @return an \link{sfc} object with all two-point \code{LINESTRING} geometries of point pairs from the first to the second geometry, of length x * y, with y cycling fastest. |
| 10 | +#' See examples for ideas how to convert these to \code{POINT} geometries. |
| 11 | +#' @details in case \code{x} lies inside \code{y}, when using S2, the end points |
| 12 | +#' are on polygon boundaries, when using GEOS the end point are identical to \code{x}. |
| 13 | +#' @examples |
| 14 | +#' r = sqrt(2)/10 |
| 15 | +#' pt1 = st_point(c(.1,.1)) |
| 16 | +#' pt2 = st_point(c(.9,.9)) |
| 17 | +#' pt3 = st_point(c(.9,.1)) |
| 18 | +#' b1 = st_buffer(pt1, r) |
| 19 | +#' b2 = st_buffer(pt2, r) |
| 20 | +#' b3 = st_buffer(pt3, r) |
| 21 | +#' (ls0 = st_nearest_points(b1, b2)) # sfg |
| 22 | +#' (ls = st_nearest_points(st_sfc(b1), st_sfc(b2, b3))) # sfc |
| 23 | +#' plot(b1, xlim = c(-.2,1.2), ylim = c(-.2,1.2), col = NA, border = 'green') |
| 24 | +#' plot(st_sfc(b2, b3), add = TRUE, col = NA, border = 'blue') |
| 25 | +#' plot(ls, add = TRUE, col = 'red') |
| 26 | +#' |
| 27 | +#' nc = st_read(system.file("gpkg/nc.gpkg", package="sf")) |
| 28 | +#' plot(st_geometry(nc)) |
| 29 | +#' ls = st_nearest_points(nc[1,], nc) |
| 30 | +#' plot(ls, col = 'red', add = TRUE) |
| 31 | +#' pts = st_cast(ls, "POINT") # gives all start & end points |
| 32 | +#' # starting, "from" points, corresponding to x: |
| 33 | +#' plot(pts[seq(1, 200, 2)], add = TRUE, col = 'blue') |
| 34 | +#' # ending, "to" points, corresponding to y: |
| 35 | +#' plot(pts[seq(2, 200, 2)], add = TRUE, col = 'green') |
| 36 | +#' |
| 37 | +#' @export |
| 38 | +st_nearest_points = function(x, y, ...) UseMethod("st_nearest_points") |
| 39 | + |
| 40 | +#' @export |
| 41 | +#' @name st_nearest_points |
| 42 | +st_nearest_points.sfc = function(x, y, ..., pairwise = FALSE) { |
| 43 | + stopifnot(st_crs(x) == st_crs(y)) |
| 44 | + longlat = isTRUE(st_is_longlat(x)) |
| 45 | + if (longlat && sf_use_s2()) { |
| 46 | + ret = if (pairwise) |
| 47 | + s2::s2_minimum_clearance_line_between(x, y) |
| 48 | + else |
| 49 | + do.call(c, lapply(x, s2::s2_minimum_clearance_line_between, y)) |
| 50 | + st_as_sfc(ret, crs = st_crs(x)) |
| 51 | + } else { |
| 52 | + if (longlat) |
| 53 | + message_longlat("st_nearest_points") |
| 54 | + st_sfc(CPL_geos_nearest_points(x, st_geometry(y), pairwise), crs = st_crs(x)) |
| 55 | + } |
| 56 | +} |
| 57 | + |
| 58 | +#' @export |
| 59 | +#' @rdname st_nearest_points |
| 60 | +st_nearest_points.sfg = function(x, y, ...) { |
| 61 | + st_nearest_points(st_geometry(x), st_geometry(y), ...) |
| 62 | +} |
| 63 | + |
| 64 | +#' @export |
| 65 | +#' @rdname st_nearest_points |
| 66 | +st_nearest_points.sf = function(x, y, ...) { |
| 67 | + st_nearest_points(st_geometry(x), st_geometry(y), ...) |
| 68 | +} |
| 69 | + |
| 70 | +#' get index of nearest feature |
| 71 | +#' |
| 72 | +#' get index of nearest feature |
| 73 | +#' @param x object of class \code{sfg}, \code{sfc} or \code{sf} |
| 74 | +#' @param y object of class \code{sfg}, \code{sfc} or \code{sf}; if missing, features in \code{x} will be compared to all remaining features in \code{x}. |
| 75 | +#' @param ... ignored |
| 76 | +#' @param check_crs logical; should \code{x} and \code{y} be checked for CRS equality? |
| 77 | +#' @param longlat logical; does \code{x} have ellipsoidal coordinates? |
| 78 | +#' @return for each feature (geometry) in \code{x} the index of the nearest feature (geometry) in |
| 79 | +#' set \code{y}, or in the remaining set of \code{x} if \code{y} is missing; |
| 80 | +#' empty geometries result in \code{NA} indexes |
| 81 | +#' @seealso \link{st_nearest_points} for finding the nearest points for pairs of feature geometries |
| 82 | +#' @export |
| 83 | +#' @examples |
| 84 | +#' ls1 = st_linestring(rbind(c(0,0), c(1,0))) |
| 85 | +#' ls2 = st_linestring(rbind(c(0,0.1), c(1,0.1))) |
| 86 | +#' ls3 = st_linestring(rbind(c(0,1), c(1,1))) |
| 87 | +#' (l = st_sfc(ls1, ls2, ls3)) |
| 88 | +#' |
| 89 | +#' p1 = st_point(c(0.1, -0.1)) |
| 90 | +#' p2 = st_point(c(0.1, 0.11)) |
| 91 | +#' p3 = st_point(c(0.1, 0.09)) |
| 92 | +#' p4 = st_point(c(0.1, 0.9)) |
| 93 | +#' |
| 94 | +#' (p = st_sfc(p1, p2, p3, p4)) |
| 95 | +#' try(st_nearest_feature(p, l)) |
| 96 | +#' try(st_nearest_points(p, l[st_nearest_feature(p,l)], pairwise = TRUE)) |
| 97 | +#' |
| 98 | +#' r = sqrt(2)/10 |
| 99 | +#' b1 = st_buffer(st_point(c(.1,.1)), r) |
| 100 | +#' b2 = st_buffer(st_point(c(.9,.9)), r) |
| 101 | +#' b3 = st_buffer(st_point(c(.9,.1)), r) |
| 102 | +#' circles = st_sfc(b1, b2, b3) |
| 103 | +#' plot(circles, col = NA, border = 2:4) |
| 104 | +#' pts = st_sfc(st_point(c(.3,.1)), st_point(c(.6,.2)), st_point(c(.6,.6)), st_point(c(.4,.8))) |
| 105 | +#' plot(pts, add = TRUE, col = 1) |
| 106 | +#' # draw points to nearest circle: |
| 107 | +#' nearest = try(st_nearest_feature(pts, circles)) |
| 108 | +#' if (inherits(nearest, "try-error")) # GEOS 3.6.1 not available |
| 109 | +#' nearest = c(1, 3, 2, 2) |
| 110 | +#' ls = st_nearest_points(pts, circles[nearest], pairwise = TRUE) |
| 111 | +#' plot(ls, col = 5:8, add = TRUE) |
| 112 | +#' # compute distance between pairs of nearest features: |
| 113 | +#' st_distance(pts, circles[nearest], by_element = TRUE) |
| 114 | +st_nearest_feature = function(x, y, ..., check_crs = TRUE, longlat = isTRUE(st_is_longlat(x))) { |
| 115 | + |
| 116 | + if (missing(y)) { # https://github.com/r-spatial/s2/issues/111#issuecomment-835306261 |
| 117 | + longlat = force(longlat) # evaluate only once |
| 118 | + x = st_geometry(x) |
| 119 | + ind <- vapply( |
| 120 | + seq_along(x), |
| 121 | + function(i) st_nearest_feature(x[i], x[-i], check_crs = FALSE, longlat = longlat), |
| 122 | + integer(1) |
| 123 | + ) |
| 124 | + ifelse(ind >= seq_along(x), ind + 1, ind) |
| 125 | + } else { |
| 126 | + if (check_crs) |
| 127 | + stopifnot(st_crs(x) == st_crs(y)) |
| 128 | + if (longlat && sf_use_s2()) |
| 129 | + s2::s2_closest_feature(x, y) |
| 130 | + else { |
| 131 | + if (longlat) |
| 132 | + message_longlat("st_nearest_feature") |
| 133 | + CPL_geos_nearest_feature(st_geometry(x), st_geometry(y)) |
| 134 | + } |
| 135 | + } |
| 136 | +} |
0 commit comments