Skip to content

Commit

Permalink
adding Yandex TMS
Browse files Browse the repository at this point in the history
  • Loading branch information
mixaz committed Sep 18, 2016
1 parent a9c6bee commit 29369fd
Show file tree
Hide file tree
Showing 4 changed files with 299 additions and 17 deletions.
5 changes: 5 additions & 0 deletions src/org/openstreetmap/gui/jmapviewer/TileXY.java
Expand Up @@ -54,4 +54,9 @@ public double getX() {
public double getY() {
return y;
}

@Override
public String toString() {
return "tile["+x+","+y+"]";
}
}
209 changes: 209 additions & 0 deletions 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;
}
}
87 changes: 71 additions & 16 deletions src/org/openstreetmap/gui/jmapviewer/tilesources/TMSTileSource.java
Expand Up @@ -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;

/**
Expand All @@ -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
Expand All @@ -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;
Expand All @@ -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;
}
}
Expand Up @@ -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
};

/**
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 29369fd

Please sign in to comment.