---------------------------------------------------------
The Liberty Basic Newsletter - Issue #96 - MAY 2002
    2002, http://groups.yahoo.com/group/lbnews/
             All Rights Reserved
---------------------------------------------------------
"You've got to be very careful if you don't know where 
you're going, because you might not get there."
     ---Yogi Berra
---------------------------------------------------------
In this issue:
	- Introducing the Team!
	- Data Validation and Error Trapping
		(debugging code BEFORE you run it!)
	- Tipcorner - binary file access
	- Updating the Open Source Editor
		(changing the runtime icon)
	- Spotlight on Polar Coordinates
		tutorial by Tom Nally
		polar1.bas by Nally
		atari2.bas by Nally
		polar coordinate demo by Guy Canida
	- Submissions
---------------------------------------------------------
---------------------------------------------------------
INTRODUCING THE TEAM!

		WELCOME TO THE TEAM!
			BRAD MOORE
			TOM NALLY

Look for Tom's first article in this issue.  Brad will
be publishing newsletter #97.  Thanks to you both!

The lbnews group is owned by Carl Gundel, to assure
smooth transitions between publishers.  Please direct any
complaints about the current publishers to Carl:

	Carl Gundel: carlg@libertybasic.com

The group is also moderated by Alyce, Brad and Tom.  We
three also take turns writing, editing and publishing
the newsletters.  Send comments to the group, and send
complaints and article submissions to any of us:

	Alyce Watson: alycewatson@charter.net
	Brad Moore: brad.moore@weyerhaeuser.com
	Tom Nally:  SteelWeaver52@aol.com

The newsletters are all contained in the files section
at the lbnews web page.  They are easily navigated because
of the terrific index and table of contents contributed by
Bill Jennings!  He updates it each month, and he is also
a moderator of lbnews.  If you have a comment about the
index or contents lists, contact Bill:

	Bill Jennings: bbjen@bigfoot.com

---------------------------------------------------------
---------------------------------------------------------
DATA VALIDATION AND ERROR TRAPPING
(debugging code BEFORE you run it!)

Have another look at the quote by Yogi Berra:

"You've got to be very careful if you don't know where 
you're going, because you might not get there."

If you want to write computer programs, you need to know
where they are going!  You must have a clear idea of what
you want your program to do.  With that idea firmly in
mind, you can debug your programs AS YOU WRITE THEM, before
you've even given them a sample run!

Proactive debugging requires data validation and error
trapping.  This just means that you must insure that data
used by the program will actually work, and is the kind of
data required by your program, and is in the proper range.


DIVIDE BY ZERO?
A common error that crashes programs is an attempt to divide
by zero.  The answer, if the computer could give us one, is
infinity!  But the computer cannot do that, and so it is an
impossible calculation.  An attempt to divide by zero will
cause the program to halt with an error.  You might find 
yourself dividing data to compute an average, for instance, 
or to organize records, figure a score, etc.  

Here is a tiny program that asks the user for two numbers, 
then it attempts to divide the first number by the second 
number.

If the user entered 0 for the second number, and the program
didn't trap that possibility, then it would halt with an
error.  It was quite simple to test for a value of 0, and
to avoid trying the division if it was equal to 0.

'snip 
'trapping divide by zero error:
input "Type first number  ";number1
input "Type second number  ";number2

if number2=0 then
    print "Cannot divide by zero!"
    end
else
    print "The result of dividing is ";
    print number1/number2
    end
end if
'end snip


VALID NUMBERS?
There are other reasons to validate numeric data.  You might
ask a user for his age, and he might answer "eighteen".  Hmm.
Your program would see that as "0", and this could cause some
serious problems!  Here is a trivial example that checks for a
valid age input from a user.  It requests further input from
the user if a valid age isn't entered.

[again]
input "Age?";age

if age=0 or age > 110 then
    print "Please try again!"
    goto [again]
end if

print "Your age is ";age


You could also assign a default value in the event that a
piece of data is outside of the acceptable range.  Here is
another trivial example.  This one sets a value for age
if it finds an invalid value.

input "Age?";age

if age=0 then age=10
if age>110 then age=90
print "Your age is ";age


Have you spotted the flaw in the above samples?  Sometimes,
you have to put on your thinking cap to imagine the ways
that a program can go wrong.  What if the user enters a
NEGATIVE number?  Let's fix that, too:

input "Age?";age

if age<10 then age=10
if age>110 then age=90
print "Your age is ";age  

Now, if any age less than 10 is entered, age is set to a
default of 10.  If a user entered -345, age would be set
to a valid number of 10.  Of course, your program might
need to handle this eventuality differently than the little
samples here.  The point is to find the flaws so that your
program can fix them and prevent corrupted data and even
program crashes.


Okay, now that we've established some ways to check for valid
numeric input, we'll think about valid text input.  The easiest 
check is for any input at all.  In this little demo, the user
is asked for his name:

input "Name?";name$

if name$="" then
    print "You didn't enter a name!"
else
    print "Hello, ";name$
end if


What if we need to get specific text input from a user?  The
following demo asks the user to choose red or blue.  Have
a look:

input "Red or blue?";color$

select case color$

case "Red"
print "You chose red!"

case "Blue"
print "You chose blue!"

case else
print "You didn't choose a valid color!"

end select


VALID TEXT?
What happens if the user types "red", or "RED"?  The
program prints "You didn't choose a valid color!"
This is another trivial example, but you might have a program
that relies upon accurate text data.  To check for accuracy
regardless of case, use UPPER$() or LOWER$() to evaluate
the text.  In the following modification of the color input
demo, the user's answer is changed to lowercase so that it
can be evaluated.  Now, he can enter "red", "RED", "rEd" or any
other variation and the program will know that he choose
the color red.

input "Red or blue?";color$

color$=lower$(color$)

select case color$

case "red"
print "You chose red!"

case "blue"
print "You chose blue!"

case else
print "You didn't choose a valid color!"

end select


FILE EXIST?
Another proactive debugging technique requires checking for
a file's existence before attempting to open it or use it.
If you try to load a bitmap file that doesn't exist, the 
program will halt with an error.  Imagine that you have included
some bmpbutton images in your distribution, and your user
gets curious or careless and renames or deletes some of these
files.  When the program hits the LOADBMP or BMPBUTTON
command, it will halt with an error.  

If a program attempts to open a disk file for input and it 
doesn't exist, again the program will halt with an error.

If a program attempts to rename a file and the new filename
is that of an existing file, the program will halt with an
error.  For instance:

