# Rotating Rectangles

Based on a seminar I went to yesterday.

``````displayMode(FULLSCREEN)
function setup()

local n = {2,3}
local picture = "Documents:Snowman" -- REPLACE THIS LINE
meshes = {}
pics = {}
nmeshes = 0
local w = math.min(WIDTH,HEIGHT)
if w == WIDTH then
ox,oy = 0,(HEIGHT-WIDTH)/2
else
ox,oy = (WIDTH-HEIGHT)/2,0
end
local ver,tex,l,img,m
for _,v in ipairs(n) do
m = mesh()
table.insert(meshes,m)
local img = image(w,w)
table.insert(pics,img)
m.texture = img
nmeshes = nmeshes + 1
ver = {}
tex = {}
l = w/v
for i=1,v do
for j=1,v do
for _,u in ipairs({
{1,1,1,0},
{1,0,0,0},
{0,0,0,1},
{1,1,1,0},
{0,0,0,1},
{0,1,1,1}
}) do
table.insert(ver,vec2((i-u[1])*l,(j-u[2])*l))
table.insert(tex,vec2((i-u[3])/v,(j-u[4])/v))
end
end
end
m.vertices = ver
m.texCoords = tex
m:setColors(255,255,255,255)
end
cmesh = 0
m = mesh()
img = image(w,w)
m.texture = img
m:setRectTex(1,0,0,1,1)
meshes[0] = m
setContext(img)
background(255, 255, 255, 255)
noSmooth()
sprite(picture,w/2,w/2)
setContext()
stime = ElapsedTime
end

function draw()
background(51, 51, 51, 255)
pushMatrix()
translate(ox,oy)
meshes[cmesh]:draw()
popMatrix()
if auto then
if ElapsedTime - stime > 1 then
nextmesh()
end
end
end

function touched(touch)
if touch.state == ENDED then
if touch.tapCount == 2 then
auto = not auto
else
nextmesh()
end
end
end

function nextmesh()
local n = cmesh
cmesh = cmesh%nmeshes + 1
setContext(pics[cmesh])
resetMatrix()
noSmooth()
background(255, 255, 255, 255)
meshes[n]:draw()
setContext()
stime = ElapsedTime
end
``````

The image is chopped up into a grid of squares which are then rotated 90 degrees anticlockwise (I think!). This process repeats itself, but as it does so then it cycles through a list of different sized grids. The default is to alternate between a grid of size 2 and of size 3. You can manually advance the process by tapping the screen, or set it to auto by double tapping.

It works by setting the texture of each mesh to the result of rendering the previous one. But then the rectangles in each mesh are pre-rotated so when a mesh is drawn it does the necessary rotation.

Interesting. In working through how your code worked, I simplified parts of it, as follows. (Update) I have added the `slices` array to reintroduce the flexibility in Andrew’s original code. (Further update) I have applied the edge effects correction.

``````
displayMode(FULLSCREEN)
function setup()
slices = {1, 3, 5}
local picture = myPict(slices) -- Replace with code for image
noSmooth()
meshes, pics = {}, {}
local dim = math.min(WIDTH, HEIGHT)
-- Edge effects correction to dim:
local sn = slices[2] * slices[3]
dim = math.floor(dim / sn) * sn
ox, oy = (WIDTH - dim) / 2, (HEIGHT - dim) / 2
for mn = 1, 3 do
local m = mesh()
local img = image(dim, dim)
meshes[mn - 1] = m
pics[mn - 1] = img
m.texture = img
local n = slices[mn]
local l = dim / n
local r = math.pi / 2
if mn == 1 then
r = 0
setContext(img)
background(255)
sprite(picture, dim / 2, dim / 2)
setContext()
end
for i = 0, n - 1 do
for j = 0, n - 1 do
local cx, cy = (i + 0.5) * l, (j + 0.5) * l
local idx = m:addRect(cx, cy, l, l, r)
local tx, ty = i / n, j / n
m:setRectTex(idx, tx, ty, 1 / n, 1 / n)
end
end
end
nmeshes = #meshes
cmesh = 0
stime = ElapsedTime
end

function draw()
background(0)
translate(ox, oy)
meshes[cmesh]:draw()
if auto and ElapsedTime - stime > 1 then nextmesh() end
end

function touched(touch)
if touch.state == ENDED then
if touch.tapCount == 2 then
auto = not auto
else
nextmesh()
end
end
end

function nextmesh()
local n = cmesh
cmesh = cmesh % nmeshes + 1
setContext(pics[cmesh])
resetMatrix()
background(255)
meshes[n]:draw()
setContext()
stime = ElapsedTime
end

``````

and I used the following image to follow the movement of the parts of the image. (Update) Faster version.

``````
function myPict(slices)
local n = slices[2] * slices[3]
local dim = math.min(WIDTH, HEIGHT)
-- Edge effects correction to dim:
dim = math.floor(dim / n) * n
local img = image(dim, dim)
local w = dim / n
-- Improved sizing of numbering:
fontSize(1152 / n / (math.floor(math.log10(n * n)) + 1))
rectMode(CORNER)
setContext(img)
for j = 0, n - 1 do
for i = 0, n - 1 do
local rn = n * j + i + 1
local c = H2RGB(rn / (n * n))
fill(c)
rect(i * w + 1, j * w + 1, w, w)
fill(255)
text(rn, i * w + w/2, j * w + w/2)
end
end
setContext()
return img
end

-- Hue (nil or [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
else r, b = 1, x end
return color(255 * r, 255 * g, 255 * b)
end

``````

Ah, I forgot about rotations in `addRect`. Useful.

The choice of pairs 2,3 was arbitrary. I’m told that successive Fibonnacci numbers make good choices. Also, there are edge effects - I’ll post an update that fixes those soon.

I think I see what you mean by edge effects - when I cycle through {3, 5} something is lost by the time the end state returns to the origin. (Update) I solved it by forcing the dimension of the picture and the mesh to be an integral multiple of the product of the size of the two ‘slices’.

That was my solution too.