CLLocation speed return -1.0 - ios

I have problem. My GPS (on iPad mini 2 in Wifi and on iPhone 6 in 3G/4G) the speed return -1.0. Have an idea?
This what i receive in console log:
Long: 12.5245, Lat: 41.9456, Speed:-1.0, kph: -3.6
Here the code in didUpdateLocations()
let userLocation: CLLocation = locations[0]
var speed: CLLocationSpeed = CLLocationSpeed()
speed = (locationManager.location?.speed)!
SpeedLabel.text = String(format: "%.0f km/h", speed * 3.6)
let long = String(Float(userLocation.coordinate.longitude))
let lat = String(Float(userLocation.coordinate.latitude))
print("Long: \(long), Lat: \(lat), Speed:\(speed), kph: \(speed * 3.6) ")

I had this problem too. A negative value means an invalid speed.
This is most of the time occured when you're inside a building and your location is moving a lot due to the building.
A simple fix would be:
if speed < 0 {
speed = 0
}
This checks if the speed is negative. If it is, it'll reset it to 0.

Related

how to detect difference between 2 points on the map and consider the zoom?

I am using a map with some annotations, I want to group the nearest annotations in annotation group to not overlap in the design in case of user zoom out, but my problem is to how to know the distance between annotations and this distance should change when zooming in and out.
the distance should be between points with x and y formate note meters
So my question is to how to catch the difference between 2 points on the map and consider the zoom
// convert location to cLLocation
let cLLocation1 = CLLocation(latitude: post1Location?.lat ?? 0, longitude: post1Location?.lng ?? 0)
let cLLocation2 = CLLocation(latitude: post2Location?.lat ?? 0, longitude: post2Location?.lng ?? 0)
// this is return the dinsactence in metres but i don't need that
let distance = cLLocation1.distance(from: cLLocation2)
let annotaionPoint1 = MKMapPoint(cLLocation1.coordinate)
let annotaionPoint2 = MKMapPoint(cLLocation2.coordinate)
let xDistance = max(annotaionPoint1.x, annotaionPoint2.x) - min(annotaionPoint1.x, annotaionPoint2.x)
let yDistance = max(annotaionPoint1.y, annotaionPoint2.y) - min(annotaionPoint1.y, annotaionPoint2.y)
this is working but zoom in and zoom out no effect so I need zoom to make change
if min(xDistance, yDistance) <= 32 {
/// action
}

iOS Calculate speed of device using Core Motion

I'm trying to calculate speed of physical device
In google i got
Using via CLLocationManager// I DON'T want to use
Using UIAccelerometer class : DEPECRATED
Upto now i have tried like this
func coreMotion() { // CALLING FROM VIEW DID LOAD
if self.motionManager.isDeviceMotionAvailable {
self.motionManager.deviceMotionUpdateInterval = 0.5
self.motionManager.startDeviceMotionUpdates(to: OperationQueue.current!,
withHandler: { [weak self] (deviceMotion, error) -> Void in
if let error = error {
print("ERROR : \(error.localizedDescription)")
}
if let deviceMotion = deviceMotion {
self?.handleDeviceMotionUpdate(deviceMotion)
}
})
} else {
print("WHAT THE HELL")
}
}
func handleDeviceMotionUpdate(_ deviceMotion: CMDeviceMotion) {
let attitude = deviceMotion.attitude
let roll = self.degrees(attitude.roll)
let pitch = self.degrees(attitude.pitch)
let yaw = self.degrees(attitude.yaw)
let accl = deviceMotion.userAcceleration
self.calculateSpeed(accl)
self.previousAccl = accl
print("Roll: \(roll), Pitch: \(pitch), Yaw: \(yaw)")
print("ACCELRATION: \(accl.x) \(accl.y) \(accl.z)")
}
func degrees(_ radians: Double) -> Double {
return 180 / Double.pi * radians
}
I'm getting acceleration object as well i.e userAcceleration
How can i calculate speed from that?
To compute the speed of the device, there is two possibilities for you :
1 - by approximating the derivative function of the position : with two position and the time between those two position you can estimate the speed.
2 - or compute a primitive of the acceleration. But take into account that this method will give you the correct speed value only if you know the speed à t_0 (the begining of your measures)
But if you insist on doing it using acceleration you can compute speed at t_i (where i is the number of update you received from the accelerometer)
speed(t_i) = speed(t_i-1) + acceleration(t_i) * (t_i - t_i-1)
and speed(t_0) is supposed to be known
that way you must at each update from the accelerometer do
speed = speed + acceleration * (lastUpdateTime - currentTime)
[Edit]
this is indeed like you mentioned it in the comments only one dimension if you wish to compute speed for all three dimensions you will have to do this three time once for each axis
speedX = speedX + accelerationX * (lastUpdateTime - currentTime)
speedY = speedY + accelerationY * (lastUpdateTime - currentTime)
speedZ = speedZ + accelerationZ * (lastUpdateTime - currentTime)
And you will need to have knowledge of speedX/Y/Z at t_0 to initialise your var at the correct value.

