Classes
From GeoMod
Similar to functions classes can abstract code from the main program and make it easier to reuse the code.
A car class example
Why use a class? Say you have a program with a bunch of cars. Each car will be different but they all have certain similar properties, such as 4 wheels, a body etc. The car class can set up you basic car and you can then modify all the different properties of that car.
For example, here is a (slightly adapted) car class written by Ekta Amar that creates a car.
from visual import *
class carT:
def __init__(self,position):
self.car = frame(pos=position)
self.wheels = []
self.wheels.append(wheel(vector(-2,-1,-1), self.car))
self.wheels.append(wheel(vector(2,-1,-1), self.car))
self.wheels.append(wheel(vector(-2,-1,1), self.car))
self.wheels.append(wheel(vector(2,-1,1), self.car))
self.chasis= box(frame=self.car, length=4, width=3, height= 2,
color=color.green)
self.cha_fr = box(frame=self.car, pos=(0,-0.5,2),length=1.5, width=2, height =1,color=color.yellow)
def carmov(self): # To move the car
while 1:
rate(5)
if self.car.z <=0:
change = .2
if self.car.z >2.0:
change = -.3
self.car.z=self.car.z + change
self.wheelrot(change)
print 'final pos', self.car.z
def wheelrot(self,change): # To rotate the wheels
for i in self.wheels:
i.wheelrot(change)
print i
class wheel:
def __init__(self, pos, inframe, rad=0.5, offset=vector(0.0,0.1,0), ax=vector(1,0,0)):
self.wheel = frame(axis=ax, frame=inframe)
self.rad=rad
self.bwheel = sphere(frame=self.wheel, pos=pos,
color=color.red, radius=rad)
self.wwheel = sphere(frame=self.wheel, pos=pos+offset,
color=color.white, radius=rad)
def wheelrot(self,change): # To rotate the wheels
centerpt = (self.bwheel.pos+self.wwheel.pos)/2.0
circum=2*3.14*self.rad
ang = (change/circum)*2*pi
self.bwheel.rotate(angle=ang, axis=(1,0,0), origin=centerpt)
self.wwheel.rotate(angle=ang, axis=(1,0,0), origin=centerpt)
You will notice that there are actually two classes here, one for the car (carT) and one for the wheels (wheel). You will also notice that each class has a series of functions in it starting with __init__.
If you tried to save and run this code it would not work because all it does is define the classes. The program to run these classes is;
toyotaCamery =carT(vector(0,0,0)) #Create road road = box(pos=(0,-1.60,0), length =20.0, width=20, height= 0.2, color=color.blue) scene.autoscale=0 # To call the function for motion of the car toyotaCamery.carmov() # TO call the function for rotation of the wheels toyotaCamery.wheelrot()
This creates a car that moves back and forth. Notice that the wheels rotate acurately.
If you wanted to create two cars then you could just add the line
toyotaCamery2 =carT(vector(5,0,5))
which would create a second car that did not move (because you have not called the methods in the class for movement (eg. toyotaCamery.carmov()).
A Raster Class
Here we start with the same program to create an array of tiles:
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)
Now we will create a class to create a set of tiles and manipulate them.
First we take out the lines of code defining the tiles
# 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
and replace them with the call to the class.
tileset = raster(nx, nz, dx, dz)
Creation of an object from a class is called instantiation
We also add, near the top of the file the description of the raster class, so the new code becomes;
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
class raster:
'''creates a raster array of tiles
with the top, left tile at position (0,0,0)'''
def __init__(self, nx, nz, dx=1, dz=1):
self.nx = nx #number of columns
self.nz = nz #number of rows
self.dx = dx #x dimension of tiles
self.dz = dz #x dimension of tiles
self.tiles=[]
for i in range(nx):
for j in range(nz):
self.tiles.append(box(length=dx,
width=dz,
height=.5,
color=(uniform(0.5,1),0,0) ))
self.tiles[-1].pos.x=i*dx
self.tiles[-1].pos.z=j*dz
# 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)
tileset = raster(nx, nz, dx, dz)
#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)
This is the set of tiles that have not been translated. To translate the files we could call the translate function by adding the line
translate(tileset.tiles, (nx-1)*dx/2.0, 0.0, (nz-1)*dz/2.0)
Note that the set of tiles are now named tileset.tiles
Another alternative is to add the translate function to the class, so that the class becomes;
class raster:
'''creates a raster array of tiles
with the top, left tile at position (0,0,0)'''
def __init__(self, nx, nz, dx=1, dz=1):
self.nx = nx #number of columns
self.nz = nz #number of rows
self.dx = dx #x dimension of tiles
self.dz = dz #x dimension of tiles
self.tiles=[]
for i in range(nx):
for j in range(nz):
self.tiles.append(box(length=dx,
width=dz,
height=.5,
color=(uniform(0.5,1),0,0) ))
self.tiles[-1].pos.x=i*dx
self.tiles[-1].pos.z=j*dz
def translate(self, x_late=0, y_late=0, z_late=0):
'''program to translate all tiles in raster'''
for i in self.tiles:
i.pos.x=i.pos.x-x_late
i.pos.z=i.pos.z-z_late
print i.pos
Within the class, whenever the class refers to itself it uses self.whatever notation.
The translation function is now called by the line;
tileset.translate( (nx-1)*dx/2.0, 0.0, (nz-1)*dz/2.0 )
You do not need to include the name of the list (tiles) in the translate function because the list is part of the class that is calling the function.
thus the final program now becomes;
from visual import *
from random import uniform
class raster:
'''creates a raster array of tiles
with the top, left tile at position (0,0,0)'''
def __init__(self, nx, nz, dx=1, dz=1):
self.nx = nx #number of columns
self.nz = nz #number of rows
self.dx = dx #x dimension of tiles
self.dz = dz #x dimension of tiles
self.tiles=[]
for i in range(nx):
for j in range(nz):
self.tiles.append(box(length=dx,
width=dz,
height=.5,
color=(uniform(0.5,1),0,0) ))
self.tiles[-1].pos.x=i*dx
self.tiles[-1].pos.z=j*dz
def translate(self, x_late=0, y_late=0, z_late=0):
'''program to translate all tiles in raster'''
for i in self.tiles:
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)
tileset = raster(nx, nz, dx, dz)
#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
tileset.translate( (nx-1)*dx/2.0, 0.0, (nz-1)*dz/2.0 )



