Draw function, Processing, Python

Hi just wondering if the draw function is called when a while loop is running. I would like the draw function to be called after every iteration of the while loop and I would like to put a delay in every iteration. However it does not seem to draw until the while loop is complete. I have tried adding delays and reDraw() but it still doesn’t work. Does anyone know how I could get this to work?
Thanks Daniel

Please post your code so that we can offer specific suggestions.

1 Like
add_library('peasycam')
from peasy import PeasyCam

import math

def setup():
    size(800, 800, P3D)
    cam = PeasyCam(this, 100)
    cam.setMinimumDistance(50)
    cam.setMaximumDistance(500)
    background(23,117,46)
    textSize(10)
    frameRate(60)
    strokeWeight(5)
    global finished
    finished = False
    

#faces class

class Face:
    def __init__(self, index):
        self.index = index
        
    def getcolour(self):
        if self.index == 0:
            self.colour = 'white'
            self.pos_curr = [0,1,0]
            self.pos_set = [0,1,0]
            
        elif self.index == 1:
            self.colour = 'blue'
            self.pos_curr = [0,0,1]
            self.pos_set = [0,0,1]
            
        elif self.index == 2:
            self.colour = 'orange'
            self.pos_curr = [1,0,0]
            self.pos_set = [1,0,0]
            
        elif self.index == 3:
            self.colour = 'green'
            self.pos_curr = [0,0,-1]
            self.pos_set = [0,0,-1]
            
        elif self.index == 4:
            self.colour = 'red'
            self.pos_curr = [-1,0,0]
            self.pos_set = [-1,0,0]
            
        elif self.index == 5:
            self.colour = 'yellow'
            self.pos_curr = [0,-1,0]
            self.pos_set = [0,-1,0]
            
    def check(self):
        if self.pos_curr == self.pos_set:
            return True
        else:
            return False
        
        

#cube class

class Cube:
    def __init__(self, x, y, z):
        self.faces = []
        #current positions of each cube -2<x<2 
        self.x_curr = x
        self.y_curr = y
        self.z_curr = z
        
        #the solved positition of the cube
        self._xset = x
        self._yset = y
        self._zset = z
    
    def getfaces(self):
        for i in range (0,6):
            newFace = Face(i)
            newFace.getcolour()
            self.faces.append(newFace)
    
    def show(self):
        len_= 10
        r=6
        stroke(0)
        pushMatrix()
        
        translate(self.x_curr*2*r,self.y_curr*2*r,self.z_curr*2*r)
        beginShape(QUADS)
        
        #front face
        for each in self.faces:
            if each.pos_curr == [0,0,1]:
                if each.colour == 'white':
                    fill(251,255,255)
                elif each.colour == 'blue':
                    fill(77,77,255)
                elif each.colour == 'green':
                    fill(57,255,20)
                elif each.colour == 'orange':
                    fill(255,95,31)
                elif each.colour == 'yellow':
                    fill(255,237,39)
                elif each.colour == 'red':
                    fill(255,49,49)
        vertex(r, r, r)
        vertex(r, -r, r)
        vertex(-r, -r, r)
        vertex(-r, r, r)

        #bottom face
        for each in self.faces:
            if each.pos_curr == [0,-1,0]:
                if each.colour == 'white':
                    fill(251,255,255)
                elif each.colour == 'blue':
                    fill(77,77,255)
                elif each.colour == 'green':
                    fill(57,255,20)
                elif each.colour == 'orange':
                    fill(255,95,31)
                elif each.colour == 'yellow':
                    fill(255,237,39)
                elif each.colour == 'red':
                    fill(255,49,49)
        vertex(r, r, r)
        vertex(r, r, -r)
        vertex(-r, r, -r)
        vertex(-r, r, r)
        
        #right face
        for each in self.faces:
            if each.pos_curr == [1,0,0]:
                if each.colour == 'white':
                    fill(251,255,255)
                elif each.colour == 'blue':
                    fill(77,77,255)
                elif each.colour == 'green':
                    fill(57,255,20)
                elif each.colour == 'orange':
                    fill(255,95,31)
                elif each.colour == 'yellow':
                    fill(255,237,39)
                elif each.colour == 'red':
                    fill(255,49,49)
        vertex(r, r, r)
        vertex(r, r, -r)
        vertex(r, -r, -r)
        vertex(r, -r, r)
        

        #back face
        for each in self.faces:
            if each.pos_curr == [0,0,-1]:
                if each.colour == 'white':
                    fill(251,255,255)
                elif each.colour == 'blue':
                    fill(77,77,255)
                elif each.colour == 'green':
                    fill(57,255,20)
                elif each.colour == 'orange':
                    fill(255,95,31)
                elif each.colour == 'yellow':
                    fill(255,237,39)
                elif each.colour == 'red':
                    fill(255,49,49)
        vertex(r, r, -r)
        vertex(r, -r, -r)
        vertex(-r, -r, -r)
        vertex(-r, r, -r)

        #up face
        for each in self.faces:
            if each.pos_curr == [0,1,0]:
                if each.colour == 'white':
                    fill(251,255,255)
                elif each.colour == 'blue':
                    fill(77,77,255)
                elif each.colour == 'green':
                    fill(57,255,20)
                elif each.colour == 'orange':
                    fill(255,95,31)
                elif each.colour == 'yellow':
                    fill(255,237,39)
                elif each.colour == 'red':
                    fill(255,49,49)
        vertex(r, -r, r)
        vertex(r, -r, -r)
        vertex(-r, -r, -r)
        vertex(-r, -r, r)

        #left face
        for each in self.faces:
            if each.pos_curr == [-1,0,0]:
                if each.colour == 'white':
                    fill(251,255,255)
                elif each.colour == 'blue':
                    fill(77,77,255)
                elif each.colour == 'green':
                    fill(57,255,20)
                elif each.colour == 'orange':
                    fill(255,95,31)
                elif each.colour == 'yellow':
                    fill(255,237,39)
                elif each.colour == 'red':
                    fill(255,49,49)
        vertex(-r, r, r)
        vertex(-r, r, -r)
        vertex(-r, -r, -r)
        vertex(-r, -r, r)

        endShape()
        popMatrix()
        