Adding CLLocationDistances

I'm trying to add CLLocationDistances and getting strange results. Here is my code:
var locations = [CLLocation]()
var totalDistance = CLLocationDistance()
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
self.locations.append(locations.first!)
if self.locations.count > 1 {
self.calculateTotalDistance()
}
}
func calculateTotalDistance() -> CLLocationDistance {
var y = 0
self.totalDistance = 0
while y < (locations.count - 1) {
let firstLocation = self.locations[y]
let secondLocation = self.locations[y + 1]
let distance = firstLocation.distanceFromLocation(secondLocation)
print(distance)
totalDistance += distance
y++
}
self.updateLabelWithText()
return totalDistance
}
private func updateLabelWithText() {
let distance = String(self.totalDistance)
let message = "Distance in meters: " + distance
self.distanceTextLabel.text = message
}
Essentially, every time I get a new CLLocation object from the system, I append it to my array. Then I iterate through the array, and get the distance between each individual points, and then add them together. I am testing the code on an actual device. As of now, when I run this code, even when I just sit down, the totalDistance variable reaches a count of 100 or so in 10 seconds, despite me not having moved anywhere close to 100 meters.
Also, in the calculateTotalDistance function, I print the distance calculated, and the distances don't seem right at all. Here is an example of what was printed to the console after the app launched for a few seconds:
0.0
1.15645918113224
1.06166528806247
1.06006756503664
1.05847219105153
16.1407724137949
9.67662215264722
0.0
1.15645918113224
1.06166528806247
1.06006756503664
1.05847219105153
16.1407724137949
9.6766221526472
Again, these are values just from when I'm sitting down, so I'm obviously not moving 16 meters, or 9 meters at a time.
Any idea what i'm doing wrong here?
thanks
This is because of accuracy of GPS. Check horizontalAccuracy of CLLocation before adding it to array.
You should also set desiredAccuracy of CLLocationManger to kCLLocationAccuracyBest.

Get vertical and horizontal components of distance between two coordinates in iOS

