/*
	CLASE PARA EL PASO DE PUNTOS DE WGS84 A MERCATOR Y VICEVERSA.
*/

	var semieje_mayor = 6378137.0;
	var excentricidad = 0.0818191908426215;

	function longToX(longitudeDegrees)
	{
			var longitude;	
				
		    longitude = toRadians(longitudeDegrees);
			return semieje_mayor * longitude;
	}
	
	function latToY(latitudeDegrees)
	{
	    var latitude, y, parte1, parte2, a , b;
	    
		latitude = toRadians(latitudeDegrees);
		parte1 = Math.log(Math.tan(latitude / 2 + Math.PI / 4));
		a = 1.0 + excentricidad * Math.sin(latitude);
		b = 1.0 - excentricidad * Math.sin(latitude);
		parte2 = (excentricidad / 2) * Math.log(a / b);
		return (parte1 - parte2) * semieje_mayor;

	}	
	
	function xToLong(x)
	{
		var longRadians, longDegrees, rotations, longitude;
		longRadians = x / semieje_mayor;
		longDegrees = toDegrees(longRadians);
    	rotations = Math.floor((longDegrees + 180) / 360);
		longitude = longDegrees - (rotations * 360);
		return longitude;
	}
	
	function yToLat(y)
	{
		var lat, latfiso, latant, a, b;
		var i;

		latfiso = y / semieje_mayor;
		lat = latfiso;
    
		do
   		 {
   
			a = 1.0 + (excentricidad * Math.sin(lat));
			b = 1.0 - (excentricidad * Math.sin(lat));
			latant = lat;
			lat = 2 * Math.atan(Math.pow(a / b, excentricidad / 2) * Math.pow(Math.E, latfiso)) - Math.PI / 2;
   		 } while  (Math.abs(toDegrees(lat) - toDegrees(latant)) > 0.0000000001);

		return toDegrees(lat);
	
	}



