java 如何使用谷歌地图沿折线移动标记

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/40526350/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 05:17:38  来源:igfitidea点击:

How to move marker along polyline using google map

javaandroidgoogle-mapsgoogle-maps-markers

提问by Andrii Omelchenko

I am trying to move the marker according to the polyline and with animation. Similar to the below image:

我正在尝试根据折线和动画移动标记。类似于下图:

Taken from Mapbox

取自 Mapbox

Mapboxis already giving this kind of demo. But I want to achieve the same using Google maps. However right now my marker is not rotating along the path. Here is what I have tried:

Mapbox已经提供了这种演示。但我想使用谷歌地图实现同样的目标。但是现在我的标记没有沿着路径旋转。这是我尝试过的:

private void onReady(List<LatLng> polyz) {

      for (int i = 0; i < polyz.size() - 1; i++) {
        LatLng src = polyz.get(i);
        LatLng dest = polyz.get(i + 1);
        Polyline line = map.addPolyline(new PolylineOptions()
            .add(new LatLng(src.latitude, src.longitude),
                new LatLng(dest.latitude, dest.longitude))
            .width(2).color(Color.RED).geodesic(true));

      }
      LatLngBounds.Builder builder = new LatLngBounds.Builder();
      builder.include(polyz.get(0));
      builder.include(polyz.get(polyz.size()-1));
      map.moveCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), 48));
      map.animateCamera(CameraUpdateFactory.zoomTo(7), 1000, null);
      BitmapDescriptor icon = BitmapDescriptorFactory.fromResource(R.drawable.car);
      marker = map.addMarker(new MarkerOptions()
          .position(polyz.get(0))
          .title("Curr")
          .snippet("Move"));
      marker.setIcon(icon);

    }

And the animation:

和动画:

    private void animateMarker(GoogleMap myMap, final Marker marker, final List<LatLng> directionPoint,
      final boolean hideMarker) {
    final Handler handler = new Handler();
    final long start = SystemClock.uptimeMillis();
    Projection proj = myMap.getProjection();
    final long duration = 600000;

    final Interpolator interpolator = new LinearInterpolator();

    handler.post(new Runnable() {
      int i = 0;

      @Override
      public void run() {
        long elapsed = SystemClock.uptimeMillis() - start;
        float t = interpolator.getInterpolation((float) elapsed
            / duration);
        Location location=new Location(String.valueOf(directionPoint.get(i)));
        Location newlocation=new Location(String.valueOf(directionPoint.get(i+1)));
        marker.setAnchor(0.5f, 0.5f);
        marker.setRotation(location.bearingTo(newlocation)  - 45);
        if (i < directionPoint.size()) {
          marker.setPosition(directionPoint.get(i));
        }
        i++;

        if (t < 1.0) {
          // Post again 16ms later.
          handler.postDelayed(this, 16);
        } else {
          if (hideMarker) {
            marker.setVisible(false);
          } else {
            marker.setVisible(true);
          }
        }
      }
    });
  }

回答by Andrii Omelchenko

You can use for your task your approach based on custom marker animation: animate separately car movement and car turns throughout all direction points. For this You need 2 kinds of animation:

您可以将基于自定义标记动画的方法用于您的任务:在所有方向点上分别为汽车运动和汽车转弯设置动画。为此,您需要 2 种动画:

1) animation for car movement;

1) 汽车运动动画;

2) animation for car turn;

2)汽车转弯动画;

which calls each other on its end (car movement animation on end calls car turn animation and vice versa: car turn animation on its end calls car movement animation and so for all points of car path).

它在其末端相互调用(末端的汽车运动动画称为汽车转弯动画,反之亦然:汽车转弯动画在其末端调用汽车运动动画等对于汽车路径的所有点)。

For example on fig.:

例如上图:

enter image description here

在此处输入图片说明

1) animation for car movement from P0to P1;

1) 汽车从P0到 的运动动画P1

2) animation for car turn on P1;

2) 汽车启动动画P1

3) animation for car movement from P1to P2

3)汽车从P1到的运动动画P2

and so on.

等等。

Car movement animation can be implemented by method like this:

汽车运动动画可以通过这样的方法实现:

private void animateCarMove(final Marker marker, final LatLng beginLatLng, final LatLng endLatLng, final long duration) {
        final Handler handler = new Handler();
        final long startTime = SystemClock.uptimeMillis();

        final Interpolator interpolator = new LinearInterpolator();

        // set car bearing for current part of path
        float angleDeg = (float)(180 * getAngle(beginLatLng, endLatLng) / Math.PI);
        Matrix matrix = new Matrix();
        matrix.postRotate(angleDeg);
        marker.setIcon(BitmapDescriptorFactory.fromBitmap(Bitmap.createBitmap(mMarkerIcon, 0, 0, mMarkerIcon.getWidth(), mMarkerIcon.getHeight(), matrix, true)));

        handler.post(new Runnable() {
            @Override
            public void run() {
                // calculate phase of animation
                long elapsed = SystemClock.uptimeMillis() - startTime;
                float t = interpolator.getInterpolation((float) elapsed / duration);
                // calculate new position for marker
                double lat = (endLatLng.latitude - beginLatLng.latitude) * t + beginLatLng.latitude;
                double lngDelta = endLatLng.longitude - beginLatLng.longitude;

                if (Math.abs(lngDelta) > 180) {
                    lngDelta -= Math.signum(lngDelta) * 360;
                }
                double lng = lngDelta * t + beginLatLng.longitude;

                marker.setPosition(new LatLng(lat, lng));

                // if not end of line segment of path 
                if (t < 1.0) {
                    // call next marker position
                    handler.postDelayed(this, 16);
                } else {
                    // call turn animation
                    nextTurnAnimation();
                }
            }
        });
    }

