BEGINNING COMPUTER PROGRAMMING Chapter 18: OOP ... goes the computer

You may want to review Chapter 11: The Computer does some Algebra with real numbers ... that introduces the FPU and real numbers ... up to Chapter 15, and especially Chapter 13: The Computer files its Records before you dig into the following. We are about to venture into some very useful stuff that will also help your math insights and skills. Recall that a straight line is the shortest distance between two points. If you were to plot, on some graph paper, two points in Euclidean 2 space, calling them A and B with co-ordinates (x1, y1) and (x2, y2) respectively, then the distance between A and B is given by the formula sqrt( (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) ). This is sometimes abbreviated as sqrt( dX*dX + dY*dY ) … or spelled out in words … the square_root_of ( (the difference in the x’s squared) + (the difference in the y’s squared) ). Our first little program will do just this. We will use real numbers, (HLA type real32’s), for each value of x and y. You may recall that a real number is just a positive or negative or zero decimal number. This includes all fractions, (rational numbers), and all numbers (irrational) like the square root of 2 and PI that never have a repeating pattern to their decimal part … Thus, we always just approximate reals, (i.e. just the irrational reals), to some number of decimal places. You may have seen somewhere that 100.001 can be represented by 1.00001e2. This means the same thing as 1.00001 * 100 which we know is equal to 100.001. The HLA default output for real numbers is in a format like 1.00001e2.

So let’s dig in. Don’t be afraid to make changes and see the output. You can uncomment the line that I commented out … to verify that the output there is what is expected.

Here is a quick Python version, to get you started ...

# distanceAndPoints.py

'''

To find the distance between 2 points, we may

use the fact that the square on the hypotenuse,

of any right angled triangle, is equal to the sum

of the squares on the other two sides ...

See: The hypotenuse of a right triangle

http://en.wikipedia.org/wiki/Hypotenuse

'''

# We can store our points (on the 2-D XY plane) like this ...

class Point:

def __init__(self, x, y): # a constructor

self.x = x

self.y = y

def __str__(self): # so we can print a Point p

return str( (self.x,self.y) )

def length(self):

return ( (self.x)**2 + (self.y)**2 )**0.5

def distance(self, p):

return ( (self.x-p.x)**2 + (self.y-p.y)**2 )**0.5

def direction(self):

import math

a = math.atan2(self.y,self.x)*180/math.pi

if a >= 0:

return a

else:

return a+360

def angle(self, p):

import math

a = (math.atan2(p.y,p.x)-math.atan2(self.y,self.x))*180/math.pi

if a >= 0:

return a

else:

return a+360

def getxy(message):

while 1:

try:

x, y = eval(input('Enter ' + message + ' point x, y : ' ))

return x, y

except:

print('Error! Enter two numbers separated by a comma.')

more = True

while more:

x, y = getxy('1st')

p1 = Point(x, y)

print('p1 =',p1, ':: p1.length() =', p1.length(), ':: p1.direction() =', p1.direction())

x, y = getxy('2nd')

p2 = Point(x, y)

print('p2 =',p2, ':: p2.length() =', p2.length(), ':: p2.direction() =', p2.direction())

print("The distance 'p1.distance(p2)' =", p1.distance(p2))

print("The angle 'p1.angle(p2)' =", p1.angle(p2))

more = ( input('More y/n ? ').upper() != 'N' )

# Just some playing with a 30, 60, 90 deg triangle,

# with sides 1, srqr(3), 2 ... (to check the output

# of atan2 with some known values.)

import math

print(math.atan2(3**0.5, 1)*180/math.pi) # 60 degs with y/x = sqrt(3)/1

print(math.atan2(1, 3**0.5)*180/math.pi) # 30 degs with y/x = 1/sqrt(3)

# Triangles1.py

class Point:

def __init__(self, x, y): # a constructor

self.x = x

self.y = y

def __str__(self): # so we can print a Point p

return str( (self.x,self.y) )

def length(self):

