Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

sample points on polygon edge in R

Tags:

r

gis

polygons

If I have a spatialpolygons object in R, how can I generate a set of n points that are on the edge of that polygon?

I originally thought I could just sample from the polygon vertices, but it looks like there are sometimes stretches where there are no vertices because the polygon edge is a straight line...

like image 993
Pascal Avatar asked Oct 25 '25 06:10

Pascal


2 Answers

A simple solution would be to use st_segmentize() from package sf that adds points to straight lines, then sample along these finer points.

st_segmentize() has an argument dfMaxLength that defines the max distance to allow along a line. The smaller you will set, the more points you will have. It should at least be as small as the minimum distance between any two points.

library(sf)
library(tidyverse)

## original form
poly <- st_polygon(x=list(cbind(x=c(1,2,3,1),y=c(1,2,1,1))))

# segmentize, then convert to points
poly_points <- st_segmentize(poly, dfMaxLength = 0.1) %>% 
  st_coordinates() %>% 
  as.data.frame() %>% 
  select(X, Y) %>% 
  st_as_sf(coords = c("X", "Y"))

## plot: you can just use sample() now on your point dataset
plot(poly, reset = FALSE, main = "segmentize (black point), then sample 5 (red points)")
plot(poly_points, reset = FALSE, add = TRUE)
plot(poly_points[sample(1:nrow(poly_points), size = 5),], add = TRUE, col = 2, pch = 19)

enter image description here

To get the minimum distance between any two points (beware of zero):

 poly %>% 
  st_coordinates() %>% 
  as.data.frame() %>% 
  st_as_sf(coords = c("X", "Y")) %>% 
  st_distance() %>%  c() %>% 
  unique() %>% 
  sort
like image 176
Matifou Avatar answered Oct 26 '25 19:10

Matifou


Assuming you want to draw points around the perimeter, I would split this into two parts:

P(Point p on Edge e) = P(point p | Edge e) P(Edge e)

with P(Edge e) proportional to its length. So first sample an edge, then sample a point on it.

Here's an example triangle:

  poly <- Polygon(list(x=c(1,2,3,1),y=c(1,2,1,1)))

We'll calculate the lengths of the sides:

  require(gsl) #for fast hypot function
  xy <- poly@coords
  dxy <- diff(xy)
  h <- hypot(dxy[,"x"], dxy[,"y"])

and draw a random side:

  e <- sample(nrow(dxy), 1, probs=h)

and then draw a point on that edge:

  u <- runif(1)
  p <- xy[e,] + u * dxy[e,]

Wrapping the whole thing in a function, we have:

  rPointOnPerimeter <- function(n, poly) {
    xy <- poly@coords
    dxy <- diff(xy)
    h <- hypot(dxy[,"x"], dxy[,"y"])

    e <- sample(nrow(dxy), n,replace=TRUE, prob=h)

    u <- runif(n)
    p <- xy[e,] + u * dxy[e,]

    p
  }

with a demo:

plot( rPointOnPerimeter(100,poly) )
like image 26
Neal Fultz Avatar answered Oct 26 '25 21:10

Neal Fultz



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!