What do horizontalAccuracy and verticalAccuracy of a CLLocation refer to?
The -1 for verticalAccuracy
indicates that the altitude in the CLLocation
is not valid. You only get altitude with a 3D GPS position.
The 1414 for horizontalAccuracy
indicates that the horizontal (lat/lon) position could be up to 1414m off (this is just an estimated error). This is probably a location determined by cell tower triangulation or WiFi location data. GPS locations usually report 100m or better.
To get a higher accuracy location (300m or better) you need to set desiredAccuracy
and wait for the GPS receiver to lock onto at least 3 satellites (or 4 for a 3D fix). Until that happens CLLocationManager
will give you the best it has which is WiFi or Cell tower triangulation results.
CoreLocation current accuracy/range
When you get a location from the CLLocationManager
you can read the effective accuracy using horizontalAccuracy
and verticalAccuracy
on CLLocation
.
Creating a location based reminder: what to do with horizontal accuracy?
As pointed out by progmr, horizontalAccuracy
is purely an estimate of the uncertainty in the location.
To back this up, I did a couple of real-world tests where:
- I created a location-based reminder in the Reminders app, which has
radius = 0
but also reportshorizontalAccuracy = 0
. - I created a reminder using the same location in my own code, setting
radius = 0
, but the return fromCLGeocoder
reportinghorizontalAccuracy = 100
With each test, the reminders fired at exactly the same position. horizontalAccuracy
is purely for information.
How accurate is CLLocation accuracy?
When you're using CoreLocation, you're getting back "answers" that get better and better. I've noticed that the "best" answer is almost always accurate to within 100m, so theoretically you could probably cut down on the "buffer" that you're normally given. The only way to really know, though, and this is what I would do, is to test test test. Find iphones and ipods from all generations and see what types of accuracies you're getting and what types of results you're getting. In a lot of ways, it depends on the type of app you're making, but if you want to deliver sensitive or important information based on where the user is, you should really wait for the framework to give you a nearly exact location.
Why is horizontalAccuracy = 0.00?
It seems you have found a bug.
There are some "secrets" in Gps application developpment:
1) if latitude and longitude both have the value 0 and if this location is marked as valid then this is always a programming error, on your or on API side, or some other place. Although (0,0) is theoretically possible practically it is reachable only via simulation. No ship or airplane can exactly navigate to (0,0) with a precision of 10cm.
2) same applies to some other values, like hdop or in your case horAcc.
So ignore this location!
iOS Location Accuracy
It's a limitation of the hardware, possible combined with your particular location. If you are indoors writing your code then GPS isn't going to work (try walking to a window), so you rely on WiFi which might just have very bad accuracy where you are, or on cell towers which isn't very accurate anywhere.
Can't get index in array of CLLocation Swift
A possible solution is to use reduce(into:)
. It's easier to play with "previous index".
func filterInvalidLocation(route: [CLLocation]) -> [CLLocation] {
let maxDistance = 500000.0
let minDistance = 10000.0
let reduced = route.reduce(into: [CLLocation]()) { (accumulated, currentLocation) in
// We don't add it if negative horizontal accuracy
guard currentLocation.horizontalAccuracy >= 0 else {
print("\(currentLocation) removed because of horizontalAccuracy being negative")
return
}
// We don't add it if Low Accuracy
guard currentLocation.horizontalAccuracy < 80 else {
print("\(currentLocation) removed because of horizontalAccuracy being > 80")
return
}
// We don't add it if not moving
guard currentLocation.speed > 1 else {
print("\(currentLocation) removed because of speed < 1")
return
}
guard let last = accumulated.last else {
//There is no valid one yet to compare, we consider this one as valid
accumulated.append(currentLocation)
return
}
//We check if there location is "newer"
guard last.timestamp < currentLocation.timestamp else {
print("\(currentLocation) removed because distance is older than previous one")
return
}
let distanceFromLast = currentLocation.distance(from: last)
print(distanceFromLast)
// We don't add it distance between last and current is too big
guard distanceFromLast < maxDistance else {
print("\(currentLocation) removed because distance is too big (\(distanceFromLast))")
return
}
// We don't add it distance between last and current is too low
guard distanceFromLast > minDistance else {
print("\(currentLocation) removed because distance is too small (\(distanceFromLast))")
return
}
//Current Location passed all test, we add it
accumulated.append(currentLocation)
}
return reduced
}
With sample:
let date = Date()
let locations: [CLLocation] = [CLLocation(coordinate: CLLocationCoordinate2D(latitude: 30.0, longitude: 45.0),
altitude: 30.0,
horizontalAccuracy: 0.1,
verticalAccuracy: 0.1,
course: 0.1,
speed: 2,
timestamp: date),
CLLocation(coordinate: CLLocationCoordinate2D(latitude: 30.0, longitude: 45.0),
altitude: 30.0,
horizontalAccuracy: -1.0,
verticalAccuracy: 0.1,
course: 0.1,
speed: 2,
timestamp: date),
CLLocation(coordinate: CLLocationCoordinate2D(latitude: 30.0, longitude: 45.0),
altitude: 30.0,
horizontalAccuracy: 90,
verticalAccuracy: 0.1,
course: 0.1,
speed: 2,
timestamp: date),
CLLocation(coordinate: CLLocationCoordinate2D(latitude: 30.0, longitude: 45.0),
altitude: 30.0,
horizontalAccuracy: 0.1,
verticalAccuracy: 0.1,
course: 0.1,
speed: 0.1,
timestamp: date),
CLLocation(coordinate: CLLocationCoordinate2D(latitude: 30.0, longitude: 45.0),
altitude: 30.0,
horizontalAccuracy: 0.1,
verticalAccuracy: 0.1,
course: 0.1,
speed: 2,
timestamp: date.addingTimeInterval(-1.0)),
CLLocation(coordinate: CLLocationCoordinate2D(latitude: 35.0, longitude: 50.0),
altitude: 30.0,
horizontalAccuracy: 0.1,
verticalAccuracy: 0.1,
course: 0.1,
speed: 2,
timestamp: date.addingTimeInterval(+1.0)),
CLLocation(coordinate: CLLocationCoordinate2D(latitude: 30.001, longitude: 45.0),
altitude: 30.0,
horizontalAccuracy: 0.1,
verticalAccuracy: 0.1,
course: 0.1,
speed: 2,
timestamp: date.addingTimeInterval(+2.0)),
CLLocation(coordinate: CLLocationCoordinate2D(latitude: 31.0, longitude: 45.0),
altitude: 30.0,
horizontalAccuracy: 0.1,
verticalAccuracy: 0.1,
course: 0.1,
speed: 2,
timestamp: date.addingTimeInterval(+1.0)),
]
This can be tested on playground, we should keep the first one and the one at index 7.
Related Topics
Using Tint Color on Uiimageview
Why Does Safari Mobile Have Trouble Handling Many Input Fields on iOS 8
Avplayer Stops Playing Video After Buffering
Xcode 7 How to Refresh Provisioning Profiles
Xcode: Could Not Inspect the Application Package
Use Uibarbuttonitem Icon in Uibutton
Uitextfield Should Accept Number Only Values
Why Does My Uitableview "Jump" When Inserting or Removing a Row
Negative Spacer for Uibarbuttonitem in Navigation Bar on iOS 11
iPhone Uitextfield Background Color
Remove Uisegmentedcontrol Separators Completely. (Iphone)
Complete List of iOS App Permissions
Adding Click Event on Infowindow/Marker in Google Maps Sdk for Native iOS/Objective C
How to Embed a Uitableview in a Uiscrollview
Swift Framework: Umbrella Header '[...].H' Not Found
Request Permissions Again After User Denies Location Services