diff --git a/LICENSE b/LICENSE
index 44f8488ce8..135e9c5a3d 100644
--- a/LICENSE
+++ b/LICENSE
@@ -82,6 +82,7 @@
- junidecode-0.1.jar - BSD-4-Clause-UC (http://sourceforge.net/projects/junidecode/)
- kxml2-2.3.0.jar - BSD license (http://www.kxml.org/)
- tuprolog.jar - LGPL (http://apice.unibo.it/xwiki/bin/view/Tuprolog/)
+ - OpenMap framework - Apache License (https://code.google.com/p/android-openmap-framework/)
* Pull-requests and translations:
- All pull requests are accepted under MIT License (most honorable contributors are mentioned in AUTHORS list)
diff --git a/OsmAnd/src/com/jwetherell/openmap/common/Ellipsoid.java b/OsmAnd/src/com/jwetherell/openmap/common/Ellipsoid.java
new file mode 100644
index 0000000000..a99a15572f
--- /dev/null
+++ b/OsmAnd/src/com/jwetherell/openmap/common/Ellipsoid.java
@@ -0,0 +1,167 @@
+// **********************************************************************
+//
+//
+ * Computes arc distance `c' on the sphere. equation (5-3a). (0 <= c + * <= PI) + *
+ * + * @param phi1 + * latitude in radians of start point + * @param lambda0 + * longitude in radians of start point + * @param phi + * latitude in radians of end point + * @param lambda + * longitude in radians of end point + * @return float arc distance `c' + * + */ + public static final float sphericalDistance(float phi1, float lambda0, float phi, float lambda) { + return (float) sphericalDistance((double) phi1, (double) lambda0, (double) phi, (double) lambda); + } + + /** + * Calculate spherical arc distance between two points with double + * precision. + *
+ * Computes arc distance `c' on the sphere. equation (5-3a). (0 <= c + * <= PI) + *
+ * + * @param phi1 + * latitude in radians of start point + * @param lambda0 + * longitude in radians of start point + * @param phi + * latitude in radians of end point + * @param lambda + * longitude in radians of end point + * @return float arc distance `c' + */ + public static final double sphericalDistance(double phi1, double lambda0, double phi, double lambda) { + double pdiff = Math.sin(((phi - phi1) / 2.0)); + double ldiff = Math.sin((lambda - lambda0) / 2.0); + double rval = Math.sqrt((pdiff * pdiff) + Math.cos(phi1) * Math.cos(phi) * (ldiff * ldiff)); + + return 2.0 * Math.asin(rval); + } + + /** + * Calculate spherical azimuth between two points. + *
+ * Computes the azimuth `Az' east of north from phi1, lambda0 bearing toward + * phi and lambda. (5-4b). (-PI <= Az <= PI). + *
+ * + * @param phi1 + * latitude in radians of start point + * @param lambda0 + * longitude in radians of start point + * @param phi + * latitude in radians of end point + * @param lambda + * longitude in radians of end point + * @return float azimuth east of north `Az' + * + */ + public static final float sphericalAzimuth(float phi1, float lambda0, float phi, float lambda) { + return (float) sphericalAzimuth((double) phi1, (double) lambda0, (double) phi, (double) lambda); + } + + /** + * Calculate spherical azimuth between two points with double precision. + *
+ * Computes the azimuth `Az' east of north from phi1, lambda0 bearing toward + * phi and lambda. (5-4b). (-PI <= Az <= PI). + *
+ * + * @param phi1 + * latitude in radians of start point + * @param lambda0 + * longitude in radians of start point + * @param phi + * latitude in radians of end point + * @param lambda + * longitude in radians of end point + * @return float azimuth east of north `Az' + * + */ + public static final double sphericalAzimuth(double phi1, double lambda0, double phi, double lambda) { + double ldiff = lambda - lambda0; + double cosphi = Math.cos(phi); + + return Math.atan2(cosphi * Math.sin(ldiff), (Math.cos(phi1) * Math.sin(phi) - Math.sin(phi1) * cosphi * Math.cos(ldiff))); + } + + /** + * Calculate point at azimuth and distance from another point, with double + * precision. + *
+ * Returns a LatLonPoint.Double at arc distance `c' in direction `Az' from + * start point. + *
+ * + * @param phi1 + * latitude in radians of start point + * @param lambda0 + * longitude in radians of start point + * @param c + * arc radius in radians (0 < c <= PI) + * @param Az + * azimuth (direction) east of north (-PI <= Az < PI) + * @return LatLonPoint + * + */ + public static final LatLonPoint sphericalBetween(double phi1, double lambda0, double c, double Az) { + double cosphi1 = Math.cos(phi1); + double sinphi1 = Math.sin(phi1); + double cosAz = Math.cos(Az); + double sinAz = Math.sin(Az); + double sinc = Math.sin(c); + double cosc = Math.cos(c); + + return new LatLonPoint(ProjMath.radToDeg(Math.asin(sinphi1 * cosc + cosphi1 * sinc * cosAz)), ProjMath.radToDeg(Math.atan2(sinc * sinAz, cosphi1 * cosc + - sinphi1 * sinc * cosAz) + + lambda0)); + } + + /** + * Calculate point between two points. + *
+ * Same as spherical_between() above except it calculates n equal segments + * along the length of c. + *
+ * + * @param phi1 + * latitude in radians of start point + * @param lambda0 + * longitude in radians of start point + * @param c + * arc radius in radians (0 < c <= PI) + * @param Az + * azimuth (direction) east of north (-PI <= Az < PI) + * @param n + * number of points along great circle edge to calculate + * @return float[n+1] radian lat,lon pairs + * + */ + public static final float[] sphericalBetween(float phi1, float lambda0, float c, float Az, int n) { + // full constants for the computation + double cosphi1 = Math.cos(phi1); + double sinphi1 = Math.sin(phi1); + double cosAz = Math.cos(Az); + double sinAz = Math.sin(Az); + int end = n << 1; + + // new radian points + float[] points = new float[end + 2]; + points[0] = phi1; + points[1] = lambda0; + + float inc = c / n; + c = inc; + for (int i = 2; i <= end; i += 2, c += inc) { + + // partial constants + double sinc = Math.sin(c); + double cosc = Math.cos(c); + + // generate new point + points[i] = (float) Math.asin(sinphi1 * cosc + cosphi1 * sinc * cosAz); + + points[i + 1] = (float) Math.atan2(sinc * sinAz, cosphi1 * cosc - sinphi1 * sinc * cosAz) + lambda0; + } + return points; + } + + /** + * Calculate point between two points with double precision. + *
+ * Same as spherical_between() above except it calculates n equal segments + * along the length of c. + *
+ * + * @param phi1 + * latitude in radians of start point + * @param lambda0 + * longitude in radians of start point + * @param c + * arc radius in radians (0 < c <= PI) + * @param Az + * azimuth (direction) east of north (-PI <= Az < PI) + * @param n + * number of points along great circle edge to calculate + * @return double[n+1] radian lat,lon pairs + * + */ + public static final double[] sphericalBetween(double phi1, double lambda0, double c, double Az, int n) { + // full constants for the computation + double cosphi1 = Math.cos(phi1); + double sinphi1 = Math.sin(phi1); + double cosAz = Math.cos(Az); + double sinAz = Math.sin(Az); + int end = n << 1; + + // new radian points + double[] points = new double[end + 2]; + points[0] = phi1; + points[1] = lambda0; + + double inc = c / n; + c = inc; + for (int i = 2; i <= end; i += 2, c += inc) { + + // partial constants + double sinc = Math.sin(c); + double cosc = Math.cos(c); + + // generate new point + points[i] = Math.asin(sinphi1 * cosc + cosphi1 * sinc * cosAz); + + points[i + 1] = Math.atan2(sinc * sinAz, cosphi1 * cosc - sinphi1 * sinc * cosAz) + lambda0; + } + return points; + } + + /** + * Calculate great circle between two points on the sphere. + *
+ * Folds all computation (distance, azimuth, points between) into one + * function for optimization. returns n or n+1 pairs of lat,lon on great + * circle between lat-lon pairs. + *
+ * + * @param phi1 + * latitude in radians of start point + * @param lambda0 + * longitude in radians of start point + * @param phi + * latitude in radians of end point + * @param lambda + * longitude in radians of end point + * @param n + * number of segments + * @param include_last + * return n or n+1 segments + * @return float[n] or float[n+1] radian lat,lon pairs + * + */ + public static final float[] greatCircle(float phi1, float lambda0, float phi, float lambda, int n, boolean include_last) { + // number of points to generate + int end = include_last ? n + 1 : n; + end <<= 1;// *2 for pairs + + // calculate a bunch of stuff for later use + double cosphi = Math.cos(phi); + double cosphi1 = Math.cos(phi1); + double sinphi1 = Math.sin(phi1); + double ldiff = lambda - lambda0; + double p2diff = Math.sin(((phi - phi1) / 2)); + double l2diff = Math.sin((ldiff) / 2); + + // calculate spherical distance + double c = 2.0f * Math.asin(Math.sqrt(p2diff * p2diff + cosphi1 * cosphi * l2diff * l2diff)); + + // calculate spherical azimuth + double Az = Math.atan2(cosphi * Math.sin(ldiff), (cosphi1 * Math.sin(phi) - sinphi1 * cosphi * Math.cos(ldiff))); + double cosAz = Math.cos(Az); + double sinAz = Math.sin(Az); + + // generate the great circle line + float[] points = new float[end]; + points[0] = phi1; + points[1] = lambda0; + + double inc = c / n; + c = inc; + for (int i = 2; i < end; i += 2, c += inc) { + + // partial constants + double sinc = Math.sin(c); + double cosc = Math.cos(c); + + // generate new point + points[i] = (float) Math.asin(sinphi1 * cosc + cosphi1 * sinc * cosAz); + + points[i + 1] = (float) Math.atan2(sinc * sinAz, cosphi1 * cosc - sinphi1 * sinc * cosAz) + lambda0; + } + + return points; + } + + /** + * Calculate great circle between two points on the sphere with double + * precision. + *
+ * Folds all computation (distance, azimuth, points between) into one + * function for optimization. returns n or n+1 pairs of lat,lon on great + * circle between lat-lon pairs. + *
+ * + * @param phi1 + * latitude in radians of start point + * @param lambda0 + * longitude in radians of start point + * @param phi + * latitude in radians of end point + * @param lambda + * longitude in radians of end point + * @param n + * number of segments + * @param include_last + * return n or n+1 segments + * @return double[n] or double[n+1] radian lat,lon pairs + * + */ + public static final double[] greatCircle(double phi1, double lambda0, double phi, double lambda, int n, boolean include_last) { + // number of points to generate + int end = include_last ? n + 1 : n; + end <<= 1;// *2 for pairs + + // calculate a bunch of stuff for later use + double cosphi = Math.cos(phi); + double cosphi1 = Math.cos(phi1); + double sinphi1 = Math.sin(phi1); + double ldiff = lambda - lambda0; + double p2diff = Math.sin(((phi - phi1) / 2)); + double l2diff = Math.sin((ldiff) / 2); + + // calculate spherical distance + double c = 2.0f * Math.asin(Math.sqrt(p2diff * p2diff + cosphi1 * cosphi * l2diff * l2diff)); + + // calculate spherical azimuth + double Az = Math.atan2(cosphi * Math.sin(ldiff), (cosphi1 * Math.sin(phi) - sinphi1 * cosphi * Math.cos(ldiff))); + double cosAz = Math.cos(Az); + double sinAz = Math.sin(Az); + + // generate the great circle line + double[] points = new double[end]; + points[0] = phi1; + points[1] = lambda0; + + double inc = c / n; + c = inc; + for (int i = 2; i < end; i += 2, c += inc) { + + // partial constants + double sinc = Math.sin(c); + double cosc = Math.cos(c); + + // generate new point + points[i] = Math.asin(sinphi1 * cosc + cosphi1 * sinc * cosAz); + + points[i + 1] = Math.atan2(sinc * sinAz, cosphi1 * cosc - sinphi1 * sinc * cosAz) + lambda0; + } + + return points; + } + + /** + * Calculate partial earth circle on the sphere. + *
+ * Returns n float lat,lon pairs at arc distance c from point at + * phi1,lambda0. + *
+ * + * @param phi1 + * latitude in radians of center point + * @param lambda0 + * longitude in radians of center point + * @param c + * arc radius in radians (0 < c < PI) + * @param s + * starting angle in radians. North up is zero. + * @param e + * angular extent in radians, clockwise right from starting + * angle. + * @param n + * number of points along circle edge to calculate + * @return float[n] radian lat,lon pairs along earth circle + * + */ + public static final float[] earthCircle(float phi1, float lambda0, float c, float s, float e, int n) { + return earthCircle(phi1, lambda0, c, s, e, n, new float[n << 1]); + } + + /** + * Calculate earth circle on the sphere. + *
+ * Returns n float lat,lon pairs at arc distance c from point at + * phi1,lambda0. + *
+ * + * @param phi1 + * latitude in radians of center point + * @param lambda0 + * longitude in radians of center point + * @param c + * arc radius in radians (0 < c < PI) + * @param n + * number of points along circle edge to calculate + * @return float[n] radian lat,lon pairs along earth circle + * + */ + public static final float[] earthCircle(float phi1, float lambda0, float c, int n) { + return earthCircle(phi1, lambda0, c, 0.0f, MoreMath.TWO_PI, n, new float[n << 1]); + } + + /** + * Calculate earth circle in the sphere. + *
+ * Returns n float lat,lon pairs at arc distance c from point at + * phi1,lambda0. + *
+ * + * @param phi1 + * latitude in radians of center point + * @param lambda0 + * longitude in radians of center point + * @param c + * arc radius in radians (0 < c < PI) + * @param n + * number of points along circle edge to calculate + * @param ret_val + * float[] ret_val array of n*2 number of points along circle + * edge to calculate + * @return float[n] radian lat,lon pairs along earth circle + * + */ + public static final float[] earthCircle(float phi1, float lambda0, float c, int n, float[] ret_val) { + return earthCircle(phi1, lambda0, c, 0.0f, MoreMath.TWO_PI, n, ret_val); + } + + /** + * Calculate earth circle in the sphere. + *
+ * Returns n float lat,lon pairs at arc distance c from point at + * phi1,lambda0. + *
+ * + * @param phi1 + * latitude in radians of center point. + * @param lambda0 + * longitude in radians of center point. + * @param c + * arc radius in radians (0 < c < PI). + * @param s + * starting angle in radians. North up is zero. + * @param e + * angular extent in radians, clockwise right from starting + * angle. + * @param n + * number of points along circle edge to calculate. + * @param ret_val + * float[] ret_val array of n*2 number of points along circle + * edge to calculate. + * @return float[n] radian lat,lon pairs along earth circle. + * + */ + public static final float[] earthCircle(float phi1, float lambda0, float c, float s, float e, int n, float[] ret_val) { + double Az, cosAz, sinAz; + double cosphi1 = Math.cos(phi1); + double sinphi1 = Math.sin(phi1); + double sinc = Math.sin(c); + double cosc = Math.cos(c); + if (n < 2) n = 2; // Safety to avoid / by zero later. + int end = n << 1;// *2 + + // Only want to create a new return float array if there was a + // null one passed in, or if the number of desired coordinates + // is bigger than what ret_val is currently allocated for. + if (ret_val == null || end > ret_val.length) { + ret_val = new float[end]; + } + + double inc = e / (n - 1); + Az = s; + + // generate the points in clockwise order (conforming to + // internal standard!) + for (int i = 0; i < end; i += 2, Az += inc) { + cosAz = Math.cos(Az); + sinAz = Math.sin(Az); + + ret_val[i] = (float) Math.asin(sinphi1 * cosc + cosphi1 * sinc * cosAz); + ret_val[i + 1] = (float) Math.atan2(sinc * sinAz, cosphi1 * cosc - sinphi1 * sinc * cosAz) + lambda0; + } + + return ret_val; + } + + /** + * Calculate partial earth circle on the sphere with double precision. + *
+ * Returns n double lat,lon pairs at arc distance c from point at + * phi1,lambda0. + *
+ * + * @param phi1 + * latitude in radians of center point + * @param lambda0 + * longitude in radians of center point + * @param c + * arc radius in radians (0 < c < PI) + * @param s + * starting angle in radians. North up is zero. + * @param e + * angular extent in radians, clockwise right from starting + * angle. + * @param n + * number of points along circle edge to calculate + * @return double[n] radian lat,lon pairs along earth circle + * + */ + public static final double[] earthCircle(double phi1, double lambda0, double c, double s, double e, int n) { + return earthCircle(phi1, lambda0, c, s, e, n, new double[n << 1]); + } + + /** + * Calculate earth circle on the sphere with double precision. + *
+ * Returns n double lat,lon pairs at arc distance c from point at + * phi1,lambda0. + *
+ * + * @param phi1 + * latitude in radians of center point + * @param lambda0 + * longitude in radians of center point + * @param c + * arc radius in radians (0 < c < PI) + * @param n + * number of points along circle edge to calculate + * @return double[n] radian lat,lon pairs along earth circle + * + */ + public static final double[] earthCircle(double phi1, double lambda0, double c, int n) { + return earthCircle(phi1, lambda0, c, 0.0f, MoreMath.TWO_PI_D, n, new double[n << 1]); + } + + /** + * Calculate earth circle in the sphere with double precision. + *
+ * Returns n float lat,lon pairs at arc distance c from point at + * phi1,lambda0. + *
+ * + * @param phi1 + * latitude in radians of center point + * @param lambda0 + * longitude in radians of center point + * @param c + * arc radius in radians (0 < c < PI) + * @param n + * number of points along circle edge to calculate + * @param ret_val + * double[] ret_val array of n*2 number of points along circle + * edge to calculate + * @return double[n] radian lat,lon pairs along earth circle + * + */ + public static final double[] earthCircle(double phi1, double lambda0, double c, int n, double[] ret_val) { + return earthCircle(phi1, lambda0, c, 0.0f, MoreMath.TWO_PI_D, n, ret_val); + } + + /** + * Calculate earth circle in the sphere in double precision. + *
+ * Returns n double lat,lon pairs at arc distance c from point at + * phi1,lambda0. + *
+ *
+ * @param phi1
+ * latitude in radians of center point.
+ * @param lambda0
+ * longitude in radians of center point.
+ * @param c
+ * arc radius in radians (0 < c < PI).
+ * @param s
+ * starting angle in radians. North up is zero.
+ * @param e
+ * angular extent in radians, clockwise right from starting
+ * angle.
+ * @param n
+ * number of points along circle edge to calculate.
+ * @param ret_val
+ * double[] ret_val array of n*2 number of points along circle
+ * edge to calculate.
+ * @return double[n] radian lat,lon pairs along earth circle.
+ *
+ */
+ public static final double[] earthCircle(double phi1, double lambda0, double c, double s, double e, int n, double[] ret_val) {
+ double Az, cosAz, sinAz;
+ double cosphi1 = Math.cos(phi1);
+ double sinphi1 = Math.sin(phi1);
+ double sinc = Math.sin(c);
+ double cosc = Math.cos(c);
+ if (n < 2) n = 2; // Safety to avoid / by zero later.
+ int end = n << 1;// *2
+
+ // Only want to create a new return float array if there was a
+ // null one passed in, or if the number of desired coordinates
+ // is bigger than what ret_val is currently allocated for.
+ if (ret_val == null || end > ret_val.length) {
+ ret_val = new double[end];
+ }
+
+ double inc = e / (n - 1);
+ Az = s;
+
+ // generate the points in clockwise order (conforming to
+ // internal standard!)
+ for (int i = 0; i < end; i += 2, Az += inc) {
+ cosAz = Math.cos(Az);
+ sinAz = Math.sin(Az);
+
+ ret_val[i] = Math.asin(sinphi1 * cosc + cosphi1 * sinc * cosAz);
+ ret_val[i + 1] = Math.atan2(sinc * sinAz, cosphi1 * cosc - sinphi1 * sinc * cosAz) + lambda0;
+ }
+
+ return ret_val;
+ }
+}
\ No newline at end of file
diff --git a/OsmAnd/src/com/jwetherell/openmap/common/LatLonPoint.java b/OsmAnd/src/com/jwetherell/openmap/common/LatLonPoint.java
new file mode 100644
index 0000000000..323a67ecfd
--- /dev/null
+++ b/OsmAnd/src/com/jwetherell/openmap/common/LatLonPoint.java
@@ -0,0 +1,339 @@
+
+// **********************************************************************
+//
+//
+ * + * @param a + * double + * @param b + * double + * @param epsilon + * the allowable error + * @return boolean + */ + public static final boolean approximately_equal(double a, double b, double epsilon) { + return (Math.abs(a - b) <= epsilon); + } + + /** + * Checks if a ~= b. Use this to test equality of floating point numbers. + *
+ * + * @param a + * float + * @param b + * float + * @param epsilon + * the allowable error + * @return boolean + */ + public static final boolean approximately_equal(float a, float b, float epsilon) { + return (Math.abs(a - b) <= epsilon); + } + + /** + * Hyperbolic arcsin. + *
+ * Hyperbolic arc sine: log (x+sqrt(1+x^2)) + * + * @param x + * float + * @return float asinh(x) + */ + public static final float asinh(float x) { + return (float) Math.log(x + Math.sqrt(x * x + 1)); + } + + /** + * Hyperbolic arcsin. + *
+ * Hyperbolic arc sine: log (x+sqrt(1+x^2)) + * + * @param x + * double + * @return double asinh(x) + */ + public static final double asinh(double x) { + return Math.log(x + Math.sqrt(x * x + 1)); + } + + /** + * Hyperbolic sin. + *
+ * Hyperbolic sine: (e^x-e^-x)/2 + * + * @param x + * float + * @return float sinh(x) + */ + public static final float sinh(float x) { + return (float) (Math.pow(Math.E, x) - Math.pow(Math.E, -x)) / 2.0f; + } + + /** + * Hyperbolic sin. + *
+ * Hyperbolic sine: (e^x-e^-x)/2
+ *
+ * @param x
+ * double
+ * @return double sinh(x)
+ */
+ public static final double sinh(double x) {
+ return (Math.pow(Math.E, x) - Math.pow(Math.E, -x)) / 2.0d;
+ }
+
+ // HACK - are there functions that already exist?
+ /**
+ * Return sign of number.
+ *
+ * @param x
+ * short
+ * @return int sign -1, 1
+ */
+ public static final int sign(short x) {
+ return (x < 0) ? -1 : 1;
+ }
+
+ /**
+ * Return sign of number.
+ *
+ * @param x
+ * int
+ * @return int sign -1, 1
+ */
+ public static final int sign(int x) {
+ return (x < 0) ? -1 : 1;
+ }
+
+ /**
+ * Return sign of number.
+ *
+ * @param x
+ * long
+ * @return int sign -1, 1
+ */
+ public static final int sign(long x) {
+ return (x < 0) ? -1 : 1;
+ }
+
+ /**
+ * Return sign of number.
+ *
+ * @param x
+ * float
+ * @return int sign -1, 1
+ */
+ public static final int sign(float x) {
+ return (x < 0f) ? -1 : 1;
+ }
+
+ /**
+ * Return sign of number.
+ *
+ * @param x
+ * double
+ * @return int sign -1, 1
+ */
+ public static final int sign(double x) {
+ return (x < 0d) ? -1 : 1;
+ }
+
+ /**
+ * Check if number is odd.
+ *
+ * @param x
+ * short
+ * @return boolean
+ */
+ public static final boolean odd(short x) {
+ return !even(x);
+ }
+
+ /**
+ * Check if number is odd.
+ *
+ * @param x
+ * int
+ * @return boolean
+ */
+ public static final boolean odd(int x) {
+ return !even(x);
+ }
+
+ /**
+ * Check if number is odd.
+ *
+ * @param x
+ * long
+ * @return boolean
+ */
+ public static final boolean odd(long x) {
+ return !even(x);
+ }
+
+ /**
+ * Check if number is even.
+ *
+ * @param x
+ * short
+ * @return boolean
+ */
+ public static final boolean even(short x) {
+ return ((x & 0x1) == 0);
+ }
+
+ /**
+ * Check if number is even.
+ *
+ * @param x
+ * int
+ * @return boolean
+ */
+ public static final boolean even(int x) {
+ return ((x & 0x1) == 0);
+ }
+
+ /**
+ * Check if number is even.
+ *
+ * @param x
+ * long
+ * @return boolean
+ */
+ public static final boolean even(long x) {
+ return ((x & 0x1) == 0);
+ }
+
+ /**
+ * Converts a byte in the range of -128 to 127 to an int in the range 0 -
+ * 255.
+ *
+ * @param b
+ * (-128 <= b <= 127)
+ * @return int (0 <= b <= 255)
+ */
+ public static final int signedToInt(byte b) {
+ return (b & 0xff);
+ }
+
+ /**
+ * Converts a short in the range of -32768 to 32767 to an int in the range 0
+ * - 65535.
+ *
+ * @param w
+ * (-32768 <= b <= 32767)
+ * @return int (0 <= b <= 65535)
+ */
+ public static final int signedToInt(short w) {
+ return (w & 0xffff);
+ }
+
+ /**
+ * Convert an int in the range of -2147483648 to 2147483647 to a long in the
+ * range 0 to 4294967295.
+ *
+ * @param x
+ * (-2147483648 <= x <= 2147483647)
+ * @return long (0 <= x <= 4294967295)
+ */
+ public static final long signedToLong(int x) {
+ return (x & 0xFFFFFFFFL);
+ }
+
+ /**
+ * Converts an int in the range of 0 - 65535 to an int in the range of 0 -
+ * 255.
+ *
+ * @param w
+ * int (0 <= w <= 65535)
+ * @return int (0 <= w <= 255)
+ */
+ public static final int wordToByte(int w) {
+ return w >> 8;
+ }
+
+ /**
+ * Build short out of bytes (in big endian order).
+ *
+ * @param bytevec
+ * bytes
+ * @param offset
+ * byte offset
+ * @return short
+ */
+ public static final short BuildShortBE(byte bytevec[], int offset) {
+ return (short) (((bytevec[0 + offset]) << 8) | (signedToInt(bytevec[1 + offset])));
+ }
+
+ /**
+ * Build short out of bytes (in little endian order).
+ *
+ * @param bytevec
+ * bytes
+ * @param offset
+ * byte offset
+ * @return short
+ */
+ public static final short BuildShortLE(byte bytevec[], int offset) {
+ return (short) (((bytevec[1 + offset]) << 8) | (signedToInt(bytevec[0 + offset])));
+ }
+
+ /**
+ * Build short out of bytes.
+ *
+ * @param bytevec
+ * bytes
+ * @param offset
+ * byte offset
+ * @param MSBFirst
+ * BE or LE?
+ * @return short
+ */
+ public static final short BuildShort(byte bytevec[], int offset, boolean MSBFirst) {
+ if (MSBFirst)
+ return (BuildShortBE(bytevec, offset));
+ // else
+ return (BuildShortLE(bytevec, offset));
+ }
+
+ /**
+ * Build short out of bytes (in big endian order).
+ *
+ * @param bytevec
+ * bytes
+ * @param MSBFirst
+ * BE or LE?
+ * @return short
+ */
+
+ public static final short BuildShortBE(byte bytevec[], boolean MSBFirst) {
+ return BuildShortBE(bytevec, 0);
+ }
+
+ /**
+ * Build short out of bytes (in little endian order).
+ *
+ * @param bytevec
+ * bytes
+ * @param MSBFirst
+ * BE or LE?
+ * @return short
+ */
+ public static final short BuildShortLE(byte bytevec[], boolean MSBFirst) {
+ return BuildShortLE(bytevec, 0);
+ }
+
+ /**
+ * Build short out of bytes.
+ *
+ * @param bytevec
+ * bytes
+ * @param MSBFirst
+ * BE or LE?
+ * @return short
+ */
+ public static final short BuildShort(byte bytevec[], boolean MSBFirst) {
+ return BuildShort(bytevec, 0, MSBFirst);
+ }
+
+ /**
+ * Build int out of bytes (in big endian order).
+ *
+ * @param bytevec
+ * bytes
+ * @param offset
+ * byte offset
+ * @return int
+ */
+ public static final int BuildIntegerBE(byte bytevec[], int offset) {
+ return (((bytevec[0 + offset]) << 24) | (signedToInt(bytevec[1 + offset]) << 16) | (signedToInt(bytevec[2 + offset]) << 8) | (signedToInt(bytevec[3 + offset])));
+ }
+
+ /**
+ * Build int out of bytes (in little endian order).
+ *
+ * @param bytevec
+ * bytes
+ * @param offset
+ * byte offset
+ * @return int
+ */
+ public static final int BuildIntegerLE(byte bytevec[], int offset) {
+ return (((bytevec[3 + offset]) << 24) | (signedToInt(bytevec[2 + offset]) << 16) | (signedToInt(bytevec[1 + offset]) << 8) | (signedToInt(bytevec[0 + offset])));
+ }
+
+ /**
+ * Build int out of bytes.
+ *
+ * @param bytevec
+ * bytes
+ * @param offset
+ * byte offset
+ * @param MSBFirst
+ * BE or LE?
+ * @return int
+ */
+ public static final int BuildInteger(byte bytevec[], int offset, boolean MSBFirst) {
+ if (MSBFirst)
+ return BuildIntegerBE(bytevec, offset);
+ // else
+ return BuildIntegerLE(bytevec, offset);
+ }
+
+ /**
+ * Build int out of bytes (in big endian order).
+ *
+ * @param bytevec
+ * bytes
+ * @return int
+ */
+ public static final int BuildIntegerBE(byte bytevec[]) {
+ return BuildIntegerBE(bytevec, 0);
+ }
+
+ /**
+ * Build int out of bytes (in little endian order).
+ *
+ * @param bytevec
+ * bytes
+ * @return int
+ */
+ public static final int BuildIntegerLE(byte bytevec[]) {
+ return BuildIntegerLE(bytevec, 0);
+ }
+
+ /**
+ * Build int out of bytes.
+ *
+ * @param bytevec
+ * bytes
+ * @param MSBFirst
+ * BE or LE?
+ * @return int
+ */
+ public static final int BuildInteger(byte bytevec[], boolean MSBFirst) {
+ if (MSBFirst)
+ return BuildIntegerBE(bytevec, 0);
+ //else
+ return BuildIntegerLE(bytevec, 0);
+ }
+
+ /**
+ * Build long out of bytes (in big endian order).
+ *
+ * @param bytevec
+ * bytes
+ * @param offset
+ * byte offset
+ * @return long
+ */
+ public static final long BuildLongBE(byte bytevec[], int offset) {
+ return (((long) signedToInt(bytevec[0 + offset]) << 56) | ((long) signedToInt(bytevec[1 + offset]) << 48)
+ | ((long) signedToInt(bytevec[2 + offset]) << 40) | ((long) signedToInt(bytevec[3 + offset]) << 32)
+ | ((long) signedToInt(bytevec[4 + offset]) << 24) | ((long) signedToInt(bytevec[5 + offset]) << 16)
+ | ((long) signedToInt(bytevec[6 + offset]) << 8) | (signedToInt(bytevec[7 + offset])));
+ }
+
+ /**
+ * Build long out of bytes (in little endian order).
+ *
+ * @param bytevec
+ * bytes
+ * @param offset
+ * byte offset
+ * @return long
+ */
+ public static final long BuildLongLE(byte bytevec[], int offset) {
+ return (((long) signedToInt(bytevec[7 + offset]) << 56) | ((long) signedToInt(bytevec[6 + offset]) << 48)
+ | ((long) signedToInt(bytevec[5 + offset]) << 40) | ((long) signedToInt(bytevec[4 + offset]) << 32)
+ | ((long) signedToInt(bytevec[3 + offset]) << 24) | ((long) signedToInt(bytevec[2 + offset]) << 16)
+ | ((long) signedToInt(bytevec[1 + offset]) << 8) | (signedToInt(bytevec[0 + offset])));
+ }
+
+ /**
+ * Build long out of bytes.
+ *
+ * @param bytevec
+ * bytes
+ * @param offset
+ * byte offset
+ * @param MSBFirst
+ * BE or LE?
+ * @return long
+ */
+ public static final long BuildLong(byte bytevec[], int offset, boolean MSBFirst) {
+ if (MSBFirst)
+ return BuildLongBE(bytevec, offset);
+ // else
+ return BuildLongLE(bytevec, offset);
+ }
+
+ /**
+ * Build long out of bytes (in big endian order).
+ *
+ * @param bytevec
+ * bytes
+ * @return long
+ */
+ public static final long BuildLongBE(byte bytevec[]) {
+ return BuildLongBE(bytevec, 0);
+ }
+
+ /**
+ * Build long out of bytes (in little endian order).
+ *
+ * @param bytevec
+ * bytes
+ * @return long
+ */
+ public static final long BuildLongLE(byte bytevec[]) {
+ return BuildLongLE(bytevec, 0);
+ }
+
+ /**
+ * Build long out of bytes.
+ *
+ * @param bytevec
+ * bytes
+ * @param MSBFirst
+ * BE or LE?
+ * @return long
+ */
+ public static final long BuildLong(byte bytevec[], boolean MSBFirst) {
+ if (MSBFirst)
+ return BuildLongBE(bytevec, 0);
+ // else
+ return BuildLongLE(bytevec, 0);
+ }
+}
\ No newline at end of file
diff --git a/OsmAnd/src/com/jwetherell/openmap/common/ProjMath.java b/OsmAnd/src/com/jwetherell/openmap/common/ProjMath.java
new file mode 100644
index 0000000000..8750118a06
--- /dev/null
+++ b/OsmAnd/src/com/jwetherell/openmap/common/ProjMath.java
@@ -0,0 +1,465 @@
+// **********************************************************************
+//
+//
+ * "The geographic or geodetic latitude is the angle which a line
+ * perpendicular to the surface of the ellipsoid at the given point makes
+ * with the plane of the equator. ...The geocentric latitude is the angle
+ * made by a line to the center of the ellipsoid with the equatorial plane".
+ * ( Map Projections --A Working Manual , p 13)
+ *
+ * Translated from Ken Anderson's lisp code Freeing the Essence of
+ * Computation
+ *
+ * @param lat
+ * float geographic latitude in radians
+ * @param flat
+ * float flatening factor
+ * @return float geocentric latitude in radians
+ * @see #geographic_latitude
+ */
+ public static final float geocentricLatitude(float lat, float flat) {
+ float f = 1.0f - flat;
+ return (float) Math.atan((f * f) * (float) Math.tan(lat));
+ }
+
+ /**
+ * Calculate the geographic latitude given a geocentric latitude. Translated
+ * from Ken Anderson's lisp code Freeing the Essence of Computation
+ *
+ * @param lat
+ * float geocentric latitude in radians
+ * @param flat
+ * float flatening factor
+ * @return float geographic latitude in radians
+ * @see #geocentric_latitude
+ */
+ public static final float geographicLatitude(float lat, float flat) {
+ float f = 1.0f - flat;
+ return (float) Math.atan((float) Math.tan(lat) / (f * f));
+ }
+
+ /**
+ * Generic test for seeing if an left longitude value and a right longitude
+ * value seem to constitute crossing the dateline.
+ *
+ * @param leftLon
+ * the leftmost longitude, in decimal degrees. Expected to
+ * represent the location of the left side of a map window.
+ * @param rightLon
+ * the rightmost longitude, in decimal degrees. Expected to
+ * represent the location of the right side of a map window.
+ * @param projScale
+ * the projection scale, considered if the two values are very
+ * close to each other and leftLon less than rightLon.
+ * @return true if it seems like these two longitude values represent a
+ * dateline crossing.
+ */
+ public static boolean isCrossingDateline(double leftLon, double rightLon, float projScale) {
+ // if the left longitude is greater than the right, we're obviously
+ // crossing the dateline. If they are approximately equal, we could be
+ // showing the whole earth, but only if the scale is significantly
+ // large. If the scale is small, we could be really zoomed in.
+ return ((leftLon > rightLon) || (MoreMath.approximately_equal(leftLon, rightLon, .001f) && projScale > 1000000f));
+ }
+}
\ No newline at end of file
diff --git a/OsmAnd/src/com/jwetherell/openmap/common/UTMPoint.java b/OsmAnd/src/com/jwetherell/openmap/common/UTMPoint.java
new file mode 100644
index 0000000000..a778d4d787
--- /dev/null
+++ b/OsmAnd/src/com/jwetherell/openmap/common/UTMPoint.java
@@ -0,0 +1,461 @@
+// **********************************************************************
+//
+// null
if
+ * conversion failed. If you pass in a UTMPoint, it will be returned
+ * as well if successful.
+ */
+ public static UTMPoint LLtoUTM(LatLonPoint llpoint, Ellipsoid ellip, UTMPoint utmpoint) {
+ // find the native zone for the given latitude/longitude point
+ int zoneNumber = getZoneNumber(llpoint.getY(), llpoint.getX());
+ boolean isnorthern = (llpoint.getLatitude() >= 0f);
+
+ return LLtoUTM(llpoint, ellip, utmpoint, zoneNumber, isnorthern);
+ }
+
+ /**
+ * Converts a set of Longitude and Latitude co-ordinates to UTM given an
+ * ellipsoid and the UTM zone to use.
+ *
+ * @param ellip
+ * an ellipsoid definition.
+ * @param llpoint
+ * the coordinate to be converted
+ * @param utmPoint
+ * A UTMPoint instance to put the results in. If null, a new
+ * UTMPoint will be allocated.
+ * @param zoneNumber
+ * the number of the zone
+ * @param isNorthern
+ * true if zone is in northern hemispehere
+ * @return A UTM class instance containing the value of null
if
+ * conversion failed. If you pass in a UTMPoint, it will be returned
+ * as well if successful.
+ */
+ public static UTMPoint LLtoUTM(LatLonPoint llpoint, Ellipsoid ellip, UTMPoint utmPoint, int zoneNumber, boolean isNorthern) {
+ double a = ellip.radius;
+ double k0 = 0.9996;
+
+ double eccSquared = ellip.eccsq;
+ double eccPrimeSquared = (eccSquared) / (1 - eccSquared);
+ double eccSquared2 = eccSquared * eccSquared;
+ double eccSquared3 = eccSquared2 * eccSquared;
+
+ double N, T, C, A, M;
+
+ double LatRad = llpoint.getRadLat();
+ double LongRad = llpoint.getRadLon();
+
+ // in middle of zone
+ double LongOrigin = (zoneNumber - 1) * 6 - 180 + 3; // +3 puts origin
+ double LongOriginRad = Math.toRadians(LongOrigin);
+
+ double tanLatRad = Math.tan(LatRad);
+ double sinLatRad = Math.sin(LatRad);
+ double cosLatRad = Math.cos(LatRad);
+
+ N = a / Math.sqrt(1 - eccSquared * sinLatRad * sinLatRad);
+ T = tanLatRad * tanLatRad;
+ C = eccPrimeSquared * cosLatRad * cosLatRad;
+ A = cosLatRad * (LongRad - LongOriginRad);
+
+ M = a
+ * ((1 - eccSquared / 4 - 3 * eccSquared2 / 64 - 5 * eccSquared3 / 256) * LatRad
+ - (3 * eccSquared / 8 + 3 * eccSquared2 / 32 + 45 * eccSquared3 / 1024) * Math.sin(2 * LatRad)
+ + (15 * eccSquared2 / 256 + 45 * eccSquared3 / 1024) * Math.sin(4 * LatRad) - (35 * eccSquared3 / 3072) * Math.sin(6 * LatRad));
+
+ double UTMEasting = (k0 * N * (A + (1 - T + C) * A * A * A / 6.0d + (5 - 18 * T + T * T + 72 * C - 58 * eccPrimeSquared) * A * A * A * A * A / 120.0d) + 500000.0d);
+
+ double UTMNorthing = (k0 * (M + N
+ * Math.tan(LatRad)
+ * (A * A / 2 + (5 - T + 9 * C + 4 * C * C) * A * A * A * A / 24.0d + (61 - 58 * T + T * T + 600 * C - 330 * eccPrimeSquared) * A * A * A * A
+ * A * A / 720.0d)));
+ if (!isNorthern) {
+ UTMNorthing += 10000000.0f; // 10000000 meter offset for
+ // southern hemisphere
+ }
+
+ if (utmPoint == null) {
+ utmPoint = new UTMPoint();
+ }
+
+ utmPoint.northing = UTMNorthing;
+ utmPoint.easting = UTMEasting;
+ utmPoint.zone_number = zoneNumber;
+ utmPoint.zone_letter = isNorthern ? 'N' : 'S';
+
+ return utmPoint;
+ }
+
+ /**
+ * Returns 'N' if the latitude is equal to or above the equator, 'S' if it's
+ * below.
+ *
+ * @param lat
+ * The float value of the latitude.
+ *
+ * @return A char value
+ */
+ protected char getLetterDesignator(double lat) {
+ char letterDesignator = 'N';
+
+ if (lat < 0) {
+ letterDesignator = 'S';
+ }
+
+ return letterDesignator;
+ }
+
+ /**
+ * Converts UTM coords to lat/long given an ellipsoid given an instance of
+ * UTMPoint.
+ *
+ * @param utm_point
+ * A UTMPoint instance.
+ * @param ellip
+ * a ellipsoid definition.
+ * @param llpoint
+ * a LatLonPoint, if you want it to be filled in with the
+ * results. If null, a new LatLonPoint will be allocated.
+ * @return A LatLonPoint class instance containing the lat/long value, or
+ * null
if conversion failed. If you pass in a
+ * LatLonPoint, it will be returned as well, if successful.
+ */
+ public static LatLonPoint UTMtoLL(UTMPoint utm_point, Ellipsoid ellip, LatLonPoint llpoint) {
+ return UTMtoLL(ellip, utm_point.northing, utm_point.easting, utm_point.zone_number, utm_point.zone_letter, llpoint);
+ }
+
+ /**
+ * Converts UTM coords to lat/long given an ellipsoid. This is a convenience
+ * class where the Zone can be specified as a single string eg."61N" which
+ * is then broken down into the ZoneNumber and ZoneLetter.
+ *
+ * @param ellip
+ * an ellipsoid definition.
+ * @param UTMNorthing
+ * A float value for the northing to be converted.
+ * @param UTMEasting
+ * A float value for the easting to be converted.
+ * @param UTMZone
+ * A String value for the UTM zone eg."61N".
+ * @param llpoint
+ * a LatLonPoint, if you want it to be filled in with the
+ * results. If null, a new LatLonPoint will be allocated.
+ * @return A LatLonPoint class instance containing the lat/long value, or
+ * null
if conversion failed. If you pass in a
+ * LatLonPoint, it will be returned as well, if successful.
+ */
+ public static LatLonPoint UTMtoLL(Ellipsoid ellip, double UTMNorthing, double UTMEasting, String UTMZone, LatLonPoint llpoint) {
+ // without the zone we can't calculate the Lat and Long
+ if (UTMZone == null || UTMZone.length() == 0) {
+ return null;
+ }
+
+ int ZoneNumber = 1;
+ char ZoneLetter = 'N'; // northern hemisphere by default if no
+ // character is found
+
+ // Break out the Zone number and zone letter from the UTMZone
+ // string We assume the string is a valid zone with a number
+ // followed by a zone letter If there is no Letter we assume
+ // that it's the Northern hemisphere
+ int ln = UTMZone.length() - 1;
+ if (ln > 0) {
+ // If it's Zero then there is only one character and it
+ // must be the Zone number
+ ZoneLetter = UTMZone.charAt(ln);
+ if (!Character.isLetter(ZoneLetter)) {
+ // No letter so assume it's missing & default to 'N'
+ ZoneLetter = 'N';
+ ln++;
+ }
+ }
+
+ // convert the number but catch the exception if it's not
+ // valid
+ try {
+ ZoneNumber = Integer.parseInt(UTMZone.substring(0, ln));
+ } catch (NumberFormatException nfe) {
+ return null;
+ }
+
+ return UTMtoLL(ellip, UTMNorthing, UTMEasting, ZoneNumber, ZoneLetter, llpoint);
+ }
+
+ /**
+ * Converts UTM coords to lat/long given an ellipsoid. This is a convenience
+ * class where the exact Zone letter is not known. Instead only the
+ * hemisphere needs to be indicated.
+ *
+ * @param ellip
+ * an ellipsoid definition.
+ * @param UTMNorthing
+ * A float value for the northing to be converted.
+ * @param UTMEasting
+ * A float value for the easting to be converted.
+ * @param ZoneNumber
+ * An int value indicating the float number.
+ * @param isNorthern
+ * A boolean which is true for the northern hemisphere otherwise
+ * false for the southern.
+ * @param llpoint
+ * a LatLonPoint, if you want it to be filled in with the
+ * results. If null, a new LatLonPoint will be allocated.
+ * @return A LatLonPoint class instance containing the lat/long value, or
+ * null
if conversion failed. If you pass in a
+ * LatLonPoint, it will be returned as well, if successful.
+ */
+ public static LatLonPoint UTMtoLL(Ellipsoid ellip, double UTMNorthing, double UTMEasting, int ZoneNumber, boolean isNorthern, LatLonPoint llpoint) {
+ return UTMtoLL(ellip, UTMNorthing, UTMEasting, ZoneNumber, (isNorthern) ? 'N' : 'S', llpoint);
+ }
+
+ /**
+ * Converts UTM coords to lat/long given an ellipsoid.
+ *
+ * Equations from USGS Bulletin 1532
+ * East Longitudes are positive, West longitudes are negative.
+ * North latitudes are positive, South latitudes are negative.
+ *
+ * @param ellip
+ * an ellipsoid definition.
+ * @param UTMNorthing
+ * A float value for the northing to be converted.
+ * @param UTMEasting
+ * A float value for the easting to be converted.
+ * @param zoneNumber
+ * An int value specifiying the UTM zone number.
+ * @param zoneLetter
+ * A char value specifying the ZoneLetter within the ZoneNumber.
+ * @param llpoint
+ * a LatLonPoint, if you want it to be filled in with the
+ * results. If null, a new LatLonPoint will be allocated.
+ * @return A LatLonPoint class instance containing the lat/long value, or
+ * null
if conversion failed. If you pass in a
+ * LatLonPoint, it will be returned as well, if successful.
+ */
+ public static LatLonPoint UTMtoLL(Ellipsoid ellip, double UTMNorthing, double UTMEasting, int zoneNumber, char zoneLetter, LatLonPoint llpoint) {
+ // check the ZoneNummber is valid
+ if (zoneNumber < 0 || zoneNumber > 60) {
+ return null;
+ }
+
+ double k0 = 0.9996;
+ double a = ellip.radius;
+ double eccSquared = ellip.eccsq;
+ double eccPrimeSquared;
+ double e1 = (1 - Math.sqrt(1 - eccSquared)) / (1 + Math.sqrt(1 - eccSquared));
+ double N1, T1, C1, R1, D, M;
+ double LongOrigin;
+ double mu, phi1Rad;
+
+ // remove 500,000 meter offset for longitude
+ double x = UTMEasting - 500000.0d;
+ double y = UTMNorthing;
+
+ // We must know somehow if we are in the Northern or Southern
+ // hemisphere, this is the only time we use the letter So even
+ // if the Zone letter isn't exactly correct it should indicate
+ // the hemisphere correctly
+ if (zoneLetter == 'S') {
+ y -= 10000000.0d;// remove 10,000,000 meter offset used
+ // for southern hemisphere
+ }
+
+ // There are 60 zones with zone 1 being at West -180 to -174
+ LongOrigin = (zoneNumber - 1) * 6 - 180 + 3; // +3 puts origin
+ // in middle of
+ // zone
+
+ eccPrimeSquared = (eccSquared) / (1 - eccSquared);
+
+ M = y / k0;
+ mu = M / (a * (1 - eccSquared / 4 - 3 * eccSquared * eccSquared / 64 - 5 * eccSquared * eccSquared * eccSquared / 256));
+
+ phi1Rad = mu + (3 * e1 / 2 - 27 * e1 * e1 * e1 / 32) * Math.sin(2 * mu) + (21 * e1 * e1 / 16 - 55 * e1 * e1 * e1 * e1 / 32) * Math.sin(4 * mu)
+ + (151 * e1 * e1 * e1 / 96) * Math.sin(6 * mu);
+ // double phi1 = ProjMath.radToDeg(phi1Rad);
+
+ N1 = a / Math.sqrt(1 - eccSquared * Math.sin(phi1Rad) * Math.sin(phi1Rad));
+ T1 = Math.tan(phi1Rad) * Math.tan(phi1Rad);
+ C1 = eccPrimeSquared * Math.cos(phi1Rad) * Math.cos(phi1Rad);
+ R1 = a * (1 - eccSquared) / Math.pow(1 - eccSquared * Math.sin(phi1Rad) * Math.sin(phi1Rad), 1.5);
+ D = x / (N1 * k0);
+
+ double lat = phi1Rad
+ - (N1 * Math.tan(phi1Rad) / R1)
+ * (D * D / 2 - (5 + 3 * T1 + 10 * C1 - 4 * C1 * C1 - 9 * eccPrimeSquared) * D * D * D * D / 24 + (61 + 90 * T1 + 298 * C1 + 45 * T1 * T1 - 252
+ * eccPrimeSquared - 3 * C1 * C1)
+ * D * D * D * D * D * D / 720);
+ lat = ProjMath.radToDeg(lat);
+
+ double lon = (D - (1 + 2 * T1 + C1) * D * D * D / 6 + (5 - 2 * C1 + 28 * T1 - 3 * C1 * C1 + 8 * eccPrimeSquared + 24 * T1 * T1) * D * D * D * D * D
+ / 120)
+ / Math.cos(phi1Rad);
+ lon = LongOrigin + ProjMath.radToDeg(lon);
+ if (llpoint != null) {
+ llpoint.setLatLon(lat, lon);
+ return llpoint;
+ }
+ return new LatLonPoint(lat, lon);
+ }
+
+ /**
+ * Find zone number based on the given latitude and longitude in *degrees*.
+ *
+ * @param lat
+ * @param lon
+ * @return
+ */
+ private static int getZoneNumber(double lat, double lon) {
+ int zoneNumber = (int) ((lon + 180) / 6) + 1;
+
+ // Make sure the longitude 180.00 is in Zone 60
+ if (lon == 180) {
+ zoneNumber = 60;
+ }
+
+ // Special zone for Norway
+ if (lat >= 56.0f && lat < 64.0f && lon >= 3.0f && lon < 12.0f) {
+ zoneNumber = 32;
+ }
+
+ // Special zones for Svalbard
+ if (lat >= 72.0f && lat < 84.0f) {
+ if (lon >= 0.0f && lon < 9.0f) zoneNumber = 31;
+ else if (lon >= 9.0f && lon < 21.0f) zoneNumber = 33;
+ else if (lon >= 21.0f && lon < 33.0f) zoneNumber = 35;
+ else if (lon >= 33.0f && lon < 42.0f) zoneNumber = 37;
+ }
+
+ return zoneNumber;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return "Zone_number=" + zone_number + ", Hemisphere=" + zone_letter + ", Northing=" + northing + ", Easting=" + easting;
+ }
+}
diff --git a/OsmAnd/src/com/jwetherell/openmap/common/ZonedUTMPoint.java b/OsmAnd/src/com/jwetherell/openmap/common/ZonedUTMPoint.java
new file mode 100644
index 0000000000..b146d12523
--- /dev/null
+++ b/OsmAnd/src/com/jwetherell/openmap/common/ZonedUTMPoint.java
@@ -0,0 +1,111 @@
+// **********************************************************************
+//
+//
+ * Equations from USGS Bulletin 1532
+ * East Longitudes are positive, West longitudes are negative.
+ * North latitudes are positive, South latitudes are negative.
+ *
+ * @param ellip
+ * an ellipsoid definition.
+ * @param UTMNorthing
+ * A float value for the northing to be converted.
+ * @param UTMEasting
+ * A float value for the easting to be converted.
+ * @param ZoneNumber
+ * An int value specifiying the UTM zone number.
+ * @param ZoneLetter
+ * A char value specifying the ZoneLetter within the ZoneNumber,
+ * letter being MGRS zone.
+ * @param llpoint
+ * a LatLonPoint, if you want it to be filled in with the
+ * results. If null, a new LatLonPoint will be allocated.
+ * @return A LatLonPoint class instance containing the lat/long value, or
+ * null
if conversion failed. If you pass in a
+ * LatLonPoint, it will be returned as well, if successful.
+ */
+ public static LatLonPoint ZonedUTMtoLL(Ellipsoid ellip, double UTMNorthing, double UTMEasting, int ZoneNumber, char ZoneLetter, LatLonPoint llpoint) {
+ return UTMPoint.UTMtoLL(ellip, UTMNorthing, UTMEasting, ZoneNumber, MGRSPoint.MGRSZoneToUTMZone(ZoneLetter), llpoint);
+ }
+
+ /**
+ * Determines the correct MGRS letter designator for the given latitude
+ * returns 'Z' if latitude is outside the MGRS limits of 84N to 80S.
+ *
+ * @param lat
+ * The float value of the latitude.
+ *
+ * @return A char value which is the MGRS zone letter.
+ */
+ protected char getLetterDesignator(double lat) {
+ // This is here as an error flag to show that the Latitude is
+ // outside MGRS limits
+ char LetterDesignator = 'Z';
+
+ if ((84 >= lat) && (lat >= 72)) LetterDesignator = 'X';
+ else if ((72 > lat) && (lat >= 64)) LetterDesignator = 'W';
+ else if ((64 > lat) && (lat >= 56)) LetterDesignator = 'V';
+ else if ((56 > lat) && (lat >= 48)) LetterDesignator = 'U';
+ else if ((48 > lat) && (lat >= 40)) LetterDesignator = 'T';
+ else if ((40 > lat) && (lat >= 32)) LetterDesignator = 'S';
+ else if ((32 > lat) && (lat >= 24)) LetterDesignator = 'R';
+ else if ((24 > lat) && (lat >= 16)) LetterDesignator = 'Q';
+ else if ((16 > lat) && (lat >= 8)) LetterDesignator = 'P';
+ else if ((8 > lat) && (lat >= 0)) LetterDesignator = 'N';
+ else if ((0 > lat) && (lat >= -8)) LetterDesignator = 'M';
+ else if ((-8 > lat) && (lat >= -16)) LetterDesignator = 'L';
+ else if ((-16 > lat) && (lat >= -24)) LetterDesignator = 'K';
+ else if ((-24 > lat) && (lat >= -32)) LetterDesignator = 'J';
+ else if ((-32 > lat) && (lat >= -40)) LetterDesignator = 'H';
+ else if ((-40 > lat) && (lat >= -48)) LetterDesignator = 'G';
+ else if ((-48 > lat) && (lat >= -56)) LetterDesignator = 'F';
+ else if ((-56 > lat) && (lat >= -64)) LetterDesignator = 'E';
+ else if ((-64 > lat) && (lat >= -72)) LetterDesignator = 'D';
+ else if ((-72 > lat) && (lat >= -80)) LetterDesignator = 'C';
+ return LetterDesignator;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return "Zone_number=" + zone_number + ", Hemisphere=" + zone_letter + ", Northing=" + northing + ", Easting=" + easting;
+ }
+}
\ No newline at end of file