|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:
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
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:
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
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 two points (beginning and end), you will need four variables: the x and y coordinates of the current point, and the x and y coordinates of the previous point. On the first iteration of the loop, there is no previous point, and so you should not draw a line on this iteration. At the end of your loop, you should copy the values of the variables storing the x and y coordinates of the current point into the corresponding variables for the previous point. That way, those values will be available during the next iteration of the loop.
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.