import java.awt.Graphics;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;

/**
 * Example3Applet
 *
 * This is a template applet for animation.
 * It illustrates how to use a graphics context
 * to draw to the screen.
 *
 * @author Arthur van Hoff
 */

/* <applet code = "SpiralRotateCar" width = "1078" height="400">
 	</applet>
 */

public
class SpiralRotateCar extends java.applet.Applet implements Runnable {
	final static Color red = Color.red;
	final static Color white = Color.white;
	final static Color yellow = Color.yellow;
	final static Color black = Color.black;
	final static BasicStroke stroke = new BasicStroke(2.0f);

	int yloc,yloc_delay;
	int xloc,xloc_delay;
	double a, a_delay = 0;
	double r, r_delay = 0;
	double angle_tan;
	int delta_x; //used in angle_tan
	int delta_y; //used in angle_tan
	
	int ANGLE_INCR_RES = 25;

    int frame;
    int delay;
    Thread animator;
    /**
     * Initialize the applet and compute the delay between frames.
     */
    public void init() {
	String str = getParameter("fps");
	int fps = (str != null) ? Integer.parseInt(str) : 25; //fps
	delay = (fps > 0) ? (1000 / fps) : 100;
    }

    /**
     * This method is called when the applet becomes visible on
     * the screen. Create a thread and start it.
     */
    public void start() {
	animator = new Thread(this);
	animator.start();
    }

    /**
     * This method is called by the thread that was created in
     * the start method. It does the main animation.
     */
    public void run() {
	// Remember the starting time
	long tm = System.currentTimeMillis();
	while (Thread.currentThread() == animator) {
	    // Display the next frame of animation.
	    repaint();

	    // Delay depending on how far we are behind.
	    try {
		tm += delay;
		Thread.sleep(Math.max(0, tm - System.currentTimeMillis()));
	    } catch (InterruptedException e) {
		break;
	    }

	    // Advance the frame
	    frame++;
	}
    }

    /**
     * This method is called when the applet is no longer
     * visible. Set the animator variable to null so that the
     * thread will exit before displaying the next frame.
     */
    public void stop() {
	animator = null;
    }
	
    /**
     * Paint a frame of animation.
     */
    public void paint(Graphics g) {
		Graphics2D g2 = (Graphics2D) g;
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);	
		int x = 400; //center x , spiral start point x
		int y = 150; //center y , spiral start point y
		int x_delay = 400; //center x_delay , spiral start point x_delay
		int y_delay = 150; //center y_delay , spiral start point y_delay
		int xwheel = 6; //wheel width
		int ywheel = 3; //wheel height
		int rectWidth = 50; //car body width
		int rectHeight = 20; //car body height		
		

		if ( a <= (4*(Math.PI/ANGLE_INCR_RES)) ) 
		{   
			//sample four points before saving time delayed points for tangent calcs (car rotation)
		}
		else 
		{  
			a_delay = a - 3*(Math.PI/ANGLE_INCR_RES);  //tangent uses current x(t),y(t) verses x(t-3),y(t-3)
			r_delay = 1/Math.cos(a_delay/3);
			xloc_delay = (int) (50*Math.sin(a_delay)*r_delay);
			yloc_delay = (int) (50*Math.cos(a_delay)*r_delay);			
		}
		
		a = a + (Math.PI/ANGLE_INCR_RES);			//increment theta by PI/50
		r = 1/Math.cos(a/3);			//radius is a function of theta (epi spiral relation)
		xloc = (int) (50*Math.sin(a)*r); // x cordinate of epi spiral
		yloc = (int) (50*Math.cos(a)*r); // y cordinate of epi spiral
		//yloc = (int) (150*Math.sin(a));
		//xloc = (int) (150*Math.cos(a));	
		
		x = x + xloc; //spiral point at time t
		y = y + yloc; // "
		x_delay = x_delay + xloc_delay;  //spiral point delayed t-3
		y_delay = y_delay + yloc_delay;  // "
		delta_x = (x - x_delay); //to calc angle of line tangent to spiral
		delta_y = (y - y_delay); //to calc angle of line tangent to spiral
		angle_tan = ( Math.atan2(delta_x,delta_y) );  //angle of line tangent to spiral
		double base_angle = 270;	//to calc relative angle of car 
		double new_angle = base_angle + angle_tan; //relative angle of car to spiral
		
		g.setColor(Color.black);
		g.drawString("Frame " + frame, 0, 20);
		g.drawString("y " + y, 0, 60);
		g.drawString("x " + x, 0, 70); 
		g.drawString("y_delay " + y_delay, 0, 90); 
		g.drawString("x_delay " + x_delay, 0, 100);
		g.drawString("Tangent Angle: " + Math.rint(Math.toDegrees(angle_tan)), 0, 120); //rotation angle of car
		g.drawString("delta_x:      " + delta_x, 0, 130);
		g.drawString("delata_y:     " + delta_y, 0, 140);
		
