// By Jan Axelsson23/10 1997
//
// This applet is meant as an excercise in vector addition
// This applet reads  parameters from the associated HTML file.
// The number of pixels between scale lines are thus defined in HTML file.
// The Paint method draws the coordinate system and the two vectors
// which are randomized initially, or when "new" button is pressed.
// The randomizing of the two vectors is triggered by a flag.
// The "hint" button draws the translated vectors to form a parallellogram.
// The "vector sum" button gives the answer.
// So far arrow heads are represented by filled circles, since that was easier to code.

import java.awt.*;
import java.lang.*;

//---------------------------------------------------------------------------------------------
public class VectorAdd extends java.applet.Applet{
	
	Point p0= new Point(0,0);	// Starting point for vectors
	Point v1=new Point(10,10);// First vector
	Point v2=new Point(10,10);// Second vector
	Point guess;				// guessed coordinates
	
	int xStep=15;				// Number of pixels between gridlines in x-direction
	int yStep=15;				// Number of pixels between gridlines in  y-direction
	int xMax=300;				// Maximum x-pixel shown
	int yMax=300;				// Maximum y-pixel shown
	
	Point origo; 				// screen coordinates for origo, definied in init()

	int arrowLength=30;		// Length of arrow head
	int arrowWidth=30;  		// Half width of arrow head

	Graphics g;
	
	Font fPlain=new Font("TimesRoman", Font.PLAIN,12);
	Font fBold=new Font("TimesRoman", Font.BOLD,12);

	FontMetrics fmBold=getFontMetrics(fBold);
		
