/*
	Roation applet allows the user 
	to see how they mentally roatate a shape
	and see how least squares regressions lines
	are used to explain data.  After the experiment it
	computes R square and least squares regression line
	Version 1.0 - 10 Oct 1999 Chris Thiel <cct@ktb.net>
			
*/

import java.lang.*;
import java.awt.*;
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Event;
import java.util.*;

public class rotation extends Applet
{
	int MAX=72;
	int step=0, n1=0;
	
	String message=null;
	int x1[] = new int[200];
	int y1[] = new int[200];
	
	int left[] = new int[MAX];
	int right[] = new int[MAX];
	int O[] = new int[MAX];
	int Correct=0,Incorrect=0;
	
	float xMean, yMean;
	
	
    float B0, B1, R, R_square,Var_x,Var_y;
  
	
	
	int i=0;
	double t, angle =0.0;
	Color buttonColor;
	int buttonWidth=70;
	int buttonHeight=40;
	Rectangle Same,Mirror,Reset,Stat;
	Font Hel = new Font("Helvetica",1,14);
	Polygon S[] = new Polygon[12];
	boolean ShowStats=false;
	
	Date today;
	long dStart,dEnd, diff;
	
/*
	Compute is the routine called to compute the Statistical Data
*/	

	public void  compute(){
	// Now calculate regression coeffecients
    	float Sx = 0, Sy =0;
    	float Sxx = 0, Sxy = 0, Syy = 0;
    	

    	for(int i=0; i< n1; i++)
    	{
    		
      		Sx += x1[i]; 
      		Sy += y1[i];
      		
    	}
    	
    	xMean = Sx / n1;
    	yMean = Sy / n1;
    	
    	for(int i=0; i< n1; i++)
    	{
      		Sxx += (x1[i]-xMean) * (x1[i]-xMean);
      		Sxy += (x1[i]-xMean) * (y1[i]-yMean);
      		Syy += (y1[i]-yMean) * (y1[i]-yMean);
      		}
    	
    	B1=Sxy/Sxx; //slope
    	B0 = yMean - B1 * xMean;//intercept
    	R_square=(Sxy*Sxy)/(Sxx*Syy);
    	R =(float)( Math.sqrt(R_square) );
    	if (B1<0) R *=  -1;
    	
	}
	
 	private int  DegreeDiff(int n){
 		return (int)(20*Math.abs( right[n] - left[n])) % 120;
 	}
    
    public void init() {
    	//setup the buttons and such
    	buttonColor = new  Color( 200,250, 220);
	    setBackground(new Color(0xF0F0D0));
	    Same = new Rectangle ( size().width-buttonWidth-10,size().height-buttonHeight-10,buttonWidth,buttonHeight);
	    Mirror= new Rectangle ( size().width-buttonWidth-10, size().height-buttonHeight-10-buttonHeight,buttonWidth,buttonHeight);
	    Reset= new Rectangle ( 10, 10,buttonWidth,25);
	    Stat= new Rectangle ( size().width-buttonWidth-10,10,buttonWidth,25);
	   
	    // Set up Array of Polygons
	    double a,r;
	    S[0] = new Polygon();
	    // "S" Shape
	   	S[0].addPoint(-40,60);
	   	S[0].addPoint(0,60);
	   	S[0].addPoint(0,20);
	   	S[0].addPoint(40,20);
	   	S[0].addPoint(40,-10);
	   	S[0].addPoint(40,-60);
	   	S[0].addPoint(0,-60);
	   	S[0].addPoint(0,-20);
	   	S[0].addPoint(-40,-20);
	   	S[0].addPoint(-40,20);
	   	
	   	// "L" Shape 
	   	/*
	   	S[0].addPoint(-40,60);
	   	S[0].addPoint(0,60);
	   	S[0].addPoint(0,-20);
	   	S[0].addPoint(40,-20);
	   	S[0].addPoint(40,-60);
	   	S[0].addPoint(-40,-60);
	   */	   	
	   	
	   	//Make the Mirror Image
	   	S[6]= new Polygon(S[0].xpoints, S[0].ypoints,S[0].npoints);
	   	int xM[]=S[6].xpoints;
    	for (int i=0;i< S[6].npoints; i++){
    		xM[i] *=-1;
    	}
    	S[6].xpoints=xM;
    	// Make array in increments of 30 degrees
    	for (int j=1; j< 6; j++){
    		S[j+6] = new Polygon(S[6].xpoints, S[6].ypoints, S[6].npoints);
    		S[j] = new Polygon(S[0].xpoints, S[0].ypoints, S[0].npoints);
    		xM = S[j+6].xpoints;
    		int yM[]=S[j+6].ypoints;
    		int nM = S[j+6].npoints;
    		int xS[]=S[j].xpoints;
    		int yS[]=S[j].ypoints;
    		int nS = S[j].npoints;
    	
    		for (int i=0;i< S[j+6].npoints; i++){
    			a = j*(Math.PI/10.0) +Math.atan2(yM[i],xM[i]);
    			r = Math.sqrt(Math.pow(xM[i],2)+Math.pow(yM[i],2));
    			xM[i] = (int)(r * Math.cos(a));
    			yM[i] = (int)(r * Math.sin(a));
    			a = j*(Math.PI/10.0) +Math.atan2(yS[i],xS[i]);
    			r = Math.sqrt(Math.pow(xS[i],2)+Math.pow(yS[i],2));
    			xS[i] = (int)(r * Math.cos(a));
    			yS[i] = (int)(r * Math.sin(a));
    		}
    		S[j+6].xpoints=xM;
    		S[j+6].ypoints=yM;
    		S[j+6].translate(200,150);
    		S[j].xpoints=xS;
    		S[j].ypoints=yS;
    		S[j].translate(200,150);
    	}
    	// Now Translate the originals
	   	S[0].translate(200,150);
    	S[6].translate(200,150);
    	
    	//Initialze the Slides for diffent combos of Rotations and Mirror Image Pairs
    	//to grade, trials 0-35 are rotations, trails 36-71 are mirror images
    	// to see the degree difference,
    	// or my matrix of 6x6, first row 0, 2nd=20°, 3rd=40° etc... 6th=100°
    	
    	int k=0;
    	//rotations
    	for (int i=0; i< 6; i++){
    	for (int j=0; j< 6; j++){
    		left [k] =i;
    		right[k] =(i+j)%6;
    		k++;
    	}}
    	//mirror images
    	for (int i=0; i<36; i++){
    		left[k] = left[i];
    		right[k] = right[i]+6;
    		k++;
       	}
    	// Shuffle the Order
    	for (int i=0; i< MAX; i++){
    		O[i]=i;
    	}
    	for (int i=0; i<300; i++){
    		int rnd1 = (int)((MAX-1)*Math.random());
    		int rnd2 = (int)((MAX-1)*Math.random());
    		int buff = O[rnd1];
    		O[rnd1]=O[rnd2];
    		O[rnd2]=buff;
    	}
    	
    	//Initailize the timing variables
    	today = new Date();
    	dStart=today.getTime();
    	message="Click <Mirror> or <Same>";
    	n1=0; 
		repaint();
	}
	
