Skip to content

Instantly share code, notes, and snippets.

@mstrimas
Created March 8, 2018 20:27
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mstrimas/ac50a38a7e656a2b3a173f3a6b31a760 to your computer and use it in GitHub Desktop.
Save mstrimas/ac50a38a7e656a2b3a173f3a6b31a760 to your computer and use it in GitHub Desktop.
Chaikin's corner cutting algorithm
library(tidyverse)
library(gganimate)
library(hrbrthemes)
# generate a jagged polygon
set.seed(1)
n <- 60
theta <- (runif(n) + 1:n - 1) * 2 * pi / n
radius <- rgamma(n, shape = 3)
radius <- radius / max(radius)
xy <- cbind(cos(theta) * radius, sin(theta) * radius)
xy <- rbind(xy, xy[1, ])
xy[, 1] <- xy[, 1] %>% {(. - min(.)) / (max(.) - min(.))}
xy[, 2] <- xy[, 2] %>% {(. - min(.)) / (max(.) - min(.))}
# function for a single chaikin iteration
chaikin <- function(x) {
n_pts <- nrow(x)
qr <- matrix(NA_real_, nrow = 2 * (n_pts - 1) + 1, ncol = 2)
qr[seq(1, nrow(qr) - 1, by = 2), ] <- 0.75 * x[-n_pts, ] + 0.25 * x[-1, ]
qr[seq(2, nrow(qr) - 1, by = 2), ] <- 0.75 * x[-1, ] + 0.25 * x[-n_pts, ]
qr[nrow(qr), ] <- qr[1, ]
qr
}
# iteratively apply chaikin, saving each step
xy_smoothed <- data.frame(xy) %>%
mutate(iteration = 0) %>%
select(iteration, x = X1, y = X2)
for (i in 1:4) {
xy <- chaikin(xy)
xy_smoothed <- data.frame(xy) %>%
mutate(iteration = i) %>%
select(iteration, x = X1, y = X2) %>%
rbind(xy_smoothed, .)
}
g <- ggplot(xy_smoothed, aes(x, y)) +
geom_polygon(data = filter(xy_smoothed, iteration == 0), fill = "grey40") +
geom_polygon(aes(frame = iteration), lwd = 1.5, color = "red", fill = NA) +
labs(x = NULL, y = NULL,
title = "Chaikin's corner cutting algorithm, iteration = ") +
theme_ipsum_rc() +
theme()
gganimate(g, "chaikin.gif")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment