How to get Voronoi diagram around polygons - r

I would like to generate a Voronoi diagram around 2D polygons. This question is somehow similar to this one here addressed for Python.
Is straightforward how this works for points, below is an example with sf::st_voronoi() function:
library(sf)
#> Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1
p <- rbind(c(3.2,4),
c(3,4.6),
c(3.8,4.4),
c(3.5,3.8),
c(3.4,3.6),
c(3.9,4.5))
plot(p, pch = 16)
p %>% st_multipoint() %>% st_voronoi() %>% plot(col = NA, add = TRUE)
Created on 2020-05-28 by the reprex package (v0.3.0)
But when I try the same function for some generated polygons, I do not get the results I would like:
library(sf)
#> Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1
p1 <- rbind(c(0,0), c(1,0), c(3,2), c(2,4), c(1,4), c(0,0))
p2 <- rbind(c(3,0), c(4,0), c(4,1), c(3,1), c(3,0))
pol <- st_multipolygon(list(list(p1), list(p2)))
plot(st_voronoi(pol), col = NA, lwd = 2, lty = 3)
plot(pol, col = rgb(1,0,0, alpha = 0.3), add = TRUE)
Created on 2020-05-28 by the reprex package (v0.3.0)
It seems that the Voronoi grid is based on the vertices of the polygons, which makes sense. However, I would like to get a Voronoi grid surrounding the red polygons and not intersecting them, that is, to treat a polygon as a point. Note that, getting the centroids of the polygons (e.g. with sf::st_centroid) and then generating a Voronoi grid is a path I tried, but the Voronoi grid will still intersect the polygons.

Here is my attempt. This is mostly relying on sf but I use smoothr::densify() to add vertices to straight edges of polygons (since the voronoi polygons are initially built around the polygon vertices), and I rely on a function from data.table to combine sf objects. There are probably ways to make this more efficient.
You would probably also want to simplify input polygons, although that is not needed in this test case.
The one really unresolved issue is for when two polygons share a boundary. The polygon-based voronoi should just follow that boundary, but currently does not.
library(sf)
# additionally requires:
## smoothr to densify polygons
## data.table to combine results
## poly = input sf polygons
## clip = polygon to be used as an extent for the output
## max_distance = argument for smoothr::densify, what max distance to have between vertices of a polygon. For breaking up long edges. In map units.
polyVoronoi <- function(poly, clip = NULL, max_distance = NULL) {
# add vertices to polygons to have voronoi polygons along straight edges of polygon
if (!is.null(max_distance)) {
poly <- smoothr::densify(poly, max_distance = max_distance)
}
# generate voronoi polygons for all vertices
vv <- st_voronoi(st_combine(poly))
vv <- st_collection_extract(vv, 'POLYGON')
# deal with geom validity issues
if (!all(st_is_valid(vv))) {
for (i in 1:length(vv)) {
vv[i] <- st_make_valid(vv[i])
if (!all(st_is_valid(vv[i]))) stop()
}
}
# determine which voronoi polygons intersect with input polygons
ii <- st_intersects(poly, vv)
# union/dissolve voronoi polygons that belong to the same inputs
resList <- vector('list', length(ii))
for (i in 1:length(ii)) {
xx <- vv[ii[[i]]]
xx <- st_combine(xx)
if (!all(st_is_valid(xx))) {
xx <- st_make_valid(xx)
}
resList[[i]] <- st_union(xx)
}
res <- st_as_sf(data.table::rbindlist(lapply(resList, st_as_sf)))
res <- res[1:nrow(res),]
res <- st_geometry(res)
if (!is.null(clip)) {
res <- st_intersection(res, clip)
}
return(res)
}
Example using built in dataset from sf
nc = st_read(system.file("shape/nc.shp", package="sf"))
# project to North America Albers Equal Area
nc <- st_transform(nc, crs = "+proj=aea +lat_1=20 +lat_2=60 +lat_0=40 +lon_0=-96 +x_0=0 +y_0=0 +ellps=GRS80 +datum=NAD83 +units=m +no_defs")
poly = st_geometry(nc)
# sample just a few polygons
poly <- poly[sample(1:length(poly), 12)]
# define bounds that we want for the output
e <- st_buffer(st_make_grid(poly, n = 1), 50000)
vv <- polyVoronoi(poly, clip = e, max_distance = 10000)
plot(vv, border = 'blue')
plot(poly, add = TRUE)
As you can see, there is a problem when polygons are in contact, and I haven't resolved this yet. Suggestions welcome!