	private int CY(int y0){
		return size().height-20-(y0/20);
	}
	private int CX(int x0){
		return (int)(70+2.7*x0);
	}
	public void paint( Graphics g ) {
		
      if (ShowStats){
      	compute();
      	g.setColor(Color.red);
		g.drawString(" n = "+n1+"  (Correct Same responses under 5 seconds)", 70 ,20);
		g.drawString(" y = "+B1+"x + "+B0, 70 ,35);
		g.drawString("r  = "+R_square, 70 ,50);
		g.drawString("2", 75 ,47);
		g.drawString("^", 74 ,32);
		


      	//Draw axes and labels
      	g.setColor(Color.black);
      	g.drawLine(CX(-10),280,CX(160),280);
      	g.drawLine(CX(-10),20,CX(-10),CY(0));
      	for (int i=0;i<101;i+=20) {
      		g.drawLine(CX(i), CY(50) ,CX(i), CY(0));
      		g.drawString(i+"°",CX(i)-5,295);
      	}
      	for (int i=500;i<5001;i+=500) {
      		g.drawLine(CX(-10), CY(i) ,CX(-8), CY(i));
      		g.drawString(i+" ms",5,CY(i)+5);
      	}
      	//Draw observations and regression line
      
      	g.setColor(Color.blue);
      	for (int i=0;i<n1;i++){
      		g.fillOval(CX(x1[i])-2,CY(y1[i])-2,4,4);
      	}
      	g.setColor(Color.red);
      	g.drawLine(CX(0),CY((int)(B0)),CX(110),CY( (int)(B1*110+B0)) );
      
      	
      	//Draw button to return
      	g.setColor( buttonColor);
		g.fill3DRect(Stat.x, Stat.y, Stat.width, Stat.height,true);
		g.setColor( Color.black);
		g.draw3DRect(Stat.x, Stat.y, Stat.width, Stat.height,true);
		g.setColor(Color.blue);
		g.setFont(Hel);
		g.drawString("Return", Stat.x+(int)(.2*buttonWidth),28);
      } else { // do the experiment 
		int degree = DegreeDiff(O[step]);
		g.drawString("Rx time = "+diff+" ms",20,290);
		g.drawString("Trail #"+step,20,270);
		g.drawString(degree+"°",20,280);
		
		
		//g.drawString(" step = "+step+" Number "+O[step]+" ["+left[O[step]]+", "+right[O[step]]+"] "+degree+"°",120,35);
		g.setFont(Hel);
		g.drawString("Correct: "+Correct+"  Incorrect: "+Incorrect,120,290);
		g.drawString(message,90,20);
		//DrawShape
		g.setColor( Color.red);
		
		
			g.setColor( Color.red);
			S[left[O[step]]].translate(-75,0);
   			g.fillPolygon(S[left[O[step]]]);
			S[left[O[step]]].translate(75,0);
		g.setColor( Color.blue);
			S[right[O[step]]].translate(75,0);
			g.fillPolygon(S[right[O[step]]]);
			S[right[O[step]]].translate(-75,0);
		
		
		//Draw Buttons
		
		g.setColor( buttonColor);
		g.fill3DRect(Same.x, Same.y, Same.width, Same.height,true);
		g.fill3DRect(Mirror.x, Mirror.y, Mirror.width, Mirror.height,true);
		g.fill3DRect(Reset.x, Reset.y, Reset.width, Reset.height,true);
		g.fill3DRect(Stat.x, Stat.y, Stat.width, Stat.height,true);
		g.setColor( Color.black);
		g.draw3DRect(Same.x, Same.y, Same.width, Same.height,true);
		g.draw3DRect(Mirror.x, Mirror.y, Mirror.width, Mirror.height,true);
		g.draw3DRect(Reset.x, Reset.y, Reset.width, Reset.height,true);
		g.draw3DRect(Stat.x, Stat.y, Stat.width, Stat.height,true);
		g.setColor(Color.blue);
		
		g.drawString("Same", Same.x+(int)(.20*buttonWidth),Same.y+(int)(.65*buttonHeight));
		g.drawString("Mirror", Mirror.x+(int)(.20*buttonWidth), Mirror.y+(int)(.65*buttonHeight));
		g.drawString("Reset", Reset.x+(int)(.15*buttonWidth),28);
		g.drawString("Stats", Stat.x+(int)(.2*buttonWidth),28);
	
	} 
}// of paint
/*
     * Mouse methods
     */
    public boolean mouseDown(java.awt.Event evt, int x0, int y0) {
     
        if ( Same.inside(x0,y0) ) {
        	today = new Date();
        	dEnd=today.getTime();
        	diff=dEnd-dStart;
        	
        	
        	
        	if (O[step] < 36){
        		message="Correct!";
        		Correct++;
        		if ((diff>100)&&(diff<6000)){ // record if Correct and done in reasonable time
        			x1[n1]= DegreeDiff(O[step]);
					y1[n1]=(int)(diff);
					n1++;
				}
        	} else {
        		message="No, last one was a mirror image";
        		Incorrect++;
        	}
        	step++;
        	if (step >71) step=0;
        	//reset stopwatch
			today = new Date();
        	dStart=today.getTime();
        } else 
        if ( Mirror.inside(x0,y0) ) {
        	today = new Date();
        	dEnd=today.getTime();
        	diff=dEnd-dStart;
        	
        	if (O[step] > 35){
        		message="Correct!";
        		Correct++;
        		if ((diff>100)&&(diff<6000)){ // record if Correct and done in reasonable time
        			x1[n1]=  DegreeDiff(O[step]);
					y1[n1]=(int)(diff);
					n1++;
				}
        	} else {
        		message="No, the last one was the same";
        		Incorrect++;
        	}
        	
        	step++;
        	if (step >71) step=0;
        	//reset stopwatch
			today = new Date();
       		dStart=today.getTime();
       		
        } else 
        if ( Reset.inside(x0,y0) ) {
        	// Shuffle the Order
    	for (int i=0; i< MAX; i++){
    		O[i]=i;
    	}
    	for (int i=0; i<300; i++){
    		int rnd1 = (int)((MAX-1)*Math.random());
    		int rnd2 = (int)((MAX-1)*Math.random());
    		int buff = O[rnd1];
    		O[rnd1]=O[rnd2];
    		O[rnd2]=buff;
    	}
    	
    	//Initailize the timing variables
    	today = new Date();
    	dStart=today.getTime();
    	n1=0;
		step=0; Correct=0; Incorrect=0;
        message ="All statistics reset!";
        repaint();	
        } else 
        if ( Stat.inside(x0,y0) ) {
        
        	//show stats
        	
        	if( n1 <3 ) {
        		message = "Not enough data yet!";
        	} else {
        		ShowStats =!ShowStats;
        	}
        	}	
       repaint();
       return true;
    }
	
  	
  	
    public boolean mouseMove(java.awt.Event evt, int x, int y) {
       y= (int)((size().height-20-y)*20);
       x= (int)((x-70)/2.7);
       if (ShowStats) getAppletContext().showStatus("Location of mouse: (" + x + ", " + y + ")");
       
               
        return true;
    }

    public void mouseEnter() {
        repaint();
    }

    public void mouseExit() {
       
        repaint();
    }
}//of applet    
    