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.