Start a new topic

Poi are not displayed in correct directions in android.

Poi are not displayed in correct directions in android.


Hi,

I have marked 2 locations but the poi are displayed in different direction than the actual location.

I have been trying to get this worked from last 2 weeks. My client is intrested in your product and is ready to buy if the demo is successful.

I'm fetching the location from Google play service LocationServices.FusedLocationApi

Below is my class to fetch Location. Download FusedLocationProvider

package com.wikitude.samples;

import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.os.Bundle;
import android.os.StrictMode;
import android.util.Log;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;



/**
* Created by searock on 30/05/16.
*/

public class FusedLocationProvider implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
com.google.android.gms.location.LocationListener,
ArchitectViewHolderInterface.ILocationProvider {

private LocationRequest mLocationRequest;
private GoogleApiClient mGoogleApiClient;
private LocationListener listener;
private String TAG = "FusedLocationProvider";

public FusedLocationProvider(Context ctx, LocationListener locationListener){

mGoogleApiClient = new GoogleApiClient.Builder(ctx)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();

mGoogleApiClient.connect();

Log.i(TAG, "Connecting...");

this.listener = locationListener;
}

@Override
public void onConnected(Bundle bundle) {

Log.i(TAG, "onConnected");

mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(1000); // Update location every second

try{
if(mGoogleApiClient.isConnected()) {

Log.i(TAG, "requestLocationUpdates");
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
}
}catch (SecurityException se){
Log.i(TAG, se.toString());
}catch (Exception e){
Log.i(TAG, e.toString());
}

}

@Override
public void onConnectionSuspended(int i) {
Log.i(TAG, "onConnectionSuspended");
}

@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.i(TAG, "onConnectionFailed");
}

@Override
public void onLocationChanged(Location recentLoc) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();

StrictMode.setThreadPolicy(policy);

Log.i(TAG, Double.toString(recentLoc.getLongitude()));

listener.onLocationChanged(recentLoc);
}

@Override
public void onPause() {
Log.i(TAG, "onPause");
if(mGoogleApiClient.isConnected()) {

Log.i(TAG, "removeLocationUpdates");
//LocationServices.FusedLocationApi.removeLocationUpdates(
//mGoogleApiClient, this);
}
}

@Override
public void onResume() {
Log.i(TAG, "onResume");
try{
if(mGoogleApiClient.isConnected()){

Log.i(TAG, "requestLocationUpdates");
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
}

}catch (SecurityException se){
Log.i(TAG, se.toString());
}catch (Exception e){
Log.i(TAG, e.toString());
}
}


public void onStop(){
Log.i(TAG, "onStop");
if(mGoogleApiClient.isConnected()) {

Log.i(TAG, "disconnect");
mGoogleApiClient.disconnect();
}
}
}


 

And I have replaced the call to old location provider in SampleCamActivity.java Download SampleCamActivity.java

@Override
public ILocationProvider getLocationProvider(final LocationListener locationListener) {
//return new LocationProvider(this, locationListener);

return new FusedLocationProvider(this, locationListener);
}

 

and changed the sensor accuracy to high

@Override
public SensorAccuracyChangeListener getSensorAccuracyListener() {
return new SensorAccuracyChangeListener() {
@Override
public void onCompassAccuracyChanged( int accuracy ) {
/* UNRELIABLE = 0, LOW = 1, MEDIUM = 2, HIGH = 3 */
if ( accuracy < SensorManager.SENSOR_STATUS_ACCURACY_HIGH && SampleCamActivity.this != null && !SampleCamActivity.this.isFinishing() && System.currentTimeMillis() - SampleCamActivity.this.lastCalibrationToastShownTimeMillis > 5 * 1000) {
Toast.makeText( SampleCamActivity.this, R.string.compass_accuracy_low, Toast.LENGTH_LONG ).show();
SampleCamActivity.this.lastCalibrationToastShownTimeMillis = System.currentTimeMillis();
}
}
};
}

And I'm using 6_Browsing$Pois_3_Limiting$Range example and have modified the code slightly. Download js

I have just added a json array instead of fetching the json from a web service.

// information about server communication. This sample webservice is provided by Wikitude and returns random dummy places near given location
var ServerInformation = {
POIDATA_SERVER: "https://b47a9f2c41b113bb4987095b21061f1eb41219bf.googledrive.com/host/0Bw1oYLNzdr8pME5UM2x2bjVSY1U/main.json",
POIDATA_SERVER_ARG_LAT: "lat",
POIDATA_SERVER_ARG_LON: "lon",
POIDATA_SERVER_ARG_NR_POIS: "nrPois"
};

