This is my first real program with Clojure (and with Quil). If you’re not aware, Quil is a set of Clojure bindings to the Processing framework.
This is my program so far:
(ns quiltest.core
(:require [quil.core :as q]
[quil.middleware :as m]
[clojure.inspector :as n]))
(def width 500)
(def height 500)
(def ncurves 25)
(def curve-length 100)
(def curve-step 1)
(def noise-scale 0.001)
(defn plot-curve
[pts]
(doseq [endpoints (partition 2 1 (first pts) pts)]
(let [[p1 p2] endpoints
[x1 y1] p1
[x2 y2] p2]
(apply q/line [x1 y1 x2 y2]))))
(defn flow-step
[{:keys [x y] :as all}]
(let [noise (get all :noise q/noise)
step (get all :step curve-step)
scale (get all :scale noise-scale)
angle (q/map-range (noise (* scale x) (* scale y)) 0 1 0 q/TWO-PI)]
[(* step (q/cos angle)) (* step (q/sin angle))]))
(defn flow-line
[x y & opts]
(let [noise (get opts :noise q/noise)
step (get opts :step curve-step)
scale (get opts :scale noise-scale)]
(iterate flow-step {:x x :y y :noise noise :step step :scale scale})))
(defn ->xy
[{:keys [x y]}]
[x y])
(defn setup []
; Set frame rate to 30 frames per second.
(q/frame-rate 1)
; Set color mode to HSB (HSV) instead of default RGB.
(q/color-mode :hsb)
; setup function returns initial state. It contains
; circle color and position.
{:color 0
:angle 0})
(defn draw-state [state]
; Clear the sketch by filling it with light-grey color.
(q/background 240)
(q/stroke-weight 10)
(q/stroke 255 0 0)
(doseq
[[x-start y-start] (repeatedly ncurves (fn [] [(rand-int width) (rand-int height)]))]
(->>
(take curve-length (flow-line x-start y-start))
(map ->xy)
(plot-curve)
)))
(q/defsketch quiltest
:title "You spin my circle right round"
:size [width height]
; setup function called only once, during sketch initialization.
:setup setup
; update-state is called on each iteration before draw-state.
:draw draw-state
:features [:keep-on-top]
; This sketch uses functional-mode middleware.
; Check quil wiki for more info about middlewares and particularly
; fun-mode.
:middleware [m/fun-mode])
The basic process looks like this:
- Select a point in the window.
- Select a value from the noise function and interpret it as an angle.
- Take a step from the starting point in the direction of the angle.
- Repeat until you have a curve.
- Plot the curve.
- Repeat with another starting point.
The error I’m getting is below:
Exception in :draw function: #error {
:cause nil
:via
[{:type java.lang.NullPointerException
:message nil
:at [clojure.lang.RT floatCast RT.java 1319]}]
:trace
[[clojure.lang.RT floatCast RT.java 1319]
[quil.core$line invokeStatic core.cljc 2344]
[quil.core$line invoke core.cljc 2328]
[clojure.lang.AFn applyToHelper AFn.java 165]
[clojure.lang.AFn applyTo AFn.java 144]
[clojure.core$apply invokeStatic core.clj 665]
[clojure.core$apply invoke core.clj 660]
[quiltest.core$plot_curve invokeStatic core.clj 19]
[quiltest.core$plot_curve invoke core.clj 13]
[quiltest.core$draw_state invokeStatic core.clj 76]
[quiltest.core$draw_state invoke core.clj 66]
[clojure.lang.Var invoke Var.java 384]
[quil.middlewares.fun_mode$wrap_draw_update$quil_draw__2077 invoke fun_mode.cljc 16]
[quil.middlewares.safe_fns$wrap_fn$fn__260 invoke safe_fns.clj 8]
[quil.middlewares.bind_output$bind_output$iter__298__302$fn__303$fn__318 invoke bind_output.clj 21]
[quil.applet$_draw invokeStatic applet.clj 217]
[quil.applet$_draw invoke applet.clj 215]
[quil.Applet draw nil -1]
[processing.core.PApplet handleDraw PApplet.java 2475]
[quil.Applet handleDraw nil -1]
[processing.awt.PSurfaceAWT$12 callDraw PSurfaceAWT.java 1547]
[processing.core.PSurfaceNone$AnimationThread run PSurfaceNone.java 313]]}
stacktrace: java.lang.NullPointerException: null
at clojure.lang.RT.floatCast (RT.java:1319)
quil.core$line.invokeStatic (core.cljc:2344)
quil.core$line.invoke (core.cljc:2328)
clojure.lang.AFn.applyToHelper (AFn.java:165)
clojure.lang.AFn.applyTo (AFn.java:144)
clojure.core$apply.invokeStatic (core.clj:665)
clojure.core$apply.invoke (core.clj:660)
quiltest.core$plot_curve.invokeStatic (core.clj:19)
quiltest.core$plot_curve.invoke (core.clj:13)
quiltest.core$draw_state.invokeStatic (core.clj:76)
quiltest.core$draw_state.invoke (core.clj:66)
clojure.lang.Var.invoke (Var.java:384)
quil.middlewares.fun_mode$wrap_draw_update$quil_draw__2077.invoke (fun_mode.cljc:16)
quil.middlewares.safe_fns$wrap_fn$fn__260.invoke (safe_fns.clj:8)
quil.middlewares.bind_output$bind_output$iter__298__302$fn__303$fn__318.invoke (bind_output.clj:21)
quil.applet$_draw.invokeStatic (applet.clj:217)
quil.applet$_draw.invoke (applet.clj:215)
quil.Applet.draw (:-1)
processing.core.PApplet.handleDraw (PApplet.java:2475)
quil.Applet.handleDraw (:-1)
processing.awt.PSurfaceAWT$12.callDraw (PSurfaceAWT.java:1547)
processing.core.PSurfaceNone$AnimationThread.run (PSurfaceNone.java:313)
That’s a hefty error message, but I gather from it that there’s an error converting something to a floating point number?
Another problem I’m having is that if I supply a dummy noise function (say #(* 0 %1 %2)
) to flow-line
it still picks up q/noise
. I haven’t been able to figure out why that is.