Rotate marker as per user direction on Google Maps V2 Android
Asked Answered
G

3

24

I want to rotate marker as per bearing or sensor value received from Accelerometer to show the user where actually he is moving. I have set marker icon and flat value to true but its not working as required.

mCurrentLocationMarker.position(new LatLng(
                            LocationUtils.sLatitude, LocationUtils.sLongitude));
                    mCurrentLocationMarker.icon(icon);
                    mCurrentLocationMarker.flat(true);
                    mCurrentLocationMarker.rotation(LocationUtils.sBearing);

                    if (currentMarker != null) {
                        currentMarker.setPosition(new LatLng(
                                LocationUtils.sLatitude,
                                LocationUtils.sLongitude));
                    } else {
                        currentMarker = mGoogleMap
                                .addMarker(mCurrentLocationMarker);
                    }
                    animateCameraTo(true);

I have used this marker as marker.

I don't know why its not rotating as per user's direction. If anyone has any idea please kindly help me where i am making mistake.

LocationUtils.sBearing is the value of Bearing which i received from onLocationChanged or accelerometer.

Basically I want to make my marker same as google maps marker which shows user in which direction they are moving or turning.

Geometrician answered 20/12, 2013 at 13:35 Comment(1)
boo !!! any answer for this or #33687736 ?????Carden
P
23

This is an old question and it appears the API has changed since then.

I'm assuming you are able to get the devices bearing. If not here is a handy tutorial.

First thing is to create a marker we can use for bearing updates.

private Marker marker;

// Create this marker only once; probably in your onMapReady() method
marker = mGoogleMap.addMarker(new MarkerOptions()
        .position(new LatLng(myLatitude, myLongitude))
        .flat(true));

Note the .flat(true) portion. The ensures our marker is north aligned so that our bearings will work correctly even if the user rotates the map.

Now when you get your bearing updates you can do the following

marker.setRotation(bearing);
// or if following the linked tutorial
// marker.setRotation((float) azimuth);

This assumes your marker icon has the forward direction at the top. If your marker is rotated like the one pictured, you will have to adjust the bearing to compensate before setting it to the marker. Just a simple setRotation(bearing - 45) should do it.

Piercing answered 13/11, 2015 at 7:35 Comment(3)
if (mLastLocation.hasBearing()) {marker.setRotation(bearing); } right ?Carden
@Carden if that's where you are getting your bearing from, surePiercing
@Carden car marker is moving in right direction but marker/image feels its moving backward/reverse direction how to solve it?Gaytan
C
11

Im posting this answer because people like me who are searching for a solution related to the above question might find it useful.

So here how i did it.

As @colin said you must enable .flat(true) to rotate markers.

1.For bearing angle i have used the following code.

Here latLng1 - my old location && latLng2 - my new location

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

2.To rotate marker using above bearing angle i have used this code

Here isMarkerRotating is a boolean value. Add isMarkerRotating = false in OnCreate method

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

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

3.using above code

LatLng oldLocation, newLocaation;

float bearing = (float) bearingBetweenLocations(oldLocation, newLocaation);
rotateMarker(start_marker, bearing);
Compossible answered 5/12, 2016 at 10:50 Comment(3)
How to rotate Truck with the help of your answer ? I tried this solution but image of truck flip vertically. @CompossibleNectarous
This probably won't work if old and new location is bit far. For instance, if you are updating map in 30seconds and car speed is 90miles/hr than the difference between old and new location would be 0.75 miles and if it is a curve than it won't give perfect orientation.Satiny
@Compossible bearingBetweenLocations() returning 0.0Gaytan
A
6

In Kotlin by using Google SphericalUtil class we can get bearing by passing source and destination LatLngs like:

fun calculateBearing(lat1: Double, lng1: Double, lat2: Double, lng2: Double): Float {
        val sourceLatLng = LatLng(lat1, lng1)
        val destinationLatLng = LatLng(lat2, lng2)
        return SphericalUtil.computeHeading(sourceLatLng, destinationLatLng).toFloat()
    }

Then set this result 'bearing` to the marker like

Val bearing  = calculateBearing(lat1, lng1, lat2, lng2)
marker.rotation(bearing)

Reference: https://developers.google.com/maps/documentation/android-sdk/utility/#spherical

Audiovisual answered 19/3, 2019 at 12:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.