如何使用谷歌地图沿多段线移动标记 [英] How to move marker along polyline using google map

查看:134
本文介绍了如何使用谷歌地图沿多段线移动标记的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图根据多段线和动画来移动标记。类似于下面的图片:







适用于正确的轮转申请
$
$ b 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);


轮到车轮的动画方法可以像这样:

  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.postRotate(startAngle);
位图rotateBitmap = Bitmap.createBitmap(mMarkerIcon,0,0,mMarkerIcon.getWidth(),mMarkerIcon.getHeight(),matrix,true);
marker.setIcon(BitmapDescriptorFactory.fromBitmap(rotatedBitmap));

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

经过的时间= 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,mMarkIcon.getWidth(),mMarkerIcon.getHeight(),m,true)));

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

其中 nextMoveAnimation()是:

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


mPathPolygonPoints (汽车旅行的地理位置)是:

 私人列表< LatLng> mPathPolygonPoints; 

并且 mIndexCurrentPoint 变量是current的索引指向路径(它应该在动画开始时为0,并在 nextTurnAnimation()方法的每个路径中增加)。

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

获取方位您可以使用像即:

pre $ private double getAngle(LatLng beginLatLng,LatLng endLatLng){
double f1 = Math.PI * beginLatLng。纬度/ 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));;

$ / code>

最后您可以通过调用 animateCarMove ) once:

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

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



你应该考虑一些特殊情况,例如:

1)改变转角的符号-120到150度);

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

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

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



<5>)等等。


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

Mapbox is 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:

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

解决方案

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:

1) animation for car movement;

2) animation for car turn;

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.:

1) animation for car movement from P0 to P1;

2) animation for car turn on P1;

3) animation for car movement from P1 to 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

mMarkerIcon is:

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:

for correct rotation apply

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

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:

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:

private List<LatLng> mPathPolygonPoints;

And the mIndexCurrentPoint variable 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).

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

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

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

2) possibilities for interrupt of animation by user;

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

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

5) and so on.

这篇关于如何使用谷歌地图沿多段线移动标记的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