使用 R 的规则(多边形)平铺

Regular (polygonal) tiling using R

我试图想出一个脚本来创建一个矩阵,该矩阵包含规则多边形平铺的相邻多边形的坐标,例如正方形和八边形之间插入了一点 space(space 图中未显示:在那里,多边形共享边)。

我的第一次尝试是从一个起点 "walk" 通过坐标系。但是,当我浏览平铺的第一列时,它变得很复杂,例如向上,现在必须向下走以创建第二列。要么我完全放弃这种方法,要么我想出一个更好的顺序方案。你能帮忙吗?

ID = 1 # not relevant here
p=c(0,0) # starting point
l_m=10 # length of an edge
NODES <- matrix(NA,nrow=0,ncol = 3) 
calculateSquareUp <- function(p_start,l_m) { # draws the points of a square while walking upwards, counterclockwise
  p1=p_start
  p2=p1+c(l_m,0)
  p3=p2+c(0,l_m)
  p4=p3+c(-l_m,0)
  NODES <- rbind(p1,p2,p3,p4)
  NODES <- cbind(ID,NODES)
  list("p_up"=p4,"p_down"=p2,"NODES"=NODES)
}

calculateOctagonUp <- function(p_start,l_m) { # draws the points of an octagon while walking upwards, counterclockwise
  p1=p_start
  p2=p1+c(l_m,0)
  p3=p2+c(l_m,l_m)/sqrt(2)
  p4=p3+c(0,l_m)
  p5=p4+c(-l_m,l_m)/sqrt(2)
  p6=p5+c(-l_m,0)
  p7=p6-c(l_m,l_m)/sqrt(2)
  p8=p7+c(0,-l_m)
  NODES <- rbind(p1,p2,p3,p4,p5,p6,p7,p8)
  NODES <- cbind(ID,NODES)
  list("p_up"=p6,"p_down"=p4,"NODES"=NODES)
}

calculateSquareDown <- function(p_start,l_m) { # draws the points of a square while walking downwards, counterclockwise
  p1=p_start
  p2=p1+c(l_m,0)
  p3=p2+c(0,-l_m)
  p4=p3+c(-l_m,0)
  NODES <- rbind(p1,p2,p3,p4)
  NODES <- cbind(ID,NODES)
  list("p_up"=p2, "p_down"=p2,"NODES"=NODES)
}

calculateOctagonDown <- function(p_start,l_m) { # draws the points of an octagon while walking downwards, counterclockwise
  p1=p_start
  p2=p1+c(l_m,0)
  p3=p2+c(l_m,-l_m)/sqrt(2)
  p4=p3+c(0,-l_m)
  p5=p4+c(-l_m,-l_m)/sqrt(2)
  p6=p5+c(-l_m,0)
  p7=p6-c(-l_m,l_m)/sqrt(2)
  p8=p7+c(0,l_m)
  NODES <- rbind(p1,p2,p3,p4,p5,p6,p7,p8)
  NODES <- cbind(ID,NODES)
  list("p_up"=p3,"p_down"=p6, "NODES"=NODES)
}


space=c(10,10) 
# Easy example: a 2x2 tiling
max_polygons=2 # per column
n_polygons=4 # total number of polygons
NODES <- matrix(NA,nrow=0,ncol = 3) 
for (i in 1:n_polygons){
    if(i < round(n_polygons/2,0)){ # if first column, walk upwards
        for (j in 1:max_polygons) {
          if (j%%2==0){
            listOctagon = calculateOctagonUp(p_start=p,l_m=l_m)
            p = listOctagon[[1]]+space
            NODES <-rbind(NODES,listOctagon[[3]])
          }
          else {
            listSquare = calculateSquareUp(p_start=p,l_m=l_m)
            p = listSquare[[1]]+space
            NODES <-rbind(NODES,listSquare[[3]])

          }
        }
    } else if(i >round(n_polygons/2,0)){ # if second column, walk downwards
        for (j in 1:max_polygons) {
          if (j%%2==0){
            listOctagon = calculateOctagonDown(p_start=p,l_m=l_m)
            p = listOctagon[[2]]+space
            NODES <-rbind(NODES,listOctagon[[3]])
          }
          else {
            listSquare = calculateSquareDown(p_start=p,l_m=l_m)
            p = listSquare[[2]]+space
            NODES <-rbind(NODES,listSquare[[3]])

          }
        }
    }
}


plot(NODES[,2],NODES[,3], type = "p")

这至少是解决 sf 的大部分方法。在这里,我们利用包的仿射变换功能,简单地复制一个由一个八边形和一个正方形组成的瓦片,想复制多少就复制多少。我借用并修改了你的八边形函数来制作一个快速的八边形。显然,这将创建一个如图所示的倾斜网格,但对 plot 函数的一些修改可以在您想要的任何方向上细分单元。关键是通过将 c(x, y) 添加到 sfc 对象来为下一个图块指定正确的翻译。

对于某些背景,sf 将点和线存储为 2 列矩阵,将多边形存储为矩阵列表。这就是为什么st_polygon里面有对list的调用。

library(sf)
#> Linking to GEOS 3.6.1, GDAL 2.2.0, proj.4 4.9.3
square <- st_polygon(
  list(
    matrix(c(0,0,0,1,1,1,1,0,0,0), ncol = 2, byrow = TRUE)
  )
)
calculateOctagonUp <- function(p_start,l_m) { # draws the points of an octagon while walking upwards, counterclockwise
  p1=p_start
  p2=p1+c(l_m,0)
  p3=p2+c(l_m,l_m)/sqrt(2)
  p4=p3+c(0,l_m)
  p5=p4+c(-l_m,l_m)/sqrt(2)
  p6=p5+c(-l_m,0)
  p7=p6-c(l_m,l_m)/sqrt(2)
  p8=p7+c(0,-l_m)
  rbind(p1,p2,p3,p4,p5,p6,p7,p8,p1)
}

octagon <- st_polygon(list(calculateOctagonUp(c(0,1), 1)))

unit <- st_sfc(square, octagon)
plot_grid <- function(tile, nrow, ncol){
  col <- tile
  for (i in 1:nrow){
    col <- c(col, col + c(0, 2 + sqrt(2)))
  }
  grid <- col
  for (i in 1:ncol){
    grid <- c(grid, grid + c(1 + sqrt(2) / 2, -(1 + sqrt(2) / 2)))
  }
  plot(grid)
}

plot_grid(unit, 3, 3)

reprex package (v0.2.0) 创建于 2018-02-22。