我正在使用Gooogle Maps API v2开发Android应用程序。我的地图上有标记,我想圈出其中一个。通过使用Circle和Circle Options类,我设法轻松地做到了这一点。但是我也喜欢我的圆圈在变焦或不变时在屏幕上保持相同的尺寸,就像标记一样。这意味着圆圈在像素方面必须具有恒定的半径。遗憾的是,我们无法在API v2中设置半径像素。
我尝试了几种解决方案,但我并不满意。
在第一个中,我只是乘以或除以半径:
@Override
public void onCameraChange(CameraPosition position)
{
if(previousZoom > position.zoom) {
mSelectionCircle.setRadius(Math.abs(position.zoom - previousZoom)*2*mSelectionCircle.getRadius());
}
else if(previousZoom < position.zoom) {
mSelectionCircle.setRadius(Math.abs(position.zoom - previousZoom)*mSelectionCircle.getRadius()/2);
}
previousZoom = position.zoom;
}
它似乎首先起作用,但在快速变焦或用手指缩放时会产生错误的结果。此外,缩放在屏幕上清晰可见。
我的第二个解决方案是使用像素计转换。这个想法是在缩放/不变时重新计算以米为单位的半径,因此圆圈在屏幕上具有恒定的大小。为此,我在屏幕上显示Circle的当前位置:
Point p1 = mMap.getProjection().toScreenLocation(mSelectionCircle.getCenter());
然后我创建另一个位于圆圈边缘的点:
Point p2 = new Point(p1.x + radiusInPixels, p1.y);
哪里
int radiusInPixels = 40;
之后,我使用一个函数返回这两个点之间的距离,以米为单位。
private double convertPixelsToMeters(Point point1, Point point2) {
double angle = Math.acos(Math.sin(point1.x) * Math.sin(point2.x)
+ Math.cos(point1.x) * Math.cos(point2.x) * Math.cos(point1.y- point2.y));
return angle * Math.PI * 6378100.0; // distance in meters
}
6378100是地球平均半径。最后,我设置了Circle的新半径:
mSelectionCircle.setRadius(convertPixelsToMeters(p1, p2));
它应该在理论上工作,但我得到荒谬的半径值(10 ^ 7米!)。转换功能可能有误?
那么有更简单的方法可以做到这一点,或者如果没有,你可以帮助我理解为什么我的第二个解决方案不起作用吗?
谢谢!
答案 0 :(得分:2)
我遇到了同样的问题并且找不到解决方案,所以我自己做了,我会发帖,希望它对其他人有帮助。
“标记”方法对我不起作用,因为我希望圆圈以特定的纬度/经度为中心,而你不能用标记做到这一点:如果你为标记设置一个圆形图标,圆形边缘将触摸lat / lng,但圆圈不会在lat / lng上居中。
我创建了一个函数,根据纬度和相机缩放级别计算应该是以米为单位的圆的大小,然后在地图上添加一个相机监听器,以便每次相机更改缩放级别时更新圆的大小。结果是圆圈尺寸没有变化(至少是裸眼)。
这是我的代码:
public static double calculateCircleRadiusMeterForMapCircle(final int _targetRadiusDip, final double _circleCenterLatitude,
final float _currentMapZoom) {
//That base value seems to work for computing the meter length of a DIP
final double arbitraryValueForDip = 156000D;
final double oneDipDistance = Math.abs(Math.cos(Math.toRadians(_circleCenterLatitude))) * arbitraryValueForDip / Math.pow(2, _currentMapZoom);
return oneDipDistance * (double) _targetRadiusDip;
}
public void addCircleWithConstantSize(){
final GoogleMap googleMap = ...//Retrieve your GoogleMap object here
//Creating a circle for the example
final CircleOptions co = new CircleOptions();
co.center(new LatLng(0,0));
co.fillColor(Color.BLUE);
final Circle circle = googleMap.addCircle(co);
//Setting a listener on the map camera to monitor when the camera changes
googleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {
@Override
public void onCameraMove() {
//Use the function to calculate the radius
final double radius = calculateCircleRadiusMeterForMapCircle(12, co.getCenter().latitude, googleMap.getCameraPosition().zoom);
//Apply the radius to the circle
circle.setRadius(radius);
}
});
}
答案 1 :(得分:2)
您可能并不真正关心精确的像素大小,只是它对于所有缩放级别和设备旋转看起来都相同。
这是一种相当简单的方法。绘制(如果更改了缩放,则重绘)一个圆,其半径是可见屏幕对角线的某个百分比。
Google Maps API v2具有getProjection()
功能,可返回可见屏幕4个角的纬度/经度坐标。然后使用超级方便的Location
类,您可以计算屏幕上可见对角线的距离,并使用该对角线的百分比作为圆的半径。无论缩放比例是什么或设备旋转方式,您的圆圈尺寸都相同。
以下是Java中的代码:
public Circle drawMapCircle(GoogleMap googleMap,LatLng latLng,Circle currentCircle) {
// get 2 of the visible diagonal corners of the map (could also use farRight and nearLeft)
LatLng topLeft = googleMap.getProjection().getVisibleRegion().farLeft;
LatLng bottomRight = googleMap.getProjection().getVisibleRegion().nearRight;
// use the Location class to calculate the distance between the 2 diagonal map points
float results[] = new float[4]; // probably only need 3
Location.distanceBetween(topLeft.latitude,topLeft.longitude,bottomRight.latitude,bottomRight.longitude,results);
float diagonal = results[0];
// use 5% of the diagonal for the radius (gives a 10% circle diameter)
float radius = diagonal / 20;
Circle circle = null;
if (currentCircle != null) {
// change the radius if the circle already exists (result of a zoom change)
circle = currentCircle;
circle.setRadius(radius);
} else {
// draw a new circle
circle = googleMap.addCircle(new CircleOptions()
.center(latLng)
.radius(radius)
.strokeColor(Color.BLACK)
.strokeWidth(2)
.fillColor(Color.LTGRAY));
}
return circle;
}
答案 2 :(得分:1)
使用Marker
的自定义图标代替。您可以创建Bitmap
和Canvas
,使用后者并将其用作Marker
图标:
new MarkerOptions().icon(BitmapDescriptorFactory.fromBitmap(bitmap))...
答案 3 :(得分:0)
正如MaciejGórski所说,这是正确而简单的方法;但是如果你在google map中有很多标记,比如说5k标记,它会大大降低性能。显示此事的一些建议是:
1)让我们搜索谷歌android map API的Marker聚类实用程序。
2)然而,Marker聚类可能并不完全符合您的目的。所以你可以自己定制它。以下是讨论此问题的主题:https://github.com/googlemaps/android-maps-utils/issues/29
对不起,我没试过,因为我发现使用Polyline满足了我的目的(显示路径)。
希望这个帮助, Mttdat。