path tracing on map in ios - iphone

Some one help me out please I am stuck on it from last few days...
My task is here.
In my app i need to integrate the map, as it open it should shows the current user position, as i pressed start button while walking it starts tracing path from the position where i pressed start button till the position i pressed stop.the distance covered in this interval should be traced turn by turn navigation and also wann to collect start and stop position coordinates to calculate distance.
i have added map kit framework, core location frame work, also added map view,and also implemented method to show current user position . now
here is my code
-(void)startSignificantChangeUpdates
{
// Create the location manager if this object does not
// already have one.
if (nil == self.locatioManager)
{
self.locatioManager = [[CLLocationManager alloc] init];
self.locatioManager.delegate = self;
[self.locatioManager startMonitoringSignificantLocationChanges];
}
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
// If it's a relatively recent event, turn off updates to save power
CLLocation* location = [locations lastObject];
NSDate* eventDate = location.timestamp;
NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
if (abs(howRecent) < 15.0) {
// If the event is recent, do something with it.
NSLog(#"latitude %+.6f, longitude %+.6f\n",location.coordinate.latitude,location.coordinate.longitude);
}
MKCoordinateRegion ref=MKCoordinateRegionMakeWithDistance([location coordinate], 250,250);
[self.myMapView setRegion:ref animated:YES];
}
Please guide me from here to trace path, and can collect coordinates also .

Related

Re routing user in iphone navigation app

I am working on a navigation app that will give turn by turn navigation.
I am using google directions API to plot best route between points. Apart from source and destination user can add up to 8 waypoints. I have stored all the coordinates in an array and in didUpdateLocations method i am checking the distance between current location and coordinates stored in array. If the distance is less than 5 meters then the user is going in the right direction
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
CLLocation *myLocation = [locations lastObject];
BOOL goingWrongWay = YES;
//Searching Current Location in Coordinates Array
for(int i=0;i<self.decodedArray.count;i++)
{
CLLocation *tempLoc = [self.decodedArray objectAtIndex:i];
//NSLog(#"distance=%f", [myLocation distanceFromLocation:tempLoc]);
if([myLocation distanceFromLocation:tempLoc]<=5)
{
goingWrongWay = NO;
break;
}
}
if(goingWrongWay)
self.title = #"Wrong Way";
else
self.title = #"On Track";
NSLog(#"YES");
if(isShowingRoute)
{
NSLog(#"YES");
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:myLocation.coordinate.latitude
longitude:myLocation.coordinate.longitude
zoom:19.0];
[mapView animateToCameraPosition:camera];
}
}
Is there any other way to detect whether the user is going in the right direction or not as i have to Re-route user. BTW i am using google maps SDK for ios

didUpdateToLocation called multiple times

I have an application in which user track his/her route when jogging or cycling, So i need perfect location, so user's routes will be perfect.
But, I have one problem in this,
locManager = [[CLLocationManager alloc] init];
[locManager setDesiredAccuracy:kCLLocationAccuracyBestForNavigation];
[locManager setDelegate:self];
[locManager startUpdatingLocation];
In viewDidLoad. Using this didUpdateToLocation method called multiple times when I just dont move device a little and on map very strange route draw.
I just cant understand why this happen, if I am doing some wrong or missing something.
Thanks.......
I use locationManager.distanceFilter = 500; (or so) // meters
to prevent multiple calls from happening. just remember to call this BEFORE you start updating your location
You can set the distancefilter of the location manager hope this may help you
locationManager=[[CLLocationManager alloc] init];
locationManager.delegate=self;
locationManager.desiredAccuracy=kCLLocationAccuracyNearestTenMeters;
locationManager.distanceFilter=10.0;
[locationManager startUpdatingLocation];
When you first start location services, you'll generally see multiple location updates come whether you're moving or not. If you examine the horizontalAccuracy of the locations as they come in, you'll see that while it's "warming" up it will show a series of locations with greater and greater accuracy (i.e. smaller and smaller horizontalAccuracy values) until it reaches quiescence.
You could disregard those initial locations until horizontalAccuracy falls below a certain value. Or, better, during start up, you could disregard the previous location if (a) the distance between a new location and the old location is less than the horizontalAccuracy of the old location and (b) if the horizontalAccuracy of the new location is less than that of the prior location.
For example, let's assume you're maintaining an array of CLLocation objects, as well as a reference to the last drawn path:
#property (nonatomic, strong) NSMutableArray *locations;
#property (nonatomic, weak) id<MKOverlay> pathOverlay;
Furthermore, let's assume your location update routine is just adding to the array of locations and then indicating that the path should be redrawn:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
NSLog(#"%s", __FUNCTION__);
CLLocation* location = [locations lastObject];
[self.locations addObject:location];
[self addPathToMapView:self.mapView];
}
Then the addPathToMapView can therefore remove the second from last location if it's less accurate than the last one and if the distance between them is less than the most recent location's accuracy.
- (void)addPathToMapView:(MKMapView *)mapView
{
NSInteger count = [self.locations count];
// let's see if we should remove the penultimate location
if (count > 2)
{
CLLocation *lastLocation = [self.locations lastObject];
CLLocation *previousLocation = self.locations[count - 2];
// if the very last location is more accurate than the previous one
// and if distance between the two of them is less than the accuracy,
// then remove that `previousLocation` (and update our count, appropriately)
if (lastLocation.horizontalAccuracy < previousLocation.horizontalAccuracy &&
[lastLocation distanceFromLocation:previousLocation] < lastLocation.horizontalAccuracy)
{
[self.locations removeObjectAtIndex:(count - 2)];
count--;
}
}
// now let's build our array of coordinates for our MKPolyline
CLLocationCoordinate2D coordinates[count];
NSInteger numberOfCoordinates = 0;
for (CLLocation *location in self.locations)
{
coordinates[numberOfCoordinates++] = location.coordinate;
}
// if there is a path to add to our map, do so
MKPolyline *polyLine = nil;
if (numberOfCoordinates > 1)
{
polyLine = [MKPolyline polylineWithCoordinates:coordinates count:numberOfCoordinates];
[mapView addOverlay:polyLine];
}
// if there was a previous path drawn, remove it
if (self.pathOverlay)
[mapView removeOverlay:self.pathOverlay];
// save the current path
self.pathOverlay = polyLine;
}
Bottom line, just get rid of locations that are less accurate than the next one you have. You could get even more aggressive in the pruning process if you want, but there are tradeoffs there, but hopefully this illustrates the idea.
startUpdatingLocation
Will continuously update a user's location even when the location does not change. You just need to structure your app to handle these continuous updates according to your needs.
Try reading Apple's documentation on this subject. It is confusing at first but try anyway.
http://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/LocationAwarenessPG/CoreLocation/CoreLocation.html#//apple_ref/doc/uid/TP40009497-CH2-SW1
I think this is what you need.startMonitoringForRegion:desiredAccuracy
for Example see the following github link.
Try this Bread Crumb sample code provided by Apple..
http://developer.apple.com/library/ios/#samplecode/Breadcrumb/Introduction/Intro.html
Add this,
[locManager stopUpdatingLocation];
into your updateUserLocation delegate method.
Review the following code snippet:
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
[_locationManager stopUpdatingLocation];
}
locationManager.startUpdatingLocation() fetch location continuously and didUpdateLocations method calls several times,
Just set the value for locationManager.distanceFilter value before calling locationManager.startUpdatingLocation().
As I set 200 working fine
locationManager.distanceFilter = 200
locationManager.startUpdatingLocation()

