web-dev-qa-db-fra.com

Comment dessiner un itinéraire, le long d'une route existante, entre deux points?

Je souhaite afficher l'itinéraire de conduite entre deux sites de mon application Android. Je veux tracer la route uniquement au-dessus des segments de route.

Il y a plusieurs réponses sur le dépassement de pile lui-même, et toutes utilisaient la même méthode. Obtenez les directions du point de départ à la destination à l'aide de l'API Google Directions et tracez une polyligne sur les points renvoyés. Voici quelques-unes des réponses qui utilisent cette méthode.

https://stackoverflow.com/a/17007360/1015678

https://stackoverflow.com/a/40563930/1015678

Cependant, le problème avec la méthode ci-dessus est que, lorsque les routes ne sont pas droites, le rayon d’aube n’est pas toujours au-dessus des routes car l’API de direction ne renvoie que les points où il est nécessaire de changer de route (jonctions). Il ne donne pas de détails ponctuels dans les virages du même segment de route. Ainsi, lorsque j’utilise la méthode ci-dessus dans une région où les routes sont très sinueuses, l’itinéraire tracé n’est presque toujours pas au-dessus des segments de route.

J'ai trouvé this answer, qui fait ce que je dois faire, en utilisant l'API javascript. Dans cette solution, l’itinéraire tracé suit bien les routes, à l’instar de l’application Android de Google Maps. Est-ce que quelqu'un sait si cela est réalisable dans une application Android?

L'application Google Maps Android permet de tracer un itinéraire d'un point à un autre, en gardant l'itinéraire sur les routes. Est-ce que quelqu'un sait comment Google Maps fait cela? Est-ce qu'il utilise une autre API qui n'est pas exposée publiquement?

6
Lahiru Chandima

En effet, vous pouvez tracer un itinéraire précis dans l'API Google Maps Android à l'aide des résultats fournis par le service Web Directions API. Si vous lisez la documentation de Directions API , vous verrez que la réponse contient des informations sur les tronçons et les étapes de l'itinéraire. Chaque étape a un champ polyline décrit dans la documentation en tant que

la polyligne contient un objet ponctuel contenant une représentation polyligne codée de l’étape. Cette polyligne est un chemin approximatif (lissé) de l’étape.

Donc, l’idée principale pour résoudre votre problème est d’obtenir une réponse de l’API Directions, de parcourir en boucle les étapes et les étapes d’un itinéraire, d’obtenir pour chaque étape un polyligne codé et de le décoder en liste de coordonnées. Une fois cela fait, vous aurez une liste de toutes les coordonnées qui composent la route, pas seulement le début et la fin de chaque étape.

Pour plus de simplicité, je vous recommande d’utiliser la bibliothèque client Java pour les services Web Google Maps:

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

En utilisant cette bibliothèque, vous évitez d’implémenter vos propres tâches asynchrones et votre fonction de décodage pour les polylignes. Lisez la documentation pour savoir comment ajouter la bibliothèque client à votre projet. 

À Gradle, cela devrait ressembler à 

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

J'ai créé un exemple simple pour montrer comment cela fonctionne. Regardez mes commentaires dans le 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));
    }
}

Veuillez noter que pour le service Web, vous devez créer une clé API distincte. La clé d'API avec restriction d'applications Android ne fonctionnera pas avec le service Web.

Le résultat de mon exemple est montré dans la capture d'écran

 enter image description here

Vous pouvez également télécharger un exemple de projet complet à partir de

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

N'oubliez pas de remplacer la clé API par la vôtre.

J'espère que ça aide!

26
xomena

Vous pouvez utiliser cette bibliothèque , et c'est simple, vérifiez exemple d'utilisation

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

}

Et n'oubliez pas d'ajouter key en utilisant un générateur d'exemple, si vous recevez des avertissements concernant l'accès sans clé ( vous devriez avoir un compte de facturation pour l'utiliser avec une clé)

1
B-GangsteR

Activer l'API Direction à partir de Google Console . Remplacer API_KEY dans la classe GetPathFromLocation.Java

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

Utilisation en activité ou en 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
Ketan Ramani