CMPU 101 - Assignment 4 |
Due: by 11:59 PM on Friday, February 24th |

$Revision: 1.8 $

In this assignment you will use loops and loop variables to plot
*spirograph patterns* in a window.

Make sure you keep your own copies of all assignment files using a USB device, writable CD, and/or email attachments to yourself. The Home directory in the computers in the Mac lab is cleared of all files each time you log out. |

A *spirograph pattern* is a two-dimensional plot drawn by a pen
whose motion is determined by two circles. This is easiest to explain
by analogy: the pen is like the Earth's moon. The moon orbits around
the Earth and the Earth orbits around the sun. Assuming that
both orbits are in the same plane, and
the moon orbits multiple times around the Earth in the amount of time
it takes the Earth to orbit once around the sun,
then the moon will trace out a spiral pattern around the larger circle
of the Earth's orbit. Here is a diagram illustrating the
process, with arrows showing the motion of the large (Earth)
and small (moon) orbits:

Here we see the moon (pen) tracing four orbits around the earth in the time it takes the Earth to complete a single orbit around the Sun. By varying the following factors:

- radius of the large circle (Earth's orbit)
- radius of the small circle (moon's orbit)
- number of small orbits per large orbit (number of lunar months per Earth year)

we can achieve a variety of visual effects. By overlaying several spirograph plots in different colors, we can create spirograph art. For example (click for full size image):

Download the file cs101-assign4.zip into the Home directory. Open a terminal window and run the command

unzip cs101-assign4.zip

This will create a directory containing the files **Spirograph.java**,
**SpirographPanel.java**, and **SpirographFrame.java**.
Start DrJava and open these files. You will be modifying the
**plotSpirograph** static method in the file **Spirograph.java**.

In the file **Spirograph.java** you will see several constants defined.
These are static variables whose values never change. They define
several important quantities you will need to use for this assignment:

- CENTER_X
- The x coordinate of the center point
- CENTER_Y
- The y coordinate of the center point
- MAX_PLOTS
- This int value defines the maximum number of spirograph plots to draw in a single image.
- MAX_LARGE_RADIUS
- This double value is the maximum radius you should use for a plot's large orbit.
- MAX_SMALL_RADIUS
- This double value is the maximum radius you should use for a plot's small orbit.
- NUM_POINTS
- This int value defines the number of individual points that should be plotted for each spirograph plot.
- MAX_SMALL_ORBITS
- This int value defines the maximum number of small orbits to use in a spirograph plot.

This assignment will require you to generate some random values.
In the **Spirograph** class,
a static variable called **random** is declared and initialized
to store a reference to
a new instance of the **java.util.Random** class.
This object can be used to create random values
as described below.

To generate a random int value in the range 1..*N*, inclusive:

random.nextInt(N- 1) + 1

To generate a random double value in the range 0.0 to *MAX*, inclusive:

random.nextDouble() *MAX

To generate a **java.awt.Color** object representing a random color:

new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256))

To get started, modify the **plotSpirograph** method to
plot the circle defining the large orbit
of a single spirograph plot. The idea is to determine a sequence of points
that lie on the circle, and draw a line between successive pairs of
points. As long as the points are close enough together, the resulting
image will look like a circle.

Choose the large radius (double value) randomly in the range 0.0 to **MAX_LARGE_RADIUS**,
inclusive. Save this value in a double variable called **largeRadius**. This value
will determine the distance from the center point to points on the large orbit.

Create a **java.awt.Color** object representing a random color.
Save it in a variable called **color**. Inform the **Graphics**
object that you will use to draw the plot that you want to use this
color using the statement

graphics.setColor(color);

Next, write a loop with a loop variable **theta** (of type double)
that ranges from 0.0 to 2***Math.PI**.
The loop should generate **NUM_POINTS** uniformly distributed values within this range.
This loop defines a sequence of angles (measured in radians) that sweep out a complete circle.
Now, you just need to know how to convert an angle to a point (x and y
coordinates) on the large circle:

xOffsetLarge =largeRadius* Math.sin(theta); yOffsetLarge =largeRadius* Math.cos(theta);

By computing these offsets for each value of **theta**
and adding them to the center point's coordinates (**CENTER_X** and **CENTER_Y**), you can
find a sequence of points on the circle. Now you just need to
draw a line between adjacent pairs of points.

Because each iteration of the loop generates only a single point
(x and y values), and a line requires |

Once you have determined the coordinates of the previous and current points,
you can draw a line between them using the **drawLine** method in the **java.awt.Graphics**
class, invoking the method on the parameter **graphics** that is passed
to the **plotSpirograph** method. Note that this method expects coordinates to be
specified as **int** variables, so you will need to perform
a cast from double to int for each argument you pass to the method.
For example let's say that you have the coordinates of the current and previous points
stored in double variables called **curX**, **curY**, **prevX**, and
**prevY**. You can plot a line between these two points with
the statement

graphics.drawLine((int)prevX, (int)prevY, (int)curX, (int)curY);

Once you have implemented the loop that draws a single circle,
try running the program (**java SpirographFrame** in the DrJava interactions window.)
When you click the "Draw" button
you should see something like the following:

If you can plot a single circle, congratulations! You're most of the way there!

Once you can plot the circle defining a single large orbit, try adding a loop that will
draw multiple large circles.
Choose the number of plots to draw as a random integer value in the range
1 to **MAX_PLOTS**, inclusive, and save it in an int variable
called **numPlots**.
Then, add a loop around the code you wrote to plot a single circle
that has an integer loop variable whose range is 1 to **numPlots**.
When you run the **SpirographFrame** program and click the
"Draw" button, you should see something like the following:

To change a circle plot into a spirograph plot, all we need to do is
add an additional offset representing the small orbit to each plotted point.
First, choose a random int value in the range 1 to **MAX_SMALL_ORBITS**, inclusive,
and save it in an int variable called **numSmallOrbits**.
This is the number of small orbits the pen (moon) will make in the course
of a single large orbit.
Then, choose a random double value in the range 0.0 to **MAX_SMALL_RADIUS**,
inclusive, and save it in a double variable called **smallRadius**.
The additional offsets for the small
orbit can be calculated as follows:

xOffsetSmall =smallRadius* Math.sin(numSmallOrbits*theta); yOffsetSmall =smallRadius* Math.cos(numSmallOrbits*theta);

By multiplying the angle **theta** by **numSmallOrbits**, we
model the fact that the small orbit is being completed more quickly
than the large orbit. Once you have added these additional offsets
to the points you are plotting, you should be able to run
the **SpirographFrame** program, click the "Draw" button,
and see images of multiple spirograph plots.

Make sure your completed files are all in a directory called **cs101-assign4**
within the Home directory.
Create a zip file containing your files by running the following commands in a terminal
window:

cd zip -9r cs101-assign4-solution.zip cs101-assign4

Upload the file **cs101-assign4-solution.zip** to the
CS 101 Submission Website.

Make sure you save a copy of your files (to a USB device, writable CD, or as an email attachment to yourself) before logging out. |