Search code examples
rspatialr-sf

Optimize polygons creating from points


I have a matrix that consists of X and Y coordinates and their offsets (nXSize, nYSize). Based on it, I create polygons in a loop. Below code is very slow for a large number of points, can I somehow optimize it?

mat = structure(c(1, 1, 1, 1, 1, 1, 1, 65, 129, 193, 257, 321, 64,
                  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64), .Dim = c(6L, 4L),
                .Dimnames = list(
                  c("1", "2", "3", "4", "5", "6"),
                  c("x", "y", "nXSize", "nYSize")))

lst = sf::st_sfc(sf::st_polygon())

for (i in seq_len(nrow(mat))) {
  p1 = c(mat[i, 1], mat[i, 2])
  p2 = c(mat[i, 1] + mat[i, 3], mat[i, 2])
  p3 = c(mat[i, 1] + mat[i, 3], mat[i, 2] + mat[i, 4])
  p4 = c(mat[i, 1], mat[i, 2] + mat[i, 4])

  pts = matrix(c(p1, p2, p3, p4, p1), ncol = 2, byrow = TRUE)
  pts = pts - 1 # align matrix to P(0, 0)

  polygon = sf::st_sfc(sf::st_polygon(list(pts)))
  lst = c(lst, polygon)
}

# remove empty geometry
lst = lst[-1]

Solution

  • This should be faster. First use vectorization to compute all of the vertices and center them:

    p1 <- cbind(mat[, 1], mat[, 2]) - 1
    p2 <- cbind(mat[, 1] + mat[, 3], mat[, 2]) - 1
    p3 <- cbind(mat[, 1] + mat[, 3], mat[, 2] + mat[, 4]) - 1
    p4 <- cbind(mat[, 1], mat[, 2] + mat[, 4]) - 1
    ply <- cbind(p1, p2, p3, p4, p1)
    

    Now ply is a matrix with one row for each polygon. Next convert ply into a list of matrices (plys) and then convert the list of matrices into a list of polygons (lst):

    plys <- lapply(1:nrow(ply), function(i) matrix(ply[i, ], ncol=2, byrow=TRUE))
    lst <- sapply(plys, function(x) sf::st_sfc(sf::st_polygon(list(x))))