CLLocation elevation accuracy - ios

I have a location service app, in which the user's elevation is provided. I have found, though, that the elevation accuracy provided by the CLLocationManager is extremely inaccurate. When I test the same two spots twice, sometimes the elevation difference is forty feet and sometimes it is a hundred. Is there any way that I can improve the vertical accuracy of the CLLocation, or is there a different way of acquiring the user's elevation (third-party libraries)? I have already tried checking the verticalAccuracy property of the newLocation provided by the CLLocationManager and throwing it out if it isn't sufficient, but even when it is 'accurate' enough, it still often isn't actually accurate. Thanks for your time!
Right now I'm using:
if([newLocation verticalAccuracy] < 30) {
if(isCustomary)
altitudeLabel.text = [NSString stringWithFormat:#"%.2f feet", ([newLocation altitude] * 3.2808399)];
else
altitudeLabel.text = [NSString stringWithFormat:#"%.2f meters", [newLocation altitude]];
}
Problems with that code: often the verticalAccuracy never gets below 30, and when it does, that is still not even close to accurate enough; I have tested the code walking around my house (one story), and it says the elevation changes up to nineteen feet, which I'm sure isn't true.

The elevation derived from GPS satellites is inherently less accurate than the horizontal solution from GPS due to the geometry of the satellites. You should expect the vertical accuracy to be usually about 1.5 to 3 times worse than the horizontal accuracy. That's just a limitation of GPS and why aviation requires WAAS correction before you can use GPS for instrument approaches.
When the vertical accuracy is 20 or 30 meters you should expect the altitude to be off up to 100 feet. Expecting it to not vary by 19 feet as you walk around the house in unrealistic.
What you could do is keep a rolling, weighted average (or a Kalman filter) of the recent "good" altitude readings to help filter out the measurement errors.

What code have you tried?
This is the best code for elevation so I don't think there is anything beyond this:
-(void)awakeFromNib {
locmanager = [[CLLocationManager alloc] init];
[locmanager setDelegate:self];
[locmanager setDesiredAccuracy:kCLLocationAccuracyBest];
[locmanager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
heightMesurement.text = [NSString stringWithFormat: #"%.2f m", newLocation.altitude];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
heightMesurement.text = #"0.00 m";
}

Related

CLLocationManager sometimes provides wrong coordinates on iOS 13

Sometimes location manager gives GPS-point, which is located about hundreds meters, or several kilometers away from real device location. After it location manager continues provide us with wrong coordinates, which slowly became closer to real device location.
Such points have quite good accuracy about ~30 - ~65 meters, and some of them have speed > 0 m/s.
real path was:
Authorization status is "Always allow"
location manager is adjustment:
CLLocationManager *manager = [CLLocationManager new];
manager.allowsBackgroundLocationUpdates = YES;
manager.pausesLocationUpdatesAutomatically = NO;
manager.showsBackgroundLocationIndicator = YES;
manager.distanceFilter = 50; // meters
manager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
manager.delegate = self;
This problem is actual only for iOS 13. I made about 50 experiments, registering movement trajectories of ~5 km - ~150 km length. Same code works perfectly with iOS 12.

Google maps IOS:Recalculate Route In Direction of travelling

I m using Google map For my IOS application.
I m able to calculate Route and draw polyline based on it from directions API. The present direction api and my code is working well. But if user is not going to drawn route or going to wrong direction. I would like to recalculate route from the direction user is travelling not from the direction user is coming on. I m recalculating route for every 100 meters if not going to routhpath which is drawn.
It's calculating route correctly but in the opposite direction i m travelling on. So it should detect the direction i'm going on a road and not the backwards direction from which i m coming.
Here is code snippet. I written in delegate didUpdateToLocations:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
if (aLocationDistanceLoc == Nil) {
aLocationDistanceLoc=[[CLLocation alloc]init];
aLocationDistanceLoc=newLocation;
}
else
{
CLLocationDistance distance1 = [aLocationDistanceLoc distanceFromLocation:newLocation];
if (distance1 > 100) {
aLocationDistanceLoc=newLocation;
if (GMSGeometryIsLocationOnPathTolerance(newLocation.coordinate, routesPath, YES, 10)) {
}
else
{
flagForRouteRecalculateActive=YES;
[self callApiForNavigation:[NSString stringWithFormat:#"%f,%f",newLocation.coordinate.latitude,newLocation.coordinate.longitude] destinationPoint:[NSString stringWithFormat:#"%#,%#",currentLatDropoff ,currentLongDropoff ]];
}
}
}
Here is my Directions API call:
[NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/directions/json?origin=%f,%f&destination=%f,%f&sensor=true&mode=driving",[[arrayStart objectAtIndex:0] floatValue],[[arrayStart objectAtIndex:1] floatValue],[[arrayDestination objectAtIndex:0] floatValue],[[arrayDestination objectAtIndex:1] floatValue]]
Here is the Video demonstration of problem. You'll see as i moving in direction the route is recalculating but its recalculate from backward direction. I need to recalculate from front in the direction i m going.
video of actual Issue

Giving the different distance between two points using wifi and 3G

I am calculating the distance between two locations like below
CLLocation *locA = [[CLLocation alloc] initWithLatitude:lat longitude:lon];
CLLocationCoordinate2D coordinate = [self getLocation];
CLLocation *locB = [[CLLocation alloc] initWithLatitude:coordinate.latitude longitude:coordinate.longitude];
CLLocationDistance distance = [locA distanceFromLocation:locB];
CLLocationDistance kilometers = distance / 1000.0;
But it giving the different result when i connect to wifi and 3G network.how to get the same result for both.
You invariably will not get the same location for both. In fact, if you come back to the exact same location tomorrow and turn on location services, you might not get the same latitude and longitude even if you stayed with the same technology.
The latitude and longitude you receive from a CLLocationManager is not an exact science. In fact, if you look at the original CLLocation objects you received, you'll notice that there is a horizontalAccuracy property that reflects how accurate/inaccurate the coordinate could be. When you first start location services, you'll even see multiple locations come in, generally with increasing accuracy.
But it will never be perfect and you shouldn't expect it to be. This is one of the reasons why it's important to test location-aware code on a real device, because the simulator will lull one into a false sense of absolute accuracy which doesn't exist in the real world. You should write code that anticipates this. And, if nothing else, you should start considering horizontalAccuracy of the objects you receive from the location manager.
there's nothing wrong in the code lines you posted,
the only line that could give you differences in the 2 cases (wifi and 3g) is your method [self getLocation]
where i guess you get the device location.
In this case your device may use both gps and wifi access to calculate its location, so little differences may occurs (you may have noticed that some map applications advice you to turn your wifi on to get more accuracy)
Anyway,
in your getLocation method try to add a more precise accuracy when you use
CLLocationManager
i tried this:
- (CLLocationCoordinate2D )getLocation {
self.locationManager = [[CLLocationManager alloc] init];
locationManager.distanceFilter = kCLDistanceFilterNone; // whenever we move
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters; // 100 m
[locationManager startUpdatingLocation];
CLLocationCoordinate2D startCoord = CLLocationCoordinate2DMake(locationManager.location.coordinate.latitude, locationManager.location.coordinate.longitude);
return startCoord;
}
and the accuracy is enough to get no differences between 3G/wifi
but you could set it to
kCLLocationAccuracyBestForNavigation;
kCLLocationAccuracyBest;
kCLLocationAccuracyNearestTenMeters;
ps
i hope you are using a device with GPS, of course...

How to find if two google map routes are being intersected in an IOS project

I want to achieve the following and I am unaware whether it is possible or not. I am having two points on a road (imagine like a finishing line - they are the two edges of the pavements - they are in a straight line) and I want to check whether a user's route has passed between these points.
So I thought, I can do something like this:
get the route between these two points (they are quite near - the road is 20 m wide at most)
get the users route
check if these routes are interecting, if there is any crossing between them.
If it was pure geometry, it would be easy. I am having two lines and I want to know if there is any intersection between them.
I want to use the following in an IOS project, if it makes any difference. For example, I thought that maybe there is a programmatically way of drawing the MKPolylines and see if there is intersection. I do not want to see it visually, I just need it programmatically.
Is it possible? Can you suggest me anything else?
There is no direct method to check for that intersection.
You can turn the problem into a geometry problem by converting the lat/long positions into map positions (applying the transform to flatten onto a normalised grid). This can be done with MKMapPointForCoordinate.
One thing to consider is the inaccuracy of the GPS reported positions. In a number of cases you will find that the reported track from the GPS isn't actually on the road but running beside the road. Particularly when turning (tight) corners you will often get a large curve in the track. As such you may want to extend the width of the 'finishing line' to compensate for this.
If you just care about whether the user is within a certain distance of a set point then you can create a CLRegion to represent the target location and then call containsCoordinate: with the current user location. This removes any projection and uses the lat/long directly. You can also get the system to monitor this for you and give you a callback when the user enters or exits the region with startMonitoringForRegion:desiredAccuracy:. Again, you need to consider GPS accuracy when setting the radius.
I would try to solve this problem in three steps:
Step 1. Convert each coordinate user's track has to CGPoint and save it an array.
// in viewDidLoad
locManager = [[CLLocationManager alloc] init];
[locManager setDelegate:self];
[locManager setDesiredAccuracy:kCLLocationAccuracyBest];
[locManager startPdatingLocation];
self.userCoordinatePoints = [NSMutableArray alloc]init];
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
CLLocationCoordinate2D loc = [newLocation coordinate];
CGPoint *currentPoint = [self.mapView convertCoordinate:loc toPointToView:self.mapView];
// add points to array
self.userCoordinatePoints addObject:currentpoint];
}
Step 2. Convert MKPolylineView to CGPathRef
Create a class variable of type CGPathRef
{
CGPathRef path;
}
This method you must have implemented to create the route between two points:
- (MKOverlayView*)mapView:(MKMapView*)theMapView
viewForOverlay:(id <MKOverlay>)overlay
{
MKPolylineView *overlayView = [[MKPolylineView alloc]
initWithOverlay:overlay];
overlayView.lineWidth = 3;
overlayView.strokeColor = [[UIColor blueColor]colorWithAlphaComponent:0.5f];
// overlayView.fillColor = [[UIColor purpleColor] colorWithAlphaComponent:0.1f];
path = overlayView.path;
return overlayView;
}
Step 3: Create a custom method to check whether point lies in CGPath or not
- (BOOL)userRouteIntersectsGoogleRoute
{
// Loop through all CGPoints
for(CGPoint point in self.userCoordinatePoints)
{
BOOL val = CGPathContainsPoint(path, NULL, point);
if(val)
{
return YES;
}
}
return NO;
}

Calculating distance between user & a nearby location, and calculated distance keeps showing up as 0?

I'm using the following code to calculate the distance between my app user's location, and nearby locations (annotations). When I try to display the "Distance Away" as text in a label, it keeps saying that the calculated distance is 0. Why is this?
*Note that my table is using the coordinates placed on my MapView to determine the distance away.
Here's the code I'm using to calculate the distance from my user to a nearby location
MapViewController.m
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
for (MapViewAnnotation *annotation in self.mapView.annotations) {
CLLocationCoordinate2D coord = [annotation coordinate];
CLLocation *annotationLocation = [[CLLocation alloc] initWithLatitude:coord.latitude longitude:coord.longitude];
annotation.distance = [newLocation distanceFromLocation:annotationLocation];
}
And here's the bit I'm using to display the calculatedDistance in a label (located in my custom cell to be displayed in a tableview):
ViewController.m
cell.distanceLabel.text = [NSString stringWithFormat:#"%f m.", calculatedDistance];
Any help would be much appreciated!
for (MapViewAnnotation *annotation in self.mapView.annotations) {
CLLocationCoordinate2D coord = [annotation coordinate];
CLLocation *userLocation = [[CLLocation alloc] initWithLatitude:coord.latitude longitude:coord.longitude];
That's not the user's location, that's the annotation's location. But odd variable names aside:
CLLocationDistance calculatedDistance = [userLocation distanceFromLocation:userLocation];
The distance from a location to itself is 0. That line is probably a bug. Maybe you meant
CLLocationDistance calculatedDistance = [newLocation distanceFromLocation:userLocation];
which would return the distance between the user's new location and the (misnamed) annotation's location - probably what you want. Of course, you actually calculate just that on the line above the distance-to-self calculation, then throw it away two lines later.
tl;dr
Throw away the last two lines, they're useless.

Resources