Question

The code below draws me the sine wave throughout the screen, and beyond. However, I want that x never exceeds (width). At that point, the window should be cleared, and the wave should be drawn again, starting at 0. I tried

(set-state! :x (mod (seq->stream x) (width)))

but it didn't work. I checked some examples, tried some code which made use of checking whether (> x (width)), tried to put the logic into the draw function, but they don't work either.

I would like to draw a continuous waveform (like an electrocardiogram) on a limited display. I would appreciate any help.

(ns soso.core
  (:require [quil.core :refer :all]
            [quil.helpers.seqs :refer [seq->stream range-incl]]))

(defn setup []
  (smooth)
  (frame-rate 100)
  (background 255)
  (let [x (range-incl)]
    (set-state! :x (seq->stream x))))

(defn draw []
  (stroke 0)
  (stroke-weight 2)
  (let [x ((state :x))
        y (round (* 100 (abs (sin x))))]
    (ellipse x y 4 4)))

Edit

When I tried to put the logic into the draw function, I wrote (set-state! :x 0) in the setup function, and put the following code into the draw function:

(let [x (if (> ((state :x)) 10)
            0
          (inc ((state :x))))])

But it didn't work, and didn't throw any error in any of the nrepl buffers. To see what happened, I tried this code in the user repl:

(let [x 0]
  (take 20
        (if (> x 10)
            0
          (inc x))))

Even if I tried this code by wrapping the if statement inside (into '()), the code complained with: "IllegalArgumentException Don't know how to create ISeq from: java.lang.Long clojure.lang.RT.seqFrom". It is the same with:

(loop [x 0]
  (if (> x 10)
    0
    (recur (inc x))))

What is wrong with this if statement? The clojure api says that if tests the test condition, and then evaluates and yields then or else branches, accordingly. If it yields, it should spit out that integer, which in turn gets added to the list, which in turn should be listed by take function, I think.

Was it helpful?

Solution

Something more like this seems to give the effect you are looking for.

(defn draw []
  (stroke 0)
  (stroke-weight 2)
  (let [x ((state :x))
        y (+ 100 (* 100 (sin (/ x 100))))]
    (ellipse (mod x (width)) y 4 4)))

Couple of issues you are encountering:

  1. The input to sin is a floating value in radians. My hackery of divide by 100 here just makes sure that we're getting a nice continuous output. Practically if you want to cycle every n pixels you need to use 2 PI / n to adjust x.
  2. Rounding off the value is going to give you points, as the domain of sin is 1 to -1. Here I'm adjusting by adding on 100.
  3. Where you fiddle with x will depend on the exact requirement. Here I'm simply wrapping your x value by taking it's modulus in the draw function.

Hope this helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top