怎么用metersToEquatorPixels实现任意纬度的米到像素的转换
今天又是神奇的发现:我希望在MapView的Overlay子类里画一个半径为 R米 的圆,于是用 metersToEquatorPixels 函数,将一个距离 R米 转换为一个以当前缩放等级下像素为单位的距离。调用的时候也没太注意,结果画出来的圆确实让我费解了阵子,仔细一看发现Equator这个单词,于是大概有点明白了。查了一下etersToEquatorPixels 函数的解释:该方法把以米为计量单位的距离(沿赤道)在当前缩放水平下转换到一个以像素(水平)为计量单位的距离。在默认的Mercator投影变换下,对于给定的距离,当远离赤道时,变换后确切的像素数量会增加。
SO,解决办法就是要将赤道,也就是零纬度的米对应的像素距离换算成我们需要的纬度的 米 对应的像素距离。我们可以写这么一个方法来实现:
public static int metersToRadius(float meters, MapView map, double latitude) { return (int) (map.getProjection().metersToEquatorPixels(meters) /(Math.cos(Math.toRadians(latitude)))); }
以上转自: http://cosyattic.com/archives/152
以下原创:
其实也可以这么理解,根据“GOOGLE MAP 源码”(关于源码,请参见:http://rainbow702.iteye.com/blog/1124280),我们可以看到该方法的实现:
public float metersToEquatorPixels(float meters) { return (float)meters*circumference /CIRCUMFERENCE_IN_METERS); }
而 circumference 与 CIRCUMFERENCE_IN_METERS 又分别是什么呢?如下:
private static final double CIRCUMFERENCE_IN_METERS = 40075160.0; private int tiles = 1 << zoomLevel; private double circumference = tileSize * tiles;
其中, zoomLevel 是你的 MapView 当前的缩放比例,tileSize 定义如下:
private MapSourceInfo mapSourceInfo = new CloudmadeSourceInfo("b06a3135a4eb5848a225483969f56967"); private int tileSize = mapSourceInfo.getTileSize(); CloudmadeSourceInfo 类的定义如下: class CloudmadeSourceInfo implements MapSourceInfo { private final String apiKey; private final int tileSize; private final int style; private final String attribution = "\u00a9 2009 CloudMade - Map data CC-BY-SA 2009\nOpenStreetMap.org contributors - Terms of Use"; CloudmadeSourceInfo(String apiKey) { this(apiKey, 256); } CloudmadeSourceInfo(String apiKey, int tileSize) { this(apiKey, tileSize, 1); } CloudmadeSourceInfo(String apiKey, int tileSize, int style) { this.apiKey = apiKey; this.tileSize = tileSize; this.style = style; } public int getMaxZoom() { return 18; } public String getName() { return "Open Street Maps Cloudmade renderer"; } public String getTileUri(int x, int y, int zoom) { return "http://b.tile.cloudmade.com/"+ apiKey +"/" + style + "/" + tileSize + "/" + zoom + "/" + x + "/" + y + ".png"; } public int getTileSize() { return tileSize; } public String getAttribution() { return attribution; } }
所以,假设赤道的半径为 R,我们所处的纬度为 α 度的平面(如上图红线所画的平面)的半径为 r,那么应该有以下等式成立(请再看一下metersToEquatorPixels的实现):
meters * (circumference /2πR) = P meters * (circumference / 2πr) = p
以上,P 是在赤道上 meters 米对应的像素的长度,而 p 是在 α 度纬度上 meters 米对应的像素的长度,进而可以得出以下等式:
2πR * P = 2πr * p
从而,最终得出以下等式:
2πR * P = 2πr * p p = (R / r) * P
那么, (R / r) 是什么呢,请看上图,只要是学习简单的立体几何的人应该都可以看来吧。对,它就等于 sec (α), 亦即原帖中所得的结果 1/cos (α)。
这样一来,大家都应该知道是怎么一回事了吧。希望对看到这篇博客的人有所帮助。