CLLocation speed - iphone

I am developing GPS application.
Do you know about how to detect speed of mobile device ?
Actually, I need to detect the speed every 2 seconds.
I know didUpdateToLocation method is called when location changed.
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
But I think this method is not suitable for my issue.
So, Do I need to check speed of [CLLocationManager location] in 2 seconds ?
Any suggestion ?
Thanks in advance.

How about the code below which works from the delegate method.
Alternatively, if you did want to poll, then keep your previous location and check the distance changed from the last poll and use the manual method (also shown below) to calculate the speed.
Speed is calculated/provided in m/s so multiply by 3.6 for kmph or 2.23693629 for mph.
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
//simply get the speed provided by the phone from newLocation
double gpsSpeed = newLocation.speed;
// alternative manual method
if(oldLocation != nil)
{
CLLocationDistance distanceChange = [newLocation getDistanceFrom:oldLocation];
NSTimeInterval sinceLastUpdate = [newLocation.timestamp timeIntervalSinceDate:oldLocation.timestamp];
double calculatedSpeed = distanceChange / sinceLastUpdate;
}
}

You can only really use the delegate method you have suggested in your question.
Even if you access the [CLLocationManager location] every 2 seconds, you will only receive the coordinate you last received in the delegate method above.
Why the need to poll every two seconds? The iphone can update it's coordinates in less time on some cases.
HTH

Related

Compare GPS points to the current location

I am using the instance method distanceFromLocation in order to compare my new location with const defined locations
I am giving CLLocation *bonuslocation an instant value which is one of the gps points i am interested in and then i compare it to the new location
if the distance is less than 20m from the point an audio file is played.
While this is working perfectly for one location it does not work at all
if i add locally into the updatelocationmanager function more than one..
The code:
CLLocation *bonuslocation = [.....]
CLLocationDistance distancea = [bonuslocation distanceFromLocation newlocation]
if (distancea <= 20)
{
//play an audio
}
Can i have some advice on how to do it for 10 gps points????
Today is my Birthday can you see that as a birthday present??
Thank you..
Why not just put it in a loop? Or just run the comparison on 10 locations? What exactly is it that isn't working?
EDIT:
You never mentioned where you're getting your other locations, so let's assume you make them somehow and store them in an array...
NSArray *locationArray;
I gathered from your comment that you have different sounds for each location? A simple way would be to store the sounds in a second array...
NSArray *soundsArray;
Then you can do the following in your locationManager:didUpdateToLocation:fromLocation:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
for(int i=0; i<[locationArray count]; i++){
CLLocation *location = (CLLocation *)[locationArray objectAtIndex:i];
if([newLocation distanceFromLocation:location] < 20.0){
//perform some action e.g.
//play sound at [soundArray objectAtIndex:i]
}
}
}
Although I don't recommend simply playing a sound, as this simple logic will cause the sound to be played once for every location within the threshold all at the same time.

I can't get the gps coordinates for a persistent period of time

