(def memo-fractal (memoize fractal))
(def fractal-name->params { "hilbert-curve" hilbert-params
"tree" (tree-params [(/ PI 6) (/ PI -3)])
"sierp-3" (sierpinski-params 3)
"sierp-4" (sierpinski-params 4)
"koch" koch-params
"koch-line" koch-line-params
})
(def fractal-state (reagent.core/atom {:params (first (vals fractal-name->params)) :step 0}))
(defn gui-fractals[]
(let[{:keys [params step]} @fractal-state]
[:div
[:div (into [:select {:on-change (fn[e] (swap! fractal-state assoc :params (get fractal-name->params (.-target.value e))))}]
(mapv (fn[k] [:option {:value k} k]) (keys fractal-name->params)))]
[:div [:input {:type "range" :value (:step @fractal-state) :min 0 :max 6 :style {:width "90%"}
:on-change (fn[e] (swap! fractal-state assoc :step (js/parseFloat (.-target.value e))))}]]
[draw-fitted-polylines [400 400] (memo-fractal params (int step))]]))
(def memo-fractal-with-steps (memoize fractal-with-steps)) ;; not so sure about a memo with a float arg ! :(
(def fractal-with-steps-state (reagent.core/atom {:params (first (vals fractal-name->params)) :step 0}))
(let [k 32
n 5]
(display-svgs! js/klipse-container 200
(map (comp (partial draw-fitted-polylines [400 400])
(partial fractal-with-steps
(get fractal-name->params "sierp-4"))
(partial * (/ 1 k))) (range k (* n k)))))
(defn gui-fractals-stepified[]
(let[{:keys [params step]} @fractal-with-steps-state]
[:div
[:div (into [:select {:on-change (fn[e] (swap! fractal-with-steps-state assoc :params (get fractal-name->params (.-target.value e))))}]
(mapv (fn[k] [:option {:value k} k]) (keys fractal-name->params)))]
[:div [:input {:type "range" :value (:step @fractal-with-steps-state) :step 0.01 :min 0 :max 6 :style {:width "90%"}
:on-change (fn[e] (swap! fractal-with-steps-state assoc :step (js/parseFloat (.-target.value e))))}]]
[draw-fitted-polylines [400 400] (memo-fractal-with-steps params step)]]))
(defn fractal-step [[step-f step-elts] current-elts]
(into step-elts (step-f current-elts)))
(defn fractal [[init-elts step-params] details]
(nth (iterate (partial fractal-step step-params) init-elts) details))
(defn merged-juxt[fs]
(comp (partial reduce into [])(apply juxt fs)))
;; cf. infra
(defn merged-juxt[fs]
(with-meta (comp (partial reduce into []) (apply juxt fs))
{:is-from merged-juxt
:args fs}))
(defn sierpinski-params [n]
(let[step-elt (regular-polygon n)
make-transform #(make-polylines-transform (comp (partial add %)
(partial scale (/ 1 (dec n)))))]
(condp = n
3 [[]
[(merged-juxt (for [i [0 1 2]] (make-transform (rotate (+ PI (* i 2 (/ PI 3))) [1. 0.]))))
[step-elt]]]
4 [[]
[(merged-juxt (let [d [-1 0 1]]
(for [dx d dy d :when (not= 0 dx dy)]
(make-transform (scale (sqrt 2.) [dx dy])))))
[(map (partial rotate (/ PI 4)) step-elt)]]])))
[draw-fitted-polylines [400 400] (fractal (sierpinski-params 3) 6)]
(def TWO_PI (* 2 PI))
(defn regular-polygon [n]
(vec (take (inc n)(iterate (partial rotate (/ TWO_PI n)) [1. 0]))))
[draw-fitted-polylines [200 200] (map regular-polygon (range 3 7))]
(defn tree-params [angles]
(let[branch [0 -1]
ratio (/ (+ 1 (sqrt 5.)) 2.)]
[[]
[(merged-juxt (for [a angles]
(make-polylines-transform
(comp (partial add branch)
(partial scale (/ 1 ratio))
(partial rotate a)))))
[[[0. 0] branch]]]]))
[draw-fitted-polylines [400 400] (fractal (tree-params [(/ PI 6)(/ PI -3)]) 8)]
(def koch-params [[[[-0.5 0][0.5 0]]]
[(merged-juxt (for [[v a] [[[(/ -1 3) 0] 0]
[[(/ 1 3) 0] 0]
[(rotate (/ PI -3) [(/ 1 6) 0]) (/ PI 3)]
[(rotate (/ PI 3) [(/ -1 6) 0]) (/ PI -3)]]]
(make-polylines-transform (comp (partial add v)
(partial rotate a)
(partial scale (/ 1 3))))))
[]]])
[draw-fitted-polylines [400 400] (fractal koch-params 4)]
;; hilbert is different because there is only one polyline. We do not transform and merge sequences of polylines but transform and merge polylines (sequences of points). Also, the initial polyline is only one point long.
(def hilbert-transform
(comp (merged-juxt
[(comp (partial mapv (comp (partial add [-0.5 0.5]) (partial rotate (/ PI 2)))) reverse)
(partial mapv (partial add [-0.5 -0.5]))
(partial mapv (partial add [0.5 -0.5]))
(comp (partial mapv (comp (partial add [0.5 0.5]) (partial rotate (/ PI -2)))) reverse)])
(partial mapv (partial scale 0.5))))
[draw-fitted-polylines [400 400] [(nth (iterate hilbert-transform [[0 0]]) 5)]]
(def hilbert-params [[[[0 0]]] [(partial mapv hilbert-transform) []]])
[draw-fitted-polylines [400 400] (fractal hilbert-params 6)]
(def koch-transform
(let [s (partial scale (/ 1 3))]
(comp (merged-juxt
[(partial mapv (comp (partial add [(/ -1 3) 0]) s))
(comp rest (partial mapv (comp (partial add (rotate (/ PI 3) [(/ -1 6) 0])) (partial rotate (/ PI -3)) s)))
(comp rest (partial mapv (comp (partial add (rotate (/ PI -3) [(/ 1 6) 0])) (partial rotate (/ PI 3)) s)))
(comp rest (partial mapv (comp (partial add [(/ 1 3) 0]) s)))]))))
[draw-fitted-polylines [400 400] [(nth (iterate koch-transform [[-0.5 0][0.5 0]]) 2)]]
(def koch-line-params [[[[-0.5 0] [0.5 0]]] [(partial mapv koch-transform) []]])
[draw-fitted-polylines [400 400] (fractal koch-line-params 6)]
This is an org fragment With α textsup
This is an org fragment With α textsup elisp → org src