/FileExtraction/Java_unseen/labexp_osmtracker-android/app/src/main/java/net/osmtracker/util/MercatorProjection.java
package net.osmtracker.util;


/**
 * Geopoint to 2D projection using Mercator system.
 * 
 * @author Nicolas Guillaumin
 * 
 */
public class MercatorProjection {

	/**
	 * Maximum latitude useable with Mercator projection.
	 */
	private static final double MAX_LATITUDE = 85.0511f;

	/**
	 * X & longitude offset in used 2-dim arrays.
	 */
	public static final byte X = 0, LONGITUDE = 0;

	/**
	 * Y & latitude offsets in used 2-dim arrays.
	 */
	public static final byte Y = 1, LATITUDE = 1;

	/**
	 * Width & Height of the projection (pixels)
	 */
	private int width, height;
	
	/**
	 * Scale of the projection
	 */
	private double scale;

	/**
	 * Four corners of the projection, in converted coordinates
	 */
	private double topX, topY, bottomX, bottomY;

	/**
	 * Dimensions of projected space.
	 */
	private double dimX, dimY;

	public MercatorProjection(double minLat, double minLon, double maxLat, double maxLon, int w, int h) {
		width = w;
		height = h;

		// Get data range for X and Y
		double rangeX = Math.abs(convertLongitude(maxLon) - convertLongitude(minLon));
		double rangeY = Math.abs(convertLatitude(maxLat) - convertLatitude(minLat));

		// Determine scale for each axis
		double scaleX = rangeX / width;
		double scaleY = rangeY / height;

		// Determine which scale to use. We take the greater to
		// be able to fit in width AND height
		scale = (scaleX > scaleY) ? scaleX : scaleY;

		// Determine offset for X & Y, to translate
		// lon/lat into screen center
		double offsetX = (width * scale) - rangeX;
		double offsetY = (height * scale) - rangeY;

		// Determine 4 corners of projection
		topX = convertLongitude(minLon) - (offsetX / 2);
		topY = convertLatitude(minLat) - (offsetY / 2);
		bottomX = convertLongitude(maxLon) + (offsetX / 2);
		bottomY = convertLatitude(maxLat) + (offsetY / 2);

		// Calculate projection dimensions
		dimX = bottomX - topX;
		dimY = bottomY - topY;
	}

	/**
	 * Projects lon/lat coordinates into this projection.
	 * 
	 * @param longitude
	 *				Longitude to project
	 * @param latitude
	 *				Latitude to project
	 * @return An array of 2 int projected coordinates (use
	 *			{@link MercatorProjection.X} and {@link MercatorProjection.Y} for
	 *			access.
	 */
	public int[] project(double longitude, double latitude) {
		int[] out = new int[2];

		out[X] = (int) Math.round(((convertLongitude(longitude) - topX) / dimX) * width);
		out[Y] = (int) Math.round(height - (((convertLatitude(latitude) - topY) / dimY) * height));

		return out;
	}

	/**
	 * Convert longitude to X coordinate.
	 * 
	 * @param longitude
	 *				Longitude to convert.
	 * @return Converted X coordinate.
	 */
	private double convertLongitude(double longitude) {
		return longitude;
	}

	/**
	 * Converts latitude to Y coordinate.
	 * 
	 * @param latitude
	 *				Latitude to convert.
	 * @return Converted Y coordinate.
	 */
	private double convertLatitude(double latitude) {
		if (latitude < -MAX_LATITUDE) {
			latitude = -MAX_LATITUDE;
		} else if (latitude > MAX_LATITUDE) {
			latitude = MAX_LATITUDE;
		}

		return Math.log(Math.tan(Math.PI / 4 + (latitude * Math.PI / 180 / 2))) / (Math.PI / 180);
	}

	public double getScale() {
		return scale;
	}
	
	/**
	 * Given a float degree value (latitude or longitude), format it to Degrees/Minutes/Seconds.
	 * @param degrees  The value, such as 43.0438
	 * @param isLatitude  Is this latitude, not longitude?
	 * @return  The Degrees,Minutes,Seconds, such as: 43° 2' 38" N
	 */
	public static String formatDegreesAsDMS(Float degrees, final boolean isLatitude) {		
		if (degrees == null) {
			return "";
		}
		
		final boolean neg;
		if (degrees > 0) {
			neg = false;
		} else {
			neg = true;
			degrees = -degrees;
		}
		StringBuffer dms = new StringBuffer();

		int n = degrees.intValue();
		dms.append(n);
		dms.append("\u00B0 ");

		degrees = (degrees - n) * 60.0f;
		n = degrees.intValue();
		dms.append(n);
		dms.append("' ");

		degrees = (degrees - n) * 60.0f;
		n = degrees.intValue();
		dms.append(n);
		dms.append("\" ");

		if (isLatitude)
			dms.append(neg ? 'S' : 'N');
		else
			dms.append(neg ? 'W' : 'E');

		return dms.toString();
	}
}