I have implemented the standard method of retrieving the coordinates from the gps using - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation.
The problem is that this function is called only on initialization and not throughout the life of the program. Is this normal?
In android you would implement a listener and you would get data instantly.
Is this not the wright way how i'm doing it? If it is, what could be the problem? (btw i've checked, i don't stopUpdatingLocation)
I have a CLLocationManager inherited class named testing and initialize it
testing* cllm = [[testing alloc] init];
cllm.delegate = self;
i later start the updating
[cllm startUpdatingLocation];
self.locationManagerDelegate = delegate;
and later is called
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
but after that it isn't called anymore. I need it to be called frequently so that i may calculate the distance to a certain point X from where i am.
Agreed with #Matt, without more code the best solution I can offer is this to tell it to update every time the device is moved with:
[self.locationManager setDistanceFiler:kCLDistanceFilterNone]
Update
I went through past projects and found the code I believe you are looking for assuming your location manager subclass is working properly
- (void)viewDidLoad {
[super viewDidLoad];
//Location
// create new location manager
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.distanceFilter = kCLDistanceFilterNone;
// start location manager
[self.locationManager startUpdatingLocation];
}
-(void) distanceBetweenUserandPin {
CLLocation *currentUserLocation = [[CLLocation alloc] initWithLatitude:_currentLocation.latitude longitude:_currentLocation.longitude];
CLLocation *currentPinLocation = [[CLLocation alloc] initWithLatitude:_pinLocation.latitude longitude:_pinLocation.longitude];
CLLocationDistance distanceBetweenUserAndPinMeters = [currentUserLocation distanceFromLocation:currentPinLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
//This successfully saves Lat, Long Data to a point location
CLLocationCoordinate2D location = CLLocationCoordinate2DMake(newLocation.coordinate.latitude, newLocation.coordinate.longitude);
NSLog(#"%f, %f", location.latitude, location.longitude);
//This assigns the value of location to the ivar _currentLocation
_currentLocation = CLLocationCoordinate2DMake(location.latitude, location.longitude);
NSLog(#"%f, %f", _currentLocation.latitude, _currentLocation.longitude);
}
First, it seems strange to me that you would use a subclass of CLLocationManager, since I'm not sure what benefit that provides you. Assuming that's not the problem, however...
From the CLLocationManager documentation:
This method returns immediately. Calling this method causes the
location manager to obtain an initial location fix (which may take
several seconds) and notify your delegate by calling its
locationManager:didUpdateToLocation:fromLocation: method. After that,
the receiver generates update events primarily when the value in the
distanceFilter property is exceeded. Updates may be delivered in other
situations though. For example, the receiver may send another
notification if the hardware gathers a more accurate location reading.
What's happening is that it is being called once for the initial position fix, but it isn't calling again because other conditions haven't changed. If a user doesn't move anywhere, then new location data won't be provided since it will be the same as last time (with a few exceptions as mentioned in the docs).
When you're testing your app, make sure that you try moving around and changing your location to produce an update. If that doesn't work, try experimenting with the desiredAccuracy and distanceFilter properties:
You start standard location services by calling the
startUpdatingLocation method. This service is most appropriate for
applications that need more fine-grained control over the delivery of
location events. Specifically, it takes into account the values in the
desiredAccuracy and distanceFilter property to determine when to
deliver new events.
Other than that, I'd guess it might have to do with how you're subclassing CLLocationManager. Providing some of that code might help.

Setting up the MKReverseGeocoderDelegate?

I am a little confused about setting up the MKReverseGeocoderDelegate, I noted from Apples example that they are assigning the MKReverseGeocoder to a property iVar, in the end I decided to alloc the MKReverseGeocoder when a position is found and release the MKReverseGeocoders as they either report back success or failure, does this seem right?
// ------------------------------------------------------------------- **
// DELEGATE: CLLocationManager
// ------------------------------------------------------------------- **
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
MKReverseGeocoder *myGeocoder = [[MKReverseGeocoder alloc] initWithCoordinate:[newLocation coordinate]];
[myGeocoder setDelegate:self];
[myGeocoder start];
}
// ------------------------------------------------------------------- **
// DELEGATE: MKReverseGeocoderDelegate
// ------------------------------------------------------------------- **
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark {
NSLog(#"%#", [placemark locality]);
[geocoder release];
}
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error {
[geocoder release];
}
#end
You're fine in terms of memory management. If you run this through the leaks tool in Instruments, it'll probably complain about a possible leak in your locationManager:didUpdate method, but it's wrong about that, it just can't see where you're releasing the object.
I would do a couple things to decrease the impact on the geocoder, though. I'd look and see that the location you just didUpdate to has an accuracy that's worth talking about. When Core Location first comes to life, you're likely to get some garbage hits before the hardware's really up and receiving. And then the accuracy will narrow in on the real location (the Google Maps app shows pretty nicely what is happening there, the blue circle zeroing in on your real location). There's probably no point in geocoding until you've got an accuracy within 100 meters or so.
EDIT: Try this
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
if((newLocation.coordinate.latitude != oldLocation.coordinate.latitude) &&
(newLocation.coordinate.longitude != oldLocation.coordinate.longitude) &&
([newLocation horizontalAccuracy] < 100 && [newLocation horizontalAccuracy] > 0))
{
MKReverseGeocoder *myGeocoder = [[MKReverseGeocoder alloc] initWithCoordinate:[newLocation coordinate]];
[myGeocoder setDelegate:self];
[myGeocoder start];
}
}
That should ignore updates that are the same as the last update (which might be fairly frequent) and those that have invalid accuracy (you'll get negative numbers there occasionally, when the location hardware is first fired up) or are over 100 meters of horizontal accuracy.
Also, if you just want to do this once, go ahead and have your CLLocationManager stop updating once you get a valid and sufficiently accurate position.
In the MKReverseGeocoder Class Reference, Apple says that
Each Map Kit application has a limited amount of reverse geocoding capacity, so it is to your advantage to use reverse geocode requests sparingly. Here are some rules of thumb for using this class most effectively:
Send at most one reverse-geocoding request for any one user action.
(...)
In your case, If there is a slow network connection (i.e. position changes are faster then location lookups), multiple requests can be instantiated.
Your code will probably work fine in most cases, however it is not the suggested way to implement it. And implementing anything that only works "in most cases" is not a goot idea at all.

Small Location Change Detection

I'm need to detect small location change for the iphone , I tried the sample that's called Locate Me, but it doesn't recognize the small change in the location. Is there any way for doing this?
Thanks in Advance.
Best regards
John
How small is the change that you expected?
Maybe you should set the accuracy to it's maximum and calculate the displacement on the delegate method.
Configure the location manager to give you it's best.
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[locationManager setDistanceFilter:0.0];
And then on the delegate method:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
// Calculate the distance between the two locations
CGFloat distance = [newLocation distanceFromLocation:oldLocation];
if (distance >= MIN_DISPLACEMENT) {
// Do something
} else {
// Do something
}
}
To get more accurate data from the location manager, set the proper keys for UIRequiredDeviceCapabilities (location-services, gps) on the Info.plist.

CLLocation manager Gives me old position

i used CLLoction manager to get location.but when ever i start my location then it gives me oldlocation which is store in device previously.i want to reset the location for this i used flag on first launch of application i used newlocation and call stopupdateinglocation and startupdatinglocation method.But oldlocation is not changed it show old location.
Every CLLocation has a timestamp property that you can use to filter all location updates that are too old for your usage.
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSTimeInterval age = [newLocation.timestamp timeIntervalSinceNow];
if(age < SOME_CONSTANT_IN_SECONDS)
{
//Use location
}
}
You can't clear the old location, but you can check the horizontalAccuracy to know if this is a good location (current) or something old and irrelevant.