Golden Angle: an experiment with phi, large images and HSV

The code below, for Codea version 1.4.6(15), creates a rotating coloured background with a hypnotic dynamic.

The background is made up of four image panes, because of the limitation in rendering to large images discussed here. To keep things simple, the background pattern is drawn four times, each time being clipped to one of the panes. With displayMode(STANDARD), hairline gaps appear between the panes that spoil the effect. They disappear with displayMode(FULLSCREEN).

The colouring makes use of the relationship between HSV and RGB to create a spectrum.

The pattern is based on the golden angle and Helmut Vogel’s construction of the sunflower head(Fermat’s spiral).


--
-- Golden Angle
-- 

displayMode(FULLSCREEN)
supportedOrientations(LANDSCAPE_ANY)
function setup()
    scale, dot, spin = 6, 10, 24
    local pi2 = 2 * math.pi
    local phi = (1 + math.sqrt(5)) / 2 -- Golden ratio
    local ga = pi2 / phi ^ 2           -- Golden angle (radians)
    w2, h2 = WIDTH / 2, HEIGHT / 2
    local radius = math.sqrt(w2 * w2 + h2 * h2)
    local max = (radius / scale) ^ 2   -- Number of dots
    len2 = (radius * 2 + dot) / 2      -- Size of each quarter tile
    img, ox, oy = {}, {}, {}
    for j = 0, 3 do
        img[j] = image(len2, len2)
        setContext(img[j])
        ox[j] = -(j % 2) * len2
        oy[j] = -(1 - math.floor(j / 2)) * len2
        local ang = 0
        for i = 1, max do 
            local l = math.sqrt(i) * scale
            local x, y = l * math.cos(ang), l * math.sin(ang)
            local r, g, b = H2RGB(l / radius)
            fill(r, g, b)
            ellipse(x - ox[j], y - oy[j], dot)
            ang = (ang + ga) % pi2
        end
        setContext()
    end
    spriteMode(CORNER)
end

function draw()
    background(0)
    translate(w2, h2)
    rotate(ElapsedTime * spin % 360)
    for i = 0, 3 do sprite(img[i], ox[i], oy[i]) end
end

-- Hue (nil or [0, 1)) to RGB; (S = 1, V = 1)
function H2RGB(h)
    if not h then return 0, 0, 0 end
    local r, g, b
    local h1 = h * 6
    local x = (1 - math.abs(h1 % 2 - 1))
    if h1 < 1 then r, g, b = 1, x, 0
    elseif h1 < 2 then r, g, b = x, 1, 0
    elseif h1 < 3 then r, g, b = 0, 1, x
    elseif h1 < 4 then r, g, b = 0, x, 1
    elseif h1 < 5 then r, g, b = x, 0, 1
    elseif h1 < 6 then r, g, b = 1, 0, x end
    return 255 * r, 255 * g, 255 * b
end

Fantastic and hypnotic.

wow, cool