Last active
August 29, 2015 14:05
-
-
Save rm-hull/4a74ef32e6956801b289 to your computer and use it in GitHub Desktop.
A recursively generated tree is simply _a branch with a tree on the end of it_.
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.demo.recursive-trees | |
(:require-macros | |
[cljs.core.async.macros :refer [go]] | |
[dommy.macros :refer [sel1 node]]) | |
(:require | |
[cljs.core.async :refer [chan <! >!]] | |
[dommy.core :refer [insert-after!]] | |
[jayq.core :refer [$ hide show]] | |
[big-bang.core :refer [big-bang]] | |
[big-bang.components :refer [dropdown slider]] | |
[enchilada :refer [ctx canvas canvas-size value-of]] | |
[monet.canvas :refer [alpha circle stroke-style stroke-width fill-style fill-rect | |
begin-path line-to move-to close-path stroke composition-operation]])) | |
(def canvas-width (first (canvas-size))) | |
(def canvas-height (second (canvas-size))) | |
(def colors ["red" "green" "blue" "yellow" "purple" "orange"]) | |
(def initial-state { | |
:color (rand-nth colors) | |
:rand (value-of :rand "y") | |
:init-height (value-of :init-height 100) | |
:branch-fan (value-of :branchfan 110) | |
:branch-density (value-of :branchdensity 3) | |
:input-angle-factor (value-of :inpafact 0.8) | |
:input-height-factor (value-of :inphf 0.8) | |
:depth (value-of :depth 5)}) | |
(defn handle-incoming-msg [event world-state] | |
(-> | |
world-state | |
(merge event))) | |
(defn degrees->radians [d] | |
(/ (* (double d) Math/PI) 180.0)) | |
(defn draw-tree! [ctx [x y] angle branch-fan height depth world-state] | |
(if (zero? depth) | |
ctx | |
(let [theta (/ branch-fan (:branch-density world-state)) | |
;start (- angle (/ branch-fan 2)) | |
start (- angle theta) | |
height-factor (if (<= depth 2) | |
(/ (:input-height-factor world-state) 2) | |
(:input-height-factor world-state)) | |
height' (* height height-factor) | |
branch-fan' (* branch-fan (:input-angle-factor world-state)) | |
x' (+ x (* height (Math/cos (degrees->radians angle)))) | |
y' (+ y (* height (Math/sin (degrees->radians angle)))) | |
next-pos [x' y']] | |
(loop [angle start | |
i (:branch-density world-state)] | |
(when (pos? i) | |
(line-to ctx x' (- canvas-height y')) | |
(if (= (:rand world-state) "n") | |
(draw-tree! | |
ctx | |
next-pos | |
angle | |
branch-fan' | |
height' | |
(dec depth) | |
world-state) | |
(draw-tree! | |
ctx | |
next-pos | |
(+ angle (/ theta -2) (* (rand) theta)) | |
branch-fan' | |
(* height' (/ (+ 0.5 (rand)) 1.5)) | |
(dec depth) | |
world-state)) | |
(move-to ctx x (- canvas-height y)) | |
(recur | |
(+ angle theta) | |
(dec i)))) | |
ctx))) | |
(defn render [world-state] | |
(-> | |
ctx | |
(fill-style :white) | |
(fill-rect {:x 0 :y 0 :w canvas-width :h canvas-height}) | |
(composition-operation :darker) | |
(stroke-style (:color world-state)) | |
(stroke-width 2) | |
(begin-path) | |
(move-to (/ canvas-width 2) (- canvas-height 20)) | |
(draw-tree! | |
[(/ canvas-width 2) 20] | |
90 | |
(:branch-fan world-state) | |
(:init-height world-state) | |
(:depth world-state) | |
world-state) | |
(stroke))) | |
(defn box [content] | |
[:span {:style "width: 300px; | |
display: inline-block; | |
border: 1px solid lightgrey; | |
margin-right: 5px; | |
margin-bottom: 5px; | |
padding-left: 5px; | |
border-radius: 3px; | |
background: whitesmoke;"} content]) | |
(defn start [] | |
(let [updates-chan (chan 1)] | |
(go | |
(->> | |
(sel1 :#canvas-area) | |
(insert-after! (node | |
[:div | |
[:div | |
(box (slider | |
:id :depth | |
:label-text " Depth: " | |
:initial-value (:depth initial-state) | |
:min-value 2 | |
:max-value 8 | |
:step 1 | |
:send-channel updates-chan)) | |
(box (slider | |
:id :init-height | |
:label-text " Init height: " | |
:initial-value (:init-height initial-state) | |
:min-value 10 | |
:max-value 400 | |
:step 5 | |
:send-channel updates-chan)) | |
(dropdown | |
:id :color | |
:label-text " Color: " | |
:initial-value (:color initial-state) | |
:options (zipmap colors colors) | |
:send-channel updates-chan)] | |
[:div | |
(box (slider | |
:id :branch-fan | |
:label-text " Branch Fan: " | |
:initial-value (:branch-fan initial-state) | |
:min-value 0 | |
:max-value 360 | |
:step 1 | |
:send-channel updates-chan)) | |
(box (slider | |
:id :branch-density | |
:label-text " Branch Density: " | |
:initial-value (:branch-density initial-state) | |
:min-value 1 | |
:max-value 8 | |
:step 1 | |
:send-channel updates-chan)) | |
(dropdown | |
:id :rand | |
:label-text " Random: " | |
:initial-value (:rand initial-state) | |
:options {"y" "On" "n" "Off"} | |
:send-channel updates-chan)] | |
[:div | |
(box (slider | |
:id :input-angle-factor | |
:label-text " Input Angle Factor: " | |
:initial-value (:input-angle-factor initial-state) | |
:min-value 0.0 | |
:max-value 5.0 | |
:step 0.05 | |
:send-channel updates-chan)) | |
(box (slider | |
:id :input-height-factor | |
:label-text " Input Height Factor: " | |
:initial-value (:input-height-factor initial-state) | |
:min-value 0.0 | |
:max-value 5.0 | |
:step 0.05 | |
:send-channel updates-chan))]])))) | |
(big-bang | |
:initial-state initial-state | |
:on-receive handle-incoming-msg | |
:receive-channel updates-chan | |
:to-draw render))) | |
(show canvas) | |
(start) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment