CPTR 124 Fundamentals of Programming


In this lab you will design and implement two classes given some minimal requirements. You will determine the needed instance variables and implement methods that conform to a specified interface that client code expects.


  1. Teams

    You are encouraged to work with a partner for this lab. You and your partner should begin thinking about the problems and begin writing the code before lab time.

  2. Preparing your working folder

    Make a subfolder named Lab6 within your H:\cptr124 folder.

  3. 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 lines are often represented by an equation.

  4. Point Class. Create a Point class that provides the functionality of a two-dimensional geometric point. Specifically:

    1. 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 (the constructor here creates a new Point object with the same x and y coordinates as the parameter), and
      • a default constuctor with no arguments that creates a point at the origin (0,0).

    2. 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);
      		 

    3. 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
      See the sample client code for examples of their usage. Notice that clients can examine the x and y values of a point object, but clients cannot modify them. This means that Point objects are immutable.

      There should be no other way for code outside the Point class to determine a point's x or y coordinate values.

    4. 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.

      In mathematics, the distance between two points (x1,y1) and (x2, y2), is given by the formula

      Distance formula

      The Math.sqrt() method can be used to compute the square root; for example, the following statement will assign 5 to d:

      		d = Math.sqrt(25);
      		

      To square an expression, just multiply it to itself, as in:

              (x2 - x1) * (x2 - x1)
              

  5. Line Class. Create a Line class that provides the functionality of two-dimensional geometric lines. Specifically:

    1. 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, if it is a vertical line) 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.

    2. 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.

    3. 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.
      Thus, intercept() returns the y-intercept when called on a non-vertical line, and it returns the x-intercept when called on vertical lines.

    4. 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.

    5. 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)

    6. 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
        y = m
        2x + b2
        since both righthand expression equal y, set them equal to each other:
        m1x + 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 both of the coordinates (the x coordinate comes from the vertical line and the y coordinate comes from the horizontal line).

  6. 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."

    The Math.abs() method can be used to find the absolute value, as in: Math.abs(-5) (which equals 5).

    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.

  7. Test Code. Your two classes should work with the code provided here (GeometryTest.java). 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 will be tested against other Java code, not just the one provided above. Feel free to write other test programs to exercise your code.

  8. Check out

    Provide your Point.java and Line.java sources files to tested by an automated test suite. If your code contains errors, you may retest it twice. After the third test, your grade will be based on the number of remaining errors. After your code passes all the tests or after three unsuccessful testing tries (whichever comes first), submit a printout of both of your source files. Be sure your name and your partner(s) names are included on the printout.

    Important: All testing must be completed by the due date. Code printouts without official testing are unacceptable.