For some reason, this code always returns 0, no matter where I am
public Long getClosestLinkID()
{
GeoCoordinate cur = HereMapsManager.instance.getPositionAnchor(); //returns my current position
Long closest = -1L;
RoadElement closest_elem = RoadElement.getRoadElement(cur, "fre");
if (closest_elem != null) {
closest = closest_elem.getPermanentDirectedLinkId();
}
return closest;
}
It finds a valid RoadElement, but calling getPermanentDirectedLinkId() (or getPermanentLinkId()) constantly returns 0.
Now, the documentation says:
Returns:
Permanent Link ID with direction of this element or 0 if not available.
So I tried with random coordinates on the map a little bit everywhere on the roads in France, and it keeps returning 0. I'm lost here.
getPermanentDirectedLinkId and getPermanentLinkId property is unavailable when the public transport mode RouteOptions.TransportMode#PUBLIC_TRANSPORT is used. For all the other transport modes, it is available only in routes calculated with the online connectivity mode. You should set your Connectivity explicitly to ONLINE(setConnectivity(Connectivity.ONLINE)).
Also, check if you are in one of the below two modes:
Tracking - NavigationManager.startTracking()
Navigation - NavigationManager.startNavigation()
This is required inorder to map match your location to a route.
You have to explicitly download and use offline maps as well to get this information.
Editing to add more information based on the customer comment below: You can check the classes and methods supported for your SDK by looking up the below pages
Starter SDK: {SDK-Download-location}/HERE_Android_SDK_Starter_v3.8_65/HERE-sdk/libs/docs/mapsdoc/index.html
Premium SDK: {SDK-Download-location}/HERE_Android_SDK_Premium_v3.8.0.104/sdk/HERE-sdk/libs/docs/mapsdoc-hybridplus/index.html
Related
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;
I am using SKPOITrackerManager to track self-defined trackable POIs in navigation mode. The arraylist of SKTrackablePOI objects has many elements which are placed near my route. But only one of them is tracked by onReceivedPOIs(). This method only returns a one-element-list. But it is called 5 to 10 times for exactly one POI. I am sorry that I can not post my complete code here due to project agreement. But here I can show you my settings in an implementation of the SKPOITrackerListener interface:
public void startPOITracking() {
poiTrackerManager = new SKPOITrackerManager(this);
SKTrackablePOIRule skTrackablePOIRule = new SKTrackablePOIRule();
skTrackablePOIRule.setAerialDistance(15000);
skTrackablePOIRule.setRouteDistance(15000);
skTrackablePOIRule.setNumberOfTurns(15000);
skTrackablePOIRule.setMaxGPSAccuracy(15000);
skTrackablePOIRule.setEliminateIfUTurn(false);
skTrackablePOIRule.setMinSpeedIgnoreDistanceAfterTurn(12000);
skTrackablePOIRule.setMaxDistanceAfterTurn(150000);
poiTrackerManager.startPOITrackerWithRadius(100, 0.5);
poiTrackerManager.setRuleForPOIType(SKTrackablePOIType.INVALID, skTrackablePOIRule);
poiTrackerManager.addWarningRulesforPoiType(SKTrackablePOIType.INVALID);
}
I have set the limitions to very high values within SKTrackablePOIRule and still a get only one POI. I can even comment out the line with poiTrackerManager.setRuleForPOIType(SKTrackablePOIType.INVALID, skTrackablePOIRule); and I still receive only one single POI. Maybe someone can help to understand my problem.
Here is something I used in the past:
poiTrackingManager = new SKPOITrackerManager(this);
SKTrackablePOIRule rule = new SKTrackablePOIRule();
rule.setAerialDistance(5000); // this would be our main constraint, stating that all the POIs with 5000m, aerial distance should be detected
rule.setNumberOfTurns(100); // this has to be increased – otherwise some points will be disconsidered
rule.setRouteDistance(10000);//this has to be increased as the real road route will be longer than the aerial distance
rule.setMinSpeedIgnoreDistanceAfterTurn(20); //decrease this to evaluate all candidates
rule.setMaxDistanceAfterTurn(10000); //increase this to make sure we don't exclude any candidates
rule.setEliminateIfUTurn(false); // setting this to true (default) excludes points that require us to make an U-turn to get to them
rule.setPlayAudioWarning(false);
Note: I'm not certain what are the max/min values for these parameters as I've seen some issues when they are too high (they do affect the routing algorithm, more precissely how the road graph is explored so this could explain why at high values it might malfunction) - I would say that you should start with conservative values and then gradually increase them
For startPOITrackerWithRadius I would use different values as if you set the radius to 100 (meters) this would greatly reduce the number of POIs that the SDK is able to analyze (even if the rules are good, the POIs might not be analyzed as they don't fall in the "radius" (aerial distance) around your current position) :
poiTrackingManager.startPOITrackerWithRadius(1500, 0.5);
Also see http://sdkblog.skobbler.com/detecting-tracking-pois-in-your-way/ for more insights on how the POITraker works
With Unity, the CardboardHead script is added to the main camera and that handles everything quite nicely, but I need to be able to "recenter" the view on demand and the only option I see so far is to rorate the entire scene and it seems like this is something the would address first-hand and I can't find anything in the docs.
With Oculus Mobile SDK (GearVR), it would be OVRCamera.ResetCameraPositionOrientation(Vector3.one, Vector3.zero, Vector3.up, Vector3.zero); though they handle it nicely each time the viewer is put on so it's rarely needed there.
There's a "target" parameter on the CardboardHead that lets you use to another gameobject as a reference for rotation. Or you can use a dummy parent gameobject. Either way, when you want to recenter, you set this reference object's rotation so that the CardboardHead is now pointing forward. Add this function to an script on the CardboardHead (or just add it into that script):
public void Recenter() {
Transform reference = target != null ? target : transform.parent;
if (reference != null) {
reference.rotation = Quaternion.Inverse(transform.rotation) * reference.rotation;
// next line is optional -- try it with and without
reference.rotation = Quaternion.FromToRotation(reference.up, Vector3.up) * reference.rotation;
}
}
Cardboard.SDK.Recenter (); should do the trick.
Recenter orientation Added Recenter() function to Cardboard.SDK, which resets the head tracker so the phone's current heading becomes the forward direction (+Z axis).
Couldn't find the docs for the API/SDK but it's in the release notes for the v0.4.5 Update.
You can rotate the Cardboard Main to point in a certain direction.
This is what worked for me when I wanted the app to start up pointing a certain way. Since the CardboardHead points at Vector3.zero on startup if no target is assigned, I ran a function during Start() for the CardboardMain that would point in the direction I wanted.
Of course, if you're already rotating CardboardMain for some other reason, it may be possible to use this same method by creating a parent of the CardboardHead (child of CardboardMain) and doing the same thing.
This question is a bit old but for Google VR SDK 1.50+ you can do
transform.eulerAngles = new Vector3(newRot.x, newRot.y, newRot.z);
UnityEngine.VR.InputTracking.Recenter();
also, if you don't want to get confused you also need to catch the GvrEditorEmulator instance and Recenter it as well.
#if UNITY_EDITOR
gvrEditorEmulator.Recenter();
#endif
Recentering GvrEditorEmulator though doesn't seem to work very well at the moment but if you disable it you'll see the recentering works for the main camera.
I'm using google.maps.geometry.spherical.computeDistanceBetween() to compute the distance between relatively close points (10-30 meters). This works perfectly in Linux (Chrome and Firefox), but sometimes gives me crazy results in Android. One case that I got was with this:
var p1 = new google.maps.LatLng(-22.960584,-43.206687999999986);
var p2 = new google.maps.LatLng(-22.960584,-43.206939000000034);
alert(google.maps.geometry.spherical.computeDistanceBetween(p1,p2));
It should give 25 meters or so, yet once I got hundred of thousands of meters. Again, it is not always that I get crazy values, just "sometimes", probably related with lots of computations?
Is this a well known bug? If it is, I cannot use this method and would have to make my own.
Thanks,
L.
As far as I can tell, this is an Android bug. I think this could very well explain why in the MyTracks app I usually get randomly points in other continents and huge distances.
I computed the distance function with the method below, and now I always get the correct values. In particular, if this is what it looks, this is a very serious bug for Android app that uses this function.
In case anyone cares, this is the distance function between to LatLng p and q:
function dist(p,q) {
var c = Math.PI/180;
// Google (gives randomly wrong results in Android!)
//return google.maps.geometry.spherical.computeDistanceBetween(p,q);
// Chord
//return 9019995.5222 * Math.sqrt((1-Math.cos(c*(p.lat()-q.lat())))
// + (1-Math.cos(c*(p.lng()-q.lng()))) * Math.cos(c*p.lat()) * Math.cos(c*q.lat()));
// Taylor for chord
return 111318.845 * Math.sqrt(Math.pow(p.lat()-q.lat(),2)
+ Math.pow(p.lng()-q.lng(),2) * Math.cos(c*p.lat()) * Math.cos(c*q.lat()));
}
Notice that these are the computations for the chord, that is, the distance in R^3, not the geodesic distance in the sphere. Certainly more than enough for hiking/car travel computations using GPS. I ended up using the Taylor expansion since it is precise to 1/10 mm, and less tough with the CPU.
I am developping an application that uses the Camera preview, take picture, and zoom functions.
I am trying to remain compatible with the Android API level 7 (2.1 Eclair), which does not implement Camera.Parameters.getMaxZoom(), Camera.Parameters.setZoom(), etc, so I have to use the String parameters returned by the hardware. For example:
final String zoomSupportedString = parameters.get("zoom-supported"); // parameters is a Camera.Parameters
final boolean zoomSupported = (zoomSupportedString != null ? Boolean.parseBoolean(zoomSupportedString) : false);
if (zoomSupported) {
// Computes the min an max zoom levels for taking a picture:
final int minTake = parameters.getInt("taking-picture-zoom-min");
final int maxTake = parameters.getInt("taking-picture-zoom-max");
// etc.
}
But not all the devices use the same parameters, and I couldn't find any valid camera parameters list on the internet.
By checking the values returned by Camera.Parameters.flatten() (see doc) on a HTC I could find "zoom-supported", "taking-picture-zoom-min", "taking-picture-zoom-max" and "max-zoom". And surprisingly, I have found no "min-zoom".
But the parameter "taking-picture-zoom-min" doesn't exist on Samsung Galaxy S, for example, and this leads null to be returned and getInt() to throw a NumberFormatException: 'null' cannot be parsed as an integer.
Knowing that I am trying to remain compatible with Android-7, is there any better way to handle the zoom than using the string values returned by the hardware? And if so, is it possible to find somewhere a list of all the valid zoom parameters (or even a list by vendor)?
i know it's an old topic, but for those that are searching for Camera zoom... i had the same issue and now that i have 2 android devices which work differently, both had something in commmon.
Camera.Parameters.setZoom(int value) didn't work on both of them, so i started testing. One device has "taking-picture-zoom-...;" but both devices have "zoom=...;" in the Camera.Parameters. On the device that has "taking-picture-zoom-...;", if i use Camera.Parameters.set("zoom", int value) it would crash, while on the other it would work just fine. So, my solution is, when initializing the camera I store a boolean that holds true for Camera.Parameters.get("taking-picture-zoom")!=null, and false otherwise. From that moment on, when setting zoom, just check the boolean and use the appropriate zoom-command... and that's it, works like a charm ! ofcourse, you could also just make a String hold the appropriate command and use that when setting zoom.