#+PROPERTY: BLOG Test subtree export #+OPTIONS: toc:nil # I have no idea why the jekyll layout does not work for me ☹ #+name: inline-html-header #+begin_src elisp :exports none :results html :var title="Programming as Composing" (concat " " title " ") #+end_src #+name: inline-gif-js-src #+BEGIN_SRC sh :output :results html :exports none :var id= "gif-js-worker-code" echo " EOF #+END_SRC #+name: inline-klipse-header #+begin_src elisp :exports none :results html :var url="https://storage.googleapis.com/app.klipse.tech/css/codemirror.css" (concat " ") #+end_src #+name: inline-klipse-footer #+begin_src elisp :exports none :results html :var url="https://storage.googleapis.com/app.klipse.tech/plugin/js/klipse_plugin.js" (concat " ") #+end_src http://emacs.stackexchange.com/a/28387 #+name: inline-klipse-clojure #+begin_src elisp :exports none :results html :var blk="" (concat "
\n"
 (cadr (org-babel-lob--src-info blk))
 "\n"
 "
") #+end_src #+name: inline-klipse-clojure-s #+begin_src elisp :exports none :results html :var blks='("") (setq res "") (concat "
\n"
(dolist (blk blks res)
  (setq res (concat res "\n" (cadr (org-babel-lob--src-info blk)))))
 "\n"
 "
") #+end_src should really be an optional boolean parameter of inline-klipse-clojure ! #+name: inline-hidden-klipse-clojure #+begin_src elisp :exports none :results html :var blk="" (concat "
\n"
 (cadr (org-babel-lob--src-info blk))
 "\n"
 "
") #+end_src #+name: inline-hidden-klipse-clojure-s #+begin_src elisp :exports none :results html :var blks='("") (setq res "") (concat "
\n"
(dolist (blk blks res)
  (setq res (concat res "\n" (cadr (org-babel-lob--src-info blk)))))
 "\n"
 "
") #+end_src #+name: inline-klipse-reagent #+begin_src elisp :exports none :results html :var blk="" (concat "
\n"
 (cadr (org-babel-lob--src-info blk))
 "\n"
 "
") #+end_src #+name: inline-klipse-reagent-s #+begin_src elisp :exports none :results html :var blks='("") (setq res "") (concat "
\n"
(dolist (blk blks res)
  (setq res (concat res "\n" (cadr (org-babel-lob--src-info blk)))))
  "\n"
 "
") #+end_src #+name: inline-klipse-reagent-anim-s #+begin_src elisp :exports none :results html :var blks='("") (setq res "") (concat "
\n"
(dolist (blk blks res)
  (setq res (concat res "\n" (cadr (org-babel-lob--src-info blk)))))
  "\n"
 "
