Reputation: 1752
I have a dataframe of lines, each line with a x/y start and end coordinate. These lines describe a grid / fishnet as you can see in the minimal example below. Regrettably, the grid is not perfectly even and every so often shifted a bit.
library(sf)
#> Linking to GEOS 3.6.1, GDAL 2.2.3, PROJ 4.9.3
library(purrr)
library(ggplot2)
df <- data.frame(
x_start = c(2:9,rep(1,8)),
x_end = c(2:9,rep(10,8)),
y_start = c(rep(1,8),2:9),
y_end = c(rep(10,8),2:9)
)
head(df)
#> x_start x_end y_start y_end
#> 1 2 2 1 10
#> 2 3 3 1 10
#> 3 4 4 1 10
#> 4 5 5 1 10
#> 5 6 6 1 10
#> 6 7 7 1 10
lines_sf <- pmap(df,function(x_start,x_end,y_start,y_end){
st_linestring(
matrix(
c(
x_start,
y_start,
x_end,
y_end),
ncol = 2,byrow = TRUE)
)
}) %>%
st_as_sfc()
lines_sf
#> Geometry set for 16 features
#> geometry type: LINESTRING
#> dimension: XY
#> bbox: xmin: 1 ymin: 1 xmax: 10 ymax: 10
#> CRS: NA
#> First 5 geometries:
#> LINESTRING (2 1, 2 10)
#> LINESTRING (3 1, 3 10)
#> LINESTRING (4 1, 4 10)
#> LINESTRING (5 1, 5 10)
#> LINESTRING (6 1, 6 10)
plot(lines_sf)
I would like to create polygons from these lines, where each square (of the smallest unit) is an individual polygon (no overlaps). I've illustrated this with a manually constructed example below:
polygons <- data.frame(x1 = rep(2:8,8),y1 = sort(rep(2:8,8)))
polygons$x2 <- polygons$x1+1
polygons$x3 <- polygons$x2
polygons$x4 <- polygons$x1
polygons$y2 <- polygons$y1
polygons$y3 <- polygons$y1+1
polygons$y4 <- polygons$y3
polygons_sf <- pmap(polygons,function(x1,x2,x3,x4,y1,y2,y3,y4){
st_polygon(
list(st_linestring(
matrix(
c(x1,y1,x2,y2,x3,y3,x4,y4,x1,y1),
ncol = 2,byrow = TRUE)
))
)
}) %>%
st_as_sfc() %>%
st_sf()
polygons_sf$nrow <- 1:nrow(polygons_sf)
ggplot() + geom_sf(data = polygons_sf, aes(fill = factor(nrow))) +
geom_sf(data = lines_sf, colour = "red",lty = 2) +
theme(legend.position = "none")
Created on 2020-03-09 by the reprex package (v0.3.0)
The ESRI Tool "Feature to Polygon" allows this kind of operation, as shown in the image below:
Upvotes: 3
Views: 1012
Reputation: 1752
A colleague made me aware of st_polygonize()
, which does the trick!
polygons_sf <- st_sf(st_cast(st_polygonize(st_union(lines_sf))))
polygons_sf$nrow <- rnorm(nrow(polygons_sf))
plot(polygons_sf)
Created on 2020-03-10 by the reprex package (v0.3.0)
Upvotes: 3
Reputation: 3402
Try this, the idea is to create an actual grid (polygons) fitted to your example, label the cells by row and col and filter the first and last row & col:
#Size, if not square you could create sizex and sizey
size=length(unique(df$x_start))
#Grid to pols
grid=st_make_grid(lines_sf, n=c(size,size)) #Final number of cells
#Add a df
grid.df=st_sf(ind=1:length(grid), grid)
#Label rows and cols
grid.df$row=cut(grid.df$ind,size, labels=FALSE)
grid.df$col=rep(1:size,size)
#Filter our first and last col and row
polys <- grid.df[!grid.df$row %in% c(1,size) & !grid.df$col %in% c(1,size),]
plot(st_geometry(polys), col="red", add=TRUE)
Upvotes: 2