i have a map v2 application with ability to drawing polylines from pinpointed location to user current location fetched from gps.
i used google directions in order to get polyline strings.
after drawing got some unease at the end point of each polyline.
see screenshot from actual device :
this is my drawing codes :
for(int j = 0; j < allPoints.length - 1;j++) {
if(allPoints[j] != null) {
System.out.println("pontos " + allPoints[j]);
List<LatLng> test = decodePoly(allPoints[j]);
for (int i = 0; i < test.size() - 1; i++) {
LatLng src = test.get(i);
LatLng dest = test.get(i + 1);
try {
Polygon line = googleMap.addPolygon(new PolygonOptions()
.add(new LatLng(src.latitude, src.longitude),
new LatLng(dest.latitude, dest.longitude))
.strokeColor(Color.BLUE).geodesic(true));
} catch (NullPointerException e) {
Log.e("Error", "NullPointerException onPostExecute: " + e.toString());
} catch (Exception e2) {
Log.e("Error", "Exception onPostExecute: " + e2.toString());
}
}
}
}
can i put a circle after each polyline ? does it fix my problem ?
As #Cheesebaron states, the best options is adding only one Polyline. I haven't tested it because I don't have an example of your allPoints data, but it could be something like this:
for (int j = 0; j < allPoints.length - 1; j++) {
if (allPoints[j] != null) {
List<LatLng> test = decodePoly(allPoints[j]);
Polyline line = googleMap.addPolyline(new PolylineOptions().color(Color.BLUE).geodesic(true).addAll(test));
}
}
You can also create only one Polyline instead of one Polyline for each allPoints[j]:
PolylineOptions polylineOptions = new PolylineOptions().color(Color.BLUE).geodesic(true);
for (int j = 0; j < allPoints.length - 1; j++) {
if (allPoints[j] != null) {
List<LatLng> test = decodePoly(allPoints[j]);
polylineOptions.addAll(test);
}
}
Polyline line = googleMap.addPolyline(polylineOptions);
Related
In my app user can insert multiple location and show in map. How can i achieve this? I know how to draw route between two location but i want to draw route between multiple marker as like image.
In image marker show location that is entered by user. I also want to calculate distance between marker like calculate distance between B to C and C to D.
How can I achieve this??
Use direction api which return multi-part directions using a series of waypoints.
Direction api Documentation
private static final LatLng LOWER_MANHATTAN = new LatLng(40.722543,-73.998585);
private static final LatLng BROOKLYN_BRIDGE = new LatLng(40.7057, -73.9964);
private static final LatLng WALL_STREET = new LatLng(40.7064, -74.0094);
private String getMapsApiDirectionsUrl() {
String origin = "origin=" + LOWER_MANHATTAN.latitude + "," + LOWER_MANHATTAN.longitude;
String waypoints = "waypoints=optimize:true|" + BROOKLYN_BRIDGE.latitude + "," + BROOKLYN_BRIDGE.longitude + "|";
String destination = "destination=" + WALL_STREET.latitude + "," + WALL_STREET.longitude;
String sensor = "sensor=false";
String params = origin + "&" + waypoints + "&" + destination + "&" + sensor;
String output = "json";
String url = "https://maps.googleapis.com/maps/api/directions/"
+ output + "?" + params;
return url;
}
}
When you get response from above request . you need to draw route from response
public void drawRoute(String result) {
try {
//Tranform the string into a json object
final JSONObject json = new JSONObject(result);
JSONArray routeArray = json.getJSONArray("routes");
JSONObject routes = routeArray.getJSONObject(0);
JSONObject overviewPolylines = routes.getJSONObject("overview_polyline");
String encodedString = overviewPolylines.getString("points");
List<LatLng> list = decodePoly(encodedString);
Polyline line = mMap.addPolyline(new PolylineOptions()
.addAll(list)
.width(12)
.color(Color.parseColor("#05b1fb"))//Google maps blue color
.geodesic(true)
);
} catch (JSONException e) {
}
}
You will get more detail of this from Draw-route-github
For Distance calculation you need to Distance Matrix API is a service that provides travel distance and time for a matrix of origins and destinations
Using direction api you can achieve this.
you just have to pass user inserted marker as waypoints as follow
https://maps.googleapis.com/maps/api/directions/json?
origin=sydney,au&destination=perth,au
&waypoints=via:-37.81223%2C144.96254%7Cvia:-34.92788%2C138.60008
&key=YOUR_API_KEY
you will get list of route which have the distance between to points
//retrofit
#GET("https://maps.googleapis.com/maps/api/directions/json")
Observable<DirectionResults> getDirectionWithWayPoints(#Query("origin") String origin, #Query("destination") String destination, #Query("waypoints") String wayPoints, #Query("key") String key);
// plotting logic
api.getDirectionWithWayPoints(startPoint, endPoint, stringBuilder.toString(), getString(R.string.API_KEY))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new Observer<DirectionResults>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(DirectionResults directionResults) {
hideDialog();
if (null == directionResults) {
return;
}
ArrayList<LatLng> routelist = new ArrayList<>();
routelist.add(latLngStart);
if (directionResults.getRoutes().size() > 0) {
List<LatLng> decodelist;
RoutesItem routeA = directionResults.getRoutes().get(0);
if (routeA.getLegs().size() > 0) {
for (int j = 0; j < routeA.getLegs().size(); j++) {
List<StepsItem> steps = routeA.getLegs().get(j).getSteps();
StepsItem step;
Location location;
String polyline;
for (int i = 0; i < steps.size(); i++) {
step = steps.get(i);
polyline = step.getPolyline().getPoints();
decodelist = DirectionsJSONParser.decodePoly(polyline);
routelist.addAll(decodelist);
}
}
}
}
if (routelist.size() > 0) {
routelist.add(latLngEnd);
rectLine = new PolylineOptions().width(12).color(
Color.CYAN);
for (int i = 0; i < routelist.size(); i++) {
rectLine.add(routelist.get(i));
}
// Adding route on the map
if (null != mMap) {
mMap.addPolyline(rectLine);
fixZoom(rectLine, mMap);
getVehicleId();
}
}
}
#Override
public void onError(Throwable e) {
hideDialog();
e.printStackTrace();
}
#Override
public void onComplete() {
}
});
}
}
Google provides libraries out of the box for solving this kind of issues.
I would structure my application in following manner.
Use Retrofit 2 for connecting to network. (https://square.github.io/retrofit/)
Use google API's, you will need more than 1 API to achieve both of the tasks.
2.a To find out distances between two points use Google Distance Matrix API (https://developers.google.com/maps/documentation/distance-matrix/start).
2.b To add multiple markers you can refer to following answer
Google Maps JS API v3 - Simple Multiple Marker Example
For draw route you can use :
PolylineOptions options = new
PolylineOptions().width(5).color(Color.BLUE).geodesic(true);
for (int z = 0; z < list.size(); z++) {
LatLng point = list.get(z);
options.add(point);
}
line = myMap.addPolyline(options);
And calculating distance for usimg **Google Maps Direction API**
I am drawing route on google map using waypoints. Everything looks good except my origin and destination is also connected. I am sure my origin and destination is not same.
Here is the url generated after I generate directions url from list of latitude/longitudes.
https://maps.googleapis.com/maps/api/directions/json?
&origin=26.8530478,75.78491989999999
&destination=26.8804683,75.75850109999999
&waypoints=26.8566917,75.7691974%7C
26.868405,75.76440269999999%7C
26.8762989,75.7664082
&key=MY_API_KEY
And also attaching the output. The straight line from "1" to "5' should not be there. Please help me in finding the mistake.
Thanks.
ParserTask -
ArrayList<LatLng> points = new ArrayList<LatLng>();
PolylineOptions lineOptions = new PolylineOptions();
// LatLngBounds.Builder builder = new LatLngBounds.Builder();
int color = ContextCompat.getColor(activity, R.color.black_overlay);
if (null != result)
for (int i = 0; i < result.size(); i++) {
// Fetching i-th route
List<HashMap<String, String>> path = result.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);
//builder.include(position);
}
lineOptions = new PolylineOptions().width(15).color(color).addAll(points).zIndex(6);
}
if (activity instanceof OnRoutesParsingCompletedCallBack) {
((OnRoutesParsingCompletedCallBack) activity).
onRoutesParsingCompleted(lineOptions);
}
Activity with map object -
#Override
public void onRoutesParsingCompleted(PolylineOptions lineOptions) {//}, LatLngBounds.Builder builder) {
if (lineOptions.getPoints().size() > 0) {
googleMap.addPolyline(lineOptions);
} else
Toast.makeText(this, "There is something wrong. No routes to draw!", Toast.LENGTH_SHORT).show();
mCurrLocationMarker.showInfoWindow();
progressBar.setVisibility(GONE);
googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(currentLatLong, 13));
}
I think, the issue is that you are adding all possible routes to the same polyline. So, the polyline goes by the first route, then it "returns" to the start point and goes again by the second route. You either need to remove the for that loops over the results:
if (null != result)
// Fetching 1st route
List<HashMap<String, String>> path = result.get(0);
// Fetching all the points in 1st 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);
//builder.include(position);
}
lineOptions = new PolylineOptions().width(15).color(color).addAll(points).zIndex(6);
}
Or you can create a polyline for each existing route.
on my app i add 2 marker on map. When i add a second marker with click i call a function to calculate route and add polyline on map.
This is the code for polyline
protected void onPostExecute(List<List<HashMap<String, String>>> result) {
ArrayList<LatLng> points = null;
PolylineOptions lineOptions = null;
MarkerOptions markerOptions = new MarkerOptions();
String distance = "";
String duration = "";
String value_duration = "";
// Traversing through all the routes
for (int i = 0; i < result.size(); i++) {
points = new ArrayList<LatLng>();
lineOptions = new PolylineOptions();
// Fetching i-th route
List<HashMap<String, String>> path = result.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);
if (j == 0) { // Get distance from the list
distance = (String) point.get("distance");
continue;
} else if (j == 1) { // Get duration from the list
duration = (String) point.get("duration");
value_duration = (String) point.get("duration_");
continue;
}
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.parseColor("#F7B907"));
}
// Drawing polyline in the Google Map for the i-th route
distanza_percorso = distance;
durata_percorso = duration;
testo_car.setText(durata_percorso);
durata_tragitto = Float.parseFloat(value_duration);
Log.d("durata_tragitto", "durata: " + value_duration);
polylineFinal = map.addPolyline(lineOptions);
moveToBounds(map.addPolyline(lineOptions));
}
Now i would like to remove polyline by map if i replace second marker and call a new calculate route.
I have write this codde:
if (polylineFinal != null){
polylineFinal.remove();
}
but the polyline on map are not remove.
Can you help me please? Any idea why?
Thanks
Not sure but try updating your adding polyline code with this,
polylineFinal = map.addPolyline(lineOptions);
moveToBounds(polylineFinal);
I'm following a tutorial to implement route drawing on my map. I implemented it, run it, choose points and then it crashes. It gives me this error
Attempt to invoke virtual method 'com.google.android.gms.maps.model.Polyline com.google.android.gms.maps.GoogleMap.addPolyline(com.google.android.gms.maps.model.PolylineOptions)' on a null object reference
The thing is that this shouldn't be empty since I have at least 3 points on the map....
The studio points my error to be here, but I dont find it: `protected void onPostExecute(List>> result) {
ArrayList points;
PolylineOptions lineOptions = null;
for (int i = 0; i < result.size(); i++) {
points = new ArrayList<>();
lineOptions = new PolylineOptions();
// Fetching i-th route
List<HashMap<String, String>> path = result.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);
}
lineOptions.addAll(points);
lineOptions.width(10);
lineOptions.color(Color.RED);
}
if(lineOptions != null) {
googleMap.addPolyline(lineOptions); //---> ERROR supose to be here..
}
else {
}
}
}`
If anybody could give me a hand, I would kindly appreciate it.
I am trying this from quite long so is why i am here seeking for some serious help!!
In my application i am suppose to plot more than 2 alternative routes onclick of a button, say in my application i have 3 buttons such as r1,r2 and r3.When i enter the source and destination locations in my application's respective's edittexts and click enter then i shall be plotting by default r1 so now when i click on r2 button the path/route plotted on the map previously should be erased/deleted and the new alternative path/route should be plotted on the map but isnt happening that way instead of erasing the previous path/route it is plotting both the routes on the map:( can someone please help me?
Here is my code.
List<RoutesDictionary> routeDicList = new ArrayList<RoutesDictionary>();
routeTwo.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
map.clear();
routeDicList.clear();
routeType = 2;
rout = "walking";
new TrafficData().execute();
Log.d("TH routeTwo", "In routeTwo After" +
`enter code here`routeDicList.size());
}
});
public class TrafficData extends AsyncTask<Context, String, String> {
routeTwo.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
map.clear();
routeDicList.clear();
routeType = 2;
rout = "walking";
new TrafficData().execute();
}
});
#Override
protected String doInBackground(Context... params) {
try {
if (!via_route.equals("")) {
url = "http://maps.googleapis.com/maps/api/directions/json?origin="
+ sourceAdd
+ "&destination="
+ destinationAdd
+ "&waypoints=via:"
+ via_route
+ "&sensor=false&mode=" + rout;
} else {
url = "http://maps.googleapis.com/maps/api/directions/json?origin="
+ sourceAdd
+ "&destination="
+ destinationAdd
+ "&sensor=false&mode=" + rout;
}
// Making HTTP request
try {
// defaultHttpClient
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet httpPost = new HttpGet(url);
HttpResponse httpResponse = httpClient.execute(httpPost);
result = EntityUtils.toString(httpResponse.getEntity());
Log.v("Traffic App : ", "The Traffic App result is : "
+ result);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
Log.v("Traffic App : ", "The Traffic App resultTraffic is : "
+ resultTraffic);
try {
JSONObject routesObj = new JSONObject(result);
String status = routesObj.getString("status");
if (status.equals("OK")) {
routesDictionary = new RoutesDictionary();
allRouteDic.addSrcAddress(sourceAdd);
allRouteDic.addDesAddress(destinationAdd);
AllRoutes.allRoutes.add(allRouteDic);
Log.v("***********************", "THE ***** Array list : ");
JSONArray routesArr = routesObj.getJSONArray("routes");
JSONObject mainObj = routesArr.getJSONObject(0);
JSONArray legsArr = mainObj.getJSONArray("legs");
int legsSize = legsArr.length();
for (int i = 0; i < legsSize; i++) {
routesDictionary.addlegsDistance(legsArr.getJSONObject(
i).getJSONObject("distance"));
routesDictionary.addlegsDuration(legsArr.getJSONObject(
i).getJSONObject("duration"));
routesDictionary.addlegsEndaddress(legsArr
.getJSONObject(i).getString("end_address"));
routesDictionary
.addlegsEndlocation(legsArr.getJSONObject(i)
.getJSONObject("end_location"));
routesDictionary.addlegsStartaddress(legsArr
.getJSONObject(i).getString("start_address"));
routesDictionary.addlegsStartlocation(legsArr
.getJSONObject(i).getJSONObject(
"start_location"));
routeDicList.add(routesDictionary);
JSONArray stepsArr = legsArr.getJSONObject(i)
.getJSONArray("steps");
int stepsLen = stepsArr.length();
for (int j = 0; j < stepsLen; j++) {
routesDictionary
.addlegs_StepsDistance(stepsArr
.getJSONObject(j).getJSONObject(
"distance"));
routesDictionary
.addlegs_StepsDuration(stepsArr
.getJSONObject(j).getJSONObject(
"duration"));
routesDictionary.addlegs_StepsEndlocation(stepsArr
.getJSONObject(j).getJSONObject(
"end_location"));
routesDictionary.addlegs_StepsHtmlInstruct(stepsArr
.getJSONObject(j).getString(
"html_instructions"));
routesDictionary
.addlegs_StepsPloyline(stepsArr
.getJSONObject(j).getJSONObject(
"polyline"));
routesDictionary
.addlegs_StepsStartlocation(stepsArr
.getJSONObject(j).getJSONObject(
"start_location"));
routesDictionary.addlegs_StepsTravelmode(stepsArr
.getJSONObject(j).getString("travel_mode"));
routeDicList.add(routesDictionary);
}
}
int strLoc = routeDicList.get(0)
.getlegs_StepsStartlocation().size();
for (int k = 0; k < strLoc; k++) {
routesDictionary.addStrLatit(routeDicList.get(0)
.getlegs_StepsStartlocation().get(k)
.getString("lat"));
routesDictionary.addStrlongi(routeDicList.get(0)
.getlegs_StepsStartlocation().get(k)
.getString("lng"));
routeDicList.add(routesDictionary);
}
int endLoc = routeDicList.get(0).getlegs_StepsEndlocation()
.size();
for (int l = 0; l < endLoc; l++) {
routesDictionary.addEndLatit(routeDicList.get(0)
.getlegs_StepsEndlocation().get(l)
.getString("lat"));
routesDictionary.addEndLongi(routeDicList.get(0)
.getlegs_StepsEndlocation().get(l)
.getString("lng"));
routeDicList.add(routesDictionary);
}
int strL = routeDicList.get(0).getStrLatit().size();
for (int m = 0; m < strL; m++) {
Log.v("Traffic : ", "*** Latitude and Longi *** : "
+ routeDicList.get(0).getStrLatit().get(m)
+ " "
+ routeDicList.get(0).getStrLong().get(m));
}
int endL = routeDicList.get(0).getEndLatit().size();
for (int m = 0; m < endL; m++) {
Log.v("Traffic : ", "### Latitude and Longi ### : "
+ routeDicList.get(0).getEndLatit().get(m)
+ " "
+ routeDicList.get(0).getEndLong().get(m));
}
rectOptions = new PolylineOptions();
Log.v("*****************", "The RECTPOINTS SIZE : "
+ rectOptions.getPoints().size());
rectOptions.getPoints().clear();
switch (routeType) {
case 1:
rectOptions.color(Color.RED);
break;
case 2:
rectOptions.color(Color.BLUE);
break;
case 3:
rectOptions.color(Color.GREEN);
break;
default:
break;
}
rectOptions.width(4);
for (int i = 1; i < strL; i++) {
rectOptions.add(new LatLng(Double.valueOf(routeDicList
.get(0).getStrLatit().get(i)), Double
.valueOf(routeDicList.get(0).getStrLong()
.get(i))));
}
// Get back the mutable Polygon
map.clear();
polyline = map.addPolyline(rectOptions.geodesic(false));
polyline.remove();
polyline = map.addPolyline(rectOptions.geodesic(true));
double lng = Double.valueOf(routeDicList.get(0)
.getlegs_StepsStartlocation().get(0)
.getString("lng"));
double lat = Double.valueOf(routeDicList.get(0)
.getlegs_StepsStartlocation().get(0)
.getString("lat"));
map.animateCamera(CameraUpdateFactory.newLatLngZoom(
new LatLng(lat, lng), 14.0f));
// start longitude and latitude
double startlng = Double
.valueOf(routeDicList.get(0)
.getlegs_StepsEndlocation().get(0)
.getString("lng"));
double startlat = Double
.valueOf(routeDicList.get(0)
.getlegs_StepsEndlocation().get(0)
.getString("lat"));
// start location marker
addMarker(startlat, startlng);
// end longitude and latitude
double endlng = Double.valueOf(routeDicList.get(0)
.getlegs_StepsStartlocation().get(endLoc - 1)
.getString("lng"));
double endlat = Double.valueOf(routeDicList.get(0)
.getlegs_StepsStartlocation().get(endLoc - 1)
.getString("lat"));
// end location marker
addMarker(endlat, endlng);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
1- You set the OnClickListener for routeTwo button twice one in the main class and one in the AsyncTask , the one in the AsyncTask should be removed.
2- Pressing the button twice fast would produce your problem, because you will start two separably AsyncTasks each one will draw a route so both routes would be displayed, i prefer using just one AsyncTask as a global variable and before running new one check if there is a running AsyncTask ,this could be done by
if(trafficData != null && trafficData.getStatus() != AsyncTask.Status.FINISHED){
trafficData .cancel(true);
}