What I want to do is this:
I receive a list of directions/paths (that the user will have to follow using my app).
I am having trouble drawing the path on the map. The directions/paths contains the name of the streets, the coordinates of the streets and the segments of the streets.
I cant figure out how to draw the path/route on the map and make the route update - for example when the user moves (on the way) an icon to move indicating the progress of the user or the line drawn for the route gets shorter this really doesn't matter that much. So can you point me to tutorials which I can refer to?
I've seen a lot so far, but most of them get the directions from Google maps or the lines drawn are just straight lines from Start point to end point and doesn't fit the streets at all.
To achieve this, follow the below steps
Get list of ArrayList markerPoints;
Create your markers for it
single path,
LatLng origin = markerPoints.get(0);
LatLng dest = markerPoints.get(1);
// Getting URL to the Google Directions API
String url = getDirectionsUrl(origin, dest);
DownloadTask downloadTask = new DownloadTask();
// Start downloading json data from Google Directions API
downloadTask.execute(url);
for multiple destination path, for example A-B-D-C etc
private List<String> getDirectionsUrl(ArrayList<LatLng> markerPoints) {
List<String> mUrls = new ArrayList<>();
if (markerPoints.size() > 1) {
String str_origin = markerPoints.get(0).latitude + "," + markerPoints.get(0).longitude;
String str_dest = markerPoints.get(1).latitude + "," + markerPoints.get(1).longitude;
String sensor = "sensor=false";
String parameters = "origin=" + str_origin + "&destination=" + str_dest + "&" + sensor;
String output = "json";
String url = "https://maps.googleapis.com/maps/api/directions/" + output + "?" + parameters;
mUrls.add(url);
for (int i = 2; i < markerPoints.size(); i++)//loop starts from 2 because 0 and 1 are already printed
{
str_origin = str_dest;
str_dest = markerPoints.get(i).latitude + "," + markerPoints.get(i).longitude;
parameters = "origin=" + str_origin + "&destination=" + str_dest + "&" + sensor;
url = "https://maps.googleapis.com/maps/api/directions/" + output + "?" + parameters;
mUrls.add(url);
}
}
return mUrls;
}
Call the above method from
List<String> urls = getDirectionsUrl(markerPoints);
if (urls.size() > 1) {
for (int i = 0; i < urls.size(); i++) {
String url = urls.get(i);
DownloadTask downloadTask = new DownloadTask();
// Start downloading json data from Google Directions API
downloadTask.execute(url);
}
}
}
the above code will call for to create multiple paths, like A-B, B-D, D-C etc
try following this tutorial. You should draw between user location and marker. On user side call function onLocationChange to get the actual position and redraw the line. http://wptrafficanalyzer.in/blog/driving-route-from-my-location-to-destination-in-google-maps-android-api-v2/
Follow this:Android Google Map V3 PolyLine cannot be drawn
It'll help.
You just need to parse the data received after hitting Google Directions API
Related
I was using google directions api to get the route between two latlng points and plotting it on a google map. The issue is that i can optimize the route when adding waypoints but i can't control the optimization criteria. The code i am using for creating the request url is :
private String getDirectionsUrl(LatLng origin, LatLng dest) {
// Origin of route
String str_origin = "origin=" + origin.latitude + "," + origin.longitude;
// Destination of route
String str_dest = "destination=" + dest.latitude + "," + dest.longitude;
// Sensor enabled
String sensor = "sensor=false";
// Waypoints
String waypoints = "";
for (int i = 0; i < markerPoints.size(); i++) {
LatLng point = (LatLng) markerPoints.get(i);
if (i == 0)
waypoints = "waypoints=optimize:true|";
if (i == markerPoints.size() - 1) {
waypoints += point.latitude + "," + point.longitude;
} else {
waypoints += point.latitude + "," + point.longitude + "|";
}
}
// Building the parameters to the web service
String parameters = str_origin + "&" + str_dest + "&" + sensor + "&" + waypoints + "&mode=driving&key=YOUR_API_KEY";
// Output format
String output = "json";
// Building the url to the web service
String url = "https://maps.googleapis.com/maps/api/directions/" + output + "?" + parameters;
return url;
}
In short, i want to add optimization criteria in this string. Is it possible or do i have to enable alternate routes and manually calculate the travel distance of each path and choose the shortest?
I have developed an application to read KML files of point type and then update their elevation using Google Elevation API. As you can see it receives latitude and longitude of the point and appends it with an API key to retrieve the elevation. Because my KML files have multiple points, I've used ThreadPool to read lat and long of points, append it with the key, and send the URL to Google Elevation API.Something like this:
ScheduledThreadPoolExecutor executor = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(CORE_NUMBERS + 1);
String providerURL = provider.getServiceURL();
String providerKey = provider.getServiceAPIkey();
for (PointFeature p: points) {
String coordinate = p.getLatitude() + "," + p.getLongitude(); // get latitude and longitude of the feature
String url = providerURL + "locations=" + coordinate + providerKey; // creating the url of web service which contains coordinate
HeightTask task = new HeightTask(url, p); // task of each points
executor.execute(task);
}
The heightTask class is where I parse the JSON result from API and get the elevation and set the heithUpdate flag. Here is the snippet:
public class HeightTask implements Runnable {
private String url;
private Feature feature;
public HeightTask(String url, Feature f) {
this.feature = f;
this.url = url;
}
#Override
public void run() {
if (feature instanceof PointFeature) {
float height = GoogleAPIJsonParser.parsePoint(HttpManager.getData(url));
if (height != Float.NaN){
feature.updateHeight(height);
feature.setHeightUpdated(true);
Log.d("elevationPoint",height+"");
}
}
}
}
What I need is a callback to know if the elevation of all points in a layer has been updated. Is there any pattern in threadPool or just loop through all points and check the hieghtUpdate flags?
Modify code as below.
Change your HeightTask to implement Callable interface.
Prepare a collection of Callable tasks and submit using invokeAll()
List<HeightTask > futureList = new ArrayList<HeightTask >();
for (PointFeature p: points) {
String coordinate = p.getLatitude() + "," + p.getLongitude(); // get latitude and longitude of the feature
String url = providerURL + "locations=" + coordinate + providerKey; // creating the url of web service which contains coordinate
HeightTask task = new HeightTask(url, p);
futureList.add(taks);
}
executor.invokeAll(futureList);
invokeAll:
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException
Executes the given tasks, returning a list of Futures holding their status and results when all complete. Future.isDone() is true for each element of the returned list. Note that a completed task could have terminated either normally or by throwing an exception.
My goal is to do autocomplete prediction using Google Places API, and now I want to make some kind algorithm that will take current location lat and lng, and make a prediction of places only in 100-200 km diameter.
So, at this moment I get user's current location lat and lng, how to set 100-200 km?
private void getCurrentLocation() {
mLastLocation = LocationServices.FusedLocationApi
.getLastLocation(mGoogleApiClient);
if (mLastLocation != null) {
double latitude = mLastLocation.getLatitude();
double longitude = mLastLocation.getLongitude();
mLatLonBounds = new LatLngBounds(new LatLng(latitude,longitude),
new LatLng(latitude,longitude));
Log.d("myTag","lat = "+mLatLonBounds.northeast.latitude+" ,lon = "+mLatLonBounds.northeast.longitude);
//Log.d("myTag","lat = "+mLatLonBounds.southwest.latitude+" ,lon = "+mLatLonBounds.southwest.longitude);
}else {
//some code
}
}
Here is how I set bounds to auto prediction:
#Nullable
private ArrayList<AutoCompletePlace> getAutocomplete(CharSequence constraint) {
if (mGoogleApiClient.isConnected()) {
Log.i(Constants.AUTO_COMPLETE_TAG, "Starting autocomplete query for: " + constraint);
// Submit the query to the autocomplete API and retrieve a PendingResult that will
// contain the results when the query completes.
PendingResult<AutocompletePredictionBuffer> results = Places.GeoDataApi
.getAutocompletePredictions(mGoogleApiClient, constraint.toString(),
**mBounds**, mPlaceFilter);
// This method should have been called off the main UI thread. Block and wait for at most 60s
// for a result from the API.
AutocompletePredictionBuffer autocompletePredictions = results.await(60, TimeUnit.SECONDS);
// Confirm that the query completed successfully, otherwise return null
final Status status = autocompletePredictions.getStatus();
if (!status.isSuccess()) {
Toast.makeText(getContext(), "Error contacting API: " + status.toString(),
Toast.LENGTH_SHORT).show();
Log.e(Constants.AUTO_COMPLETE_TAG, "Error getting autocomplete prediction API call: " + status.toString());
autocompletePredictions.release();
return null;
}
Log.i(Constants.AUTO_COMPLETE_TAG, "Query completed. Received " + autocompletePredictions.getCount()
+ " predictions.");
// Copy the results into our own data structure, because we can't hold onto the buffer.
// AutocompletePrediction objects encapsulate the API response (place ID and description).
Iterator<AutocompletePrediction> iterator = autocompletePredictions.iterator();
ArrayList resultList = new ArrayList<>(autocompletePredictions.getCount());
while (iterator.hasNext()) {
AutocompletePrediction prediction = iterator.next();
// Get the details of this prediction and copy it into a new PlaceAutocomplete object.
resultList.add(new AutoCompletePlace(prediction.getPlaceId(),
prediction.getDescription()));
}
// Release the buffer now that all data has been copied.
autocompletePredictions.release();
return resultList;
}
Log.e(Constants.AUTO_COMPLETE_TAG, "Google API client is not connected for autocomplete query.");
return null;
Example my current location 48.6180288,22.2984587.
UPDATE: Before the Francois Wouts give me the answer, I found another solution on stackoverflow, you can use it too.
public static final LatLngBounds setBounds(Location location, int mDistanceInMeters ){
double latRadian = Math.toRadians(location.getLatitude());
double degLatKm = 110.574235;
double degLongKm = 110.572833 * Math.cos(latRadian);
double deltaLat = mDistanceInMeters / 1000.0 / degLatKm;
double deltaLong = mDistanceInMeters / 1000.0 / degLongKm;
double minLat = location.getLatitude() - deltaLat;
double minLong = location.getLongitude() - deltaLong;
double maxLat = location.getLatitude() + deltaLat;
double maxLong = location.getLongitude() + deltaLong;
Log.d("Location", "Min: " + Double.toString(minLat) + "," + Double.toString(minLong));
Log.d("Location","Max: "+Double.toString(maxLat)+","+Double.toString(maxLong));
// Set up the adapter that will retrieve suggestions from the Places Geo Data API that cover
// the entire world.
return new LatLngBounds(new LatLng(minLat,minLong),new LatLng(maxLat,maxLong));
According to Wikipedia, you probably want to allow around 1 degree in each direction around the user's location to cover 100-200km. The exact area covered will depend on where the user is, but this should be a good enough approximation for most use cases.
Try the following, for example:
double radiusDegrees = 1.0;
LatLng center = /* the user's location */;
LatLng northEast = new LatLng(center.latitude + radiusDegrees, center.longitude + radiusDegrees);
LatLng southWest = new LatLng(center.latitude - radiusDegrees, center.longitude - radiusDegrees);
LatLngBounds bounds = LatLngBounds.builder()
.include(northEast)
.include(southWest)
.build();
I believe this should work correctly even across the antemeridian. Let me know how you go!
I have written some code to search nearby places based on their prominence. Next, I'd like to have my app search places based on ascending distance from the user. In order to do that, I learned that I need to use rankby=distance but rankby does not allow a value for radius - so the following radius-based search doesn't work:
nearPlaces = googlePlaces.search(
gps.getLatitude(),
gps.getLongitude(),
radius,
types
);
I've seen several blogs and articles where people asked similar questions, but none of them provided an answer which seems to work. What should I be using, if not the above?
correct is rankBy=distance...
Keep the B capital in rankBy...
private static final String PLACES_SEARCH_URL = "https://maps.googleapis.com/maps/api/place/search/json?rankby=distance&";
public PlacesList search(double latitude, double longitude, double radius, String types)
throws Exception {
this._latitude = latitude;
this._longitude = longitude;
this._radius = radius;
//this._rankby=_rankby;
try {
HttpRequestFactory httpRequestFactory = createRequestFactory(HTTP_TRANSPORT);
HttpRequest request = httpRequestFactory
.buildGetRequest(new GenericUrl(PLACES_SEARCH_URL));
request.getUrl().put("key", API_KEY);
request.getUrl().put("location", _latitude + "," + _longitude);
// request.getUrl().put("radius", _radius);
request.getUrl().put("rankBy", _radius);
// in meters
request.getUrl().put("sensor", "false");
//request.getUrl().put("rankby", _rankby);
if(types != null)
request.getUrl().put("types", types);
PlacesList list = request.execute().parseAs(PlacesList.class);
// Check log cat for places response status
Log.d("Places Status", "" + list.status);
return list;
} catch (HttpResponseException e) {
Log.e("Error:", e.getMessage());
return null;
}
}
You can bypass it. I used 'GOOGLE PLACES WEB SERVICES'
https://developers.google.com/places/webservice/search :
get a JSON of all your places using PLACES API (use HttpURLConnection to send the request) :
String nearByPlaceSearchURL = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?"
+ "location=" + myLatPosition + "," + myLonPosition
+ "&radius=" + myPlaceDistanceMeters
+ "&types=" + myPlaceName
+ "&key=" + MyConstants.KEY_FOR_PLACES_AND_DISTANCES_API;
Parse the returned JSON and get the coordinates, LAT/LON, of each one of the places.
Get a JSON of all the distances from your current position to each one of the places using DISTANCE MATRIX API:
String distancesSearchURL = "https://maps.googleapis.com/maps/api/distancematrix/json?"
+ "origins=" + myLatPosition + "," + myLonPosition
+ "&destinations=" + allPlacesCoordinates
+ "&mode=walking"
+ "&key=" + MyConstants.KEY_FOR_PLACES_AND_DISTANCES_API;
Note that the distance is a walking,driving or cycling distance, which is the distance we are interested in. The radius distance (air distance) is not relevant. The walking/driving/cycling distances are bigger than the air distance.Therefore, for example, you can search for a place in radius of 10 km but the walking distance to it will be 11 km.
Create an Object for each one of the places with its name and distance from your current position as internal variables.
Generate an ArrayList containing all your Objects places.
Sort the ArrayList using the method comparator according to the distance.
am trying to integrate Google Places API into my app.
Now I am finding out my current location of the Phone, how do I embed the longitude and latitude which I have got into the following URL instead of "location=34.0522222,-118.2427778"
"https://maps.googleapis.com/maps/api/place/search/xml?location=34.0522222,-118.2427778&radius=500&types=restaurants&sensor=false&key=Your_API_Key"
Do you mean how do you do string manipulation such as (untested):
int latitude = ...;
int longitude = ...;
String preamble = "https://maps.googleapis.com/maps/api/place/search/xml?location=";
String postamble = "&radius=500&types=restaurants&sensor=true&key=";
String key = "Your_api_key";
String latStr = latitude + "";
String longStr = longitude + "";
String url = preamble + latStr + "," + longStr + postamble + key;
$lat = location[0];
$long = location[1];
Should work, but I use json for geting long and lat from google. Is better. I can check it again if not working.
Here is better json solution:
http://maps.googleapis.com/maps/api/geocode/json?address=Atlantis&sensor=true&oe=utf-8
You should change Atlantis to address