// (c) MIT 2003.  All rights reserved.

///////////////////////////////////////////////////////////////////////////////
//
// FILE:	GPoint.java
//
// AUTHOR:	Manoj D. Muzumdar
//		archon@ai.mit.edu
//
// DATE:	06-XX-98
//
// COPYRIGHT:	Massachusetts Institute of Technology
//		All rights reserved.
//
// PURPOSE:	Geometric modeling
//
// HISTORY:     11-06-98 archon
//              Made mutable
//
///////////////////////////////////////////////////////////////////////////////

package rec.geo;

import java.awt.*;
import rec.util.*;

/**
 * A GPoint is a mutable representation of a point in two-dimensional space.
 */
public class GPoint extends GShape
{
  /**
   * @param angle   The angle in radians.
   */
  public static GPoint fromPolar( double magnitude, double angle )
  {
    return( Geometry.toRectangular( magnitude, angle ) );
  }

  //////////////////////////////////////////////////////////////////////////////

  public GPoint( int x, int y )
  {
    this.x = (new Double( x )).doubleValue();
    this.y = (new Double( y )).doubleValue();
  } 

  public GPoint( double x, double y )
  {
    this.x = x;
    this.y = y;
  }

  public GPoint( GPoint gp )
  {
    x = gp.x;
    y = gp.y;
  }

  //////////////////////////////////////////////////////////////////////////////

  public GShape copy()
  {
    return( new GPoint( this ) );
  }

  public void reflect()
  {
    double tmp = x;

    x = y;
    y = tmp;
  }

  public void translate( double dx, double dy )
  {
    x = x + dx;
    y = y + dy;
  }

  public void rotate( GPoint gp, double angle )
  {
    GPoint ngp = Geometry.locatePoint( gp,
				       Geometry.distance( gp, this ),
				       Geometry.angle( gp, this ) + angle );

    x = ngp.x;
    y = ngp.y;
  }

  public double dotProduct( GPoint gp )
  {
    return ( gp.x * x ) + ( gp.y * y );
  }

  public double crossProduct( GPoint gp )
  {
    return (x * gp.y) - (gp.x * y);
  }
  
  public GPoint minus( GPoint gp )
  {
    return new GPoint( x - gp.x, y - gp.y );
  }
  
  

  //////////////////////////////////////////////////////////////////////////////

  public double size()
  {
    // A point has no size.
    return( 0.0 );
  }

  public void resize( double scaleFactor )
  {
    // A resized point is that original point.
  }

  //////////////////////////////////////////////////////////////////////////////

  public Rectangle getBounds()
  {
    return( new Rectangle( getIntX() - 1, getIntY() - 1, 2, 2 ) );
  }

  //////////////////////////////////////////////////////////////////////////////

  /**
   * A point is not displayed.
   */
  public void display( Graphics g )
  {
  }

  //////////////////////////////////////////////////////////////////////////////
  public boolean contains( GPoint gp )
  {
    return( equals( gp ) );
  }

  public boolean includes( GPoint gp )
  {
    return( equals( gp ) );
  }

  public boolean includes( GPoint gp, double offset )
  {
    Assert.check( offset >= 0.0, "offset cannot be negative" );

    return( Geometry.distance( this, gp ) <= offset );
  }

  //////////////////////////////////////////////////////////////////////////////

  public Point getPoint()
  {
    return( new Point( getIntX(), getIntY() ) );
  }

  public int getIntX()
  {
    return( (int)Math.rint( x ) );
  }

  public int getIntY()
  {
    return( (int)Math.rint( y ) );
  }

  public double getX() 
  {
    return x;
  }
  
  public double getY() 
  {
    return y;
  }
  

  //////////////////////////////////////////////////////////////////////////////

  public double getMagnitude()
  {
    return( Geometry.distance( ORIGIN, this ) );
  }

  /**
   * @return   The angle in radians.
   */
  public double getAngle()
  {
    return( Geometry.angle( ORIGIN, this ) );
  }

  //////////////////////////////////////////////////////////////////////////////

  /**
   * @param angle  The angle in radians.
   */
  public GPoint locatePoint( double magnitude, double angle )
  {
    return( Geometry.locatePoint( this, magnitude, angle ) );
  }

  //////////////////////////////////////////////////////////////////////////////

  public boolean equals( GPoint gp )
  {
    return( gp.x == x && gp.y == y );
  }

  public boolean equals( Object p )
  {
    if ( p instanceof GPoint )
      return equals( (GPoint)p );
    else
      return false;
  }

  public int hashCode( )
  {
    return (int)( x + y );
  }


  ////////////////////////////////////////////////////////////////////////////

  public String toString()
  {
    return( "[" + ( (int)x ) + "," + ( (int)y ) + "]" );
  }

  ////////////////////////////////////////////////////////////////////////////

  public double x;
  public double y;

  ////////////////////////////////////////////////////////////////////////////

  public static final GPoint ORIGIN = new GPoint( 0.0, 0.0 );
}

/////////////////////////////////////////////////////////////////////////////
