If one is interested in sampling points with a distance constraint for each polygon, in the meanwhile, there are two nice and fast possibilities: (1) using QGIS "random points inside polygons" through RQGIS-package , or (2) using spatstat::rSSI-function.
In the following examples for (1) RQGIS and (2) spatstat::rSSI:
## load relevant packages
if(!require("pacman")) install.packages("pacman")
pacman::p_load(sf, sp, rgdal, dplyr, mapview, spatstat, maptools, devtools)
## load data and convert to sf
columbus <- readOGR(system.file("shapes/columbus.shp", package="spData")[1]) %>%
sf::st_as_sf(.)
## start random sampling with distance constraint
# # # # # # # # # # # # # # # # # # # #
# (1) ... using RQGIS
# # # # # # # # # # # # # # # # # # # #
devtools::install_github("jannes-m/RQGIS")
library("RQGIS")
# ... open QGIS tunnel
RQGIS::open_app() # QGIS must be installed
# ... find suitable algorithm
RQGIS::find_algorithms(search_term = "random")
# [6] "Random points inside polygons (fixed)
# ---------------->qgis:randompointsinsidepolygonsfixed"
# [7] "Random points inside polygons (variable)
# ------------->qgis:randompointsinsidepolygonsvariable"
# ... check usage
RQGIS::get_usage(alg = "qgis:randompointsinsidepolygonsfixed")
RQGIS::get_args_man(alg = "qgis:randompointsinsidepolygonsfixed")
# ... process random points with minimum distance (0.25 degree)
# using a fixed maximum number (10)
rdnmPts.RQGIS <- RQGIS::run_qgis(alg = "qgis:randompointsinsidepolygonsfixed",
show_output_paths = TRUE,
load_output = TRUE, params = list(
VECTOR = columbus, MIN_DISTANCE = "0.25",
VALUE = "10",OUTPUT = "rndm_pts.shp"))
# ... take a look on the result
mapview::mapview(list(rdnmPts.RQGIS, columbus))
# ... check number of random points
nrow(rdnmPts.RQGIS)
# [1] 187
# # # # # # # # # # # # # # # # # # # #
# (2) ... using spatstat::rSSI ------------------------------------
# # # # # # # # # # # # # # # # # # # #
# spatstat::rSSI uses a special format input. Therefore, a function is created
# to transform the simple feature to owin-format.
# init function
genRandomPtsDist <- function(x, seed = 123, dist = 10, n = Inf,
maxit = 100, quiet = TRUE, ...)
{
# get start time of process
process.time.start <- proc.time()
# get crs
crs <- sf::st_crs(x = x)
# convert simple feature to spatial polygons
x.sp <- x %>% as(., "Spatial") %>% as(., "SpatialPolygons")
# convert to owin object
x.owin <- x.sp %>%
slot(., "polygons") %>%
lapply(X = ., FUN = function(x){sp::SpatialPolygons(list(x))}) %>%
lapply(X = ., FUN = spatstat::as.owin)
# generate random sampling with distant constraint (can be parallelized)
pts.ppp <- lapply(X = 1:length(x.owin), FUN = function(i, x.owin, r, n, quiet,
seed, maxit, ...)
{
if(quiet == FALSE) cat("Run ", i, " of ", length(x.owin), "\n")
set.seed(seed)
spatstat::rSSI(r = r, n = n, giveup = maxit, win = x.owin[[i]], ...)
}, quiet = quiet, x.owin = x.owin, r = dist, n = n, seed = seed, maxit = maxit, ...)
# back-conversion to simple feature
pts.sf <- pts.ppp %>%
lapply(X = ., FUN = function(x) sf::st_as_sfc(as(x, "SpatialPoints"))) %>%
do.call(c, .) %>%
sf::st_sf(., crs = crs)
# get intersected items
pts.inter.x <- sf::st_intersects(x = pts.sf, y = x) %>% unlist
if(length(pts.inter.x) != nrow(pts.sf))
{
warning("Some sample points are outside a polygon")
} else{
pts.sf$In <- pts.inter.x
}
# get time of process
process.time.run <- proc.time() - process.time.start
if(quiet == FALSE) cat(paste0("------ Run of genRandomPtsDist: " ,
round(x = process.time.run["elapsed"][[1]]/60, digits = 3), " Minutes ------\n"))
return(pts.sf)
} # end of function
## Using the defined function, now one can generate a random sample.
# ... process random points with minimum distance (0.25 degree)
# using a fixed maximum number (10)
rdnmPts.rSSI <- genRandomPtsDist(x = columbus, dist = 0.25, n = 10, quiet = FALSE)
# ... take a look on the result
mapview::mapview(list(rdnmPts.rSSI, columbus))
# ... check number of random points
nrow(rdnmPts.rSSI)
# [1] 171