#Moves class

class Moves:
    def __init__(self):
        self.yes=True

    def create(self):
        a=[]
        b=[]
        self.cubeList = []
        for x in range(-1,2):
            for y in range(-1,2):
                for z in range(-1,2):
                    newCube = Cube(x, y, z)
                    newCube.getfaces()
                    a.append(newCube)
                b.append(a)
                a=[]
            self.cubeList.append(b)
            b=[]
        
        
        
    def applyMatrix(self, rotation, matrix3D, face, matrix3D_2):
        angle=0
        while angle < HALF_PI:
            angle += 0.01
            for a in self.cubeList:
                for b in a:
                    for i in b:
                        if face == 'z':
                            check = i.z_curr
                        elif face == 'y':
                            check = i.y_curr
                        elif face == 'x':
                            check = i.x_curr
                        if check == rotation:
                            #altering position of each cube
                            
                            newx = matrix3D_2[0][0]*i.x_curr + matrix3D_2[0][1]*i.y_curr + matrix3D_2[0][2]*i.z_curr
                            newy = matrix3D_2[1][0]*i.x_curr + matrix3D_2[1][1]*i.y_curr + matrix3D_2[1][2]*i.z_curr
                            newz = matrix3D_2[2][0]*i.x_curr + matrix3D_2[2][1]*i.y_curr + matrix3D_2[2][2]*i.z_curr
                            i.x_curr = newx
                            i.y_curr = newy
                            i.z_curr = newz
                            strokeWeight(0)
            push()
            for n in self.cubeList:
                for each in n:
                    for q in each:
                        q.show()
            pop()
        strokeWeight(5)
        
        
        for a in self.cubeList:
            for b in a:
                for i in b:
                    i.x_curr = round(i.x_curr)
                    i.y_curr = round(i.y_curr)
                    i.z_curr = round(i.z_curr)
        
                    
        for a in self.cubeList:
            for b in a:
                for i in b:
                    if face == 'z':
                        check = i.z_curr
                    elif face == 'y':
                        check = i.y_curr
                    elif face == 'x':
                        check = i.x_curr
                    if check == rotation:
                        #altering the rotation of each cube
                        for each in i.faces:
                            if face == 'z':
                                a = -matrix3D[0][0]*each.pos_curr[0] + -matrix3D[0][1]*each.pos_curr[1] + -matrix3D[0][2]*each.pos_curr[2]
                                b = -matrix3D[1][0]*each.pos_curr[0] + -matrix3D[1][1]*each.pos_curr[1] + -matrix3D[1][2]*each.pos_curr[2]
                                c = matrix3D[2][0]*each.pos_curr[0] + matrix3D[2][1]*each.pos_curr[1] + matrix3D[2][2]*each.pos_curr[2]
                            elif face == 'x':
                                a = matrix3D[0][0]*each.pos_curr[0] + matrix3D[0][1]*each.pos_curr[1] + matrix3D[0][2]*each.pos_curr[2]
                                b = -matrix3D[1][0]*each.pos_curr[0] + -matrix3D[1][1]*each.pos_curr[1] + -matrix3D[1][2]*each.pos_curr[2]
                                c = -matrix3D[2][0]*each.pos_curr[0] + -matrix3D[2][1]*each.pos_curr[1] + -matrix3D[2][2]*each.pos_curr[2]
                            elif face == 'y':
                                a = -matrix3D[0][0]*each.pos_curr[0] + -matrix3D[0][1]*each.pos_curr[1] + -matrix3D[0][2]*each.pos_curr[2]
                                b = matrix3D[1][0]*each.pos_curr[0] + matrix3D[1][1]*each.pos_curr[1] + matrix3D[1][2]*each.pos_curr[2]
                                c = -matrix3D[2][0]*each.pos_curr[0] + -matrix3D[2][1]*each.pos_curr[1] + -matrix3D[2][2]*each.pos_curr[2]
                                a=-a
                                b=b
                                c=-c
                            newVector = [a,b,c]
                            each.pos_curr = newVector
                            

    def turnZ(self, move):
        #for z rotations
        #user = input('f, m, b, F, M or B')
        user= move
        if user == 'f':
            rotation = 1
            dir = -1
        elif user == 'F':
            rotation = 1
            dir = 1
        
        elif user == 's':
            rotation = 0
            dir = -1
        elif user == 'S':
            rotation =0
            dir = 1

        elif user == 'b':
            rotation = -1
            dir = -1
        elif user == 'B':
            rotation =-1
            dir = 1
        matrix3D = [[round(cos(dir*HALF_PI)),-round(sin(dir*HALF_PI)),0],[round(sin(dir*HALF_PI)),round(cos(dir*HALF_PI)),0],[0,0,1]]  
        matrix3D_2 = [[cos(dir*0.01),-sin(dir*0.01),0],[sin(dir*0.01),cos(dir*0.01),0],[0,0,1]]      
        self.applyMatrix(rotation, matrix3D, 'z', matrix3D_2)

    def turnX(self, move):
        #for x rotations
        user = move

        if user == 'r':
            rotation = 1
            dir = -1
        elif user == 'R':
            rotation = 1
            dir = 1
        
        elif user == 'm':
            rotation = 0
            dir = -1
        elif user == 'M':
            rotation =0
            dir = 1

        elif user == 'l':
            rotation = -1
            dir = -1
        elif user == 'L':
            rotation =-1
            dir = 1

        matrix3D = [[1,0,0],[0,round(cos(dir*HALF_PI)),-round(sin(dir*HALF_PI))],[0,round(sin(dir*HALF_PI)),round(cos(dir*HALF_PI))]]
        matrix3D_2 = [[1,0,0],[0,cos(dir*0.01),-sin(dir*0.01)],[0,sin(dir*0.01),cos(dir*0.01)]]    
        self.applyMatrix(rotation, matrix3D, 'x', matrix3D_2)
        
    def turnY(self, move):
        #for y rotations
        user = move

        if user == 'u':
            rotation = 1
            dir = -1
        elif user == 'U':
            rotation = 1
            dir = 1
        
        elif user == 'e':
            rotation = 0
            dir = -1
        elif user == 'E':
            rotation =0
            dir = 1

        elif user == 'd':
            rotation = -1
            dir = -1
        elif user == 'D':
            rotation =-1
            dir = 1

        matrix3D = [[round(cos(dir*HALF_PI)), 0, round(sin(dir*HALF_PI))], [0, 1, 0], [-round(sin(dir*HALF_PI)), 0, round(cos(dir*HALF_PI))]]
        matrix3D_2 = [[cos(dir*0.01), 0, sin(dir*0.01)], [0, 1, 0], [-sin(dir*0.01), 0, cos(dir*0.01)]]    
        self.applyMatrix(rotation, matrix3D, 'y', matrix3D_2)

    def axis(self, move):
        #a = input('Would you like to rotate along x, y or z axis? ')
        if  move == 'l' or move == 'm' or move == 'r' or move == 'L' or move == 'M' or move == 'R':
            self.turnX(move)
        elif move == 'u' or move == 'e' or move == 'd' or move == 'U' or move == 'E' or move == 'D':
            self.turnY(move)
        else:
            self.turnZ(move)

