In this assignment you will write a graphics-based program to draw a "rectangular" spiral, centered in the window. This is based on Programming project 6.21 in our textbook.
This assignment will give you practice creating and implementing classes, using loops and conditionals, doing console-based IO, drawing to a graphics window, and writing a unit test. Also you'll get practice with the program development process. Please read over the whole assignment before beginning: in particular, do not wait until the assignment is due to read about submitting it: you'll want to do your first submit before the final deadline, because when you submit it we do some checks on your code, and you will be able to resubmit if you fail those checks (but not if you are out of time).
This document may seem voluminous, because it includes some
instructional material, and hints on how to do certain things. You'll
need to read it or parts thereof more than once, possibly skimming
some parts on the first reading. To help you find things as you are
working on the assignment, here is a
table of contents for the main sections:
Table of Contents
Resources
The programming environment for this assignment
Reminder: The first time you access the assignment on Vocareum, you
will need to go through the link on d2l (More
detailed directions about this were given on Lab 1). Any subsequent accesses to
the same assignment can be made via labs.vocareum.com
(or through the d2l link).
In the normal Vocareum configuration, you have a Linux terminal, but no way to run a program with a graphical user interface (GUI). For this assignment we are using a different Vocareum configuration that will allow you to open multiple windows, including a separate one to run your GUI program. With this configuration, when you start up Vocareum for this assignment, it will allow you to open up a virtual Linux desktop in your browser. Note: You will not be able to run GUI programs from the regular Linux terminal that appears under the source code area of the regular Vocareum IDE.
How to start up a virtual Linux Desktop in Vocareum
The way you get to a virtual linux desktop in this assignment is to go
to a menu that's on the upper right of the workbench window: choose
Actions--> Applications --> Desktop.
That will open a linux desktop in another tab in your browser. If it starts with a pop-up dialog, choose "Use default configuration." There are a few ways to open a terminal window in this desktop. You can use the Applications menu at the top left of the screen, and choose "Terminal Emulator". Or you can right click anywhere on the desktop, and choose "Open Terminal Here".
Warning: depending on how you started up the terminal, it might not start out in your home directory (i.e., "work"), but rather starts in the root directory ("/") or somewhere else. So the first thing you should do is
cdto get into your home directory. (One way to check if you are in your home directory is you will see the ~ (tilde) right before the $ in the Linux shell prompt.)
Your home directory will be populated with the starter files we are providing you. Part of what we provided is source code for a complete sample Java GUI program there, so you can try out compiling and running such a program in this environment before you write code for your own program. Compile and run this program:
javac CarViewer.java java CarViewerMore about this car example (from Section 3.8 of the textbook) later.
You can switch between these two tabs in your browser to switch between editing (normal Vocareum window), and compiling and running (Linux desktop). To make it easier to see your compile errors at the same time as you view your source code, you can put the Vocareum tab in a different browser window altogether.
Another option with the desktop is to use one of the other source code editors available within the desktop itself. I saw emacs and vim (Rt-click on desktop-->Applications-->Accessories). I'm not sure how fast these work on this platform, so if you end up using one of these, let me know how it goes. (I only opened emacs there briefly once; it started up pretty fast, so that's a good sign.) Both emacs and vim are a little different than other editors you are used to, so you probably would want to take a look at an online tutorial on the web before using them. Eclipse is also available there; it may be somewhat slower than running it locally.
You can disconnect from the Desktop by closing its tab, or from the main Vocareum window (upper right) do: Actions-->Applications-->Stop App. Then you can restart later the same way you did the first time.
Using another IDE for this assignment
If you don't want to use Vocareum and its Linux desktop as your
development environment, you can use another IDE running locally on
your own machine.
If you choose go this other route, you would do the following:
The files in bold below are ones you create and/or modify and submit. The ones not in bold are files you will use, but that you should not modify. The ones with a * to the left are starter files we provided.
"I certify that the work submitted for this assignment does not violate USC's student conduct code. In particular, the work is my own, not a collaboration, and does not involve code created by other people or AI software, except for the resources explicitly mentioned in the CS 455 Course Syllabus. And I did not share my solution or parts of it with other students in the course."
Then it will display a 500 tall by 800 wide pixel window with the spiral displayed on it, such that the start of the first segment is centered in the window.
Here is a screenshot of output from one run of our solution to this assignment, where our responses to the console prompts were to use a 10-pixel initial segment length, and draw a 30-segment spiral (shown in the (500, 800 window)).
Here's a different spiral to make it easier to see how each segment is arranged (initial segment = 20, number of segments = 10). Also, I resized window before doing this screenshot of the window, so that's why the window is smaller.
If some of the segments to be displayed based on the input values given would go outside the window, that part of the spiral will not be visible: this is the expected behavior. For example, here's a spiral with initial segment length of 10, and number of segments = 100, shown without resizing the window:
As mentioned in the textbook, every time a window gets resized or iconified and de-iconified paintComponent gets called again. Here's a later screenshot created during the same run shown above, but after the user dragged the corner to make the window larger, and now the whole spiral is visible. Note that the spiral is centered in the new window dimensions.
Similarly if the user makes the window smaller while running the program, a completely visible spiral could become partially hidden after the resize.
More about the graphics library methods necessary to get these results in the section on Graphics programming.
There are a few other requirements for the assignment discussed in the following sections. To summarize here, the other requirements are:
We are giving you the
exact interface to use for this class. By interface, we
mean what clients need to know about the class to use it, i.e., the
class name, the class comment, the
public method headers and associated method comments. Do not change the public
interface when you incorporate it into your own program. We have provided skeleton code for
SpiralGenerator.java.
Please read
the class and method comments in that file for
its exact specification.
Note: For all
work in this course, when we say do not change the interface for a
class, we mean no changing the
class name or the
provided method headers, no adding public methods, no removing public
methods.
As part of the grading process, we will be using our own test programs with such classes, and if you
change the public interface your code might not even compile with our test
programs. We will be testing whether your class implementation
matches the specification.
SpiralGenerator does not depend on any of the other
classes you are creating here. It does depend on the Java library classes
Point and Line2D, see the section on lines and points for more about these classes.
The Car example
We provided you with the
source code for that example as part of the starter
files for this assignment. You can use the code in CarViewer.java as a
starting point for your SpiralViewer class for this assignment.
In addition to examining the general structure of the car example
code, you can use it to test out running a GUI program in the Vocareum
virtual Linux Desktop before developing your own code. When you run
it there, you can also see how the display changes when you change the
size of the window in which the CarViewer application is running and
the corresponding code that gets that to happen (the display for your
program will also change when the window is resized).
We also modified CarComponent.java a little bit from the version of
the code from the text: we instrumented the code so it prints a message
to the console every time paintComponent gets called, to help you better
understand when the Java Swing graphics framework calls paintComponent. To see this, once you
start running the program, make sure
you can see the terminal window, as well as the CarComponent window; then try resizing the CarComponent
window, and minimizing it and opening it again.
Any program of non-trivial size will be developed faster, with fewer
bugs, using the technique of incremental development, which means
developing and testing pieces of the program incrementally. The
incremental aspect is that your program may gradually grow until it
includes the complete functionality. (Other people use different
names for the same thing. Sometimes it's called building subsets.)
A desirable feature of individual classes is that they are as
independent as possible from a program that uses them. Some classes,
such as String, or ArrayList (which we will see
soon) are general-purpose and can be used in many different programs.
Other classes are more special-purpose, such as SpiralGenerator,
but still are modules that can be separated from a particular program
that uses them. We can
test such a module using a unit-test, which is a program specially
designed to test the module.
We often unit-test one (or more) classes, and then once we are
convinced that unit is working correctly, we can integrate that class
with other code that uses it. If this larger code base is now buggy,
we can feel fairly certain that the bug is in the new code we added,
since we already tested the first class. So any time we find bugs, it's in a
small program: much easier than locating bugs in large programs.
Similarly, if we make later changes or enhancements to our
application our code will be more robust in the face of these
changes because, in our unit-test, we tested the module in ways not
specific to how it was used in this application.
(As you have experienced as a user, software is always getting changed
over time, e.g., the latest version of Windows is in the
double-digits.) For example, in our SpiralViewer we would
not be able to see if SpiralGenerator had the correct results for spirals that
start using negative coordinates.
For this assignment, the final product will not be a very large
program, but we want to get you in the practice of using incremental
development, so you will still be successful when you are trying to
develop and debug much larger programs. Even in this program there
are at least two distinct issues to deal with: (1) figuring out how to
create the correct sequence of segments
(2) figuring out how to do a graphics-based program in Java.
It will be much easier you we can deal with these issues
one at a time, so you can isolate bugs related to each one more easily.
For this assignment you are required to write a console-based Tester
class to test your SpiralGenerator class.
This test
program is described in more detail in the next section.
When you are compiling and running your test
program you should be able to do it as follows:
For the larger program we are
doing for this assignment (for that one main is in
SpiralViewer.java), you can either list all of the files it
uses on the command line or use the following convenient shorthand:
So, what should you put in your SpiralGeneratorTester?
This will be a console-based program -- i.e., no GUI. It will be a
non-interactive program (i.e., fixed data, nothing read in
from the user) that tests every method multiple times, printing
informative output to the console with the results of each operation.
For a SpiralGenerator with given parameters you can
predetermine what all the output will be. But instead of comparing
with reference output (that you'd likely have to compute by hand),
in your tester you're going to just test a subset of what has to be true for a spiral.
Here are the requirements for your test program:
Note: When you test a method such as the SpiralGenerator
constructor, which has a
restriction on its parameter (in this case the restriction is that the
unitLength must be greater or equal to one) it means that the behavior of
the method is undefined if that precondition is not met.
Your test program should not attempt any tests that violate preconditions on methods.
We will test your
SpiralGeneratorTester with our own buggy SpiralGenerator
classes.
The JComponent methods, getWidth() and
getHeight(), which get the width and height of the
component, will come in handy here. Since SpiralComponent
is a subclass of JComponent you can directly call those
methods from your component object. For an example of such calls, see the
CarComponent class included in the starter code (and discussed further
here).
Printing lines and points
Recall that you never will be calling paintComponent
yourself, nor are you allowed to change the parameters to it.
We have published a more complete set of style
guidelines for the course on the assignments page, but here are a
few things to pay particular attention to for this program:
Implementing the required class design
will also be part
of your style/documentation score.
The files you need to submit are the ones shown in bold in the earlier
section on assignment files.
No matter where/how you developed the code, we will be grading it on
Vocareum using the java compiler and virtual machine there (Version
1.8, aka Java 8).
If you developed your program outside of Vocareum, for example, using
Eclipse on your laptop, you'll need to upload your code to Vocareum
and recompile and retest it completely before you submit it.
Do not wait until the
final due date/time is imminent before testing it on Vocareum.
Please read the
earlier section on using another IDE for more details on this.
How to submit your program
When you are ready to submit the assignment press the big "Submit"
button in your PA1 Vocareum work area. Do not wait until the
final due date/time is imminent before attempting to submit for the
first time. You are allowed to submit as many times as you like,
but we will only grade the last one submitted.
What happens when you click submit.
Vocareum will check that you have
the correct files in your work area and whether they compile. It will
also check whether the segments generated by your
SpiralGenerator class are
correct for a very small spiral.
Passing these submit checks is not necessary or sufficient to
submit your code (the graders will get a copy of what you submitted
either way). (It would be necessary but not sufficient for getting
full credit.) However, if your final submitted code does not pass all the tests we
would expect that you would include some explanation of that in your
README. One situation where it might fail would be if you only
completed a subset of the assignment (and your README should document
what subset you completed.)
The results of the submit checks will appear on your terminal window. You
can also access them by going to the "Details" menu, and choosing
"View Submission Report". (Like we did on Lab 1.) Please read this report to see if you
passed the tests, so you can fix your program and resubmit if
necessary. Make sure you scroll down to the bottom of the report so
you don't miss anything.
If you are unsure of whether you
submitted the right version, there's a way to view the contents of your
last submit in Vocareum after the fact: see the item in the file list on the left
called "Latest Submission".
More details of the error-checking
As mentioned in the earlier section, when your program prompts for the
length of the initial segment, and also when it prompts for the number
of segments to display, you will error check that a
positive value is entered. More specifically, we mean that on an
invalid value the program will print out an informative error
message and then prompt and read again until the user enters a valid
value. Example with the segment length prompt (user input shown in italics):
Enter length of initial segment: -5
ERROR: value must be > 0
Enter length of initial segment: -1
ERROR: value must be > 0
Enter length of initial segment: 0
ERROR: value must be > 0
Enter length of initial segment: 5
Your program does not have to handle non-numeric input. (We will not
test it on that case.)
Class design
To help you make your program object-oriented, we are giving you the
general class design for this program.
You are required to use the following classes (ones in bold are
ones you will be creating yourself or implementing):
Note: this list doesn't include all the java library classes that will
be used in the program; for example SpiralComponent will need
java.awt.Graphics.
Our program
follows the conventions of graphical classes used in the textbook (see
Resources, near the beginning of this
document, for relevant textbook readings). In particular, the design
for this assignment overall follows the car example from Section 3.8 of the
textbook that has a viewer and a component. One difference is the
car example also has a graphical object that can get instantiated
multiple times and drawn in different locations on the screen (the
Car class). We have no such analogous class in our design.
You will do all the drawing in the SpiralComponent class
itself.
Incremental development and unit testing
Testing the SpiralGenerator class
You are actually going to submit two programs for this assignment,
both of which use your SpiralGenerator class either
directly or indirectly. One is
SpiralViewer, described earlier, that has a graphical
display. The other is a console-based program,
SpiralGeneratorTester, expressly written to
test your SpiralGenerator class, without including the
drawing functionality of the SpiralViewer program. The
rationale for unit tests was discussed in the previous
section. First, here's more information about compiling Java code:
As mentioned in the previous section a test program like
SpiralGeneratorTester is called a unit test; we have discussed
such unit tests in lecture, and they are also discussed in Section 3.4
of the textbook. One goal of this test program is for you to test the
functionality of the SpiralGenerator class.
How to compile and run multi-file Java programs on the command line
Often you can just list the file that contains main in the
compile command and javac figures out what other classes
are used in that program and compiles those as well. However,
sometimes the Java compiler gets confused when you only have modified some of the
source files since the original compile. For running a program that
uses multiple class files, the only class name you give as the
argument to the java virtual machine is the one containing
main.
javac SpiralGenerator*.java
java SpiralGeneratorTester
The wild-card ("*" symbol) in the compile command will match the two files
SpiralGeneratorTester.java and SpiralGenerator.java.
javac @SpiralViewer.list
java SpiralViewer
The SpiralViewer.list file (one of your starter files) just
consists of the list of files to compile for the program. The
@ on the command line tells javac to look in the file that
follows it to find out what java files to compile. An alternate is to
use *.java instead in the compile command, although that
one would also attempt to compile
SpiralGeneratorTester.java as well as the code for the car
example.
Here is an example of partial output from a SpiralGeneratorTester
running with a SpiralGenerator that is not currently working correctly
(i.e., it fails some of the tests):
. . .
Making a spiral starting from java.awt.Point[x=200,y=300]
with a unit length of 5, and made up of 10 segments:
Segment #1: Point2D.Double[200.0, 300.0] Point2D.Double[205.0, 300.0]
Segment #2: Point2D.Double[205.0, 299.0] Point2D.Double[205.0, 294.0]
FAILED: last two segments are not connected
. . .
Segment #4: Point2D.Double[195.0, 295.0] Point2D.Double[205.0, 305.0]
FAILED: segment is not horizontal or vertical. Skipping pair tests.
. . .
Segment #6: Point2D.Double[210.0, 305.0] Point2D.Double[210.0, 290.0]
Segment #7: Point2D.Double[210.0, 290.0] Point2D.Double[210.0, 305.0]
FAILED: last two segments are not perpendicular
. . .
About your tester output and the example shown above:
Hints on graphics programming
The graphics primitives you will need for this program are
covered in the graphics sections at the end of Chapters 2 and 3 of the
textbook, except for a few things we will discuss here. You
will not need to go hunting through the online documentation or
random websites to figure out how to do the necessary drawing. More
specifically: how to draw a line is shown in section 2.10.2, and there
is a concrete example of drawing lines
alien face example in textbook section 2.10.4;
we also provided the code from another example from the textbook (see
the Car example section for more on that.)
Lines and Points
As discussed in the textbook (and in
lecture, with respect to the similar Rectangle class), the
shape classes in the java graphics library do not have drawing
capabilities themselves, but just store data about something you'll be
drawing. We'll be using lines and points here, but
there are several line and point classes that we'll try to disentangle here:
Most Java classes have a
toString method defined that returns a String form of the
object, useful for printing its contents; even better, if we pass an
object that has toString defined to a print or println
statement, this toString method will get implicitly called. However,
for some reason Line2D.Double does not have a
toString that does what we want, so if you want to print a line,
you'll have write code to print the points it contains. Here's some example code
to print a segment returned by our nextSegment() method.
getP1 and getP2 are Line2D methods
(which means they also work for Line2D.Double).
Line2D currSeg = gen.nextSegment();
System.out.println(currSeg.getP1() + " " + currSeg.getP2());
Here's some sample output from that statement:
Point2D.Double[215.0, 310.0] Point2D.Double[215.0, 285.0]
How to communicate information between objects
There are several techniques to communicate information between
classes and methods of classes, including via parameters and return
values of methods. In particular, here you have the issue of receiving
some information in main in SpiralViewer, that
is, the initial segment length to use and the number of segments to draw, but needing to use that information in the
component. To do this, your SpiralComponent class will
need to have its own constructor (Note: this is different than the
simpler component examples in the book). From main you can pass
the information to that constructor, and then, if you also needed access
to it in other methods, you would save it in instance variables.
README file
For this and all other programs you will be required to submit a text
file called README with your assignment. In it you will
initial the certification we mentioned earlier. This is also the place to document
known bugs in your program. That means you should describe thoroughly
any test cases that fail for the program you are submitting. (Not
your bug history -- just info about the version you are submitting.)
You should also document here what subset your solution implements if
you weren't able to complete the whole program (more about that in the
next section). If you used any outside
allowable resources for your code give your references for that
here too (it is not necessary include references
to the Ch. 2 and 3 graphics examples).
You can also use the
README to give the grader any other special information,
such as if there is some special way to compile or run your program
(this would be unusual for students who complete the assignment).
Grading criteria
This program will be graded based on correctness, style, and
testing. Programs that do not compile will get little or no credit.
However, an incomplete program can get some correctness points if it
has partial functionality (you document the partial functionality in
the README, discussed above). This grading policy is to encourage
frequent testing of subsets (discussed earlier in the section
on incremental development). Also, for incomplete
programs, the style score will be scaled
according to how much is completed.
For this program only, we won't enforce method-length restrictions
(guideline #9), and while you should document any instance
variables that are not obvious from their names, you do not have to
worry about representation invariants (item #17) -- we will be
discussing those later this semester.
How to turn in your assignment
Make sure your name, NetID, course, assignment, and semester are at the top of
each file you submit (for source files, they would be inside of
comments) for any assignment you submit for this course. You will lose a
point on any assignment for which this information is missing. Note:
your NetID is the part of your USC email address before the @