From 29369fdf5a00e21c4dd7895f620a2207f213b54b Mon Sep 17 00:00:00 2001 From: "gmixaz@gmail.com" Date: Sun, 18 Sep 2016 20:14:42 +0300 Subject: [PATCH] adding Yandex TMS --- .../openstreetmap/gui/jmapviewer/TileXY.java | 5 + .../gui/jmapviewer/YandexUtils.java | 209 ++++++++++++++++++ .../jmapviewer/tilesources/TMSTileSource.java | 87 ++++++-- .../tilesources/TemplatedTMSTileSource.java | 15 +- 4 files changed, 299 insertions(+), 17 deletions(-) create mode 100644 src/org/openstreetmap/gui/jmapviewer/YandexUtils.java diff --git a/src/org/openstreetmap/gui/jmapviewer/TileXY.java b/src/org/openstreetmap/gui/jmapviewer/TileXY.java index f3419990d9a..11e79eb5b6c 100644 --- a/src/org/openstreetmap/gui/jmapviewer/TileXY.java +++ b/src/org/openstreetmap/gui/jmapviewer/TileXY.java @@ -54,4 +54,9 @@ public double getX() { public double getY() { return y; } + + @Override + public String toString() { + return "tile["+x+","+y+"]"; + } } diff --git a/src/org/openstreetmap/gui/jmapviewer/YandexUtils.java b/src/org/openstreetmap/gui/jmapviewer/YandexUtils.java new file mode 100644 index 00000000000..3acc1180801 --- /dev/null +++ b/src/org/openstreetmap/gui/jmapviewer/YandexUtils.java @@ -0,0 +1,209 @@ +package org.openstreetmap.gui.jmapviewer; + +/** + * The same as OsmMercator.java - tools to convert coordinates but for Yandex Elliptical Mercator projection + * + * Source: + * https://habrahabr.ru/post/151103/ + * http://www.geofaq.ru/forum/index.php?action=vthread&forum=2&topic=7&page=5#msg1152 + */ +public class YandexUtils { + + public static final int TILE_SIZE = 256; + + public static double[] geoToMercator(double[] g) { + double d = g[0] * Math.PI / 180, m = g[1] * Math.PI / 180, l = 6378137, k = 0.0818191908426, f = k + * Math.sin(m); + double h = Math.tan(Math.PI / 4 + m / 2), j = Math.pow( + Math.tan(Math.PI / 4 + Math.asin(f) / 2), k), i = h / j; + // return new DoublePoint(Math.round(l * d), Math.round(l * + // Math.log(i))); + return new double[] { l * d, l * Math.log(i) }; + } + + public static double[] mercatorToGeo(double[] e) { + double j = Math.PI, f = j / 2, i = 6378137, n = 0.003356551468879694, k = 0.00000657187271079536, h = 1.764564338702e-8, m = 5.328478445e-11; + double g = f - 2 * Math.atan(1 / Math.exp(e[1] / i)); + double l = g + n * Math.sin(2 * g) + k * Math.sin(4 * g) + h + * Math.sin(6 * g) + m * Math.sin(8 * g); + double d = e[0] / i; + return new double[] { d * 180 / Math.PI, l * 180 / Math.PI }; + } + + public static double[] mercatorToTiles(double[] e) { + double d = Math.round((20037508.342789 + e[0]) * 53.5865938), f = Math + .round((20037508.342789 - e[1]) * 53.5865938); + d = boundaryRestrict(d, 0, 2147483647); + f = boundaryRestrict(f, 0, 2147483647); + return new double[] { d, f }; + } + + public static double[] tileToMercator(long[] d) { + return new double[] { Math.round(d[0] / 53.5865938 - 20037508.342789), + Math.round(20037508.342789 - d[1] / 53.5865938) }; + } + + public static double[] tileCoordinatesToPixels(double[] i, int h) { + double g = Math.pow(2, toScale(h)); + return new double[] { (int) i[0] / g, (int) i[1] / g }; + } + + public static double boundaryRestrict(double f, double e, double d) { + return Math.max(Math.min(f, d), e); + } + + public static int toScale(int i) { + return 23 - i; + } + + public static long[] getTile(double[] h, int i) { + long e = 8; + long j = toScale(i), g = (long) h[0] >> j, f = (long) h[1] >> j; + return new long[] { g >> e, f >> e }; + } + + public static long[] getPxCoordFromTileCoord(double[] h, int i) { + long j = toScale(i), g = (long) h[0] >> j, f = (long) h[1] >> j; + return new long[] { g, f }; + } + + public static long[] getTileCoordFromPixCoord(long[] h, int i) { + long j = toScale(i), g = h[0] << j, f = h[1] << j; + return new long[] { g, f }; + + } + + public static double[] ReGetTile(double[] h, int i) { + long e = 8; + long j = toScale(i); + long g = (long) h[0] << (int) j; + long f = (long) h[1] << (int) j; + double ge = g << (int) e; + double fe = f << (int) e; + long g2 = (long) (h[0] + 1) << (int) j; + long f2 = (long) (h[1] + 1) << (int) j; + double ge2 = g2 << (int) e; + double fe2 = f2 << (int) e; + + double ad_g = (ge2 - ge) * (h[0] - Math.floor(h[0])); + double ad_f = (fe2 - fe) * (h[1] - Math.floor(h[1])); + + return new double[] { ge + ad_g, fe + ad_f }; + } + + public static double[] ReGetTile(long[] h, int i) { + long e = 8; + long j = toScale(i); + long g = (long) h[0] << (int) j; + long f = (long) h[1] << (int) j; + return new double[] { g << (int) e, f << (int) e }; + } + + public static double[] getGeoFromTile(int x, int y, int zoom) { + double a, c1, c2, c3, c4, g, z, mercX, mercY; + a = 6378137; + c1 = 0.00335655146887969; + c2 = 0.00000657187271079536; + c3 = 0.00000001764564338702; + c4 = 0.00000000005328478445; + mercX = (x * TILE_SIZE * 2 ^ (23 - zoom)) / 53.5865938 - 20037508.342789; + mercY = 20037508.342789 - (y * TILE_SIZE * 2 ^ (23 - zoom)) / 53.5865938; + + g = Math.PI / 2 - 2 * Math.atan(1 / Math.exp(mercY / a)); + z = g + c1 * Math.sin(2 * g) + c2 * Math.sin(4 * g) + c3 + * Math.sin(6 * g) + c4 * Math.sin(8 * g); + + return new double[] { mercX / a * 180 / Math.PI, z * 180 / Math.PI }; + } + + public static long[] getTileFromGeo(double lat, double lon, int zoom) { + double rLon, rLat, a, k, z; + rLon = lon * Math.PI / 180; + rLat = lat * Math.PI / 180; + a = 6378137; + k = 0.0818191908426; + z = Math.pow( + Math.tan(Math.PI / 4 + rLat / 2) + / (Math.tan(Math.PI / 4 + Math.asin(k * Math.sin(rLat)) + / 2)), k); + return new long[] { + (int)(((20037508.342789 + a * rLon) * 53.5865938 / Math.pow(2, + (23 - zoom)))) / TILE_SIZE, + (int)(((20037508.342789 - a * Math.log(z)) * 53.5865938 / Math + .pow(2, (23 - zoom)))) / TILE_SIZE}; + } + + public static double tile2lon(double x, int aZoom) { + return (x / Math.pow(2.0, aZoom) * 360.0) - 180; + } + + public static double tile2lat(double y, int aZoom) { + + final double MerkElipsK = 0.0000001; + final long sradiusa = 6378137; + final long sradiusb = 6356752; + final double FExct = (double) Math.sqrt(sradiusa * sradiusa - sradiusb + * sradiusb) + / sradiusa; + final int TilesAtZoom = 1 << aZoom; + double result = (y - TilesAtZoom / 2) / -(TilesAtZoom / (2 * Math.PI)); + result = (2 * Math.atan(Math.exp(result)) - Math.PI / 2) * 180 + / Math.PI; + double Zu = result / (180 / Math.PI); + double yy = ((y) - TilesAtZoom / 2); + + double Zum1 = Zu; + Zu = Math.asin(1 + - ((1 + Math.sin(Zum1)) * Math.pow(1 - FExct * Math.sin(Zum1), + FExct)) + / (Math.exp((2 * yy) / -(TilesAtZoom / (2 * Math.PI))) * Math + .pow(1 + FExct * Math.sin(Zum1), FExct))); + while (Math.abs(Zum1 - Zu) >= MerkElipsK) { + Zum1 = Zu; + Zu = Math + .asin(1 + - ((1 + Math.sin(Zum1)) * Math.pow( + 1 - FExct * Math.sin(Zum1), FExct)) + / (Math.exp((2 * yy) + / -(TilesAtZoom / (2 * Math.PI))) * Math + .pow(1 + FExct * Math.sin(Zum1), FExct))); + } + + result = Zu * 180 / Math.PI; + + return result; + + } + + public static double pixels2lon(int x, int aZoom) { + return tile2lon(x/(double)TILE_SIZE,aZoom); + } + + public static double pixels2lat(int y, int aZoom) { + return tile2lat(y/(double)TILE_SIZE,aZoom); + } + + public static double[] getMapTileFromCoordinates(final double aLat, + final double aLon, final int zoom) { + final double[] out = new double[2]; + + final double E2 = (double) aLat * Math.PI / 180; + final long sradiusa = 6378137; + final long sradiusb = 6356752; + 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; + final double B2 = (double) (1 << zoom); + out[0] = B2 / 2 - M2 * B2 / 2 / Math.PI; + + out[1] = (aLon + 180) / 360 * (1 << zoom); + + return out; + } +} diff --git a/src/org/openstreetmap/gui/jmapviewer/tilesources/TMSTileSource.java b/src/org/openstreetmap/gui/jmapviewer/tilesources/TMSTileSource.java index 9df810c5df3..de4f24e0056 100644 --- a/src/org/openstreetmap/gui/jmapviewer/tilesources/TMSTileSource.java +++ b/src/org/openstreetmap/gui/jmapviewer/tilesources/TMSTileSource.java @@ -6,6 +6,7 @@ import org.openstreetmap.gui.jmapviewer.Coordinate; import org.openstreetmap.gui.jmapviewer.OsmMercator; import org.openstreetmap.gui.jmapviewer.TileXY; +import org.openstreetmap.gui.jmapviewer.YandexUtils; import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate; /** @@ -17,6 +18,8 @@ public class TMSTileSource extends AbstractTMSTileSource { protected int minZoom; protected OsmMercator osmMercator; + private boolean useYandexMercator = false; + /** * Constructs a new {@code TMSTileSource}. * @param info tile source information @@ -28,6 +31,10 @@ public TMSTileSource(TileSourceInfo info) { this.osmMercator = new OsmMercator(this.getTileSize()); } + public void enableYandexMercator(boolean enable) { + useYandexMercator = enable; + } + @Override public int getMinZoom() { return (minZoom == 0) ? super.getMinZoom() : minZoom; @@ -45,33 +52,81 @@ public double getDistance(double lat1, double lon1, double lat2, double lon2) { @Override public Point latLonToXY(double lat, double lon, int zoom) { - return new Point( - (int) osmMercator.lonToX(lon, zoom), - (int) osmMercator.latToY(lat, zoom) - ); + Point pp; + if(useYandexMercator) { + double[] mercator = YandexUtils.geoToMercator(new double[] {lon, lat }); + double[] tiles = YandexUtils.mercatorToTiles(mercator); +// long xy[] = YandexUtils.getTileFromGeo(lat,lon,zoom); + pp = new Point( + (int) tiles[0], + (int) tiles[1] + ); + } + else { + pp = new Point( + (int) osmMercator.lonToX(lon, zoom), + (int) osmMercator.latToY(lat, zoom) + ); + } +// System.out.println("latLonToXY lat=" +lat+", lon="+lon+", zoom="+zoom+ ": p1="+ p1+" p2="+p2); + return pp; } @Override public ICoordinate xyToLatLon(int x, int y, int zoom) { - return new Coordinate( - osmMercator.yToLat(y, zoom), - osmMercator.xToLon(x, zoom) - ); + Coordinate cc; + if(useYandexMercator) { + cc = new Coordinate( + YandexUtils.pixels2lat(y,zoom), + YandexUtils.pixels2lon(x,zoom) + ); + } + else { + cc = new Coordinate( + osmMercator.yToLat(y, zoom), + osmMercator.xToLon(x, zoom) + ); + } +// System.out.println("xyToLatLon x=" +x+", y="+y+", zoom="+zoom+ ": cc1="+ cc1+" cc2="+cc2); + return cc; } @Override public TileXY latLonToTileXY(double lat, double lon, int zoom) { - return new TileXY( - osmMercator.lonToX(lon, zoom) / getTileSize(), - osmMercator.latToY(lat, zoom) / getTileSize() - ); + TileXY tileXY; + if(useYandexMercator) { + double xy[] = YandexUtils.getMapTileFromCoordinates(lat,lon,zoom); + tileXY = new TileXY( + xy[1], + xy[0] + ); + } + else { + tileXY = new TileXY( + osmMercator.lonToX(lon, zoom) / getTileSize(), + osmMercator.latToY(lat, zoom) / getTileSize() + ); + } +// System.out.println("latLonToTileXY lat=" +lat+", lon="+lon+", zoom="+zoom+ ": p1="+ tileXY1+" p2="+tileXY2); + return tileXY; } @Override public ICoordinate tileXYToLatLon(int x, int y, int zoom) { - return new Coordinate( - osmMercator.yToLat(y * getTileSize(), zoom), - osmMercator.xToLon(x * getTileSize(), zoom) - ); + Coordinate cc; + if(useYandexMercator) { + cc = new Coordinate( + YandexUtils.tile2lat(y,zoom), + YandexUtils.tile2lon(x,zoom) + ); + } + else { + cc = new Coordinate( + osmMercator.yToLat(y * getTileSize(), zoom), + osmMercator.xToLon(x * getTileSize(), zoom) + ); + } +// System.out.println("tileXYToLatLon x=" +x+", y="+y+", zoom="+zoom+ ": cc1="+ cc1+" cc2="+cc2); + return cc; } } diff --git a/src/org/openstreetmap/gui/jmapviewer/tilesources/TemplatedTMSTileSource.java b/src/org/openstreetmap/gui/jmapviewer/tilesources/TemplatedTMSTileSource.java index 6ee0c61f4c3..9f7b8f23216 100644 --- a/src/org/openstreetmap/gui/jmapviewer/tilesources/TemplatedTMSTileSource.java +++ b/src/org/openstreetmap/gui/jmapviewer/tilesources/TemplatedTMSTileSource.java @@ -43,10 +43,11 @@ public class TemplatedTMSTileSource extends TMSTileSource implements TemplatedTi private static final String PATTERN_NEG_Y = "\\{-y\\}"; private static final String PATTERN_SWITCH = "\\{switch:([^}]+)\\}"; private static final String PATTERN_HEADER = "\\{header\\(([^,]+),([^}]+)\\)\\}"; + private static final String PATTERN_YANDEX = "\\{yandex\\}"; // CHECKSTYLE.ON: SingleSpaceSeparator private static final String[] ALL_PATTERNS = { - PATTERN_HEADER, PATTERN_ZOOM, PATTERN_X, PATTERN_Y, PATTERN_Y_YAHOO, PATTERN_NEG_Y, PATTERN_SWITCH + PATTERN_HEADER, PATTERN_ZOOM, PATTERN_X, PATTERN_Y, PATTERN_Y_YAHOO, PATTERN_NEG_Y, PATTERN_SWITCH, PATTERN_YANDEX }; /** @@ -77,6 +78,18 @@ private void handleTemplate() { } matcher.appendTail(output); baseUrl = output.toString(); + + pattern = Pattern.compile(PATTERN_YANDEX); + output = new StringBuffer(); + matcher = pattern.matcher(baseUrl); + while (matcher.find()) { + enableYandexMercator(true); + matcher.appendReplacement(output, ""); + } + matcher.appendTail(output); + baseUrl = output.toString(); + + System.out.println("handleTemplate:"+baseUrl); } @Override