Related

Plot an ellipse between two geographical foci in R

I am trying to find out the geographical area that is equidistant from two points, and to plot this as an ellipse.
I can produce plots for one point easily using st_buffer, and can find numerous R functions that will plot ellipse from a known centroid if I define the axis, but have not been able to find one that will plot an ellipse given two known foci and a defined distance.
The similar question here gets some way towards an answer, but is not readily applicable to geographic situations - Draw an ellipse based on its foci
My code is pretty simple at the moment, and given each coordinate with a 100km radius. However, I would like to find out all the positions that would be reachable by a 200km (or other defined distance) trip between both sites.
library(tidyverse)
library(sf)
#Give Coordinates
citylocations <- tibble::tribble(
~city, ~lon, ~lat,
"London", -0.1276, 51.5072,
"Birmingham", -1.8904, 52.4862,
)
citydflocations <- as.data.frame(citylocations)
#Convert to SF
citysflocations <- sf::st_as_sf(citydflocations, coords = c("lon","lat" ), crs = 4326)
#Convert location file to National Grid Planar
cityBNGsflocations <- citysflocations %>%
st_transform(citysflocations, crs = 27700)
#Produce circles with 100km buffer
dat_circles <- st_buffer(cityBNGsflocations, dist = 100000)
join_circles <- st_union(dat_circles) %>%
st_transform(4326)
plot(join_circles, col = 'lightblue')```
The function below should create buffers of varying distances for each of the two points it is given, finds the intersection the two buffers, unions the intersections, and finally returns a convex hull of those intersections. The output should be a near approximation of an ellipse with the two points as foci.
The straight-line(s) distance from one city to any edge of the polygon and then to the other city should equal the distance given in the function (200,000m in the example below).
It works on the data provided, but is fragile as there's no error checking or warning suppression. Make sure the dist argument is greater than the distance between the two points, and that the points have a crs that can use meters as a distance. (lat/lon might not work)
The example below only uses 20 points for the 'ellipse', but changing the function should be relatively straightforward.
library(sf)
#> Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1; sf_use_s2() is TRUE
library(tidyverse)
#Give Coordinates
citylocations <- tibble::tribble(
~city, ~lon, ~lat,
"London", -0.1276, 51.5072,
"Birmingham", -1.8904, 52.4862,
)
citydflocations <- as.data.frame(citylocations)
#Convert to SF
citysflocations <- sf::st_as_sf(citydflocations, coords = c("lon","lat" ), crs = 4326)
#Convert location file to National Grid Planar
cityBNGsflocations <- citysflocations %>%
st_transform(citysflocations, crs = 27700)
#Produce circles with 100km buffer
dat_circles <- st_buffer(cityBNGsflocations, dist = 100000)
join_circles <- st_union(dat_circles) %>%
st_transform(4326)
#plot(join_circles, col = 'lightblue')
### the ellipse function using 20 buffers ####
ellipse_fn <- function(x_sf, y_sf, distance){
#set distance argument to meters, get sequence of distances for buffers
distance = units::set_units(distance, 'm')
dists_1 <- seq(units::set_units(0, 'm'), distance, length.out = 22)
# create empty sf object to place for loop objects in
# purrr would probably be better here
nrows <- 20
df <- st_sf(city = rep(NA, nrows), city.1 = rep(NA, nrows), geometry = st_sfc(lapply(1:nrows, function(x) st_geometrycollection())))
intersections <- for(i in 2:21){
buff_1 <- st_buffer(cityBNGsflocations[1,], dist = dists_1[i])
buff_2 <- st_buffer(cityBNGsflocations[2,], dist = distance - dists_1[i])
intersection <- st_intersection(buff_1, buff_2)
df[i-1,] <- intersection
}
df %>%
st_set_crs(st_crs(x_sf)) %>%
st_union() %>%
st_convex_hull()
}
### end ellipse function ###
# Using the ellipse function with 2 points & 200000m distance
ellipse_sf <- ellipse_fn(cityBNGsflocations[1,], cityBNGsflocations[2,], dist = 200000)
# You'll get lots of warnings here about spatial constance...
ggplot() +
geom_sf(data = ellipse_sf, fill = 'black', alpha = .2) +
geom_sf(data = cityBNGsflocations, color = 'red')
Created on 2022-06-03 by the reprex package (v2.0.1)
mapview plot of the cities & 'ellipse' on a map:

Finding the radius of a circle that circumscribes a polygon

I am trying to find the best way of obtaining: the length of the longest line from the center of a polygon to its edge.
In the code below, I download the polygon data of the 75254 zip code located in Texas, USA. I then determine the location of its center with sf::st_centroid() and I plot the geometries using the tmap package.
# Useful packages
library(dplyr)
library(sf)
library(tigris)
library(tmap)
# Download polygon data
geo <- tigris::zctas(cb = TRUE, starts_with = "75254")
geo <- st_as_sf(geo)
# Determine the location of the polygon's center
geo_center <- st_centroid(geo)
# Plot geometries
tm_shape(geo) +
tm_polygons() +
tm_shape(geo_center) +
tm_dots(size = 0.1, col = "red")
Once again, is there an efficient way to determine the length of the line going from the center of the polygon all the way to the farthest point on the polygon's edge? In other words, how can I find the radius of the circle that perfectly circumscribes the polygon given that both the circle and the polygon have the same center?
Thank you very much for your help.
One point here, although I mentioned, st_bbox wouldn't work as the centroid of the bbox and the one of your shape are not the same, since the centroid is weighted. See here one approach based on the further distance to the points of the border, but you woud need to project your shape (currently is unprojected):
library(dplyr)
library(sf)
library(tigris)
library(tmap)
# Download polygon data
geo <- tigris::zctas(cb = TRUE, starts_with = "75254")
geo <- st_as_sf(geo)
st_crs(geo)
#> Coordinate Reference System:
#> EPSG: 4269
#> proj4string: "+proj=longlat +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +no_defs"
#Need to project
geo=st_transform(geo,3857)
# Determine the location of the polygon's center
geo_center <- st_centroid(geo)
#> Warning in st_centroid.sf(geo): st_centroid assumes attributes are constant over
#> geometries of x
plot(st_geometry(geo))
plot(st_geometry(geo_center), col="blue", add=TRUE)
#Cast to points
geopoints=st_cast(geo,"POINT")
#> Warning in st_cast.sf(geo, "POINT"): repeating attributes for all sub-geometries
#> for which they may not be constant
r=max(st_distance(geo_center,geopoints))
r
#> 3684.917 [m]
buffer=st_buffer(geo_center,dist=r)
plot(st_geometry(buffer), add=TRUE, border="green")
OP didn't ask for this, but in case anyone else would like to do this for multiple shapes, here's a version that builds on dieghernan's example to do that.
library(dplyr)
library(sf)
library(tigris)
library(tmap)
# Download polygon data
raw <- tigris::zctas(cb = TRUE, starts_with = "752")
geo <- raw %>%
st_as_sf() %>%
slice(1:5) %>%
st_transform(3857) %>%
arrange(GEOID10) # Sort on GEOID now so we don't have to worry about group_by resorting later
# Compute the convex hull
hull <- geo %>% st_convex_hull()
# Compute centroids
geo_center <- st_centroid(geo)
# Add centroid, then cast hull to points
hull_points <- hull %>%
mutate(centroid_geometry = geo_center$geometry) %>%
st_cast("POINT")
# Compute distance from centroid to all points in hull
hull_points$dist_to_centroid <- as.numeric(hull_points %>%
st_distance(hull_points$centroid_geometry, by_element = TRUE))
# Pick the hull point the furthest distance from the centroid
hull_max <- hull_points %>%
arrange(GEOID10) %>%
group_by(GEOID10) %>%
summarize(max_dist = max(dist_to_centroid)) %>%
ungroup()
# Draw a circle using that distance
geo_circumscribed <- geo_center %>% st_buffer(hull_max$max_dist)
# Plot the shape, the hull, the centroids, and the circumscribed circles
tm_shape(geo) +
tm_borders(col = "red") +
tm_shape(hull) +
tm_borders(col = "blue", alpha = 0.5) +
tm_shape(geo_center) +
tm_symbols(col = "red", size = 0.1) +
tm_shape(geo_circumscribed) +
tm_borders(col = "green")

Clip spatial polygon by world map in R

This is my first time doing any sort of spatial data visualization in R, and I'm stuck on a particular issue. I would like to clip a spatial polygon (specified by a series of lat/long coordinates) according to a world map, such that any part of the polygon which overlaps with a map polygon is removed. Using what I have in the below code as an example, I want to clip the rectangular spatial polygon so that only oceanic portions of the polygon remain.
I've found examples of how to retain the intersection between two spatial polygons, but I want to do the opposite. Perhaps there is a way to define the intersection, then "subtract" that from the polygon I wish to clip?
This might be a really basic question, but any tips will be appreciated!
Specify lat/long data:
x_coord <- c(25, 25, 275, 275)
y_coord <- c(20, -50, -50, 20)
xy.mat <- cbind(x_coord, y_coord)
xy.mat
Convert to spatial polygons object:
library(sp)
poly = Polygon(xy.mat)
polys = Polygons(list(poly),1)
spatial.polys = SpatialPolygons(list(polys))
proj4string(spatial.polys) = CRS("+proj=longlat +datum=WGS84 +no_defs
+ellps=WGS84 +towgs84=0,0,0")
Convert to spatial polygons data frame and export as shapefile:
df = data.frame(f=99.9)
spatial.polys.df = SpatialPolygonsDataFrame(spatial.polys, df)
spatial.polys.df
library(GISTools)
library(rgdal)
writeOGR(obj=spatial.polys.df, dsn="tmp", layer="polygon",
driver="ESRI Shapefile")
Plot world map and add .shp file:
map("world", wrap=c(0,360), resolution=0, ylim=c(-60,60))
map.axes()
shp <- readOGR("polygon.shp")
plot(shp, add=TRUE, col="blue", border=FALSE)
Here is a solution that stays in sf the entire time (I don't know sp), and illustrates constructing an sf object from scratch. st_difference create the geometry you want exactly, and then plotting can be done with the base plot method or the development version of ggplot which has geom_sf. I used map data from maps and rnaturalearth for this, you can adapt to your particular situation. Wrapping around the dateline is a little finicky regardless unfortunately.
library(tidyverse)
library(sf)
#> Linking to GEOS 3.6.1, GDAL 2.2.0, proj.4 4.9.3
library(rnaturalearth)
library(maps)
#>
#> Attaching package: 'maps'
#> The following object is masked from 'package:purrr':
#>
#> map
x_coord <- c(25, 25, 275, 275)
y_coord <- c(20, -50, -50, 20)
polygon <- cbind(x_coord, y_coord) %>%
st_linestring() %>%
st_cast("POLYGON") %>%
st_sfc(crs = 4326, check_ring_dir = TRUE) %>%
st_sf() %>%
st_wrap_dateline(options = c("WRAPDATELINE=YES", "DATELINEOFFSET=180"))
land <- rnaturalearth::ne_countries(returnclass = "sf") %>%
st_union()
ocean <- st_difference(polygon, land)
#> although coordinates are longitude/latitude, st_difference assumes that they are planar
plot(st_geometry(land))
plot(st_geometry(polygon), add = TRUE)
plot(st_geometry(ocean), add = TRUE, col = "blue")
ggplot() +
theme_bw() +
borders("world") +
geom_sf(data = ocean)
Created on 2018-03-13 by the reprex package (v0.2.0).
If I understand correctly what you want you can do it with the sf package using st_difference() and st_union()`.
Base on your code here is what you can do.
# world data
data("wrld_simpl", package = 'maptools')
# load sf package
library('sf')
# coerce sp object to sf
world <- st_as_sf(wrld_simpl)
rectangle <- st_as_sf(spatial.polys)
# difference between world polygons and the rectangle
difference <- st_difference(rectangle, st_union(world))
# coerce back to sp
difference <- as(difference, 'Spatial')
# plot the result
plot(difference)

