Created
September 20, 2014 23:43
-
-
Save rm-hull/7124e7b5bb84198b994a to your computer and use it in GitHub Desktop.
A polyline interpolator, implemented in a CSP style: two _big-bang_'s interact - the 'generator' sends pairs of polylines to an 'interpolator' which is responsible for smooth rendering the transitions between the _from_ and _to_ states. The code here will form the basis of future gists: (i) to visualise solving the travelling salesman problem (u…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns big-bang.examples.interpolator | |
(:require | |
[cljs.core.async :as async] | |
[enchilada :refer [canvas ctx canvas-size]] | |
[big-bang.core :refer [big-bang]] | |
[big-bang.package :refer [make-package]] | |
[jayq.core :refer [show]] | |
[monet.canvas :refer [clear-rect fill-style fill fill-rect circle | |
stroke-style stroke-width stroke-join stroke | |
begin-path move-to line-to]])) | |
(defn random-point [] | |
[(+ 20 (rand-int 760)) (+ 20 (rand-int 560))]) | |
(defn make-points [n] | |
(repeatedly n random-point)) | |
(defn interpolate-line [from to n] | |
(let [from (vec from) | |
size (count from) | |
step (fn [f] (fn [a b] (double (/ (- (f b) (f a)) n)))) | |
delta (mapv (juxt (step first) (step second)) from to)] | |
(fn [idx t] | |
(when (and (< idx size) (<= t n)) | |
(let [[dx dy] (nth delta idx) | |
[x y] (nth from idx)] | |
[(+ x (* dx t)) (+ y (* dy t))]))))) | |
(def dummy) | |
(def background | |
(let [[w h] (canvas-size)] | |
{:x 0 :y 0 :w w :h h})) | |
(defn update-clock [event world-state] | |
(update-in world-state [:t] inc)) | |
(defn create-new-interpolator [event world-state] | |
(let [[from to] (event :lines)] | |
(assoc world-state | |
:interpolator (interpolate-line from to 58) | |
:t 0))) | |
(defn draw-polyline [ctx interpolator t] | |
(let [[x y] (interpolator 0 t)] | |
(-> | |
ctx | |
(begin-path) | |
(move-to x y))) | |
(loop [i 1] | |
(when-let [[x y] (interpolator i t)] | |
(line-to ctx x y) | |
(recur (inc i)))) | |
(stroke ctx)) | |
(defn draw-circles [ctx interpolator t] | |
(begin-path ctx) | |
(loop [i 0] | |
(when-let [[x y] (interpolator i t)] | |
(-> ctx (circle {:x x :y y :r 5}) (fill)) | |
(recur (inc i)))) | |
ctx) | |
(defn render [{:keys [interpolator t] :as world-state}] | |
(when (interpolator 0 t) | |
(-> | |
ctx | |
(clear-rect background) | |
(fill-style :red) | |
(stroke-style :red) | |
(stroke-width 3) | |
(stroke-join :round) | |
(draw-polyline interpolator t) | |
(draw-circles interpolator t)))) | |
(defn send-lines [event {:keys [lines] :as world-state}] | |
(make-package | |
(update-in world-state [:lines] next) | |
{:lines (take 2 lines)})) | |
(defn mutate [points] | |
(let [i (rand-int 20) | |
j (rand-int 20)] | |
(assoc | |
points | |
j (points i) | |
i (points j)))) | |
(def initial-state | |
(let [points (vec (make-points 20))] | |
;{:lines (repeatedly #(make-points 20))} | |
;{:lines (repeatedly #(mutate points))} | |
{:lines (repeatedly #(shuffle points))} | |
)) | |
(defn start [] | |
(show canvas) | |
(let [chan (async/chan)] | |
;;; INTERPOLATOR: | |
; this big-bang is responsible for rendering tween lines | |
(big-bang | |
:initial-state {:interpolator (constantly nil)} | |
:on-tick update-clock | |
:receive-channel chan | |
:on-receive create-new-interpolator | |
:to-draw render) | |
;;; GENERATOR: | |
; this big-bang generates lines, and sends pairs to the INTERPOLATOR | |
(big-bang | |
:initial-state initial-state | |
:on-tick send-lines | |
:send-channel chan | |
:tick-rate 1200))) | |
(start) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment