package utilities;
import gameObjects.Flag;
import gameObjects.GameObject;

/*
 * Created on 04.10.2004
 */

/**
 * @author Soccer Group I
 */
public class Geometrie {
	
	static double sqr (double x) {
		return x * x;
	}
	
	/***********************************************************
	 * Konvertiert einen Winkel aus dem Gradmass ins Bogenmass
	 * @param degAngle ein Winkel im Gradmass
	 * @return der konvertierte Winkel im Bogenmass
	 ***********************************************************/
	public static double deg2rad(double degAngle){
	    return degAngle * Math.PI / 180;
	}

	/***********************************************************
	 * Konvertiert einen Winkel aus dem Bogenmass ins Gradmass
	 * @param radAngle ein Winkel im Bogenmass
	 * @return der konvertierte Winkel im Gradmmass
	 ***********************************************************/
	public static double rad2deg(double radAngle){
	    return radAngle * 180 / Math.PI;
	}
	
	public static Vektor getPosition (Vektor f1, Vektor f2, double d1, double d2, double winkel1, double winkel2){
		//Differenz der Vektoren zu den Flaggen
		Vektor df = f2.sub(f1);
		//?ber Cosinussatz (term1 = cos(alpha)):
		double term1 = (sqr(d1) + sqr(df.length()) - sqr(d2) ) / (2 * d1 * df.length());
		if (term1 > 1) {System.err.println(term1);term1 = 1; }
		if (term1 < -1){System.err.println(term1);term1 = -1; }
		double alpha =Math.acos(term1);   
		//"Winkelsatz" zwischen zwei Vektoren:
		double term2 = f1.mul(df) / (f1.length() * df.length());
		if (term2 > 1) {System.err.println(term2);term2 = 1; } 
		if (term2 < -1) {System.err.println(term2);term2 = -1; }
		double beta = Math.acos(term2);
		//Winkel, um den der erzeugte Vektor gedreht wird
		double omega = alpha + beta;
		double cosOmega = Math.cos(omega);
		double sinOmega = Math.sin(omega);
		//Vektor mit Richtung f1 und L?nge d1 erzeugen und drehen
		Vektor f1_nach_spieler = f1.mul(d1 / f1.length()).turn(rad2deg(omega));		
		/*Vektor f1_nach_spieler = f1.mul(d1 / f1.length()).mul(new Matrix2x2(cosOmega, -sinOmega, sinOmega, cosOmega));*/
		return f1.add(f1_nach_spieler);
		/*Sicherung:Vektor f1_nach_spieler = f1.mul(d1 / f1.length()).mul(new Matrix2x2(cosOmega, -sinOmega, sinOmega, cosOmega));		
		return f1.add(f1_nach_spieler);*/		
	}
	
	public static Vektor getPosition2(Vektor f1, Vektor f2, double d1, double d2, double winkel1, double winkel2){
	    Vektor df = f2.sub(f1);
		//?ber Cosinussatz (term1 = cos(alpha)):
		double term1 = (sqr(d1) + sqr(df.length()) - sqr(d2) ) / (2 * d1 * df.length());
		if (term1 > 1) {System.err.println(term1);term1 = 1; }
		if (term1 < -1){System.err.println(term1);term1 = -1; }
		double alpha =Math.acos(term1);
		return f1.add(df.turn(rad2deg(alpha)).mul(d1 / df.length()));	   
	}
	
	public static double getViewDirection (Vektor p, Flag f){
		//double alpha = Math.acos(Math.abs((f.getAbsX() - p.getX()))/f.getDist())*360 / (2 * Math.PI);
	    double alpha = rad2deg(Math.acos(Math.abs(f.getAbsX() - p.getX())/f.getDist()));
	    //if (alpha > 90) System.err.println("Winkel au?erhalb des erwarteten Wertebereiches");
		double angle = 0;
		//Spieler ist rechts unten von der Flagge
		if ((f.getAbsX() - p.getX() <= 0 ) && (f.getAbsY() - p.getY() <= 0)){
			angle = alpha - 180;
		}
		//Spieler rechts oben
		if ((f.getAbsX() - p.getX() <= 0 ) && (f.getAbsY() - p.getY() >= 0)){
			angle = 180- alpha;
		}
		//Spieler links unten
		if ((f.getAbsX() - p.getX() >= 0 ) && (f.getAbsY() - p.getY() <= 0)){
			angle = - alpha;
		}
		if ((f.getAbsX() - p.getX() >= 0 ) && (f.getAbsY() - p.getY() >= 0)){
			angle = alpha;
		}
		//System.out.println(normAngle(angle - f.getDir()));
		return normAngle(angle - f.getDir());
	}

	
	public static Vektor getObjectPosition (Vektor pos, double viewDir, GameObject obj){
    	double alpha = deg2rad(viewDir + obj.getDir());
    	return new Vektor(Math.cos(alpha) * obj.getDist() + pos.getX(), Math.sin(alpha) * obj.getDist() +pos.getY()); 
	}
	
	/******************************************************************
	 * Transformiert einen Winkel in den Bereich von -180 bis 180°
	 * @param angle ein Winkel im Gradmass
	 * @return Der Transformierte Winkel
	 ******************************************************************/	
	public static double normAngle(double angle){
	    while (angle > 180) angle -= 360;
		while (angle < -180) angle += 360;
		return (int) Math.round(angle);
	}
		
	/***************************************************************************
	 * Berechnet die Euklidische Distanz zwischen zwei Punkten.
	 * @param x1 X-Komponente des ersten Punktes
	 * @param y1 Y-Komponente des ersten Punktes
	 * @param x2 X-Komponente des zweiten Punktes
	 * @param y2 Y-Komponente des zweiten Punktes
	 * @return Math.sqrt(sqr(x1 - x2) + sqr(y1 - y2))
	 **************************************************************************/
	public static double distance(double x1, double y1, double x2, double y2){
	    return Math.sqrt(sqr(x1 - x2) + sqr(y1 - y2));
	}
	
	/***************************************************************************
	 * Berechnet den Lotpunkt von einem Punkt auf eine Gerade
	 * @param px X-Komponente des Punktes, von dem aus das Lot gefaellt wird
	 * @param py Y-Komponente des Punktes, von dem aus das Lot gefaellt wird
	 * @param ox X-Komponente eines Punktesauf der Geraden
	 * @param oy Y-Komponente eines Punktesauf der Geraden
	 * @param doX X-Komponente des Richtungsvektors der Geraden
	 * @param doY Y-Komponente des Richtungsvektors der Geraden
	 * @return den Lotpunkt
	 **************************************************************************/	
	public static Vektor lotVonPunktAufGerade(double px, double py, double ox, double oy , double doX, double doY)
	throws NullVektorException{
	    if ((doX == 0) && (doY == 0)) throw new NullVektorException();
	    Vektor pVektor = new Vektor(px, py);
    	Vektor oVektor = new Vektor(ox, oy);
    	Vektor doVektor = new Vektor(doX, doY);
    	double x = (pVektor.sub(oVektor).mul(doVektor)) / (doVektor.mul(doVektor)); 
    	Vektor destination = doVektor.mul(x).add(oVektor);
	    return destination;
	}
	

	
	/**************************************************
	 * Berechnet den Winkel zweier Vektoren in Bogenmaß
	 * @param a Vektor1
	 * @param b Vektor2
	 * @return Winkel zwischen a und b im Bogenmass
	 */
	public static double angleBetweenVectors(Vektor a, Vektor b){
		return Math.acos(a.mul(b)/(a.length()*b.length()));
	}
	

}