Monday, 5 June 2017

Rotate Marker And Move Animation On Google Map

  No comments
I spent days figuring this all out the first time. It’s actually really easy once you know how, but the information was so fragmented it took forever to put the pieces together.
Then I forgot to write it down. Then I went out and drank a bunch of beer to celebrate putting it together, and probably screwed up my memory of the process. A month later, I went to do it again and um… uh… hmmm… SHOOT!
So here it all is in writing for the benefit of you and my future self. Past Self: “Sorry current self.” 😭


Here is my code to move a car like ola uber


package com.gangsofcoder.googlemapdemo;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.PersistableBundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.animation.LinearInterpolator;
import android.widget.Button;
import android.widget.Toast;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.RequestParams;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;

import cz.msebera.android.httpclient.Header;

public class MoveCar extends AppCompatActivity {
    private GoogleMap googleMap;
    SupportMapFragment mapFragment;
    Marker marker;
    private boolean isMarkerRotating = false;
    ArrayList<LatLng> listOfPoints = new ArrayList<>();
    int currentPt = 0;
    LatLng finalPosition;
    Marker mMarker;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setUpMapIfNeeded();
        //new location details
        listOfPoints.add(new LatLng(30.701623, 76.684220));
        listOfPoints.add(new LatLng(30.702486, 76.685487));
        listOfPoints.add(new LatLng(30.703135, 76.684891));
        listOfPoints.add(new LatLng(30.703256, 76.685000));
        listOfPoints.add(new LatLng(30.703883, 76.685941));
        listOfPoints.add(new LatLng(30.703413, 76.685190));
    }

    private void setUpMapIfNeeded() {
        if (mapFragment == null) {
            mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);

            if (mapFragment != null) {
                mapFragment.getMapAsync(new OnMapReadyCallback() {
                    @Override
                    public void onMapReady(GoogleMap googleMap) {
                        loadMap(googleMap);
                    }
                });
            }
        }
    }

    private void loadMap(GoogleMap map) {
        googleMap = map;

        mMarker = googleMap.addMarker(new MarkerOptions().position(new LatLng(30.701623, 76.684220)).icon(BitmapDescriptorFactory.fromResource(R.drawable.icon_car)));    
   

        final Handler handler = new Handler();
        //Code to move car along static latitude and longitude

      /*  handler.postDelayed(new Runnable() {
            @Override
            public void run() {

                if (currentPt < listOfPoints.size()) {
                    //post again
                    Log.d("tess", "inside run ");
                    Location targetLocation = new Location(LocationManager.GPS_PROVIDER);
                    targetLocation.setLatitude(listOfPoints.get(currentPt).latitude);
                    targetLocation.setLongitude(listOfPoints.get(currentPt).longitude);
                    animateMarkerNew(targetLocation, mMarker);
                    handler.postDelayed(this, 3000);
                    currentPt++;
                } else {
                    Log.d("tess", "call back removed");
                    //removed callbacks
                    handler.removeCallbacks(this);
                }
            }
        }, 3000);*/

//Here move marker along real time updates
        final RequestParams params = new RequestParams();
        params.put("source_lattitude", "lat");
        params.put("source_longitude", "long");
        params.put("date", "date");
     
//new handler
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {

                LoopjHttpClient.post(getString(R.string.default_upload_website), params, new AsyncHttpResponseHandler() {
                    @Override
                    public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
                   
                        try {
                            JSONObject jsonObject = new JSONObject(new String(responseBody));
                            String status = jsonObject.getString("status");
                            String text = jsonObject.getString("text");
                            //reading json array
                            JSONArray jsonArray = jsonObject.getJSONArray("result");
                            String source = jsonArray.getJSONObject(0).getString("source");

                            String[] latLong = source.split(",");
                            Location location = new Location(LocationManager.GPS_PROVIDER);
                            location.setLatitude(Double.parseDouble(latLong[0]));
                            location.setLongitude(Double.parseDouble(latLong[1]));
//calling method to animate marker
                            animateMarkerNew(location, mMarker);
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }

                    @Override
                    public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
                        Log.d("onFailure", "onFailure");
                    }
                });

                handler.postDelayed(this, 3000);
            }
        }, 3000);

    }

    private void animateMarkerNew(final Location destination, final Marker marker) {

        if (marker != null) {
           
                    final LatLng startPosition = marker.getPosition();
                    final LatLng endPosition = new LatLng(destination.getLatitude(), destination.getLongitude());

                    final float startRotation = marker.getRotation();
                    final LatLngInterpolatorNew latLngInterpolator = new LatLngInterpolatorNew.LinearFixed();

                    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, endPosition);
                                marker.setPosition(newPosition);
                                googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder()
                                        .target(newPosition)
                                        .zoom(15.5f)
                                        .build()));

                                marker.setRotation(getBearing(startPosition, new LatLng(destination.getLatitude(), destination.getLongitude())));
                            } catch (Exception ex) {
                                //I don't care atm..
                            }
                        }
                    });
                    valueAnimator.addListener(new AnimatorListenerAdapter() {
                        @Override
                        public void onAnimationEnd(Animator animation) {
                            super.onAnimationEnd(animation);
                         
                            // if (mMarker != null) {
                                // mMarker.remove();
                            // }
                            // mMarker = googleMap.addMarker(new MarkerOptions().position(endPosition).icon(BitmapDescriptorFactory.fromResource(R.drawable.icon_car)));

                        }
                    });
                    valueAnimator.start();
        }
    }

    private interface LatLngInterpolatorNew {
        LatLng interpolate(float fraction, LatLng a, LatLng b);

        class LinearFixed implements LatLngInterpolatorNew {
            @Override
            public LatLng interpolate(float fraction, LatLng a, LatLng b) {
                double lat = (b.latitude - a.latitude) * fraction + a.latitude;
                double lngDelta = b.longitude - a.longitude;
                // Take the shortest path across the 180th meridian.
                if (Math.abs(lngDelta) > 180) {
                    lngDelta -= Math.signum(lngDelta) * 360;
                }
                double lng = lngDelta * fraction + a.longitude;
                return new LatLng(lat, lng);
            }
        }
    }


    //Method for finding bearing between two points
    private float getBearing(LatLng begin, LatLng end) {
        double lat = Math.abs(begin.latitude - end.latitude);
        double lng = Math.abs(begin.longitude - end.longitude);

        if (begin.latitude < end.latitude && begin.longitude < end.longitude)
            return (float) (Math.toDegrees(Math.atan(lng / lat)));
        else if (begin.latitude >= end.latitude && begin.longitude < end.longitude)
            return (float) ((90 - Math.toDegrees(Math.atan(lng / lat))) + 90);
        else if (begin.latitude >= end.latitude && begin.longitude >= end.longitude)
            return (float) (Math.toDegrees(Math.atan(lng / lat)) + 180);
        else if (begin.latitude < end.latitude && begin.longitude >= end.longitude)
            return (float) ((90 - Math.toDegrees(Math.atan(lng / lat))) + 270);
        return -1;
    }
}

