How do I draw a route, along an existing road, between two points?

前端 未结 4 613
孤街浪徒
孤街浪徒 2020-11-27 03:18

I want to show the driving route between two locations in my android app. I want to draw the route only on top of road segments.

There are several answers on stack o

相关标签:
4条回答
  • 2020-11-27 03:30

    For me, I used OSM to get directions as geojson then draw the route on Google map using google maps utils
    first

    // build.gradle
    dependencies {
    implementation 'com.google.maps.android:android-maps-utils:0.5'
    }
    
    // in maps Activity
    // mMap is Google map
    // geoJsonData is the returend json object from directions api
    // which in my case is OSM
    GeoJsonLayer layer = new GeoJsonLayer(mMap, geoJsonData);
    
    // now you can add the layer to the map
    layer.addLayerToMap();
    // congrats you draw the road between two points now :)
    

    For more information check this Google Maps Android GeoJson Utility.
    Happy Coding

    0 讨论(0)
  • 2020-11-27 03:34

    You can use this library, and it's simple, check example of usage:

    Routing routing = new Routing.Builder()
        .travelMode(AbstractRouting.TravelMode.DRIVING)
        .withListener(this)
        .alternativeRoutes(true)
        .waypoints(start, end)
        .build();
    routing.execute();
    
    
    @Override
    public void onRoutingSuccess(List<Route> route, int shortestRouteIndex) {
        progressDialog.dismiss();
        CameraUpdate center = CameraUpdateFactory.newLatLng(start);
        CameraUpdate zoom = CameraUpdateFactory.zoomTo(16);
    
        map.moveCamera(center);
    
        if(polylines.size()>0) {
            for (Polyline poly : polylines) {
                poly.remove();
            }
        }
    
        polylines = new ArrayList<>();
        // Add route(s) to the map.
        for (int i = 0; i <route.size(); i++) {
    
            //In case of more than 5 alternative routes
            int colorIndex = i % COLORS.length;
    
            PolylineOptions polyOptions = new PolylineOptions();
            polyOptions.color(getResources().getColor(COLORS[colorIndex]));
            polyOptions.width(10 + i * 3);
            polyOptions.addAll(route.get(i).getPoints());
            Polyline polyline = map.addPolyline(polyOptions);
            polylines.add(polyline);
    
            Toast.makeText(getApplicationContext(),"Route "+ (i+1) +": distance - "+ route.get(i).getDistanceValue()+": duration - "+ route.get(i).getDurationValue(),Toast.LENGTH_SHORT).show();
        }
    
        // Start marker
        MarkerOptions options = new MarkerOptions();
        options.position(start);
        options.icon(BitmapDescriptorFactory.fromResource(R.drawable.start_blue));
        map.addMarker(options);
    
        // End marker
        options = new MarkerOptions();
        options.position(end);
        options.icon(BitmapDescriptorFactory.fromResource(R.drawable.end_green));
        map.addMarker(options);
    
    }
    

    And don't forget to add key using builder from example, if you getting warnings about keyless access (you should have billing account to use it with key)

    0 讨论(0)
  • 2020-11-27 03:44

    Indeed, you can draw precise route in Google Maps Android API using results provided by Directions API web service. If you read the documentation for Directions API you will see that response contains information about route legs and steps. Each step has a field polyline that is described in the documentation as

    polyline contains a single points object that holds an encoded polyline representation of the step. This polyline is an approximate (smoothed) path of the step.

    So, the main idea to solve your issue is to get response from Directions API, loop through route legs and steps, for each step get encoded polyline and decode it to the list of coordinates. Once done you will have a list of all coordinates that compound the route, not only begin and end point of each step.

    For simplicity I recommend using the Java client library for Google Maps Web services:

    https://github.com/googlemaps/google-maps-services-java

    Using this library you can avoid implementing your own async tasks and decoding function for polylines. Read the documentation to figure out how to add the client library in your project.

    In Gradle it should be something similar to

    compile 'com.google.maps:google-maps-services:(insert latest version)'
    compile 'org.slf4j:slf4j-nop:1.7.25'
    

    I have created a simple example to demonstrate how it works. Have a look at my comments in the code

    public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {
    
        private GoogleMap mMap;
        private String TAG = "so47492459";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_maps);
            // Obtain the SupportMapFragment and get notified when the map is ready to be used.
            SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                    .findFragmentById(R.id.map);
            mapFragment.getMapAsync(this);
        }
    
        @Override
        public void onMapReady(GoogleMap googleMap) {
            mMap = googleMap;
    
            LatLng barcelona = new LatLng(41.385064,2.173403);
            mMap.addMarker(new MarkerOptions().position(barcelona).title("Marker in Barcelona"));
    
            LatLng madrid = new LatLng(40.416775,-3.70379);
            mMap.addMarker(new MarkerOptions().position(madrid).title("Marker in Madrid"));
    
            LatLng zaragoza = new LatLng(41.648823,-0.889085);
    
            //Define list to get all latlng for the route
            List<LatLng> path = new ArrayList();
    
    
            //Execute Directions API request
            GeoApiContext context = new GeoApiContext.Builder()
                    .apiKey("YOUR_API_KEY")
                    .build();
            DirectionsApiRequest req = DirectionsApi.getDirections(context, "41.385064,2.173403", "40.416775,-3.70379");
            try {
                DirectionsResult res = req.await();
    
                //Loop through legs and steps to get encoded polylines of each step
                if (res.routes != null && res.routes.length > 0) {
                    DirectionsRoute route = res.routes[0];
    
                    if (route.legs !=null) {
                        for(int i=0; i<route.legs.length; i++) {
                            DirectionsLeg leg = route.legs[i];
                            if (leg.steps != null) {
                                for (int j=0; j<leg.steps.length;j++){
                                    DirectionsStep step = leg.steps[j];
                                    if (step.steps != null && step.steps.length >0) {
                                        for (int k=0; k<step.steps.length;k++){
                                            DirectionsStep step1 = step.steps[k];
                                            EncodedPolyline points1 = step1.polyline;
                                            if (points1 != null) {
                                                //Decode polyline and add points to list of route coordinates
                                                List<com.google.maps.model.LatLng> coords1 = points1.decodePath();
                                                for (com.google.maps.model.LatLng coord1 : coords1) {
                                                    path.add(new LatLng(coord1.lat, coord1.lng));
                                                }
                                            }
                                        }
                                    } else {
                                        EncodedPolyline points = step.polyline;
                                        if (points != null) {
                                            //Decode polyline and add points to list of route coordinates
                                            List<com.google.maps.model.LatLng> coords = points.decodePath();
                                            for (com.google.maps.model.LatLng coord : coords) {
                                                path.add(new LatLng(coord.lat, coord.lng));
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            } catch(Exception ex) {
                Log.e(TAG, ex.getLocalizedMessage());
            }
    
            //Draw the polyline
            if (path.size() > 0) {
                PolylineOptions opts = new PolylineOptions().addAll(path).color(Color.BLUE).width(5);
                mMap.addPolyline(opts);
            }
    
            mMap.getUiSettings().setZoomControlsEnabled(true);
    
            mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(zaragoza, 6));
        }
    }
    

    Please note that for web service you have to create a separate API key, the API key with Android app restriction won't work with web service.

    The result of my example is shown in screenshot

    You can also download a complete sample project from

    https://github.com/xomena-so/so47492459

    Don't forget replace the API key with yours.

    I hope this helps!

    0 讨论(0)
  • 2020-11-27 03:44

    Enable Direction API from Google Console. Replace API_KEY in GetPathFromLocation.java class

    import android.graphics.Color;
    import android.os.AsyncTask;
    import android.util.Log;
    
    import com.google.android.gms.maps.model.LatLng;
    import com.google.android.gms.maps.model.PolylineOptions;
    
    import org.json.JSONObject;
    
    import java.io.BufferedReader;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    
    public class GetPathFromLocation extends AsyncTask<String, Void, PolylineOptions> {
    
        private String TAG = "GetPathFromLocation";
        private String API_KEY = "Place_Your_API_Key";
        private LatLng source, destination;
        private DirectionPointListener resultCallback;
    
        public GetPathFromLocation(LatLng source, LatLng destination, DirectionPointListener resultCallback) {
            this.source = source;
            this.destination = destination;
            this.resultCallback = resultCallback;
        }
    
        public String getUrl(LatLng origin, LatLng dest) {
    
            String str_origin = "origin=" + origin.latitude + "," + origin.longitude;
            String str_dest = "destination=" + dest.latitude + "," + dest.longitude;
            String sensor = "sensor=false";
            String parameters = str_origin + "&" + str_dest + "&" + sensor;
            String output = "json";
            String url = "https://maps.googleapis.com/maps/api/directions/" + output + "?" + parameters + "&key=" + API_KEY;
    
            return url;
        }
    
        @Override
        protected PolylineOptions doInBackground(String... url) {
    
            String data;
    
            try {
                InputStream inputStream = null;
                HttpURLConnection connection = null;
                try {
                    URL directionUrl = new URL(getUrl(source, destination));
                    connection = (HttpURLConnection) directionUrl.openConnection();
                    connection.connect();
                    inputStream = connection.getInputStream();
    
                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                    StringBuffer stringBuffer = new StringBuffer();
    
                    String line = "";
                    while ((line = bufferedReader.readLine()) != null) {
                        stringBuffer.append(line);
                    }
    
                    data = stringBuffer.toString();
                    bufferedReader.close();
    
                } catch (Exception e) {
                    Log.e(TAG, "Exception : " + e.toString());
                    return null;
                } finally {
                    inputStream.close();
                    connection.disconnect();
                }
                Log.e(TAG, "Background Task data : " + data);
    
    
                JSONObject jsonObject;
                List<List<HashMap<String, String>>> routes = null;
    
                try {
                    jsonObject = new JSONObject(data);
                    // Starts parsing data
                    DirectionHelper helper = new DirectionHelper();
                    routes = helper.parse(jsonObject);
                    Log.e(TAG, "Executing Routes : "/*, routes.toString()*/);
    
    
                    ArrayList<LatLng> points;
                    PolylineOptions lineOptions = null;
    
                    // Traversing through all the routes
                    for (int i = 0; i < routes.size(); i++) {
                        points = new ArrayList<>();
                        lineOptions = new PolylineOptions();
    
                        // Fetching i-th route
                        List<HashMap<String, String>> path = routes.get(i);
    
                        // Fetching all the points in i-th route
                        for (int j = 0; j < path.size(); j++) {
                            HashMap<String, String> point = path.get(j);
    
                            double lat = Double.parseDouble(point.get("lat"));
                            double lng = Double.parseDouble(point.get("lng"));
                            LatLng position = new LatLng(lat, lng);
    
                            points.add(position);
                        }
    
                        // Adding all the points in the route to LineOptions
                        lineOptions.addAll(points);
                        lineOptions.width(10);
                        lineOptions.color(Color.BLUE);
    
                        Log.e(TAG, "PolylineOptions Decoded");
                    }
    
                    // Drawing polyline in the Google Map for the i-th route
                    if (lineOptions != null) {
                        return lineOptions;
                    } else {
                        return null;
                    }
    
                } catch (Exception e) {
                    Log.e(TAG, "Exception in Executing Routes : " + e.toString());
                    return null;
                }
    
            } catch (Exception e) {
                Log.e(TAG, "Background Task Exception : " + e.toString());
                return null;
            }
        }
    
        @Override
        protected void onPostExecute(PolylineOptions polylineOptions) {
            super.onPostExecute(polylineOptions);
            if (resultCallback != null && polylineOptions != null)
                resultCallback.onPath(polylineOptions);
        }
    }
    

    DirectionHelper.java

    import com.google.android.gms.maps.model.LatLng;
    
    import org.json.JSONArray;
    import org.json.JSONException;
    import org.json.JSONObject;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    
    public class DirectionHelper {
    
        public List<List<HashMap<String, String>>> parse(JSONObject jObject) {
    
            List<List<HashMap<String, String>>> routes = new ArrayList<>();
            JSONArray jRoutes;
            JSONArray jLegs;
            JSONArray jSteps;
    
            try {
    
                jRoutes = jObject.getJSONArray("routes");
    
                /** Traversing all routes */
                for (int i = 0; i < jRoutes.length(); i++) {
                    jLegs = ((JSONObject) jRoutes.get(i)).getJSONArray("legs");
                    List path = new ArrayList<>();
    
                    /** Traversing all legs */
                    for (int j = 0; j < jLegs.length(); j++) {
                        jSteps = ((JSONObject) jLegs.get(j)).getJSONArray("steps");
    
                        /** Traversing all steps */
                        for (int k = 0; k < jSteps.length(); k++) {
                            String polyline = "";
                            polyline = (String) ((JSONObject) ((JSONObject) jSteps.get(k)).get("polyline")).get("points");
                            List<LatLng> list = decodePoly(polyline);
    
                            /** Traversing all points */
                            for (int l = 0; l < list.size(); l++) {
                                HashMap<String, String> hm = new HashMap<>();
                                hm.put("lat", Double.toString((list.get(l)).latitude));
                                hm.put("lng", Double.toString((list.get(l)).longitude));
                                path.add(hm);
                            }
                        }
                        routes.add(path);
                    }
                }
    
            } catch (JSONException e) {
                e.printStackTrace();
            } catch (Exception e) {
            }
    
    
            return routes;
        }
    
        //Method to decode polyline points
        private List<LatLng> decodePoly(String encoded) {
    
            List<LatLng> poly = new ArrayList<>();
            int index = 0, len = encoded.length();
            int lat = 0, lng = 0;
    
            while (index < len) {
                int b, shift = 0, result = 0;
                do {
                    b = encoded.charAt(index++) - 63;
                    result |= (b & 0x1f) << shift;
                    shift += 5;
                } while (b >= 0x20);
                int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
                lat += dlat;
    
                shift = 0;
                result = 0;
                do {
                    b = encoded.charAt(index++) - 63;
                    result |= (b & 0x1f) << shift;
                    shift += 5;
                } while (b >= 0x20);
                int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
                lng += dlng;
    
                LatLng p = new LatLng((((double) lat / 1E5)),
                        (((double) lng / 1E5)));
                poly.add(p);
            }
    
            return poly;
        }
    }
    

    DirectionPointListener.java

    import com.google.android.gms.maps.model.PolylineOptions;
    
    public interface DirectionPointListener {
        public void onPath(PolylineOptions polyLine);
    }
    

    Use in Activity or Fragment

    LatLng source = new LatLng(xx.xxxx, yy.yyyy);
    LatLng destination = new LatLng(xx.xxxx, yy.yyyy);
    
    new GetPathFromLocation(source, destination, new DirectionPointListener() {
                @Override
                public void onPath(PolylineOptions polyLine) {
                    yourMap.addPolyline(polyLine);
                }
            }).execute();
    
    0 讨论(0)
提交回复
热议问题