Classes

From GeoMod

Jump to: navigation, search

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)

which produces Image:tiles.png

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)

which displays Image:tiles_classes-2.png

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 )
Personal tools