return ( (self.x)**2 + (self.y)**2 )**0.5

def distance(self, p):

return ( (self.x-p.x)**2 + (self.y-p.y)**2 )**0.5

def direction(self):

import math

a = math.atan2(self.y,self.x)*180/math.pi

if a >= 0:

return a

else:

return a+360

def angle(self, p):

import math

a = (math.atan2(p.y,p.x)-math.atan2(self.y,self.x))*180/math.pi

if a >= 0:

return a

else:

return a+360

def vector(self, p):

return Point(p.x-self.x, p.y-self.y)

class Triangle():

def __init__(self, p1, p2, p3 ):

self.p1 = Point(p1.x, p1.y)

self.p2 = Point(p2.x, p2.y)

self.p3 = Point(p3.x, p3.y)

def __str__(self):

return '( ' + str( (self.p1.x,self.p1.y) ) + ', ' \

+ str( (self.p2.x,self.p2.y) ) + ', ' \

+ str( (self.p3.x,self.p3.y) ) + ' )'

def sides(self):

a = self.p1.distance(self.p2)

b = self.p2.distance(self.p3)

c = self.p3.distance(self.p1)

return a, b, c

def perimeter(self):

a, b, c = self.sides()

return a+b+c

def area(self):

a, b, c = self.sides()

s = (a+b+c)/2.0

return (s*(s-a)*(s-b)*(s-c))**0.5

def angles(self):

a = self.p1.vector(self.p2)

b = self.p2.vector(self.p3)

c = self.p3.vector(self.p1)

A = 180 - b.angle(c)

B = 180 - c.angle(a)

C = 180 - a.angle(b)

return A, B, C

def getxy(message):

while 1:

try:

x, y = eval(input('Enter ' + message + ' point x, y : ' ))

return x, y

except:

print('Error! Enter two numbers separated by a comma.')

more = True

while more:

x, y = getxy('1st')

p1 = Point(x, y)

print('p1 =',p1)

x, y = getxy('2nd')

p2 = Point(x, y)

print('p2 =', p2)

x, y = getxy('3rd')

p3 = Point(x, y)

print('p3 =', p3)

va = p1.vector(p2)

da = va.direction()

print('va = p1.vector(p2) =', va, ':: da = va.direction() =', da)

vb = p2.vector(p3)

db = vb.direction()

print('vb = p2.vector(p3) =', vb, ':: db = vb.direction() =', db)

vc = p3.vector(p1)

dc = vc.direction()

print('vc = p3.vector(p1) =', vc, ':: dc = vc.direction() =', dc)

t = Triangle(p1, p2, p3)

print('Triangle t =', t)

print('t.sides() =', t.sides())

print('t.angles() =', t.angles())

print('t.perimeter() =', t.perimeter())

print('t.area() =', t.area())

more = ( input('More y/n ? ').upper() != 'N' )

# Triangles2.py

# Points in 3-D space may be simply stored using a Python 'list 'for a 'container'.

# Each 'list' has 3 elements, (i.e. a 3-D 'vector').

# Here ... a Triangle is simply a list containing 3 lists ... and EACH of these 3 lists

# being ... a list of 3 values ... one value for each x, y, z of each point in 3-space

def distance(v1, v2):

if len(v1) != len(v2):

print('Error! Both vectors passed in must be of equal dimension.')

return

sumOfSquares = 0

for i in range(len(v1)):

sumOfSquares += (v2[i]-v1[i])**2

return sumOfSquares**0.5

def dotProduct(v1, v2):

if len(v1) != len(v2):

print('Error! Both vectors passed in must be of equal dimension.')

return

sumProducts = 0

for i in range(len(v1)):

sumProducts += v2[i]*v1[i]

return sumProducts

def length(v):

return dotProduct(v, v)**0.5

def angle(v1, v2):

import math

a = length(v1)

b = length(v2)

dotP = dotProduct(v1, v2)

if (a*b)==0: # let zero vector have angle 0

return 0

