Mystic Rose

Hi,
This is a traditional mathematical circle pattern called Mystic Rose… google it for more info, but essentially it is a circle with points marked equidistant around the circumference, and lines drawn between every point.

My approach was to work out the coordinates of the points, put them in a table and then read out the values to plot the lines. The loop increments to prevent duplicating lines.

To see how this works, un-comment the print instruction just before the end and set the points down to 4. this should just draw 6 lines. The numbers are the table key values so 1 2 3 4 indicates a line drawn from (c[1], c[2]) to (c[3], c[4]).

I’d be grateful to hear any feedback. Initially I was iterating angles and getting some very strange results which iterating points solved. And somehow I wonder if I should be using iPairs for coordinates, but would need help as to how to do this, and would it be more efficient anyway?

Many thanks,

David

-- Mystic Rose v3.1 by David Cockram

-- Use this function to perform your initial setup
function setup()
    print("Hello World!")
    
    parameter.integer ("points", 2,40,20)
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(40, 40, 50)

    -- This sets the line thickness
    strokeWidth(2)

    -- Do your drawing here
    fill(31, 103, 38, 132)
    ellipse(380, 370, 704)
    
    a = 380             -- circle centre (a,b) radius r
    b = 370
    r = 350
    angle = 360/points  -- angle to increment
    w = points*2        -- number of coordinates
    c = {}              -- table of coords {x1, y1, x2, y2 ... etc}
        
-- this part works out the coordinates, based on the number of points
    
    for i = 0, points-1 do
    t = i*angle    

-- put coordinate pairs in a table, c

    c[2*i+1] = a + r*math.sin(math.rad(t))   -- x coordinate
    c[2*i+2] = b + r*math.cos(math.rad(t))   -- y coordinate
    end
    
-- draw lines. The start value h+2 increments each loop to prevent repeating lines    
          
    for h = 1, w-3, 2 do
        
    for i = h+2, w-1, 2 do
    line(c[h], c[h+1], c[i], c[i+1])
--   print(h, h+1, i, i+1)  -- line drawing key table values to check 
    end

    end
 
end

@David - I think your approach is fine.

ipairs are most useful where you are looping through a non sequential table, eg a bunch of physics objects.

Lovely result! =D>

@David Looks good. Maybe you can add parameters to change the line colors, or random colors.

@David I like seeing examples like this because they’re fun to expand on. I’m not sure of your coding experience, but what would happen if you added a line limit parameter. If it was set to like 600 lines, then when line 601 was drawn, line 1 would erase, etc. Would that cause a rotation effect or just random lines erasing. There’s a lot of possibilities.

Nice job! For those who want to see before loading:
sss

Very cool, I’m having fun with it :slight_smile:

Adding a bit of animation:

-- Mystic Rose v3.1 by David Cockram

function setup()
    centre = vec2(WIDTH/2,HEIGHT/2)
    radius = math.min(WIDTH,HEIGHT)/2 - 20

    parameter.integer ("points", 2,40,20,compute_points)
    frame = 0
end

function draw()
    background(40, 40, 50)
    strokeWidth(2)
    fill(31, 103, 38, 132)
    translate(centre.x,centre.y)
    rotate(frame/2)
    ellipseMode(RADIUS)
    ellipse(0,0,radius)
    local n = math.abs(math.floor(frame/10)%(2*npts-4)-npts+2)+2
    for h = 1, npts-1 do
        rotate(angle)
        for i = 2, n do
            line(radius, 0, x[i], y[i])
        end
    end
    frame = frame + 1
end

function compute_points(n)
    x,y = {},{}
    angle = 2*math.pi/n
    for i=0,n-1 do
        table.insert(x,radius*math.cos(angle*i))
        table.insert(y,radius*math.sin(angle*i))
    end
    angle = 360/n
    npts = n
end

Thanks for the feedback and pic :wink: That animation is great Andrew… I just need to spend time figuring out how the hell you did that! Very clever.

I added a rotation slider… it does create some more interesting patterns. Try leaving the points at 11 at first and move the rotation back and forth to see what happens. As @dave1707 says, it’s fun to expand on.


-- Mystic Rose v3.3  rotation by David Cockram

-- Use this function to perform your initial setup
function setup()
    print("Hello World!")
    
    parameter.integer ("points", 2,20,11)
    parameter.integer ("rotation", 1, 90, 33)
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(40, 40, 50)

    -- This sets the line thickness
    strokeWidth(1)

    -- Do your drawing here
    fill(31, 103, 38, 132)
    ellipse(380,370,704)
    
    a = 380             -- circle centre (a,b) radius r
    b = 370
    r = 350
    angle = 360/points  -- angle to increment
    w = points*2        -- number of coordinates
    c = {}              -- table of coords {x1, y1, x2, y2 ... etc}
        