	boolean newVectorFlag=true;	//true only after new button is pressed, reset in paint()
		
//---------------------------------------------------------------------------------------------
	public void init(){
		// read xStep, yStep, xMax, yMax from HTML parameters
		String temp;
		temp=getParameter("xStep");
		if (temp!=null) xStep=Integer.parseInt( temp);
		temp=getParameter("yStep");
		if (temp!=null) yStep=Integer.parseInt( temp);
		temp=getParameter("xMax");
		if (temp!=null) xMax=Integer.parseInt( temp);
		temp=getParameter("yMax");
		if (temp!=null) yMax=Integer.parseInt( temp);
		
		origo=new Point(xMax/2, yMax/2);
		
		resize(xMax+1, yMax+1);
		g=getGraphics();
		
		setLayout( new FlowLayout(FlowLayout.LEFT));
		add(new Button("hint"));
		add(new Button("vector sum"));
		add(new Button("new"));
	}
//---------------------------------------------------------------------------------------------
	public boolean mouseDown(Event evt, int x, int y){
		guess=new Point(Math.round( (x-origo.x)/xStep ),
						 Math.round(-(y-origo.y)/yStep));
		if (guess.equals(Add(v1,v2))){
		 	g.drawString("Great!",size().width/5,size().height*4/5);
		 	drawSum();
		 }
		 	
		return true;
	}
//---------------------------------------------------------------------------------------------
	public boolean mouseMove(Event evt, int x, int y){
		guess=new Point(Math.round( (x-origo.x)/xStep ),
						 Math.round(-(y-origo.y)/yStep));

		g.setFont(fBold);
		g.setColor(Color.white);
		g.fillRect(0,size().height-fmBold.getHeight(),100,size().height);
		g.setColor(Color.black);
		g.drawString("("+guess.x+", "+guess.y+")", 0,size().height-fmBold.getDescent());
		return true;
	}
//---------------------------------------------------------------------------------------------
	public boolean action(Event evt, Object arg){
		String actionName=(String) arg;

		if (evt.target instanceof Button){
			if ("hint".equals((String) arg))
					drawHelp();
			else if (actionName.equals("vector sum")) 
				drawSum();
			else if (actionName.equals("new")) {
				newVectorFlag=true;
				repaint();
			}
		}

		
		return true;
	}
//---------------------------------------------------------------------------------------------
	public void drawSum(){
		Point sum;
		sum= Add(v1, v2);
	    g.setColor(Color.red);
		drawVector(g,p0,sum);
	}
//---------------------------------------------------------------------------------------------
	public void drawHelp(){
		Point sum;
		sum= Add(v1, v2);
		g.setColor(Color.green);
		drawVector(g, v1, sum, false);
		drawVector(g, v2, sum, false);
	}
//---------------------------------------------------------------------------------------------
	public void drawCoordinates(Graphics g){
	// function which draws grid with spacing xStep, yStep (unit pixels)
	// and places a filled circle at (0,0)	
		setBackground(Color.white);
		g.setColor(Color.cyan);
		
		for (int ix=origo.x;ix<=size().width;ix=ix+xStep)
			g.drawLine(ix, 0,ix, size().height);
		for (int ix=origo.x;ix>=0;ix=ix-xStep)
			g.drawLine(ix, 0,ix, size().height);
			
		for (int iy=origo.y;iy<=size().height;iy=iy+yStep)
			g.drawLine(0, iy, size().width, iy);
		for (int iy=origo.y;iy>=0;iy=iy-yStep)
			g.drawLine(0, iy, size().width, iy);
			
		// draw dot representing origo
		int radius=4;
		g.fillOval(origo.x-radius, origo.y-radius, 1+2*radius, 1+2*radius);	
	}
//---------------------------------------------------------------------------------------------
	public Point Add(Point v1, Point v2){
		return new Point(v1.x+v2.x, v1.y+v2.y);
	}
//---------------------------------------------------------------------------------------------
	public void drawVector(Graphics g,Point p1, Point p2, boolean extras){
	// function which draws vector from point p1 to point p2
		// here follows the screen coordinates
		int x1=origo.x+p1.x*xStep;
		int x2=origo.x+p2.x*xStep;
		int y1=yMax-(origo.y+p1.y*yStep);
		int y2=yMax-(origo.y+p2.y*yStep);
		// draw the line, the labels, and the arrow head
		g.drawLine(x1, y1, x2,y2);
		if (extras){
			g.drawString("("+p2.x+","+p2.y+")",x2,y2);
			drawArrowHead(g, new Point(x1,y1), new Point(x2,y2));
		}
	}
//---------------------------------------------------------------------------------------------
	public void drawVector(Graphics g,Point p1, Point p2){
		// if no boolean variable, then draw vector with labels and arrowhead
		drawVector(g, p1, p2, true);
	}
//---------------------------------------------------------------------------------------------
	public void drawArrowHead(Graphics g,Point p1, Point p2){
		// inputs the screen coordinates for the vector
		// p1 is first point, p2 second point
//		double alpha=Math.atan( (p2.y-p1.y)/(p2.x-p1.x)); 	//angle for vector
//		double L=Math.sqrt( (p2.x-p1.x)^2 + (p2.y-p1.y)^2 );	// vector length
//		double aL=L-(double) arrowLength;
//		double beta= Math.atan( arrowWidth/aL); // angle to arrow corner from p1
//
//		int xData [] ={p1.x+(int)(L*Math.cos(alpha)),
//						p1.x+(int)(aL*Math.cos(alpha+beta)),
//						p1.x+(int)(aL*Math.cos(alpha-beta)),
//						p1.x+(int)(L*Math.cos(alpha))};
//		int yData [] ={p1.y+(int)(L*Math.sin(alpha)),
//						p1.y+(int)(aL*Math.sin(alpha+beta)),
//						p1.y+(int)(aL*Math.sin(alpha-beta)),
//						p1.y+(int)(L*Math.sin(alpha))};	
//							
//		Polygon poly = new Polygon (xData, yData, 4);
//		g.fillPolygon(poly);
		
		// draw dot representing arrow head	
		int radius=3;
		g.fillOval( p2.x-radius, p2.y-radius, 1+2*radius, 1+2*radius);			
	}
//---------------------------------------------------------------------------------------------
	public void paint (Graphics g){
	
		g.setFont(fPlain);
		// new vectors
		if (newVectorFlag==true){
			v1.x=(int)(0.5*xMax/xStep*(0.5-Math.random() ));
			v1.y=(int)(0.5*yMax/yStep*(0.5-Math.random() ));
			v2.x=(int)(0.5*xMax/xStep*(0.5-Math.random() ));
			v2.y=(int)(0.5*yMax/yStep*(0.5-Math.random() ));
		}
		newVectorFlag=false;
		
		// draw coordinate system
		drawCoordinates(g);
		
		// draw individual vectors
       	g.setColor(Color.blue);
		drawVector(g,p0,v1);
		drawVector(g,p0,v2);
	} 
//---------------------------------------------------------------------------------------------

}