if dotP/( a*b ) >=1 or dotP/(a*b) <=-1 : # allow for rounding errors

return 0

return 180/math.pi * math.acos(dotP/(a*b))

def vector(v1, v2):

if len(v1) != len(v2):

print('Error! Both vectors passed in must be of equal dimension.')

return

v =[]

for i in range(len(v1)):

v.append(v2[i]-v1[i])

return v

def sides(t):

s = []

for i in range(len(t)):

s.append(distance(t[i],t[(i+1) % len(t)]))

return s

def area(t):

a, b, c = sides(t)

s = (a+b+c)/2.0

if s-a <= 0 or s-b <=0 or s-c <= 0:

return 0;

return (s*(s-a)*(s-b)*(s-c))**0.5

def perimeter(t):

if not area(t):

return 0

d=0

for each_d in sides(t):

d += each_d

return d

def vectors(t):

s = []

for i in range(len(t)):

s.append(vector(t[i], t[((i+1)%len(t))]))

return s

def angles(t):

v = vectors(t)

angs = []

if not area(t):

for i in range(len(t)):

angs.append( 0 )

return angs

for i in range(len(v)):

angs.append(180 - angle( v[((i+1)%len(v))], v[((i+2)%len(v))]))

return angs

def angles2(t):

if not area(t):

return 0,0,0

a,b,c = sides(t)

import math

A = 180/math.pi*math.acos((b*b+c*c-a*a)/(2*b*c));

B = 180/math.pi*math.acos((c*c+a*a-b*b)/(2*c*a));

C = 180/math.pi*math.acos((a*a+b*b-c*c)/(2*a*b));

#C = 180-A-B;

return A,B,C

def getxyz(message):

while 1:

try:

x, y, z = eval(input('Enter ' + message + ' point x, y, z : ' ))

return x, y, z

except:

print('Error! Enter three numbers separated by commas.')

more = True

while more:

x, y, z = getxyz('1st')

p1 = [x, y, z] # create 1st point

print('p1 =', p1)

x, y, z = getxyz('2nd')

p2 = [x, y, z] # create 2nd point

print('p2 =', p2)

x, y, z = getxyz('3rd')

p3 = [x, y, z] # create 3rd point

print('p3 =', p3)

print()

a = vector(p1, p2)

print('a = p1->p2 =', a)

b = vector(p2, p3)

print('b = p2->p3 =', b)

c = vector(p3, p1)

print('c = p3->p1 =', c)

print()

print('distance(p1, p2) =', distance(p1, p2))

print('dotProduct(p1, p2) =', dotProduct(p1, p2))

print('length(p1)*length(p2) =', length(p1)*length(p2))

print('angle(p1, p2) =', angle(p1, p2))

print('C = interior angle(a, b) =', 180 - angle(a, b))

print()

print('distance(p2, p3) =', distance(p2, p3))

print('dotProduct(p2, p3) =', dotProduct(p2, p3))

print('length(p2)*length(p3) =', length(p2)*length(p3))

print('angle(p2, p3) =', angle(p2, p3))

print('A = interior angle(b, c) =', 180 - angle(b, c))

print()

print('distance(p3, p1) =', distance(p3, p1))

print('dotProduct(p3, p1) =', dotProduct(p3, p1))

print('length(p3)*length(p1) =', length(p3)*length(p1))

print('angle(p3, p1) =', angle(p3, p1))

print('B = interior angle(c, a) =', 180 - angle(c, a))

print()

t = [p1, p2, p3] # create triangle, a list of lists ...

print('The triangle t is', t)

print('with area(t) =', area(t))

print('and perimeter(t) =', perimeter(t))

print('The sides(t) a, b, c are', sides(t))

print('The direction vectors(t) of sides a, b, c are', vectors(t))

print('The zero corrected interior angles(t) A, B, C are', angles(t))

print('The zero corrected confirm angles2(t) A, B, C are', angles2(t))

more = ( input('More y/n ? ').upper() != 'N' )