where

在哪里

mMarkerIconis:

mMarkerIcon是:

Bitmap mMarkerIcon;
...
mMarkerIcon = BitmapFactory.decodeResource(getResources(), R.drawable.the_car);  // for your car icon in file the_car.png in drawable folder

and car icon should be North oriented:

和汽车图标应该朝北:

enter image description here

在此处输入图片说明

for correct rotation apply

正确旋转应用

nextTurnAnimation()- method called on end of car movement animation to start car turn animation:

nextTurnAnimation()- 在汽车运动动画结束时调用的方法以启动汽车转弯动画:

private void nextTurnAnimation() {
        mIndexCurrentPoint++;

        if (mIndexCurrentPoint < mPathPolygonPoints.size() - 1) {
            LatLng prevLatLng = mPathPolygonPoints.get(mIndexCurrentPoint - 1);
            LatLng currLatLng = mPathPolygonPoints.get(mIndexCurrentPoint);
            LatLng nextLatLng = mPathPolygonPoints.get(mIndexCurrentPoint + 1);

            float beginAngle = (float)(180 * getAngle(prevLatLng, currLatLng) / Math.PI);
            float endAngle = (float)(180 * getAngle(currLatLng, nextLatLng) / Math.PI);

            animateCarTurn(mCarMarker, beginAngle, endAngle, TURN_ANIMATION_DURATION);
        }
    }

In its turn car turn animation method can be like this:

轮到汽车转弯动画方法可以是这样的:

private void animateCarTurn(final Marker marker, final float startAngle, final float endAngle, final long duration) {
        final Handler handler = new Handler();
        final long startTime = SystemClock.uptimeMillis();
        final Interpolator interpolator = new LinearInterpolator();

        final float dAndgle = endAngle - startAngle;

        Matrix matrix = new Matrix();
        matrix.postRotate(startAngle);
        Bitmap rotatedBitmap = Bitmap.createBitmap(mMarkerIcon, 0, 0, mMarkerIcon.getWidth(), mMarkerIcon.getHeight(), matrix, true);
        marker.setIcon(BitmapDescriptorFactory.fromBitmap(rotatedBitmap));

        handler.post(new Runnable() {
            @Override
            public void run() {

                long elapsed = SystemClock.uptimeMillis() - startTime;
                float t = interpolator.getInterpolation((float) elapsed / duration);

                Matrix m = new Matrix();
                m.postRotate(startAngle + dAndgle * t);
                marker.setIcon(BitmapDescriptorFactory.fromBitmap(Bitmap.createBitmap(mMarkerIcon, 0, 0, mMarkerIcon.getWidth(), mMarkerIcon.getHeight(), m, true)));

                if (t < 1.0) {
                    handler.postDelayed(this, 16);
                } else {
                    nextMoveAnimation();
                }
            }
        });
    }

where nextMoveAnimation()is:

在哪里nextMoveAnimation()

private void nextMoveAnimation() {
        if (mIndexCurrentPoint <  mPathPolygonPoints.size() - 1) {
            animateCarMove(mCarMarker, mPathPolygonPoints.get(mIndexCurrentPoint), mPathPolygonPoints.get(mIndexCurrentPoint+1), MOVE_ANIMATION_DURATION);
        }
    }

The mPathPolygonPoints(geopoints of car trip) is:

mPathPolygonPoints(开车出行的geopoints)是:

private List<LatLng> mPathPolygonPoints;

And the mIndexCurrentPointvariable is index of current point on path (it should be 0 at start of animation and incremented on each turn of path in nextTurnAnimation()method).

mIndexCurrentPoint变量是在路径当前点的索引(它应该是0,在动画的开始和递增在路径的每匝nextTurnAnimation()方法)。

TURN_ANIMATION_DURATION- duration (in ms) animation for car turn on path geopoint;

TURN_ANIMATION_DURATION- 汽车开启路径地理点的持续时间(以毫秒为单位)动画;

MOVE_ANIMATION_DURATION- duration (in ms) animation for car movement along line segment of path;

MOVE_ANIMATION_DURATION- 汽车沿路径线段移动的持续时间(以毫秒为单位)动画;

To get bearing You can use method like that:

要获得轴承您可以使用这样的方法:

private double getAngle(LatLng beginLatLng, LatLng endLatLng) {
        double f1 = Math.PI * beginLatLng.latitude / 180;
        double f2 = Math.PI * endLatLng.latitude / 180;
        double dl = Math.PI * (endLatLng.longitude - beginLatLng.longitude) / 180;
        return Math.atan2(Math.sin(dl) * Math.cos(f2) , Math.cos(f1) * Math.sin(f2) - Math.sin(f1) * Math.cos(f2) * Math.cos(dl));;
    }

Finally You can start all animations by call animateCarMove()once:

最后,您可以通过调用animateCarMove()一次来启动所有动画:

animateCarMove(mCarMarker, mPathPolygonPoints.get(0), mPathPolygonPoints.get(1), MOVE_ANIMATION_DURATION);

other steps of animation will be called automatically for each point of car path.

将为汽车路径的每个点自动调用其他动画步骤。

And You should take into account some "special cases" like:

您应该考虑一些“特殊情况”,例如:

1) changing sign of of turn angle (e.g. bearing changes from -120 to 150 degrees);

1) 改变转向角的符号(例如方位角从-120度变为150度);

2) possibilities for interrupt of animation by user;

2) 用户中断动画的可能性;

3) calculate animation duration on path segment length (e.g. 1 sec for 1 km of segment length instead of fixed MOVE_ANIMATION_DURATION)

3) 计算路径段长度的动画持续时间(例如,1 公里段长度为 1 秒而不是固定MOVE_ANIMATION_DURATION

4) probably tune value 16in handler.postDelayed(this, 16);line for better performance;

4) 可能在线调整值16handler.postDelayed(this, 16);获得更好的性能;

5) and so on.

5)等等。

回答by antonio

The problem is the way you are creating your Locationobjects. You are using the Location (String provider)constructor that Construct a new Location with a named provider(documentation):

问题在于您创建Location对象的方式。您正在使用使用命名提供程序(文档)构造新位置Location (String provider)构造函数

By default time, latitude and longitude are 0, and the location has no bearing, altitude, speed, accuracy or extras.

默认时间,纬度和经度为 0,位置没有方位、高度、速度、精度或附加值。

In your case you are not creating a Locationwith your desired coordinates but a Locationwhose provider's name is String.valueOf(directionPoint.get(i))but the Locationobjects are created with latitude and longitude = 0.

在您的情况下,您不是Location使用所需的坐标创建一个,而是创建一个Location其提供者的名称,String.valueOf(directionPoint.get(i))Location对象是使用纬度和经度 = 0 创建的。

The correct way to create the Locationobjects is as follows:

创建Location对象的正确方法如下:

Location location = new Location(LocationManager.GPS_PROVIDER);
location.setLatitude(directionPoint.get(i).latitude);
location.setLongitude(directionPoint.get(i).longitude);

Location newlocation = new Location(LocationManager.GPS_PROVIDER);
newlocation.setLatitude(directionPoint.get(i+1).latitude);
newlocation.setLongitude(directionPoint.get(i+1).longitude);

Anyway take into account that you will get an ArrayIndexOutOfBoundsExceptionbecause you are not taking into account that i+1will be ==directionPoint.size()in the end.

无论如何要考虑到你会得到一个,ArrayIndexOutOfBoundsException因为你没有考虑到最终i+1会得到==directionPoint.size()的。

回答by noogui

I think what you're looking for is Marker Animations.

我认为您正在寻找的是Marker Animations

You can animate markers so that they exhibit dynamic movement in a variety of different circumstances. To specify the way a marker is animated, use the marker's animation property, of type google.maps.Animation. The following Animation values are supported:

-DROP indicates that the marker should drop from the top of the map to its final location when first placed on the map. Animation will cease once the marker comes to rest and animation will revert to null. This type of animation is usually specified during creation of the Marker.

-BOUNCE indicates that the marker should bounce in place. A bouncing marker will continue bouncing until its animation property is explicitly set to null.

您可以为标记设置动画,以便它们在各种不同情况下表现出动态运动。要指定标记动画的方式,请使用标记的动画属性,类型为 google.maps.Animation。支持以下动画值:

-DROP 表示标记首次放置在地图上时应从地图顶部下降到其最终位置。一旦标记静止,动画将停止,动画将恢复为空。这种类型的动画通常在创建标记期间指定。

-BOUNCE 表示标记应该弹跳到位。弹跳标记将继续弹跳,直到其动画属性显式设置为 null。

Here's a snippet from the guide:

这是指南中的一个片段:

var marker;

      function initMap() {
        var map = new google.maps.Map(document.getElementById('map'), {
          zoom: 13,
          center: {lat: 59.325, lng: 18.070}
        });

        marker = new google.maps.Marker({
          map: map,
          draggable: true,
          animation: google.maps.Animation.DROP,
          position: {lat: 59.327, lng: 18.067}
        });
        marker.addListener('click', toggleBounce);
      }

      function toggleBounce() {
        if (marker.getAnimation() !== null) {
          marker.setAnimation(null);
        } else {
          marker.setAnimation(google.maps.Animation.BOUNCE);
        }
      }