quil / quil-site

Source code of quil.info
http://quil.info
Eclipse Public License 1.0
7 stars 13 forks source link

Lissajous Table #22

Closed ampersanda closed 5 years ago

ampersanda commented 5 years ago

http://quil.info/sketches/local/be3b9156d926ba1b15fdc7bfd39d2fad257cf2d0f02b79c24206300662efe8d1

(ns lissajous.core
  (:require [quil.core :as q]
            [quil.middleware :as m]))

(def circle-width 62.5)
(def rules (atom {:columns 0
                  :rows    0
                  :curves  nil}))

(defn setup []
  (q/frame-rate 60)
  (q/color-mode :hsb)

  (let [cols (dec (/ (q/width) circle-width))
        rows (dec (/ (q/height) circle-width))]

    (swap! rules assoc :columns cols)
    (swap! rules assoc :rows rows)
    (swap! rules assoc :curves (vec (repeat cols (vec (repeat rows {:x nil :y nil :points []}))))))

  {:angle 0})

(defn update-state [{:keys [angle]}]
  {:angle (+ angle 0.04)})

(defn create-circles-and-guides [angle mode]
  (let [hcw (/ circle-width 2)]
    (doseq [i (range (mode @rules))]
      (let [def-cx (+ (* i circle-width) hcw circle-width)
            cx (cond (= :columns mode) def-cx
                     (= :rows mode) hcw)

            cy (cond (= :columns mode) hcw
                     (= :rows mode) def-cx)

            diameter (- circle-width 10)
            r (/ diameter 2)

            angle-speed (* angle (inc i))
            angle-set-to-zero (- angle-speed q/HALF-PI)

            x (* r (q/cos angle-set-to-zero))
            y (* r (q/sin angle-set-to-zero))

            point-x (+ cx x)
            point-y (+ cy y)

            create-circle (fn []
                            (q/stroke-weight 1)
                            (q/ellipse cx cy diameter diameter))

            create-point (fn []
                           (q/stroke-weight 8)
                           (q/point point-x point-y))

            create-line (fn []
                          (q/stroke-weight 1)
                          (cond (= :columns mode) (q/line point-x 0 point-x (q/height))
                                (= :rows mode) (q/line 0 point-y (q/width) point-y)))]

        (create-circle)
        (create-point)
        (create-line)

        (cond
          (= :columns mode) (doseq [j (range (:rows @rules))] (swap! rules assoc-in [:curves j i :x] point-x))
          (= :rows mode) (doseq [j (range (:columns @rules))] (swap! rules assoc-in [:curves i j :y] point-y)))))))

(defn draw-state [{:keys [angle]}]
  (q/background 0)

  (q/no-fill)
  (q/stroke 255)

  (create-circles-and-guides angle :columns)
  (create-circles-and-guides angle :rows)

  (doseq [r (range (:rows @rules))
          c (range (:columns @rules))]
    (let [draw-lissajous (fn [points]
                           (q/stroke 255)
                           (q/stroke-weight 1)
                           (q/no-fill)
                           (q/begin-shape)

                           (doseq [x (range (count points))]
                             (let [p (nth points x)
                                   posx (:x p)
                                   posy (:y p)]
                               (q/vertex posx posy)))

                           (q/end-shape))

          current (nth (nth (:curves @rules) r) c)]
      (swap! rules update-in [:curves r c :points] conj {:x (:x current) :y (:y current)})
      (draw-lissajous (:points current)))))

(q/defsketch lissajous
             :title "Ampersanda - Lissajous"
             :size [500 500]
             :setup setup
             :update update-state
             :draw draw-state
             :features [:keep-on-top]
             :middleware [m/fun-mode])
nbeloglazov commented 5 years ago

Thanks, that looks cool! But I'm concerned a little by performance: when I run this sketch is starts very fast but as time goes on it slows down. I suspect there is some kind of memory leak. Looking at the code you do a lot of changes to rules atom inside draw. Could you explain what those updates do? I feel there is an opportunity to optimize them.

nbeloglazov commented 5 years ago

Looked at the code closer. Seems like you are adding a new point to all curves on each invocation of draw so it's keep growing indefinitely, right? You don't really need to store all the points because they start repeating after some time. Maybe you can calculate that for current [i, j] circle you "completed" the loop and no longer need to add new points?

ampersanda commented 5 years ago

Oh okay, I'll revised them. Thank you for the suggestion 🙃. I think I should just subvec the first point which I added to the atom before redraw it after the angle is more than TWO-PI

ampersanda commented 5 years ago

http://quil.info/sketches/show/112bd73f0204acbe7be2c6437a2dfb8e27fe17fe0ed86b248afd376864dc9c2e

nbeloglazov commented 5 years ago

Thanks for the quick fix! The updated version feels much faster.

One last thing. The sketch will be shown in size 200x200 so only 2 circles will be displayed and the first 2 circles (2x2) are the most basic. What if instead of using the first 2 circles we randomly selected angle speeds for them? That way each time you refresh small 200x200 sketch you'll get different patterns. Though I'm not sure how to nicely handle bigger case like 500x500 where you current implementation looks neat. Maybe something like number of rows/cols less than certain N (e.g. 4) then angle speed is selected randomly.

What do you think?

ampersanda commented 5 years ago

That's okay, this is the version of 200x200. http://quil.info/sketches/show/85bf2fd0b0984862a185f097f7598143e213353a557dfb8d3079c309dafd5109, I randomize the speed every run.

500x500 http://quil.info/sketches/show/112bd73f0204acbe7be2c6437a2dfb8e27fe17fe0ed86b248afd376864dc9c2e

nbeloglazov commented 5 years ago

Thanks Mochamad! Added the example: http://quil.info/?example=lissajous%20table. I made some changes to the sketch: removed fun-mode as seems like you are updating most of state through atoms anyway and angle can be calculated based on frame-count. Updated function that generates speed to produce unique speeds and be compatible with 500x500. Also added a few comments.

http://quil.info/sketches/show/example_lissajous-table

ampersanda commented 5 years ago

Thank you for the code refactoring (I still figure out how to code better in Clojure) and comments at the sketch codes. I forgot to add explanation about what I code.