Instantly share code, notes, and snippets.

Embed
What would you like to do?
Arnold's cat map is named after the mathematician Vladimir Arnold, who in the 1960s demonstrated the effect of repeatedly applying a linear transformation to an image of a cat (hence the name). Each animation frame transforms the pixels according to the pisano period of the largest dimension (width or height). Eventually the image will restore b…
(ns arnolds-cat-map.demo
(:use [monet.canvas :only [draw-image get-pixel composition-operation]]
[monet.core :only [animation-frame]]
[enchilada :only [ctx canvas proxy-request]]
[jayq.core :only [show]]
[jayq.util :only [wait]])
(:use-macros [dommy.macros :only [sel1 node]]))
(def cat-resources
[
"https://gist.github.com/rm-hull/8859515c9dce89935ac2/raw/cat_01.jpg"
"https://gist.github.com/rm-hull/8859515c9dce89935ac2/raw/cat_02.jpg"
"https://gist.github.com/rm-hull/8859515c9dce89935ac2/raw/cat_03.jpg"
"https://gist.github.com/rm-hull/8859515c9dce89935ac2/raw/cat_04.jpg"
"https://gist.github.com/rm-hull/8859515c9dce89935ac2/raw/cat_05.jpg"
"https://gist.github.com/rm-hull/8859515c9dce89935ac2/raw/cat_06.jpg"
"https://gist.github.com/rm-hull/8859515c9dce89935ac2/raw/cat_07.jpg"
"https://gist.github.com/rm-hull/8859515c9dce89935ac2/raw/cat_08.jpg"
])
(defn random-cat []
(nth cat-resources (rand-int (count cat-resources))))
(defn load-image! [url & [callback-fn]]
(let [img (js/Image.)]
(when callback-fn
(set! (.-onload img) (fn [] (callback-fn img))))
(set! (.-crossOrigin img) "anonymous")
(set! (.-src img) (proxy-request url)))
img)
(defn offset [[x y] w]
(* (+ (* y w) x) 4))
(defn pisano-period [n]
(fn [x y]
[(mod y n) (mod (+ x y) n)]))
(defn draw-frame! [ctx n mapper-fn]
(let [image-in (. ctx (getImageData 0 0 n n))
image-out (. ctx (createImageData n n))
data-in (.-data image-in)
data-out (.-data image-out)]
(doseq [y (range n)
x (range n)
:let [i (offset [x y] n)
o (offset (mapper-fn x y) n)]
c (range 4)]
(aset data-out (+ o c) (aget data-in (+ i c))))
(. ctx (putImageData image-out 0 0))
ctx))
(defn animate [img]
(let [width (.-width img)
height (.-height img)]
(draw-image ctx img { :x 0 :y 0 :w width :h height })
(wait
2000
(fn []
(let [n (max width height)
mapper-fn (pisano-period n)]
(letfn [(loop []
(animation-frame loop)
(draw-frame! ctx n mapper-fn))]
(loop)))))))
(show canvas)
(load-image! (random-cat) animate)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment