GoogleMaps API (Android) – 在缩放标记的边缘之间绘制多段线

GoogleMaps API (Android) – Draw PolyLine between the edges of Markers adjusting with Zoom

在 Android 上使用 GoogleMaps API,我将一系列标记添加到 MapOverlay。

当用户缩放地图时,这些标记在屏幕上保持相同大小。

我有一条连接这些标记的折线,它目前从每个标记的中心延伸到下一个标记。

我想更改此设置,使多段线在每个标记的边缘开始和结束。

我的问题是边缘的 Lat/Lng 随着用户缩放而改变。

最好的方法是什么?

我目前添加我的标记和线如下:

markerOptions = new MarkerOptions().position(latLng)
    .anchor(0.5F, 0.5F).draggable(false).visible(true)
    .icon(BitmapDescriptorFactory.fromResource(markerId));
this.googleMap.addMarker(markerOptions);

PolylineOptions options = new PolylineOptions();
options.add(new LatLng(controlPointEnd1.getLatitude(),controlPointEnd1.getLongitude()));
…
this.googleMap.addPolyline(options.width(4).color(Color.MAGENTA).geodesic(false)); 

Screen shot showing: Ground overlay, a couple of markers and the PolyLine 提前致谢。

目标

我看到您正在使用圆圈形式的图标,并且想创建一条连接圆圈边界而不是圆心的多段线。

这里我们要解决以下问题:

  1. 计算以屏幕像素为单位的圆形标记的半径。由于图标不会改变大小,它将是一个常量值。

  2. 计算圆边界坐标的偏移位置,并在这些点之间绘制折线

解决方案

计算屏幕像素圆半径的相关代码如下

//Let's calculate what is a radius in screen pixels for our icon
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
Drawable m_icon = ResourcesCompat.getDrawableForDensity(getResources(),R.drawable.ic_circle,dm.densityDpi,null);
int height = ((BitmapDrawable)m_icon).getBitmap().getHeight();
int width = ((BitmapDrawable)m_icon).getBitmap().getWidth();

iconRadiusPixels = width / 2;

我想您有圆形图标的可绘制资源 R.drawable.ic_circle。此代码可位于 onCreate() 方法中。

接下来是计算边界点偏移位置的函数。我们将需要具有 SphericalUtil class 的 Google Maps Android API Utility Library,我们可以使用它来计算点之间的航向和圆半径的偏移量。您必须将实用程序库包含在您的 gradle 中作为 compile 'com.google.maps.android:android-maps-utils:0.4'。代码的相关部分如下

private void showCustomPolyline () {
    //Get projection
    Projection proj = mMap.getProjection();
    //Get a point on the screen that corresponds to first marker
    Point p = proj.toScreenLocation(sydney1);
    //Lets create another point that is shifted on number of pixels iqual to icon radius
    //This point is located on circle border
    Point b = new Point(p.x + iconRadiusPixels, p.y);
    //Get the LatLng for a point on the circle border
    LatLng l = proj.fromScreenLocation(b);
    //Calculate the radius of the icon (distance between center and point on the circle border)
    double r = SphericalUtil.computeDistanceBetween(sydney1,l);
    //Calculate heading from point 1 to point 2 and from point 2 to point 1
    double heading1 = SphericalUtil.computeHeading(sydney1, sydney2);
    double heading2 = SphericalUtil.computeHeading(sydney2, sydney1);

    //Calculate real position where the polyline starts and ends taking into account radius and heading
    LatLng pos1 = SphericalUtil.computeOffset(sydney1, r, heading1);
    LatLng pos2 = SphericalUtil.computeOffset(sydney2, r, heading2);

    //Create polyline
    PolylineOptions options = new PolylineOptions();
    options.add(pos1);
    options.add(pos2);

    poly = mMap.addPolyline(options.width(4).color(Color.RED).geodesic(false));
}

最后,您可以监听 GoogleMap.OnCameraMoveListener 或 GoogleMap.OnCameraIdleListener 等相机事件,并在相机移动时重新绘制多段线。为简单起见,让我们在相机完成移动后重新绘制多段线

@Override
public void onCameraIdle() {
    if (this.poly != null) {
        this.poly.remove();
        this.poly = null;
    }
    this.showCustomPolyline();
}

结论

您可以从 GitHub

下载包含完整代码的示例项目

https://github.com/xomena-so/so43303695

只需在 app/src/debug/res/values/google_maps_api.xml

中用你的替换我的 API 密钥