import java.awt.* ;
import java.awt.geom.* ;

public class PolyStar {

    Point2D.Double CenterP ;
    double RadiusL ;
    double RadiusS ;
    int nPoints ;
    int nSkip ;

    public PolyStar(Point P, int R, int n)
    // Inputs: P is a Point object storing the x and y coordinates of 
    // the center of the star; R is the radius of the star, and n is
    // the number of points on the outer-boundary of the star; e.g., 
    // a 5-point star or a 6-point star
    {
		CenterP = new Point2D.Double(P.x, P.y) ;
		if (R <= 0)
	   R = 1 ;
		RadiusL = R ;
		if (n <= 5)
	 	   n = 5 ;
		nPoints = n ;
		nSkip = (n-1)/2 ;
		computeSmallRadius() ;
    }

    public PolyStar(int x, int y, int R, int n)
    // Inputs: x and y are the coordinates of the center of the star; 
    // R is the radius of the star, and n is the number of points on 
    // the outer-boundary of the star; e.g., a 5-point star or a 
    // 6-point star
    {
		CenterP = new Point2D.Double(x, y) ;
		if (R <= 0)
	 	   R = 1 ;
		RadiusL = R ;
		if (n <= 5)
	 	   n = 5 ;
		nPoints = n ;
		nSkip = (n-1)/2 ;
		computeSmallRadius() ;
    }

    private void computeSmallRadius()
    {
		// Algorithm taken from
		// http://geometryalgorithms.com/Archive/algorithm_0104/algorithm_0104B.htm
		// Makes some garbage collection happen
		Point2D.Double P0 = new Point2D.Double(1.0,0.0) ;
		Point2D.Double P1 = RootOfUnity(nSkip, nPoints) ;
		Point2D.Double Q0 = RootOfUnity(1, nPoints) ;
		Point2D.Double Q1 = RootOfUnity(nPoints+1-nSkip, nPoints) ;
		Point2D.Double U  = new Point2D.Double(P1.x-P0.x, P1.y-P0.y) ;
		Point2D.Double V  = new Point2D.Double(Q1.x-Q0.x, Q1.y-Q0.y) ;
		Point2D.Double W  = new Point2D.Double(P0.x-Q0.x, P0.y-Q0.y) ;
		double s = (V.y*W.x - V.x*W.y) / (V.x*U.y - V.y*U.x) ;
		Point2D.Double I  = new Point2D.Double(P0.x+s*U.x, P0.y+s*U.y) ;
		RadiusS = I.distance(new Point2D.Double())*RadiusL ;
    }

    private Point2D.Double RootOfUnity(int k, int n)
    // Returns k'th n'th root of unity 
    {
		double Angle = k * 2.0 * Math.PI / n ;
		return new Point2D.Double(Math.cos(Angle), Math.sin(Angle)) ;
    }

    public Point getOuterPoint(int k)
    // Input: The point number
    // Return value: A reference to a Point object containing the 
    // x and y coordinate of the point on the outer circle.
    {
		int modK = k%nPoints ;	// Probably not necessary ...
		Point2D.Double RoU = RootOfUnity(modK, nPoints) ;
		// Two reasons for the weirdness
		//   (1), The roots of unity start with x = 1, y = 0;
		//        So we want to start with x = 0, y = 1.
		//   (2), y decreases as we go up the scrren;
		//        So we want to really start with x = 0, y = -1
		double rX = - RoU.y ;
		double rY = - RoU.x ;
		return new Point((int)(CenterP.x + RadiusL*rX), (int)(CenterP.y + RadiusL*rY)) ;
    }

    public Point getInnerPoint(int k)
    // Input: The point number
    // Return value: A reference to a Point object containing the 
    // x and y coordinate of the point on the inner circle.
    {
		int modK = k%nPoints ;	// Probably not necessary ...
		Point2D.Double RoU = RootOfUnity(2*modK+1, 2*nPoints) ;
		double rX = - RoU.y ;
		double rY = - RoU.x ;
		return new Point((int)(CenterP.x + RadiusS*rX), (int)(CenterP.y + RadiusS*rY)) ;
    }

}