// implementation of AR-Experience (aka "World")
var World = {

// user's latest known location, accessible via userLocation.latitude, userLocation.longitude, userLocation.altitude
userLocation: null,

// you may request new data from server periodically, however: in this sample data is only requested once
isRequestingData: false,

// true once data was fetched
initiallyLoadedData: false,

// different POI-Marker assets
markerDrawable_idle: null,
markerDrawable_selected: null,
markerDrawable_directionIndicator: null,

// list of AR.GeoObjects that are currently shown in the scene / World
markerList: ,

// The last selected marker
currentMarker: null,

locationUpdateCounter: 0,
updatePlacemarkDistancesEveryXLocationUpdates: 10,

// called to inject new POI data
loadPoisFromJsonData: function loadPoisFromJsonDataFn(poiData) {

// show radar & set click-listener
PoiRadar.show();
$('#radarContainer').unbind('click');
$("#radarContainer").click(PoiRadar.clickedRadar);

// empty list of visible markers
World.markerList = ;

// start loading marker assets
World.markerDrawable_idle = new AR.ImageResource("assets/marker_idle.png");
World.markerDrawable_selected = new AR.ImageResource("assets/marker_selected.png");
World.markerDrawable_directionIndicator = new AR.ImageResource("assets/indi.png");

// loop through POI-information and create an AR.GeoObject (=Marker) per POI
for (var currentPlaceNr = 0; currentPlaceNr < poiData.length; currentPlaceNr++) {
var singlePoi = {
"id": poiData.id,
"latitude": parseFloat(poiData.latitude),
"longitude": parseFloat(poiData.longitude),
"altitude": parseFloat(poiData.altitude),
"title": poiData.name,
"description": poiData.description
};

World.markerList.push(new Marker(singlePoi));
}

// updates distance information of all placemarks
World.updateDistanceToUserValues();

World.updateStatusMessage(currentPlaceNr + ' places loaded');

// set distance slider to 100%
$("#panel-distance-range").val(100);
$("#panel-distance-range").slider("refresh");
},

// sets/updates distances of all makers so they are available way faster than calling (time-consuming) distanceToUser() method all the time
updateDistanceToUserValues: function updateDistanceToUserValuesFn() {
for (var i = 0; i < World.markerList.length; i++) {
World.markerList.distanceToUser = World.markerList.markerObject.locations.distanceToUser();
}
},

// updates status message shon in small "i"-button aligned bottom center
updateStatusMessage: function updateStatusMessageFn(message, isWarning) {

var themeToUse = isWarning ? "e" : "c";
var iconToUse = isWarning ? "alert" : "info";

$("#status-message").html(message);
$("#popupInfoButton").buttonMarkup({
theme: themeToUse
});
$("#popupInfoButton").buttonMarkup({
icon: iconToUse
});
},

// location updates, fired every time you call architectView.setLocation() in native environment
locationChanged: function locationChangedFn(lat, lon, alt, acc) {

// store user's current location in World.userLocation, so you always know where user is
World.userLocation = {
'latitude': lat,
'longitude': lon,
'altitude': alt,
'accuracy': acc
};


// request data if not already present
if (!World.initiallyLoadedData) {
World.requestDataFromServer(lat, lon);
World.initiallyLoadedData = true;
} else if (World.locationUpdateCounter === 0) {
// update placemark distance information frequently, you max also update distances only every 10m with some more effort
World.updateDistanceToUserValues();
}

// helper used to update placemark information every now and then (e.g. every 10 location upadtes fired)
World.locationUpdateCounter = (++World.locationUpdateCounter % World.updatePlacemarkDistancesEveryXLocationUpdates);
},

// fired when user pressed maker in cam
onMarkerSelected: function onMarkerSelectedFn(marker) {
World.currentMarker = marker;

// update panel values
$("#poi-detail-title").html(marker.poiData.title);
$("#poi-detail-description").html(marker.poiData.description);

var distanceToUserValue = (marker.distanceToUser > 999) ? ((marker.distanceToUser / 1000).toFixed(2) + " km") : (Math.round(marker.distanceToUser) + " m");

$("#poi-detail-distance").html(distanceToUserValue);

// show panel
$("#panel-poidetail").panel("open", 123);

$( ".ui-panel-dismiss" ).unbind("mousedown");

$("#panel-poidetail").on("panelbeforeclose", function(event, ui) {
World.currentMarker.setDeselected(World.currentMarker);
});
},

// screen was clicked but no geo-object was hit
onScreenClick: function onScreenClickFn() {
// you may handle clicks on empty AR space too
},

// returns distance in meters of placemark with maxdistance * 1.1
getMaxDistance: function getMaxDistanceFn() {

// sort palces by distance so the first entry is the one with the maximum distance
World.markerList.sort(World.sortByDistanceSortingDescending);

// use distanceToUser to get max-distance
var maxDistanceMeters = World.markerList.distanceToUser;

// return maximum distance times some factor >1.0 so ther is some room left and small movements of user don't cause places far away to disappear
return maxDistanceMeters * 1.1;
},

// udpates values show in "range panel"
updateRangeValues: function updateRangeValuesFn() {

// get current slider value (0..100);
var slider_value = $("#panel-distance-range").val();

// max range relative to the maximum distance of all visible places
var maxRangeMeters = Math.round(World.getMaxDistance() * (slider_value / 100));

// range in meters including metric m/km
var maxRangeValue = (maxRangeMeters > 999) ? ((maxRangeMeters / 1000).toFixed(2) + " km") : (Math.round(maxRangeMeters) + " m");

// number of places within max-range
var placesInRange = World.getNumberOfVisiblePlacesInRange(maxRangeMeters);

// update UI labels accordingly
$("#panel-distance-value").html(maxRangeValue);
$("#panel-distance-places").html((placesInRange != 1) ? (placesInRange + " Places") : (placesInRange + " Place"));

// update culling distance, so only palces within given range are rendered
AR.context.scene.cullingDistance = Math.max(maxRangeMeters, 1);

// update radar's maxDistance so radius of radar is updated too
PoiRadar.setMaxDistance(Math.max(maxRangeMeters, 1));
},

// returns number of places with same or lower distance than given range
getNumberOfVisiblePlacesInRange: function getNumberOfVisiblePlacesInRangeFn(maxRangeMeters) {

// sort markers by distance
World.markerList.sort(World.sortByDistanceSorting);

// loop through list and stop once a placemark is out of range ( -> very basic implementation )
for (var i = 0; i < World.markerList.length; i++) {
if (World.markerList.distanceToUser > maxRangeMeters) {
return i;
}
};

// in case no placemark is out of range -> all are visible
return World.markerList.length;
},

handlePanelMovements: function handlePanelMovementsFn() {

$("#panel-distance").on("panelclose", function(event, ui) {
$("#radarContainer").addClass("radarContainer_left");
$("#radarContainer").removeClass("radarContainer_right");
PoiRadar.updatePosition();
});

$("#panel-distance").on("panelopen", function(event, ui) {
$("#radarContainer").removeClass("radarContainer_left");
$("#radarContainer").addClass("radarContainer_right");
PoiRadar.updatePosition();
});
},

// display range slider
showRange: function showRangeFn() {
if (World.markerList.length > 0) {

// update labels on every range movement
$('#panel-distance-range').change(function() {
World.updateRangeValues();
});

World.updateRangeValues();
World.handlePanelMovements();

// open panel
$("#panel-distance").trigger("updatelayout");
$("#panel-distance").panel("open", 1234);
} else {

// no places are visible, because the are not loaded yet
World.updateStatusMessage('No places available yet', true);
}
},

// request POI data
requestDataFromServer: function requestDataFromServerFn(lat, lon) {

//alert('lat = ' + lat);
//alert('lon = ' + lon);

// set helper var to avoid requesting places while loading
World.isRequestingData = true;
World.updateStatusMessage('Requesting places from web-service');
World.loadPoisFromJsonData(localData);
World.isRequestingData = false;
// server-url to JSON content provider
/*var serverUrl = ServerInformation.POIDATA_SERVER + "?" + ServerInformation.POIDATA_SERVER_ARG_LAT + "=" + lat + "&" + ServerInformation.POIDATA_SERVER_ARG_LON + "=" + lon + "&" + ServerInformation.POIDATA_SERVER_ARG_NR_POIS + "=20";

var jqxhr = $.getJSON(serverUrl, function(data) {
World.loadPoisFromJsonData(data);
})
.error(function(err) {
World.updateStatusMessage("Invalid web-service response.", true);
World.isRequestingData = false;
})
.complete(function() {
World.isRequestingData = false;
});*/
},

// helper to sort places by distance
sortByDistanceSorting: function(a, b) {
return a.distanceToUser - b.distanceToUser;
},

// helper to sort places by distance, descending
sortByDistanceSortingDescending: function(a, b) {
return b.distanceToUser - a.distanceToUser;
}

};


/* forward locationChanges to custom function */
AR.context.onLocationChanged = World.locationChanged;

/* forward clicks in empty area to World */
AR.context.onScreenClick = World.onScreenClick;

var localData = ;

 

I will upload the complete project in sometime.

Hi there!

Using Google's LocationService is definitely a good idea. It is way more accurate than what one could achieve in writing a LocationProvider manually.

Please note that the AR-View uses whatever you pass in its setLocation method as lat/lon/alt values.
Even the SDK Sample app does nothing but using params it gets from the "primitive LocationProvider.java implementation".

Assuming you get proper lat/lon values using the LocationProvider, you can just pass them to the architectView.
OnLocationChanged event will then be fire in JS so you can double check. 

Please debug in JS and Android code to understand why the POIs are not located where you expect them to be.
My assumption is that your location is accurate but updated quite frequently, so that the new POI is created slightly next to the current user location.

Also note that the altitude is a crucial thing. I'd rather recommend using an unknown altitude value when setting it in Android code than setting an inaccurate altitude which may then cause creation of POIs off in altitude.

Hope this helps
Login or Signup to post a comment