Functions

From GeoMod

Jump to: navigation, search

Introducing functions. The first example uses the 2d array of tiles. The second uses the bouncing ball example code.

2d tiles

In the code for the 2d array of tiles we create a set of tiles with the top left corner of the tiles at the position (0,0,0),

from visual import *
from random import uniform

# define parameters
nx = 5
lx = 4.0
nz= 4
lz=4.0

# initialize variables
dx = lx/nx
dz= lz/nz

# create tiles (top left at 0,0,0)
tiles=[]

for i in range (nx):
    for j in range (nz):
        tiles.append(box(length=dx,
                         width=dz,
                         height=.5,
                         color=(uniform(0.5,1),0,0) ))
        tiles[-1].pos.x=0+i*dx
        tiles[-1].pos.z=0+j*dz
        #print i,j, tiles[-1].pos

#create axes
xaxis= cylinder(axis=(4,0,0), color=color.red, radius=.05)
yaxis= cylinder(axis=(0,4,0), color=color.blue, radius=.05)
zaxis= cylinder(axis=(0,0,4), color=color.yellow, radius=.05)

which gives Image:tiles-a.png

To move the tiles so that the center of the set of tiles is at (0,0,0) we add the following code to the end of the program.

#translate tiles so center of grid is 0,0,0
for i in tiles:
    i.pos.x=i.pos.x-(nx-1)*dx/2.0
    i.pos.z=i.pos.z-(nz-1)*dz/2.0
    print (nx-1)/2.0, (nz-1)/2.0, i.pos

This gives Image:tiles.png

Functions

What if we had a number of sets of tiles that we wanted to translate to different locations? We have used functions before; in the code above, the function "uniform(0.5,1)" selects a random number between 0.5 and 1. The code for the uniform() function is imported in the second line of the program.

from random import uniform

Well, we can also create our own functions. Here is an adaptation of the above code, but with the translation of the tiles done by a function.

from visual import *
from random import uniform

def translate(lst, x_late=0, y_late=0, z_late=0):
    '''program to translate all objects in list (lst)'''
    for i in lst:
        i.pos.x=i.pos.x-x_late
        i.pos.z=i.pos.z-z_late
        print i.pos

# define parameters
nx = 5
lx = 4.0
nz= 4
lz=4.0

# initialize variables
dx = lx/nx
dz= lz/nz

# create tiles (top left at 0,0,0)
tiles=[]

for i in range (nx):
    for j in range (nz):
        tiles.append(box(length=dx,
                         width=dz,
                         height=.5,
                         color=(uniform(0.5,1),0,0) ))
        tiles[-1].pos.x=0+i*dx
        tiles[-1].pos.z=0+j*dz
        #print i,j, tiles[-1].pos

#create axes
xaxis= cylinder(axis=(4,0,0), color=color.red, radius=.05)
yaxis= cylinder(axis=(0,4,0), color=color.blue, radius=.05)
zaxis= cylinder(axis=(0,0,4), color=color.yellow, radius=.05)

###translate tiles so center of grid is 0,0,0
translate(tiles, (nx-1)*dx/2.0, 0.0, (nz-1)*dz/2.0)

In this code we create a new function called translate which moves all objects in the list by the amount specified. This produces the same result as the previous code.

The function is defined in the line

def translate(lst, x_late=0, y_late=0, z_late=0):

which defines the name of the function (translate) and the variables that need to be sent to the function. This function requires that a list of objects be sent to it. When the list gets to the function it is called lst no matter what the original name of the array (in this example the original name is tiles). You can also tell the function how much to translate the array of tiles in the x, y and z directions. These translation values are held in the variables x_late, y_late and z_late. These three values are optional. If they are not entered they take the default values given in the line (0 for all three).

The call to the function is the line

translate(tiles, (nx-1)*dx/2.0, 0.0, (nz-1)*dz/2.0)

which gives the name of the list that is to be translated, and the x, y and z translations.


Bouncing ball

In the following code (posted by Beth Bradshaw) a function called contact is defined that determines if two balls hit one another. The function takes two arguments (ball1 and ball2) that are spheres and calculates the distance between the spheres and compares it to the sum of the radii to see if the balls overlap or touch. If the balls touch the function returns True and if not it returns False.

from visual import *
from random import uniform,seed

def contact(ball1,ball2):
    hit=false
    #calculate distance
    a=ball1.pos.z-ball2.pos.z
    b=ball1.pos.x-ball2.pos.x
    d=ball1.pos.y-ball1.pos.y
    c=((a*a)+(b*b)+(d*d))**0.5
    #sum radii
    r=ball1.radius+ball2.radius
    #determine if there is a hit
    if c <= r:
        hit=true
    return hit
        
scene.forward = (0, -0.5,1) 
scene.up = (0,0,1)
scene.forward = (0, 1,0)
scene.lights = [vector(0, -10, 0)]

xaxis = curve(pos=[ (20, 0, 0), (0, 0,0)], color=(1,0,0))
yaxis = curve(pos=[ (0, 10, 0), (0, 0,0)], color=(0,1,0))
zaxis = curve(pos=[ (0, 0, 10), (0, 0,0)], color=(0,0,1))

balls=[]
seed(4)
nballs=5
vx=zeros((nballs,))
vz=zeros((nballs,))

for i in range(nballs):
    rad=uniform(0.5,2)
    vx[i]=uniform(1,2)
    balls.append(sphere(radius=rad,pos=(i,0,10)))

'''gravity constant'''
g = -9.8
'''change in time'''
dt = 0.01
'''initial z velocity'''
velz = 0.0
'''initial time'''
t = 0.0
print vx,vz
while t==0.0:
    rate(60)
    '''time'''
    t = t + dt
    vz=vz+g*dt
    for n,i in enumerate(balls):
        i.pos.z = i.pos.z + vz[n] * dt #+ 0.5 * g * dt * dt
        i.pos.x = i.pos.x + vx[n] * dt
        if i.pos.z < i.radius:
            vz[n] = -vz[n] * 0.75
            vx[n] = vx[n] * 0.75
            i.pos.z = i.radius
        
    for n in range(nballs-1):
        for m in range (n+1,nballs):
            ball1=balls[n]
            ball2=balls[m]
            print 'contact',n,m
            if contact(ball1,ball2):
                print n,m
Personal tools