Re routing user in iphone navigation app - iphone

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

Related

path tracing on map in ios

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 .

CLLocationManager tracks wrong Location (Track Me)

I am implementing Track me option in my code.CLLocationManager is not working as expected.when I start app remain at the same position ,CLLocationManager changes around 20-30 meters with-in 1 min minutes..then I remain Constant.
And If i change my position to track same thing happen in starting 1 min CLLocationManager moves 20-30 min extra then moves with my speed..
Why this happening..
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.distanceFilter = 0.0001;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
}
-(void)start {
[self.locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager*)manager
didUpdateToLocation:(CLLocation*)newLocation
fromLocation:(CLLocation*)oldLocation {
[self processLocationChange:newLocation fromLocation:oldLocation];
}
-(void)processLocationChange:(CLLocation*)newLocation fromLocation:oldLocation {
if (newLocation != oldLocation) {
NSLog(#"Moved from %# to %#", oldLocation, newLocation);
CLLocation* lastKnownLocation = NULL;
if ([self.locationPoints count] > 0) {
lastKnownLocation = [self.locationPoints objectAtIndex:[self.locationPoints count] - 1];
}
else {
lastKnownLocation = newLocation;
self.bottomLeft = newLocation.coordinate;
self.topRight = newLocation.coordinate;
}
// Check for new boundaries
CLLocationCoordinate2D coords = newLocation.coordinate;
if (coords.latitude < bottomLeft.latitude || coords.longitude < bottomLeft.longitude) {
self.bottomLeft = coords;
NSLog(#"Changed bottom left corner");
}
if (coords.latitude > topRight.latitude || coords.longitude > topRight.longitude) {
self.topRight = coords;
NSLog(#"Changed top right corner");
}
double speed = fabs(newLocation.speed);
double deltaDist = fabs([newLocation distanceFromLocation:lastKnownLocation]);
double newAvgSpeed = (self.totalDistance + deltaDist) / ((double)[self getElapsedTimeInMilliseconds] / 1000.0);
double accuracy = newLocation.horizontalAccuracy;
double alt = newLocation.altitude;
NSLog(#"Change in position: %f", deltaDist);
NSLog(#"Accuracy: %f", accuracy);
NSLog(#"Speed: %f", speed);
NSLog(#"Avg speed: %f", newAvgSpeed);
self.totalDistance += deltaDist;
self.currentSpeed = speed;
self.avgSpeed = newAvgSpeed;
self.altitude = alt;
NSLog(#"Delta distance = %f", deltaDist);
NSLog(#"New distance = %f", self.totalDistance);
// Add new location to path
[self.locationPoints addObject:newLocation];
// Update stats display
[self.first.start1 updateRunDisplay];
// Update map view
[self updateMap:lastKnownLocation newLocation:newLocation];
}
}
I faced the same problem in my current Pedometer app. I stretched, banged my head for couple of days. Then I found out that CLLocationManager is not able to track <5 meter distance and location generate updates. I kept self.locationManager.distanceFilter =2.0; and it gave me location updates even device was stationary. So I just changed distancefilter to 5.0 meter and it started working great. Try taking 5 meters it should work, I tested and all my wrong notifications issues vanished:
self.locationManager.distanceFilter =5.0;
You are taking self.locationManager.distancefilter=0.0001 which is I suppose out of capacity for CLLocationManager to track such a minor movement. Also you need to filter out old locations i.e. cached location updates as mentioned in Location Awareness Guide by Apple. I have used this condition in my code to filter all events which are older than 5 seconds.
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations
{
CLLocation *currentLocation=[locations lastObject];
NSDate* eventDate = currentLocation.timestamp;
NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
if(abs(howRecent)<5.0 && self.currentLocation.horizontalAccuracy<=10 && self.currentLocation.horizontalAccuracy>0)
{
//you have got fresh location event here.
}
}
I think give the distance filter effective with this
self.locationManager.distanceFilter = kCLDistanceFilterNone;
and you can start updating location method but also try this method these both methods are required to get exact location
[locationManager startMonitoringSignificantLocationChanges];

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.

Why is MKMapView putting me in the sea?

I have this code to set the map at the user's location:
MKCoordinateSpan span;
span.latitudeDelta=0.2;
span.longitudeDelta=0.2;
CLLocationCoordinate2D location=mapView.userLocation.coordinate;
location = mapView.userLocation.location.coordinate;
MKCoordinateRegion region;
region.span=span;
region.center=location;
[mapView setRegion:region animated:TRUE];
[mapView regionThatFits:region];
Now when I do mapView.showsUserLocation=YES it shows my location at the right place (on my device, and the apple hq in the simulator) however, both times the code above puts me in the sea somewhere near africa!
Any ideas?
The latitude/longitude pair 0/0 is on the equator due south of Greenwich, England. That spot is in the Gulf of Guinea, off the West coast of Africa. If that's where your pin is getting placed, then your mapView.userLocation isn't getting set.
Probably your code here is running before MKMapKit has had a chance to get its location. What you really want to do is have your viewController adopt the MKMapKitDelegate protocol, set the .delegate property of your map view to self, and then implement the method:
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
That method will get called when the map kit locates the user, and you can use the userLocation value you get passed there to set the region on the map. Until that gets called the first time, though, the MapView is still working on locating itself, and your asking about its location is premature.
Also, your regionThatFits there at the end is a no-op. That method doesn't resize the region in place, it actually returns a resized region, for you to use however you will. So you want to set your map view's region to what that method returns. Like this:
[mapView setRegion:[mapView regionThatFits:region] animated:TRUE];
What I have done was add the following entry on info.plist:
NSLocationAlwaysUsageDescription
Got this info into this (very good) tutorial:
https://www.youtube.com/watch?v=Z272SMC9zuQ
You can choose this method..
- (void)mapView:(MKMapView *)_mapView regionDidChangeAnimated:(BOOL)animated{
CLGeocoder *ceo = [[CLGeocoder alloc]init];
CLLocation *loc = [[CLLocation alloc]initWithLatitude:_mapView.region.center.latitude longitude:_mapView.region.center.longitude];
CLLocationAccuracy accuracy = _mapView.userLocation.location.horizontalAccuracy;
if (accuracy) {
current_pickup_location = loc;
[_currentStreetSpinner startAnimating];
[ceo reverseGeocodeLocation:loc
completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error){
CLPlacemark *placemark = [placemarks objectAtIndex:0];
NSString *locatedAt = [[placemark.addressDictionary valueForKey:#"FormattedAddressLines"] componentsJoinedByString:#", "];
// NSLog(#"location %#",placemark.location);
NSLog(#"I am currently at %#",locatedAt);
_currentStreetLabel.text = locatedAt;
static_iVar = _currentStreetLabel.text;
[_currentStreetSpinner stopAnimating];
[self listDoctorsWithSpeciality_id:currentSpeciality_id
withProfessionalityId:currentProfessionality_id];
}];
}
}
I am answering this question because the answer picked did not really help me and I was having the exact same issue. didUpdateUserLocation is not very practical because it makes the app update every single time the location changes. The other issue with the above solution is that when the map loads it's still too early to ask for a location. So how do you ask for user location before the the map loads so that the zooming doesn't take you to Africa?
You need to request the location by using the location manager on the viewDidLoad. Then after that you can set the region.
SWIFT 3
//top of your class
let locManger = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
//request user location
locManager.startUpdatingLocation()
//this is the code that sets the region based on the location
let span = MKCoordinateSpanMake(0.5, 0.5)
let location = CLLocationCoordinate2DMake((locManager.location?.coordinate.latitude)!, (locManager.location?.coordinate.longitude)!)
let region = MKCoordinateRegionMake(location, span)
yourMap.setRegion(region, animated: false)
//stop location updating
locManager.stopUpdatingLocation()
}

iphone updateToLocation works differently over 3G versus wireless network?

I have a simple mapview that has the following viewdidload method and didupdate to location:
- (void)viewDidLoad {
NSLog(#"in view did load");
[super viewDidLoad];
self.mapView.showsUserLocation = YES;
self.put_url = nil;
locationManager = [[CLLocationManager alloc] init];
[locationManager setDesiredAccuracy:kCLLocationAccuracyNearestTenMeters];
[locationManager setDelegate:self];
noUpdates = 0;
[locationManager startUpdatingLocation];
self.availableParking = [[NSMutableArray alloc] init];
//self.availableParking = nil;
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
NSLog(#"in didupdatetolocatoin");
if([newLocation horizontalAccuracy] < 100 && [newLocation horizontalAccuracy] > 0) {
// Add annotation to map
DDAnnotation *annotation = [[DDAnnotation alloc] initWithCoordinate:newLocation.coordinate title:#"Park Here?"];
MKCoordinateRegion region;
MKCoordinateSpan span;
span.latitudeDelta = 0.05;
span.longitudeDelta = 0.05;
region.span = span;
region.center = newLocation.coordinate;
self.mapView.region = region;
NSLog(#"in didupdatetolocation");
noUpdates++;
NSLog(#"IN UPDATELOCATION NOUPDATES = %d",noUpdates);
if (noUpdates == 1) {
[self.mapView addAnnotation:annotation];
NSLog(#"ADDED ANNOTATION IN didUpdateToLocation!!");
[locationManager stopUpdatingLocation];
[self.settingsViewController setState:self.mapView.userLocation.subtitle andCity:#"fuckface"];
NSLog(#"STOPPED UPDATING LOCATION");
UpdateLocation *updatedLocation = [[[UpdateLocation alloc] initWithUserid:#"fuckface" andCoordinate:newLocation.coordinate withMapViewController:self]
autorelease];
NSLog(#"Lat = %f, Long = %f",newLocation.coordinate.latitude,newLocation.coordinate.longitude);
//[NSThread detachNewThreadSelector:#selector(getLocations) toTarget:self withObject:nil];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(sendUpdate)
name:#"NoteFromOne"
object:updatedLocation];
}
// We only update location once, and let users to do the rest of the changes by dragging annotation to place they want
} else {
NSLog(#"Accuracy not good enough %lf", [newLocation horizontalAccuracy]);
}
}
When Im connected to a wireless network it works flawlessly zooming in and dropping an annotation pin in my current location. Over the 3G network it never zooms or drops the pin. Any ideas as to why? Thanks in advance.
Here's a couple of screen shots:
With 3G:
alt text http://www.freeimagehosting.net/uploads/fe7fcbb2ea.jpg
With wifi:
alt text http://www.freeimagehosting.net/uploads/6b653e60a7.jpg
The GPS unit has nothing to do with the network connection (unless the GPS signal is not available, in which case the GPS may try to use the wifi hotspot or the cell your device is connected to in order to infer your location). It works independently of it if the GPS signal is available, and the network is only used to actually show the map. From the code snipped you posted, you only show the map when you reach an horizontal accuracy less than 100 meters, otherwise you let the GPS unit updating the location. However, if you try your code in the exact SAME place, the GPS unit on your device should always return the same updates. Therefore, I really do not understand the behaviour you are describing: this would be possible only if the GPS unit returned different updates for the same place when a different network connection is available because the GPS signal is not available. Are you seeing the same latitude/longitude in the two cases or not? Are you seeing the same accuracy? Be careful to measure this in exactly the same place in both cases.
If you obtain the same updates, then it may be possible that your 3G cellular connection is simply not powerful enough or is only apparently available, so that you did not get the map. Try testing the speed of your 3G network from the same place.
A related consideration. You should allow the GPS unit to work until either a specified amount of time elapses (say 20 seconds, use NSTimer for this) or until you reach a specified level of accuracy, whichever happens first. Otherwise you may end up consuming too much the battery.