当我开发Android地图应用程序时,我想在地图上画一个半径为1米的圆。众所周知,我无法直接绘制1米,我需要根据缩放级别将1米转换为两个像素之间的距离。如何进行转换?是否有任何API可供使用。
Canvas.draw(x, y, radius),我应该给这个方法传递什么值?
当我开发Android地图应用程序时,我想在地图上画一个半径为1米的圆。众所周知,我无法直接绘制1米,我需要根据缩放级别将1米转换为两个像素之间的距离。如何进行转换?是否有任何API可供使用。
Canvas.draw(x, y, radius),我应该给这个方法传递什么值?
假设您的地图是谷歌地图,它们使用墨卡托投影,因此您需要使用该投影进行转换。 在墨卡托投影下,像素代表的米数随着纬度的变化而变化,因此尽管米在地球半径比较小,但纬度非常重要。
以下所有示例都是 JavaScript,因此您可能需要将它们翻译成中文。
这里是坐标系统的一般说明:
http://code.google.com/apis/maps/documentation/javascript/maptypes.html#WorldCoordinates
此示例包含一个 MercatorProjection 对象,其中包括 fromLatLngToPoint() 和 fromPointToLatLng() 方法:
http://code.google.com/apis/maps/documentation/javascript/examples/map-coordinates.html
一旦您将 (x,y) 转换为 (lat,lon),这是如何绘制圆形的:
// Pseudo code
var d = radius/6378800; // 6378800 is Earth radius in meters
var lat1 = (PI/180)* centerLat;
var lng1 = (PI/180)* centerLng;
// Go around a circle from 0 to 360 degrees, every 10 degrees
for (var a = 0 ; a < 361 ; a+=10 ) {
var tc = (PI/180)*a;
var y = asin(sin(lat1)*cos(d)+cos(lat1)*sin(d)*cos(tc));
var dlng = atan2(sin(tc)*sin(d)*cos(lat1),cos(d)-sin(lat1)*sin(y));
var x = ((lng1-dlng+PI) % (2*PI)) - PI ;
var lat = y*(180/PI);
var lon = x*(180/PI);
// Convert the lat and lon to pixel (x,y)
}
这两个混搭应用程序在地球表面绘制给定半径的圆:
http://maps.forum.nu/gm_sensitive_circle2.html
http://maps.forum.nu/gm_drag_polygon.html
如果您选择忽略投影,则可以使用笛卡尔坐标,并使用勾股定理简单绘制圆形:
Projection projection = mapView.getProjection();
Point center = projection.toPixels(new GeoPoint(yourLat * E6, yourLong * E6), null);
float radius = projection.metersToEquatorPixels(radiusInMeters);
canvas.draw(center.x, center.y, radius, new Paint());
public static int metersToRadius(float meters, MapView map, double latitude) {
return (int) (map.getProjection().metersToEquatorPixels(meters) * (1/ Math.cos(Math.toRadians(latitude))));
}
三个问题你需要问: 1- 地图有多大 2- 缩放级别是多少 3- 屏幕有多大
让我们假设地图的宽高比与您的屏幕相同(如果不同,则需要考虑如何裁剪(垂直或水平)或如何拉伸并更改第1点的答案)
一旦您知道了第1和第3个问题的答案,就可以计算出100%缩放情况下米和像素之间的比率,因此您将拥有每米像素数
接下来,您需要保持一个缩放因子(例如:双倍大小的缩放为200%)
您的调用绘制圆形的代码应如下所示:
Canvas.draw(x,y, radius_in_meters * pixels_per_meter * zoom_factor/100);
您可以计算所需半径的缩放级别:
首先,我们需要计算手机屏幕的宽度。在缩放级别1下,地球赤道长度为256像素,每个后续缩放级别都会使表示地球赤道所需像素数量加倍。以下函数返回屏幕将显示1公里宽度区域的缩放级别。
private int calculateZoomLevel() {
int ht, screenWidth;
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
ht = displaymetrics.heightPixels;
screenWidth = displaymetrics.widthPixels;
double equatorLength = 40075004; // in meters
double widthInPixels = screenWidth;
double metersPerPixel = equatorLength / 256;
int zoomLevel = 1;
while ((metersPerPixel * widthInPixels) > 1000) {
metersPerPixel /= 2;
++zoomLevel;
}
Log.i(tag, "zoom level = " + zoomLevel);
return zoomLevel;
}