name "c:\test.txt" as "c:\hello.txt"

If "c:\hello.txt" is the name of an existing file, then the
program will halt with an error.

It is easy to test for a file's existence, and this is explained 
in detail in newsletter #95, so please check there!

INDEX OUT OF BOUNDS?
If you try to access an array element that is larger than the
dimension of the array, you'll get an index out of bounds error.
To avoid this error, be sure to DIM your arrays to be large enough!
If you have no idea at design time how many elements an array will 
need to contain, then find a way to check the data to get a number, 
then DIM or REDIM the array to be just a bit larger than that number.
Just remember that REDIMming an array will erase the previous
contents, so it will need to be filled again.

Here's an example that reads data from an ini file into an array.
It first read in data simply to count the number of items.  It
then DIMS and array to the needed size.  The second time through,
it reads the items into the array.

open "lbasic3.ini" for input as #f

while NOT(EOF(#f))  'while end of file not reached
input #f, item$
i=i+1               'increment counter
wend

close #f

DIM ar$(i+2)        'DIM array large enough to hold data
i=0                 'reset counter

open "lbasic3.ini" for input as #f
while NOT(EOF(#f))
input #f, ar$(i)    'input data to array
i=i+1
wend

close #f

for j=1 to i
print ar$(j)       'print it out so we can check it
next
end

API ERROR?
Most API function calls have a return value.  Sometimes
the return value has meaning.  It may be that a return
of nonzero equal success.  It may be that a return of
zero equals success!  The return may also be a value that
will be used by your program.  Whatever the return is,
it is always a good idea to check its validity before
attempting to continue.  If the return shows an error,
then your program should trap it, as in this immitation
sample:

calldll #mydll, "DoAFunction",arg as long, result as long
if result<>0 then
    notice "Error!  Please try again!"
    wait
end if

FILES, WINDOWS, DLLS NOT CLOSED?
If a program exits without closing all windows, files and DLLS
that it has opened, then the program may continue to reside in
memory, causing problems, and perhaps a computer crash.  You may
also see the program itself crash.  To be assured that this doesn't
happen, be sure to issue a trapclose command that references a 
branch label where all files, windows and DLLS are closed before
an END statement is issued.  Don't forget to end all programs with an
END statement!  Remember, you MAY have a menu item, button, etc. that
allows the user to close the program, and that goes to the [quit]
branch label, but the user might close the program using the system
menu, the X in the corner of the titlebar, or by hitting ALT-F4.
Those are the "closes" that you'll need to trap with a
trapclose command.  Example:

nomainwin
open "A Window" for window as #1
print #1, "trapclose [quit]"
wait

[quit]
close #1:end

---------------------------------------------------------
---------------------------------------------------------
TIPCORNER - BINARY FILE ACCESS

Liberty BASIC 3 provides a binary access mode.  Binary mode
means manipulating the bytes in a file.  The bits and 
bytes must be manipulated and written to the file or read from 
the file as characters.  There are 8 bits in a byte, and a byte 
is written to the file as a character... chr$(n).  Use the SEEK 
command to seek to the desired point in the file for reading or 
writing.  Use the LOC(#handle) function to get the current 
position.  This mode never writes line delimiters when printing 
to the file.  

Sequential files must be written in their entirety.  Random
files may write single records within a file, but they are limited
to writing at record boundaries and they may only write an entire
record.  Binary mode allows us to open a file, seek to the desired
location anywhere in the file, then write data of any desired length
to replace the existing data at that location in the file.

Here's the way to open a file for binary access:

open "myfile.ext" for binary as #handle

Here is the way to set the file pointer to the desired
position in the file:

fpos=1024
seek #handle, fpos

or

seek #handle, 1024

'get the current file position
fpos = loc(#handle)

'write a byte to the file 
print #handle, chr$(143)

'mock example
open "myfile.bin" for binary as #myfile
seek #myfile, 1024
print #myfile, "write this into the file"
notice str$(loc(#myfile) - 1024); " bytes written"
close #myfile
end

We can use binary file access to replace the torch icon
in the runtime engine with another 16-color icon of our
own choice.  See the next section for binary access
in action.

---------------------------------------------------------
---------------------------------------------------------
UPDATING THE OPEN SOURCE EDITOR
	CHANGING THE RUNTIME ICON

[runtimeIcon]
    filedialog "Choose Icon","*.ico",icoFile$
    if icoFile$="" then wait

    shortFile$=SeparateFile$(icoFile$)
    filePath$=SeparatePath$(icoFile$)
    files filePath$,shortFile$, info$()

    'check file size - must be 766 for 16-color icon:
    if info$(1,1) <> "766" then
        notice "Not a 16-color icon!"
        wait
    end if

    filedialog "Choose runtime engine","*.exe",runexe$
    if runexe$="" then wait

    'open icon file and read into a string variable:
    open icoFile$ for input as #iconfile
    saveicon$=input$(#iconfile, lof(#iconfile))
    close #iconfile

    'open the runtime engine, seek to the proper
    'location, and write the icon info at that spot:
    open runexe$ for binary as #bin
    seek #bin, 21664
    print #bin, right$(saveicon$,744)
    close #bin
    notice "Icon has been included in ";runexe$
    wait

---------------------------------------------------------
---------------------------------------------------------
SPOTLIGHT ON POLAR COORDINATES
tutorial by Tom Nally
SteelWeaver52@aol.com
Thanks for a great article, Tom and welcome to the team!

UNDERSTANDING AND PLOTTING POLAR COORDINATES
By Nally

I suspect that I was daydreaming in math class the first time polar 
coordinates were discussed in my presence.  And I'm darned if I can 
remember whether that was junior high school, high school or college.  
Suffice it say that my discussion of polar coordinates herein will 
probably not resemble what students are typically taught in school.  
Instead, I will share my own understanding of the polar coordinate 
system, and how one might draw polar graphs in LB programs.

If any of this information resembles what we are taught in school, 
consider that purely coincidental.

Basically, here are the six questions that I will discuss:

A. What are polar coordinates?
B. What units are used in polar coordinates?
C. How does a programmer convert from polar to Cartesian coordinates?
D. How does a programmer convert from Cartesian to polar coordinates?
E. How does one plot polar coordinate points in an LB GraphicBox?; and
F. How are polar coordinates useful in the real world?

            

A. WHAT ARE POLAR COORDINATES?

The polar coordinate system is a way to determine the location of a point 
on a plane given a known point and a known reference line.  We might refer 
to the known point as the "pole", the "origin" or the "center of the circle".  
(In this discussion, I will call it the "origin".)  The known reference line 
is any line that passes through the origin that we are willing to assign an 
angle of zero.  Typically, if we are drawing a polar coordinate system on a 
sheet of paper, the reference line is a vector which starts at the origin, 
and goes to the right.  If this sheet of paper happens to be a map with North 
at the top, then the reference line would start at a known point, then head 
in a cardinal direction, such as due East or due North.

Any point, Q, on a polar coordinate plane can be located by finding it's 
angular distance from the reference line, and its linear (or "radial")
 distance from the origin.  What is the angular distance to point Q?  
Well, imagine yourself standing at the origin of our polar coordinate 
system with your right arm pointed along our reference line.  Then, 
sweep your arm in a counterclockwide direction until you are now 
pointing at point Q.  The angle through which your arm swept is the 
angular distance to point Q.  This value is also called the "angular 
coordinate of Q", and we often name this angle by giving it a greek 
letter, such as phi or theta.  Herein, we will call the angular coordinate 
of a point "phi".

The radial distance to point Q is the straight-line distance that you would 
have to walk at the angle "phi" in order to arrive at point Q.  
This distance is often called the "radial coordinate of Q".  This 
coordinate is often given the name "R".

So, in a polar coordinate system, any point Q can be defined by its polar 
coordinates, phi and R.  A common notation used to define Q by use of Q's 
polar coordinates looks like this:

Q(phi, R)

The polar coordinate system can be compared to the "cartesian coordinate 
system", which is a system with which most programmers have some familiarity.   
The cartesian system also uses two values to define the location of a 
point--point Q, again--on a plane.  One of these values is Q's offset 
from the Y axis, which is known as Q's "x coordinate" because it represents 
Q's distance from the origin along a line which is parallel to the X axis.  
The second value is Q's offset from the X axis, which is known as Q's 
"y coordinate" because it represents Q's distance from the origin along 
a line parallel to the Y axis.  In the cartesian system, the notation 
used to define Q by reference to it's cartesian coordinates looks like this:

Q(x, y)

To help us understand these systems a little further, I will provide my 
robot, Bob, instructions for finding the stump in my back yard using each 
of these two systems.  First, the polar coordinate system.

I will choose my back porch as the origin of my polar system.  My arbitrary 
reference line will be a vector which begins at my porch, and goes directly 
through my bird bath, which is due East of my porch.

Bob, here are my instructions for finding the stump in my backyard:

(1) Bob, stand at the origin, my porch, and face the bird bath.
(2) Bob, rotate your robot frame 36.87 degrees counterclockwise.
(3) Bob, along your new heading, motor outward a distance of exactly 50 feet.  
You are now at the stump.

Bob just found the stump by virtue of his ability to follow instructions given 
in a polar coordinate frame of reference.  Let's put Bob to work again, but 
use a cartesion system this time.

Once more, I will choose my back porch for the origin of this system.  For the 
X axis, I will choose the vector that begins at the origin and passes through 
my bird bath, which is due East of the porch.  The Y axis of my system is a 
vector that begins at my porch, and is located on a line which is 90 degrees 
counterclockwise from my X-axis.

Bob, here are my new instructions for finding the stump in my backyard:

(1) Bob, stand at the origin, and motor along the X axis a distance of 
exactly 40 feet.
(2) Bob, rotate your robot frame counterclockwise so that you now have a 
heading which is parallel to the Y axis.
(3) Bob, motor along this new heading exactly 30 feet.  You are now at 
the stump.

Bob has now successfully navigated to the stump twice after being given 
instructions using both coordinate systems.

Bob, take a bow.  (But don't get cocky.)

            

B. WHAT UNITS ARE USED IN POLAR COORDINATES?

Above, we stated that a polar coordinate consists of a pair of values.  
One value is an angle (called "phi" in this article), while the second 
value is a distance from the origin (refered to as "R" herein).

There is really no convention for the distance units to use when describing R.  
It could be milimeters, meters, inches, feet, furlongs or miles.  It could even 
be astronomical units or parsecs if we are using a polar coordinate system to 
discuss objects in space.  Since any reader of this article may at some point 
use polar coordinates to plot data in LB, the R unit for that programming 
endeavor will probably be, well, pixels.  In other words, the problem you 
are solving will define what units to use for the R value.

With regard to the angular unit, I typically start my solution to the problem 
by thinking about phi in terms of degrees.  This is simply because degrees 
are so familiar to most of us.

If I use a computing language to solve my problem, however, at some point 
I will probably need to convert any degree measurements into an alternate 
measure of angular distance called "radians".  This is because trig functions 
which need an angle as an argument will want to see that angle expressed in 
radians.  Likewise, those trig functions that "output" an angle
--such as ATN()--will return an angle expressed in radians.

So, just what is a "radian"?

To understand radians, let's conduct this "thought exercise".  On a sheet 
of paper, use a compass to draw a circle.  Make the radius any size you want.  
In this thought exercise, it doesn't matter how big the circle is, as long as 
it fits on the paper.   Now, cut seven pieces of string whose length is exactly 
the same length as the radius of the circle.  We are going to use these pieces 
of string as instruments of measure.  In fact, we will call them "radians" because 
the length of each piece corresponds exactly to the length of the radius of the circle.

Next, let's attempt to measure the length of the circumference of the circle by 
snuggly wrapping these radians end to end around the circumference of the circle.  

Of course, we couldn't really wrap these strings "snuggly" around the circumference 
of a circle on a flat sheet of paper.  That's why this is a "thought exercise" rather 
than a real exercise.  But if we could do that, we would find that it takes exactly 
2*pi (or 6.2832) radians to wrap exactly one time around the circumference of the circle.  
In other words, the 360 degree arc of the circle corresponds exactly to 2*pi radians.  
This will be true regardless of the radius of the circle.

Next in our thought exercise, we want to find out what portion of a radian corresponds 
to a 30 degree arc when pulled snuggly along the circumference of the circle. 

To accomplish this, we need to draw a reference line on our circle, then draw an angle 
which is 30 degrees to our reference line.  Next, we hold one end of our radian where 
the reference line intersects the circumference of the circle, and pull it snuggly 
around the circle's circumference until it wraps past the 30 degree line.  If we were 
able to do this accurately, we would find out that it takes exactly 0.5236 radians to 
wrap along an arc corresponding to 30 degrees.  Again, this will be true regardless 
of the radius of the circle.

If we repeated this exercise for any number of angles, we would observe that each unique 
angle sweeps out a unique length of arc at the circumference of the circle, and that 
this arc length can be expressed in terms of radians.  It follows, then, that any angle 
itself can be expressed in terms of radians.  This is how radians serve as a substitue 
for the degree measure of an angle.

Fortunately, we don't need to cut a piece of string every time we want to find the 
radian measure of an angle, provided that we already know the degree measure of the 
angle.  Recall that we have already established that 360 degrees corresponds exactly 
with 2*pi or 6.2832 radians.  Therefore, 1 degree corresponds to 6.2832/360, or 
0.01745 radians.  Here is a conversion example: a 27 degree angle would be identical 
to 27*0.01745 or 0.4712 radians.  

Since 0.01745 is a conversion factor that's pretty hard to remember, when I convert 
from degrees to radians, I typically just multiply the degree measure by 2*pi, then 
divide by 360 to get radians.  Works every time:  
27 degrees = (27/360) * (2 * pi) radians.

            

C.  HOW DOES A PROGRAMMER CONVERT FROM POLAR TO CARTESION COORDINATES?

I am happy to report that it will only take me a few words to describe how polar 
coordinates can be converted to cartesian coordinates.  First, recall that the 
notation for a polar coordinate pair looks like this:

Q(phi, R)

To convert this polar coordinate to a cartesian coordinate requires two operations.  
One operation finds the X coordinate in the cartesian system:

X = R * cos(phi)

The second operation finds the Y coordinate of the cartesian system:

Y = R * sin(phi)

Not too hard, that.

            

D.  HOW DOES A PROGRAMMER CONVERT FROM CARTESIAN TO POLAR COORDINATES?

Converting from cartesian coordinates to polar coordinates is not quite as simple.  
The easy part is finding "R" which is simply accomplished by using the Pythagorean 
Theorem, also called the "distance formula":

R = sqrt(x^2 + y^2)

Given only x and y, finding phi is a little more difficult.  The ATN() function 
is useful but not sufficient.  ATN() only returns radian values from -pi/2 
through +pi/2, which corresponds to -90 through 90 degrees.  

Here's an example which will illustrate the problem.  If x = -1 and y = -1, 
then y/x =1, and the ATN(y/x) = pi/4 or 45 degrees.  This is a problematic 
answer because we know that the cartesian coordinate pair Q(-1,-1) actually 
corresponds to an angle of 5*pi/4 or 225 degrees.  

The difficulty is caused by the fact that ATN() only takes a single argument.  
If the argument is positive, then ATN() returns a value between 0 and pi/2 
(0 and 90 degrees).  If the argument is negative, then ATN returns a value 
between -pi/2 and 0 (-90 and 0 degrees).  Therefore, ATN() gives 
disproportionate attention to those angles in only half of the circle, 
while blatantly ignoring the feelings of those angles in the other half 
where low self-esteem, sadly, is a chronic problem.

Some languages (MS Excel comes to mind) get around this problem by offering 
a more comprehensive arctangent function called ATAN2().  ATAN2() takes two 
arguemtns, x and y, which is sufficient information to return the correct 
value for phi.  ATAN2() would be used like this in a program:

X = 25
Y = -60
phi = ATAN2(X, Y)

In the companion file, ATAN2.bas, I provide a custom ATAN2() function written 
for Liberty Basic.  It takes x and y as arguments, and will return phi in 
radians.  In this function, x or y (or both) must be non-zero.  If both x 
and y are zero, then ATAN2() should not be called, because the point in 
question exists at the origin of the system where phi is meaningless.  

Here's an exercise for the ambitious: write an ATAN2$() function which returns 
the string value of phi if Q is not at the origin, but returns "Q is at the 
origin" if Q is at the origin.  The usefulness of this function is that there 
would be no restrictions on the arguments.

            

E.  HOW DOES ONE PLOT POLAR COORDINATE POINTS IN AN LB GRAPHICBOX?

I find polar systems fun primarily because some trig functions plotted within 
polar systems produce interesting curves.  (Play with the LB program "PolarPhun" 
to see a few of 'em.)  So, how is the plotting of polar data accomplished?  
Plotting polar data is identical to plotting cartesian data, except that at some 
point during the routine, the data must be converted from polar coordinates to 
cartesian coordinates.  

Here are the five steps that I go through, followed by a discussion of each step.  
In a second companion program  to this article, Polar1.bas, I provide source code 
which implements these steps.

1. Generate the polar data by defining an equation using trig functions, then  
generating a series of polar coordinate pairs within a For/Next loop.
2. Convert the polar data into cartesian data within another For/Next loop.
3. Scale the data up or down by multiplying the x and y cartesian values by a 
scalefactor, so that the data will plot nicely.
4. "Shift" or "offset" the data points so that they print about the center pixel 
of the GRAPHICBOX.
5. Plot the data within the GRAPHICBOX.


1. The first step in generating the data is defining an equation containing one or 
more trig functions.  A simple function with which to start might look like this:

R = 2.5 + 2*sin(12*phi)

This function will plot a daisy-like graph with 12 petals.

In general, I prefer to use only the sin() and cos() trig functions in my polar 
equations, 
while excluding the tan() function.  One reason for this is that the sin() and cos() 
functions will always return a value between -1 and 1.  That enables the programmer 
to control the magnitude of R.  In the equation shown just above, R will never be 
greater than 4.5 (which occurs when sin(12*phi) = 1), nor will it ever be less than 
0.5 (which occurs when sin(12*phi) = -1).  On the other hand, the tan() function 
will return a value between minus infinity and plus infinity.  This not only makes 
graphing the output more difficult, but it also risks a program crash due to an 
overflow error.  For example, the tangent of pi/2 is infinity.

A simple programming routine to generate a set of polar data pairs may look 
like this:

DIM R(360)
DIM x(360)
DIM y(360)
DIM xscaled(360)
DIM yscaled(360)
DIM xplot(360)
DIM yplot(360)
pi = 3.14159

for degree = 0 to 360
    phi = (degree/360) *(2*pi)
    R(degree) = 2.5 + 2*sin(12*phi)
next degree


2. Converting polar coordinate pairs to cartesian coordinate pairs is accomplished 
exactly as described in section C above.  The source code for that operation might 
look like this:

for degree = 0 to 360
     phi = (degree/360) * (2*pi)
     x(degree) = R(degree) * cos(phi)
     y(degree) = R(degree) * sin(phi)
next degree

When this loop has concluded, we will have a set of 361 cartesian coordinate pairs 
that have been converted from polar coordinate pairs.

3. As indicated above, R in this equation will always occur within a range of 
0.5 to 4.5.  If you examine the x and y values coming out of the loop just above, 
you will observe that x and y will always occur within a range of -4.5 to +4.5.  
Note that if we plotted our data without scaling it first, all the points would 
plot within a small, tight box which will be 9 pixels high by 9 pixels wide.  
That's a pretty small box to hold 360 data points.  Certainly, the plotted data 
would have more meaning for us if we could scale it up so that all the plotted 
points were discernable.  But how large should we scale it?

Say that we are plotting to a Graphicbox that is 200 pixes wide by 200 pixels high.  
If we want to make full use of the real estate provided by this Graphicbox, it might 
be nice to plot data to within 10 pixels of the border of the graphic box.  Therefore, 
any scaled value for x and y should be no larger than 90, nor smaller than -90.  Why 
these two values?  Because we are going to place our origin at the center of the 
Graphicbox, which is the pixel with the coordinates (x=100, y=100).  Therefore, the 
largest plotted x value will be no greater than 100 + 90 = 190, and the smallest 
plotted x value will be no less than 100 - 90 = 10.  The same goes for the plotted 
y values.  

To review, the largest x value as it comes out of the function will be 4.5, but the 
largest x value after scaling will be 90.  So, the scale factor that must be applied 
to all x and y values is 20.

Whatever the scale factor happens to be, we don't want to calculate it "by hand", we 
want the computer to calculate the scale factor.  To do that, we have to find the most 
extreme value of all x and y, whether that value be positive or negative.  Here's one 
way to do that:


xmax = 0
xmin = 0
ymax = 0
ymin = 0

for degree = 0 to 360
    if (x(degree) > xmax) then xmax = x(degree)
    if (x(degree) < xmin) then xmin = x(degree)
    if (y(degree) > ymax) then ymax = y(degree)
    if (y(degree) < ymin) then ymin = y(degree)
next degree

At this point, we've determined the largest and smallest of all x and y.  Now 
we have to find the value which is largest in magnitude.  The value which is 
largest in magnitude will be stored in a variable called BiggestXY.  The 
coding below will take care of that task:

BiggestXY = 0
If (abs(xmax) > BiggestXY) then BiggestXY = abs(xmax)
If (abs(xmin) > BiggestXY) then BiggestXY = abs(xmin)
If (abs(ymax) > BiggestXY) then BiggestXY = abs(ymax)
If (abs(ymin) > BiggestXY) then BiggestXY = abs(ymin)


Of the 361 pairs of (x, y) values, we've now found the most extreme value of 
all of them, and we've placed it in a variable called BiggestXY.  Now, we can 
establish the scalefactor which, when multiplied against BiggestXY, will yield 
a value of 90.

Scalefactor = 90 / BiggestXY

At this time, we can multiply all of x() and y() by the scalefactor.  This will 
produce a dataset with magnitudes that will use most of the real estate of the 
Graphicbox.

for degree = 0 to 360
    xscaled(degree) = Scalefactor * x(degree)
    yscaled(degree) = Scalefactor * y(degree)
next degree


4. We are getting closer to plotting our data, but we are not quite 
there yet.  First, realize that our Graphicbox has a natural origin 
defined by it's own coordinate (x = 0, y = 0).  This Graphicbox 
coordinate exists in the upper left hand corner of the Graphicbox.  
If we plotted all values of Q(xscaled(), yscaled()) about the natural 
origin of the Graphicbox, then we would only see the lower right 
quadrant of the data set.  Any point Q whose xscaled() or yscaled() 
value is less than zero will not appear within the Graphicbox.

To correct for this, we need to plot the data not around the Graphicbox's 
natural origin, but around the Graphicbox's geometric center.  We might 
think of this operation as shifting all the data points to the geometric center.  
As indicated above, the center of this Graphicbox is located at (x = 100, y = 100).

To enable this data shift, simply add 100 to all of the xscaled() values and 
100 to all of the yscaled() values:

For degree = 0 to 360
	xplot(degree) = 100 + xscaled(degree)
	yplot(degree) = 100 + yscaled(degree)
next degree

This would be a good time to consider another issue related to plotting data 
on computer screens.  This issue is the direction of the Y axis.  When we plot 
data in school, we usually draw the Y axis pointing upward in our notebooks.  
In most computer languages, however, y values increase in a downward direction.  
If we want positive y values to be plotted upward of the Graphicbox's geometric 
center, then we need to "reverse" the direction of y.  To accomplish this, the 
four lines of code shown above can be replaced by these:

for degree = 0 to 360
    xplot(degree) = 100 + xscaled(degree)
    yplot(degree) = 100 - yscaled(degree)
next degree


5. So far, we've generated our polar data; we've converted it to cartesian 
coordinates; we've scaled it up (or down); and we've shifted it to the geometric 
center of the graphic box.  Now, we want to create a routine which actually plots the data.

We learned in geometry that a "point" represents a location in space, but otherwise 
has no extents.  That is, we can talk about "where" a point is, but not "how big" a 
point is because it does not have "bigness".  In computer graphics, we often represent 
points with pixels.  Pixels do have "bigness", though not very much of it.  So, instead 
of just using pixels to plot our data, lets plot some kind of a "marker" at each data point.  
In PolarPhun, a small circle with a radius of 2 pixels seemed to serve as a pretty good 
marker.  Shown below is source code which plots a small, circular marker at each data point:

'We assume that the window is called "main" and that 
'the Graphicbox is called "PlotArea"


for degree = 0 to 360
     print #main.PlotArea, "place " + str$(xplot(degree)) + " " _
                              + str$(yplot(degree))
     print #main.PlotArea, "circle 2"
next degree

On many occasions, we will want our plot to appear as a relatively smooth curve instead 
of a sequence of markers.  To do that, we can plot lines between successive data points.  
The code below will accomplish this:


for degree = 1 to 360
    xplot1 = xplot(degree - 1)
    yplot1 = yplot(degree - 1)
    xplot2 = xplot(degree)
    yplot2 = yplot(degree)

    print #main.PlotArea, "line " + str$(xplot1) + " " + _
                           str$(yplot1) + " " + _
                           str$(xplot2) + " " + str$(yplot2)
next degree

            

F.  HOW ARE POLAR COORDINATES USEFUL IN THE REAL WORLD?

Ok, I give up.  How?

Polar coordinate systems probably have many wonderful uses.  But the truth is, 
I personally can't identify very many of 'em.  Since I first started plotting 
polar graphs back in the days of the Commodore 64, I've mainly used them to
 make insteresting shapes.

I know that polar systems are used quite often in aviation.  In fact, if you 
look at the regional maps inside your Microsoft Flight Simulator Pilot's 
Handbook, you will see compass circles overlaid on top of airports.  Each 
compass circle will have a vector drawn from the center of the circle to due 
North.  The vector is the "reference line" that we discussed in other sections 
of this article.  Starting at due North on each compass circle, the circles are 
marked every 5 degrees.  During flight planning, if a pilot draws a line from 
the center of the compass circle to his destination airport, that line will 
cut the circle at a specific degree mark.  This is the heading at which the 
pilot must steer his plane in order to arrive at his destination.  

I expect that polar systems are used for navigation at sea, too.  Certainly, polar 
systems are used in land surveying.  For other important uses of polar coordinate 
systems, I must humbly defer to others.

END
---------------------------------------------------------
---------------------------------------------------------
POLAR1.BAS

'***********************************************
'
'Polar1.bas by Nally + April 2000
'Released as open source
'
'Polar1.bas plots the function defined
'by R = 2.5 + 2*sin(12*phi) using polar
'coordinates.
'
'To change the function plotted, locate
'the branch label [Plot.click].  The
'function is defined a few lines below
'that branch label.
'
'***********************************************

pi = 3.141592
PlotType$    = "Markers"
MarkerValue$ = "set"
LineValue$   = "reset"
Scalefactor = 1
BiggestXY = 0
xmin = 0
xmax = 0
ymin = 0
ymax = 0

Dim R(360)
Dim x(360)
Dim y(360)
Dim xscaled(360)
Dim yscaled(360)
Dim xplot(360)
Dim yplot(360)


    NoMainWin
    WindowWidth = 440
    WindowHeight = 265

    Graphicbox #main.PlotArea, 214, 21, 200, 200
    Button #main.Plot, "Plot !", [Plot.click], UL, 25, 126, 170, 30
    Groupbox #main.groupbox4, "Plot Appearance", 26, 16, 168, 105
    Radiobutton #main.radioMarkers, " Plot markers", [markers.Set], [markers.Set], 38, 46, 112, 20
    Radiobutton #main.radioLines, " Plot Lines", [Lines.Set], [Lines.Set], 38, 71, 96, 20
    Button #main.About, "About...", [About.click], UL, 30, 186, 74, 25
    Button #main.Quit, "Quit", [Quit.click], UL, 118, 186, 72, 25
    Open "Plotting Polar Coordinates" For Window As #main
    Print #main.PlotArea, "fill white; flush"
    Print #main, "font arial 10"
    Print #main, "trapclose [Quit.click]"

    GoSub [Print.Initial.Control.Values]

[main.inputLoop]   'wait here for input event
    Wait
    GoTo [main.inputLoop]


[Quit.click]


    Close #main: End

[Print.Initial.Control.Values]

    Print #main.radioMarkers, "Set"
    Print #main.PlotArea, "fill white"

    Return




[markers.Set]

    Print #main.radioMarkers, "value? MarkerValue$"
    If (MarkerValue$ = "set") Then
         PlotType$ = "Markers"
    End If
    If (MarkerValue$ = "reset") Then
         PlotType$ = "Lines"
    End If

    GoTo [main.inputLoop]


[Lines.Set]

    Print #main.radioLines, "value? LineValue$"
    If (LineValue$ = "set") Then
         PlotType$ = "Lines"
    End If
    If (LineValue$ = "reset") Then
         PlotType$ = "Markers"
    End If

    GoTo [main.inputLoop]


[Plot.click]

    'for all angles between zero and 360 degrees,
    'find the value of R as defined by
    'R = 2.5 + 2*sin(12*phi)
    For degree = 0 to 360
        phi = (degree/360) *(2*pi)
        R(degree) = 2.5 + 2*Sin(12*phi)
    Next degree

    'Convert polar coordinates to
    'cartesian coordinates
    For degree = 0 to 360
        phi = (degree/360) * (2*pi)
        x(degree) = R(degree) * Cos(phi)
        y(degree) = R(degree) * Sin(phi)
    Next degree

    'Find the extreme values of all cartesian
    'x and y values as a prelude to
    'finding the scalefactor
    xmax = 0
    xmin = 0
    ymax = 0
    ymin = 0

    For degree = 0 to 360
        If (x(degree) > xmax) Then xmax = x(degree)
        If (x(degree) < xmin) Then xmin = x(degree)
        If (y(degree) > ymax) Then ymax = y(degree)
        If (y(degree) < ymin) Then ymin = y(degree)
    Next degree

    BiggestXY = 0
    If (abs(xmax) > BiggestXY) Then BiggestXY = abs(xmax)
    If (abs(xmin) > BiggestXY) Then BiggestXY = abs(xmin)
    If (abs(ymax) > BiggestXY) Then BiggestXY = abs(ymax)
    If (abs(ymin) > BiggestXY) Then BiggestXY = abs(ymin)


    'Establish the scalefactor
    Scalefactor = 90 / BiggestXY

    'Create a scaled set of the cartesian coordinates
    'so that the data will plot nicely in the Graphicbox
    For degree = 0 to 360
        xscaled(degree) = Scalefactor * x(degree)
        yscaled(degree) = Scalefactor * y(degree)
    Next degree

    'Shift the data set to the center of the
    'Graphicbox, while also reversing the
    'direction of y.
    For degree = 0 to 360
        xplot(degree) = 100 + xscaled(degree)
        yplot(degree) = 100 - yscaled(degree)
    Next degree

    If (PlotType$ = "Lines") Then [Skip.To.Lines]

    'If markers have been selected, plot markers
    Print #main.PlotArea, "discard"
    Print #main.PlotArea, "cls"
    Print #main.PlotArea, "fill white"
    Print #main.PlotArea, "down"

    For degree = 0 to 360
        Print #main.PlotArea, "place " + Str$(xplot(degree)) + " " + Str$(yplot(degree))
        Print #main.PlotArea, "circle 2"
    Next degree

    GoTo [Plotting.Accomplished]

    [Skip.To.Lines]

    'If lines have been selected, plot lines
    Print #main.PlotArea, "discard"
    Print #main.PlotArea, "cls"
    Print #main.PlotArea, "fill white"
    Print #main.PlotArea, "down"

    For degree = 1 to 360
        xplot1 = xplot(degree - 1)
        yplot1 = yplot(degree - 1)
        xplot2 = xplot(degree)
        yplot2 = yplot(degree)

        Print #main.PlotArea, "line " + Str$(xplot1) + " " + Str$(yplot1) + " " + _
                              Str$(xplot2) + " " + Str$(yplot2)
    Next degree

    [Plotting.Accomplished]

    Print #main.PlotArea, "flush"

    GoTo [main.inputLoop]



[About.click]

    Notice "About Plotting Polar Coordinates" + Chr$(13) + _
           "By Nally + April 2000      " + Chr$(13) + _
           "Made with Liberty Basic    " + Chr$(13) + _
           "Released as open source    "
    GoTo [main.inputLoop]

---------------------------------------------------------
---------------------------------------------------------
ATARI2.BAS

'***********************************************
'
'Atan2.bas by Nally + April 2000
'Released as open source
'
'A function called ATAN2() is provided herein.
'ATAN2() takes two arguements: cartesian x and y
'coordinates.  It returns an angle, phi, in
'radians.
'
'ATAN2() differs from ATN() in this regard:
'while ATN() only returns an angle between
'-pi/2 and +pi/2, ATAN2() will return any
'angle in the full circle.
'
'The user should not call the function if both
'x and y = 0.  This corresponds to a point at
'the origin of the coordinate system where
'the angle phi has no meaning.
'
'***********************************************


pi = 3.14159265


Print " "
Print "Note: Input real numbers for"
Print "      x and y.  Either x or y"
Print "      or both must be non-zero."
Print " "
Print "** INPUT  **"
Print " "

Input "x = "; x
Input "y = "; y

Print " "
Print "** OUTPUT **"
Print " "

phiRads = ATAN2(x, y)
phiDegs = 360 * (phiRads / (2 * pi))
R = (x^2 + y^2)^(1/2)
Print "Cartesion Coordinates of Q....Q("; x; ", "; y; ")"
Print " "
Print "ATAN2 in radians.............."; phiRads
Print "ATAN2 in degrees.............."; phiDegs
Print "Distance to Q................."; R
Print " "
Print "Polar Coordinates of Q........Q("; phiRads; ", "; R;")"




End

Function ATAN2(x, y)
    pi = 3.14159265
    Result$ = "Undetermined"
    If (x = 0) and (y > 0) Then
        ATAN2 = pi / 2
        Result$ = "Determined"
    End If
    If (x = 0) and (y < 0) Then
        ATAN2 = 3 * pi / 2
        Result$ = "Determined"
    End If
    If (x > 0) and (y = 0) Then
        ATAN2 = 0
        Result$ = "Determined"
    End If
    If (x < 0) and (y = 0) Then
        ATAN2 = pi
        Result$ = "Determined"
    End If

    If Result$ = "Determined" Then [End.of.function]


    BaseAngle = Atn(abs(y)/abs(x))
    If (x > 0) and (y > 0) Then ATAN2 = BaseAngle
    If (x < 0) and (y > 0) Then ATAN2 = pi - BaseAngle
    If (x < 0) and (y < 0) Then ATAN2 = pi + BaseAngle
    If (x > 0) and (y < 0) Then ATAN2 = 2*pi - BaseAngle

    [End.of.function]

End Function
---------------------------------------------------------
---------------------------------------------------------
POLAR COORDINATE DEMO BY GUY CANIDA
gfcanida@swing.be

Thanks for a wonderful polar coordinate demo, Guy!!


Demo to easy understand use of polar coordinates
  '
  ' Guy Canida March 31, 2002
  '
  ' Just run it and follow instructions
  nomainwin
  ' Set up main window
  BackgroundColor$ = "blue"
  WindowWidth = 540
  WindowHeight = 385
  UpperLeftX = 50
  UpperLeftY = 50
  pi=3.141592
  centerx=150:centery=150
  radius=100
  open "Polar Coordinates in Motion" for window_popup as #m
  call message "     Just click when told", 4000

  ' box for explanation

  BackgroundColor$ = "white"
  ForegroundColor$ = "blue"
  WindowWidth = 180
  WindowHeight = 330
  UpperLeftX = 390
  UpperLeftY = 75
  graphicbox #t.txt, 0, 0, 250, 350
  open " " for window_popup as #t
  print #t.txt, " fill white ; color yellow ; backcolor yellow ; down ; size 2"
  print #t.txt, "place 30 210":print #t.txt, "piefilled 90 90 0 -30" ' angle
  print #t.txt, "color black ; place 60 200":print #t.txt, "\a"
  print #t.txt, "color darkcyan ; backcolor white"
  print #t.txt, "line 10 210 170 210"  ' x axis
  print #t.txt, "line 30 60 30 240"    ' y axis
  print #t.txt, "color red ; line 150 110 150 210"  ' Y
  print #t.txt, "place 155 165":print #t.txt, "\Y"
  print #t.txt, "color blue ; line 30 110 150 110"  ' X
  print #t.txt, "place 85 225":print #t.txt, "\X"
  print #t.txt, "color black ; line 30 210 150 110" ' R
  print #t.txt, "place 70 165":print #t.txt, "\R"
  print #t.txt, "place 45 245":print #t.txt, "\    2         2        2"
  print #t.txt, "place 45 256":print #t.txt, "\ X    +   Y    =  R"
  print #t.txt, "place 45 276":print #t.txt, "\ X=R*COS(a)"
  print #t.txt, "place 45 296":print #t.txt, "\ Y=R*SIN(a)"

 ' box for animated demo

  BackgroundColor$ = "white"
  ForegroundColor$ = "blue"
  WindowWidth = 310
  WindowHeight = 330
  UpperLeftX = 70
  UpperLeftY = 75
  graphicbox #1.po, 0,0,310,330
  open " " for window_popup as #1
  print #1.po, "fill white ; down ; size 2"

  ' popup message
  print #t.txt, "when leftButtonUp"
  print #1.po, "when leftButtonUp"
  call message "First, 2 axis , X Y coordinates", 3000
  print #1.po, "when leftButtonUp [endit]"
  print #t.txt, "when leftButtonUp [endit]"

  ' loop forever

   while pi=3.141592

     ' go around a full circle from x axis counter clockwise

     for degree=359 to 1 step -1

     if degree=325 then
       print #1.po, "when leftButtonUp"
       print #t.txt, "when leftButtonUp"
       call message "   Click to end this", 2000
       print #t.txt, "when leftButtonUp [endit]"
       print #1.po, "when leftButtonUp [endit]"
      end if

     ' LB needs angles expressed in radian in trig functions

     radian=degree*pi/180

     print #1.po, "color darkcyan"

     x=centerx+radius*cos(radian)
     y=centery+radius*sin(radian)

     ' redraw image at angle=degree

     print #1.po, "backcolor white"
     print #1.po, "place ";centerx;" ";centery
     print #1.po, "circle ";radius+2
     print #1.po, "place 297 ";centery+3:print #1.po, "\>"
     print #1.po, "place 297 ";centery+17:print #1.po, "\X"
     print #1.po, "place ";centerx-4;" 18":print #1.po, "\^"
     print #1.po, "place ";centerx-15;" 18":print #1.po, "\Y"
     print #1.po, "line 10 ";centerx;" 300 ";centerx
     print #1.po, "line ";centery;" 10 ";centery;" 300"

     ' check in which quadrant we are to draw the pie that shows the angle

     quadrant=4-int(degree/90)
     select case quadrant
      case 1
       start=(quadrant-1)*90+1:at=degree-360
      case 2
       start=degree:at=180-degree
      case 3
       start=(quadrant-1)*90-1:at=degree-180
      case 4
       start=degree:at=degree*(-1)+3
      end select

     print #1.po, "place ";centerx;" ";centery
     print #1.po, "color yellow ; backcolor yellow; piefilled 90 91 ";start;" ";at
     print #1.po, "color black ; line ";centerx;" ";centery;" ";x;" ";" ";y  ' radius
     print #1.po, "color red"
     print #1.po, "line ";x;" ";centery;" ";x;" ";y            ' cos(angle)
     print #1.po, "color blue"
     print #1.po, "line ";centerx;" ";y;" ";x;" ";y            ' sin(angle)
     print #1.po, "flush"

     ' for good animation, please adapt

     timer 15, [itHappened]
     wait
    [itHappened]
     timer 0
     print #1.po, "cls"
    next
   wend
[endit]

  ' reset control and image for next step

  print #t.txt, "cls":print #1.po, "cls"
  print #1, "trapclose"
  print #1.po, "when leftButtonUp"
  print #t.txt, "when leftButtonUp"
  print #1.po, "backcolor white"
  call message "Now let'go polar coordinates", 3500

  ' set explanation of polar coordinates

  print #t.txt, "place 60 150"
  print #t.txt, "color yellow ; backcolor yellow ; piefilled 90 90 2 -30"
  print #t.txt, "color black ; place 80 145":print #t.txt, "\a"
  print #t.txt, "backcolor white ; color darkcyan ; size 1"
  print #t.txt, "line 30 150 150 150"            ' X
  t=140
  z=150-80*sin(pi/4)
  print #t.txt, "color red ; size 1 ; line 60 150 ";t;" ";z
  print #t.txt, "place 105 110":print #t.txt, "\R"
  print #t.txt, "color blue ; line ";t;" 150 ";t;" ";z
  print #t.txt, "place ";t+5;" 125":print #t.txt, "\Y"
  print #t.txt, "color black ; place 45 80":print #t.txt, "\ Y = R * SIN(a)"
  print #t.txt, "place 30 180":print #t.txt, "\Horizontal axis is angle zero"
  print #t.txt, "place 30 200":print #t.txt, "\R can also be a function"
  call message "Only one axis x and an angle", 3500
  print #1.po, "cls"
  print #1.po, "backcolor white ; color darkcyan ; size 1 ; line 10 ";centerx;" 300 ";centerx
  print #1.po, "place 297 ";centery+3:print #1.po, "\>"
  print #1.po, "place 297 ";centery+17:print #1.po, "\X"

  ' run polar coordinates demo

  for degree=269 to -90 step -1
   radian=degree*pi/180
   b=radius*cos(pi/4-radian)
   x=centerx+radius*cos(radian)
   y=centery+b*sin(radian)
   print #1.po, "color black ; size 1 ; line ";centerx;" ";centery;" ";x;" ";" ";y  ' radius
   print #1.po, "color red"
   c=(radius+3)*cos(pi/4-radian)
   t=centerx+(radius+3)*cos(radian)
   z=centery+c*sin(radian)
   print #1.po, "size 4 ; set ";t;" ";z
   print #1.po, "color darkcyan ; size 1 ; line 10 ";centerx;" 300 ";centerx
   print #1.po, "flush"
   timer 5, [itHappened2]
    wait
    [itHappened2]
    timer 0
   print #1.po, "color yellow ; line ";centerx;" ";centery;" ";x;" ";" ";y  ' radius
  next
  call message "       Click to end it", 3500
  print #1.po, "when leftButtonUp [quit]"
  print #t.txt, "when leftButtonUp [quit]"
  timer 1200, [quit]
   wait
[quit]
  timer 0
  call message "Guy Canida April 1st, 2002", 5000
  close #1:close #m:close #t

 ' popup message subroutine

  sub message msg$, time
   BackgroundColor$ = "white"
   ForegroundColor$ = "blue"
   UpperLeftX = 250
   UpperLeftY = 150
   WindowWidth = 150
   WindowHeight = 25
   TEXTBOX #0.text, 0, 0, 150, 25
   open " " for window_popup as #0
    print #0.text, "when leftButtonUp [itHappened2]"
    print #0.text, msg$
     timer time, [itHappened2]
      wait
      [itHappened2]
     timer 0
   close #0
  end sub
end

---------------------------------------------------------
---------------------------------------------------------
SUBMISSIONS

The Liberty BASIC Newsletter encourages all LB programmers
to submit articles for publication.  Everyone has something
valuable to say, from beginners to veteran LBers.  Consider
sharing a code routine, with explanation.  Perhaps you can
review a favorite LB website, or program, or coding tool?
Why not submit a list of questions that have been nagging
at you?  How about sharing your favorite algorithm?
---------------------------------------------------------
---------------------------------------------------------
    Comments, requests, submissions or corrections: 
Simply reply to this message, or contact a member of the team!

			The Team:
	Alyce Watson: alycewatson@charter.net
	Brad Moore: brad.moore@weyerhaeuser.com
	Tom Nally:  SteelWeaver52@aol.com
	Carl Gundel: carlg@libertybasic.com
	Bill Jennings: bbjen@bigfoot.com
---------------------------------------------------------
---------------------------------------------------------