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?
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
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!
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é)
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();