web-dev-qa-db-de.com

Wie zeichne ich eine Route entlang einer vorhandenen Straße zwischen zwei Punkten?

Ich möchte die Fahrtroute zwischen zwei Orten in meiner Android-App anzeigen. Ich möchte die Route nur auf Straßensegmenten zeichnen.

Der Stack-Überlauf selbst enthält mehrere Antworten, und alle verwendeten dieselbe Methode. Holen Sie sich die Wegbeschreibungen vom Startpunkt zum Ziel mithilfe der Google Routenplaner-API und zeichnen Sie eine Polylinie über die zurückgegebenen Punkte. Nachfolgend finden Sie einige Antworten, die diese Methode verwenden.

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

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

Das Problem bei der obigen Methode ist jedoch, wenn die Straßen nicht gerade sind und die Morgenröte nicht immer auf den Straßen liegt, da die Routen-API nur Punkte zurückgibt, an denen Sie von einer Straße zur anderen (an Kreuzungen) wechseln müssen. In den Kurven desselben Straßensegments werden keine Punktdetails angegeben. Wenn ich also die obige Methode in einem Gebiet mit so vielen Kurven benutze, liegt die gezeichnete Route fast immer nicht auf Straßensegmenten.

Ich habe this answer gefunden, was ich tun muss, indem ich die Javascript API benutzt. In dieser Lösung folgt die gezeichnete Route den Straßen gut, ähnlich wie bei der Google Maps-App für Android. Weiß jemand, ob dies in einer Android-App erreichbar ist?

Die Google Maps Android App kann eine Route von einem Punkt zum anderen gut zeichnen und die Route auf der Straße halten. Weiß jemand, wie Google Maps dies tut? Verwendet es eine andere API, die nicht öffentlich zugänglich ist?

6
Lahiru Chandima

In der Google Maps Android API können Sie mithilfe der Ergebnisse, die vom Directions API-Webdienst bereitgestellt werden, präzise Routen zeichnen. Wenn Sie die Dokumentation für Directions API lesen, enthält diese Antwort Informationen zu Streckenabschnitten und -schritten. Jeder Schritt hat ein Feld polyline, das in der Dokumentation als beschrieben wird

polylinie enthält ein Einzelpunktobjekt, das eine kodierte Polyliniendarstellung des Schritts enthält. Diese Polylinie ist ein ungefährer (geglätteter) Pfad der Stufe.

Die Hauptidee zur Lösung Ihres Problems besteht also darin, eine Antwort von der Routenplaner-API zu erhalten, Routenabschnitte und -schritte durchlaufen zu lassen. Für jeden Schritt erhalten Sie encoded Polyline und dekodieren sie in die Koordinatenliste. Sobald Sie fertig sind, haben Sie eine Liste aller Koordinaten, die die Route zusammensetzen, nicht nur Anfangs- und Endpunkt jedes Schritts.

Zur Vereinfachung empfehle ich die Verwendung der Java-Client-Bibliothek für Google Maps-Webdienste:

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

Mit dieser Bibliothek können Sie vermeiden, Ihre eigenen asynchronen Aufgaben und Dekodierungsfunktionen für Polylinien zu implementieren. Lesen Sie die Dokumentation, um zu erfahren, wie Sie die Clientbibliothek in Ihr Projekt einfügen. 

In Gradle sollte es ähnlich sein 

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

Ich habe ein einfaches Beispiel erstellt, um zu zeigen, wie es funktioniert. Schau dir meine Kommentare im Code an

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

Bitte beachten Sie, dass für einen Webdienst ein separater API-Schlüssel erstellt werden muss. Der API-Schlüssel mit Android-App-Einschränkung funktioniert nicht mit dem Webdienst.

Das Ergebnis meines Beispiels ist im Screenshot dargestellt

enter image description here

Sie können auch ein vollständiges Beispielprojekt von herunterladen

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

Vergessen Sie nicht, den API-Schlüssel durch Ihren zu ersetzen.

Ich hoffe das hilft!

26
xomena

Sie können diese library verwenden, und es ist ganz einfach, überprüfen Sie Verwendungsbeispiel

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

}

Und vergessen Sie nicht, key mithilfe des Builders aus dem Beispiel hinzuzufügen, wenn Sie Warnungen über den schlüssellosen Zugriff erhalten ( Sie sollten ein Abrechnungskonto haben , um es mit dem Schlüssel zu verwenden)

1
B-GangsteR

Aktivieren Sie die Richtungs-API von Google Console aus. __ Ersetzen Sie API_KEY in der GetPathFromLocation.Java-Klasse

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

Verwendung in Aktivität oder 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