# Aperiodic monotile # Single-tile code by Otto Perdeck # https://rpubs.com/OttoP/1019978 # # Multi-tile code by Bryan Clair # http://turtlegraphics.wordpress.com/ library(ggplot2) library(dplyr) kite_longlen <- cos(pi/6) kite_shortlen <- sin(pi/6) a <- sin(pi/6)*kite_longlen # = sqrt(3)/4 b <- cos(pi/6)*kite_longlen # = 0.75 kite <- matrix(c(0, 0, a, b, 0, 1, -a, b), byrow=T, ncol=2) kitedf <- as.data.frame(kite) names(kitedf) <- c("x", "y") kitedf$p <- 1:nrow(kitedf) ggplot(kitedf, aes(x, y)) + geom_polygon(fill="blue") + geom_label(aes(label=p))+ theme_minimal() + theme(aspect.ratio = 1) + ggtitle("Kite") rotationMatrix <- function(theta) { matrix(c(cos(theta), -sin(theta), sin(theta), cos(theta)), byrow=T, nrow=2) } transpose <- function(m, x, y) { m + matrix(c(rep(x, dim(m)[1]), rep(y, dim(m)[1])), byrow=F, ncol=2) } kite1 <- as.data.frame(kite%*%rotationMatrix(-pi/6)) kite1$kite <- 1 kite2 <- as.data.frame(kite%*%rotationMatrix(pi/6)) kite2$kite <- 2 kite3 <- as.data.frame(transpose(kite%*%rotationMatrix(5*pi/6), 0, 2*kite_longlen)) kite3$kite <- 3 kite4 <- as.data.frame(transpose(kite%*%rotationMatrix(-3*pi/6), 1+kite_shortlen, kite_longlen)) kite4$kite <- 4 kite5 <- as.data.frame(transpose(kite%*%rotationMatrix(3*pi/6), 0, 2*kite_longlen)) kite5$kite <- 5 kite6 <- as.data.frame(transpose(kite%*%rotationMatrix(-pi/6), 1+kite_shortlen, kite_longlen)) kite6$kite <- 6 kite7 <- as.data.frame(transpose(kite%*%rotationMatrix(-5*pi/6), 1+kite_shortlen, kite_longlen)) kite7$kite <- 7 kite8 <- as.data.frame(transpose(kite%*%rotationMatrix(5*pi/6), 1+kite_shortlen, kite_longlen)) kite8$kite <- 8 monotile_composite <- do.call("rbind", list(kite1, kite2, kite3, kite4, kite5, kite6, kite7, kite8)) names(monotile_composite) <- c("x", "y", "kite") monotile_composite$kite <- as.factor(monotile_composite$kite) offset_x <- mean(monotile_composite$x) offset_y <- mean(monotile_composite$y) monotile_composite$x <- monotile_composite$x-offset_x monotile_composite$y <- monotile_composite$y-offset_y size <- max(c(monotile_composite$x, monotile_composite$y)) ggplot(monotile_composite, aes(x=x,y=y,group=kite,fill=kite)) + geom_polygon() + theme_minimal() + theme(aspect.ratio = 1) + xlim(c(-size,size)) + ylim(c(-size,size)) + ggtitle("Composite Monotile") refPoint <- function(k,i) { unlist(k[i,1:2]) } monotile <- matrix(c(refPoint(kite1, 1), refPoint(kite1, 4), refPoint(kite1, 3), refPoint(kite1, 2), refPoint(kite3, 1), refPoint(kite5, 4), refPoint(kite5, 3), refPoint(kite6, 2), refPoint(kite6, 1), refPoint(kite8, 4), refPoint(kite8, 3), refPoint(kite8, 2), refPoint(kite7, 3), refPoint(kite7, 2)), byrow = T, ncol=2) monotile[,1] <- monotile[,1]-offset_x # mean(monotile[,1]) monotile[,2] <- monotile[,2]-offset_y # mean(monotile[,2]) ggplot(as.data.frame(monotile), aes(V1, V2)) + geom_polygon(mapping = aes(x=x,y=y,group=kite), data = monotile_composite, fill="purple", color="grey") + geom_path(data=as.data.frame(rbind(monotile, monotile[1,])), color="black", size=1) + theme_minimal() + theme(aspect.ratio = 1) + xlim(c(-size,size)) + ylim(c(-size,size)) + ggtitle("Monotile") + xlab("x") + ylab("y") ggplot(as.data.frame(monotile), aes(V1, V2)) + geom_polygon(mapping = aes(x=x,y=y,group=kite), data = monotile_composite, fill='white', color="grey") + geom_path(data=as.data.frame(rbind(monotile, monotile[1,])), color="black", size=1) + theme_void() + theme(aspect.ratio = 1) + xlim(c(-size,size)) + ylim(c(-size,size)) ggplot(monotile_df, aes(V1, V2)) + geom_polygon(mapping = aes(x=x,y=y,group=kite), data = monotile_composite, fill='white', color="grey") + geom_path(data=as.data.frame(rbind(monotile, monotile[1,])), color="black", size=1) + theme_void() + theme(aspect.ratio = 1) + xlim(c(-size,size)) + ylim(c(-size,size)) # Bryan Clair's code starts here # # Build a data frame "one_tile" with vertices, a kite variable for polygons, # and an order variable to draw the outside edge. This simplifys the structure # of the data and makes it easier to handle multiple tiles # monotile_edge <- as.data.frame(rbind(monotile, monotile[1,])) %>% select(x=V1, y=V2) monotile_edge %>% ggplot(aes(x=x,y=y)) + geom_path() one_tile <- monotile_edge %>% mutate(order = row_number()) %>% left_join(monotile_composite, ., by=c('x','y')) %>% mutate(order = ifelse(duplicated(order),NA,order)) # Plot the kite polygons one_tile %>% ggplot(aes(x=x,y=y,group=kite)) + geom_polygon( fill='white', color="grey") # Plot the edge one_tile %>% filter(!is.na(order)) %>% arrange(order) %>% ggplot(aes(x=x,y=y)) + geom_path() # Plot the kite polygons and edge one_tile %>% ggplot(aes(x=x,y=y)) + geom_polygon(aes(group=kite), fill='white', color="grey") + geom_path(data = one_tile %>% arrange(order) %>% filter(!is.na(order))) # Function takes integer (dx,dy) coordinates and translates the # one_tile by the appropriate amount to lie on a periodic tiling # (which of course has holes) # tile_translate <- function(delta) { dx <- delta[1] dy <- delta[2] one_tile %>% mutate(x = x + (2.25)*dx, y = y + sqrt(3)*dy +.425*dx) } # Kludgy way to build a list of translation coordinates tilespots <- list() for (x in 1:5) { for (y in 1:8) { tilespots <- append(tilespots, list(c(x,y))) } } # Create a new data frame with all the translations multi_tiles <- bind_rows(lapply(tilespots, tile_translate), .id='tile') # Plot it multi_tiles %>% ggplot(aes(x=x,y=y)) + geom_polygon( aes(group=interaction(tile,kite)), fill='white', color="grey") + geom_path(data = multi_tiles %>% arrange(order) %>% filter(!is.na(order)), aes(group=tile)) + coord_fixed() + theme_void()