今天又是神奇的发现:我希望在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 (α)。
这样一来,大家都应该知道是怎么一回事了吧。希望对看到这篇博客的人有所帮助。