Is possible to route in android sdk using calculateroute.json - android

I am using Here maps SDK in an android project.
I want to calculate track here and put it into an android map to route exactly this way (calculated on API)
I tried to get points from Json and map them to waypoints, but the calculated way sometimes differs from the original.
What I have tried so far:
1. Get calculateroute.json from
https://route.api.here.com/routing/7.2/calculateroute.json
2. Put coordinates to RoutePlan
RoutePlan plan = new RoutePlan();
plan.addWaypoint(new RouteWaypoint(new GeoCoordinate(54.3782893, 18.7009037, 0), RouteWaypoint.Type.STOP_WAYPOINT));
plan.addWaypoint(new RouteWaypoint(new GeoCoordinate(54.2660919, 18.6583687, 0), RouteWaypoint.Type.STOP_WAYPOINT));
3. Calculate route and put to a map
new CoreRouter().calculateRoute(plan, new CoreRouter.Listener() {
#Override
public void onCalculateRouteFinished(List<RouteResult> list, RoutingError error) {
MapRoute mapRoute = new MapRoute(list.get(0).getRoute()
new Map().addMapObject(mapRoute)
}
}
I want to do :
1. Get calculateroute.json from
https://route.api.here.com/routing/7.2/calculateroute.json
2. Create MapRoute from the calculateroute.json result ( but don't calculate it )
3. Put MapRoute to map and start navigation

Basically there is no direct way to achieve this, a workaround solution is as described in the thread : Backend Calculated Route,Here-API to just show Guidance and route on Map

Related

Android - google maps gets stuck

I'm developing a App which display a Google map and a bunch of markers on it. There's a lot of markers so I divided them in smaller groups and display only those, which are in some bounds depending on the current position of the camera.
To do that I'm using the GoogleMap.OnCameraIdleListener. First I remove the listener, do my calculations and drawing and then I restore the listener to the Fragment containing my map:
#Override
public void onCameraIdle() {
mMap.setOnCameraIdleListener(null);
clearMap();
findTheMarkersInBounds();
displayTheMarkers();
mMap.setOnCameraIdleListener(this);
}
This way I only draw the markers I need to display and the performance is way better then having 1000 markers on the map at once. I also draw about the same number of polylines but that's not the point now.
For some strange reasons, after some panning and zooming the maps doesn't respond anymore. Can't zoom it nor pan it. App displays a dialog that it is not responding and I should wait or close the app. No erros are displayed in logcat. I can't exactly tell when this happens. Sometimes after the first pan, sometimes I can move around 2-3 minutes. Same thing happens on the emulator and on the physical device.
Anyone experienced something like this? Thanks!
Or am I approaching this the wrong way? How else should I optimize the map to display about 1000 markers and polylines. (The markers have text on them, so it can't be the same Bitmap and all of the polylines can have different colors and need to be clickable, so I can't combine them into one large polyline)
EDIT. A little more info about my methods:
After all the marker positions are loaded from the internal database, I do a for-loop through all of them and based on their position and I place them to the corresponding region. Its an 2D array of lists.
My whole area is divided to 32x32 smaller rectangular areas. When I'm searching for the markers to display, I determine which region is in view and display only those markers, which are in this area.
This way I don't need to loop over all of the markers.
My methods (very simplified) look like this:
ArrayList<MarkerObject> markersToDisplay = new ArrayList<MarkerObject>();
private void findTheMarkersInBounds() {
markersToDisplay.clear();
LatLngBounds bounds = mMap.getProjection().getVisibleRegion().latLngBounds;
int[] regionCoordinates = getRegionCoordinates(bounds); // i, j coordinates of my regions [0..31][0..31]
markersToDisplay.addAll(subdividedMarkers[regionCoordinates[0]][regionCoordinates[1]]);
}
private void drawMarkers() {
if ((markersToDisplay != null) && (markersToDisplay.size() > 0)) {
for (int i=0; i<markersToDisplay.size(); i++) {
MarkerObject mo = markersToDisplay.get(i);
LatLng position = new LatLng(mo.gpsLat, mo.gpsLon);
BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromBitmap(createMarker(getContext(), mo.title));
GroundOverlay m = mMap.addGroundOverlay(groundOverlayOptions.image(bitmapDescriptor).position(position, 75));
m.setClickable(true);
}
}
}
It is hard to help you without source code of findTheMarkersInBounds() and displayTheMarkers(), but seems, you need different approach to increase performance, for example:
improve your findTheMarkersInBounds() logic if it possible;
runfindTheMarkersInBounds() in separate thread and show not all markers in same time, but one by one (or bunch of 10..20 at one time) during findTheMarkersInBounds() searching;
improve your displayTheMarkers() if it possible, actually may be use custom drawing on canvas (like in this answer) instead of creating thousands Marker objects.
For question updates:
Small improvements (first, because they are used for main):
pass approximately max size of markersToDisplay as constructor parameter:
ArrayList<MarkerObject> markersToDisplay = new ArrayList<MarkerObject>(1000);
Instead for (int i=0; i<markersToDisplay.size(); i++) {
use for (MarkerObject mo: markersToDisplay) {
Do not create LatLng position every time, create it once and store in MarkerObject fields.
Main improvement:
This lines are the source of issues:
BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromBitmap(createMarker(getContext(), mo.title));
GroundOverlay m = mMap.addGroundOverlay(groundOverlayOptions.image(bitmapDescriptor).position(position, 75));
IMHO using Ground Overlays for thousands of markers showing is bad idea. Ground Overlay is for several "user" maps showing over default Google Map (like local plan of Park or Zoo details). Use custom drawing on canvas like on link above. But if you decide to use Ground Overlays - do not recreate them every time: create it once, store references to them in MarkerObject and reuse:
// once when marker created (just example)
mo.overlayOptions = new GroundOverlayOptions()
.image(BitmapDescriptorFactory.fromBitmap(createMarker(getContext(), mo.title)))
.position(mo.position, 75))
.setClickable(true);
...
// in your drawMarkers() - just add:
...
for (MarkerObject mo: markersToDisplay) {
if (mo.overlayOptions == null) {
mo.overlayOptions = createOverlayOptionsForThisMarker();
}
mMap.addGroundOverlay(mo.overlayOptions)
}
But IMHO - get rid of thousands of Ground Overlays at all - use custom drawing on canvas.
After further investigation and communication with the google maps android tech support we came to a solution. There's a bug in the GroundOverlay.setZIndex() method.
All you have to do is to update to the newest API version. The bug is not present anymore in Google Maps SDK v3.1.
At this moment it is in Beta, but the migration is pretty straightforward.

How to implement Google Directions API for unknown destination?

I'm a beginner in android studio and I'm currently create cycling apps for my final project. in these apps I need to implement Maps and Direction API. I search for tutorials, but they all set the destination. and in my apps the destination is unknown.
it's possible if I display the current location (automatic) and draw a line in Maps while the user is riding, please give a tutorial too? And it's possible if I use a Free API Key for this project?
thank you ...
First, This direction API is not free.
2nd you need to provide start and endpoint for direction API routes.
You can use the current location as your start point and if you have no destination then where do you want to draw a line? Means from your current location to where?
or If you want to draw a tracking line from your starting position to your current position then you don't need Direction API, you just need Live location tracking and can draw Polylines on your map using current location. Following is the code for your help.
To get this library into our app, we need to add the following to our build.gradle file.
implement 'com.google.maps:google-maps-services:0.1.20'
// Initialize Geo Context First
private GeoApiContext getGeoContext() {
GeoApiContext geoApiContext = new GeoApiContext();
return geoApiContext.setQueryRateLimit(3)
.setApiKey(getString(R.string.directionsApiKey))
.setConnectTimeout(1, TimeUnit.SECONDS)
.setReadTimeout(1, TimeUnit.SECONDS)
.setWriteTimeout(1, TimeUnit.SECONDS);
}
// This code will fetch the result from Google direction api from origin to destination
DateTime now = new DateTime();
DirectionsResult result = DirectionsApi.newRequest(getGeoContext()).mode(TravelMode.DRIVING).origin(origin)
.destination(destination)
.departureTime(now).await();
// You can use this method to add marker on the map
private void addMarkersToMap(DirectionsResult results, GoogleMap mMap) {
mMap.addMarker(new MarkerOptions().position(new LatLng(results.routes[0].legs[0].startLocation.lat, results.routes[0].legs[0].startLocation.lng)).title(results.routes[0].legs[0].startAddress));
mMap.addMarker(new MarkerOptions().position(new LatLng(results.routes[0].legs[0].endLocation.lat, results.routes[0].legs[0].endLocation.lng)).title(results.routes[0].legs[0].startAddress).snippet(getEndLocationTitle(results)));
}
// Use this method to draw polyline/routes on your map
private void addPolyline(DirectionsResult results, GoogleMap mMap) {
List<LatLng> decodedPath = PolyUtil.decode(results.routes[0].overviewPolyline.getEncodedPath());
mMap.addPolyline(new PolylineOptions().addAll(decodedPath));
}

Mapbox Navigation via Customised Routes

So Mapbox provides an awesome Navigation SDK for Android, and what I have been trying to do is create my own routes, representing each point as a Feature in a Geojson file, and then passing them on to the MapMatching module to get directions that I can then pass to the Navigation Engine.
My solution evolves into two main parts. The first one involves iterating through the points I want navigation to go through, by adding them as input to the .coordinates element of MapboxMapMatching.builder() and subsequently converting this to
.toDirectionRoute(); per Mapbox instructions and example here: https://www.mapbox.com/android-docs/java/examples/use-map-matching/
private void getWaypointRoute(List<Point> features) {
originPosition = features.get(0);
destinationPosition = features.get(features.size() - 1);
MapboxMapMatching.builder()
.accessToken(Mapbox.getAccessToken())
.coordinates(features)
.steps(true) // Setting this will determine whether to return steps and turn-by-turn instructions.
.voiceInstructions(true)
.bannerInstructions(true)
.profile(DirectionsCriteria.PROFILE_DRIVING)
.build().enqueueCall(new Callback<MapMatchingResponse>() {
#Override
public void onResponse(Call<MapMatchingResponse> call, Response<MapMatchingResponse> response) {
if (response.body() == null) {
Log.e(TAG, "Map matching has failed.");
return;
}
if (response.isSuccessful()) {
currentRoute = response.body().matchings().get(0).toDirectionRoute();
The second bit involves just passing 'currentRoute' to the NavigationLauncher as shown below:
NavigationLauncherOptions options = NavigationLauncherOptions.builder()
.origin(origin)
.destination(destination)
.directionsRoute(currentRoute)
.shouldSimulateRoute(simulateRoute)
.enableOffRouteDetection(false)
.build();
// Call this method with Context from within an Activity
NavigationLauncher.startNavigation(MainActivity.this, options);
An example of the route can be seen here Android Simulator Snapshot with Route . Each point across the route, is an intersection, and corresponds to a feature in my GeoJson file. The problem becomes when I launch the navigation. Every time, either in the simulator or on a real device, each point is interpreted as a destination so the voice command goes 'You have reached your first (second, third etc) destination'. I find this annoying as I would like to have a single route with a destination and that's it. I would just like to have this points so I have my own custom path, instead of the shortest path typically returned by routing applications. I try to avoid the problem by setting voiceInstructions off but then the system goes bananans and the navigation screen moves to lat, lng (0,0) which is pretty much somewhere West of Africa. Any help on how I could resolve this it would be greatly appreciated and I would be happy to buy a beer or two for the person that provides the right answer. I have reached out to Mapbox Support as well but we have not found an answer to the problem so I asked them to escalate it internally within their engineering team, as I believe, although the problem I am solving is not uncommon, it is still not very much tested by developers. Cheers!
So here I am and after the kind support of Mapbox Support and Rafa Gutierrez
I can now answer this post myself.
The problem has been arising due to MapboxMapMatching automatically setting .coordinates as waypoints. If instead, one edits explicitly the waypoints variable to have only two waypoints: origin and destination, then the system is able to process the input customised route without translating each input coordinate as a waypoint. The code example below hopefully clarifies the point described above:
MapboxMapMatching.builder()
.accessToken(Mapbox.getAccessToken())
.coordinates(lineStringRep.coordinates())
.waypoints(OD)
.steps(true)
.voiceInstructions(true)
.bannerInstructions(true)
.profile(DirectionsCriteria.PROFILE_DRIVING)
.build().enqueueCall(new Callback<MapMatchingResponse>()
where OD is an array of integers storing the first (origin) and last index (destination) of your coordinates
OD[0] = 0;
OD[1] = features.size() - 1;

Skobler Android: How can I get all points to simulated route?

I need to get many points of simulated route. My goal is get all points to paint a route using shape with SKPolyline in another view. How can I get that?
Regards.
If i understand your goal you want to draw the route that skobbler calculate for you using SKPolyline.
After request route calculation the callback onRouteCalculationCompleted will call with SKRouteInfo.
To get the route positions try:
List<SKExtendedRoutePosition> list = SKRouteManager.getInstance().getExtendedRoutePointsForRoute(skRouteInfo.getRouteID());
Don't forget to set ExtendedPointsReturned=true when you request route calculation.
SKRouteSettings routeS = new SKRouteSettings();
routeS.setStartCoordinate(startPosition.getCoordinate());
routeS.setDestinationCoordinate(destinationPosition.getCoordinate());
// number of alternative routes specified here
routeS.setNoOfRoutes(1);
routeS.setRouteMode(SKRouteSettings.SKRouteMode.CAR_FASTEST);
//set true if you want the route is draw on map
routeS.setRouteExposed();
routeS.setExtendedPointsReturned(true);
SKRouteManager.getInstance().calculateRoute(routeS);
etzuk's answer is correct, but remember to cached the route before you can get all the skPosition of created route.
On onRouteCalculationCompleted, add saveRouteToCahce before getting route's coordinates like this:
SKRouteManager.getInstance().saveRouteToCache(skRouteInfo.getRouteID());
List<SKExtendedRoutePosition> coordinatesForRoute = SKRouteManager.getInstance()
.getExtendedRoutePointsForRoute(
skRouteInfo.getRouteID());

Clickable Polylines Google Maps API Android

I would like to click a spot on a Google maps v2 android map. If the clicked point intersects a point on a polyline path, then display the polyline. I do not see any documented clickable events for polylines in android. I tried to extend the current Polyline object (marked final)
What other options do I have?
You can use library:
https://github.com/googlemaps/android-maps-utils
And detect clicks to polyline using next method (in OnMapClickListener):
PolyUtil.isLocationOnPath(point, polyline.getPoints(), isGeodesic, tolerance);
With the recent update of the maps api, v8.4, introduces clickable Polyline
As mentioned in the doc:
Use the OnPolylineClickListener to listen to click events on a
clickable polyline. To set this listener on the map, call
googleMap.setOnPolylineClickListener(...). When
a user clicks on a polyline, you will receive an
onPolylineClick(Polyline) callback.
gradle-dependency:
compile 'com.google.android.gms:play-services-maps:8.4.0'
implement callback: GoogleMap.OnPolylineClickListener
initialize Polyline:
Polyline polyline = googleMap.addPolyline(options);
polyline.setClickable(true);
...
receive events
#Override
public void onPolylineClick(Polyline polyline) {
....
}
Happy coding :)
Register an OnMapClickListener. Determine if a given click is on your line yourself. If it is, do whatever it was you wanted to do in this case.
I had a similar issue where I could not process click events on polylines. I was using Xamarin for Android which is C# but the functionality is largely the same as the Android Java Libraries in this case.
In the end, I ended up doing what seemed to be the only option.
This involved processing all of the midpoints of my polylines(of which there were around 1300). On every OnMapClick, I took the LatLng of the click event and performed a distance formula between it and the midpoint of all polylines in the static List<PolylineOptions>. I then attached a map marker to the closest polyline.
From a tap on a polyline, it pops up a marker in about a quarter of a second.
I imagine the implemented marker click events from the Google Maps API work in a similar way.
Here is the for loop that handles finding the closest point to a click.
int i = 0;//create an indexer for the loop
double shortestDist = 100;//set an initial very large dist just to be safe
int myIndex = 0;//set variable that will store the running index of the closest point
foreach (PolylineOptions po in myPolylines) {
var thisDist = Distance (point, midPoint (po.Points [0].Latitude, po.Points [0].Longitude, po.Points [1].Latitude, po.Points [1].Longitude));//calculate distance between point and midpoint of polyline
if (thisDist < shortestDist) {
shortestDist = thisDist;//remember current shortest distance
myIndex = i;//set closest polyline index to current loop iteration
}
i++;
}
I know it isn't the prettiest code but it gets the job done. I didn't see a real answer to this anywhere on the internet so here it is. It could probably be made more efficient by calculating the midpoints beforehand and storing them in an equally sized list and then not having to call the midpoint formula for each polyline on every map click but it works really fast already.
EDIT
I do my testing on a galaxy s3 by the way, so I think it's not too inefficient.
If you are using com.google.android.gms:play-services-maps:8.4.0 then it includes polylines click listener
googleMap.setOnPolylineClickListener(new GoogleMap.OnPolylineClickListener()
{
     #Override
     public void onPolylineClick(Polyline polyline)
      {
          //do your work selected polyline
     }
});
PolylineOptions line = new PolylineOptions();
Polyline polyline = googleMap.addPolyline(line);
polyline.setClickable(true);

Categories

Resources