web-dev-qa-db-fra.com

Comment déplacer le marqueur le long de la polyligne à l'aide de Google Map

J'essaie de déplacer le marqueur selon la polyligne et avec animation. Similaire à l'image ci-dessous:

Taken from Mapbox

Mapbox propose déjà ce type de démo. Mais je veux obtenir le même résultat en utilisant Google maps. Cependant, en ce moment, mon marqueur ne tourne pas le long du chemin. Voici ce que j'ai essayé:

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

    }

Et l'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);
          }
        }
      }
    });
  }
25
user7140906

Vous pouvez utiliser pour votre tâche votre approche basée sur une animation de marqueur personnalisée: animez séparément le mouvement de la voiture et les virages de la voiture à travers tous les points de direction. Pour cela, vous avez besoin de 2 types d'animation:

1) animation pour le mouvement de la voiture;

2) animation pour le tour de voiture;

qui s'appelle les uns sur les autres (animation de mouvement de voiture à la fin appelle l'animation de virage de voiture et vice versa: l'animation de virage de voiture à sa fin appelle l'animation de mouvement de voiture et ainsi pour tous les points du chemin de la voiture).

Par exemple sur la fig .:

enter image description here

1) animation pour le mouvement de la voiture de P0 À P1;

2) animation pour allumer la voiture P1;

3) animation pour le mouvement de la voiture de P1 À P2

etc.

L'animation de mouvement de voiture peut être implémentée par une méthode comme celle-ci:

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

mMarkerIcon est:

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

et l'icône de voiture doit être orientée vers le nord:

enter image description here

pour une rotation correcte appliquer

nextTurnAnimation() - méthode appelée sur l'animation de fin de mouvement de voiture pour démarrer l'animation de virage de voiture:

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

À son tour, la méthode d'animation de tour de voiture peut être comme ceci:

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

nextMoveAnimation() est:

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

Le mPathPolygonPoints (géopoints du trajet en voiture) est:

private List<LatLng> mPathPolygonPoints;

Et la variable mIndexCurrentPoint est l'index du point courant sur le chemin (il doit être 0 au début de l'animation et incrémenté à chaque tour de chemin dans la méthode nextTurnAnimation()).

TURN_ANIMATION_DURATION - animation de durée (en ms) pour le virage en voiture sur le géopoint du chemin;

MOVE_ANIMATION_DURATION - animation de durée (en ms) pour le mouvement de la voiture le long du segment de ligne du chemin;

Pour vous orienter Vous pouvez utiliser une méthode comme celle-ci:

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

Enfin, vous pouvez démarrer toutes les animations en appelant animateCarMove() une fois:

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

les autres étapes de l'animation seront appelées automatiquement pour chaque point du chemin de la voiture.

Et vous devez prendre en compte certains "cas spéciaux" comme:

1) changement du signe de l'angle de virage (par exemple, changement de relèvement de -120 à 150 degrés);

2) possibilités d'interruption de l'animation par l'utilisateur;

3) calculer la durée de l'animation sur la longueur du segment de chemin (par exemple 1 sec pour 1 km de longueur de segment au lieu de fixe MOVE_ANIMATION_DURATION)

4) régler probablement la valeur 16 Dans la ligne handler.postDelayed(this, 16); pour de meilleures performances;

5) et ainsi de suite.

25
Andrii Omelchenko

Le problème est la façon dont vous créez vos objets Location. Vous utilisez le constructeur Location (String provider) qui Construit un nouvel emplacement avec un fournisseur nommé (documentation) :

Par défaut, la latitude et la longitude sont égales à 0, et l'emplacement n'a pas de relèvement, d'altitude, de vitesse, de précision ou d'extras.

Dans votre cas, vous ne créez pas un Location avec vos coordonnées souhaitées mais un Location dont le nom du fournisseur est String.valueOf(directionPoint.get(i)) mais les objets Location sont créés avec la latitude et longitude = 0.

La façon correcte de créer les objets Location est la suivante:

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

Quoi qu'il en soit, tenez compte du fait que vous obtiendrez un ArrayIndexOutOfBoundsException car vous ne tenez pas compte du fait que i+1 Sera ==directionPoint.size() à la fin.

3
antonio

Je pense que ce que vous recherchez est Marker Animations .

Vous pouvez animer des marqueurs afin qu'ils présentent un mouvement dynamique dans diverses circonstances. Pour spécifier la façon dont un marqueur est animé, utilisez la propriété d'animation du marqueur, de type google.maps.Animation. Les valeurs d'animation suivantes sont prises en charge:

-DROP indique que le marqueur doit tomber du haut de la carte à son emplacement final lors de son premier placement sur la carte. L'animation cessera une fois que le marqueur s'arrêtera et l'animation redeviendra nulle. Ce type d'animation est généralement spécifié lors de la création du marqueur.

-BOUNCE indique que le marqueur doit rebondir en place. Un marqueur de rebond continuera de rebondir jusqu'à ce que sa propriété d'animation soit explicitement définie sur null.

Voici un extrait du 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);
        }
      }
1
noogui