EECS 132: Homework Assignment 3
Programming Project 3
Due Saturday, April 10 at 11:59pm (EDT)
IMPORTANT: Read the Do's and Dont's in the Course Honor Policy found on blackboard.
I. Overview
The purpose of this project is to give you practice designing a class/type hierarchy. It is
important that you spend time designing your class hierarchy before you start coding. If
you properly organize your classes and/or interfaces, you can achieve the desired program
behavior below with significantly less code than with a poorly organized hierarchy. This
project will also how there are limitations to what we can do with Java's classes and
interfaces.
II. Code Readability (20% of your project grade)
New for this assignment: The comments above the class or interface and above each
method must be written in JavaDoc format. You will be introduced to JavaDoc style
commenting in the labs. You can also find a description in the Java in a Nutshell text. Be
sure to run JavaDoc and view the webpage in order to verify that you have implemented
the comments correctly.
To receive the full readability marks, your code must follow the following guideline:
All variables (fields, parameters, local variables) must be given appropriate and
descriptive names.
All variable and method names must start with a lowercase letter. All class and
interface names must start with an uppercase letter.
The class body should be organized so that all the fields are at the top of the file, the
constructors are next, the non-static methods next, and the static methods at the
bottom.
There should not be two statements on the same line.
All code must be properly indented (see page 644 of the Lewis book for an example
of good style). The amount of indentation is up to you, but it should be at least 2
spaces, and it must be used consistently throughout the code.
You must be consistent in your use of {, }. The closing } must be on its own line and
indented the same amount as the line containing the opening {.
There must be an empty line between each method.
There must be a space separating each operator from its operands as well as a space
after each comma.
There must be a comment at the top of the file that is in proper JavaDoc format and
includes both your name and a description of what the class represents. The comment
should include tags for the author.
There must be a comment directly above each method (including constructors) that is
in proper JavaDoc format and states what task the method is doing, not how it is
doing it. The comment should include tags for any parameters, return values and
2021/4/11 EECS 132: Homework Assignment 3
file:///C:/Users/DeiDylan/Downloads/hw3.html 2/8
exceptions, and the tags should include appropriate comments that indicate the
purpose of the inputs, the value returned, and the meaning of the exceptions.
There must be a comment directly above each field that, in one line, states what the
field is storing.
There must be a comment either above or to the right of each non-field variable
indicating what the variable is storing. Any comments placed to the right should be
aligned so they start on the same column.
There must be a comment above each loop that indicates the purpose of the loop.
Ideally, the comment would consist of any preconditions (if they exist) and the
subgoal for the loop iteration.
Any code that is complicated should have a short comment either above it or aligned
to the right that explains the logic of the code.
III. Program Testing (20% of your project grade)
New for this assignment: The testing routines should be included in a JUnit test class.
You are to write a test report that indicates the kinds of tests needed to thoroughly test
your project. The tests should demonstrate that all of your methods behave correctly. An
conditional statements will need tests that go through each branch of the execution. Any
loops will need tests that cover the "test 0, test 1, test many" and "test first, test middle,
test last" guidelines. Your testing report should not list the actual tests and results.
You are to have a JUnit test class or classes that implement each of the needed tests.
Comments and method names in your JUnit class should connect to your testing report.
For example, if your testing report states "method xxx must be tested with string inputs of
different lengths", then the reader should be able to go to the JUnit class and easily
identify the tests that test that method on inputs of length 0, 1, and more than 1.
The testing report must be separate from the JUnit class. In most companies, the testing
document will be written in a style that allows both programmers and non-programmers
to read it and recognize whether all the needed test cases were included.
Routines you do not have to JUnit test: Some methods print to the screen, such as the
constructor are not easy to test with JUnit. For these methods, your testing report should
still state how you will test them, and then you will test them yourself by running your code
(similar to what you did for previous projects).
Testing inherited routines: You are not required to have tests for methods that a class
inherits but does not override. However, many companies will require you to write tests for
them. The reason is that later updates may choose to override the methods and you want
the tests already there for when that happens. A very good practice is to write your tests
before you design your program based on what the desired final results are, and then the
tests will verify that the classes perform correctly regardless of how you decide to create
your hierarchy.
IV. Java Programming (60% of your grade)
2021/4/11 EECS 132: Homework Assignment 3
file:///C:/Users/DeiDylan/Downloads/hw3.html 3/8
Design Rules: Your project must contain the following types and each type must contain
the listed methods. The project may use any combination of classes, abstract classes, or
interfaces that you feel is appropriate. The project may add additional types to the ones
listed. The classes/types may contain additional methods to the ones listed if you feel they
are needed. You may use any combination of inheritance, method overriding, and method
overloading to achieve the needed behavior. Part of the coding grade will be the quality of
the hierarchy you create.
Hint (repeated from above): Spend a lot of time designing your hierarchy before you
code. A well designed hierarchy will reduce the amount of code you have to write.
Programming (60% of the project grade)
Here is a Java shortcuts you will use: variable length parameters.
An overview of variable length parameters
A variable length parameter is a Java shortcut that can be used by a method that takes an
array as input. With the shortcut, you do not need to create the array explicitly. For
example:
public int maximum(int[] a) {
int max = 0;
for (int i = 1; i < a.length; i++)
if (a[i] > a[max])
max = i;
return max;
}
is the normal way we pass an array to a method. To call maximum, we must create an array
first: maximum(new int[]{1, 2, 3}).
If we change maximum to take a variable length parameter, it looks like this:
public int maximum(int... a) {
int max = 0;
for (int i = 1; i < a.length; i++)
if (a[i] > a[max])
max = i;
return max;
}
Notice that the body of maximum did not change. The input a is still an array of int. However,
we now have two ways to call a. We can still use the traditional way of passing in an array:
maximum(new int[]{1, 2, 3}) or we can just pass in the elements and Java will automatically
place them in an array of the correct size: maximum(1, 2, 3). Note that there can be only one
variable length parameter per method, and the variable length parameter must be the last
parameter of the method. (Can you see why?)
Your programming task
This project will have you build a hierarchy of shapes similar to, but also different from, the
lecture hierarchy.
Creating a hierarchy of types
2021/4/11 EECS 132: Homework Assignment 3
file:///C:/Users/DeiDylan/Downloads/hw3.html 4/8
Your project should contain the following types. Each type can be a class, abstract class, or
an interface. You are welcome (and probably should) create any additional types, public,
and private methods as you feel are needed.
Please note: the descriptions of these methods are what the method should do, not how
you are to program it. Spend time thinking about how to organize your code before you
code. Your goal is to create a good hierarchy that lets you achieve all the behavior below
without writing a large amount of code.
1. Point: The Point type consists of two double values and represents a 2-dimensional
point. The Point type should have the following methods:
getX returns the x-coordinate of the point
getY returns the y-coordinate of the point
setX takes an double as input and changes the x-coordinate of the point.
setY takes an double as input and changes the y-coordinate of the point.
rotateAbout takes a Point and a double as input. The double is an angle, in radians,
and the method should rotate this point about the input point by the input
angle. That means, treat the input point as the origin and rotate this point.
To treat the input point as the origin, you subtract this point's x-coordinate by
the input point's x-coordinate, and subtract this point's y-coordinate by the
input point's y-coordinate. Then you do the rotation:
x' = x cos t - y sin t
y' = x sin t + y cos t
and then add the input points x-coordinate and y-coordinates to the x' and y'
values, and set the result to be this point's new coordinates.
2. Line: The Line type consists of two Point values and represents a 2D line segment. A
Line type instance should be created with either 4 double values representing the
coordinates of the endpoints of the line, or it can be created with 2 Point values
representing the endpoints of the line. The Line type should have the following
methods:
getFirstPoint: returns the first endpoint of the line.
getSecondPoint: returns the second endpoint of the line.
setFirstPoint: takes a Point as input and changes the first endpoint of the line.
setSecondPoint: takes a Point as input and changes the second endpoint of the
line.
getLines: returns an array containing all Line types that make up this line (i.e. the
array should contain only this line.
3. Rectangle: The Rectangle type represents a rectangle. A Rectangle type instance should be
created with one Point representing the center of the Rectangle plus two lengths
representing the height and width. The Rectangle type should have the following
methods:
getCenter: returns a Point that represents the center of the rectangle.
getWidth: returns the width of the rectangle.
getHeight: returns the height of the rectangle.
setCenter: takes a Point as input and sets the center of the rectangle to this input
point.
setWidth: takes a double as input that is the new width for the rectangle.
2021/4/11 EECS 132: Homework Assignment 3
file:///C:/Users/DeiDylan/Downloads/hw3.html 5/8
setHeight: takes a double as input that is the new height for the rectangle.
rotate: takes a double as input that represents an angle in radians, and it rotates
the rectangle about its center byt the input angle.
getPoints: returns an array consisting of the 4 Points that make up the corners of
the rectangle
getLines: returns an array containing the 4 Lines that make up the border of the
rectangle.
4. Square: The Square type represents a square. A Square type instance should be created
with one Point representing the center of the Square plus one double representing both
the height and width. The Square type should have the following methods:
getCenter: returns a Point that represents the center of the square.
getWidth: returns the width of the square.
getHeight: returns the height of the square.
setCenter: takes a Point as input and sets the center of the square to this input
point.
setWidth: takes a double as input that is the new width for the square.
setHeight: takes a double as input that is the new height for the square.
rotate: takes a double as input that represents an angle in radians, and it rotates
the square about its center by the input angle.
getPoints: returns an array consisting of the 4 Points that make up the corners of
the square
getLines: returns an array containing the 4 Lines that make up the border of the
square.
5. Triangle: The Triangle type represents a triangle. A Triangle type instance should be
created with three Point values representing the three points of a triangle. The Triangle
type should have the following methods:
getCenter: returns a Point that represents the center of the triangle. The center
can be calculated by taking two lines, each from one angle to the midpoint of
the opposite side, and then calculating the intersection of those lines. If the end
points of the first line is (x1,y1) and (x2,y2) and the end points of the second line
are (x3,y3) and (x4,y4), the intersection point is:
x = ((x1*y2 - y1*x2)*(x3-x4) - (x1-x2)*(x3*y4-y3*x4))/((x1-x2)*(y3-y4)-(y1-y2)*(x3-
x4))
y = ((x1*y2 - y1*x2)*(y3-y4) - (y1-y2)*(x3*y4-y3*x4))/((x1-x2)*(y3-y4)-(y1-y2)*(x3-
x4))
setCenter: takes a Point as input and moves the triangle so it's new center is the
input point.
rotate: takes a double as input that represents an angle in radians, and it rotates
the triangle about its center by the input angle.
getPoints: returns an array consisting of the 3 Points that make up the corners of
the triangle.
getLines: returns an array consisting of the 3 Lines that make up the border of the
triangle.
6. Polygon: The Polygon type represents an arbitrary polygon. A Polygon type instance should
be created with a variable length input of Point values representing the (at least three)
points that make up the polygon. The Polygon type should have the following methods:
2021/4/11 EECS 132: Homework Assignment 3
file:///C:/Users/DeiDylan/Downloads/hw3.html 6/8
getCenter: returns a Point that represents the "center" of the polygon. Since this is
an arbitrary polygon, the center will be defined as the center of the bounding
rectangle of the polygon. (The top edge of the bounding rectangle is at the top
most point of the polygon, the left edge of the bounding rectangle is at the
leftmost point of the polygon, and so forth.)
setCenter: takes a Point as input and moves the polygon so it's new center is the
input point.
rotate: takes a double as input that represents an angle in radians, and it rotates
the polygon about its center by the input angle. (Note that the rotation could
change the center of the polygon. That is okay since we are only roughly
defining a center given that this polygon is completely arbitrary.)
getPoints: returns an array consisting of the Points that make up the polygon.
getLines: returns an array consisting of the Lines that make up the polyhon.
7. NGon: The NGon type represents regular polygon with an arbitrary number of sides. A NGon
type instance should be created with one Point representing the center of the NGon plus
one int representing the number of sides and one double representing the side
length. The NGon type should have the following methods:
getCenter: returns a Point that represents the center of the polygon.
getSideLength: returns the length of each side of the polygon.
getNumSides: returns the number of sides of the polygon.
setCenter: takes a Point as input and moves the polygon so that its center is the
input point.
setSideLength: takes a double as input that is the new length of each side of the
polygon.
rotate: takes a double as input that represents an angle in radians, and it rotates
the polygon about its center by the input angle.
getPoints: returns an array consisting of the n Points that make up the corners of
the polygon.
getLines: returns an array containing the n Lines that make up the edges of the
polygon.
Here is a "simple" way to calculate the points and/or lines. The distance from the
center of the polygon to the midpoint of a side is n / (2 tan(Pi / n)). From that,
you can set the end points of one side. Then repeat for each side, of the n-gon.
Place point k twice as far away from point (k-2) as point (k-1) is, on a straight
line, and then rotate that point about point (k-1) by the size of the
interior/exterior angle. The interior angle is calculated by Pi (n-2) / n.
8. EquilateralTriangle: The EquilateralTriangle type represents triangle with three equal
length sides. A EquilaterlTriangle type instance should be created with one Point
representing the center of the EquilateralTriangle plus one double representing the
side length. The EquilateralTriangle type should have the following methods:
getCenter: returns a Point that represents the center of the triangle.
getSideLength: returns the length of each side of the triangle.
setCenter: takes a Point as input and moves the triangle so that its center is the
input point.
setSideLength: takes a double as input that is the new length of each side of the
triangle.
2021/4/11 EECS 132: Homework Assignment 3
file:///C:/Users/DeiDylan/Downloads/hw3.html 7/8
rotate: takes a double as input that represents an angle in radians, and it rotates
the triangle about its center by the input angle.
getPoints: returns an array consisting of the 3 Points that make up the corners of
the triangle.
getLines: returns an array containing the 3 Lines that make up the edges of the
triangle.
9. SnowFlake: The SnowFlake type represents a polygon that is a snowflake-type fractal. A
SnowFlake instance should be created with a regular polgton (Square, NGon or
EquilateralTriangle) and a int as input. The input polygon is the base shape and the int
is the number of levels of the fractal. The SnowFlake type should have the following
methods:
getBaseShape returns the base shape used for the fractal.
getNumLevels returns the number of levels of the fractal.
setNumLevels takes an int and sets the number of levels for the fractal.
getCenter returns a Point that is the center of the fractal.
setCenter takes a Point as input and moves the fractal so that the input point is
the new center.
rotate takes a double as input that represetnts an angle in radians, and it rotates
the fractal about its cetner by the input angle.
getPoints: returns an array consisting of the points that make up the corners of
the fractal.
getLines: returns an array consisting of the lines that make up the edges of the
fractal.
The way you calculate the points/lines is as follows. If the number of levels is 0,
the points/lines are the same as the base shape. Otherwise, you repeat for each
level of the fractal. Take each line of the current fractal, and you split the line ___
into four smaller lines that have the shape _/\_. You do this by splitting the line
into 3 equal pieces, and then rotate the middle piece by 60 degrees, creating _/
_ and finally adding one more segment in to create _/\_.
So, a snowflake with level 0 is just the base shape. A snowflake at level 1 is the
base shape with each line ___ of the base shape replaced by _/\_. A snowflake at
level 2 take a snowflake at level 1 and replaces each line ___ with _/\_, and so on.
Extra Credit
Create an additional types:
1. TriangleFractal: The TriangleFractal is a triangle that is drawn as a subdivision-type
fractal. A TriangleFractal instance should be created with a triangle (either Triangle or
EquilateralTriangle) and an int as input. The input triangle is the base shape and the int
is the number of levels of the fractal. The TriangleFractal type should have the
following methods:
getBaseShape returns the triangle used for the base shape of the fractal.
getNumLevels returns the number of levels of the fractal.
setNumLevels takes an int and sets the number of levels for the fractal.
getCenter returns a Point that is the center of the fractal.
2021/4/11 EECS 132: Homework Assignment 3
file:///C:/Users/DeiDylan/Downloads/hw3.html 8/8
setCenter takes a Point as input and moves the fractal so that the input point is
the new center.
rotate takes a double as input that represetnts an angle in radians, and it rotates
the fractal about its cetner by the input angle.
getPoints: returns an array consisting of the 3 points that make up the outer
corners of the fractal.
getLines: returns an array consisting of the 3 lines that make up the outer edges
of the fractal.
When a TriangleFractal is drawn, if the number of levels is 0, just the base triangle is
drawn. Otherwise,
a. Take the triangle that is the base shape of this fractal.
b. Create three Triangles, for each Triangle, use the center point plus two of the
original Triangle's endpoints.
c. Create three TriangleFractals using the new Triangles as the base shapes. Each new
TriangleFractal should have its number of levels set to be one less than this
fractal.
d. Each of the three TriangleFractals is then drawn.