Calculating exact distance in iPhone - iphone

I am trying to calculate distance from start using Core Location framework, but when i put the Application on an iPhone device, the data is not correct. Distance keeps on fluctuating and showing random data. Kindly help me out. Also, Altitude is showing zero.
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
//Altitude
if(startingPoint==nil)
self.startingPoint=newLocation;
NSString *currentAltitude = [[NSString alloc] initWithFormat:#"%g",
newLocation.altitude];
heightMesurement.text=currentAltitude;
[currentAltitude release];
//Distance
if(startingPoint==nil)
self.startingPoint=newLocation;
//if(newLocation.horizontalAccuracy <= 100.0f) {
// [locationManager stopUpdatingLocation];
//}
//test start.......................................................
//startlocation
NSString *sp = [[NSString alloc]
initWithFormat:#"%f",startingPoint];
NSLog(#"\nStarting point=%#",startingPoint);
ssp.text=sp;
//endlocation
NSString *ep = [[NSString alloc]
initWithFormat:#"%f",newLocation];
NSLog(#"\nStarting point=%#",newLocation);
eep.text=ep;
//test end............................................................
CLLocationDistance mydistance=[newLocation distanceFromLocation:startingPoint];
NSString *tripString = [[NSString alloc]
initWithFormat:#"%f",mydistance];
distLabel.text=tripString;
[tripString release];
//test........................
[sp release];
[ep release];
}//Location Manager ends..
//Time interval of 3 sec....
-(void)locationUpdate:(NSTimer*)timer{
if(timer != nil) [timer invalidate];
[self.locationManager startUpdatingLocation];
}

As to why your altitude may be zero, please see this answer to a similar question.
This may just be a problem with your NSLog statements, but both the starting and ending points are printed out with NSLog statements that say
NSLog(#"\nStarting point=%#",
The way you seem to have scheduled a 3-second timer is not really the way iOS wants you to use CLLocationManager. The preferred way is to tell CLLocationManager what your location criterion are, and then just start it updating. You don't actually need to keep telling it to start updating every 3 seconds. You can just do it once, and then if you ever decide you don't need any more updates, then call
[locationManager stopUpdatingLocation];
If the OS has no new location information, it probably doesn't make sense to keep asking. It'll tell you when it has new location information, via locationManager:didUpdateToLocation:fromLocation. So, I would recommend starting the process more like this:
CLLocationManager* locationManager = [[CLLocationManager alloc] init];
if ([locationManager locationServicesEnabled]) {
Reachability* netStatus = [Reachability sharedReachability];
if (([netStatus internetConnectionStatus] != NotReachable) || ([netStatus localWiFiConnectionStatus] != NotReachable)) {
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
locationManager.distanceFilter = 100.0; // 100 m, or whatever you want
[locationManager startUpdatingLocation];
} else {
// TODO: error handling
}
}
self.locMgr = locationManager;
[locationManager release];
The location manager will often deliver you multiple results, with increasing accuracy as it hones in on your location. If you're continually restarting it, I'm wondering if that's causing it problems.

Related

Posting current location to rails from iPhone

I am building a rails-backed iphone app that uses AFNetworking to create posts at specific locations. So the post model has lat/lng parameters that should be filled in with the client's current location.
At this point, the posts can be made, but the lat/lng comes up as null.
In my (save:) method I pass a conditional to see if a location was found- this is what is failing i.e. "No Location" is logged.
- (void)save:(id)sender {
[self getLocation];
NSArray *locations;
CLLocation *location = [locations objectAtIndex:0];
Post *post = [[Post alloc] init];
post.content = self.contentTextView.text;
post.photoData = UIImagePNGRepresentation(self.imageView.image);
[self.view endEditing:YES];
ProgressView *progressView = [ProgressView presentInWindow:self.view.window];
if (location) {
[post savePostAtLocation:location withBlock:^(CGFloat progress) {
[progressView setProgress:progress];
} completion:^(BOOL success, NSError *error) {
[progressView dismiss];
if (success) {
[self.navigationController popViewControllerAnimated:YES];
} else {
NSLog(#"ERROR: %#", error);
}
}];
} else {
NSLog(#"No Location");
}
}
I have also attempted to implement a locationManager like so
-(void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
[self getLocation];
}
-(CLLocation *) getLocation{
CLLocationManager * locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
self.locationManager.distanceFilter = 80.0f;
[locationManager startUpdatingLocation];
CLLocation * location = [locationManager location];
return location;
}
I think ideally I would implement the savePostAtlocation in the CLLocationManagerDelegate where I could pass in the locations array like this:
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations
{
CLLocation *location = [locations objectAtIndex:0 /* firstObject */];
if (location) {
[Post createPostAtLocation:location...
But I want to have the post created onSave so I am trying to identify the location but running into some problems..
How do I properly get the current location and pass it into the dictionary?
Any advice on this would be greatly appreciated. Thanks!
Looking at your code, I think you have a slight misunderstanding about how CLLocationManager is designed to work. It looks like you are trying to call [self getLocation] from inside locationManager:didUpdateLocations. This is not correct. Try something like this, inside your save method that is called when you press your button (I would remove the code that's currently in there while testing):
CLLocationManager * locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
self.locationManager.distanceFilter = 80.0f;
[locationManager startUpdatingLocation];
Then it will start generating location data. When that happens, the phone will automatically call locationManager:didUpdateLocations very rapidly. Then, in locationManager:didUpdateLocations you could use:
CLLocation * location = [manager location];
NSLog(#"%#", location);
To see your location data in the console.
What I have written here should get the phone generating location data for you. What you say about createPostAtLocation: in locationManager:didUpdateLocations is probably the correct way to go. When you get the location data, call [manager stopUpdatingLocation] to make the phone stop, then post the location data you got back to your server.

Sending location to server with CLLocationManager when iphone is in background

i'm having trouble sending my position when the application lies in the background. I'm using CLLocationManager and startMonitoringSignificantLocationChanges. The posision didUpdateToLocation delegate method is performed once, but not more. I've tried to walk around but no new locations is sent to the server.
I have set the "Required background modes" -> "App registers for location updates" in the info.plist file.
Anyone got an idea on what might be wrong?
Code from where the tracking is started:
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = appDelegate;
[appDelegate setLocationManager:locationManager withDistanceFilter:kCLDistanceFilterNone];
[appDelegate.theLocationManager startMonitoringSignificantLocationChanges];
Code (from CLLocationManagerDelegate):
- (void)setLocationManager:(CLLocationManager*)locationManager withDistanceFilter:(CLLocationDistance)distanceFilter {
// create a new manager and start checking for sig changes
self.theLocationManager.delegate = nil;
[theLocationManager release];
self.theLocationManager = locationManager;
self.theLocationManager.delegate = self;
self.theLocationManager.distanceFilter = distanceFilter;
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
NSDate *newLocationTimestamp = newLocation.timestamp;
NSDate *oldLocationTimestamp = oldLocation.timestamp;
int locationUpdateInterval = 15;//15 sec
if (!([newLocationTimestamp timeIntervalSinceDate:oldLocationTimestamp] < locationUpdateInterval)) {
//NSLog(#"New Location: %#", newLocation);
[self updateToLocation:newLocation];
}
}
- (void)updateToLocation:(CLLocation *)newLocation {
NSLog(#"update location!!");
NSString *latitude = [NSString stringWithFormat:#"%f", [newLocation coordinate].latitude];
NSString *longitude = [NSString stringWithFormat:#"%f", [newLocation coordinate].longitude];
[currentUser updatePositionWithLongitude:longitude andLatitude:latitude];
}
Like Bill Brasky said, the accuracy to which you have set your location manager is likely not registering the distance that you have walked. Try setting your location manager accuracy much higher, just to see if works, then dial it back down to a happy medium between accuracy and battery efficiency. Just for testing, take it all the way up:
[appDelegate.theLocationManager setDesiredAccuracy:kCLLocationAccuracyBestForNavigation];
Then instead of:
[appDelegate.theLocationManager startMonitoringSignificantLocationChanges];
try:
[appDelegate.theLocationManager startUpdatingLocation];
The -startMonitoringForSignificantLocationChanges is directly tied to cell tower connectivity. You may need to travel miles to get connection to a new tower and trigger a location change event. I know that the region monitoring is a bit more accurate as it uses updates of location from Wifi, cell tower, and even other apps that inquire on location. You will need to figure out how accurate and how often you need your app to be. You may need to actively monitor location in the background (which would be a battery killer for sure). Hope this helps.

CLLocationManagerDelegate, when will the method be invoke: locationManager:didUpdateToLocation:fromLocation:

in CLLocationManagerDelegate, when will the method be invoke: locationManager:didUpdateToLocation:fromLocation:
could you explain more detail, if possible could you explain with example? thanks very much
if my current location is changing(eg, I am on a train), does this method be invoked? if yes, how many times or how frequently it is be invoked?
if I stay at one place and not move, does this method be invoked? if yes, how many times or how frequently it is be invoked?
This method is called whenever your iOS device has moved past the distance filter you have set. For example if you set it to
[self.locationManager setDistanceFilter:kCLDistanceFilterNone];
The method will be called every time the device is moved.
A code example of this would be finding the coordinates then assigning those values to labels
- (void)viewDidLoad{
[super viewDidLoad];
altitudeLabel.text = #"0 ft";
ftOrM = YES;
// Note: we are using Core Location directly to get the user location updates.
// We could normally use MKMapView's user location update delegation but this does not work in
// the background. Plus we want "kCLLocationAccuracyBestForNavigation" which gives us a better accuracy.
//
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
self.locationManager.delegate = self; // Tells the location manager to send updates to this object
[self.locationManager setDesiredAccuracy:kCLLocationAccuracyBestForNavigation];
[self.locationManager setDistanceFilter:kCLDistanceFilterNone];
[self.locationManager startUpdatingLocation];
}
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation: (CLLocation*)newLocation fromLocation:(CLLocation *)oldLocation {
tLatitude = [NSString stringWithFormat:#"%3.5f", newLocation.coordinate.latitude];
tLongitude = [NSString stringWithFormat:#"%3.5f", newLocation.coordinate.longitude];
/* the following returns 0 */
float distanceMeters;
float distanceFeet;
if (ftOrM == YES) {
distanceMeters = newLocation.altitude;
distanceFeet = distanceMeters * 3.2808399;
tAltitude = [NSString stringWithFormat:#"%.02f ft", distanceFeet];
altitudeLabel.text = tAltitude;
}
else {
tAltitude = [NSString stringWithFormat:#"%.02f m", newLocation.altitude];
NSLog(#"Altitude:");
NSLog(#"%#", tAltitude);
altitudeLabel.text = tAltitude;
NSLog(#"Altitude:");
NSLog(#"%#", tAltitude);
}
//[manager stopUpdatingLocation];
}
For the first one this method will invoked, and the frequency depends on the speed.
And if don't change your location then this method will not invoked.
And how much time your location is changing this method will call.

CLLocation manager keep getting same latitude and longitude when clicking button?

This is my first question in this site.
I have this serious problem.... I'll explain this from the beginning…
in my app i need to get the current location of the user when the user click on the button in the application.. but the problem is when is click on the button its not updating to the current location its getting the previous location. But when i reset the location warnings in the iphone app its get the correct location.
Here is the code steps i did for this application to get the current location of the user...
First I import to the application ...
then i am using global files to keep data of the application because i need to access them through the application.
so what I did in the globle.m and .h file is ...
CLLocationManager* locationManager;
#synthesize locationManager
+ (Globals*)sharedGlobals {
#synchronized(self) {
if(_sharedGlobals == nil) {
_sharedGlobals = [[super allocWithZone:NULL] init];
_sharedGlobals.locationManager = [[CLLocationManager alloc]init];
[_sharedGlobals.locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
}
}
return _sharedGlobals;
}
Then in my other view controller I put the CLLocationManagerDelegate and in the .m file
-(IBAction) didTapSearchbtn{
if (![CLLocationManager locationServicesEnabled]) {
}else {
[[Globals sharedGlobals].geoLocations removeAllObjects];
search.text = nil;
[Globals sharedGlobals].fromTextField = NO;
[[Globals sharedGlobals].locationManager setDelegate:self];
[[Globals sharedGlobals].locationManager startUpdatingLocation];
}
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
if (newLocation.horizontalAccuracy < 0) return;
[[Globals sharedGlobals].locationManager setDelegate:nil];
[[Globals sharedGlobals].locationManager stopUpdatingLocation];
[[Globals sharedGlobals].geoLocations setObject:[[NSString alloc] initWithFormat:#"%f", newLocation.coordinate.latitude] forKey:#"geolat"];
[[Globals sharedGlobals].geoLocations setObject:[[NSString alloc] initWithFormat:#"%f", newLocation.coordinate.longitude] forKey:#"geolong"];
[self retriveDataFromInternet];
[[Globals sharedGlobals].locationManager release];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
//GPS error
[[Globals sharedGlobals].locationManager setDelegate:nil];
[[Globals sharedGlobals].locationManager stopUpdatingLocation];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"YumTable!", nil) message:NSLocalizedString(#"Enable Your GPS settings to get your current location", nil) delegate:nil cancelButtonTitle:NSLocalizedString(#"Ok", nil) otherButtonTitles:nil];
[alert show];
[alert release];
[[Globals sharedGlobals].locationManager release];
}
i put the label to my view controller and went different places to take latitudes and longitudes .. but always it getting same latitude and longitude ... but when I reset the location warnings and run the app again it took the correct latitude and longitude ... so if i need to take current location always i have to reset it. But what i need is to get current location every time when i click the search button...
Can any one can say whats wrong in this code and can any one help me ....
And Also very very sorry about my bad english ... :)
The LocationManager will return the previos location because it tries to be as fast as possible and it thinks that this location might be good enough. I usually check the timestamp on the new location to ensure that it is a fresh one. If it is to old I don't stop the manager and wait for the next one.
I would suggest that you look at the sample code provided by Apple, https://developer.apple.com/library/ios/#samplecode/LocateMe/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007801
This code is copied from the example:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
// test the age of the location measurement to determine if the measurement is cached
// in most cases you will not want to rely on cached measurements
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
if (locationAge > 5.0) return;
}
I missed Typed my code ... after I figur that out my application start to work perfectly ... Thank you guys for your great help..
[_sharedGlobals.locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
instead of that I used
[_sharedGlobals.locationManager setDesiredAccuracy:kCLLocationAccuracyBestforNavigation];

CLLoacationManager class returning cached data

How to remove cached data which is sent by CLLocationManager and how to increase its accuracy.Every time i launch the app it gives me cached data and updates it after some time.I have seen several threads but i am not able to get a concrete sol .can anybody provide me the code?
I am using the following method to get position data....
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
I have set the delegate and accuracy here.....
- (void)viewDidLoad {
[super viewDidLoad];
bestEffortAtLocation = nil;
latLocationArray = [[NSMutableArray alloc]init];
longLocationArray = [[NSMutableArray alloc]init];
locationManager =[[CLLocationManager alloc]init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
}
Also can i use CLLocationManager to compute the distance travelled by person?
There doesn't seem to be a way to dump the cached data. The docs recommend using the timestamp property of the CLLocation object to determine how recent the data is, which is what I do.
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
//wait until we get a recent location, no more than 2 minutes old
if([newLocation.timestamp timeIntervalSinceNow] <= (60 * 2)){
DLog(#"New location:\n\tLat: %f\n\tLon: %f", newLocation.coordinate.latitude, newLocation.coordinate.longitude)
//turn off location updates
[self.locManager stopUpdatingLocation];
DLog(#"Stopping Location Updates");
//Do stuff
}
}
In my testing I haven't had to wait more than a second or two before I get new data.
On your second point, you could have a variable that you add to whenever you get a location update. The distance between updates can be pretty easy to get using CLLocation's distanceFromLocation: method.
Instead of set the distanceFilter to kCLDistanceFilterNone
i.e. locationManager.distanceFilter = kCLDistanceFilterNone;
You may give some value to distanceFilter and check
For e.g. locationManager.distanceFilter =0.5f;
And to calculate distance travel you have to implement the didUpdateToLocation: fromLocation:
where you have to find the new latitude and longitude
Finally
CLLocationObject = newLocation;
CLLocationDistance yourdistance = [newLocation getDistanceFrom:CLLocationObject];
NSString *distance = [[NSString alloc]
initWithFormat:#"%gm", yourdistance ];
NSLog(#"you have travel=%#",distance);