		g.drawString("Spiral Angle: " + Math.rint(Math.toDegrees(a)), 0, 160); //rotation angle of car
		g.drawString("Rotate Angle: " + Math.rint(Math.toDegrees(new_angle)),
			0, 170); //rotation angle of car
		
		//******Rotate Car************************************************************
		//rotate car variables
		double ap = 0;				//angle of point 1
		double ap2 = Math.PI/2;		//angle of point 2
		double ap3 = Math.PI;		//angle of point 3
		double ap4 = 3*Math.PI/2;	//angle of point 4
		double ANGLE_OFFSET = Math.toRadians(210);
		int radius = 50;
		ap = ap - new_angle + ANGLE_OFFSET;
		ap2 = ap2 - new_angle + ANGLE_OFFSET;
		ap3 = ap3 - new_angle + ANGLE_OFFSET;
		ap4 = ap4 - new_angle + ANGLE_OFFSET;
		int yploc = (int) (radius*Math.sin(ap));
		int xploc = (int) (radius*Math.cos(ap));	
		int yploc2 = (int) (radius*Math.sin(ap2));
		int xploc2 = (int) (radius*Math.cos(ap2));	
		int yploc3 = (int) (radius*Math.sin(ap3));
		int xploc3 = (int) (radius*Math.cos(ap3));	
		int yploc4 = (int) (radius*Math.sin(ap4));
		int xploc4 = (int) (radius*Math.cos(ap4));	
		int ylocwindow1 = (int) ((radius+20)*Math.sin(ap));
		int xlocwindow1 = (int) ((radius+20)*Math.cos(ap));
		int ylocwindow2 = (int) ((radius+20)*Math.sin(ap2));
		int xlocwindow2 = (int) ((radius+20)*Math.cos(ap2));	

		g.drawString("ap :  " + Math.rint(ap), 0, 200);
		g.drawString("ap2:  " + Math.rint(ap2), 0, 210);
		g.drawString("ap3:  " + Math.rint(ap3), 0, 220);

		int xtri[] = {(x+xploc), x+xploc2, x+xploc3, x+xploc4, (x+xploc)};
		int ytri[] = {(y+yploc), y+yploc2, y+yploc3, y+yploc4, (y+yploc)};

		int xwindow[] = {x, (x+xlocwindow1), x+xlocwindow2, x};
		int ywindow[] = {y, (y+ylocwindow1), y+ylocwindow2, y};

		GeneralPath polyline3 = new GeneralPath(GeneralPath.WIND_EVEN_ODD,xtri.length);
		polyline3.moveTo (xtri[0], ytri[0]);
		for (int index = 1;index < xtri.length; index++) 
		{
			polyline3.lineTo(xtri[index],
				ytri[index]);
		};
		polyline3.closePath();
		g2.setPaint(red);
		g2.fill(polyline3);	

		GeneralPath polyline4 = new GeneralPath(GeneralPath.WIND_EVEN_ODD,xwindow.length);
		polyline4.moveTo (xwindow[0], ywindow[0]);
		for (int index = 1;index < xwindow.length; index++) 
		{
			polyline4.lineTo(xwindow[index],
				ywindow[index]);
		};
		polyline4.closePath();
		g2.setPaint(black);
		g2.fill(polyline4);	

//spiral drawing*****************************************************************
		
		g2.setPaint(black);
		g2.setStroke(stroke);
		//g2.draw(new Line2D.Double(x,y, 1, 1));
		//g2.draw(new Ellipse2D.Double(0,0,300,300));
		g2.draw(new Arc2D.Double(400, 0,  //far left spiral curve
			1605,
			100,
			90, 83,
			Arc2D.OPEN));
		g2.draw(new Arc2D.Double(-1200, 0,	//far right spiral curve
			1605,
			100,
			5, 90,
			Arc2D.OPEN));
		g2.draw(new Arc2D.Double(350, 100, //bottom dip
			110,
			100,
			180, 180,
			Arc2D.OPEN));
		//xloc, yloc, xwidth,yheight,startdeg,curvelength(degree)
		g2.draw(new Arc2D.Double(350, 38, //inner left spiral curve
			165,
			205,
			103, 90,
			Arc2D.OPEN));
		g2.draw(new Arc2D.Double(300, 43, //inner left spiral curve
			160,
			210,
			0, 75,
			Arc2D.OPEN));
		
    } // endpaintGrpahics
}
