今天又是神奇的发现:我希望在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 * pp = (R / r) * P
那么, (R / r) 是什么呢,请看上图,只要是学习简单的立体几何的人应该都可以看来吧。对,它就等于 sec (α), 亦即原帖中所得的结果 1/cos (α)。
这样一来,大家都应该知道是怎么一回事了吧。希望对看到这篇博客的人有所帮助。