Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
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…
(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