iOS Core Location Set Pin to user location in viewDidLoad

I am attempting to set a map annotation to the user's current location. I am trying to set the pin in the viewDidLoad method, however because the method
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
Has not been called yet, the lat and long are 0.000000. Is there a way to call this method in my viewDidLoad or any other solution that will make a pin appear at my beginning location when the application loads?
UPDATE, Added Annotation Code
CLLocationCoordinate2D theCoordinate;
theCoordinate.latitude = (_currentLocation.latitude);
theCoordinate.longitude = (_currentLocation.longitude);
NSLog(#"The Coordinate Value:");
NSLog(#"%f, %f",theCoordinate.latitude,theCoordinate.longitude);
DDAnnotation *annotation = [[[DDAnnotation alloc] initWithCoordinate:theCoordinate addressDictionary:nil] autorelease];
annotation.title = #"Drag to Move Pin";
annotation.subtitle = [NSString stringWithFormat:#"%f %f", annotation.coordinate.latitude, annotation.coordinate.longitude];
[self.mapView addAnnotation:annotation];
UPDATE 2
Still not working, code is in the didUpdateLocation Method
static BOOL annotationAdded = NO;
if (!annotationAdded) {
annotationAdded = YES;
CLLocationCoordinate2D theCoordinate;
theCoordinate.latitude = _currentLocation.latitude;
theCoordinate.longitude = _currentLocation.longitude;
//Sets Initial Point to Africa Because Method to obtain current Location
//Hasen't Fired when View Loads
theCoordinate.latitude = (mapView.userLocation.coordinate.latitude);
theCoordinate.longitude = (mapView.userLocation.coordinate.longitude);
NSLog(#"The Coordinate Value:");
NSLog(#"%f, %f",theCoordinate.latitude,theCoordinate.longitude);
DDAnnotation *annotation = [[[DDAnnotation alloc] initWithCoordinate:theCoordinate addressDictionary:nil] autorelease];
annotation.title = #"Drag to Move Pin";
annotation.subtitle = [NSString stringWithFormat:#"%f %f", annotation.coordinate.latitude, annotation.coordinate.longitude];
[self.mapView addAnnotation:annotation];
}
MKMapView automatically places an annotation of class MKUserLocation when you set mapView.showsUserLocation = YES.
You can replace the default view for this annotation to whatever default annotation view you want by doing this in mapView:viewForAnnotation::
- (MKAnnotationView *) mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]]) {
// replace the following with code to generate and return custom user position annotation view
return customAnnotationView;
}
//*** other code ***//
}
Update:
If all you want to do is set a pin initially (once) at the user's location when the view loads, then you will have to wait until the phone can grab the data you need since that takes some time. Add your annotation in mapView:didUpdateUserLocation the first time it is called, and that should do the trick:
- (void) mapView:(MKMapView *)theMapView didUpdateUserLocation:(MKUserLocation *)userLocation {
static BOOL annotationAdded = NO;
if (!annotationAdded) {
annotationAdded = YES;
//*** add annotation to mapView ***//
}
}
Final Comment:
I would generally avoid setting a static pin at a users location the first time this method is called, however, and instead opt to just using the default standard blue dot. That is because the location services in the phone take time to find an accurate reading on the user's location, but in the interest of time it will send you location updates as soon as possible. This means that the first location update may not be very accurate, but subsequent updates may be much more accurate. That is why the standard blue dot sometimes changes position frequently within the first few moments of showing up on the map.
Just a caveat. Obviously what you choose to do depends on what the purpose of your app is.
I've never found a way to manually call that method. I believe it's a delegate method that's completely passive. Sorry.
It takes some time for the device to determine the location -- you can't speed up the process by calling -locationManager:didUpdateToLocation: yourself. You'll need to either use #Matt's suggestion to let the map draw the user's location, or else wait for -...didUpdateToLocation: to be called and take action then.

MapKit - didUpdateToLocation called but userLocation not updated

I have a MKMapView configured like so:
mapView = [[MKMapView alloc] init];
[mapView setMapType:MKMapTypeStandard];
[mapView setShowsUserLocation:YES];
[mapView setDelegate:self];
I then initialize a CLLocationManager and call startUpdatingLocation.
I am using iSimulate to send the GPS data from my phone, to the simulator, which seems to be working since the CLLocationManager delegate method is invoked with my correct GPS coordinates. However the MKMapView never moves the blue dot away from Cupertino.
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
NSLog(#"Did Update Location = %f / %f", [newLocation coordinate].latitude, [newLocation coordinate].longitude);
NSLog(#"Current User Location = %f / %f", [[mapView userLocation] coordinate].latitude, [[mapView userLocation] coordinate].longitude);
}
The above method outputs the following:
>>> Did Update Location = 40.740100 / -73.989900 # Correct
>>> Current User Location = 37.331693 / -122.030457 # Cupertino... Incorrect
Even if I manually update the userLocation's coordinate using:
[[mapView userLocation] setCoordinate:[newLocation coordinate]];
The dot still just sits on Cupertino. Am I missing something?
The problem with CLLocation manger is that is caches the old location and some time it returns the old location. To get a new location just check the time stamp of the CLLocation object if it is older than the time limit then ignore this location
-(void) locationManager:(CLLocationManager*)manager
didUpdateToLocation:(CLLocation*)newLocation
fromLocation:(CLLocation*) oldLocation
{
NSDate* time = newLocation.timestamp;
NSTimeInterval timePeriod = [time timeIntervalSinceNow];
if(timePeriod < 2.0 ) { //usually it take less than 0.5 sec to get a new location but you can use any value greater than 0.5 but i recommend 1.0 or 2.0
[manager stopUpdatingLocation];
// process the location
} else {
// skip the location
}
}
The dot still just sits on Cupertino. Am I missing something?
Are you testing this on the simulator? Note that in the simulator, the location dot always remains in Cupertino. Try it on a device - maybe you don't have a bug at all!

iPhone Gps logging inaccurate

I'm logging gps points during a walk. Below it shows the function that the coordinates are saved each 5 seconds.
i Did several tests but i cannot get the right accuracy i want. (When testing the sky is clear also tests in google maps shows me that the gps signal is good).
here is the code:
-(void)viewDidAppear:(BOOL)animated{
if (self.locationManager == nil){
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
locationManager.delegate = self;
// only notify under 100 m accuracy
locationManager.distanceFilter = 100.0f;
locationManager.desiredAccuracy= kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
}
}
- start logging
[NSTimer scheduledTimerWithTimeInterval:5 target:self selector:#selector(getData) userInfo:nil repeats:YES];
</code>
<code>
-(void)getData{
int distance;
// re-use location.
if ([ [NSString stringWithFormat:#"%1.2f",previousLat] isEqualToString:#"0.00"]){
// if previous location is not available, do nothing
distance = 0;
}else{
CLLocation *loc1 = [[CLLocation alloc] initWithLatitude:previousLat longitude:previousLong];
CLLocation *loc2 = [[CLLocation alloc] initWithLatitude:latGlobal longitude:longGlobal];
distance = [loc1 getDistanceFrom: loc2];
}
// overwrite latGlobal with new variable
previousLat = latGlobal;
previousLong = longGlobal;
// store location and save data to database
// this part goes ok
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
// track the time to get a new gps result (for gps indicator orb)
lastPointTimestamp = [newLocation.timestamp copy];
// test that the horizontal accuracy does not indicate an invalid measurement
if (newLocation.horizontalAccuracy < 0) return;
// test the age of the location measurement to determine if the measurement is cached
// don't rely on cached measurements
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
if (locationAge > 5.0) return;
latGlobal = fabs(newLocation.coordinate.latitude);
longGlobal= fabs(newLocation.coordinate.longitude);
}
I have taken a screenshot of the plot results (the walk takes 30 minutes) and an example of what i'am trying to acomplish:
http://www.flickr.com/photos/21258341#N07/4623969014/
i really hope someone can put me in the right direction.
Looking at your plots - This is exactly what I see too in an app I am working on.
Looking at your code. Whenever location is updated, locationManager calls didUpdateToLocationFromLocation - polling at 5s intervals will give you a lot of points at the same location. (but not relevant to the question)
Also I think you are leaking a lastPointTimestamp (not relevant to the question)
Right - the jumping around - you can look at the accuracy of the points : you do this in locationManager anyway but only check for <0. Is there a pattern of what the horizontal accuracy is on the jumping points ? The accuracy figure may be much worse then for other points, or one specific value (caused by a switch to cell tower triangulation).
Finally, you may need to implement filtering. Kalman filters are the over-the-top way to go, but I am looking at using low-pass filters combined with some basic physics (max acceleration & speed for walking, cycling, running, driving etc) to improve results.
Happy to collaborate on this.