#Moves meaning

#Z axis
#f front face
#s middle face
#b back face

#Y axis
#u top face
#e middle face
#d bottom face

#X axis
#l left face
#m middle face
#r right face

a=Moves()
a.create()

move = 'U'


def draw():
    background(79,117,110)
    textSize(8)
    if keyPressed:
        if key == ' ':
            fill(0)
            text("Moves:", -50, -30,0)
            textSize(5)
            text("f- blue", -50, -20,0)
            text("b- green", -50, -13,0)
            text("u- white", -50, -6,0)
            text("d- yellow", -50, 1,0)
            text("l- red", -50, 8,0)
            text("r- orange", -50, 13,0)
    counter=0
delay(100)
    for i in a.cubeList:
        for each in i:
            for z in each:
                z.show()
                counter+=1
    
    while keyPressed:
        finished = True
        if key == 'f':
            a.axis('F')
            delay(500)
        elif key == 'r':
            a.axis('r')
            delay(500)
        #elif key == 's':
        #    a.axis('S')
        #    delay(500)
        elif key == 'b':
            a.axis('B')
            delay(500)
        elif key == 'u':
            a.axis('D')
            delay(500)
        #elif key == 'e':
        #    a.axis('E')
        #    delay(500)
        elif key == 'd':
            a.axis('U')
            delay(500)
        elif key == 'l':
            a.axis('l')
            delay(500)
        #elif key == 'm':
        #    a.axis('m')
        #    delay(800)
            
        elif key == 'F':
            a.axis('f')
            delay(500)
        elif key == 'R':
            a.axis('R')
            delay(500)
        #elif key == 'S':
        #    a.axis('s')
        #   delay(500)
        elif key == 'B':
            a.axis('b')
            delay(500)
        elif key == 'U':
            a.axis('d')
            delay(500)
        #elif key == 'E':
        #    a.axis('e')
        #    delay(800)
        elif key == 'D':
            a.axis('u')
            delay(500)
        elif key == 'L':
            a.axis('L')
            delay(500)
        #elif key == 'M':
        #    a.axis('M')
        #    delay(800)
        break

