CPTR 124 Fundamentals of Programming
In this lab you will design and implement your own class given some minimal requirements. You will determine the needed instance variables and implement methods that conform to a specified interface that client code expects. In the process you will organize your classes into a Java package.
- Teams. You may work with a partner on this lab. You may partner with anyone in this class, but it is
helpful if one of you remembers how to compute slopes, intercepts, etc. from high school algebra class.
Please submit only one check sheet containing both partners' names.
You may work alone if you insist.
- Housekeeping. Create a project named Lab7.
In your Lab7 project, create a package named Geometry.
The Point and Line classes described below are to be part of
this Geometry package.
- Geometric Primitives. Several primitives are used in geometry:
- Two-dimensional geometric points are real number pairs (x, y). We'll approximate real numbers with double precision floating point numbers.
- A geometric line is an infinite set of colinear points. A line can be defined by two nonequal points on that line, and are often represented by an equation.
- Point Class. Create a Point class in your Geometry package that
provides the functionality of two-dimensional geometric
points. Specifically:
- You must be able to create a Point object using any of
three constructors:
- one that takes two doubles (the x and y coordinates),
- one that takes a reference to a Point object (a new Point object is created with the same x and y coordinates), and
- a default constuctor with no arguments that creates a point at the origin (0,0).
- Write a toString() method that takes no
arguments and returns a String object. It
shows the point in a nice human-readable form.
Whenever Java needs to convert an object to a string
(for example, when calling
System.out.println()), the object's
toString() method is called:
Point pt = new Point(3, 4); // Prints "pt = (3.0,4.0)" System.out.println("pt = " + pt);
Use a DecimalFormat object with the format string "0.##" to limit the display of the double precision floating point numbers to two digits after the decimal point. This DecimalFormat can be shared by all Point objects (that is, make it a static field of the Point class).
The difference between using a DecimalFormat object and our trusty System.out.printf() is that printf will always show the two decimal places, but our format object will show at most two decimal places.
- Include accessor methods to read a point's
coordinates:
- getX(): returns the x coordinate of the point
- getY(): returns the y coordinate of the point
There should be no other way for code outside the Point class to determine a point's x or y coordinate values.
- Include a distance() method that computes the
distance to a point passed into it:
Point pt1 = new Point(3, 4); System.out.println("pt1 = " + pt1); Point pt2 = new Point(15, 10); // Prints "Distance: 13.416407864998739" System.out.println("Distance: " + pt1.distance(pt2));
As you can see, to find the distance between points pt1 and pt2, use
pt1.distance(pt2)
The call
pt2.distance(pt1)
would work just as well.
(Don't forget that your Point class should be a part of your Geometry package.)
- You must be able to create a Point object using any of
three constructors:
- Line Class. Create a Line class in your Geometry package that
provides the functionality of two-dimensional geometric lines.
Specifically:
- You must be able to create a Line object. Its only
constructor accepts two nonequal Point objects
that determine the line. The constructor's behavior is
undefined if the two points passed to it are equal. (Being
undefined means you don't have to worry what your program does
if a client attempts to create such a line.)
While clients create a Line object with two points, these actual points are not useful after the line is created. You should precompute the slope and y-intercept (or x-intercept, as appropriate) and let these two values define the state of a line object. (See below for more information about intercepts.)
This information about the slope and intercept should not be directly accessible by clients. Clients can see these values via methods (see below) but cannot change them. This means that lines, like points, are immutable objects.
- Include a slope() method that returns the
slope of the line. Recall that a vertical line has an
undefined slope. We'll let our vertical lines have a slope of
Double.POSITIVE_INFINITY, a static final value
(obviously respresenting positive infinity)
publically available in the java.lang.Double class.
- Include an intercept() method that returns:
- for a non-vertical line, the y coordinate of the point of intersection with the y-axis, or
- for a vertical line, the x coordinate of the point of intersection with the x-axis.
- Write a toString() method that takes no
arguments and returns a String object. It
shows the equation of the line
in a nice human-readable form. The equation
should be in slope-intercept form: y = mx + b.
For example:
Line myLine = new Line(new Point(3, 4), new Point(15, 10)); // Prints "Line: y = 0.5x + 2.5" System.out.println("Line: " + line);
Careful! Recall that a horizontal line that crosses the y-axis at 3 has the equation
y = 3 and a vertical line that crosses the x-axis at 3 has the equation
x = 3 Your program should handle these situations correctly.
As with the Point class (see above), use a shared DecimalFormat object to limit numeric values to two decimal places.
- Include a satisfies() method that accepts a
single Point as a parameter and returns a
boolean value indicating whether or not the
point is on the line.
How do you determine if a point satisfies a line? If you know the line's slope and intercept (i.e., the line's equation), you simply plug in the x and/or y values of the point and see if the equality holds:
- for y = mx + b, plug in x and see if you get y
- for y = c, where c is some number, y has to equal c (x does not matter)
- for x = c, where c is some number, x has to equal c (y does not matter)
- Include an intersect() method that accepts a
single Line as a parameter and returns a
Point object indicating the point of
intersection of the two lines. If the lines are
parallel, the result is null.
How do you compute the point of intersection of two lines?
- If the two lines have the same slope, there is no single point of intersection. That's why we return a null reference.
- If neither line is horizontal or vertical, we have a pair of equations that look like
y = m1x + b1 since both righthand expression equal y, set them equal to each other:
y = m2x + b2m1x + b1 = m2x + b2 and solve for x:m1x - m2x + b1
=
m2x - m2x + b2
m1x - m2x + b1
=
b2
m1x - m2x + b1 - b1
=
b2 - b1
m1x - m2x
=
b2 - b1
(m1 - m2)x
=
b2 - b1
x
=
(b2 - b1)/ (m1 - m2)
This final equation
x = (b2 - b1)/ (m1 - m2) serves as a formula to compute x. Once you have x you can plug it into either of the original equations to compute y. The x and y values are then used to create the required point.
- If one of the lines is horizontal or vertical, you know immediately one of the coordinates (x for vertical lines and y for horizontal lines). Plug the known value into the equation for the other line to compute the other coordinate.
- If one of the lines is horizontal and the other is vertical, you know immediately one of the coordinates (the x coordinate comes from the vertical line and the y coordinate comes from the horizontal line).
- You must be able to create a Line object. Its only
constructor accepts two nonequal Point objects
that determine the line. The constructor's behavior is
undefined if the two points passed to it are equal. (Being
undefined means you don't have to worry what your program does
if a client attempts to create such a line.)
- Handling Floating Point Imprecision.
Since floating point numbers are imprecise, the == operator may not
work as expected when comparing floating point numbers. The == operator tests for
exactly matching bit patterns between its two operands. Because of the imprecise
representation, a computed value for
25 may be 24.99999 or 25.000001 instead of exactly 25. This means that a point that supposed
to be on a line (when computing satisfies()) may not really appear to be on the
line!
A better approach, for our situation,
is to test to see if the absolute
value of the difference is less than a small value. For example, if a and b
are floating point numbers, instead of using
a == b write a class method named equals() that accepts two doubles and returns the result of the following comparison:
|a - b| < 0.0001 (The vertical bars mean absolute value.) This, in effect, says "The values of a and b are so close that we consider them equal."
In your equals() method treat Double.POSITIVE_INFINITY specially. Use == to see if a and b are both Double.POSITIVE_INFINITY; if so, return true. If one is == to Double.POSITIVE_INFINITY but the other is not, then return false. If neither a nor b are Double.POSITIVE_INFINITY, then proceed with the absolute value of the difference code mentioned above. This procedure will suffice for this program.
- Class Organization.
As mentioned above, place your Point and Line in a package named
Geometry.
- Test Code. Your two classes should work with the
code provided
here (GeometryTest.java).
This GeometryTest class should reside in the default package of your
Lab7 project. The output of
this test program can be found
here, but, more
importantly, your code should work with any Java
program that needs to use these geometric objects and
respects
the interface described above. Your class may be
tested against other Java code, not just the one
provided above. Feel free to write other test programs
to exercise your code.
- Coding Conventions. As always, use the standard Java
coding style conventions.
- Submission. When you believe the program works correctly:
- recheck your style to make sure it is similar to the Sun guidelines,
- let me check and review your lab with you,
- get a Lab Report (one per team),
- close your project, exit Eclipse, and log out from your workstation.