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 ...