绘制常量大小的圆圈在屏幕上在谷歌地图API第2版(Draw circles of constant

2019-09-02 03:39发布

我正在使用Gooogle企业地图API V2的Android应用程序。 我有我的地图标记,我想圆他们中的一个。 我成功地做到这一点很容易,用圈与圈选项类。 但我也希望我的圈子里来放大或unzooming时,就像做标记保持相同的尺寸在屏幕上。 这意味着,圈必须在像素方面恒定的半径。 可悲的是,我们不能设置在API第2个像素的半径。

我尝试了好几种解决方案,但我不太满意。

在第一个,我刚乘或除半径:

@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;
}

它似乎在第一次工作,但很快就放大或用手指缩放时产生错误的结果。 此外,该比例在屏幕上清晰可见。

我的第二个解决方案是采用像素米的转换。 我们的想法是缩放/ unzooming时重新计算半径米,所以圆的屏幕上有一定的大小。 要做到这一点,我得到的屏幕上圆的当前位置:

 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平均是地球半径。 最后,我设置了圆的半径新:

  mSelectionCircle.setRadius(convertPixelsToMeters(p1, p2));

这在理论上应该工作,但我得到可笑的半径值(10 ^7米!)。 该转换功能可能是错的?

那么,有没有一个简单的方法来做到这一点,如果没有,你可以帮我明白为什么我的第二个soluton不起作用?

谢谢!

Answer 1:

使用自定义图标Marker代替。 您可以创建BitmapCanvas ,画上了后者,并把它作为一个Marker图标:

new MarkerOptions().icon(BitmapDescriptorFactory.fromBitmap(bitmap))...


Answer 2:

我来到翻过了同样的问题,找不到解决办法,所以我做到了我自己,我会后,希望是有帮助的一些其他人。

该“标记”的做法并没有为我工作,因为我想圈在一个特定的纬度/经度为中心的,你不能这样做,有一个标记:如果您设置一个圆圈图标为您的标记,圆边会触动LAT /经度,但圆不会对纬度/经度为中心。

我创建了一个函数来计算应该是什么在给定的纬度和摄像机缩放级别米圆的大小,然后添加在地图上的摄像机监听器来更新循环的每次改变摄像机缩放级别的大小。 其结果是一个不圆的尺寸(至少到裸眼)改变。

这里是我的代码:

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);
        }
    });
}


Answer 3:

你可能真的不关心精确的像素大小,只是它会查找所有缩放级别和设备旋转相同。

这是一个相当简单的方式来做到这一点。 绘制(重绘如果变焦改变)一个圆的半径是对角线可视屏幕的一定百分比。

谷歌地图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;
}


Answer 4:

作为MaciejGórski建议,这是去正确的和简单的方法; 但如果你有很多在谷歌地图的标记,让我们说5K的标记,例如,它会极大地降低性能。 一些建议,以显示这件事情是:

1)让谷歌Android地图API的搜索标记聚集效用。

2)然而,标记集群也许不是完全贴合你的目的。 所以,你可以自己定制。 这里是线程讨论这件事情: https://github.com/googlemaps/android-maps-utils/issues/29

我很抱歉,我没有尝试它,因为我发现用折线满足我的目的(显示路径)。

希望这有助于,Mttdat。



文章来源: Draw circles of constant size on screen in Google Maps API v2