Overview

The goal of this lab is to explore and experience good object oriented design with regards to encapsulation and information hiding. The program you are going to write is simple: it takes commands from the user and produces output. Its functionality is to keep track of the bounding box for points as they are "added". The bounding box for a set of points is the smallest rectangle (aligned with the x/y axis) that contains all the points. The commands are:
  1. add x y adds another point that the bounding box needs to include. No output.
  2. box outputs the current bounding box in the format xmin < x < xmax , ymin < y < ymax.
  3. map x y prints the point (x,y) (which should be inside the bounding box) mapped into the unit square according to the following formula: newx = (x - minX)/width and newy = (y - minY)/height, where minX is the minimum x-value in the bounding box, minY is the minimum y-value in the bounding box, and width and height are the bounding box's width and height. map should return "error" if (x,y) is not in the current bounding box.
  4. done exits the program
Sample Runs
~/$ java Lab03
add 0 0
add 2 2
box
0.0 < x < 2.0, 0.0 < y < 2.0
map 1 1
0.5 0.5
map 1 1.5
0.5 0.75
add 1.8 .2
box
0.0 < x < 2.0, 0.0 < y < 2.0
add 1 3
box
0.0 < x < 2.0, 0.0 < y < 3.0
done 
 
~/$ java Lab03
add 4 5
add 9 3
add 6 7
box
4.0 < x < 9.0, 3.0 < y < 7.0
map 5 6
0.2 0.75
add 2 6
map 5 6
0.42857142857142855 0.75
box
2.0 < x < 9.0, 3.0 < y < 7.0
done

The Rules

I'm going to try and force you to use good Object Oriented Design practices. So, there are a few rules. First and foremost, in all that you do, all fields are private! Otherwise, here are my rules:
Rule 1: Rule 2: Rule 3:
You must define a class Point with at least
  • the constructor
    public Point(double x, double y)
    that initializes the points x & y appropriately,
  • the method
    public static Point read(Scanner sc)
    that reads an x and a y value from the scanner and returns the associated point, and
  • the method
    public String toString()
    that returns a String consisting of the x-coordinate, a space, and the y-coordinate.
  • the method
    public static void main(String[] args)
    that tests (in whatever way you see fit) the methods in your Point class.
Anything else you want in point is OK except that you must declare all data-members (fields) private!

Note: be prepared to add more public methods to Point as you need them working on later Steps.

Your program must be able to be run as:
java Lab03
... and it must accept exactly the input syntax described above, and produce exactly the output described above. Also, Step 3 has one more rule!
You must define a class Box with the interface shown below, and no other public methods! Of course, all fields must be private!
public class Box
{
  // constructor for Box taking a single point
  public Box(Point p) { ... }

  // constructor for Box taking two initial points
  public Box(Point a, Point b) { ... }

  // expand the bounding box (if needed) to include point p
  public void growBy(Point p) { ... }

  // given point p in the bounding box, return associated
  // point in the unit square (see notes); return null if
  // p is not inside the bounding box.
  public Point mapIntoUnitSquare(Point p) { ... }

  // returns string representation like: 
  // 2.0 < x < 9.0, 3.0 < y < 7.0
  public String toString() { ... }
}
Note: Just to explain the one-argument constructor, the bounding box around point p should be the "empty box" around that point. For example
Point p = new Point(3,5);
Box B = new Box(p);
String s = B.toString();
System.out.println(s);
... would print out 3.0 < x < 3.0, 5.0 < y < 5.0

Step 1: Get to the Point

You know you're going to want a class Point. Go ahead and write it. Think first of what operations you're likely to need, and then start writing them one-by-one. Make sure to have a
public static void main(String[] args)
you can use to test as you go. Keep adding new code that tests each new function as you add it, but don't get rid of the old tests. When you're done with the program, main() should be a complete test suite you can run to verify that Point works the way it should!

Step 2: Think inside the Box

Now start implementing the Box class. Start with the one-argument constructor and the toString() function. Be sure to include a main() that tests them. Then start adding the other methods, testing as often as you can, and never deleting tests from main(). You may find that you have to go back and add some new methods to Point as you go along. That's OK. Be sure to re-test whenever you do, though!

Note1: you might find the methods Math.max and Math.min useful!

Note2: from a design perspective, operations that you need that make sense for points generally, i.e. are not necessarily only things someone would want for the Box class, should be done in the Point class. Only things that are really specific to dealing with the Box concept should be in the Box class. So if you find yourself wanting to get at x and y coordinate data fields of Point from code in the Box class, you should ask yourself whether providing a new method in class Point would work instead.

Step 3: Get with the Program

Finally, write the class Lab03. It should be a breeze now that you've got Box and Point written.
~/$ java Lab03
asdf
Error! Unknown command "asdf"!  
add 2 2
box
2.0 < x < 2.0, 2.0 < y < 2.0
add 5 1.5
box
2.0 < x < 5.0, 1.5 < y < 2.0
add 2.5 2.5
box
2.0 < x < 5.0, 1.5 < y < 2.5
done
~/$ java Lab03
add 2.8 -1.8
add -3.0 -3.5
box
-3.0 < x < 2.8, -3.5 < y < -1.8
map 0 0
error
map -2 -2
0.1724137931034483 0.8823529411764706  
add 2.5 2.5
box
-3.0 < x < 2.8, -3.5 < y < 2.5
map -2 -2
0.1724137931034483 0.25
done

To Submit:

submit -c=IC211 -p=lab03 Point.java Box.java Lab03.java

Step 4: [Going Further] How well did you follow the rules?

Let's see if you followed the rule. Find a classmate who has finished the other steps as well. Copy his/her Point.class and Box.class into a new directory, and copy your Lab03.class in there as well. Run java Lab03 Did it work? If you followed the rules, it has to work! That's the beauty of separating interface and implmentation! As long as the interface elments you rely on stay the same, you can change the the implementation behind it as much as you like.