diff --git a/OsmAnd-java/src/net/osmand/util/MapUtils.java b/OsmAnd-java/src/net/osmand/util/MapUtils.java index df88dea313..eafb8c1c52 100644 --- a/OsmAnd-java/src/net/osmand/util/MapUtils.java +++ b/OsmAnd-java/src/net/osmand/util/MapUtils.java @@ -12,19 +12,17 @@ import net.osmand.util.GeoPointParserUtil.GeoParsedPoint; /** - * This utility class includes : + * This utility class includes : * 1. distance algorithms * 2. finding center for array of nodes * 3. tile evaluation algorithms - * - * */ public class MapUtils { - - // TODO change the hostname back to osm.org once HTTPS works for it - // https://github.com/openstreetmap/operations/issues/2 - private static final String BASE_SHORT_OSM_URL = "https://openstreetmap.org/go/"; - + + // TODO change the hostname back to osm.org once HTTPS works for it + // https://github.com/openstreetmap/operations/issues/2 + private static final String BASE_SHORT_OSM_URL = "https://openstreetmap.org/go/"; + /** * This array is a lookup table that translates 6-bit positive integer * index values into their "Base64 Alphabet" equivalents as specified @@ -38,19 +36,19 @@ public class MapUtils { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '_', '~' }; - public static double getDistance(LatLon l, double latitude, double longitude){ + public static double getDistance(LatLon l, double latitude, double longitude) { return getDistance(l.getLatitude(), l.getLongitude(), latitude, longitude); } - + private static double scalarMultiplication(double xA, double yA, double xB, double yB, double xC, double yC) { // Scalar multiplication between (AB, AC) - return (xB - xA) * (xC - xA) + (yB- yA) * (yC -yA); + return (xB - xA) * (xC - xA) + (yB - yA) * (yC - yA); } public static double getOrthogonalDistance(double lat, double lon, double fromLat, double fromLon, double toLat, double toLon) { return getDistance(getProjection(lat, lon, fromLat, fromLon, toLat, toLon), lat, lon); } - + public static LatLon getProjection(double lat, double lon, double fromLat, double fromLon, double toLat, double toLon) { // not very accurate computation on sphere but for distances < 1000m it is ok double mDist = (fromLat - toLat) * (fromLat - toLat) + (fromLon - toLon) * (fromLon - toLon); @@ -69,7 +67,7 @@ public class MapUtils { } return new LatLon(prlat, prlon); } - + public static double getProjectionCoeff(double lat, double lon, double fromLat, double fromLon, double toLat, double toLon) { // not very accurate computation on sphere but for distances < 1000m it is ok double mDist = (fromLat - toLat) * (fromLat - toLat) + (fromLon - toLon) * (fromLon - toLon); @@ -84,38 +82,38 @@ public class MapUtils { return (projection / mDist); } } - + private static double toRadians(double angdeg) { // return Math.toRadians(angdeg); return angdeg / 180.0 * Math.PI; } - + /** * Gets distance in meters */ - public static double getDistance(double lat1, double lon1, double lat2, double lon2){ + public static double getDistance(double lat1, double lon1, double lat2, double lon2) { double R = 6372.8; // for haversine use R = 6372.8 km instead of 6371 km - double dLat = toRadians(lat2-lat1); - double dLon = toRadians(lon2-lon1); - double a = Math.sin(dLat/2) * Math.sin(dLat/2) + - Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) * - Math.sin(dLon/2) * Math.sin(dLon/2); + double dLat = toRadians(lat2 - lat1); + double dLon = toRadians(lon2 - lon1); + double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + + Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) * + Math.sin(dLon / 2) * Math.sin(dLon / 2); //double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); //return R * c * 1000; // simplyfy haversine: return (2 * R * 1000 * Math.asin(Math.sqrt(a))); } - - + + /** * Gets distance in meters */ - public static double getDistance(LatLon l1, LatLon l2){ + public static double getDistance(LatLon l1, LatLon l2) { return getDistance(l1.getLatitude(), l1.getLongitude(), l2.getLatitude(), l2.getLongitude()); } - + public static double checkLongitude(double longitude) { - if(longitude > -180 && longitude <= 180) { + if (longitude > -180 && longitude <= 180) { return longitude; } while (longitude < -180 || longitude > 180) { @@ -127,9 +125,9 @@ public class MapUtils { } return longitude; } - + public static double checkLatitude(double latitude) { - if(latitude > -80 && latitude <= 80) { + if (latitude > -80 && latitude <= 80) { return latitude; } while (latitude < -90 || latitude > 90) { @@ -139,47 +137,46 @@ public class MapUtils { latitude -= 180; } } - if(latitude < -85.0511) { + if (latitude < -85.0511) { return -85.0511; - } else if(latitude > 85.0511){ - return 85.0511; - } + } else if (latitude > 85.0511) { + return 85.0511; + } return latitude; } - - public static int get31TileNumberX(double longitude){ + + public static int get31TileNumberX(double longitude) { longitude = checkLongitude(longitude); long l = 1L << 31; - return (int)((longitude + 180d)/360d * l); + return (int) ((longitude + 180d)/360d * l); } - public static int get31TileNumberY( double latitude){ + + public static int get31TileNumberY(double latitude) { latitude = checkLatitude(latitude); - double eval = Math.log( Math.tan(toRadians(latitude)) + 1/Math.cos(toRadians(latitude)) ); + double eval = Math.log(Math.tan(toRadians(latitude)) + 1/Math.cos(toRadians(latitude))); long l = 1L << 31; - if(eval > Math.PI){ + if (eval > Math.PI) { eval = Math.PI; } - return (int) ((1 - eval / Math.PI) / 2 * l); + return (int) ((1 - eval / Math.PI) / 2 * l); } - - public static double get31LongitudeX(int tileX){ - return MapUtils.getLongitudeFromTile(21, tileX /1024f); + + public static double get31LongitudeX(int tileX) { + return MapUtils.getLongitudeFromTile(21, tileX / 1024f); } - - public static double get31LatitudeY(int tileY){ + + public static double get31LatitudeY(int tileY) { return MapUtils.getLatitudeFromTile(21, tileY / 1024f); } - - - + + /** - * - * Theses methods operate with degrees (evaluating tiles & vice versa) + * Theses methods operate with degrees (evaluating tiles & vice versa) * degree longitude measurements (-180, 180) [27.56 Minsk] - // degree latitude measurements (90, -90) [53.9] + * // degree latitude measurements (90, -90) [53.9] */ - - public static double getTileNumberX(float zoom, double longitude){ + + public static double getTileNumberX(float zoom, double longitude) { longitude = checkLongitude(longitude); final double powZoom = getPowZoom(zoom); double dz = (longitude + 180d)/360d * powZoom; @@ -188,29 +185,29 @@ public class MapUtils { } return dz; } - - public static double getTileNumberY(float zoom, double latitude){ + + public static double getTileNumberY(float zoom, double latitude) { latitude = checkLatitude(latitude); - double eval = Math.log( Math.tan(toRadians(latitude)) + 1/Math.cos(toRadians(latitude)) ); + double eval = Math.log(Math.tan(toRadians(latitude)) + 1/Math.cos(toRadians(latitude))); if (Double.isInfinite(eval) || Double.isNaN(eval)) { - latitude = latitude < 0 ? - 89.9 : 89.9; - eval = Math.log( Math.tan(toRadians(latitude)) + 1/Math.cos(toRadians(latitude)) ); + latitude = latitude < 0 ? -89.9 : 89.9; + eval = Math.log(Math.tan(toRadians(latitude)) + 1/Math.cos(toRadians(latitude))); } return (1 - eval / Math.PI) / 2 * getPowZoom(zoom); } - - public static double getTileEllipsoidNumberY(float zoom, double latitude){ + + public static double getTileEllipsoidNumberY(float zoom, double latitude) { final double E2 = (double) latitude * Math.PI / 180; final long sradiusa = 6378137; final long sradiusb = 6356752; - final double J2 = (double) Math.sqrt(sradiusa * sradiusa - sradiusb * sradiusb) / sradiusa; + final double J2 = (double) Math.sqrt(sradiusa * sradiusa - sradiusb * sradiusb) / sradiusa; final double M2 = (double) Math.log((1 + Math.sin(E2)) - / (1 - Math.sin(E2)))/ 2- J2 * Math.log((1 + J2 * Math.sin(E2))/ (1 - J2 * Math.sin(E2))) / 2; + / (1 - Math.sin(E2))) / 2 - J2 * Math.log((1 + J2 * Math.sin(E2)) / (1 - J2 * Math.sin(E2))) / 2; final double B2 = getPowZoom(zoom); return B2 / 2 - M2 * B2 / 2 / Math.PI; } - - public static double getLatitudeFromEllipsoidTileY(float zoom, float tileNumberY){ + + public static double getLatitudeFromEllipsoidTileY(float zoom, float tileNumberY) { final double MerkElipsK = 0.0000001; final long sradiusa = 6378137; final long sradiusb = 6356752; @@ -236,54 +233,52 @@ public class MapUtils { return Zu * 180 / Math.PI; } - - + + public static double getTileDistanceWidth(float zoom) { LatLon ll = new LatLon(30, MapUtils.getLongitudeFromTile(zoom, 0)); LatLon ll2 = new LatLon(30, MapUtils.getLongitudeFromTile(zoom, 1)); - return getDistance(ll, ll2) ; + return getDistance(ll, ll2); } - + public static double getLongitudeFromTile(double zoom, double x) { return x / getPowZoom(zoom) * 360.0 - 180.0; } - - public static double getPowZoom(double zoom){ - if(zoom >= 0 && zoom - Math.floor(zoom) < 0.001f){ - return 1 << ((int)zoom); + + public static double getPowZoom(double zoom) { + if (zoom >= 0 && zoom - Math.floor(zoom) < 0.001f) { + return 1 << ((int) zoom); } else { return Math.pow(2, zoom); } } - - - public static float calcDiffPixelX(float rotateSin, float rotateCos, float dTileX, float dTileY, float tileSize){ - return (rotateCos * dTileX - rotateSin * dTileY) * tileSize ; + + public static float calcDiffPixelX(float rotateSin, float rotateCos, float dTileX, float dTileY, float tileSize) { + return (rotateCos * dTileX - rotateSin * dTileY) * tileSize; } - - public static float calcDiffPixelY(float rotateSin, float rotateCos, float dTileX, float dTileY, float tileSize){ - return (rotateSin * dTileX + rotateCos * dTileY) * tileSize ; + + public static float calcDiffPixelY(float rotateSin, float rotateCos, float dTileX, float dTileY, float tileSize) { + return (rotateSin * dTileX + rotateCos * dTileY) * tileSize; } - + public static double getLatitudeFromTile(float zoom, double y) { int sign = y < 0 ? -1 : 1; return Math.atan(sign * Math.sinh(Math.PI * (1 - 2 * y / getPowZoom(zoom)))) * 180d / Math.PI; } - - - public static int getPixelShiftX(float zoom, double long1, double long2, double tileSize){ + + + public static int getPixelShiftX(float zoom, double long1, double long2, double tileSize) { return (int) ((getTileNumberX(zoom, long1) - getTileNumberX(zoom, long2)) * tileSize); } - - - public static int getPixelShiftY(float zoom, double lat1, double lat2, double tileSize){ + + + public static int getPixelShiftY(float zoom, double lat1, double lat2, double tileSize) { return (int) ((getTileNumberY(zoom, lat1) - getTileNumberY(zoom, lat2)) * tileSize); } - - - - public static void sortListOfMapObject(List list, final double lat, final double lon){ + + + public static void sortListOfMapObject(List list, final double lat, final double lon) { Collections.sort(list, new Comparator() { @Override public int compare(MapObject o1, MapObject o2) { @@ -292,17 +287,17 @@ public class MapUtils { } }); } - + public static String buildGeoUrl(double latitude, double longitude, int zoom) { - return "geo:" + ((float) latitude) + "," + ((float)longitude) + "?z=" + zoom; + return "geo:" + ((float) latitude) + "," + ((float) longitude) + "?z=" + zoom; } - + // Examples // System.out.println(buildShortOsmUrl(51.51829d, 0.07347d, 16)); // http://osm.org/go/0EEQsyfu // System.out.println(buildShortOsmUrl(52.30103d, 4.862927d, 18)); // http://osm.org/go/0E4_JiVhs // System.out.println(buildShortOsmUrl(40.59d, -115.213d, 9)); // http://osm.org/go/TelHTB-- - public static String buildShortOsmUrl(double latitude, double longitude, int zoom){ - return BASE_SHORT_OSM_URL + createShortLinkString(latitude, longitude, zoom) + "?m"; + public static String buildShortOsmUrl(double latitude, double longitude, int zoom) { + return BASE_SHORT_OSM_URL + createShortLinkString(latitude, longitude, zoom) + "?m"; } public static String createShortLinkString(double latitude, double longitude, int zoom) { @@ -310,9 +305,9 @@ public class MapUtils { long lon = (long) (((longitude + 180d)/360d)*(1L << 32)); long code = interleaveBits(lon, lat); String str = ""; - // add eight to the zoom level, which approximates an accuracy of one pixel in a tile. + // add eight to the zoom level, which approximates an accuracy of one pixel in a tile. for (int i = 0; i < Math.ceil((zoom + 8) / 3d); i++) { - str += intToBase64[(int) ((code >> (58 - 6 * i)) & 0x3f)]; + str += intToBase64[(int) ((code >> (58 - 6 * i)) & 0x3f)]; } // append characters onto the end of the string to represent // partial zoom levels (characters themselves have a granularity of 3 zoom levels). @@ -321,7 +316,7 @@ public class MapUtils { } return str; } - + public static GeoParsedPoint decodeShortLinkString(String s) { // convert old shortlink format to current one s = s.replaceAll("@", "~"); @@ -346,28 +341,28 @@ public class MapUtils { x <<= 3; y <<= 3; for (int j = 2; j >= 0; j--) { - x |= ((digit & (1 << (j+j+1))) == 0 ? 0 : (1 << j)); - y |= ((digit & (1 << (j+j))) == 0 ? 0 : (1 << j)); + x |= ((digit & (1 << (j + j + 1))) == 0 ? 0 : (1 << j)); + y |= ((digit & (1 << (j + j))) == 0 ? 0 : (1 << j)); } z += 3; } double lon = x * Math.pow(2, 2 - 3 * i) * 90. - 180; double lat = y * Math.pow(2, 2 - 3 * i) * 45. - 90; // adjust z - if(i < s.length() && s.charAt(i) == '-') { + if (i < s.length() && s.charAt(i) == '-') { z -= 2; - if(i + 1 < s.length() && s.charAt(i + 1) == '-') + if (i + 1 < s.length() && s.charAt(i + 1) == '-') z++; } return new GeoParsedPoint(lat, lon, z); } - - /** - * interleaves the bits of two 32-bit numbers. the result is known as a Morton code. + + /** + * interleaves the bits of two 32-bit numbers. the result is known as a Morton code. */ - private static long interleaveBits(long x, long y){ + private static long interleaveBits(long x, long y) { long c = 0; - for(byte b = 31; b>=0; b--){ + for (byte b = 31; b >= 0; b--) { c = (c << 1) | ((x >> b) & 1); c = (c << 1) | ((y >> b) & 1); } @@ -376,82 +371,84 @@ public class MapUtils { /** * Calculate rotation diff D, that R (rotate) + D = T (targetRotate) - * D is between -180, 180 + * D is between -180, 180 + * * @param rotate * @param targetRotate - * @return + * @return */ public static float unifyRotationDiff(float rotate, float targetRotate) { float d = targetRotate - rotate; - while(d >= 180){ + while (d >= 180) { d -= 360; } - while(d < -180){ + while (d < -180) { d += 360; } return d; } - + /** * Calculate rotation diff D, that R (rotate) + D = T (targetRotate) - * D is between -180, 180 + * D is between -180, 180 + * * @param rotate * @return */ public static float unifyRotationTo360(float rotate) { - while(rotate < -180){ + while (rotate < -180) { rotate += 360; } - while(rotate > +180){ + while (rotate > +180) { rotate -= 360; } return rotate; } /** - * @param diff align difference between 2 angles ]-PI, PI] - * @return + * @param diff align difference between 2 angles ]-PI, PI] + * @return */ public static double alignAngleDifference(double diff) { - while(diff > Math.PI) { + while (diff > Math.PI) { diff -= 2 * Math.PI; } - while(diff <=-Math.PI) { + while (diff <= -Math.PI) { diff += 2 * Math.PI; } return diff; - + } - + /** - * diff align difference between 2 angles ]-180, 180] - * @return + * diff align difference between 2 angles [-180, 180] + * + * @return */ public static double degreesDiff(double a1, double a2) { double diff = a1 - a2; - while(diff > 180) { + while (diff > 180) { diff -= 360; } - while(diff <=-180) { + while (diff <= -180) { diff += 360; } return diff; - - } + } + - public static double convert31YToMeters(double y1, double y2) { // translate into meters return (y1 - y2) * 0.01863d; } - + public static double convert31XToMeters(double x1, double x2) { // translate into meters return (x1 - x2) * 0.011d; } - - - public static QuadPoint getProjectionPoint31(int px, int py, int st31x, int st31y,int end31x, int end31y) { + + + public static QuadPoint getProjectionPoint31(int px, int py, int st31x, int st31y, int end31x, int end31y) { double projection = calculateProjection31TileMetric(st31x, st31y, end31x, end31y, px, py); double mDist = squareRootDist31(end31x, end31y, st31x, @@ -472,9 +469,8 @@ public class MapUtils { } return new QuadPoint(prx, pry); } - - - + + public static double squareRootDist31(int x1, int y1, int x2, int y2) { // translate into meters double dy = MapUtils.convert31YToMeters(y1, y2); @@ -482,18 +478,18 @@ public class MapUtils { return Math.sqrt(dx * dx + dy * dy); // return measuredDist(x1, y1, x2, y2); } - + public static double measuredDist31(int x1, int y1, int x2, int y2) { return getDistance(MapUtils.get31LatitudeY(y1), MapUtils.get31LongitudeX(x1), MapUtils.get31LatitudeY(y2), MapUtils.get31LongitudeX(x2)); } - + public static double squareDist31TileMetric(int x1, int y1, int x2, int y2) { // translate into meters double dy = convert31YToMeters(y1, y2); double dx = convert31XToMeters(x1, x2); return dx * dx + dy * dy; } - + public static double calculateProjection31TileMetric(int xA, int yA, int xB, int yB, int xC, int yC) { // Scalar multiplication between (AB, AC) double multiple = MapUtils.convert31XToMeters(xB, xA) * MapUtils.convert31XToMeters(xC, xA) + @@ -502,8 +498,8 @@ public class MapUtils { } public static boolean rightSide(double lat, double lon, - double aLat, double aLon, - double bLat, double bLon) { + double aLat, double aLon, + double bLat, double bLon) { double ax = aLon - lon; double ay = aLat - lat; double bx = bLon - lon;