我知道输入和输出是什么,但我不确定它是如何工作或为什么工作。
此代码用于给定包含一组点的最小和最大经度/纬度(正方形),确定Google地图上仍将显示所有这些点的最大缩放级别。原作者不见了,所以我不确定这些数字中的一些是什么(即6371和8)。认为这是一个难题= D
int mapdisplay = 322; //min of height and width of element which contains the map
double dist = (6371 * Math.acos(Math.sin(min_lat / 57.2958) * Math.sin(max_lat / 57.2958) +
(Math.cos(min_lat / 57.2958) * Math.cos(max_lat / 57.2958) * Math.cos((max_lon / 57.2958) - (min_lon / 57.2958)))));
double zoom = Math.floor(8 - Math.log(1.6446 * dist / Math.sqrt(2 * (mapdisplay * mapdisplay))) / Math.log (2));
if(numPoints == 1 || ((min_lat == max_lat)&&(min_lon == max_lon))){
zoom = 11;
}
答案 0 :(得分:11)
可以轻松解释一些数字
MeanRadiusEarthInKm = 6371(根据IUGG)
DegToRadDivisor = 180 / PI = 57.2958
再次,缩放级别使每一步的尺寸加倍,即将缩放级别增加屏幕尺寸的一半。
zoom = 8 - log(factor * dist) / log(2) = 8 - log_2(factor * dist)
=> dist = 2^(8-zoom) / factor
从数字中我们发现缩放级别8对应的距离为276.89km。
答案 1 :(得分:11)
我使用下面的简单公式:
public int getZoomLevel(Circle circle) {
if (circle != null){
double radius = circle.getRadius();
double scale = radius / 500;
zoomLevel =(int) (16 - Math.log(scale) / Math.log(2));
}
return zoomLevel;
}
您也可以用特定半径替换圆圈。
答案 2 :(得分:2)
This page非常有助于解释所有这些内容(两个lat-lng对之间的距离等)。
6371是以千米为单位的近似地球半径。
57.2958是180 / pi
另外,请查看这些墨卡托投影计算,以便在纬度 - 经度和X-Y之间进行转换:http://wiki.openstreetmap.org/wiki/Mercator
答案 3 :(得分:0)
我认为他得到了这个功能:
function calculateZoom(WidthPixel,Ratio,Lat,Length){
// from a segment Length (km),
// with size ratio of the of the segment expected on a map (70%),
// with a map widthpixel size (100px), and a latitude (45°) we can ge the best Zoom
// earth radius : 6,378,137m, earth is a perfect ball; perimeter at the equator = 40,075,016.7 m
// the full world on googlemap is available in a box of 256 px; It has a ratio of 156543.03392 (px/m)
// for Z = 0;
// pixel scale at the Lat_level is ( 156543,03392 * cos ( PI * (Lat/180) ))
// map scale increase at the rate of square root of Z
//
Length = Length *1000; //Length is in Km
var k = WidthPixel * 156543.03392 * Math.cos(Lat * Math.PI / 180); //k = perimeter of the world at the Lat_level, for Z=0
var myZoom = Math.round( Math.log( (Ratio * k)/(Length*100) )/Math.LN2 );
myZoom = myZoom -1; // z start from 0 instead of 1
//console.log("calculateZoom: width "+WidthPixel+" Ratio "+Ratio+" Lat "+Lat+" length "+Length+" (m) calculated zoom "+ myZoom);
// not used but it could be usefull for some: Part of the world size a the Lat
MapDim = k /Math.pow(2,myZoom);
//console.log("calculateZoom: size of the map at the Lat: "+MapDim + " meters.");
//console.log("calculateZoom: world perimeter at the Lat: " +k+ " meters.");
return(myZoom);
}
答案 4 :(得分:0)
我需要相反:给定某个缩放级别的特定半径(即缩放级别15的40米),我需要其他缩放级别的半径,在地图中显示相同的圆形大小(图形)。要做到这一点:
// after retrieving the googleMap from either getMap() or getMapAsync()...
// we want a circle with r=40 meters at zoom level 15
double base = 40 / zoomToDistFactor(15);
final Circle circle = googleMap.addCircle(new CircleOptions()
.center(center)
.radius(40)
.fillColor(Color.LTGRAY)
);
googleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {
@Override
public void onCameraMove() {
CameraPosition cameraPosition = googleMap.getCameraPosition();
LatLng center = cameraPosition.target;
float z2 = cameraPosition.zoom;
double newR = base * zoomToDistFactor(z2);
circle.setRadius(newR);
}
});
// ...
private double zoomToDistFactor(double z) {
return Math.pow(2,8-z) / 1.6446;
}
我想我会把它放在这里,以拯救其他人获得这种转换的努力。
作为旁注,在cameramovelistener中像这样移动圆圈会使圆圈运动变得非常不稳定。我最终将一个视图放在封闭的MapView的中心,只是画了一个小圆圈。
答案 5 :(得分:0)
经过多次尝试,我提出了解决方案。我假设您在半径之外有填充(例如,如果您的半径= 10000 m,那么左右将为2500 m)。另外,您还应该以米为单位。您可以设置带有反向缩放的合适缩放(二进制搜索)。如果将moveCamera
更改为animateCamera
,将获得有趣的搜索动画。半径越大,您收到的缩放值越准确。
private fun getCircleZoomValue(latitude: Double, longitude: Double, radius: Double,
minZoom: Float, maxZoom: Float): Float {
val position = LatLng(latitude, longitude)
val currZoom = (minZoom + maxZoom) / 2
val camera = CameraUpdateFactory.newLatLngZoom(position, currZoom)
googleMap!!.moveCamera(camera)
val results = FloatArray(1)
val topLeft = googleMap!!.projection.visibleRegion.farLeft
val topRight = googleMap!!.projection.visibleRegion.farRight
Location.distanceBetween(topLeft.latitude, topLeft.longitude, topRight.latitude,
topRight.longitude, results)
// Difference between visible width in meters and 2.5 * radius.
val delta = results[0] - 2.5 * radius
val accuracy = 10 // 10 meters.
return when {
delta < -accuracy -> getCircleZoomValue(latitude, longitude, radius, minZoom,
currZoom)
delta > accuracy -> getCircleZoomValue(latitude, longitude, radius, currZoom,
maxZoom)
else -> currZoom
}
}
用法:
if (googleMap != null) {
zoomCircle(latitude, longitude, radius, googleMap!!.minZoomLevel,
googleMap!!.maxZoomLevel)
}
您应在googleMap?.setOnCameraIdleListener
的第一个事件内部调用此方法,请参阅animateCamera works and moveCamera doesn't for GoogleMap - Android。如果您在onMapReady
之后立即调用它,则距离会错误,因为该时间该地图不会自行绘制。
警告!缩放级别取决于位置(纬度)。这样,根据距赤道的距离,圆具有相同的缩放级别将具有不同的大小(请参见Determine a reasonable zoom level for Google Maps given location accuracy)。