Skip to content

Commit 2baaec7

Browse files
committed
create clean voronoi point order PR #1371 #2426
1 parent a07adc6 commit 2baaec7

6 files changed

Lines changed: 70 additions & 15 deletions

File tree

‎NEWS.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# version 1.0-18
22

3+
* add flag for preservation of point order in `st_voronoi` #1371 for GEOS >= 3.12
4+
35
* fix build failure with GDAL < 3.4.0 #2436
46

57
# version 1.0-17

‎R/geom-transformers.R‎

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,7 @@ st_minimum_rotated_rectangle.sf = function(x, dTolerance, ...) {
450450
#' @name geos_unary
451451
#' @export
452452
#' @param envelope object of class \code{sfc} or \code{sfg} containing a \code{POLYGON} with the envelope for a voronoi diagram; this only takes effect when it is larger than the default envelope, chosen when \code{envelope} is an empty polygon
453+
#' @param point_order logical; preserve point order if TRUE and GEOS version >= 3.12; overrides bOnlyEdges
453454
#' @details \code{st_voronoi} creates voronoi tesselation. \code{st_voronoi} requires GEOS version 3.5 or above
454455
#' @examples
455456
#' set.seed(1)
@@ -470,33 +471,48 @@ st_minimum_rotated_rectangle.sf = function(x, dTolerance, ...) {
470471
#' # compute Voronoi polygons:
471472
#' pols = st_collection_extract(st_voronoi(do.call(c, st_geometry(pts))))
472473
#' # match them to points:
473-
#' pts$pols = pols[unlist(st_intersects(pts, pols))]
474+
#' pts_pol = st_intersects(pts, pols)
475+
#' pts$pols = pols[unlist(pts_pol)] # re-order
476+
#' if (isTRUE(try(compareVersion(sf_extSoftVersion()["GEOS"], "3.12.0") > -1,
477+
#' silent = TRUE))) {
478+
#' pols_po = st_collection_extract(st_voronoi(do.call(c, st_geometry(pts)),
479+
#' point_order = TRUE)) # GEOS >= 3.12 can preserve order of inputs
480+
#' pts_pol_po = st_intersects(pts, pols_po)
481+
#' print(all(unlist(pts_pol_po) == 1:(n/2)))
482+
#' }
474483
#' plot(pts["id"], pch = 16) # ID is color
475484
#' plot(st_set_geometry(pts, "pols")["id"], xlim = c(0,1), ylim = c(0,1), reset = FALSE)
476485
#' plot(st_geometry(pts), add = TRUE)
477486
#' layout(matrix(1)) # reset plot layout
478487
#' }
479-
st_voronoi = function(x, envelope, dTolerance = 0.0, bOnlyEdges = FALSE)
488+
st_voronoi = function(x, envelope, dTolerance = 0.0, bOnlyEdges = FALSE, point_order = FALSE)
480489
UseMethod("st_voronoi")
481490

482491
#' @export
483-
st_voronoi.sfg = function(x, envelope = st_polygon(), dTolerance = 0.0, bOnlyEdges = FALSE)
484-
get_first_sfg(st_voronoi(st_sfc(x), st_sfc(envelope), dTolerance, bOnlyEdges = bOnlyEdges))
492+
st_voronoi.sfg = function(x, envelope = st_polygon(), dTolerance = 0.0, bOnlyEdges = FALSE, point_order = FALSE)
493+
get_first_sfg(st_voronoi(st_sfc(x), st_sfc(envelope), dTolerance, bOnlyEdges = bOnlyEdges, point_order = point_order))
485494

486495
#' @export
487-
st_voronoi.sfc = function(x, envelope = st_polygon(), dTolerance = 0.0, bOnlyEdges = FALSE) {
496+
st_voronoi.sfc = function(x, envelope = st_polygon(), dTolerance = 0.0, bOnlyEdges = FALSE, point_order = FALSE) {
488497
if (compareVersion(CPL_geos_version(), "3.5.0") > -1) {
489498
if (isTRUE(st_is_longlat(x)))
490499
warning("st_voronoi does not correctly triangulate longitude/latitude data")
500+
if (compareVersion(CPL_geos_version(), "3.12.0") > -1) {
501+
bOnlyEdges = as.integer(bOnlyEdges)
502+
if (point_order) bOnlyEdges = 2L # GEOS enum GEOS_VORONOI_PRESERVE_ORDER
503+
} else {
504+
if (point_order)
505+
warning("Point order retention not supported for GEOS ", CPL_geos_version())
506+
}
491507
st_sfc(CPL_geos_voronoi(x, st_sfc(envelope), dTolerance = dTolerance,
492508
bOnlyEdges = as.integer(bOnlyEdges)))
493509
} else
494510
stop("for voronoi, GEOS version 3.5.0 or higher is required")
495511
}
496512

497513
#' @export
498-
st_voronoi.sf = function(x, envelope = st_polygon(), dTolerance = 0.0, bOnlyEdges = FALSE) {
499-
st_set_geometry(x, st_voronoi(st_geometry(x), st_sfc(envelope), dTolerance, bOnlyEdges))
514+
st_voronoi.sf = function(x, envelope = st_polygon(), dTolerance = 0.0, bOnlyEdges = FALSE, point_order = FALSE) {
515+
st_set_geometry(x, st_voronoi(st_geometry(x), st_sfc(envelope), dTolerance, bOnlyEdges = bOnlyEdges, point_order = point_order))
500516
}
501517

502518
#' @name geos_unary

‎man/geos_unary.Rd‎

Lines changed: 12 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎src/geos.cpp‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535
# if GEOS_VERSION_MINOR >= 11
3636
# define HAVE311
3737
# endif
38+
# if GEOS_VERSION_MINOR >= 12
39+
# define HAVE312
40+
# endif
3841
#else
3942
# if GEOS_VERSION_MAJOR > 3
4043
# define HAVE340

‎tests/geos.R‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,26 @@ st_line_merge(mls)
7373
if (isTRUE(try(compareVersion(sf_extSoftVersion()["GEOS"], "3.5.0") > -1, silent = TRUE))) {
7474
# voronoi:
7575
set.seed(1)
76-
x = st_multipoint(matrix(runif(10),,2))
76+
m = matrix(runif(10),,2)
77+
x = st_multipoint(m)
7778
box = st_polygon(list(rbind(c(0,0),c(1,0),c(1,1),c(0,1),c(0,0))))
7879
v = st_sfc(st_voronoi(x, st_sfc(box)))
7980
plot(v, col = 0, border = 1, axes = TRUE)
8081
plot(box, add = TRUE, col = 0, border = 1) # a larger box is returned, as documented
8182
plot(x, add = TRUE, col = 'red', cex=2, pch=16)
8283
plot(st_intersection(st_cast(v), box)) # clip to smaller box
8384
plot(x, add = TRUE, col = 'red', cex=2, pch=16)
85+
v0 = st_sfc(st_voronoi(st_sfc(x), st_sfc(box)))
86+
pal <- c("black", "red", "green", "blue", "orange")
87+
opar = par(mfrow=c(1,2))
88+
plot(st_collection_extract(v0, "POLYGON"), col=pal)
89+
text(m[,1], m[,2], label=1:5, col="white")
90+
if (isTRUE(try(compareVersion(sf_extSoftVersion()["GEOS"], "3.12.0") > -1, silent = TRUE))) {
91+
v2 = st_sfc(st_voronoi(st_sfc(x), st_sfc(box), point_order=TRUE))
92+
plot(st_collection_extract(v2, "POLYGON"), col=pal)
93+
text(m[,1], m[,2], label=1:5, col="white")
94+
}
95+
par(opar)
8496

8597
v = st_voronoi(x)
8698
print(class(v))

‎tests/geos.Rout.save‎

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

2-
R version 4.2.2 Patched (2022-11-10 r83330) -- "Innocent and Trusting"
3-
Copyright (C) 2022 The R Foundation for Statistical Computing
4-
Platform: x86_64-pc-linux-gnu (64-bit)
2+
R version 4.4.1 (2024-06-14) -- "Race for Your Life"
3+
Copyright (C) 2024 The R Foundation for Statistical Computing
4+
Platform: x86_64-pc-linux-gnu
55

66
R is free software and comes with ABSOLUTELY NO WARRANTY.
77
You are welcome to redistribute it under certain conditions.
@@ -162,14 +162,26 @@ LINESTRING (0 0, 1 1, 2 0)
162162
> if (isTRUE(try(compareVersion(sf_extSoftVersion()["GEOS"], "3.5.0") > -1, silent = TRUE))) {
163163
+ # voronoi:
164164
+ set.seed(1)
165-
+ x = st_multipoint(matrix(runif(10),,2))
165+
+ m = matrix(runif(10),,2)
166+
+ x = st_multipoint(m)
166167
+ box = st_polygon(list(rbind(c(0,0),c(1,0),c(1,1),c(0,1),c(0,0))))
167168
+ v = st_sfc(st_voronoi(x, st_sfc(box)))
168169
+ plot(v, col = 0, border = 1, axes = TRUE)
169170
+ plot(box, add = TRUE, col = 0, border = 1) # a larger box is returned, as documented
170171
+ plot(x, add = TRUE, col = 'red', cex=2, pch=16)
171172
+ plot(st_intersection(st_cast(v), box)) # clip to smaller box
172173
+ plot(x, add = TRUE, col = 'red', cex=2, pch=16)
174+
+ v0 = st_sfc(st_voronoi(st_sfc(x), st_sfc(box)))
175+
+ pal <- c("black", "red", "green", "blue", "orange")
176+
+ opar = par(mfrow=c(1,2))
177+
+ plot(st_collection_extract(v0, "POLYGON"), col=pal)
178+
+ text(m[,1], m[,2], label=1:5, col="white")
179+
+ if (isTRUE(try(compareVersion(sf_extSoftVersion()["GEOS"], "3.12.0") > -1, silent = TRUE))) {
180+
+ v2 = st_sfc(st_voronoi(st_sfc(x), st_sfc(box), point_order=TRUE))
181+
+ plot(st_collection_extract(v2, "POLYGON"), col=pal)
182+
+ text(m[,1], m[,2], label=1:5, col="white")
183+
+ }
184+
+ par(opar)
173185
+
174186
+ v = st_voronoi(x)
175187
+ print(class(v))
@@ -666,4 +678,4 @@ CRS: NA
666678
>
667679
> proc.time()
668680
user system elapsed
669-
19.725 0.860 19.747
681+
11.890 0.081 12.018

0 commit comments

Comments
 (0)