I am currently looking into (existing) solution for iOS under Xamarin. I have a map with following code:
public override async Task<string> ResolveLatLngToAddress(double lat, double lng, MapAddressFormat addressFormat)
{
var geocoder = new CLGeocoder();
try
{
var placemarks = await geocoder.ReverseGeocodeLocationAsync(new CLLocation(lat, lng));
if (placemarks.Length > 0)
{
var placemark = placemarks[0];
switch (addressFormat)
{
case MapAddressFormat.AddressFormatFull:
{
return FormatUtils.Join(true, placemark.Name, placemark.Locality, placemark.SubLocality);
}
case MapAddressFormat.AddressFormatNoNumber:
{
return FormatUtils.Join(true, placemark.Thoroughfare, placemark.Locality, placemark.SubLocality);
}
}
}
}
catch (Foundation.NSErrorException e)
{
// Unable to find a location with the supplied latitude and longitude
}
return null;
}
}
The code works really well when user moves the pin around, there is a textbox control that displays currently selected address. Once the user starts zooming in and out however, the application breaks and the function stops working.
I have done some research and I understand that CLGeocoder class works in a way that if the users starts too many requests, the response slows down and then stops completely (https://developer.apple.com/documentation/corelocation/clgeocoder).
I can see that the problem is that the event is triggered multiple times during the zoom, e.g. zooming in triggers for example 20 requests for location resolution.
I would to trigger the location resolution only after the user finished zooming, is it possible to achieve somehow, for example with delayed binding?
Please note that I am new to both iOS development and Xamarin.
Thank you very much for any help.
thank you for your comments. I have eventually solved it by caching previously queried location and re-querying only if the lat/lng coordinates changed by certain margin which I estimated to be 1 meter (perfectly fine for my purposes).
private double _cached_lat = 999;
private double _cached_lng = 9999;
private string _cached_location = "";
public override async Task<string> ResolveLatLngToAddress(double lat, double lng, MapAddressFormat addressFormat)
{
double latDif = System.Math.Abs(_cached_lat - lat);
double lngDif = System.Math.Abs(_cached_lng - lng);
//precission - around 1m
double geo_precission = 0.000005;
if (((System.Math.Abs (_cached_lat - lat) < geo_precission) && (System.Math.Abs (_cached_lng - lng) < geo_precission)) && (!string.IsNullOrEmpty(_cached_location)))
{
return _cached_location;
}
var geocoder = new CLGeocoder();
Related
Simple question need simple answer.
How can I track the residence time in a specific geofence.
When I add geofence with Trigger on Enter, will I automatic receive a trigger when I leave that geofence. Basically I need to remember the time when I enter a geofence and when I leave that geofence so I can subtract leave-enter time and have my duration time. But I believe its not that easy to do that. So any other idea or advise how to solve that problem efficient ?
Thanks
I found one solution for this problem. In order to determine the dwell time in a geofence i have to get the time when user trigger a geofence and then i use to calculate if user leave the geofence with this mathematical method
Handler handler = new Handler();
getCurrentLatLng();
final Runnable myRunnable = new Runnable() {
public void run() {
GeofenceFinished myFinishedGeofence = db.getGeofenceFinishedByID("Finished" + id);
if (!isUserInRegion(latitude, longitude, myLatLng.latitude, myLatLng.longitude, rd)
|| myFinishedGeofence == null) {
String time = convertTime(endTime - startTime);
// get the finishedGeofence and set the duration of stay time
if (myFinishedGeofence != null)
setDurationOfStay("Finished" + id, time, getCurrentTime(System.currentTimeMillis()));
Toast.makeText(mContext, "Finish to determine duration of stay of " + myFinishedGeofence.getAddress(), Toast.LENGTH_SHORT).show();
handler.removeCallbacks(this);
} else {
getCurrentLatLng();
endTime += Constants.DELAY;
handler.postDelayed(this, Constants.DELAY);
}
}
private void setDurationOfStay(String geofenceid, String time, String endTime) {
if (db == null) db = GeofenceDatabaseHelper.getInstance(mContext);
if (!db.setDurationOfFinishedGeofence(geofenceid, time, endTime)) {
Log.i("setDurationOfStay", "fail");
}
}
};
handler.postDelayed(myRunnable, Constants.DELAY);
private boolean isUserInRegion(double firstLat, double firstLog, double curLat, double curLog, float radius) {
double distance = calculateDistance(firstLat, firstLog, curLat, curLog);
return distance <= radius;
}
To calculate the distance of user and center of geofence, i need to convert the current latitude and longitude in meter, so i can calculate that with the parametic equation for circle
So I use this approach from github
// https://github.com/mgavaghan/geodesy
private double calculateDistance(double firstLat, double firstLog, double curLat, double curLog) {
GeodeticCalculator geoCalc = new GeodeticCalculator();
Ellipsoid reference = Ellipsoid.WGS84;
GlobalPosition pointA = new GlobalPosition(firstLat, firstLog, 0.0); // Point A
GlobalPosition userPos = new GlobalPosition(curLat, curLog, 0.0); // Point B
// Distance between Point A and Point B
double distance = geoCalc.calculateGeodeticCurve(reference, userPos, pointA).getEllipsoidalDistance();
return distance;
}
hope it helps someone :D
How to get the most accurate geo-location on an android device, I tried following code snippet But on Nexus 4 and 10, it doesn't work even after the gps is turned on :
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
String locationProvider = locationManager.getBestProvider(new Criteria(), true);
if (locationProvider != null) {
//Log.d(TAG, "locationProvider is not null");
Location lastKnownLocation = locationManager.getLastKnownLocation(locationProvider);
if (lastKnownLocation != null) {
AppConstants.lat = latLon[0] = lastKnownLocation.getLatitude();
AppConstants.lon = latLon[1] = lastKnownLocation.getLongitude();
retryGenerating = false;
//Log.d(TAG, "lastKnownLocation, lat = " + AppConstants.lat + ", lon = " + AppConstants.lon);
}
}
The most accurate location you get by explicitly setting the LocationProvider to GPS Provider. Expect usually 3-6m accuracy, up to 30m in urban canyons.
You need to to be outside and have free view to sky.
Expect a delay of 20-40 s for the first valid location after going outside.
As a part of my final year project in university I'm analysing Twitter data using graph entropy. To briefly outline the purposes:
I want to collect all tweet from a certain area (London) containing keywords "cold", "flu" etc. This part is done using Streaming API.
Then I want to access each of the user's (who tweeted about being ill, collected in previous section) list of followers and following to be able to build a graph for further analysis. And here I'm stuck.
I assume for the second part I should be using Search API, but I keep getting error 88 even for a single user.
Below is the code I use for the first part:
final TwitterStream twitterStream = new TwitterStreamFactory(cb.build())
.getInstance();
StatusListener listener = new StatusListener() {
public void onStatus(Status status) {
User user = status.getUser();
long userid = user.getId();
String username = status.getUser().getScreenName();
String content = status.getText();
GeoLocation geolocation = status.getGeoLocation();
Date date = status.getCreatedAt();
if (filterText(content)) {
System.out.println(username+"\t"+userid);
System.out.println(content);
System.out.println(geolocation);
System.out.println(date);
try {
getConnections(userid);
} catch (TwitterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//OTHER LISTENER METHODS
};
twitterStream.addListener(listener);
// London
double lat3 = 51.23;
double lat4 = 51.72;
double lon3 = -0.56;
double lon4 = 0.25;
double[][] bb = { { lon3, lat3 }, { lon4, lat4 } };
FilterQuery fq = new FilterQuery();
fq.locations(bb);
twitterStream.filter(fq);
private static boolean filterText(String tweet) {
return tweet.contains("flu")
|| tweet.contains("cold")
|| tweet.contains("cough")
|| tweet.contains("virus");
}
And this is what I'm trying to complete the second part with:
private static void getConnections(long id) throws TwitterException {
Twitter twitter = new TwitterFactory().getInstance();
long lCursor = -1;
IDs friendsIDs = twitter.getFriendsIDs(id, lCursor);
System.out.println(twitter.showUser(id).getName());
System.out.println("==========================");
do
{
for (long i : friendsIDs.getIDs())
{
System.out.println("follower ID #" + i);
System.out.println(twitter.showUser(i).getName());
}
}while(friendsIDs.hasNext());
}
Any suggestions?
When you receive error 88, that's Twitter telling you that you're being rate limited:
The request limit for this resource has been reached for the current rate limit window.
The search call is limited to either 180 or 450 calls in a 15 minute period. You can see the rate limits here and this documentation explains the rate limiting in detail.
As for how to get around it, you may have to throttle your search calls to the API. Twitter4J provides ways to inspect current limits/exhaustion which may help - see Twitter#getRateLimitStatus().
Can anyone please inform me how to work with blackberry location-based services?
i am working on a project for a blackberry mobile application. i never had a blackberry before and i dont have a contract with any provider (just have a sim card from 3 and mobile device 9000 OS 4.6).
In the project i am currently trying to use the following code in order to retrieve the coordinates of current location (startpoint) and destination location (endpoint). It works just fine on the simulator but on the device nothing. Should i have a contract with a provider or something? and does this need just GPS or internet, or both to work?
Code:
String destination = "London";
final Landmark[] landmarks = Locator.geocode(destination.replace('\n', ' '), null);
Coordinates endPoint = landmarks[0].getQualifiedCoordinates();
// Get a location provider.
LocationProvider provider = LocationProvider.getInstance(null);
if (provider == null)
{
throw new IllegalStateException("No LocationProvider Available!!");
}
// Try to fetch the current location and get the coordinates of the current location.
Coordinates startPoint = provider.getLocation(-1).getQualifiedCoordinates();
double destiinationlatitude = endPoint.getLatitude();
double currentlatitude = startPoint.getLatitude();
thank you in advance
To get the GPS location on any version prior to 5.0 you have to instantiate this things
Criteria
Location Provider
Location Object (done with the location provider)
Here's the things you instantiate:
Criteria criteria = null;
LocationProvider provider = null;
javax.microedition.location.Location location = null;
After that you must assign values to the Criteria, get the instance of the LocationProvider using the criteria and get the Location using the LocationProvider.
criteria = new Criteria();
criteria.setPreferredPowerConsumption(Criteria.POWER_USAGE_HIGH);
criteria.setHorizontalAccuracy(50);
criteria.setVerticalAccuracy(50);
criteria.setCostAllowed(true);
provider = LocationProvider.getInstance(criteria);
location = provider.getLocation(5);
Note that the Criteria will determine if you use GPS, Wifi assisted location or Cellsite location, more info on the criteria setting here: http://www.blackberry.com/developers/docs/4.5.0api/javax/microedition/location/Criteria.html
After that, to get the coordinates you call the method: location.getQualifiedCoordinates()
And that's that... you should call this from a separate thread. And also the actual location management code should be on a try-catch block but the IDE will help you with that.
in this code we are seeing which modes are available to get co-ordinates(I.E if phone does not have a GPS then it should use satalite info.)
The Lat and Long is being retreived by the available mode.
A mapview is created (MapView which is the map, You set the required specifications such as the zooming, lat, lon, etc )then you invoke the map and the set zoom, lat, lon , etc will be applied to the map that reflects onto the screen.
CustomMapField mMapField;
Coordinates mCoordinates;
BlackBerryCriteria blackBerryCriteria = null;
BlackBerryLocation blackBerryLocation = null;
BlackBerryLocationProvider blackBerryLocationProvider = null;
double Doublelat = 0.0;
double Doublelng = 0.0;
blackBerryCriteria = new BlackBerryCriteria();
if(GPSInfo.isGPSModeAvailable(GPSInfo.GPS_MODE_CELLSITE)){
blackBerryCriteria.setMode(GPSInfo.GPS_MODE_CELLSITE);
}else if(GPSInfo.isGPSModeAvailable(GPSInfo.GPS_MODE_ASSIST)){
blackBerryCriteria.setMode(GPSInfo.GPS_MODE_ASSIST);
}else if(GPSInfo.isGPSModeAvailable(GPSInfo.GPS_MODE_AUTONOMOUS)){
blackBerryCriteria.setMode(GPSInfo.GPS_MODE_AUTONOMOUS);
}else{
blackBerryCriteria.setCostAllowed(true);
blackBerryCriteria.setPreferredPowerConsumption(Criteria.POWER_USAGE_LOW);
} try {
blackBerryLocationProvider = (BlackBerryLocationProvider) BlackBerryLocationProvider.getInstance(blackBerryCriteria);
blackBerryLocation = (BlackBerryLocation) blackBerryLocationProvider.getLocation(60);
QualifiedCoordinates qualifiedCoordinates = blackBerryLocation.getQualifiedCoordinates();
Doublelat = qualifiedCoordinates.getLatitude();
Doublelng = qualifiedCoordinates.getLongitude();
mCoordinates = new Coordinates(Doublelat, Doublelng, 0);
MapView mapView = new MapView();
mapView.setLatitude(finalintlat);
mapView.setLongitude(finalintlng);
mapView.setZoom(10);
MapsArguments mapsArgs = new MapsArguments(mapView);
Invoke.invokeApplication(Invoke.APP_TYPE_MAPS, mapsArgs);
}catch(Exception e){
System.out.println("Error in location :"+e.toString());
System.out.println("Error in location :"+e.getMessage());
}
I have code that is used to show a device's location. It works just fine on the emulator and it takes me to the fake location at Microsoft. But it didn't work when I build it into the phone, it showed me the world map. Is this a known bug or I have done something wrong? Here is my code:
private GeoCoordinateWatcher loc = null;
private void button1_Click(object sender, RoutedEventArgs e)
{
if (loc == null)
{
loc = new GeoCoordinateWatcher(GeoPositionAccuracy.Default);
loc.StatusChanged += loc_StatusChanged;
}
if (loc.Status == GeoPositionStatus.Disabled)
{
loc.StatusChanged -= loc_StatusChanged;
MessageBox.Show("Location services must be enabled on your phone.");
return;
}
loc.Start();
}
void loc_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e)
{
if (e.Status == GeoPositionStatus.Ready)
{
Pushpin p = new Pushpin();
p.Template = this.Resources["pinMyLoc"] as ControlTemplate;
p.Location = loc.Position.Location;
mapControl.Items.Add(p);
map1.SetView(loc.Position.Location, 17.0);
loc.Stop();
}
}
}
Instead of using the StatusChanged event, you should use the GeoCoordinateWatcher.PositionChanged event, in from which you should use the GeoPositionChangedEventArgs.Position property, to reflect the changed location.
This is due to my location doesn't support by Bing Map. I couldn't use the Bing Map app installed in my phone neither. Hmm...