#### Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

# Fermat's Spiral: another experiment with large images, meshes and HSV

edited October 2012 Posts: 489

Another simple, and mildly hypnotic, experiment with movement and colours, along the same lines as Golden Angle. Warning: some of the colour combinations may be hard to look at, and that may affect some people more than others.

```--
-- Fermat's Spiral
--

displayMode(FULLSCREEN)
supportedOrientations(LANDSCAPE_ANY)
function setup()
spin = 360
w2, h2 = WIDTH / 2, HEIGHT / 2
local len = math.sqrt(w2 * w2 + h2 * h2)
local scl = 50
local s = 5
local pi2 = math.pi * 2
local p = {}
local dim = len / scl
local ht = math.floor(dim * dim / math.pi)
for ang = 360, s, -s do
local r = -math.sqrt(theta) * scl
theta = theta % pi2
local x = r * math.cos(theta)
local y = r * math.sin(theta)
table.insert(p, vec2(x, y))
end
for ang = 0, 180, s do
local r = math.sqrt(theta) * scl
local x = r * math.cos(theta)
local y = r * math.sin(theta)
table.insert(p, vec2(x, y))
end
local v = triangulate(p)
local pAO, pBO = p[1], p[#p]
for a = s, 180 * (ht - 1), s do
local thetaA = math.rad(360 + a)
local rA = -math.sqrt(thetaA) * scl
local xA = rA * math.cos(thetaA)
local yA = rA * math.sin(thetaA)
local thetaB = math.rad(180 + a)
local rB = math.sqrt(thetaB) * scl
local xB = rB * math.cos(thetaB)
local yB = rB * math.sin(thetaB)
local pA, pB = vec2(xA, yA), vec2(xB, yB)
table.append(v, triangulate({pB, pA, pAO, pBO}))
pAO, pBO = pA, pB
end
m = mesh()
m.vertices = v
m:setColors(255, 255, 255)
img, ox, oy = {}, {}, {}
for j = 0, 3 do
img[j] = image(len, len)
setContext(img[j])
ox[j] = -(j % 2) * len
oy[j] = -(1 - math.floor(j / 2)) * len
resetMatrix()
translate(-ox[j], -oy[j])
m:draw()
setContext()
end
spriteMode(CORNER)
end

function draw()
local c = ElapsedTime / 60
background(H2RGB(c % 1))
-- The 0.5 in the line below affects the colour combinations.
-- A value of 0.4 may reduce the frequency of combinations that jar.
tint(H2RGB((c + 0.5) % 1))
translate(w2, h2)
rotate(-ElapsedTime * spin % 360)
for i = 0, 3 do sprite(img[i], ox[i], oy[i]) end
end

function table.append(t1, t2)
local t1n = #t1
for i = 1, #t2 do
t1[t1n + i] = t2[i]
end
end

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

Posts: 5,400

That's a really neat effect.

It looks like you are choosing inverse hues for the two colours? That can sometimes produce some fairly hard-to-look-at colour combinations.

• Posts: 371

.@mpilgrem, I have decided to stop trying to understand your code, and just look at the pretty colours. You have some of the best (and most confusing) code I have ever seen.

• Posts: 489

Hello @Simeon. Thank you for adding the screen shot. I've lost the ability to do that with Codea 1.4.6(15) on iOS 6.0. (I've added the issue to the tracker.) I'll add a warning about the colour combinations to my original comment; they may affect some people more than others.

• Posts: 489

Hello @Jordan. I read that you are starting to learn trigonometry. Good luck with that. Some trigonometry underpins this code, as well as polar coordinates and a line known as Fermat's spiral that is usually expressed as a relationship between its polar coordinates.

At its simplest, this code draws a pattern on a large image. The pattern is drawn in opaque white on a transparent black background. By using `tint` and `sprite` onto a coloured background, the two colours can be varied. The image is then rotated about the centre of the viewer.

A complication is that Codea cannot handle large images, so the image is in fact made up of an array of four separate images, arranged like four panes in a square window.

The pattern is drawn and coloured in using a mesh. Unfortunately, the built-in `triangulate` function cannot handle polygons with more than 256 points. In any event, the time it takes depends on the square of the number of points. So the code builds up the mesh in steps, an initial step for the complex middle and then one quad at a time.

• Posts: 371

I feel so proud for noticing that triangulate one myself (check the issue tracker ). Thanks @mpilgrem, maybe now it will make sense.