/**
 * @author
 *  Behrooz Badii 	bb2122@columbia.edu
 *  Hanhua Feng         hanhua@cs.columbia.edu
 *  Edan Harel 	        edan@columbia.edu
 */
package CookieCutter.g6;

import java.io.Serializable;

/**
 *  A point on the xy-plane.
 */
public class Point implements Serializable {
    static final Point ORIGIN = new Point( 0, 0 );

    private double _x;          // the x-coordinate
    private double _y;          // the y-coordinate    

    /** construct a point with x- and y-coordinates
     */
    public Point( double x, double y ) {
        _x = x;
        _y = y;
    }

    /** get the x coorindate
     */
    public final double x() {
        return _x;
    }

    /** get the y coordinate
     */
    public final double y() {
        return _y;
    }

    /** set the x coorindate: make sure the object is not shared
     */
    final void setX( double x ) {
        _x = x;
    }

    /** set the y coordinate: make sure the object is not shared
     */
    final void setY( double y ) {
        _y = y;
    }

    /** test whether the distance of two points are within the epsilon
     * value.
     */
    public final boolean equals( Point p ) {
        return distance( p) <= Plane.EPS;
    }

    /** calculate the distance between this point to the origin.
     */
    public final double distance() {
        return Math.sqrt( _x*_x + _y*_y );
    }

    /** calculate the distance between this point to point p.
     */
    public final double distance( Point p ) {
        return distance( p.x(), p.y() );
    }

    /** a shortcut of distance computation
     */
    public static final double distance( double x0, double y0, 
                                         double x1, double y1 ) {
        return Math.sqrt( (x0-x1)*(x0-x1) + (y0-y1)*(y0-y1) );
    }

    /** for speed-up
     */
    public static final double sqdistance( double x0, double y0, 
                                           double x1, double y1 ) {
        return (x0-x1)*(x0-x1) + (y0-y1)*(y0-y1);
    }

    /** calculate the distance between this point to point (x,y).
     */
    public final double distance( double x, double y ) {
        return Math.sqrt( (x-_x)*(x-_x) + (y-_y)*(y-_y) );
    }

    /** do a coordinate transform according to the transform matrix
     */
    public Point transform( double[] mat ) {
        return new Point( _x * mat[0] + _y * mat[1] + mat[2],
                          _x * mat[3] + _y * mat[4] + mat[5] );
    }

    /** translate a point by an offset of (xt,yt).  Equivalently,
     * transform to a parallel coordinates whose origin is at
     * (-xt,-yt).
     */
    public final Point translate( double xt, double yt ) {
        return transform( new double[]{ 1.0, 0.0, xt, 0.0, 1.0, yt } );
    }

    /** rotate a point counter-clockwisely at the origin by an angle
     * of alpha.  Equivalently, transform to a new coordinate systems
     * rotated whose x-axis has an angle of -alpha wrt the old system.
     */
    public final Point rotate( double alpha ) {
        return transform( Plane.transmatrix( 0, 0, -alpha ) );
    }  

    /** rotate a point counter-clockwisely at (x0,y0) by an angle of alpha.
     * Equivalently, transform to a new coordinate systems rotated
     * whose x-axis has an angle of -alpha wrt the old system.
     */
    public final Point rotate( double x0, double y0, double alpha ) {
        return transform( Plane.rotatematrix( x0, y0, -alpha ) );
    }  

    /** rotate a point counter-clockwisely by alpha, then translate
     * by offset of (xt,yt)
     */
    public final Point place( double xt, double yt, double alpha ) {
        return transform( Plane.transmatrix( -xt, -yt, -alpha ) );
    }

    /** get the midpoint of two points
     */
    public final Point midpoint( Point p ) {
        return new Point( ( _x + p._x ) * 0.5, ( _y + p._y ) * 0.5 );
    }

    public String toString() {
        StringBuffer sb = new StringBuffer();

        sb.append( "(" );
        sb.append( Plane.format(_x) );
        sb.append( "," );
        sb.append( Plane.format(_y) );
        sb.append( ")" );

        return new String(sb);
    }
}