/*
	CLASE PARA EL CALCULO DE DISTANCIAS ENTRE 2 PUNTOS.
*/


	function RadSex(l)
	{
    	var res;
    	res = l * Math.PI / 200;
    	return res;
	}

	function grados(l)
	{
		var res;
		res = l * 200 / Math.PI;
		return res;
	}

	function distanciaGeodesica(lon1, lat1, lon2, lat2)
	{
		/**
		 * @author Sergio Jorrín Abellán 
		 * @version 1.0
		 *
		 * TODO Clase CalcularDistancias
		 *  Método: distanciaGeodesica
		 * 	Permite calcular la distancia geodésica entre dos puntos en WGS84		
		 */
		var a = 6378137;
		var achatamiento = 298.257222;
		var alpha = 1 / achatamiento;
		var b = a - a * alpha;
		var e = (2 * alpha) - Math.pow(alpha,2);

		var lon1_rad, lat1_rad, lon2_rad, lat2_rad;
		var N;
		var P,R,Pb,Rb;
		var Ua, Ua_rad;
		var Ub, Ub_rad;
		var Um, Um_rad;
		var lat_m, lat_m_rad;
		var variac_lon_rad, variac_lon;
		var variac_lon_red, variac_lon_red_rad;
		var inc_lat, inc_lat_rad, inc_lon, inc_lon_rad;
		var par_1_rad, con_mer_rad, con_mer;
		var tg_Zm, Zm, Zm_rad;
		var inc_lat_m;
		var Zb_a, Za_b, Zb_a_rad, Za_b_rad;
		var Na, Ra, Nb;
		var x, y, s;

		//Paso a radianes
		lon1_rad = toRadians(lon1);
		lat1_rad = toRadians(lat1);
		lon2_rad = toRadians(lon2);
		lat2_rad = toRadians(lat2);

		//Normal Principal
		N = a / Math.sqrt(1 - (e * Math.pow(Math.sin(lat1_rad),2)));

		//Radio de curvatura de la elipse meridiana B.
		P = a * (1 - e) / Math.pow(1 - e * Math.pow(Math.sin(lat1_rad),2),1.5);

		R = Math.sqrt(N*P);

		Ua_rad = Math.atan((b / a) * Math.tan(lat1_rad));
		Ua = toDegrees(Ua_rad);

		Ub_rad = Math.atan((b / a) * Math.tan(lat2_rad));
		Ub = toDegrees(Ub_rad);

		Um_rad = (Ua_rad + Ub_rad) / 2;
		Um = toDegrees(Um_rad);

		//Latitud media rad.
		lat_m_rad = (lat1_rad + lat2_rad) / 2;
		//Latitud media.
		lat_m = (lat1 + lat2) / 2;

		//Variación longitud.
		variac_lon = lon2 - lon1;

		if (variac_lon == 0)
			variac_lon = 0.0000000000001;

		variac_lon_rad = toRadians(variac_lon);

		//Variación de Longitud reducida.
		variac_lon_red = variac_lon * Math.sin(lat_m_rad)/Math.sin(Um_rad);

		inc_lat = Ua - Ub;
		inc_lat_rad = Ua_rad - Ub_rad;
		
		inc_lon = variac_lon_red;
		inc_lon_rad = toRadians(inc_lon);

		// par_1
		par_1_rad = Math.sin(Um_rad) * Math.tan(inc_lon_rad/2) / Math.cos(inc_lat_rad/2);

		con_mer_rad = 2 * Math.atan(par_1_rad);
		con_mer = grados(con_mer_rad);
		
		// tangente Zm
		tg_Zm = Math.sin(inc_lat_rad/2) / (Math.cos(Um_rad)* Math.tan(inc_lon_rad/2));

		Zm_rad = Math.atan(tg_Zm);
		Zm = grados(Zm_rad);

		if(variac_lon_rad > 0)
		{
			Zb_a = Zm + 200 + con_mer/2 + 100;		
		}
		else
		{
			Zb_a = Zm + 200 + con_mer/2 - 100;		
		}
		
		Zb_a_rad = RadSex(Zb_a);

		if(variac_lon_rad > 0)
		{
			Za_b = Zm + 200 - con_mer/2 - 100;		
		}
		else
		{
			Za_b = Zm + 200 - con_mer/2 + 100;		
		}
		
		Za_b_rad = RadSex(Za_b);

		//Normal Principal B.
		Nb = a / Math.sqrt(1 - e * Math.pow(Math.sin(lat2_rad),2));

		//Radio de curvatura de la elipse meridiana B.
		Pb = a * (1 - e) / Math.pow(1 - e * Math.pow(Math.sin(lat2_rad),2),1.5);

		Rb = Math.sqrt(Nb*Pb);

		var sincos = Math.sin(variac_lon_rad) * Math.cos(lat2_rad);

		x = Nb * Math.asin(sincos);
		
		inc_lat_rad = lat1_rad - lat2_rad;

		inc_lat_m = inc_lat_rad * Nb;
		
		var w = (Math.pow(x,2)/Nb)*Math.tan(lat2_rad) * 1/2;

		y = inc_lat_m - w;

		s = x/Math.sin(Za_b_rad)*(1 +(Math.pow(y,2)/(6 * N * P)));

		return s;
	
	}

    function toDegrees(val)
    {
        return (val * 180)/Math.PI
    }
    
    function toRadians(val)
    {
        return (val * Math.PI)/180
    }
    
    function toScale(Distancia, XImg, YImg){

        var lon_cntr = (xmaxa + xmina) / 2;
        var lat_cntr = (ymaxa + ymina) / 2;

        var LatFin1 = lat_cntr + VariacLats(lat_cntr, -Distancia / 2);
        var LatFin2 = lat_cntr + VariacLats(lat_cntr, Distancia / 2);

        var VariacLons = Math.abs(LatFin2 - LatFin1) * XImg / YImg;

        var LonFin1 = lon_cntr - VariacLons / 2;
        var LonFin2 = lon_cntr + VariacLons / 2;

        xmina = LonFin1;
        ymina = LatFin1;
        xmaxa = LonFin2;
        ymaxa = LatFin2;
    }

    function VariacLats(lat_cntr, Distancia){
        var a = 6378137;
        var achatamiento = 298.257222;
        var alpha = 1 / achatamiento;
        var e = (2 * alpha) - Math.pow(alpha, 2);
        var P = 0;

        var lat_cntr_rad = toRadians(lat_cntr);

        //Radio de curvatura de la elipse meridiana B.
        P = (a * (1 - e)) / Math.pow(1 - e * Math.pow(Math.sin(lat_cntr_rad), 2), 1.5);

        //Variación de latitudes en segundos
        var A_lats_radianes = (Distancia / P) * (1 - (e * Distancia ^ 2 * Math.cos(2 * lat_cntr_rad)) / (8 * Math.pow(a,2)));

        //Variación de latitudes en grados
        var A_lats_grados = toDegrees(A_lats_radianes);

        return A_lats_grados;
    }