Find Polygon Intercepts on a Map

I'm trying to find the Radii on this map that intercept state borders in R.
Here is my code so far. Thanks to user Gregoire Vincke for providing much of the solution.
library("maps")
library("mapproj")
library("RColorBrewer")
library("mapdata")
library("ggplot2")
library("rgeos")
library("dismo")
library("ggmap")
library("rgdal")
data("stateMapEnv") #US state map
dat <- read.csv("R/longlat.csv",header = T)
map('state',fill = T, col = brewer.pal(9,"Pastel2"))
#draws circles around a point, given lat, long and radius
plotCircle <- function(lonDec, latDec, mile) {
ER <- 3959
angdeg <- seq(1:360)
lat1rad <- latDec*(pi/180)
lon1rad <- lonDec*(pi/180)
angrad <- angdeg*(pi/180)
lat2rad <- asin(sin(lat1rad)*cos(mile/ER) + cos(lat1rad)*sin(mile/ER)*cos(angrad))
lon2rad <- lon1rad + atan2(sin(angrad)*sin(mile/ER)*cos(lat1rad),cos(mile/ER)-sin(lat1rad)*sin(lat2rad))
lat2deg <- lat2rad*(180/pi)
lon2deg <- lon2rad*(180/pi)
polygon(lon2deg,lat2deg,lty = 1 , col = alpha("blue",0.35))
}
point <- mapproject(dat$lng,dat$lat)
points(point, col = alpha("black",0.90), cex = 0.4, pch = 20) #plots points
plotCircle(-71.4868,42.990684,20)
plotCircle(-72.57085,41.707932,12)
...
#this goes on for every point
I want to store the points that intercept state borders in a new data frame, any help would be appreciated!
EDIT: Here's a broad overview of the workflow using the geospatial analyses packages in R (sp, rgdal, rgeos).
Instead of using the maps package and stateMapEnv, you want a polygon shapefile of state boundaries, like one that can be found here:
https://www.census.gov/geo/maps-data/data/cbf/cbf_state.html
You can then load that shapefile in R with readOGR from the rgdal package to get a SpatialPolygons (let's call it state_poly) with one Polygons object per state.
Create a SpatialPoints object from your long/lat coordinates:
pts <- SpatialPoints(dat[, c("lng", "lat")], proj4string = CRS("+proj=longlat"))
At this point your pts and state_poly should be in longitude/latitude coordinates, but to draw circles of a fixed radius around points, you need to convert them to projected coordinates (i.e. in meters). See this question for more details:
Buffer (geo)spatial points in R with gbuffer
Create a vector with the radii of your circles around each point, and use it with gBuffer (from rgeos) and your points layer:
circ <- gBuffer(pts, width = radii, byid = TRUE)
The byid argument means it does it separately for each point, using the different values in radii in the same order as the points.
Convert the state polygons to lines: state_lines <- as(state_poly, "SpatialLines")
Use gIntersects(circ, state_lines, byid = TRUE) .
Because of byid = TRUE, the return value is a matrix with one row per circle in your spgeom1 and one column per state boundaries in spgeom2. Note that if the circle intersect a boundary between two states, it should have two "TRUE" values in that row (one for each state). If it intersects with water or the external perimeter of the US it may have only one "TRUE" value in the row.
Here is the Final Code!
library("maps")
library("mapproj")
library("RColorBrewer")
library("mapdata")
library("ggplot2")
library("rgeos")
library("dismo")
library("ggmap")
library("rgdal")
#import shape file (.shp), make sure all the other files in the zip are included in
#your file location!
state_poly <- readOGR(dsn = 'C:/Users/chopp/Documents/R', layer='cb_2015_us_state_500k')
#data containing lng and lat coordinates with radii
data <- read.csv("R/longlat.csv", header = T)
#create spatial point objects out of your lng and lat data
pts <- SpatialPoints(data[,c("lng","lat")], proj4string = CRS("+proj=longlat"))
#convert spatial points to projected coordinates (points and map lines)
ptsproj <- spTransform(pts, CRS("+init=epsg:3347"))
state_poly_proj<- spTransform(state_poly, CRS("+init=epsg:3347"))
#convert radii units to meters, used in our gBuffer argument later on
radii <- data$rad*1609.344
#create circular polygons with. byid = TRUE will create a circle for each point
circ <- gBuffer(ptsproj, width = radii, byid = TRUE)
#convert state polygons to state lines
state_lines<- as(state_poly_proj, "SpatialLines")
#use gIntersects with byid = TRUE to return a matrix where "TRUE" represents
#crossing state boundaries or water
intdata <- gIntersects(circ, state_lines, byid = TRUE)
#write the matrix out into a csv file
write.csv(intdata,"R/Agents Intercepts 2.csv")

Buffer (geo)spatial points in R with gbuffer

I'm trying to buffer the points in my dataset with a radius of 100km. I'm using the function gBuffer from the package rgeos. Here's what I have so far:
head( sampledf )
# postalcode lat lon city province
#1 A0A0A0 47.05564 -53.20198 Gander NL
#4 A0A1C0 47.31741 -52.81218 St. John's NL
coordinates( sampledf ) <- c( "lon", "lat" )
proj4string( sampledf ) <- CRS( "+proj=longlat +datum=WGS84" )
distInMeters <- 1000
pc100km <- gBuffer( sampledf, width=100*distInMeters, byid=TRUE )
I get the following warning:
In gBuffer(sampledf, width = 100 * distInMeters, byid = TRUE) :
Spatial object is not projected; GEOS expects planar coordinates
From what I understand/read, I need to change the Coordinate Reference System (CRS),
in particular the projection, of the dataset from 'geographic' to 'projected'.
I'm not sure sure how to change this. These are all Canadian addresses, I might add.
So NAD83 seems to me a natural projection to choose but I may be wrong.
Any/all help would be greatly appreciated.
With a little bit more digging, it turns out that using a 'projected' coordinates reference system is as simple as
# To get Statscan CRS, see here:
# http://spatialreference.org/ref/epsg/3347/
pc <- spTransform( sampledf, CRS( "+init=epsg:3347" ) )
EPSG3347, used by STATSCAN (adequate for Canadian addresses), uses a lambert conformal conic projection. Note that NAD83 is inappropriate: it is a 'geographic', rather than a 'projected' CRS. To buffer the points
pc100km <- gBuffer( pc, width=100*distm, byid=TRUE )
# Add data, and write to shapefile
pc100km <- SpatialPolygonsDataFrame( pc100km, data=pc100km#data )
writeOGR( pc100km, "pc100km", "pc100km", driver="ESRI Shapefile" )
As #MichaelChirico pointed out, projecting your data to usergeos::gBuffer() should be applied with care. I am not an expert in geodesy, but as far I understood from this ESRI article (Understanding Geodesic Buffering), projecting and then applying gBuffer means actually producing Euclidean buffers as opposed to Geodesic ones. Euclidean buffers are affected by the distortions introduced by projected coordinate systems. These distortions might be something to worry about if your analysis involves wide buffers especially with a wider range of latitudes across big areas (I presume Canada is a good candidate).
I came across the same issue some time ago and I targeted my question towards gis.stackexchange - Euclidean and Geodesic Buffering in R. I think the R code that I proposed then and also the given answer are relevant to this question here as well.
The main idea is to make use of geosphere::destPoint(). For more details and a faster alternative, see the mentioned gis.stackexchange link above. Here is my older attempt applied on your two points:
library(geosphere)
library(sp)
pts <- data.frame(lon = c(-53.20198, -52.81218),
lat = c(47.05564, 47.31741))
pts
#> lon lat
#> 1 -53.20198 47.05564
#> 2 -52.81218 47.31741
make_GeodesicBuffer <- function(pts, width) {
# A) Construct buffers as points at given distance and bearing ---------------
dg <- seq(from = 0, to = 360, by = 5)
# Construct equidistant points defining circle shapes (the "buffer points")
buff.XY <- geosphere::destPoint(p = pts,
b = rep(dg, each = length(pts)),
d = width)
# B) Make SpatialPolygons -------------------------------------------------
# Group (split) "buffer points" by id
buff.XY <- as.data.frame(buff.XY)
id <- rep(1:dim(pts)[1], times = length(dg))
lst <- split(buff.XY, id)
# Make SpatialPolygons out of the list of coordinates
poly <- lapply(lst, sp::Polygon, hole = FALSE)
polys <- lapply(list(poly), sp::Polygons, ID = NA)
spolys <- sp::SpatialPolygons(Srl = polys,
proj4string = CRS("+proj=longlat +ellps=WGS84 +datum=WGS84"))
# Disaggregate (split in unique polygons)
spolys <- sp::disaggregate(spolys)
return(spolys)
}
pts_buf_100km <- make_GeodesicBuffer(as.matrix(pts), width = 100*10^3)
# Make a kml file and check the results on Google Earth
library(plotKML)
#> plotKML version 0.5-9 (2019-01-04)
#> URL: http://plotkml.r-forge.r-project.org/
kml(pts_buf_100km, file.name = "pts_buf_100km.kml")
#> KML file opened for writing...
#> Writing to KML...
#> Closing pts_buf_100km.kml
Created on 2019-02-11 by the reprex package (v0.2.1)
And to toy around, I wrapped the function in a package - geobuffer
Here is an example:
# install.packages("devtools") # if you do not have devtools, then install it
devtools::install_github("valentinitnelav/geobuffer")
library(geobuffer)
pts <- data.frame(lon = c(-53.20198, -52.81218),
lat = c(47.05564, 47.31741))
pts_buf_100km <- geobuffer_pts(xy = pts, dist_m = 100*10^3)
Created on 2019-02-11 by the reprex package (v0.2.1)
Others might come up with better solutions, but for now, this worked well for my problems and hopefully can solve other's problems as well.

Resources