Skip to content

Instantly share code, notes, and snippets.

@rm-hull
Last active December 16, 2015 20:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rm-hull/5491968 to your computer and use it in GitHub Desktop.
Save rm-hull/5491968 to your computer and use it in GitHub Desktop.
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