// Arup Guha
// 2/14/06
// Program created in class to illustrate how to create a compareTo
// method and then test that method.

import java.io.*;
import java.util.*;

public class Point implements Comparable {

  // Stores a standard Cartesian Point.
  private double x;
  private double y;

  // Used for comparisons of equality between doubles.
  final static double EPSILON =  0.000001;

  // Standard constructor.
  public Point(double x_val, double y_val) {
    x = x_val;
    y = y_val;
  }

  // Implements a compareTo method. Point objects closer to the origin
  // come before those farther from the origin. For points that are
  // equidistant from the origin within a tolerance of 10^-6, the angle
  // they form with the origin breaks the tie. Points with smaller angles
  // come before those with greater angles in this situation.
  public int compareTo(Object o) {

    if (o instanceof Point) {

      Point temp = (Point)o;

      // Calculate the difference in distances between this and o/temp.
      double difference = this.Distance() - temp.Distance();

      // The difference is significant.
      if (Math.abs(difference) > EPSILON)

        // Current object comes first.
        if (difference < 0)
          return -1;

        // o comes first.
        else
          return 1;  
 
      // Only check the difference in angles if distances are (almost) same.

      // this comes first.
      if (this.Angle()-temp.Angle() < 0)
        return -1;

      // o/temp comes first.
      else if (this.Angle()-temp.Angle() > 0)
        return 1;

      // They are equal!!!
      else
        return 0;
    }

    // Random default answer.
    else
      return -1;
  }

  // Returns the distance of the current object from the origin.
  public double Distance() {
    return Math.sqrt(x*x+y*y);
  }

  // Returns the angle formed by the positive x-axis and the vector from
  // the origin to this Point.
  public double Angle() {

    // Quadrants I and II.
    if (y >= 0) {

      // The cosine of an angle is the x-value divided by the distance
      // of that point from the origin.
      return Math.acos(x/Distance());
    }

    // Otherwise, since cos is an even function, we can just subtract
    // the answer of acos from 2PI.
    return 2*Math.PI - Math.acos(x/Distance());

  }

  // Returns the String representation of this object.
  public String toString() {
    return "("+x+", "+y+")";
  }

  public static void main(String[] args) throws IOException {

    // Create an array of Point objects.
    Point[] points = new Point[10];

    // Fill in our points array with various points that are different
    // distances and angles from the origin.
    points[0] = new Point(1,1);
    points[1] = new Point(2,2);
    points[2] = new Point(1.9999998,2);
    points[3] = new Point(-6,8);
    points[4] = new Point(8,8);
    points[5] = new Point(-8,8);
    points[6] = new Point(16,9);
    points[7] = new Point(15,14);
    points[8] = new Point(15,15);
    points[9] = new Point(14,15);
 
    // Sort these points.
    Arrays.sort(points);

    // See if they print out the way we want.
    for (int i=0; i<points.length; i++)
      System.out.println(points[i]);
  }

}