*********************************************************************************
****************************SECOND MODULE***********************************
*********************************************************************************

package com.example.gangsofcoder.carmoving;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.location.Location;
import android.location.LocationManager;
import android.nfc.Tag;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.animation.LinearInterpolator;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.RequestParams;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.LinkedHashSet;

import cz.msebera.android.httpclient.Header;

public class MainActivity extends AppCompatActivity {
    private GoogleMap googleMap;
    SupportMapFragment mapFragment;
    ArrayList<String> listOfPointsFromServer = new ArrayList<>();
    ArrayList<LatLng> listOfPointsFromRoadApi = new ArrayList<>();
    int currentPt = 0;
    LatLng finalPosition;
    Marker mMarker;
    private static final String TAG = "MainActivity";

    @Override    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setUpMapIfNeeded();
    }


    private void setUpMapIfNeeded() {
        if (mapFragment == null) {
            mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);

            if (mapFragment != null) {
                mapFragment.getMapAsync(new OnMapReadyCallback() {
                    @Override                    public void onMapReady(GoogleMap googleMap) {
                        loadMap(googleMap);
                    }
                });
            }
        }
    }

    private void loadMap(GoogleMap map) {
        googleMap = map;
        Log.d(TAG, "loadMap");
        //mMarker = googleMap.addMarker(new MarkerOptions().position(new LatLng(30.701623, 76.684220)).icon(BitmapDescriptorFactory.fromResource(R.drawable.icon_car)));
        final Handler handler = new Handler();

        //Here move marker along real time updates        handler.postDelayed(new Runnable() {
            @Override            public void run() {
                AsyncHttpClient client = new AsyncHttpClient();
                client.get(getString(R.string.default_upload_website), new AsyncHttpResponseHandler() {
                    @Override                    public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
                        try {
                            JSONObject jsonObject = new JSONObject(new String(responseBody));
                            String status = jsonObject.getString("status");
                            String text = jsonObject.getString("text");

                            if (jsonObject.getString("code").equals("201")) {
                                //reading json array                                JSONArray jsonArray = jsonObject.getJSONArray("result");
                                for (int i = 0; i < jsonArray.length(); i++) {
                                    if (jsonArray.length() == 1) {
                                        listOfPointsFromServer.add(String.valueOf(jsonArray.get(i)));
                                        //                                    } else {
                                        listOfPointsFromServer.add(String.valueOf(jsonArray.get(i)));
                                    }
                                }
                                pointsFromServer(listOfPointsFromServer);
                            }
                            //End of 201
                            /*String source = jsonArray.getJSONObject(0).getString("source");                            String[] latLong = source.split(",");                            Location location = new Location(LocationManager.GPS_PROVIDER);                            location.setLatitude(Double.parseDouble(latLong[0]));                            location.setLongitude(Double.parseDouble(latLong[1]));*/
                            //animateMarker(location, mMarker);
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }

                    @Override                    public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {

                    }
                });
            }
        }, 1000);
    }

    private void pointsFromServer(ArrayList<String> listOfPointsFromServer) {
        Log.d(TAG, "pointsFromServer");
        this.listOfPointsFromServer = listOfPointsFromServer;
        LinkedHashSet<String> set = new LinkedHashSet<>(listOfPointsFromServer);
        final ArrayList<String> pointsWithoutDuplicates = new ArrayList<>(set);

        /*Below code for google map road api       *We can hit the road api with maximum 100 points        */
        String startUrl = "https://roads.googleapis.com/v1/snapToRoads?path=";
        String endUrl = "&interpolate=true&key=YOUR_API_KEY_HERE";

        StringBuilder middleUrl = new StringBuilder();
        //Code to create middle url        for (int i = 0; i < pointsWithoutDuplicates.size(); i++) {
            if (pointsWithoutDuplicates.size() == 1) {
                //Do your work here if we get single location            } else {
                if (i < pointsWithoutDuplicates.size() - 1) {
                    middleUrl.append(pointsWithoutDuplicates.get(i));
                    middleUrl.append("|");
                } else {
                    middleUrl.append(pointsWithoutDuplicates.get(i));
                }
            }
        }//End of for loop
        //Url to hit the road api        String roadApiUrl = startUrl + middleUrl + endUrl;
        Log.d(TAG, roadApiUrl);
        //Code to hit road api url        AsyncHttpClient client = new AsyncHttpClient();
        client.get(roadApiUrl, new AsyncHttpResponseHandler() {
            @Override            public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
                try {

                    JSONObject locationDataToParse = new JSONObject(new String(responseBody));
                    JSONArray snappedPoints = locationDataToParse.getJSONArray("snappedPoints");
                    //Looping through all location points                    Log.d(TAG, String.valueOf(snappedPoints.length()));
                    for (int i = 0; i < snappedPoints.length(); i++) {
                        JSONObject c = snappedPoints.getJSONObject(i);
                        //Parse latitude and longitude inside location object                        JSONObject location = c.getJSONObject("location");
                        String latitude = location.getString("latitude");
                        String longitude = location.getString("longitude");
                        LatLng latLng = new LatLng(Double.parseDouble(latitude), Double.parseDouble(longitude));
                        listOfPointsFromRoadApi.add(latLng);
                    }
                    if (listOfPointsFromRoadApi != null) {
                        pointsFromRoadApi(listOfPointsFromRoadApi);
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }

            @Override            public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {

            }
        });


    }

    private void pointsFromRoadApi(final ArrayList<LatLng> listOfPointsFromRoadApi) {
       /* this.listOfPointsFromRoadApi = listOfPointsFromRoadApi;        //LinkedHashSet preserved the insertion order and automatically remove the duplicates values        LinkedHashSet<String> set = new LinkedHashSet<>(listOfPointsFromServer);        final ArrayList<String> pointsWithoutDuplicates = new ArrayList<>(set);*/
        final Handler handler = new Handler();
        //Code to move car along static latitude and longitude        handler.postDelayed(new Runnable() {
            @Override            public void run() {

                if (currentPt < listOfPointsFromRoadApi.size()) {
                    //post again                    Log.d("tess", "Inside Run");
                    Location targetLocation = new Location(LocationManager.GPS_PROVIDER);
                    targetLocation.setLatitude(listOfPointsFromRoadApi.get(currentPt).latitude);
                    targetLocation.setLongitude(listOfPointsFromRoadApi.get(currentPt).longitude);
                    animateCar(targetLocation, mMarker);
                    handler.postDelayed(this, 3000);
                    currentPt++;

                } else {
                    Log.d("tess", "call back removed");
                    //removed callbacks                    handler.removeCallbacks(this);
                }
            }
        }, 1000);

    }

    private void animateCar(final Location destination, final Marker marker) {

        if (marker != null) {
            Log.d(TAG, "marker not null");
            final LatLng startPosition = marker.getPosition();
            final LatLng endPosition = new LatLng(destination.getLatitude(), destination.getLongitude());

            // final float startRotation = marker.getRotation();            final LatLngInterpolator latLngInterpolator = new LatLngInterpolator.LinearFixed();

            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, endPosition);
                        marker.setPosition(newPosition);
                     
                        marker.setRotation(getBearing(startPosition, new LatLng(destination.getLatitude(), destination.getLongitude())));
                    } catch (Exception ex) {
                        //I don't care atm..                    }
                }
            });
            valueAnimator.addListener(new AnimatorListenerAdapter() {
                @Override                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);

                }
            });
            valueAnimator.start();
        } else {
            //set marker here            Log.d(TAG, "Marker is null");
            mMarker = googleMap.addMarker(new MarkerOptions().position(new LatLng(destination.getLatitude(), destination.getLongitude())).icon(BitmapDescriptorFactory.fromResource(R.drawable.icon_car)));
            googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder()
                    .target(new LatLng(destination.getLatitude(), destination.getLongitude()))
                    .zoom(15.5f)
                    .build()));
        }
    }

    private interface LatLngInterpolator {
        LatLng interpolate(float fraction, LatLng a, LatLng b);

        class LinearFixed implements LatLngInterpolator {
            @Override            public LatLng interpolate(float fraction, LatLng a, LatLng b) {
                double lat = (b.latitude - a.latitude) * fraction + a.latitude;
                double lngDelta = b.longitude - a.longitude;
                // Take the shortest path across the 180th meridian.                if (Math.abs(lngDelta) > 180) {
                    lngDelta -= Math.signum(lngDelta) * 360;
                }
                double lng = lngDelta * fraction + a.longitude;
                return new LatLng(lat, lng);
            }
        }
    }

    //Method for finding bearing between two points    private float getBearing(LatLng begin, LatLng end) {
        double lat = Math.abs(begin.latitude - end.latitude);
        double lng = Math.abs(begin.longitude - end.longitude);

        if (begin.latitude < end.latitude && begin.longitude < end.longitude)
            return (float) (Math.toDegrees(Math.atan(lng / lat)));
        else if (begin.latitude >= end.latitude && begin.longitude < end.longitude)
            return (float) ((90 - Math.toDegrees(Math.atan(lng / lat))) + 90);
        else if (begin.latitude >= end.latitude && begin.longitude >= end.longitude)
            return (float) (Math.toDegrees(Math.atan(lng / lat)) + 180);
        else if (begin.latitude < end.latitude && begin.longitude >= end.longitude)
            return (float) ((90 - Math.toDegrees(Math.atan(lng / lat))) + 270);
        return -1;
    }
}


No comments :

Post a Comment

Loading...