TileProvider方法getTile - 需要将x和y转换为lat/long

azc*_*tal 16 android google-maps google-maps-android-api-2 android-maps-v2

我正在将iOS应用程序移植到Android,并且使用Google Maps Android API v2. 该应用程序需要在地图上绘制热图叠加层.

到目前为止,看起来最好的选择是使用TileOverlay并实现自定义TileProvider.在该方法中getTile,我的方法被赋予x,y和zoom,并且需要以a的形式返回位图Tile.到现在为止还挺好.

我有一组热图项目,我将用它们在位图​​上绘制径向渐变,每个都有一个纬度/经度.我遇到以下两个任务有问题:

  1. 如何确定由x,y和zoom表示的图块是否包含热图项目的纬度/经度?
  2. 如何将热图项目的纬度/经度转换为位图的x/y坐标.

谢谢您的帮助!

UPDATE

感谢MaciejGórski的回答,以及marcin的实现,我能够回答我的问题的前半部分,但我仍然需要第二部分的帮助.为了澄清,我需要一个函数来返回指定纬度/经度的图块的x/y坐标.我试图扭转MaciejGórski的计算和marcin的答案而没有运气.

public static Point fromLatLng(LatLng latlng, int zoom){
    int noTiles = (1 << zoom);
    double longitudeSpan = 360.0 / noTiles;
    double mercator = fromLatitude(latlng.latitude);
    int y = ((int)(mercator / 360 * noTiles)) + 180;
    int x = (int)(latlng.longitude / longitudeSpan) + 180;
    return new Point(x, y);
}
Run Code Online (Sandbox Code Playgroud)

任何帮助表示赞赏!

Swa*_*shi 9

这对我有用:

double n = Math.pow(2, zoom);
double longitudeMin = x/n * 360 -180;
double lat_rad = Math.atan(Math.sinh(Math.PI * (1 - 2 * y/n)));
double latitudeMin = lat_rad * 180/Math.PI;

double longitudeMax = (x + 1)/n * 360 -180;
lat_rad = Math.atan(Math.sinh(Math.PI * (1 - 2 * (y + 1)/n)));
double latitudeMax = lat_rad * 180/Math.PI;
Run Code Online (Sandbox Code Playgroud)

参考文献:http: //wiki.openstreetmap.org/wiki/Slippy_map_tilenames


Mac*_*ski 8

在缩放级别0,只有一个图块(x = 0,y = 0).在下一个缩放级别上,图块的数量增加了四倍(在x和y上加倍).

这意味着在缩放级别上W,x可以是范围<0,1 << W)中的值.

来自文档:

瓷砖的坐标是从地图的左上角(西北角)测量的.在缩放级别N处,图块坐标的x值范围从0到2N-1并且从西向东增加,y值的范围从0到2N-1并且从北向南增加.

您可以使用简单的计算实现此目的.

对于经度,这很简单:

double longitudeMin = (((double) x) / (1 << zoom)) * 360 - 180;
double longitudeMax = (((double) x + 1) / (1 << zoom)) * 360 - 180;
longitudeMax = Double.longBitsToDouble(Double.doubleToLongBits(longitudeMax) - 1); // adjust
Run Code Online (Sandbox Code Playgroud)

这里x首先缩放为<0,1),然后变为<-180,180).

调整最大值,因此它不会与下一个区域重叠.你可以跳过这个.

对于纬度,这将更难,因为谷歌地图使用墨卡托投影.

首先你缩放y就像它在<-180,180范围内一样.请注意,值需要反转.

double mercatorMax = 180 - (((double) y) / (1 << zoom)) * 360;
double mercatorMin = 180 - (((double) y + 1) / (1 << zoom)) * 360;
Run Code Online (Sandbox Code Playgroud)

现在你使用一个执行墨卡托投影的魔法函数(来自SphericalMercator.java):

public static double toLatitude(double mercator) {
    double radians = Math.atan(Math.exp(Math.toRadians(mercator)));
    return Math.toDegrees(2 * radians) - 90;
}

latitudeMax = SphericalMercator.toLatitude(mercatorMax);
latitudeMin = SphericalMercator.toLatitude(mercatorMin);
latitudeMin = Double.longBitsToDouble(Double.doubleToLongBits(latitudeMin) + 1);
Run Code Online (Sandbox Code Playgroud)

这是从内存中输入的,没有以任何方式测试,所以如果有错误,请发表评论,我会解决它.


mar*_*cin 7

MaciejGórski如果你不介意(如果你这样做,我会删除这篇文章)我将你的代码编译成现成的方法:

private LatLngBounds boundsOfTile(int x, int y, int zoom) {
    int noTiles = (1 << zoom);
    double longitudeSpan = 360.0 / noTiles;
    double longitudeMin = -180.0 + x * longitudeSpan;

    double mercatorMax = 180 - (((double) y) / noTiles) * 360;
    double mercatorMin = 180 - (((double) y + 1) / noTiles) * 360;
    double latitudeMax = toLatitude(mercatorMax);
    double latitudeMin = toLatitude(mercatorMin);

    LatLngBounds bounds = new LatLngBounds(new LatLng(latitudeMin, longitudeMin), new LatLng(latitudeMax, longitudeMin + longitudeSpan));
    return bounds;
}
Run Code Online (Sandbox Code Playgroud)