How to repeat static drawing rotated four times by 90 degrees - python mode

Hi all,

I am new to Processing and to python for that matter. I am interested in creating linear, geometric ‘art’, in the first instance without animation, static.

I have managed to create a set of circles shifting increasingly to the right and with each time with decreasing diameter. See attachment.

And this is my code:

add_library('svg')

canvasX = 600
canvasY = 600
margin = 50

def setup():
    size(canvasX, canvasY)
    background(255)
    
    global svg_output
    svg_output = createGraphics(canvasX, canvasY, SVG, "circles_1_b.svg")

centerX = canvasX/2
centerY = canvasY/2
step = 10

def draw():
    
    beginRecord(svg_output)
    
    noLoop()
    noFill()
    global centerX
    global centerY
    global canvasX
    global canvasY
    global step
    global margin
    
    for i in range(canvasX - margin, (canvasX - margin)/2, - 2*step):
        
        circle(centerX, centerY, i)
        centerX = centerX + step

    for i in range((canvasX - margin)/2, step, - 2*step):
    
        circle(centerX, centerY, i)
        centerX = centerX - step
        
        
    endRecord()    
    
    
    save("circles_1_b.png")

Now I would like to get Processing to repeat the same drawing superimposed on the previous so that the circles shift downwards, then to the left, then upwards.

I know I can do that by repeating the above loops with small changes, but I think there must be a better way.

I am looking into the Python Processing reference, and I think first I need to group the circles in one shape with createShape. Then I’m trying various things with rotate() and translate() but I do not understand from the reference how these function work with the draw function.

Any tips, hints or words of wisdom are welcome!

Many thanks,
Leo

1 Like

Hello @LeoP,

you are on a good track with rotate() and translate()!
They can be a bit complicated to grasp so start with simple things like drawing an ellipse and figure out what it does to that ellipse.

Let’s draw one in position (0, 0) and one in position (-50, -50).

def setup():      
    size(100, 100)
    background(20)
    noStroke()

    fill(230)

    ellipse(0, 0, 20, 20)
    ellipse(-50, -50, 20, 20)

Of course you see only the one at (0, 0) and just partially but not the one in (-50, -50) because it is on the top left on the previous one, outside of the canvas:

000

Now let’s use translate:

def setup():      
    size(100, 100)
    background(20)
    noStroke()
    fill(230)

    translate(75, 75)
    ellipse(0, 0, 20, 20)
    ellipse(-50, -50, 20, 20)

As you can see, the 2 ellipses are now visible. This is because the translate function is moving the canvas. What translate(75, 75) means is that the coordinate (0, 0) that was previously drawn at the screen pixel [0, 0] is now drawn at the screen pixel [75, 75]:

000

Ok let’s add a bit of rotation now:

def setup():      
    size(100, 100)
    background(20)
    noStroke()
    fill(230)

    translate(75, 75)
    rotate(-HALF_PI / 2)
    ellipse(0, 0, 20, 20)
    ellipse(-50, -50, 20, 20)

I added a rotation by 45° counter clockwise and now the dots appear aligned:

000

/!\ Be careful: the order in which you write your transforms is important. Try switching the translate and rotate function and see how it behaves.

Something to note also is the fact that the transforms are additive:

def setup():      
    size(100, 100)
    background(20)
    noStroke()
    
    for k in range(0, 3):
        translate(25, 25)
        fill(100 + k * 50)
        ellipse(0, 0, 30 - k * 5, 30 - k * 5)

Even though, translate(25, 25) does not change, you can see how each ellipse is translated by (25, 25) from each other.

000

To go around this, we can save the current transform operations, perform the one we want, and put back the old ones with the popMatrix() and pushMatrix() functions.

def setup():      
    size(100, 100)
    background(20)
    noStroke()
    
    for k in range(0, 3):
        pushMatrix()
        translate(25, 25)
        fill(100 + k * 50)
        ellipse(0, 0, 30 - k * 5, 30 - k * 5)
        popMatrix()

Now all the ellipses are on top of each others:

000

I hope you have a better understanding of it now.
Here what your code could look like to answer your question:

def setup():   
    canvasX = 600
    canvasY = 600
    margin = 50
    centerX = 300
    centerY = 300
    step = 10
    
    size(600, 600)
    background(255)
    noFill();

    for k in range(0, 4):
        
        pushMatrix()
        translate(300, 300)
        rotate(k * HALF_PI)
        translate(-300, -300)
        
        for i in range(canvasX - margin, (canvasX - margin)/2, - 2*step):
            
            circle(centerX, centerY, i)
            centerX = centerX + step
    
        for i in range((canvasX - margin)/2, step, - 2*step):
        
            circle(centerX, centerY, i)
            centerX = centerX - step
        
        popMatrix()
2 Likes

Hallo @jb4x,

Thank you so much for taking the time to post a detailed reply. I understand how these functions work a bit better but I am playing around with your ellipses examples to really get the hang of it.

I am surprised that the draw() function is not necessary. I had understood that it is compulsory in Processing.

Kind regards,
Leo

1 Like

Setup() is called only once at the begining of the execution then draw() is called repeatedly around 60 times per second.

If you are drawing something on the canva that will never change then no need to use draw()

1 Like

You can leave out the setup(), too. So just –

canvasX = 600
canvasY = 600
margin = 50
...

You might hear this referred to as a ‘static mode’ sketch.

2 Likes