-- this part works out the coordinates, based on the number of points
    for rot = 0, 360, rotation do
    
    for i = 0, points-1 do
    t = i*angle + rot

-- put coordinate pairs in a table, c

    c[2*i+1] = a + r*math.sin(math.rad(t))   -- x coordinate
    c[2*i+2] = b + r*math.cos(math.rad(t))   -- y coordinate
    end
    
-- draw lines. The start value h+2 increments each loop to prevent repeating lines    
          
    for h = 1, w-3, 2 do
        
    for i = h+2, w-1, 2 do
    line(c[h], c[h+1], c[i], c[i+1])
--   print(h, h+1, i, i+1)  -- line drawing key table values to check 
    end

    end
    
    end
 
end

@David Some interesting effects. The one I like the best is points 2, rotation 1 at FULLSCREEN view.

Thanks @dave1707. I wondered at the possibility of putting interesting values in a table and cycling them every say 5s. Would like to add colour at some stage too. I could code the table part easily enough, but how would I cycle the settings?

@David You could add a counter in draw(). Then every 60 counts, add 1 to a table offset and 0 the counter. Use the table offset. When the offset reaches the table max, set it back to 1.

@David, Sorry, but I saw you accidently slipped a curse into your earlier code sharing post

What method do ppl normally use to ‘wait’ in Lua? I read a bit about loading extensions? Hmmmm, so decided to do a counter
for w = 0, x, 1 do
end
but x ended up around 10,000,000. I guess doing nothing takes almost no time at all…

Inserting print(x) really slows it down, but didn’t seem like a sensible solution.

@David The key to a wait function is to allow draw to execute as often as it likes but only change things after a certain time. There are two basic ways: to count frames or to count seconds.

function setup()
    frames = 0
end

function draw()
    frames = frames + 1
    if frames%10 == 0 then
        -- update stuff
    end
    -- do drawing stuff
end

Or

function setup()
    atime = ElapsedTime
end

function draw()
    if ElapsedTime > atime + 10 then
        --update stuff
        atime = ElapsedTime
    end
    -- do drawing stuff
end

More generally, you should separated updating from drawing. You should aim to draw something every frame, and ideally these should occur at a frame rate of 60fps. But you don’t have to update things every frame.

@David we’d love to have you upload your project into Codea Community. It’s very nice.

That looks beautiful David!!

Thanks guys, and @Andrew_Stacey - very helpful info as usual. Will definitely upload into CC. Just want to finish code for cycling through some nice settings. What would look nicer would be mixing from one to the next rather than cutting, esp once I introduce colour… I guess there must be a way, right?

btw is it possible to delete a post here? or just edit it down to a . or -

@David This is in response to your previous post that doesn’t seem to be here anymore. I saw the post and got a copy of your example before the site went down. I rearranged your code and changed some things to get it working, so here it is.


-- Mystic Rose v3.4  rotation 2 by David Cockram

displayMode(FULLSCREEN)

function setup()
    pTab={10,11,12,13,14}    -- point table
    rTab={20,21,22,23,24}    -- rotation table
    a = WIDTH/2     -- circle centre (a,b) radius r
    b = HEIGHT/2
    r = math.min(a,b)
    frames = 0
    n = 1
    strokeWidth(1)
end

function draw()
    background(40,40,50)
    if frames %4 == 0 then
        points = pTab[n]
        rotation = rTab[n]
        angle = 360/points -- angle to increment
        w = points*2 -- number of coordinates
        n = n + 1   -- cycle through table of points & rotation
        if n > #pTab
            then n = 1
        end
    end
    -- this part works out the coordinates, based on the number of points
    for rot = 0, 360, rotation do
        c = {} -- table of coords {x1, y1, x2, y2 ... etc}
        for i = 0, points-1 do
            t = i*angle + rot
            -- put coordinate pairs in a table, c
            table.insert(c,a + r*math.sin(math.rad(t))) -- x coordinate
            table.insert(c,b + r*math.cos(math.rad(t))) -- y coordinate
        end
        for h = 1, w-3, 2 do     
            for i = h+2, w-1, 2 do
                line(c[h], c[h+1], c[i], c[i+1])
            end
        end
    end
    frames = frames + 1
end

@David, It is possible, but you need to be a moderator, but you can edit your own post or discussion