Thanks to Esteban Moro for fine-tuning this simulation, and contributing his changes
library(chipmunkbasic)
library(ggplot2)
set.seed(1)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Initialize a simulation space
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cm <- Chipmunk$new(time_step = 0.005)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Add funnel segments
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gap <- 2
cm$add_static_segment( -70, 130, -gap, 91)
cm$add_static_segment( 70, 130, gap, 91)
cm$add_static_segment(-gap, 91, -gap, 90)
cm$add_static_segment( gap, 91, gap, 90)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Add pins
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
for (i in 1:15) {
y <- 90 - i * 3
if (i %% 2 == 1) {
xs <- seq(0, 40, 2)
} else {
xs <- seq(1, 40, 2)
}
xs <- 1.0 * sort(unique(c(xs, -xs)))
w <- 0.05
xstart <- xs - w
xend <- xs + w
for (xi in seq_along(xs)) {
cm$add_static_segment(xstart[xi], y, xend[xi], y)
}
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Add slots
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
floor <- 0
width <- 60
for (x in seq(-width, width, 3)) {
cm$add_static_segment(x, floor, x, 40)
}
cm$add_static_segment(-width, floor, width, floor)
cm$add_static_segment(-width, floor-0.2, width, floor-0.2)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Fetch all the segments. Use for plotting
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
segments_df <- cm$get_static_segments()
ggplot() +
geom_segment(data = segments_df, aes(x = x1, y = y1, xend = x2, yend = y2)) +
coord_fixed() +
theme_void() +
theme(legend.position = 'none')
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Prepare the directory for output images
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<<<<<<< HEAD
unlink(list.files("vignettes/png", "*.png", full.names = TRUE))
=======
<- here::here("vignettes")
root_dir <- file.path(root_dir, "png")
png_dir unlink(list.files(png_dir, pattern = "*.png", full.names = TRUE))
>>>>>>> internal-refactor
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# (1) advance the simulation (2) plot the circles (3) Repeat.
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<- seq(-60,60,len=100)
x0 for (i in 1:1000) {
if (i %% 10 == 0) message(i)
$advance(5)
cm
<- cm$get_circles()
circles
<- ggplot(circles) +
p geom_point(aes(x, y), size = 1.6) +
geom_segment(data = segments_df, aes(x = x1, y = y1, xend = x2, yend = y2)) +
coord_fixed() +
theme_void() +
theme(legend.position = 'none') +
geom_line(data=data.frame(x0),inherit.aes = F,aes(x=x0,y=1000*exp(-x0^2/(2*10^2))/sqrt(2*pi*10^2)),col="darkred",alpha=0.8,lwd=1) +
NULL
<- sprintf("vignettes/png/%04i.png", i)
outfile ggsave(outfile, p, width = 7, height = 7)
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ffmpeg/gifsicle to create animations
# - create mp4 from PNG files (use in vignettes)
# - create gif from mp4 (use in github readme)
# - simplify gif with gifsicle
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<<<<<<< HEAD
system("ffmpeg -y -framerate 30 -pattern_type glob -i 'vignettes/png/*.png' -c:v libx264 -pix_fmt yuv420p -s 800x800 vignettes/anim/galton.mp4")
# mp4 to gif
system("ffmpeg -y -i vignettes/anim/galton.mp4 -filter_complex 'fps=30,scale=800:-1:flags=lanczos,split [o1] [o2];[o1] palettegen [p]; [o2] fifo [o3];[o3] [p] paletteuse' man/figures/galton-1.gif")
system("gifsicle -O99 -o man/figures/galton-2.gif -k 16 man/figures/galton-1.gif")
=======
<- "galton"
root_name <- paste0(root_dir, "/anim/", root_name, ".mp4")
mp4_name <- tempfile(fileext = ".gif")
tmp_name <- paste0("man/figures/", root_name, ".gif")
gif_name
system(glue::glue("ffmpeg -y -framerate 30 -pattern_type glob -i '{png_dir}/*.png' -c:v libx264 -pix_fmt yuv420p -s 800x800 '{mp4_name}'"))
system(glue::glue("ffmpeg -y -i '{mp4_name}' -filter_complex 'fps=30,scale=800:-1:flags=lanczos,split [o1] [o2];[o1] palettegen [p]; [o2] fifo [o3];[o3] [p] paletteuse' '{tmp_name}'"))
>>>>>>> internal-refactor
system(glue::glue("gifsicle -O99 -o '{gif_name}' -k 16 '{tmp_name}'"))