/* @(#)Shapes.java  15 February 2006
 *
 * Copyright 2006
 * College of Computer Science
 * Northeastern University
 * Boston, MA  02115
 *
 * This software may be used for educational purposes as long as
 * this copyright notice is retained intact at the top of all files.
 *
 * To discuss commercial use of this software, contact 
 * Prof. Richard Rasala or Prof. Viera Proulx at the Northeastern 
 * University College of Computer Science: 617-373-2462.
 *
 * The principal software developer on this project is Jeff Raab.
 *
 * Should this software be modified, the words "Modified from 
 * Original" must be included as a comment below this notice.
 *
 * All publication rights are retained.  This software or its 
 * documentation may not be published in any media either in whole
 * or in part without explicit permission.
 *
 * This software was created with support from Northeastern 
 * University and from NSF grant DUE-9950829.
 */

import edu.neu.ccs.*;
import edu.neu.ccs.gui.*;
import edu.neu.ccs.codec.*;
import edu.neu.ccs.console.*;
import edu.neu.ccs.filter.*;
import edu.neu.ccs.jpf.*;
import edu.neu.ccs.parser.*;
import edu.neu.ccs.pedagogy.*;
import edu.neu.ccs.quick.*;
import edu.neu.ccs.util.*;

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.font.*;
import java.awt.image.*;
import javax.swing.*;
import javax.swing.border.*;
import java.io.*;
import java.util.*;
import java.math.*;
import java.beans.*;
import java.lang.reflect.*;
import java.net.URL;
import java.util.regex.*;
import java.text.ParseException;

public class Shapes
{

    /**
     * Returns a regular polygon shape with N vertex points
     * and the given radius r and center x, y.
     * 
     * Requires N >= 3 and r > 0.
     * 
     * @param N the number of vertex points
     * @param r the radius
     * @param x the x-position of the center
     * @param y the y-position of the center
     * @return
     */
    public static Shape regularPolygon
        (int N, double r, double x, double y)
    {
        boolean OK = (N >= 3) && (r > 0);
        
        if (! OK)
            return null;
        
        float a = (float) x;
        float b = (float) y;
        
        float radius = (float) r;
        
        float[][] vertex = new float[N][2];
        
        double angle = 0;
        double delta = 360.0 / N;
        
        for (int i = 0; i < N; i++) {
            float u = (float) MathUtilities.sindeg(angle);
            float v = (float) MathUtilities.cosdeg(angle);
            
            u = a + radius * u;
            v = b - radius * v;
            
            vertex[i][0] = u;
            vertex[i][1] = v;
            
            angle += delta;
        }
        
        return new PolygonShape(vertex);
    }
    
    
    /**
     * Returns a regular wavygon shape with N vertex points
     * and the given radius r and center x, y.
     * 
     * A wavygon is a star shape that uses a smooth curve
     * rather than straight edges.
     * 
     * The inner radius of a wavygon is half of the radius.
     * 
     * Requires N >= 3 and r > 0.
     * 
     * @param N the number of vertex points
     * @param r the radius
     * @param x the x-position of the center
     * @param y the y-position of the center
     * @return
     */
    public static Shape regularWavygon
        (int N, double r, double x, double y)
    {
        boolean OK = (N >= 3) && (r > 0);
        
        if (! OK)
            return null;
        
        int M = 2 * N;
        
        float a = (float) x;
        float b = (float) y;
        
        float outer = (float) r;
        float inner = outer / 2;
        
        float[][] vertex = new float[M][2];
        
        double angle = 0;
        double delta = 360.0 / M;
        
        for (int i = 0; i < M; i++) {
            float u = (float) MathUtilities.sindeg(angle);
            float v = (float) MathUtilities.cosdeg(angle);
            
            if ((i % 2) == 0) {
                u = a + outer * u;
                v = b - outer * v;
            }
            else {
                u = a + inner * u;
                v = b - inner * v;
            }
            
            vertex[i][0] = u;
            vertex[i][1] = v;
            
            angle += delta;
        }
        
        return new AutomaticCurve(vertex, Tangent.chordStrategy(0.25f));
    }
    
    
    /**
     * Returns the outline of a regular star shape with N
     * vertex points and the given radius r and center x, y.
     * 
     * Conceptually, a star begins with the vertices of a
     * regular polygon but connects each vertex i with
     * vertex i+K for fixed K >= 2.
     * 
     * This method returns the outline shape of such a star,
     * that is, instead of returning the edges between the
     * vertices this methods computes the boundary polygon.
     * 
     * Requires N >= 5, K >= 2, N > 2*K, and r > 0.
     * 
     * @param N the number of vertex points
     * @param K the jump between vertices
     * @param r the radius
     * @param x the x-position of the center
     * @param y the y-position of the center
     * @return
     */
    public static Shape regularStar
        (int N, int K, double r, double x, double y)
    {
        boolean OK = (N > 2 * K) && (K >= 2) && (r > 0);
        
        if (! OK)
            return null;
        
        // compute factor needed to find inner radius
        double theta = 360.0 / N;
        double phi;
        
        double x1 = 0;
        double y1 = 1;
        
        phi = K * theta;
        
        double x2 = MathUtilities.sindeg(phi);
        double y2 = MathUtilities.cosdeg(phi);
        
        phi = theta;
        
        double x3 = MathUtilities.sindeg(phi);
        double y3 = MathUtilities.cosdeg(phi);
        
        phi = (1 - K) * theta;
        
        double x4 = MathUtilities.sindeg(phi);
        double y4 = MathUtilities.cosdeg(phi);
        
        Line2D A = new Line2D.Double(x1, y1, x2, y2);
        Line2D B = new Line2D.Double(x3, y3, x4, y4);
        
        Point2D P = Geometry.intersect(A, B);
        
        double px = P.getX();
        double py = P.getY();
        
        double factor = Math.sqrt(px * px + py * py);
        double s = factor * r;
        
        int M = 2 * N;
        
        float a = (float) x;
        float b = (float) y;
        
        float outer = (float) r;
        float inner = (float) s;
        
        float[][] vertex = new float[M][2];
        
        double angle = 0;
        double delta = 360.0 / M;
        
        for (int i = 0; i < M; i++) {
            float u = (float) MathUtilities.sindeg(angle);
            float v = (float) MathUtilities.cosdeg(angle);
            
            if ((i % 2) == 0) {
                u = a + outer * u;
                v = b - outer * v;
            }
            else {
                u = a + inner * u;
                v = b - inner * v;
            }
            
            vertex[i][0] = u;
            vertex[i][1] = v;
            
            angle += delta;
        }
        
        return new PolygonShape(vertex);
    }
    
    
}