") #+end_src #+name: foo #+begin_src clojure :exports none (+ 1 1) #+end_src #+name: bar #+begin_src clojure :exports none (+ 2 2) #+end_src http://endlessparentheses.com/how-i-blog-one-year-of-posts-in-a-single-org-file.html https://github.com/yoshinari-nomura/org-octopress/blob/master/ox-jekyll.el #+NAME: init-reagent-examples #+BEGIN_SRC clojure :exports none (ns my.reagent-examples (:require [clojure.string :as string] [reagent.core :as reagent] [reagent.dom.server] [reagent.ratom])) (enable-console-print!) #+END_SRC #+NAME: src-gif-save-svg #+BEGIN_SRC clojure :exports none (defn str->url [s t] (let[blob (js/Blob. #js [s] #js {:type t})] (.createObjectURL js/URL blob) )) (def worker-url (let[ gif-worker-src (.-textContent (. js/document (getElementById "gif-js-worker-code")))] (str->url gif-worker-src "application/javascript"))) (defn svgs->animated-gif-url![cb delays svgs] (let [delays (if (number? delays) (repeat delays) delays) [w h] ((comp (juxt :width :height) second first) svgs) gif (js/GIF. #js {:workers 4 :quality 1 :width w :height h :workerScript worker-url }) process (fn process[svgs delays](let[img (js/Image.) svg-url (str->url (reagent.dom.server/render-to-static-markup (first svgs)) "image/svg+xml")] (do (set! (.-onload img) (fn[](do (.addFrame gif img #js{:copy true :delay (first delays)}) (let[r (rest svgs)] (if (seq r) (process r (rest delays)) (.render gif) ))))) (set! (.-src img) svg-url))))] (do (.on gif "finished" cb);; partial does not work ?! (process svgs delays)))) (defn save-svgs![filename delays svgs] (letfn [(download-blob! [filename blob] (let[download-link (. js/document (createElement "a"))] (do (set! (.-download download-link) filename) (set! (.-href download-link) (.createObjectURL js/URL blob)) (.click download-link))))] (svgs->animated-gif-url! (fn[blob](download-blob! filename blob)) delays svgs))) (defn display-svgs! ([delays svgs](display-svgs! js/klipse-container delays svgs)) ([parent delays svgs] (svgs->animated-gif-url! (fn[blob] (let[img (js/Image.)] (do (.appendChild parent img) (set! (.-src img) (.createObjectURL js/URL blob))))) delays svgs))) #+END_SRC #+NAME: src-gif-save-svg-use #+BEGIN_SRC clojure :exports none (def data (map (comp (partial draw-fitted-polylines [200 200]) (fn[a][(map (partial rotate a) (regular-polygon 5))]) (partial * 2 (/ PI 64))) (range 64))) (comment ;; <-no auto save (save-svgs! "test-save-svgs.gif" 200 data) ) (display-svgs! 100 data) #+END_SRC #+NAME: src-dynamic-homoiconicity #+BEGIN_SRC clojure :exports none (defn comp [& fs] (with-meta (apply (fn ([] identity) ([f] f) ([f g] (fn ([] (f (g))) ([x] (f (g x))) ([x y] (f (g x y))) ([x y z] (f (g x y z))) ([x y z & args] (f (apply g x y z args))))) ([f g & fs] (reduce comp (list* f g fs)))) fs) {:is-from comp :args fs})) (defn partial [& args] (with-meta (apply (fn ([f] f) ([f arg1] (fn ([] (f arg1)) ([x] (f arg1 x)) ([x y] (f arg1 x y)) ([x y z] (f arg1 x y z)) ([x y z & args] (apply f arg1 x y z args)))) ([f arg1 arg2] (fn ([] (f arg1 arg2)) ([x] (f arg1 arg2 x)) ([x y] (f arg1 arg2 x y)) ([x y z] (f arg1 arg2 x y z)) ([x y z & args] (apply f arg1 arg2 x y z args)))) ([f arg1 arg2 arg3] (fn ([] (f arg1 arg2 arg3)) ([x] (f arg1 arg2 arg3 x)) ([x y] (f arg1 arg2 arg3 x y)) ([x y z] (f arg1 arg2 arg3 x y z)) ([x y z & args] (apply f arg1 arg2 arg3 x y z args)))) ([f arg1 arg2 arg3 & more] (fn [& args] (apply f arg1 arg2 arg3 (concat more args))))) args) {:is-from partial :args args})) (defn mapv [& args] (with-meta (apply (fn ([f coll] (-> (reduce (fn [v o] (conj! v (f o))) (transient []) coll) persistent!)) ([f c1 c2] (into [] (map f c1 c2))) ([f c1 c2 c3] (into [] (map f c1 c2 c3))) ([f c1 c2 c3 & colls] (into [] (apply map f c1 c2 c3 colls)))) args) {:is-from mapv})) (defn merged-juxt[fs] (with-meta (comp (partial reduce into []) (apply juxt fs)) {:is-from merged-juxt :args fs})) #+END_SRC #+NAME: src-svg-polyline #+BEGIN_SRC clojure :exports none (defn svg-polyline[ps] (let[[[x0 y0] & ps] ps init-point (str "M " x0 ", " y0 " ") seg (fn[[x y]] (str "L " x ", " y " "))] (reduce #(str %1 (seg %2)) init-point ps))) #+END_SRC #+NAME: src-svg-polyline-use #+BEGIN_SRC clojure :exports none (svg-polyline [[10 10][10 20][20 20]]) #+END_SRC #+NAME: src-draw-polylines #+BEGIN_SRC clojure :exports none (defn draw-polylines[[w h] pss] [:svg {:xmlns "http://www.w3.org/2000/svg" :width w :height h} [:rect {:x 0 :y 0 :width w :height h :fill "white"}] [:path {:stroke "black" :stroke-width 1 :fill "none" :d (reduce str (map svg-polyline pss))}] ]) #+END_SRC #+NAME: src-draw-polylines-use #+BEGIN_SRC clojure :exports none [draw-polylines [300 300] [[[100 100][100 200][200 250]]]] #+END_SRC #+NAME: src-add #+BEGIN_SRC clojure :exports none (defn add [[x0 y0][x1 y1]] [(+ x0 x1)(+ y0 y1)]) #+END_SRC #+NAME: src-add-use #+BEGIN_SRC clojure :exports none (add [100 200] [10 20]) #+END_SRC #+NAME: src-make-polylines-transform #+BEGIN_SRC clojure :exports none (def make-polylines-transform (comp (partial partial mapv) (partial partial mapv) )) #+END_SRC #+NAME: src-make-polylines-transform-use #+BEGIN_SRC clojure :exports none [draw-polylines [400 400] ((make-polylines-transform (partial add [100 50])) [[[100 100][100 200][200 250]] [[50 50][200 50][200 100]]])] #+END_SRC #+NAME: src-rotate #+BEGIN_SRC clojure :exports none (defn sin[x] (.sin js/Math x)) (defn cos[x] (.cos js/Math x)) (def PI (.-PI js/Math)) (def sqrt #(.sqrt js/Math %)) (defn rotate [a [x y]] (let [c (cos a) s (sin a)] [(- (* c x) (* s y)) (+ (* s x) (* c y))])) #+END_SRC #+NAME: src-rotate-use #+BEGIN_SRC clojure :exports none (rotate (/ PI 4) [10 20]) #+END_SRC #+NAME: src-regular-polygon #+BEGIN_SRC clojure :exports none (def TWO_PI (* 2 PI)) (defn regular-polygon [n] (vec (take (inc n)(iterate (partial rotate (/ TWO_PI n)) [1. 0])))) #+END_SRC #+NAME: src-regular-polygon-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [200 200] (map regular-polygon (range 3 7))] #+END_SRC #+NAME: src-polygon-in-polygon #+BEGIN_SRC clojure :exports none (defn polygon-in-polygon[k ps] (mapv (fn [[p0 p1]](add p0 (scale (- k) (add p0 (minus p1))))) (partition 2 1 (concat ps [(second ps)])))) #+END_SRC #+NAME: src-scale #+BEGIN_SRC clojure :exports none (defn scale [k p] (mapv (partial * k) p)) (def minus (partial scale -1.)) #+END_SRC #+NAME: src-scale-use #+BEGIN_SRC clojure :exports none (scale 2 [10 20]) #+END_SRC #+NAME: src-draw-fitted-polylines #+BEGIN_SRC clojure :exports none (def -INF (.-NEGATIVE_INFINITY js/Number)) (def INF (.-POSITIVE_INFINITY js/Number)) (defn bounding-box[pss] (->> pss (reduce into [])(reduce (fn[[[x-min y-min][x-max y-max]][x y]] [[(min x-min x) (min y-min y)][(max x-max x)(max y-max y)]]) [[INF INF][-INF -INF]]))) (defn make-fitting-transform[[w h] pss] (let[[[x-min y-min][x-max y-max]](bounding-box pss) s (min (/ w (- x-max x-min)) (/ h (- y-max y-min))) center (scale 0.5 (add [x-min y-min] [x-max y-max]))] (comp (partial add [(/ w 2) (/ h 2)]) (partial scale s) (partial add (minus center))))) (defn draw-fitted-polylines[wh pss] (draw-polylines wh ((make-polylines-transform (make-fitting-transform wh pss)) pss))) #+END_SRC #+NAME: src-draw-fitted-polylines-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [200 200] ((make-polylines-transform (comp (partial add [100 100]) (partial rotate (/ PI 4)))) [[[10 10][10 20][20 25]][[5 5][20 5][20 10]]])] #+END_SRC #+NAME: src-make-rotate-around #+BEGIN_SRC clojure :exports none (defn make-rotate-around [r a] (comp (partial add r)(partial rotate a) (partial add (minus r)))) #+END_SRC #+NAME: src-make-transform-around #+BEGIN_SRC clojure :exports none (defn make-transform-around [c f] (comp (partial add c) f (partial add (minus c)))) #+END_SRC #+NAME: src-make-rotate-around-use #+BEGIN_SRC clojure :exports none ((make-rotate-around [1 0] (/ PI 2)) [2 0]) #+END_SRC #+NAME: src-angle #+BEGIN_SRC clojure :exports none (def sqrt #(.sqrt js/Math %)) (def acos #(.acos js/Math %)) (def asin #(.asin js/Math %)) (def atan2 #(.atan2 js/Math %1 %2)) (defn cross-product[[x0 y0][x1 y1]] (+ (* x0 x1) (* y0 y1))) (defn dot-product [[x0 y0][x1 y1]] (+ (* x0 x1) (* y0 y1))) (defn magnitude[p] (sqrt (cross-product p p))) (defn angle[[xr yr][x y]] (- (atan2 y x) (atan2 yr xr))) #+END_SRC #+NAME: src-angle-use #+BEGIN_SRC clojure :exports none (angle [1 0] [0 1]) #+END_SRC #+NAME: src-fractal #+BEGIN_SRC clojure :exports none (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)) #+END_SRC TODO remove the fractal and update the includes #+NAME: src-fractal-sierpinski #+BEGIN_SRC clojure :exports none (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)]]]))) #+END_SRC #+NAME: src-fractal-koch-line-transform #+BEGIN_SRC clojure :exports none (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)))])))) #+END_SRC #+NAME: src-fractal-koch-line-transform-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [400 400] [(nth (iterate koch-transform [[-0.5 0][0.5 0]]) 2)]] #+END_SRC #+NAME: src-fractal-koch-line #+BEGIN_SRC clojure :exports none (def koch-line-params [[[[-0.5 0] [0.5 0]]] [(partial mapv koch-transform) []]]) #+END_SRC #+NAME: src-fractal-koch-line-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [400 400] (fractal koch-line-params 6)] #+END_SRC #+NAME: src-matching-segs-transform #+BEGIN_SRC clojure :exports none ;; not sure about order of args : I usually but ref as first because it usually is the most likely to be bound, but not so here (defn matching-segs-transform[[p-first-dst p-last-dst] [p-first-src p-last-src]] (let[v-dst (add p-last-dst (minus p-first-dst)) v-src (add p-last-src (minus p-first-src)) a (angle v-src v-dst) c-dst (add p-first-dst (scale 0.5 v-dst)) c-src (add p-first-src (scale 0.5 v-src))] (comp (partial add c-dst) (partial rotate a) (partial scale (/ (magnitude v-dst) (magnitude v-src))) (partial add (minus c-src))))) #+END_SRC #+NAME: src-matching-polyline-transform #+BEGIN_SRC clojure :exports none ;; not sure if I should only take rest for segs after the first, assuming that the polyline to transform will actually start at p-first-src and ends at p-last-src (defn matching-polyline-transform[ps-ref seg-src] (merged-juxt (map #(partial mapv (matching-segs-transform % seg-src)) (partition 2 1 ps-ref)))) #+END_SRC #+NAME: src-koch-snowflake #+BEGIN_SRC clojure :exports none (defn koch-snowflake[d]((matching-polyline-transform (regular-polygon 3) [[-0.5 0][0.5 0]] )(first (fractal koch-line-params d)))) #+END_SRC #+NAME: src-fractal-f #+BEGIN_SRC clojure :exports none (defn fractal-step-f [[step-f step-elts-f] [current-elts i]] (into (step-elts-f i) (step-f current-elts))) (defn params->params-f [[init-elts [step-f step-elts]]] [init-elts [step-f (constantly step-elts)]]) (defn fractal-f [[init-elts step-params-f] details] (reduce (fn[current-elts i] (fractal-step-f step-params-f [current-elts i])) init-elts (range (dec details) -1 -1))) #+END_SRC #+NAME: src-fractal-f-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [400 400](fractal-f (squares-params-f (/ PI 4) false) 4)] #+END_SRC #+NAME: src-spiral-arc #+BEGIN_SRC clojure :exports none (defn spiral-arc [[r-begin a-begin][r-end a-end]] (let[n 64 ;;should be computed http://www.intmath.com/blog/mathematics/length-of-an-archimedean-spiral-6595 between (fn[[begin end] n](fn [i] (+ begin (* i (/ (- end begin) n))))) between-r (between [r-begin r-end] n) between-a (between [a-begin a-end] n)] (map (fn[i] (rotate (between-a i) [(between-r i) 0])) (range (inc n))))) #+END_SRC #+NAME: src-spiral-flower #+BEGIN_SRC clojure :exports none (defn spiral-flower[[r-begin r-end] n] (let[alternate-rs (iterate (fn[[r0 r1]][r1 r0]) [r-begin r-end]) delta-a (* PI (- 1 (/ 1 n)))] (into [] (take (* 2 (int n))(map (fn[[r0 r1][a0 a1]] (spiral-arc [r0 a0] [r1 a1])) alternate-rs (partition 2 1 (iterate (partial + delta-a) 0))))))) #+END_SRC #+NAME: src-circling-transform #+BEGIN_SRC clojure :exports none (defn rotations [n] (map (comp (partial partial rotate) (partial * (/ (* 2 PI) n))) (range n))) (defn circling-transform [d s n] (merged-juxt (map (fn[r] (make-polylines-transform (comp r (partial rotate (/ PI n))(partial add d) (partial scale s)))) (rotations n)))) #+END_SRC #+NAME: src-circling-r-transform #+BEGIN_SRC clojure :exports none (defn circling-r-transform [d s n] (merged-juxt (map (fn[r] (make-polylines-transform (comp r (partial add (rotate (/ PI n) d)) (partial scale s)))) (rotations n)))) #+END_SRC #+NAME: src-hex-out-transform #+BEGIN_SRC clojure :exports none (def hex-out-transform (let[ratio (/ (sqrt 3) 6)](circling-r-transform [(* 4 ratio) 0] ratio 6))) #+END_SRC #+NAME: src-hexagonal-tiling-deltas #+BEGIN_SRC cljoure :exports none (defn v-hexagonal-tiling-deltas[radius] (let[[dx dy] (rotate (/ PI -3) [0 radius])] [(fn[c r](+ (* 2 c dx) (if (odd? r) dx 0))) (fn[c r](* 3 dy r))])) #+END_SRC #+NAME: src-make-2d-tiling #+BEGIN_SRC cljoure :exports none (defn make-2d-tiling-transforms[[f-dx f-dy][w h]] (for[ r (range h) c (range w)] (make-polylines-transform (partial add [(f-dx c r)(f-dy c r)])))) (def make-2d-tiling (comp merged-juxt make-2d-tiling-transforms)) #+END_SRC #+NAME: src-square-tiling-deltas #+BEGIN_SRC cljoure :exports none (defn square-tiling-deltas[radius] (let [side (/ radius (sqrt 2))] [(fn[c r](* side c)) (fn[c r](* side r))])) #+END_SRC # Finally figured out how to factor some org fragment #+NAME: text-test #+BEGIN_SRC sh :output :results raw :exports none cat< :PROPERTIES: :EXPORT_JEKYLL_LAYOUT: :filename: 2017-03-19-spirographs :END: #+call: inline-html-header() #+call: inline-klipse-header() #+call: inline-gif-js-src() #+NAME: src-spirograph #+BEGIN_SRC clojure :exports none (defn spirograph[rks] (fn[a] (into [[(- (reduce + (map first rks))) 0]] (first (reduce (fn[[res c][r k]] (let[next-c (- c r)] [(map (make-rotate-around [next-c 0] (* k a)) (conj res [c 0])) next-c])) ['() 0] (reverse rks)))))) #+END_SRC #+NAME: src-spirograph-use #+BEGIN_SRC clojure :exports none [:div [draw-fitted-polylines [200 200] [(mapv last (map (comp (spirograph [[50 1][45 -4]]) (partial * PI (/ 1 256))) (range 512)))]] [draw-fitted-polylines [200 200] [(mapv last (map (comp (spirograph [[50 1][45 -3.25]]) (partial * PI 4 (/ 1 256))) (range 512)))]] [draw-fitted-polylines [200 200] [(mapv last (map (comp (spirograph [[1 1][(/ 1. 2) -7]]) (partial * PI (/ 1 256))) (range 512)))]] [draw-fitted-polylines [200 200] [(mapv last (map (comp (spirograph [[1 1][(/ 1. 2) 4]]) (partial * PI (/ 1. 256))) (range 512)))]] [draw-fitted-polylines [200 200] [(mapv last (map (comp (spirograph [[1 1][(/ 1. 2) 4][ (/ 1. 6) 16]]) (partial * PI (/ 1. 256))) (range 513)))]] [draw-fitted-polylines [200 200] [(mapv last (map (comp (spirograph [[1 1][(/ 1. 2) 8][ (/ 1. 6) 16]]) (partial * PI (/ 1. 256))) (range 513)))]] [draw-fitted-polylines [200 200] [(mapv last (map (comp (spirograph [[1 1][(/ 1. 2) 2][(/ 1. 4) 6][ (/ 1. 4) 5]]) (partial * PI (/ 1. 256))) (range 513)))]] ] #+END_SRC #+NAME:src-spiro-1-spiro-2 #+BEGIN_SRC clojure :exports none (defn spiro-1[n] (let[c (/ (condp = n 10 15 8 4 9 10 20 25 15) 200) a (/ (+ 1 c) 2) b-size (+ 1 (/ (sqrt 2) 2)) c-size (/ (- 2 (sqrt 2)) 4) b-c-ratio (/ b-size c-size) b (/ (- 1 a) (+ 1. (/ 1 b-c-ratio)))] [[a 1][b (- n)][(/ b b-c-ratio) (* 4 n)]])) (def spiro-2 (let[m (/ 1 (+ 3 (/ 1 3))) s (/ m 6)][[(+ (* 2 m) s) 1][m -12][s (* 6 12)]])) #+END_SRC #+NAME:src-spiro-1-spiro-2-use #+BEGIN_SRC clojure :exports none [:div [draw-fitted-polylines [200 200] [(mapv last (map (comp (spirograph (spiro-1 10)) (partial * PI (/ 1 256))) (range 513)))]] [draw-fitted-polylines [200 200] [(mapv last (map (comp (spirograph spiro-2) (partial * PI (/ 1 256))) (range 512)))]]] #+END_SRC #+NAME: src-gui-spiro #+BEGIN_SRC clojure :exports none (def curves (mapv (fn[[rks n]] (mapv (comp (spirograph rks) (partial * PI (/ n 256))) (range 513))) [[[[50 1][45 -4]] 1] [[[50 1][45 -3.25]] 4] [[[1 1][(/ 1. 2) -7]] 1] [[[1 1][(/ 1. 2) 4]] 1] [[[1 1][(/ 1. 2) 4][ (/ 1. 6) 16]] 1] [[[1 1][(/ 1. 2) 8][ (/ 1. 6) 16]] 1] [[[1 1][(/ 1. 2) 2][(/ 1. 4) 6][ (/ 1. 4) 5]] 1] [(spiro-1 10) 1] [spiro-2 1]])) (def wh [120 120]) (def fitting-transforms (mapv (comp make-polylines-transform (partial make-fitting-transform wh) vector (partial mapv last)) curves)) (defn arm+curve[pps n] [(nth pps n) (mapv last (take n pps))]) (def spirograph-state (reagent.core/atom {:step 200})) #+END_SRC #+NAME: src-gui-spiro-use #+BEGIN_SRC clojure :exports none (dorun (map (fn[i](let[c (nth curves i)] (display-svgs! 200 (map (comp (partial draw-polylines (map (partial * 1.2) wh)) (nth fitting-transforms i) (partial arm+curve c) (partial * 4)) (range 128))))) (range (count curves)))) (defn gui-spiro1[] (let[step (:step @spirograph-state)] [:div [:div [:input {:type "range" :value (:step @spirograph-state) :min 0 :max (* 1 520) :style {:width "90%"} :on-change (fn[e] (swap! spirograph-state assoc :step (int (js/parseFloat (.-target.value e)))))}]] (into [:div] (map (fn[i](let[c (nth curves i)] [draw-polylines (map (partial * 1.2) wh) ((nth fitting-transforms i) (arm+curve c (:step @spirograph-state)))])) (range (count curves))))])) #+END_SRC #+call: inline-hidden-klipse-clojure-s('("init-reagent-examples" "src-gif-save-svg" "src-svg-polyline" "src-draw-polylines" "src-add" "src-make-polylines-transform" "src-rotate" "src-scale" "src-draw-fitted-polylines" "src-make-rotate-around" "src-spirograph" "src-spiro-1-spiro-2" "src-gui-spiro")) The nice thing about drawing is that one can easily draw nice patterns, using compositions of primitive patterns. One of the most elementary "pattern" would be the circle, with the most basic [[https://en.wikipedia.org/wiki/Circular_symmetry][Circular symmetry]]. While a plain circle is not that pretty, just composing a few of them with spirographs can result in pretty drawings : #+call: inline-klipse-reagent-s('("src-gui-spiro" "src-gui-spiro-use")) Of course, some parameters make for prettier drawings : #+call: inline-klipse-reagent-s('("src-spiro-1-spiro-2" "src-spiro-1-spiro-2-use")) So what is a spirograph ? We want to have a function \( \alpha \rightarrow [x y] \) and the function will be parametrized by a sequence of [radius angular-velocity]. It is easier to go backward, from the last radius to the first, each time *composing* rotations around the previous center. #+call: inline-klipse-reagent-s( '("src-spirograph" "src-spirograph-use")) How does one rotate a point around any center ? By *composing* translations and rotation around the origin. As we will *compose* the resulting function, we might as well write a /make-XXX/ that returns the rotating function curryfied / partially applied to the rotation center and the angle. Instead, we could define a function taking all three parameters (rotation center, angle, and point to be rotated) and partially apply it each time we want to compose it. #+call: inline-klipse-clojure-s( '("src-make-rotate-around" "src-make-rotate-around-use")) The rotation of a point around the origin is trivially defined. #+call: inline-klipse-clojure-s( '("src-rotate" "src-rotate-use")) As we want to be able to display drawing in canvas of a given size, we *compose* scaling and translating the polylines so that it fits the canvas. #+call: inline-klipse-reagent-s( '("src-draw-fitted-polylines" "src-draw-fitted-polylines-use")) Scaling from the origin is trivially defined. We might as well define a unary minus while we are at it. #+call: inline-klipse-clojure-s( '("src-scale" "src-scale-use")) Adding two vectors in the usual trivial way. #+call: inline-klipse-clojure-s('("src-add" "src-add-use")) We are interested in transforming drawings. Drawings are sequences (vectors) of polylines, and polylines are vectors of points (and points are vectors of coords [x y] ). So we can easily make a drawing-transforming function from a point-transforming function by *composing* sequence traversals and the given point-transforming function. We can even do it in a [[https://en.wikipedia.org/wiki/Tacit_programming][tacit]] way, which will be useful for other purposes (but for now, any "equivalent" definition would do). #+call: inline-klipse-reagent-s( '("src-make-polylines-transform" "src-make-polylines-transform-use")) Actually drawing (as in "displaying") the drawing is creating the svg fragment by concatenating the svg fragments for each polyline. TODO: check for empty drawing ! #+call: inline-klipse-reagent-s('("src-draw-polylines" "src-draw-polylines-use")) The svg fragment for a polyline is just concatenating a =Move= to the first point and =Line= to each of the remain points. TODO: check for empty polyline ! #+call: inline-klipse-clojure-s( '("src-svg-polyline" "src-svg-polyline-use")) #+call: inline-klipse-footer() * Hypotrochoid * DONE Fractals CLOSED: [2017-03-20 Mon 01:34] SCHEDULED: <2017-03-20 Mon> :PROPERTIES: :EXPORT_JEKYLL_LAYOUT: :filename: 2017-03-20-fractals :END: #+NAME: src-gui-fractals #+BEGIN_SRC clojure :exports none (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))]])) #+END_SRC #+NAME: src-gui-fractals-use #+BEGIN_SRC clojure :exports none (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))]])) #+END_SRC #+NAME: src-gui-fractals-with-steps #+BEGIN_SRC clojure :exports none (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})) #+END_SRC #+NAME: src-gui-fractals-with-steps-use #+BEGIN_SRC clojure :exports none (let [k 32 n 5] (display-svgs! 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)]])) #+END_SRC #+NAME: src-fractal-with-steps #+BEGIN_SRC clojure :exports none (defn sequence-steps [n step-factor] (let [p (* n step-factor)] (map #(-> (- p %) (min 1) (max 0)) (range n)))) (defn is-from [v] (get (meta v) :is-from :default)) (defn get-args [v] (:args (meta v))) (defmulti stepify (fn [s v] (is-from v))) (defmethod stepify :default [s v] v) (defmethod stepify partial [s p] (let [args (get-args p) arg0 (first args)] (condp = arg0 add (partial add (scale s (second args))) rotate (partial rotate (* (second args) s)) scale (partial scale (js/Math.pow (second args) s)) mapv (partial mapv (stepify s (second args))) :default (apply p (map (partial stepify s)))))) (defmethod stepify comp [s c] (let [args (get-args c)] (apply comp (map stepify (reverse (sequence-steps (count args) s)) args)))) (defmethod stepify merged-juxt [s c] (let [args (get-args c)] (merged-juxt (map stepify (sequence-steps (count args) s) args)))) (defmethod stepify :default [s v] v) (defn params-step [s [init-scene [step-fs step-scene]]] [init-scene [(stepify s step-fs) step-scene]]) (def EPSILON 0.01) (defn fractal-with-steps [params details] (let [[init-scene step-params] params int-d (int details) int-fractal (nth (iterate (partial fractal-step step-params) init-scene) int-d) fractional-d (- details int-d)] (if (<= fractional-d EPSILON) int-fractal (fractal-step (second (params-step fractional-d params)) int-fractal)))) #+END_SRC #+NAME: src-fractal-with-steps-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [400 400] (fractal-with-steps (sierpinski-params 3) 1.75)] #+END_SRC #+NAME: src-fractal-sierpinski-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [400 400] (fractal (sierpinski-params 3) 6)] #+END_SRC #+NAME: src-fractal-tree #+BEGIN_SRC clojure :exports none (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]]]])) #+END_SRC #+NAME: src-fractal-tree-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [400 400] (fractal (tree-params [(/ PI 6)(/ PI -3)]) 8)] #+END_SRC #+NAME: src-fractal-koch #+BEGIN_SRC clojure :exports none (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)))))) []]]) #+END_SRC #+NAME: src-fractal-koch-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [400 400] (fractal koch-params 4)] #+END_SRC #+NAME: src-fractal-hilbert-transform #+BEGIN_SRC clojure :exports none ;; 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)))) #+END_SRC #+NAME: src-fractal-hilbert-transform-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [400 400] [(nth (iterate hilbert-transform [[0 0]]) 5)]] #+END_SRC #+NAME: src-fractal-hilbert #+BEGIN_SRC clojure :exports none (def hilbert-params [[[[0 0]]] [(partial mapv hilbert-transform) []]]) #+END_SRC #+NAME: src-fractal-hilbert-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [400 400] (fractal hilbert-params 6)] #+END_SRC #+BEGIN_SRC clojure :exports none (let[params (sierpinski-params 3)] (save-svgs! "test-save-sierp4.gif" 200 [200 200] (map (comp (partial draw-fitted-polylines [200 200]) (partial fractal-with-steps params) (partial * 0.1) (range 10 50)))) #+END_SRC #+call: inline-html-header() #+call: inline-gif-js-src() #+call: inline-klipse-header() #+call: inline-hidden-klipse-clojure-s('("init-reagent-examples" "src-gif-save-svg" "src-dynamic-homoiconicity" "src-svg-polyline" "src-draw-polylines" "src-add" "src-make-polylines-transform" "src-rotate" "src-scale" "src-draw-fitted-polylines" "src-make-rotate-around" "src-regular-polygon" "src-fractal-sierpinski" "src-fractal-tree" "src-fractal-koch" "src-fractal-hilbert-transform" "src-fractal-hilbert" "src-fractal-koch-line-transform" "src-fractal-koch-line" "src-fractal-with-steps" "src-gui-fractals" )) # #+call: inline-klipse-clojure-s('("src-gif-save-svg" "src-gif-save-svg-use")) #+call: inline-klipse-reagent-s('("src-gui-fractals")) #+call: inline-klipse-reagent-s('("src-gui-fractals-with-steps" "src-gui-fractals-with-steps-use")) #+call: inline-klipse-reagent-s('("src-fractal-sierpinski" "src-fractal-sierpinski-use")) #+call: inline-klipse-reagent-s('("src-regular-polygon" "src-regular-polygon-use")) #+call: inline-klipse-reagent-s('("src-fractal-tree" "src-fractal-tree-use")) #+call: inline-klipse-reagent-s('("src-fractal-koch" "src-fractal-koch-use")) #+call: inline-klipse-reagent-s('("src-fractal-hilbert-transform" "src-fractal-hilbert-transform-use")) #+call: inline-klipse-reagent-s('("src-fractal-hilbert" "src-fractal-hilbert-use")) #+call: inline-klipse-reagent-s('("src-fractal-koch-line-transform" "src-fractal-koch-line-transform-use")) #+call: inline-klipse-reagent-s('("src-fractal-koch-line" "src-fractal-koch-line-use")) ** Future Works - Fractal in Fractal : step-elt as a function of step nb to adjust for required precision - hilbert in sierpinski 4 - golden ratio squares and curve - golden ratio with sierpinski squares #+call: text-test() #+call: text-test-elisp() #+call: inline-klipse-footer() * DONE Bezier Curves SCHEDULED: <2017-03-20 Mon> :PROPERTIES: :EXPORT_JEKYLL_LAYOUT: :filename: 2017-03-20-bezier-curves :END: :EXPORT_JEKYLL_LAYOUT: :filename: 2017-03-20-bezier-curves :END: #+NAME: src-weighted-mean #+BEGIN_SRC clojure :exports none (defn weighted-mean [t [p0 p1]] (add (scale (- 1 t) p0) (scale t p1))) #+END_SRC #+NAME: src-weighted-mean-use #+BEGIN_SRC clojure :exports none (weighted-mean 0.25 [[0 1] [1 2]]) #+END_SRC #+NAME: src-bezier #+BEGIN_SRC clojure :exports none (defn bezier-step [ps t] (condp = (count ps) 1 (first ps) 2 (weighted-mean t ps) 3 (let[[p0 p1 p2] ps] (add (scale (* (- 1 t) (- 1 t)) p0) (add (scale (* 2 t (- 1 t)) p1) (scale (* t t) p2)))) (bezier-step (map (partial weighted-mean t) (partition 2 1 ps)) t))) (defn bezier [n ps] (if (< (count ps) 2) ps (mapv (comp (partial bezier-step ps) (partial * (/ 1 n))) (range (inc n))))) #+END_SRC #+NAME: src-bezier-use #+BEGIN_SRC clojure :exports none (def ctrl-pts [[0 0][0 1][2 1]]) [draw-fitted-polylines [400 400] [ctrl-pts (bezier 16 ctrl-pts)]] #+END_SRC #+NAME: src-square-with-curve #+BEGIN_SRC clojure :exports none (defn square-curve[n p0-p2 angle] (let[inv-sqrt-2 (/ 1. (sqrt 2)) p01 (weighted-mean inv-sqrt-2 p0-p2) p21 (weighted-mean (- 1. inv-sqrt-2) p0-p2) [p0 p2] p0-p2 p1 (weighted-mean 0.5 [((make-rotate-around p0 (/ angle 2)) p01) ((make-rotate-around p2 (/ angle -2)) p21)])] (bezier n [p0 p1 p2]))) (defn square-with-curve [n angle] (let[square (regular-polygon 4)] [square (square-curve n [(first square)(nth square 2)] angle)])) #+END_SRC #+NAME: src-square-with-curve-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [400 400] (square-with-curve 10 (/ PI 4))] #+END_SRC #+NAME: src-squares-params-f #+BEGIN_SRC clojure :exports none (defn power [x n] (nth (iterate (partial * x) 1) n)) (defn squares-params-f[angle invertRatio] (let[golden-ratio (/ 2. (+ 1. (sqrt 5))) [factor ratio a] (if invertRatio [-1 (/ 1. golden-ratio) angle ] [1 golden-ratio (- angle)])] [[] [(make-polylines-transform (comp (make-rotate-around [factor 0] a) (partial add [(* factor (+ 1. ratio)) 0]) (partial scale ratio))) ;; should use (power ratio ?) (fn[n](square-with-curve (max 1 (if invertRatio (+ 10 n) (- 10 n))) (* factor a)))]])) #+END_SRC #+NAME: src-squares-params-f-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [400 400] (let[[init [step-f step-elts-f]] (squares-params-f (/ PI 4) false)] (step-f (step-elts-f 5)))] #+END_SRC #+NAME: src-gui-golden-squares #+BEGIN_SRC clojure :exports none (def golden-squares-state (reagent.core/atom {:angle (/ PI -2) })) (defn gui-golden-squares[] (let[angle (:angle @golden-squares-state)] [:div [:div [:input {:type "range" :value (:angle @golden-squares-state) :step 0.01 :min (/ PI -2) :max (/ PI 2) :style {:width "90%"} :on-change (fn[e] (swap! golden-squares-state assoc :angle (js/parseFloat (.-target.value e))))}]] [draw-fitted-polylines [400 400](fractal-f (squares-params-f angle false) 4)]])) #+END_SRC #+NAME: src-gui-golden-squares-2 #+BEGIN_SRC clojure :exports none (def golden-squares-state-2 (reagent.core/atom {:angle (/ PI -2) })) (defn gui-golden-squares-2[] (let[angle (:angle @golden-squares-state-2)] [:div [:div [:input {:type "range" :value (:angle @golden-squares-state-2) :step 0.01 :min (/ PI -2) :max (/ PI 2) :style {:width "90%"} :on-change (fn[e] (swap! golden-squares-state-2 assoc :angle (js/parseFloat (.-target.value e))))}]] [draw-fitted-polylines [512 512](let[f1 (fractal-f (squares-params-f angle false) 12)] ((make-polylines-transform (partial rotate (/ angle -2)))(reduce into [] [f1 ((make-polylines-transform (comp (make-rotate-around [-1 0] angle)(partial add [-2 0]) (fn[[x y]][(- x) y]))) f1)])))]])) #+END_SRC #+NAME: src-golden-squares-2-gif-use #+BEGIN_SRC clojure :exports none (let[n-steps 128 half-n-steps (/ n-steps 2) rs->a (fn[rs](+ (/ PI -2) (* (/ rs half-n-steps) PI))) s->a (fn[s](if (< s half-n-steps) (rs->a s) (rs->a (- n-steps s))))] (display-svgs! 200 (map (comp (partial draw-fitted-polylines [512 512]) (fn[angle] (let[f1 (fractal-f (squares-params-f angle false) 12)] ((make-polylines-transform (partial rotate (/ angle -2))) (reduce into [] [f1 ((make-polylines-transform (comp (make-rotate-around [-1 0] angle)(partial add [-2 0]) (fn[[x y]][(- x) y]))) f1)])))) s->a) (range n-steps)))) #+END_SRC #+NAME: src-centered-golden-squares #+BEGIN_SRC clojure :exports none (defn centered-golden-squares[[dx zoom angle] [details-inc details-dec]] ((make-polylines-transform (comp (partial add [(+ dx) 0]) (partial rotate (* angle -0.5)) (partial scale zoom))) (into (fractal-f (squares-params-f angle true) details-inc) (fractal-f (squares-params-f angle false) details-dec)))) (defn inclusive-range [n [[first last] times]] (if (== times 1) (mapv (comp (partial + first) (partial * (/ (- last first) n))) (range n)) (into (inclusive-range (quot n times) [[first last] 1]) (inclusive-range (- n (quot n times)) [[last first] (dec times)])))) (defn golden-squares-anim-params [n1 n2] (let[golden-ratio (/ 2. (+ 1. (sqrt 5))) with-break (fn[c](let[h (quot n1 2) half-1 (vec (take h c)) half-2 (drop h c)] (-> half-1 (into (repeat n2 (first half-2))) (into half-2)))) dx (with-break (inclusive-range n1 [[0 (/ (+ 1 golden-ratio) golden-ratio)] 1])) dx (into dx dx) zoom (with-break (inclusive-range n1 [[(/ (+ 1 (sqrt 5)) 2) 1] 1])) zoom (into zoom zoom) angles (into (with-break (inclusive-range n1 [[0 (/ PI 2)] 2])) (with-break (inclusive-range n1 [[0 (/ PI -2)] 2])))] (mapv vector dx zoom angles))) #+END_SRC #+NAME: src-centered-golden-squares-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [400 400](centered-golden-squares (nth (golden-squares-anim-params 100 10) 55) [4 4])] #+END_SRC #+NAME: src-golden-sierp-gif-use #+BEGIN_SRC clojure :exports none (defn sierp-sq-step[pps] (reduce into [] (for [x [-1 0 1] y [-1 0 1] :when (or (not (zero? x)) (not(zero? y)))] ((make-polylines-transform (comp (partial add (rotate (/ PI 4) (scale (sqrt 2) [x y]))) (partial scale (/ 1 3)))) pps)))) (def sierp-sq-params-f [[] [sierp-sq-step (constantly [(regular-polygon 4)])]]) (defn sierp-sq[n] (let[center (fn c [n](if (<= n 0) 0 (+ (/ 2 (power 3 (dec n))) (c (dec n))) )) u (fn[n](+ (center n) (/ 1 (power 3 n))))] ((make-polylines-transform (partial scale (/ 1 (u (dec n))))) (fractal-f sierp-sq-params-f n)))) (defn sierp-params-f[angle invertRatio] (let[golden-ratio (/ 2. (+ 1. (sqrt 5))) [factor ratio a] (if invertRatio [-1 (/ 1. golden-ratio) angle ] [1 golden-ratio (- angle)])] [[] [(make-polylines-transform (comp (make-rotate-around [factor 0] a) (partial add [(* factor (+ 1. ratio)) 0]) (partial scale ratio))) ;; should use (power ratio ?) (fn[n](sierp-sq (if invertRatio 3 (min 3 (max 1 (- 3 n))))))]])) (;; <- wait for other anim to be done before starting this (defn centered-golden-sierp[[dx zoom angle] [details-inc details-dec]] ((make-polylines-transform (comp (partial add [(+ dx) 0]) (partial rotate (* angle -0.5)) (partial scale zoom))) (into (fractal-f (sierp-params-f angle true) details-inc) (fractal-f (sierp-params-f angle false) details-dec)))) (display-svgs! 200 (map (fn[p](draw-polylines [1024 512] (fitting-transform (centered-golden-sierp p [5 8])))) anim-params)) #+END_SRC #+NAME: src-gui-golden-squares-anim #+BEGIN_SRC clojure :exports none (def golden-squares-anim-state (reagent.core/atom {:step 0 })) (def anim-params (golden-squares-anim-params 100 10)) (def data (into anim-params anim-params)) (def wh [1024 512]) (def details [5 8]) ;; comment fitting-tranform def to speed things up (def fitting-transform (make-polylines-transform (make-fitting-transform wh (reduce into [] (map (fn[p] (centered-golden-squares p [0 5])) anim-params))))) (defn gui-golden-squares[] (let[step (:step @golden-squares-anim-state) n-steps (count data)] [:div [:div [:input {:type "range" :value (:step @golden-squares-anim-state) :min 0 :max n-steps :style {:width "90%"} :on-change (fn[e] (swap! golden-squares-anim-state assoc :step (js/parseFloat (.-target.value e))))}]] [draw-polylines wh (fitting-transform (centered-golden-squares (nth data step) details))]])) #+END_SRC #+NAME: src-gui-golden-squares-anim-use #+BEGIN_SRC clojure :exports none (defn gui-golden-squares[] (let[step (:step @golden-squares-anim-state) n-steps (count data)] [:div [:div [:input {:type "range" :value (:step @golden-squares-anim-state) :min 0 :max n-steps :style {:width "90%"} :on-change (fn[e] (swap! golden-squares-anim-state assoc :step (js/parseFloat (.-target.value e))))}]] [draw-polylines wh (fitting-transform (centered-golden-squares (nth data step) details))]])) #+END_SRC #+NAME: src-golden-squares-anim-use #+BEGIN_SRC clojure :exports none (def wh [1024 512]) (def details [5 8]) (defn get-date[] (.getTime (js/Date.))) [draw-polylines wh (fitting-transform (centered-golden-squares (nth anim-params (mod (int (/ (get-date) 50)) (count anim-params))) details))] #+END_SRC #+NAME: src-golden-squares-gif-use #+BEGIN_SRC clojure :exports none (display-svgs! 200 (map (fn[p](draw-polylines [1024 512] (fitting-transform (centered-golden-squares p [5 8])))) anim-params)) #+END_SRC #+call: inline-html-header() #+call: inline-gif-js-src() #+call: inline-klipse-header() #+call: inline-hidden-klipse-clojure-s('("init-reagent-examples" "src-gif-save-svg" "src-svg-polyline" "src-draw-polylines" "src-add" "src-make-polylines-transform" "src-rotate" "src-scale" "src-draw-fitted-polylines" "src-make-rotate-around" "src-regular-polygon" "src-weighted-mean" "src-gif-save-svg" "src-bezier" "src-square-with-curve" "src-squares-params-f" "src-fractal-f" "src-gui-golden-squares" "src-centered-golden-squares" "src-gui-golden-squares-anim")) # #+call: inline-klipse-reagent-anim-s('("src-golden-squares-anim-use") 50) #+call: inline-klipse-clojure-s('("src-golden-squares-gif-use")) #+call: inline-klipse-clojure-s('("src-golden-squares-2-gif-use")) #+call: inline-klipse-reagent-s('("src-gui-golden-squares")) #+call: inline-klipse-reagent-s('("src-gui-golden-squares-2")) #+call: inline-klipse-reagent-s('("src-centered-golden-squares" "src-centered-golden-squares-use")) #+call: inline-klipse-reagent-s('("src-fractal-f" "src-fractal-f-use")) #+call: inline-klipse-reagent-s('("src-squares-params-f" "src-squares-params-f-use")) #+call: inline-klipse-reagent-s('("src-square-with-curve" "src-square-with-curve-use")) #+call: inline-klipse-reagent-s('("src-bezier" "src-bezier-use")) #+call: inline-klipse-clojure-s('("src-weighted-mean" "src-weighted-mean-use")) #+call: inline-klipse-clojure-s('("src-golden-sierp-gif-use")) #+call: inline-klipse-footer() test * DONE Polygons in Polygons 1 CLOSED: [2017-04-09 Sun 18:08] SCHEDULED: <2017-04-09 Sun> :PROPERTIES: :EXPORT_JEKYLL_LAYOUT: :filename: 2017-04-09-polygons-in-polygons-1 :END: #+call: inline-html-header() #+call: inline-gif-js-src() #+call: inline-klipse-header() #+NAME: src-polygon-in-polygon-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [200 200] (take 60 (iterate (partial polygon-in-polygon 0.1) (regular-polygon 6)))] #+END_SRC #+NAME: src-polygon-in-polygon-anim #+BEGIN_SRC clojure :exports none (display-svgs! 200 (map (comp (partial draw-fitted-polylines [200 200]) (fn[n](take n (iterate (partial polygon-in-polygon 0.1) (regular-polygon 6))))) (concat (range 1 60) (range 60 0 -1)))) (display-svgs! 200 (map (comp (partial draw-fitted-polylines [200 200]) (fn[n](take n (iterate (partial polygon-in-polygon (/ 6 n)) (regular-polygon 6))))) (concat (range 15 60) (range 60 15 -1)))) #+END_SRC #+call: inline-hidden-klipse-clojure-s('("init-reagent-examples" "src-gif-save-svg" "src-dynamic-homoiconicity" "src-svg-polyline" "src-draw-polylines" "src-add" "src-make-polylines-transform" "src-rotate" "src-scale" "src-draw-fitted-polylines" "src-make-rotate-around" "src-regular-polygon" "src-scaled-regular-polygon" "src-polyline-matching-at" "src-angle" "src-polyline-angling-at" "src-angling-polygons" "src-polygon-in-polygon")) #+call: inline-klipse-clojure("src-polygon-in-polygon-anim") #+call: inline-klipse-reagent-s('("src-polygon-in-polygon" "src-polygon-in-polygon-use")) #+call: inline-klipse-reagent-s('("src-regular-polygon" "src-regular-polygon-use")) #+call: inline-klipse-footer() * DONE Polygons in Polygons 2 CLOSED: [2017-04-08 Sat 16:39] :PROPERTIES: :EXPORT_JEKYLL_LAYOUT: :filename: 2017-04-08-polygons-in-polygons-2 :END: #+call: inline-html-header() #+call: inline-gif-js-src() #+call: inline-klipse-header() Scaled regular polygons so that their sides are the same length regardless of the nb of sides #+NAME: src-scaled-regular-polygon #+BEGIN_SRC clojure :exports none (defn scaled-regular-polygon [n] (mapv (partial scale (/ 1 (* 2 (sin (/ PI n))))) (regular-polygon n))) #+END_SRC #+NAME: src-scaled-regular-polygon-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [200 200] (map scaled-regular-polygon (range 3 7))] #+END_SRC Translated polyline so that point n matches the same point of the reference polyline #+NAME: src-polyline-matching-at #+BEGIN_SRC clojure :exports none (defn polyline-matching-at[ps-ref n ps] (mapv (partial add (add (nth ps-ref (mod n (count ps-ref)))(minus (nth ps (mod n (count ps)))))) ps)) #+END_SRC #+NAME: src-polyline-matching-at-use #+BEGIN_SRC clojure :exports none (def pss (map scaled-regular-polygon (range 3 7))) (def pssf (map (partial polyline-matching-at (last pss) 0) pss)) [draw-fitted-polylines [200 200] pssf] #+END_SRC Computing the angle between two vectors Computing the difference of two angles (taking care of the modulo) Transforming a polyline so that given (integral part) point matches and that the angle is proportional to the non integral part. #+NAME: src-polyline-angling-at #+BEGIN_SRC clojure :exports none (defn mod+ [a b] (let [r (mod a b)] (if (neg? r) (+ b r) r))) (defn diff-mod[a b m] (let [dab (mod+ (- a b) m) dba (mod+ (- b a) m)] (if (< dab dba) (- dab) dba))) (defn polyline-angling-at[rs f ps] (let[n (int (+ f 0.5)) a-f (* (+ (- f n) 0.5) 1) get-pts (fn[xys](map #(nth xys (mod (+ n %) (dec (count xys)))) [-1 0 1])) [r-1 r r+1] (get-pts rs) [p-1 p p+1] (get-pts ps) a+1 (- (angle (add r+1 (minus r)) (add p+1 (minus p)))) a-1 (- (angle (add r-1 (minus r)) (add p-1 (minus p)))) a (+ a-1 (* a-f (diff-mod a-1 a+1 TWO_PI)))] (mapv (comp (make-rotate-around r a) (partial add (add r (minus p)))) ps))) #+END_SRC #+NAME: src-angling-polygons #+BEGIN_SRC clojure :exports none (defn angling-polygons [sides-min sides-max a] (let[pss (map scaled-regular-polygon (range sides-min sides-max)) pssf (mapv (partial polyline-angling-at (last pss) a) (butlast pss))] (conj pssf (last pss)))) #+END_SRC #+NAME: src-angling-polygons-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [200 200] (angling-polygons 3 12 1.5)] #+END_SRC #+NAME: src-angling-polygons-anim #+BEGIN_SRC clojure :exports none (let[n-min 3 n-max 12 step 20] (display-svgs! 200 (map (comp (partial draw-fitted-polylines [200 200]) (partial angling-polygons n-min n-max) (partial * (/ 1 n-max))) (range (* n-max step))))) #+END_SRC Unfolding a polyline of two segments #+NAME: src-interpolate-angles #+BEGIN_SRC clojure :exports none (defn interpolate-angles [f a0 a1] (+ a0 (* f (diff-mod a0 a1 TWO_PI)))) (defn unfold-segments[f [p0 p1 p2]] (let[mp1 (minus p1) a (angle (add p0 mp1) (add p2 mp1)) da (interpolate-angles f (- PI a) 0)] [p0 p1 ((make-rotate-around p1 da) p2)])) #+END_SRC #+NAME: src-interpolate-angles-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [100 100] [(unfold-segments 0.5 [[10 10][10 20] [20 30]])]] #+END_SRC Unfolding a polyline Bad algorithmic complexity ! TODO : make it actually linear (switching to matrix representations of transformations ) #+NAME: src-unfold-polyline #+BEGIN_SRC clojure :exports none (defn make-unfolding-transform[f [p0 p1 p2]] (let[mp1 (minus p1)] (make-rotate-around p1 (interpolate-angles f (- PI (angle (add p0 mp1) (add p2 mp1))) 0)))) (defn unfold-polyline[f ps] (let[f (min (/ f (dec (count ps))) 1.) transforms (reductions comp identity (map (partial make-unfolding-transform f) (partition 3 1 ps)))] (into [(first ps)] (map #(%1 %2) transforms (rest ps))))) #+END_SRC #+NAME: src-unfold-polyline-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [200 200] (map (comp (partial unfold-polyline 5.) scaled-regular-polygon) (range 3 8))] #+END_SRC #+NAME: src-unfold-polyline-anim #+BEGIN_SRC clojure :exports none (defn regular-polygon-angle[n] (/ (* (- n 2) PI) (* 2 n))) (let[n-sides-min 3 n-sides-max 12 n-steps 10] (display-svgs! 50 (map (fn[step](let[pss (map (comp (partial unfold-polyline step) scaled-regular-polygon) (range n-sides-min (inc n-sides-max))) pssf (mapv (partial polyline-angling-at (last pss) (max 0 (dec (/ step n-steps)))) (butlast pss)) a (regular-polygon-angle n-sides-max)] (draw-fitted-polylines [400 400] ((make-polylines-transform (partial rotate a)) (conj pssf (last pss)))))) (concat (range (* 2 n-sides-max n-steps)) (range (* n-sides-max n-steps) 0 -1))))) #+END_SRC #+call: inline-html-header() #+call: inline-gif-js-src() #+call: inline-klipse-header() #+call: inline-hidden-klipse-clojure-s('("init-reagent-examples" "src-gif-save-svg" "src-dynamic-homoiconicity" "src-svg-polyline" "src-draw-polylines" "src-add" "src-make-polylines-transform" "src-rotate" "src-scale" "src-draw-fitted-polylines" "src-make-rotate-around" "src-regular-polygon" "src-scaled-regular-polygon" "src-polyline-matching-at" "src-angle" "src-polyline-angling-at" "src-angling-polygons")) #+call: inline-klipse-clojure("src-angling-polygons-anim") #+call: inline-klipse-reagent-s('("src-polyline-angling-at" "src-angling-polygons" "src-angling-polygons-use")) #+call: inline-klipse-clojure-s('("src-angle" "src-angle-use")) #+call: inline-klipse-reagent-s('("src-polyline-matching-at" "src-polyline-matching-at-use")) #+call: inline-klipse-reagent-s('("src-scaled-regular-polygon" "src-scaled-regular-polygon-use")) #+call: inline-klipse-reagent-s('("src-regular-polygon" "src-regular-polygon-use")) #+call: inline-klipse-clojure-s( '("src-rotate" "src-rotate-use")) #+call: inline-klipse-reagent-s( '("src-draw-fitted-polylines" "src-draw-fitted-polylines-use")) #+call: inline-klipse-clojure-s( '("src-scale" "src-scale-use")) #+call: inline-klipse-clojure-s('("src-add" "src-add-use")) #+call: inline-klipse-reagent-s( '("src-make-polylines-transform" "src-make-polylines-transform-use")) #+call: inline-klipse-reagent-s('("src-draw-polylines" "src-draw-polylines-use")) #+call: inline-klipse-clojure-s( '("src-svg-polyline" "src-svg-polyline-use")) #+call: inline-klipse-reagent-s('("src-interpolate-angles" "src-interpolate-angles-use")) #+call: inline-klipse-reagent-s('("src-unfold-polyline" "src-unfold-polyline-use")) #+call: inline-klipse-clojure( "src-unfold-polyline-anim") #+call: inline-klipse-footer() * DONE Spiral Flower CLOSED: [2017-04-09 Sun 19:23] SCHEDULED: <2017-04-09 Sun> :PROPERTIES: :EXPORT_JEKYLL_LAYOUT: :filename: 2017-04-09-spiral-flower :END: #+NAME: src-spiral-flower-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [200 200] (spiral-flower [10 50] 7)] #+END_SRC #+NAME: src-spiral-flower-anim #+BEGIN_SRC clojure :exports none (display-svgs! 200 (let[n-min 3 n-max 12 steps 10] (map (comp (partial draw-fitted-polylines [200 200]) (partial spiral-flower [10 50]) (partial * (/ 1 steps))) (concat (range (* n-min steps) (* n-max steps)) (range (* n-max steps)(* n-min steps) -1))))) #+END_SRC #+call: inline-html-header() #+call: inline-klipse-header() #+call: inline-gif-js-src() #+call: inline-hidden-klipse-clojure-s('("init-reagent-examples" "src-gif-save-svg" "src-dynamic-homoiconicity" "src-svg-polyline" "src-draw-polylines" "src-add" "src-make-polylines-transform" "src-rotate" "src-scale" "src-draw-fitted-polylines" "src-spiral-arc" "src-spiral-flower")) #+call: inline-klipse-clojure("src-spiral-flower-anim") #+call: inline-klipse-reagent-s('("src-spiral-flower" "src-spiral-flower-use")) #+call: inline-klipse-clojure("src-spiral-arc") The rotation of a point around the origin is trivially defined. #+call: inline-klipse-clojure-s( '("src-rotate" "src-rotate-use")) As we want to be able to display drawing in canvas of a given size, we *compose* scaling and translating the polylines so that it fits the canvas. #+call: inline-klipse-reagent-s( '("src-draw-fitted-polylines" "src-draw-fitted-polylines-use")) Scaling from the origin is trivially defined. We might as well define a unary minus while we are at it. #+call: inline-klipse-clojure-s( '("src-scale" "src-scale-use")) Adding two vectors in the usual trivial way. #+call: inline-klipse-clojure-s('("src-add" "src-add-use")) We are interested in transforming drawings. Drawings are sequences (vectors) of polylines, and polylines are vectors of points (and points are vectors of coords [x y] ). So we can easily make a drawing-transforming function from a point-transforming function by *composing* sequence traversals and the given point-transforming function. We can even do it in a [[https://en.wikipedia.org/wiki/Tacit_programming][tacit]] way, which will be useful for other purposes (but for now, any "equivalent" definition would do). #+call: inline-klipse-reagent-s( '("src-make-polylines-transform" "src-make-polylines-transform-use")) Actually drawing (as in "displaying") the drawing is creating the svg fragment by concatenating the svg fragments for each polyline. TODO: check for empty drawing ! #+call: inline-klipse-reagent-s('("src-draw-polylines" "src-draw-polylines-use")) The svg fragment for a polyline is just concatenating a =Move= to the first point and =Line= to each of the remain points. TODO: check for empty polyline ! #+call: inline-klipse-clojure-s( '("src-svg-polyline" "src-svg-polyline-use")) #+call: inline-klipse-footer() * DONE Fractals 2 CLOSED: [2017-04-09 Sun 23:10] SCHEDULED: <2017-04-09 Sun> :PROPERTIES: :EXPORT_JEKYLL_LAYOUT: :filename: 2017-04-09-fractals-2 :END: #+NAME: src-matching-segs-transform-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [400 400] [(mapv (matching-segs-transform (take 2 (drop 2 (regular-polygon 3))) [[-0.5 0][0.5 0]]) (first (fractal koch-line-params 2)))]] #+END_SRC #+NAME: src-matching-polyline-transform-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [400 400] [((matching-polyline-transform (regular-polygon 3) [[-0.5 0][0.5 0]] )(first (fractal koch-line-params 4)))]] #+END_SRC #+NAME: src-hex-in-transform #+BEGIN_SRC clojure :exports none (def hex-in-transform (let[ratio (/ (sqrt 3) 3)](circling-transform [ratio 0] (* 0.5 ratio) 6))) #+END_SRC #+NAME: src-hex-in-transform-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [400 400] (fractal [[(regular-polygon 6)][hex-in-transform [(regular-polygon 6)]]] 4)] #+END_SRC #+NAME: src-koch-snowflake-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [400 400] (let[k (koch-snowflake 3)](fractal [[k] [hex-out-transform [k]]] 3))] #+END_SRC #+NAME: src-koch-f-snowflake-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [512 512] (let[n-steps 4 k (fn[n][(koch-snowflake (inc (- n-steps n)))])] (fractal-f [[(koch-snowflake 2)] [hex-out-transform k]] n-steps))] #+END_SRC #+NAME: src-koch-f-snowflake-anim #+BEGIN_SRC clojure :exports none (let[ratio (/ (sqrt 3) 6) n 50 wh [512 512] n-steps 4 k (fn[n][(koch-snowflake (inc (- n-steps n)))]) koch-flake (fractal-f [[(koch-snowflake 2)] [hex-out-transform k]] n-steps) fitting-transform (comp (make-fitting-transform wh koch-flake) (partial scale 0.8))] (display-svgs! 100 (map (comp (partial draw-polylines wh) (fn[f](f koch-flake)) make-polylines-transform (partial comp fitting-transform) (fn[step](let[s (js/Math.pow (/ 1 ratio) (/ step n))] (comp (partial add [0 (/ (* 4 ratio step s) n)]) (partial scale s))))) (range n)))) #+END_SRC #+call: inline-html-header() #+call: inline-klipse-header() #+call: inline-gif-js-src() #+call: inline-hidden-klipse-clojure-s('("init-reagent-examples" "src-gif-save-svg" "src-dynamic-homoiconicity" "src-svg-polyline" "src-draw-polylines" "src-add" "src-make-polylines-transform" "src-rotate" "src-scale" "src-regular-polygon" "src-draw-fitted-polylines" "src-angle" "src-fractal-koch-line-transform" "src-fractal-koch-line" "src-fractal" "src-fractal-f" "src-matching-segs-transform" "src-matching-polyline-transform" "src-circling-transform" "src-hex-in-transform" "src-circling-r-transform" "src-hex-out-transform" "src-koch-snowflake")) #+call: inline-klipse-reagent-s('("src-matching-segs-transform" "src-matching-segs-transform-use")) #+call: inline-klipse-reagent-s('("src-circling-transform" "src-hex-in-transform" "src-hex-in-transform-use")) #+call: inline-klipse-reagent-s('("src-koch-snowflake" "src-koch-snowflake-use")) #+call: inline-klipse-reagent-s('("src-circling-r-transform" "src-hex-out-transform" "src-koch-snowflake" "src-koch-snowflake-use")) #+call: inline-klipse-reagent("src-koch-f-snowflake-use") #+call: inline-klipse-clojure("src-koch-f-snowflake-anim") #+call: inline-klipse-footer() * DONE Tiling 1 CLOSED: [2017-04-11 Tue 14:03] SCHEDULED: <2017-04-11 Tue> :PROPERTIES: :EXPORT_JEKYLL_LAYOUT: :filename: 2017-04-11-tiling-1 :END: #+NAME: src-tiling-use #+BEGIN_SRC cljoure :exports none [:div [draw-fitted-polylines [200 200] ((make-2d-tiling (square-tiling-deltas 1) [5 5]) [(mapv (partial rotate (/ PI 4))(regular-polygon 4))])] [draw-fitted-polylines [200 200] ((make-2d-tiling (v-hexagonal-tiling-deltas 1) [5 5]) [(mapv (partial rotate (/ PI 6))(regular-polygon 6))])] [draw-fitted-polylines [200 200] ((make-2d-tiling (v-hexagonal-tiling-deltas 50) [5 5]) (spiral-flower [10 50] 6))] ] #+END_SRC #+NAME: src-poly-in-poly-tiling #+BEGIN_SRC cljoure :exports none (defn poly-in-poly-tiling[f [w h] n-sides n-polys] (let[ tiling (if (= n-sides 4) (square-tiling-deltas 2)(v-hexagonal-tiling-deltas 1))] ((make-2d-tiling tiling [w h]) ((make-polylines-transform (partial rotate (/ PI n-sides))) (take n-polys (iterate (partial polygon-in-polygon f) (regular-polygon n-sides))) ) ))) #+END_SRC #+NAME: src-poly-in-poly-tiling-use #+BEGIN_SRC cljoure :exports none [:div [draw-fitted-polylines [200 200] (poly-in-poly-tiling 0.2 [5 5] 4 30)] [draw-fitted-polylines [200 200] (poly-in-poly-tiling 0.2 [5 5] 6 30)]] #+END_SRC #+NAME: src-changing-poly-in-poly-tiling #+BEGIN_SRC cljoure :exports none (defn changing-poly-in-poly-tiling[f [w h] n-sides ] (let[ tiling (if (= n-sides 4) (square-tiling-deltas 2)(v-hexagonal-tiling-deltas 1))] (reduce into [] (map (fn[f pps]((comp f (make-polylines-transform (partial rotate (/ PI n-sides)))) pps)) (make-2d-tiling-transforms tiling [w h]) (map (fn[n-polys](take (inc n-polys) (iterate (partial polygon-in-polygon f) (regular-polygon n-sides)))) (range (* w h))))))) #+END_SRC #+NAME: src-changing-poly-in-poly-tiling-use #+BEGIN_SRC cljoure :exports none [:div [draw-fitted-polylines [300 300](changing-poly-in-poly-tiling 0.2 [5 5] 4 30)] [draw-fitted-polylines [300 300] (changing-poly-in-poly-tiling 0.1 [7 7] 6 30)]] #+END_SRC #+NAME: src-changing-poly-in-poly-tiling-f #+BEGIN_SRC cljoure :exports none (defn changing-poly-in-poly-tiling-f[f [w h] n-sides ] (let[ tiling (if (= n-sides 4) (square-tiling-deltas 2)(v-hexagonal-tiling-deltas 1)) f-wh (f [w h])] (reduce into [] (map (fn[f pps]((comp f (make-polylines-transform (partial rotate (/ PI n-sides)))) pps)) (make-2d-tiling-transforms tiling [w h]) (map (fn[n-polys](take (f-wh [(mod n-polys w) (quot n-polys w)]) (iterate (partial polygon-in-polygon 0.1) (regular-polygon n-sides))) ) (range (* w h))))))) #+END_SRC #+NAME: src-spiraling-f #+BEGIN_SRC cljoure :exports none (defn radius-f[[w h]] (fn[[c r]] (let[c-c (- c (/ (dec w) 2)) c-r (- r (/ (dec h) 2))] (int (* (sqrt (+ (* c-c c-c) (* c-r c-r))) 10))))) (defn next-spiral[[c r]] (if (and (> c 0) (or (and (< r 0) (< (- r) c)) (and (>= r 0) (<= r c)))) [c (dec r)] (if (and (< r 0) (or (and (< c 0) (< r c)) (and (>= c 0) (<= c (- r))))) [(dec c) r] (if (and (<= c 0) (or (and (< r 0) (<= c r)) (and (>= r 0) (<= r (- c))))) [c (inc r)] [(inc c) r])))) (defn spiraling-f[[w h]] (let [rc->i (reduce conj {} (map vector (take (* 4 w h) (iterate next-spiral [0 0])) (range) ))] (fn[[c r]] (- (* 0.65 w h) (rc->i [(int (+ (- r (/ (dec h) 2)))) (int (- (- c (/ (dec w) 2))))]))))) #+END_SRC #+NAME: src-spiraling-f-use #+BEGIN_SRC cljoure :exports none [:div [draw-fitted-polylines [300 300](changing-poly-in-poly-tiling-f spiraling-f [6 6] 4 30)] [draw-fitted-polylines [300 300] (changing-poly-in-poly-tiling-f spiraling-f [6 7] 6 30)]] #+END_SRC #+NAME: src-sierpinski-4-tiling #+BEGIN_SRC cljoure :exports none [draw-fitted-polylines [400 400] ((make-2d-tiling (square-tiling-deltas 6) [5 5]) (fractal (sierpinski-params 4) 3))] #+END_SRC #+NAME: src-sierpinski-4-poly-in-poly-tiling #+BEGIN_SRC cljoure :exports none (defn filled-sierpinski-params[k n-in n-sides] (let[[init-elt [f step-elt]] (sierpinski-params n-sides)] [init-elt [f (take n-in (iterate (partial polygon-in-polygon k) (first step-elt)))]])) #+END_SRC #+NAME: src-sierpinski-4-poly-in-poly-tiling-use #+BEGIN_SRC cljoure :exports none [draw-fitted-polylines [400 400] ((make-2d-tiling (square-tiling-deltas 4) [5 5]) (fractal (filled-sierpinski-params 0.2 10 4) 3))] #+END_SRC #+NAME: src-koch-tiling #+BEGIN_SRC cljoure :exports none [draw-fitted-polylines [512 512] ((make-2d-tiling (v-hexagonal-tiling-deltas (+ (/ 1 3) (* 2 (/ (sqrt 3) 3))) ) [3 3]) (let[k (koch-snowflake 3)] (fractal [[k] [hex-out-transform [k]]] 2)))] #+END_SRC # Needs to be fixed #+NAME: src-koch-tiling-anim #+BEGIN_SRC clojure :exports none (let[ratio (/ (sqrt 3) 6) n 50 wh [512 512] n-steps 4 k (fn[n][(koch-snowflake (+ 0 (- n-steps n)))]) koch-tiling-delta (+ (/ 1 3) (* 2 (/ (sqrt 3) 3))) koch-tiling ((make-2d-tiling (v-hexagonal-tiling-deltas koch-tiling-delta) [3 3]) (let[k (koch-snowflake 2)] (fractal [[k] [hex-out-transform [k]]] 2))) fitting-transform (comp (make-fitting-transform wh koch-tiling) (partial scale 0.8))] (display-svgs! 100 (map (comp (partial draw-polylines wh) (fn[f](f koch-tiling)) make-polylines-transform (partial comp fitting-transform) (fn[step](let[s (js/Math.pow (/ 1 ratio) (/ step n))] (comp (partial add [0 (/ (* 4 ratio step s) n)]) (partial scale s))))) (range n)))) #+END_SRC #+call: inline-html-header() #+call: inline-klipse-header() #+call: inline-gif-js-src() #+call: inline-hidden-klipse-clojure-s('("init-reagent-examples" "src-gif-save-svg" "src-dynamic-homoiconicity" "src-svg-polyline" "src-draw-polylines" "src-add" "src-make-polylines-transform" "src-rotate" "src-scale" "src-regular-polygon" "src-draw-fitted-polylines" "src-polygon-in-polygon" "src-spiral-arc" "src-spiral-flower" "src-angle" "src-fractal" "src-fractal-sierpinski" "src-fractal-koch-line-transform" "src-fractal-koch-line" "src-koch-snowflake" "src-fractal" "src-fractal-f" "src-circling-transform" "src-circling-r-transform" "src-matching-segs-transform" "src-matching-polyline-transform" "src-hex-in-transform" "src-hex-out-transform" "src-hexagonal-tiling-deltas")) #+call: inline-klipse-reagent-s('("src-make-2d-tiling" "src-square-tiling-deltas" "src-hexagonal-tiling-deltas" "src-tiling-use")) #+call: inline-klipse-reagent-s('("src-poly-in-poly-tiling" "src-poly-in-poly-tiling-use")) #+call: inline-klipse-reagent-s('("src-changing-poly-in-poly-tiling" "src-changing-poly-in-poly-tiling-use")) #+call: inline-klipse-reagent-s('("src-changing-poly-in-poly-tiling-f" "src-spiraling-f" "src-spiraling-f-use")) #+call: inline-klipse-reagent("src-sierpinski-4-tiling") #+call: inline-klipse-reagent-s('("src-sierpinski-4-poly-in-poly-tiling" "src-sierpinski-4-poly-in-poly-tiling-use")) #+call: inline-klipse-reagent("src-koch-tiling") #+call: inline-klipse-clojure("src-koch-tiling-anim") #+call: inline-klipse-footer() * DONE Wrapings CLOSED: [2017-04-12 Wed 13:43] SCHEDULED: <2017-04-12 Wed> :PROPERTIES: :EXPORT_JEKYLL_LAYOUT: :filename: 2017-04-12-wrapings :END: #+NAME: src-make-break-polylines #+BEGIN_SRC clojure :exports none (defn break-segment [max-len [p0 p1]] (let[delta (add p1 (minus p0)) len (magnitude delta)] (let[n (js/Math.ceil(/ len max-len)) delta-i (scale (/ 1 n) delta)] (reduce (fn[res i] (let[next (if (< i n) (add (peek res) delta-i) p1)];; we want the last point to be exact (conj res next))) [p0] (range 1 (inc n)))))) (defn break-polyline [max-len ps] (reduce into[(first ps)] (map (comp rest (partial break-segment max-len)) (partition 2 1 ps)))) (defn make-break-polylines [max-len] (partial mapv (partial break-polyline max-len))) #+END_SRC #+NAME: src-r-a->x-y #+BEGIN_SRC clojure :exports none (defn r-a->x-y[[r a]] (rotate a [r 0])) #+END_SRC #+NAME: src-circle-wrap #+BEGIN_SRC clojure :exports none (defn circle-wrap[w [x y]] (let[a (/ (* x 2 PI) w)] (r-a->x-y [y a]))) #+END_SRC #+NAME: src-circle-wrap-use #+BEGIN_SRC clojure :exports none [:div [draw-fitted-polylines [200 200] ((make-polylines-transform (partial circle-wrap 200)) [[[0 100][200 100]]])] [draw-fitted-polylines [200 200] ((make-polylines-transform (partial circle-wrap 200)) [(mapv (fn[n][(* 10 n) 100])(range 20))])]] #+END_SRC #+NAME: src-make-break-polylines-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [200 200] ((comp (make-polylines-transform (partial circle-wrap 200)) (make-break-polylines 10)) [[[0 80][200 80][200 120][0 120][0 80]]])] #+END_SRC #+NAME: src-koch-tiling-wrap #+BEGIN_SRC cljoure :exports none [:div (draw-fitted-polylines [512 512] (let[ delta (* 2 (/ (sqrt 3) 3)) data ((make-2d-tiling (v-hexagonal-tiling-deltas (+ (/ 1 3) delta) ) [6 6]) (let[k (koch-snowflake 2)] (fractal [[k] [hex-out-transform [k]]] 2))) [p-min p-max] (bounding-box data) [w h] (add p-max (minus p-min))] ((make-polylines-transform (comp (partial circle-wrap (- w delta)) (partial add (add (minus p-min) [0 2])))) data)))] #+END_SRC #+NAME: src-sierp-tiling-wrap #+BEGIN_SRC cljoure :exports none [:div (draw-fitted-polylines [512 512] (let[n 4 delta (/ -1 (js/Math.pow 3 (max 0 (- n 2)))) data((make-2d-tiling (square-tiling-deltas 6) [6 6]) (fractal (sierpinski-params 4) n)) [p-min p-max] (bounding-box data) [w h] (add p-max (minus p-min))] ((comp (make-polylines-transform (comp (partial circle-wrap (- w delta)) (partial add (add (minus p-min) [0 1])))) (make-break-polylines .1)) data)))] #+END_SRC #+NAME: src-sierp-tiling-wrap-anim #+BEGIN_SRC cljoure :exports none (defn add-disc [[[cx cy] r] svg] (conj svg [:circle {:cx cx :cy cy :r r :fill "dimgrey"}])) (let[ W-H [512 512] n 4 delta (/ -1 (js/Math.pow 3 (max 0 (- n 2)))) data((make-2d-tiling (square-tiling-deltas 6) [7 7]) (fractal (sierpinski-params 4) n)) [p-min p-max] (bounding-box data) [w h] (add p-max (minus p-min)) transform (fn [d](comp (make-polylines-transform (comp (partial circle-wrap (- w delta)) (partial add (add (minus p-min) [0 d])))) (make-break-polylines .1))) final-data ((transform 1) data) fitting (make-fitting-transform W-H final-data) n-steps 40] (display-svgs! 100 (map (fn[n]((comp (partial add-disc [(scale 0.5 W-H) (+ 9 (* (inc n) (/ 0.5 4)))]) (partial draw-polylines W-H)(make-polylines-transform fitting) (transform (inc (/ (* 0.5 n) n-steps)))) data)) (range (* 8 n-steps))))) #+END_SRC #+NAME: src-x-dilation #+BEGIN_SRC clojure :exports none (defn x-dilation[[dx ky] [x y]] [x (* y (inc (* (dec ky) (/ x dx))))]) #+END_SRC #+NAME: src-x-dilation-use #+BEGIN_SRC clojure :exports none [:div [draw-fitted-polylines [200 200] ((make-polylines-transform (partial circle-wrap 200)) [[[0 100][200 100]]])] [draw-fitted-polylines [200 200] ((make-polylines-transform (partial circle-wrap 200)) [(mapv (fn[n][(* 10 n) 100])(range 20))])]] #+END_SRC # cannot work I'm afraid #+NAME: src-koch-tiling-dilation-wrap #+BEGIN_SRC cljoure :exports none [:div (draw-fitted-polylines [512 512] (let[ delta (* 2 (/ (sqrt 3) 3)) data ((make-2d-tiling (v-hexagonal-tiling-deltas (+ (/ 1 3) delta) ) [6 3]) (let[k (koch-snowflake 2)] (fractal [[k] [hex-out-transform [k]]] 2))) [p-min p-max] (bounding-box data) [w h] (add p-max (minus p-min))] (conj ((make-polylines-transform (comp ;(partial add (add (minus p-min) [0 0])) (partial x-dilation [w (/ 1 6)]) (partial add (add (minus p-min) [0 (/ h -2)])))) (conj data [[0 (/ h 2)][10 (/ h 2)]]) )[] )))] #+END_SRC #+BEGIN_SRC clojure :exports none (defn add-disc [[[cx cy] r] svg] (conj svg [:circle {:cx cx :cy cy :r r :fill "dimgrey"}])) (let[ W-H [512 512] n 4 delta (/ -1 (js/Math.pow 3 (max 0 (- n 2)))) data((make-2d-tiling (square-tiling-deltas 6) [7 7]) (fractal (sierpinski-params 4) n)) [p-min p-max] (bounding-box data) [w h] (add p-max (minus p-min)) transform (fn [d](comp (make-polylines-transform (comp (partial circle-wrap (- w delta)) (partial add (add (minus p-min) [0 d])))) (make-break-polylines .1))) final-data ((transform 1) data) fitting (make-fitting-transform W-H final-data) n-steps 20] (display-svgs! 100 (map (fn[n]((comp (partial add-disc [(scale 0.5 W-H) (+ 9 (* (inc n) (/ 0.5 2.5)))])(partial draw-polylines W-H)(make-polylines-transform fitting) (transform (inc (/ (* 0.5 n) n-steps)))) data)) (range (* 8 n-steps))))) #+END_SRC #+NAME: src-circle-wrap-use #+BEGIN_SRC clojure :exports none [:div [draw-fitted-polylines [200 200] ((make-polylines-transform (partial circle-wrap 200)) [[[0 100][200 100]]])] [draw-fitted-polylines [200 200] ((make-polylines-transform (partial circle-wrap 200)) [(mapv (fn[n][(* 10 n) 100])(range 20))])]] #+END_SRC #+call: inline-html-header() #+call: inline-klipse-header() #+call: inline-gif-js-src() #+call: inline-hidden-klipse-clojure-s('("init-reagent-examples" "src-gif-save-svg" "src-dynamic-homoiconicity" "src-svg-polyline" "src-draw-polylines" "src-add" "src-make-polylines-transform" "src-rotate" "src-scale" "src-regular-polygon" "src-draw-fitted-polylines" "src-polygon-in-polygon" "src-spiral-arc" "src-spiral-flower" "src-make-2d-tiling" "src-hexagonal-tiling-deltas" "src-square-tiling-deltas" "src-angle" "src-fractal" "src-fractal-sierpinski" "src-fractal-koch-line-transform" "src-fractal-koch-line" "src-koch-snowflake" "src-fractal" "src-fractal-f" "src-circling-transform" "src-circling-r-transform" "src-matching-segs-transform" "src-matching-polyline-transform" "src-hex-in-transform" "src-hex-out-transform" )) #+call: inline-klipse-reagent-s('("src-r-a->x-y" "src-circle-wrap" "src-circle-wrap-use")) #+call: inline-klipse-reagent-s('("src-make-break-polylines" "src-make-break-polylines-use")) #+call: inline-klipse-reagent("src-koch-tiling-wrap") #+call: inline-klipse-reagent("src-sierp-tiling-wrap") #+call: inline-klipse-clojure("src-sierp-tiling-wrap-anim") #+call: inline-klipse-footer() * DONE Fractal Font CLOSED: [2017-04-13 Thu 13:19] SCHEDULED: <2017-04-13 Thu> :PROPERTIES: :EXPORT_JEKYLL_LAYOUT: :filename: 2017-04-13-fractal-font :END: #+NAME: src-font #+BEGIN_SRC clojure :exports none (def font { \A [ [[-0.5 0.5][0 -0.5][0.5 0.5]] [[-0.5 0.5] [-0.25 0] [0.25 0]] ] \C [ [[0.5 0.5][-0.5 0.5][-0.5 -0.5][0.5 -0.5]] ] \E [ [[0.5 0.5][-0.5 0.5][-0.5 -0.5][0.5 -0.5]] [[0.5 0.5][-0.5 0.5][-0.5 0][0.25 0]] ] \É [ [[0.5 0.5][-0.5 0.5][-0.5 -0.5][0.5 -0.5]] [[0.5 0.5][-0.5 0.5][-0.5 0][0.25 0]] ] \F [[[-0.35 0.5][-0.35 0][0.35 0]][[-0.35 0.5][-0.35 -0.5][0.5 -0.5]]] \H [[[-0.35 -0.5][-0.35 0.5]] [[-0.35 -0.5][-0.35 0][0.35 0]] [[0.35 -0.5][0.35 0.5]]] \I [ [[0 0.5][0 -0.5]][[-0.5 0.5][0.5 0.5]] [[-0.5 -0.5][0.5 -0.5]] ] \L [ [[-0.25 -0.5][-0.25 0.5][0.35 0.5]] ] \N [[[-0.35 0.5][-0.35 -0.5][0.35 0.5][0.35 -0.5]]] \P [[[-0.35 0.5][-0.35 -0.5][0.15 -0.5][0.35 -0.25][-0.15 0]]] \R [[[-0.35 0.5][-0.35 -0.5][0.15 -0.5][0.35 -0.25][-0.15 0][0.35 0.5]]] \S [[[-0.5 0.5][0.5 0.4][0.35 0.1][-0.35 -0.1][-0.5 -0.4][0.5 -0.5]]] \T [ [[-0.5 -0.5][0 -0.5][0 0.5]] [[-0.5 -0.5][0.5 -0.5]] ] \Y [ [[-0.35 -0.5][0 -0.15][0 0.5]] [[-0.35 -0.5][0 -0.15][0.35 -0.5]] ] \space [] }) #+END_SRC #+NAME: src-directed-char #+BEGIN_SRC clojure :exports none (defn directed-char[font s a letter p] ((make-polylines-transform (comp (partial add p) (partial rotate a) (partial scale s))) (get font letter))) #+END_SRC #+NAME: src-directed-char-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [200 200] (directed-char font 0.1 (/ PI 4) \A [0 0])] #+END_SRC #+NAME: src-directed-chars #+BEGIN_SRC clojure :exports none (defn directed-chars[font s a cs p] (let[letter-s (* 0.8 s) v (rotate a [s 0])] (reduce into [] (map-indexed (fn [i letter](directed-char font letter-s a letter (add p (scale i v)))) cs)))) #+END_SRC #+NAME: src-directed-chars-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [200 200] (directed-chars font 0.1 (/ PI 4) "ALICE" [0 0])] #+END_SRC #+NAME: src-chars-on-polyline #+BEGIN_SRC clojure :exports none (defn chars-on-polyline[font s cs ps] (let[segs (reduce (fn[res [p0 p1]](let[delta (add p1 (minus p0)) len (magnitude delta) seg (if (empty? res) [p0 p1] [(add p1 (scale (/ (- len s) len) (minus delta))) p1])] (if (< len s) res (conj res seg))))[] (partition 2 1 ps))] (loop[res [] cs (cycle cs) segs segs] (if (empty? segs) res (let[[p0 p1] (first segs) delta (add p1 (minus p0)) a (angle [1 0] delta) n-chars (js/Math.ceil (/ (magnitude delta) s))] (recur (into res (directed-chars font s a (take n-chars cs) p0)) (drop n-chars cs) (rest segs))))))) #+END_SRC #+NAME: src-chars-on-polyline-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [200 200] (chars-on-polyline font 0.5 "ALICE " [[0 0][10 10][20 10]])] #+END_SRC #+NAME: src-chars-on-polylines #+BEGIN_SRC clojure :exports none (defn chars-on-polylines[font s cs pss] (reduce into [] (map (partial chars-on-polyline font s cs) pss))) #+END_SRC #+NAME: src-chars-on-polylines-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [200 200] (chars-on-polylines font 0.05 "ALICE " (get font \A))] #+END_SRC #+NAME: src-chars->polylines #+BEGIN_SRC clojure :exports none (defn chars->polylines[font cs] (directed-chars font 1 0 cs [0 0])) #+END_SRC #+NAME: src-chars->polylines-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [200 200] (chars->polylines font "ALICE ")] #+END_SRC #+NAME: src-fractal-chars #+BEGIN_SRC clojure :exports none (defn fractal-chars [font sf cs n] (second (nth (iterate (fn[[i pss]][(inc i) (chars-on-polylines font (js/Math.pow sf i) cs pss)]) [1 (chars->polylines font cs)]) n))) #+END_SRC #+NAME: src-fractal-chars-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [600 200] (fractal-chars font 0.07 "ALICE " 2)] #+END_SRC #+NAME: src-fractal-words-on-word #+BEGIN_SRC clojure :exports none ;; words is a seq of seqs of chars ;; note: "ALICE THIERRY" is one words ;; ["ALICE " "THIERRY ALICE "] are words (defn fractal-words-on-word [font sf words] (reduce (fn[res [i word]] (chars-on-polylines font (js/Math.pow sf (inc i)) word res )) (chars->polylines font (first words)) (map vector (range)(rest words)))) #+END_SRC #+NAME: src-fractal-words-on-word-use #+BEGIN_SRC clojure :exports none [draw-fitted-polylines [600 200] (fractal-words-on-word font 0.07 ["ALICE " "FRANCESCA ALICE ""ALICE FRANCESCA "])] #+END_SRC #+NAME: src-fractal-chars-word #+BEGIN_SRC clojure :exports none (defn fractal-chars-word[n w-h s font cs] (let[[p0 p1] (->> cs (chars->polylines font ) first (take 2)) delta (add p1 (minus p0)) a (angle delta [1 0]) data (fractal-chars font s cs 2) c(first (first (fractal-chars font s cs 1))) fitting (make-fitting-transform (scale 0.8 w-h) data)] (map (fn [i](let[step (/ i n)] (draw-polylines w-h ((make-polylines-transform (comp (partial add (scale 0.1 w-h)) fitting (partial add c) (partial rotate (* a step)) (partial scale (js/Math.pow (/ 1 s )step)) (partial add (minus c)) )) data)))) (range n)))) #+END_SRC #+NAME: src-fractal-chars-word-anim-francesca #+BEGIN_SRC clojure :exports none (display-svgs! 100 (fractal-chars-word 20 [512 512] 0.07 font "FRANCESCA ")) #+END_SRC #+NAME: src-fractal-words #+BEGIN_SRC clojure :exports none (defn max-for[f xs] (reduce (fn[res current](if (> (f res) (f current)) res current)) xs)) ;["ALICE " "THIERRY "] (defn fractal-words[n w-h s font words] (let[widest (max-for count words) ;; does not take leading / trailing spaces into account ! margin 0.1 fitting (make-fitting-transform (scale (- 1. (* 2 margin)) w-h) (chars->polylines font widest))] (reduce into [] (map (fn[i] (let[ word (nth (cycle words) i) filling-words (into [word] (map (fn[j](->> words cycle (drop (+ i j)) (take (count words)) (apply str))) [1 2])) [p0 p1] (->> word (chars->polylines font ) first (take 2)) delta (add p1 (minus p0)) a (angle delta [1 0]) data (fractal-words-on-word font s (take 3 filling-words)) c(first (first (fractal-words-on-word font s (take 2 filling-words))))] (map (fn [i](let[step (/ i n) transf (comp (partial rotate (* a step)) (partial scale (js/Math.pow (/ 1 s )step)) (partial add (minus c-begin))) c-img (transf c)] (draw-polylines w-h ((make-polylines-transform (comp (partial add (scale margin w-h)) fitting (partial add (minus c-img)) transf )) data)))) (range n)))) (range (count words)))))) #+END_SRC #+NAME: src-fractal-words-anim-alice-thierry #+BEGIN_SRC clojure :exports none (display-svgs! 400 (fractal-words 10 [512 512] 0.07 font ["ALICE " "THIERRY " "STÉPHANIE "])) #+END_SRC #+NAME: src-fractal-words-2 #+BEGIN_SRC clojure :exports none (defn max-for[f xs] (reduce (fn[res current](if (> (f res) (f current)) res current)) xs)) (defn fractal-words[n w-h s font words] (let[widest (max-for count (flatten words)) ;; does not take leading / trailing spaces into account ! margin 0.1 fitting (make-fitting-transform (scale (- 1. (* 2 margin)) w-h) (chars->polylines font widest))] (reduce into [] (map (fn[w] (let[[p0 p1] (->> w first (chars->polylines font ) first (take 2)) delta (add p1 (minus p0)) a (angle delta [1 0]) data (fractal-words-on-word font s (take 3 w)) c(first (first (fractal-words-on-word font s (take 2 w))))] (map (fn [i](let[step (/ i n) transf (comp (partial rotate (* a step)) (partial scale (js/Math.pow (/ 1 s )step)) (partial add (minus c-begin))) c-img (transf c)] (draw-polylines w-h ((make-polylines-transform (comp (partial add (scale margin w-h)) fitting (partial add (minus c-img)) transf )) data)))) (range n)))) words)))) #+END_SRC #+NAME: src-fractal-words-anim-alice-thierry #+BEGIN_SRC clojure :exports none (display-svgs! 400 (fractal-words 10 [512 512] 0.07 font [["ALICE " "STÉPHANIE THIERRY ALICE " "ALICE STEPHANIE "]["STÉPHANIE " "ALICE STEPHANIE " "THIERRY ALICE "]["ALICE " "THIERRY STÉPHANIE ALICE " "ALICE THIERRY "] ["THIERRY " "ALICE THIERRY" "SETPHANIE THIERRY ALICE "]] )) #+END_SRC #+call: inline-html-header() #+call: inline-klipse-header() #+call: inline-gif-js-src() #+call: inline-hidden-klipse-clojure-s('("init-reagent-examples" "src-gif-save-svg" "src-dynamic-homoiconicity" "src-svg-polyline" "src-draw-polylines" "src-add" "src-make-polylines-transform" "src-rotate" "src-scale" "src-make-rotate-around" "src-regular-polygon" "src-draw-fitted-polylines" "src-polygon-in-polygon" "src-spiral-arc" "src-spiral-flower" "src-make-2d-tiling" "src-hexagonal-tiling-deltas" "src-square-tiling-deltas" "src-angle" "src-fractal" "src-fractal-sierpinski" "src-fractal-koch-line-transform" "src-fractal-koch-line" "src-koch-snowflake" "src-fractal" "src-fractal-f" "src-circling-transform" "src-circling-r-transform" "src-matching-segs-transform" "src-matching-polyline-transform" "src-hex-in-transform" "src-hex-out-transform" )) #+call: inline-klipse-reagent-s('("src-font" "src-directed-char" "src-directed-char-use")) #+call: inline-klipse-reagent-s('("src-directed-chars" "src-directed-chars-use")) #+call: inline-klipse-reagent-s('("src-chars-on-polyline" "src-chars-on-polyline-use")) #+call: inline-klipse-reagent-s('("src-chars-on-polylines" "src-chars-on-polylines-use")) #+call: inline-klipse-reagent-s('("src-chars->polylines" "src-chars->polylines-use")) #+call: inline-klipse-reagent-s('("src-fractal-chars" "src-fractal-chars-use")) #+call: inline-klipse-reagent-s('("src-fractal-words-on-word" "src-fractal-words-on-word-use")) #+call: inline-klipse-clojure-s('("src-fractal-chars-word" "src-fractal-chars-word-anim-francesca")) #+call: inline-klipse-clojure-s('("src-fractal-words" "src-fractal-words-anim-alice-thierry")) #+call: inline-klipse-footer() * polylines interpolations * Snowflakes by folding and cutting * tiles * Drosde effect combo with fractals and tiles for instance for sierpinski fractals : sierp-4 tiles, esp. horizontals stretch along the horizontal axis so that it ends(e.g. rightmost) at ×3 the size of the beginning (e.g. leftmost). Wrap around a circle (x \rightarrow theta, y \rightmost r) * patterns * celtic patterns * bounces * optical illusions https://pbs.twimg.com/media/C9e_FBSXUAAu0j5.jpg * physics * solar system Euler -> Verlet * Fractal texts ISEP ISEPISEP S E P I S E ISEPISEP ISEPISEP S E P ISEPISEP S E P ISEPISEP ISEPISEP S E P ISEPISEPI S E ISEPISEP ISEPISEPI S S E E PISEPISEP I S E P https://github.com/Enderer/sixteensegment/blob/master/src/SixteenSegment.js * Mazes Possible to have a given (fractal) path given beforehand ? TODO implement connecting algo * Data viz http://blog.klipse.tech/data/2017/03/17/data-driven-documents-google-charts.html * Escher cf. Fish #+NAME: escher #+BEGIN_SRC python -n :var detail=1 :exports code import turtle as t def add(x0y0, x1y1): """ Additionne deux vecteurs (utilisé pour translater un point d'un vecteur) """ return (x0y0[0] + x1y1[0], x0y0[1] + x1y1[1]) def update_bounds(min_max, v): """ retourne le tuple de bornes min, max éventuellement mis à jour pour prendre en compte la valeur v """ if v < min_max[0] : min_max= (v, min_max[1]) if v > min_max[1] : min_max= (min_max[0], v) return min_max def bounding_box(lines): """ retourne le tuple de deux points qui délimitent le rectangle englobant les points de l'ensemble de lignes passées en argument """ inf=float('inf') x_bounds= y_bounds=(inf, -inf) for line in lines: for (x, y) in line: x_bounds= update_bounds(x_bounds, x) y_bounds= update_bounds(y_bounds, y) return ((x_bounds[0], y_bounds[0]),(x_bounds[1], y_bounds[1])) def translate(lines, xy): """ translate toutes les coordonnées d'un ensemble de lignes """ res=[] for line in lines: current_line=[] for point in line: current_line.append(add(point, xy)) res.append(tuple(current_line)) return tuple(res) def rot(lines): """ rotation d'un ensemble de lignes, sens horaire """ res= [] for line in lines: current_line= [] for (x, y) in line: current_line.append((y, -x)) res.append(tuple(current_line)) return tuple(res) def rot_counter(lines): """ rotation d'un ensemble de lignes, sens anti-horaire """ res= [] for line in lines: current_line= [] for (x, y) in line: current_line.append((-y, x)) res.append(tuple(current_line)) return tuple(res) def above(fig1, fig2): """ retourne une figure (=ensemble de lignes) qui est composée de la figure 2 au dessus de la figure 1 """ ((x_min1, y_min1),(x_max1, y_max1))= bounding_box(fig1) ((x_min2, y_min2),(x_max2, y_max2))= bounding_box(fig2) return fig1 + translate(fig2, (x_min1-x_min2, y_max1-y_min2)) def beside(fig1, fig2): """ retourne une figure (=ensemble de lignes) qui est composée de la figure 2 à droite de la figure 1 """ ((x_min1, y_min1),(x_max1, y_max1))= bounding_box(fig1) ((x_min2, y_min2),(x_max2, y_max2))= bounding_box(fig2) return fig1 + translate(fig2, (x_max1-x_min2, y_min1-y_min2)) def quartet(fig0, fig1, fig2, fig3): """ retourne une figure (=ensemble de lignes) qui est composée de : fig0 fig1 fig2 fig3 """ return above(beside(fig2, fig3), beside(fig0, fig1)) def quartet_fun(fig0, f): """ retourne une figure composée de applications successives de la fonction f (par exemple une rotation) appliquée 3 0 2 1 """ fig1= f(fig0) fig2= f(fig1) fig3= f(fig2) return quartet(fig3, fig0, fig2, fig1) def smaller(lines): """ retourne une figure (ensemble de lignes) dont la taille est divisée par 2 (homothétie centrée sur l'origine du repère, de rapport 1/2). """ res=[] for line in lines: current_line=[] for (x, y) in line: current_line.append((x/2, y/2)) res.append(tuple(current_line)) return tuple(res) def side(fig, n): """ retourne une figure récursive de niveau n selon un côté (le haut) """ if n == 0: return fig fig= smaller(fig) return quartet(side(fig, n-1), side(fig, n-1), rot_counter(fig), fig) def corner(fig_u, fig_t, n): """ retourne une figure récursive de niveau n selon un coin (haut gauche) fig_u est en bas à droite, fig_t sert pour le côté (haut) """ if n == 0: return fig_u fig_u= smaller(fig_u) fig_t= smaller(fig_t) s= side(fig_t, n-1) return quartet(corner(fig_u, fig_t, n-1), s, rot_counter(s), fig_u) def draw(lines): """ affiche une figure (ensemble de lignes), en redimensionnant l'affichage en conséquence. """ bb= bounding_box(lines) t.setworldcoordinates(bb[0][0], bb[0][1], bb[1][0], bb[1][1]) for line in lines: t.penup() for (x,y) in line: t.goto(x, y) t.pendown() # from http://www.frank-buss.de/lisp/functional.html fish_p=(((4, 4), (6,0)), ((0, 3),(3, 4)), ((3, 4),(0, 8)) ,((0, 8), (0, 3)), ((4, 5),(7, 6)), ((7, 6), (4, 10)) ,((4, 10), (4, 5)), ((11, 0), (10, 4)), ((10, 4),(8, 8)) ,((8, 8), (4, 13)), ((4, 13), (0, 16)), ((11, 0),(14, 2)) ,((14, 2), (16, 2)), ((10, 4), (13, 5)), ((13, 5),(16, 4)) ,((9, 6), (12, 7)), ((12, 7), (16, 6)), ((8, 8),(12, 9)) ,((12, 9), (16, 8)), ((8, 12), (16, 10)), ((0, 16),(6, 15)) ,((6, 15),(8, 16)), ((8, 16),(12, 12)), ((12, 12),(16, 12)) ,((10, 16),(12, 14)), ((12, 14),(16, 13)), ((12, 16), (13, 15)) ,((13, 15), (16, 14)), ((14, 16),(16, 15))) fish_q= (((2, 0), (4, 5)), ((4, 5),(4, 7)), ((4, 0),(6, 5)) , ((6, 5), (6, 7)), ((6, 0),(8, 5)), ((8, 5),(8, 8)) , ((8, 0), (10, 6)), ((10, 6), (10, 9)), ((10, 0), (14, 11)) , ((12, 0), (13, 4)), ((13, 4), (16, 8)), ((16, 8), (15, 10)) , ((15, 10), (16, 16)), ((16, 16), (12, 10)), ((12, 10),(6, 7)) , ((6, 7), (4, 7)), ((4, 7), (0, 8)), ((13, 0), (16, 6)) , ((14, 0), (16, 4)), ((15, 0), (16, 2)), ((0, 10), (7, 11)) , ((9, 12), (10, 10)), ((10, 10), (12, 12)), ((12, 12), (9, 12)) , ((8, 15), (9, 13)), ((9, 13), (11, 15)), ((11, 15), (8, 15)) , ((0, 12), (3, 13)), ((3, 13), (7, 15)), ((7, 15), (8, 16)) , ((2, 16), (3, 13)), ((4, 16), (5, 14)), ((6, 16), (7, 15))) fish_r= (((0, 12), (1, 14)), ((0, 8), (2, 12)), ((0, 4), (5, 10)) , ((0, 0), (8, 8)), ((1, 1), (4, 0)), ((2, 2), (8, 0)) , ((3, 3), (8, 2)), ((8, 2), (12, 0)), ((5, 5), (12, 3)) , ((12, 3), (16, 0)), ((0, 16), (2, 12)), ((2, 12), (8, 8)) , ((8, 8), (14, 6)), ((14, 6), (16, 4)), ((6, 16), (11, 10)) , ((11, 10), (16, 6)), ((11, 16), (12, 12)), ((12, 12), (16, 8)) , ((12, 12), (16, 16)), ((13, 13), (16, 10)), ((14, 14), (16, 12)) , ((15, 15), (16, 14))) fish_s= (((0, 0), (4, 2)), ((4, 2), (8, 2)), ((8, 2), (16, 0)) , ((0, 4), (2, 1)), ((0, 6), (7, 4)), ((0, 8), (8, 6)) , ((0, 10), (7, 8)), ((0, 12), (7, 10)), ((0, 14), (7, 13)) , ((8, 16), (7, 13)), ((7, 13), (7, 8)), ((7, 8), (8, 6)) , ((8, 6), (10, 4)), ((10, 4), (16, 0)), ((10, 16), (11, 10)) , ((10, 6), (12, 4)), ((12, 4), (12, 7)), ((12, 7), (10, 6)) , ((13, 7), (15, 5)), ((15, 5), (15, 8)), ((15, 8), (13, 7)) , ((12, 16), (13, 13)), ((13, 13), (15, 9)), ((15, 9), (16, 8)) , ((13, 13), (16, 14)), ((14, 11), (16, 12)), ((15, 9), (16, 10))) fish_t= quartet(fish_p, fish_q, fish_r, fish_s) fish_u= quartet_fun(fish_q, rot) t.delay(0) t.speed(0) t.hideturtle() #t.tracer(0, 1) draw(quartet_fun(rot(corner(fish_u, fish_t, detail)), rot)) t.update() ts=t.getscreen() ts.getcanvas().postscript(file="fish_%d.eps" % detail) #+END_SRC #+CALL: escher(detail=0) :exports none #+CALL: escher(detail=1) :exports none #+CALL: escher(detail=2) :exports none #+CALL: escher(detail=3) :exports none #+CALL: escher(detail=4) :exports none #+BEGIN_SRC shell :exports none for detail in $(seq 0 4); do epstopdf fish_${detail}.eps; pdf2svg fish_${detail}.pdf fish_${detail}.svg; done #+END_SRC * Gears ?♂♀ #+BEGIN_EXPORT html #+END_EXPORT * Exports https://cdn.rawgit.com/jnordberg/gif.js/master/dist/gif.js https://cdn.rawgit.com/jnordberg/gif.js/master/dist/gif.worker.js Clojurescript gif.js : https://github.com/jackschaedler/goya ** svg https://bl.ocks.org/veltman/1071413ad6b5b542a1a3 ** canvas http://bl.ocks.org/veltman/03edaa335f93b5a9ee57 (def canvas (js/document.getElementById "canvas-1")) (defn save-canvas [canvas] (let[gif (js/GIF. #js {:workers 4 :quality 1 :width (.-width canvas) :height (.-height canvas) ;; CORS :( ;;:workerScript "https://cdn.rawgit.com/jnordberg/gif.js/master/dist/gif.worker.js" :workerScript worker }) context (.getContext canvas "2d") update-download-link!(fn[blob] (let[download-link (. js/document (getElementById "image-download-link"))] (set! (.-href download-link) (.createObjectURL js/URL blob)) (.click download-link))) ] (do (.addFrame gif context #js {:copy true :delay 200}) (.on gif "finished" update-download-link!) (.render gif)))) (def canvas (js/document.createElement "canvas")) (.appendChild (js/document.getElementById "klipse-container-1") canvas) (def img (js/Image.)) (def context (.getContext canvas "2d")) (set! (.-onload img) (fn[] (do (print "on load!") (.drawImage context img 0 0) (save-canvas canvas)))) (def test-svg "") (defn str->url [s t] (let[blob (js/Blob. #js [s] #js {:type t})] (.createObjectURL js/URL blob) )) (def tst-svg-url (str->url test-svg "image/svg+xml")) ;;(save-canvas (js/document.getElementById "canvas-1")) ;;(set! (.-src img) tst-svg-url) (defn save-svg[svg] (let [canvas (js/document.createElement "canvas") img (js/Image.) context (.getContext canvas "2d") svg-url (str->url svg "image/svg+xml")] (do (set! (.-onload img) (fn[] (do (print "on load!") (.drawImage context img 0 0) (save-canvas canvas)))) (set! (.-src img) svg-url)))) (save-svg test-svg)