I'm trying to create a function in swift that accurately calculates the vertical and horizontal distance of any location from the origin of the Earth (latitude: 0, longitude: 0). I know that iOS has the distanceFromLocation function, but that gives me the direct location. What I'm looking for are the horizontal and vertical components of that direction. I tried coming up with my own solution, but when I test the direct distance based on the horizontal and vertical components I got, it didn't match the actual distance. Here's my function:
func distanceFromOrigin(location:CLLocation) {
let lat = location.coordinate.latitude
let lon = location.coordinate.longitude
let earthOriginLocation = CLLocation(coordinate: CLLocationCoordinate2DMake(0.0, 0.0), altitude: CLLocationDistance(0.0), horizontalAccuracy: kCLLocationAccuracyBestForNavigation, verticalAccuracy: kCLLocationAccuracyBestForNavigation, timestamp: NSDate())
var horDistance = earthOriginLocation.distanceFromLocation(CLLocation(latitude: 0.0, longitude: location.coordinate.longitude))
var verDistance = earthOriginLocation.distanceFromLocation(CLLocation(latitude: location.coordinate.latitude, longitude: 0.0))
let overallDistance = earthOriginLocation.distanceFromLocation(location)
if lat < 0 {
print("Object is South of Equator")
verDistance *= -1
} else if lat > 0 {
print("Object is North of Equator")
} else {
print("Object is at the Equator")
}
if lon < 0 {
print("Object is West of Prime Meridian")
horDistance *= -1
} else if lon > 0 {
print("Object is East of Prime Meridian")
} else {
print("Object is at the Prime Meridian")
}
print("Vertical Distance: \(verDistance)")
print("Horizontal Distance: \(horDistance)")
print("Overall Distance: \(overallDistance)")
//Test to see if vertical and horizontal distances are accurate compared to actual distance.
print("Test: \(sqrt((pow(horDistance, 2.0)) + (pow(verDistance, 2.0))))")
}
Thanks!
Your code is fine, but your test is wrong.
You miss that the Earth is not flat and so the right-angled triangle you're considering lays on geoid and has hypotenuse greater then squared sides sum.
I'd recommend you to perform a couple of tests manually to make sure the result looks realistic and not dig deep into this geometry on a curved surface.
A minor note: your test could pass if the points are pretty close to each other, because in such case the curvature of the Earth surface will have a minimal influence on the calculation.

Calculating Distance, converting to km and then cutting out decimal places

Edit 3: Thank you beyowulf, I implemented your line of code and this is the result! Exactly what I was hoping for. Thank you for all the suggestions.
Edit 2: Interesting, as per user27388882 suggestion I changed my code to:
//convert to kilometers
let kilometers = Double(round(traveledDistance) / 1000)
The result is three decimal places. Ideally I would like only two at most, but this is a step in the right direction! Thank you!
Edit 1: for clarification of "does not work": I guess I can't post a picture, but here is a link when viewed in the simulator. The distance still appears as a super long string of decimals, despite using code to try and shorten the number of decimal places. What I perceive to not be working in my code is where the decimal places should be cut off.
I am essentially creating an app that tracks a users location while riding their bicycle. One feature is to take the distance travelled by the user and display it in KM. I have gotten the distance function to work by searching through other posts. I have also looked at NSNumberFormatter help documents, but implementing code I have seen does not work. Is this an issue of distance being a double which is calculated from CLLocation? Another piece of potentially relevant information is that I am working in Xcode 7.2 and Swift2.
I don't want to post my whole code since I want to highlight where I am stuck, but not sure if more of my code is needed to solve this.
import UIKit
import CoreLocation
// Global variables
var startLocation:CLLocation!
var lastLocation: CLLocation!
var traveledDistance:Double = 0
// Identify Labels
#IBOutlet weak var distanceLabel: UILabel!
// Create a location manager
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
//Calculate the distance between points as a total distance traveled...
if startLocation == nil {
startLocation = locations.first! as CLLocation
} else {
let lastLocation = locations.last! as CLLocation
let distance = startLocation.distanceFromLocation(lastLocation)
startLocation = lastLocation
traveledDistance += distance
//convert to kilometers
let kilometers = traveledDistance / 1000
//Convert to only two decimal places
let nf = NSNumberFormatter()
nf.minimumSignificantDigits = 1
nf.maximumFractionDigits = 2
nf.numberStyle = .DecimalStyle
nf.stringFromNumber(kilometers)
//Update the distance label
self.distanceLabel.text = "\(kilometers) kilometers"
Help me, stackOverFlow. You're my only hope.
tl;dr round out decimal places from distance value calculated from user location using swift2.
Shouldn't wait to round until you are ready to display the results? You can say something like:
let formatedString = String(format:"%.2f",Float(traveledDistance / 1000.0 + .005))
To get traveledDistance rounded to the neared hundredth of a kilometer.

Resources