If you entered 2, 3 and 0, 0 or the other way around ... either way you should have the answer ...

The distance is: 3.60555127546

If you entered 0, 0 and 3, -4 or the other way around ... either way you should have the answer ...

The distance is: 5.0

So what does this have to do with OOP? Well, we have just defined an OBJECT, a point ... and described one property of points ... they have a distance between them. With Objected Oriented Programming, we will keep together, i.e. encapsulate, all the data and all the functions that relate to some object.

Another way that we can think of a point object is ... as a vector. We can imagine the vector, for now, as having its tail at the origin, i.e. at (0, 0) ... and its head at the point (x, y). A vector object can also be described by an unique length and an unique direction angle (in the range 0..365.999999999999... degrees) from some line, say the x-axis, (or, -179.9999999999999... to +180 degrees.)

If we have some point or vector then, represented by (x, y) ... we can think of it

* as the 2 real numbers of the co-ordinates x and y ...

OR ...

* as a vector with length = sqrt( x*x + y*y ) and direction angle theta = arctan( y/x ).

NOTE! Either way, TWO unique real numbers are sufficient to describe this OBJECT! ( i.e a 2-Dimensional vector - has just TWO DIMENSIONS! )

For this example, we will choose the two real numbers that uniquely describe our point, the head of the vector. And we will also associate functions with this encapsulation of information, concerning this point/vector object ... i.e.procedures and methods that readily let us calculate / access or get and report this info ... or that set / reset / change / manipulate the numbers that are the data (point) of this object. To encapsulate all this ... we (will eventually) use a CLASS and give that class a class name. And all members of that class will use that class name ... similar to what we did with the data inside a record. Recall that we accessed parts of a record with the dot operator. ... We will likewise use this same dot operator to get to the members of the Class Object ... whether they be data ... or functions that act on that data.

You may not have heard yet ... that the tangent or tan of some angle is just the rise over the run in the right angled triangle described by the points (0, 0), (x, 0), and ( x, y) ... In this case ... y/x.

And if we know x and y, we can calculate y/x = tan( theta ). Theta is the angle measured cc (counterclockwise) from the x-axis to the point ( x, y).

Once we know the value of tan( theta ) ... we can look up that value, on a graph or in tables, or use the inverse tan of that value, (same thing as arctan), to find theta.

We will get the FPU unit to do our conversions for us. If we feed into the FPU function fpatan() ... y and x ... the function will find y/x and then the inverse tan (i.e. the arctan) of the fraction ... i.e. fpatan() outputs theta if we input y and then x ... IT IS IN RADIANS so we will multiply by 360/( 2*pi ) to convert to degrees, where the degrees are counted cc from the positive X-axis. (Recall that in one complete revolution of 360 degrees there are 2pi radians. And ... for a circle with radius1, the circumference is 2*r*pi = 2*1*pi = 2*pi ).

See below for the rest of program vectors2;

fld( y ); // now have y in st0

fld( x ); // now have x in st0, and y in st1

fpatan(); // take arctan(st1/st0) and store in st1; pop stack

fmulp( radTodeg ); // convert to degrees ... declared as: radTodeg: real32:= 360 / ( 2 * 3.14159 );

So here ... where we know y, the rise ... and x, the run ... then the rise/run = y/x = tan( theta ). Thus we find the direction angle for our vector by plugging this into the formula ... theta = arctan( y/x )

But if we instead knew the direction angle theta and the length of some vector ... we could then find the unique(x, y) that represents the head of that vector, if we place its tail at the origin. (We would use x = lengthOfVector * cos( theta ) and y = lengthOfVector* sin( theta ); Note that sin(theta)/cos(theta) = tan(theta) = y/x for all theta.)

For further quick reference see:

http://answermath.com/sin.htm http://mathworld.wolfram.com/x-Axis.htmlhttp://www.physics.uoguelph.ca/tutorials/vectors/vectors.html...

To continue click on the

*2* in this line

*Pages: [1] 2 Go Up* in the lower LEFT corner of the screen ...