Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rotating Marker in Google Maps API v2

I have followed this answer and its working great. https://stackoverflow.com/a/37048987/4209417

But the issues I'm facing now are:

  1. When I stop at any location, its not stable. I'm getting random bearing value even when I'm not moving
  2. when I'm taking turns its rotating anticlockwise which is wrong. Its should take short turns.

This is the code I'm using :

private double bearingBetweenLocations(LatLng latLng1,LatLng latLng2) {

        double PI = 3.14159;
        double lat1 = latLng1.latitude * PI / 180;
        double long1 = latLng1.longitude * PI / 180;
        double lat2 = latLng2.latitude * PI / 180;
        double long2 = latLng2.longitude * PI / 180;

        double dLon = (long2 - long1);

        double y = Math.sin(dLon) * Math.cos(lat2);
        double x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1)
                * Math.cos(lat2) * Math.cos(dLon);

        double brng = Math.atan2(y, x);

        brng = Math.toDegrees(brng);
        brng = (brng + 360) % 360;

        return brng;
    }

private void rotateMarker(final Marker marker, final float toRotation) {
        if(!isMarkerRotating) {
            final Handler handler = new Handler();
            final long start = SystemClock.uptimeMillis();
            final float startRotation = marker.getRotation();
            final long duration = 2000;

            final Interpolator interpolator = new LinearInterpolator();

            handler.post(new Runnable() {
                @Override
                public void run() {
                    isMarkerRotating = true;

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

                    float rot = t * toRotation + (1 - t) * startRotation;

                    float bearing =  -rot > 180 ? rot / 2 : rot;

                    marker.setRotation(bearing);

                    CameraPosition camPos = CameraPosition
                            .builder(mMap.getCameraPosition())
                            .bearing(bearing)
                            .target(marker.getPosition())
                            .build();
                    mMap.animateCamera(CameraUpdateFactory.newCameraPosition(camPos));

                    if (t < 1.0) {
                        // Post again 16ms later.
                        handler.postDelayed(this, 16);
                    } else {
                        isMarkerRotating = false;
                    }
                }
            });
        }
    }

In onLocationChanged()

float toRotation = (float) bearingBetweenLocations(toLatLng(oldLocation), toLatLng(newLocation));
rotateMarker(my_marker, toRotation);
like image 206
satti8893 Avatar asked Dec 17 '16 08:12

satti8893


People also ask

How do I rotate a marker on Google Maps?

Marker({ position: a, map: map, icon: { path: google. maps. SymbolPath. FORWARD_CLOSED_ARROW, scale: 6, fillColor: "red", fillOpacity: 0.8, strokeWeight: 2, rotation: angleDegrees //this is how to rotate the pointer } });

How do I move a marker smoothly on Google Maps?

initialize() function creates a google Map with location Marker. transition() & moveMarker() are used to move location marker smoothly on Google Map.


1 Answers

So finally found my own answer which i will post here, so others could find it useful.

whenever my onLocationChanged updates, i check my old & current locations then i update the marker. Like below.

 double oldLat = oldLocation.getLatitude();
 double oldLng = oldLocation.getLongitude();

 double newLat = newLocation.getLatitude();
 double newLng = newLocation.getLongitude();

 if (oldLat != newLat && oldLng != newLng){
      updateMyLocation(toLatLng(oldLocation), toLatLng(mCurrentLocation));
 }

Also i updated my marker rotation code. This rotates the marker & moves to new location with smooth animation. (adjust duration for smooth animation).

float rotation = (float) SphericalUtil.computeHeading(old, new);
rotateMarker(bus_marker, new, rotation);

private void rotateMarker(final Marker marker, final LatLng destination, final float rotation) {

    if (marker != null) {

        final LatLng startPosition = marker.getPosition();
        final float startRotation = marker.getRotation();

        final LatLngInterpolator latLngInterpolator = new LatLngInterpolator.Spherical();
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
        valueAnimator.setDuration(3000); // duration 3 second
        valueAnimator.setInterpolator(new LinearInterpolator());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {

                try {
                    float v = animation.getAnimatedFraction();
                    LatLng newPosition = latLngInterpolator.interpolate(v, startPosition, destination);
                    float bearing = computeRotation(v, startRotation, rotation);

                    marker.setRotation(bearing);
                    marker.setPosition(newPosition);

                }
                catch (Exception e){
                    e.printStackTrace();
                }
            }
        });
        valueAnimator.start();
    }
}
private static float computeRotation(float fraction, float start, float end) {
    float normalizeEnd = end - start; // rotate start to 0
    float normalizedEndAbs = (normalizeEnd + 360) % 360;

    float direction = (normalizedEndAbs > 180) ? -1 : 1; // -1 = anticlockwise, 1 = clockwise
    float rotation;
    if (direction > 0) {
        rotation = normalizedEndAbs;
    } else {
        rotation = normalizedEndAbs - 360;
    }

    float result = fraction * rotation + start;
    return (result + 360) % 360;
}
like image 87
satti8893 Avatar answered Oct 07 '22 08:10

satti8893