The while loop concerned is in applyMatrix() in moves

One possible strategy would be to refactor your code so that the variables or other specifications that are currently updated in your loop are instead updated with each call of the draw() function. Below is a simple example of refactoring.

Suppose we would like to draw some rectangles in cycles of 10. We draw 1 rectangle, then erase it and draw 2, then erase them and draw 3, et cetera. We could try this, but it does not work as intended:

def setup():
    size(400, 400)
    rectMode(CENTER)
    frameRate(1)

def draw():
    background(127)
    for i in range(10):
        background(127)
        for j in range(i):
            rect(random(100, 300), random(100, 300), 100, 100)

Refactoring the code as described above, we do this with the draw() function instead, which works as intended:

def draw():
    background(127)
    for i in range(frameCount % 10 + 1):
        rect(random(100, 300), random(100, 300), 100, 100)
1 Like

Please post Python topics in the Processing.py category. See if you can move this thread there now (click the pencil icon on the title to reassign it).

2 Likes

Hi I think I’m being slightly stupid but I’m confused at how I would implement this into my code and what you mean by this.

Essentially, you need to identify what specifications need to change each time the sketch is drawn. Instead of representing those specifications within a while loop, use global variables to hold that information, so that it persists between the automatic calls of the draw() function. Then, within the draw() function, update those global variables to prepare for the next call of the draw() function. In a sense, the automatic calls to the draw() function will become a replacement for the iterations of your while loop.

The frameCount variable that already exists is global, and might be useful to you, but it appears that your sketch is complex enough to require additional global variables. For example, you have this:

        angle=0
        while angle < HALF_PI:
            angle += 0.01

Quite likely, one of your global variables will be angle. Make sure it is declared global wherever it is used within a function. Assign it an initial value in the setup() function, then make sure it gets updated each time draw() gets called. The updating does not necessarily need to be performed within the draw() function itself. Instead, it could be updated within a function that is called directly or indirectly by the draw() function.

EDITED on June 11, 2022 to correct a typographical error.

2 Likes

Works amazingly tysm

1 Like

No need for additional fixed increasing global variables if they’re updated once per draw() iteration.

For example, if you need some global variable which is updated by .01 steps, just multiply that value by frameCount locally: someLocalVariable = .01 * frameCount

2 Likes