4

I have an application where I calculate distance travelled like the Uber application. When a driver starts a trip, the location begins to change even though a start point has been specified in the search for a ride, a driver could decide to pass an alternative route or pass long places and routes because he/ she does not know the shortest route, how then do I calculate the total distance.

The starting location is the location the driver hits start button The end location is the location the driver hits stop button

this is my code so far

    public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        lastLocation = locations.last!
        endTrip(locations.last)

        if !hasSetInitialLocation {

            let camera = GMSCameraPosition.camera(withTarget: lastLocation!.coordinate, zoom: 17)
            self.mapView.animate(to: camera)
            hasSetInitialLocation = true
            endTrip(lastLocation)
            MqttManager.instance.connectToServer()
        }
    }



func endTrip(endLoaction: CLLocation) {
        guard let statusChange = source.getStatusChange() else{return}
        var distanceTraveled: Double = 0.0
        let initialLocation = CLLocation(latitude: (statusChange.meta?.location?.lat)!, longitude: (statusChange.meta?.location?.lng)!)
        let distance = initialLocation.distance(from: endLoaction)
        distanceTraveled += distance
        let distanceInKM = Utility.convertCLLocationDistanceToKiloMeters(targetDistance: distanceTraveled)
}

How can i calculate the distance to reflect the total distance moved by the driver since there could be a change in route from the proposed start point and end point.

The driver hits a button called start trip, I want to get the distance from that moment till the moment he hits the button end trip

this implementation could be got from a similar working code like these but the only difference is that their is a start button which passes the coordinates at that point and a stop coordinate which is the end of the coordinate.

enum DistanceValue: Int {
                case meters, miles
            }

            func calculateDistanceBetweenLocations(_ firstLocation: CLLocation, secondLocation: CLLocation, valueType: DistanceValue) -> Double {
                var distance = 0.0
                let meters = firstLocation.distance(from: secondLocation)
                distance += meters
                switch valueType {
                case .meters:
                    return distance
                case .miles:
                    let miles = distance
                    return miles
                }
            }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
            if startLocation == nil {
                startLocation = locations.first
            } else if let location = locations.last {
                runDistance += lastLocation.distance(from: location)
                let calc = calculateDistanceBetweenLocations(lastLocation, secondLocation: location, valueType: .meters)

                print("TOTAL LOC 1 \(calc)")
                print("TOTAL LOC 2 \(runDistance)")
            }
            lastLocation = locations.last

        }

as shown in my print statements print("TOTAL LOC 1 \(calc)") print("TOTAL LOC 2 \(runDistance)") how can I make

calc the same with runDistance

here is what is printed in the console

TOTAL LOC 10.29331530774379
TOTAL LOC 2 10.29331530774379
TOTAL LOC 2.2655118031831587
TOTAL LOC 2 12.558827110926948
Nikunj Kumbhani
  • 3,758
  • 2
  • 26
  • 51
King
  • 1,885
  • 3
  • 27
  • 84
  • 2
    But what is your question? – Joakim Danielson Mar 08 '19 at 12:42
  • How can i calculate the distance to reflect the total distance moved by the driver – King Mar 08 '19 at 12:49
  • Isn't it just the matter of connecting location points and calculating the entire distance with `CLLocationDistance` and `CLLocationCoordinate2D`? – El Tomato Mar 08 '19 at 12:51
  • I guess you constantly need to check the current location and compare it to the previous one and add the distance to a total – Joakim Danielson Mar 08 '19 at 12:52
  • @ElTomato but how far is the trip if you drive one lap around the block? Maybe a philosophical question :) ? – Joakim Danielson Mar 08 '19 at 12:53
  • @JoakimDanielson that is the problem. A driver that is not familiar with an area could rive round the block and the distance would not count – King Mar 08 '19 at 12:59
  • I'm not sure about the app location, but apple maps don't have routes in all the countries so it's better to use google route API to calculate the total traveled route from start to the end location. You can also check the same route class in core location to calculate the trip. – Tushar Katyal Mar 08 '19 at 13:35
  • The driver hits a button called `start trip`, I want to get the distance from that moment till the moment he hits the button `end trip` – King Mar 08 '19 at 13:59
  • I don’t get what the problem is. If you have all the location points during the trip, you know the total distance traveled. Duplicate of https://stackoverflow.com/questions/44877908/how-to-calculate-the-distance-travelled-by-user-from-current-location-in-swift-3 and so on. – matt Mar 10 '19 at 15:49
  • I know the start location point, the end location point could change depending on driver or passenger. The driver could be roaming about the same point but if he returns to the exact location point for instance, the total distance traveled would be zero – King Mar 10 '19 at 15:51
  • That’s nonsense. If I drive in a big circle my travel distance is not zero. – matt Mar 10 '19 at 15:52
  • A short description from my project gives these two output from the last codes i posted TOTAL LOC 10.29331530774379 -correct TOTAL LOC 2 10.29331530774379 -correct TOTAL LOC 2.2655118031831587 -wrong TOTAL LOC 2 12.558827110926948 -correct – King Mar 10 '19 at 15:53
  • @matt exactly what my issue is. My distance should never be zero but what I have returns zero if I return back to that same coordinates irrespective of the places I passed – King Mar 10 '19 at 15:54
  • Then you are not doing what I said. You have to save all the CLLocation points from when the trip starts to when it ends. Then just total the distance from each point to the next. Done. – matt Mar 10 '19 at 15:56
  • This function is the one I implemented but gives the wrong distance `func calculateDistanceBetweenLocations(_ firstLocation: CLLocation, secondLocation: CLLocation, valueType: DistanceValue)` – King Mar 10 '19 at 15:57
  • @matt how can I do that please using some this function `func calculateDistanceBetweenLocations(_ firstLocation: CLLocation, secondLocation: CLLocation, valueType: DistanceValue)` – King Mar 10 '19 at 15:58
  • I wouldn’t use that function. I’d save all the CLLocations into an array and then sum their pair wise distances with `reduce`. – matt Mar 10 '19 at 16:00
  • @matt can you please provide code so I can mark as correct if it works. but doing like this works without storing into an array `func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) { if startLocation == nil { startLocation = locations.first as! CLLocation } else { let lastLocation = locations.last as! CLLocation let distance = startLocation.distanceFromLocation(lastLocation) startLocation = lastLocation traveledDistance += distance } }` – King Mar 10 '19 at 16:05
  • But you see that way you do not save all the individual locations in order so you get the wrong answer. – matt Mar 10 '19 at 16:23
  • yes. how do I save all the location to get the right answer – King Mar 10 '19 at 16:24
  • @King, when I made one taxi app same like your requirement, found total traveling distance click on end trip button. at that time the same thing I have done with **GMSMutablePath** and it's working fine still right now – Nikunj Kumbhani Mar 12 '19 at 05:17
  • @NikunjKumbhani can you provide codes to understand how it works and I can mark as correct – King Mar 12 '19 at 06:24
  • @King Please try my answer – Nikunj Kumbhani Mar 12 '19 at 08:56
  • @King Please check my updated answer I added the code of finding total distance of route without using the **GoogleMaps** Hope it will helps you :) – Nikunj Kumbhani Mar 12 '19 at 12:42

3 Answers3

4

If you get the distance like this using the first and last coordinate it always returns the wrong value because it can't identify the actual traveling path.

I did resolve the same issue with using the following code.

use GoogleMaps

> pod 'GoogleMaps'

Make the coordinates array while the driver is moving on a route.

var arr = [Any]() 
// Driving lat long co-ordinateds continues add in this array according to your expectation either update location or perticuler time duration.

// make GMSMutablePath of your co-ordinates
let path = GMSMutablePath()

    for obj in arr{

        print(obj)

        if let lat = (obj as? NSDictionary)?.value(forKey: PARAMETERS.LET) as? String{

            path.addLatitude(Double(lat)!, longitude: Double(((obj as? NSDictionary)?.value(forKey: PARAMETERS.LONG) as? String)!)!)

        }
    }

print(path) // Here is your traveling path
let km = GMSGeometryLength(path)
print(km) // your total traveling distance.

I did it in this app and it's working fine. Hope it will helps you :)

OR without GoogleMaps

You have to come with locations, an array of CLLocationCoordinate2D, for yourself, as per your code, though.

class ViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {
    // MARK: - Variables
    let locationManager = CLLocationManager()

    // MARK: - IBOutlet
    @IBOutlet weak var mapView: MKMapView!

    // MARK: - IBAction
    @IBAction func distanceTapped(_ sender: UIBarButtonItem) {
        let locations: [CLLocationCoordinate2D] = [...]
        var total: Double = 0.0
        for i in 0..<locations.count - 1 {
            let start = locations[i]
            let end = locations[i + 1]
            let distance = getDistance(from: start, to: end)
            total += distance
        }
        print(total)
    }

    func getDistance(from: CLLocationCoordinate2D, to: CLLocationCoordinate2D) -> CLLocationDistance {
        // By Aviel Gross
        // https://stackoverflow.com/questions/11077425/finding-distance-between-cllocationcoordinate2d-points
        let from = CLLocation(latitude: from.latitude, longitude: from.longitude)
        let to = CLLocation(latitude: to.latitude, longitude: to.longitude)
        return from.distance(from: to)
    }
}

Output

enter image description here

piet.t
  • 11,718
  • 21
  • 43
  • 52
Nikunj Kumbhani
  • 3,758
  • 2
  • 26
  • 51
0

A simple function to calculate distance (in meters) given an array of CLLocationCoordinate2D. Uses reduce instead of array iteration.

func computeDistance(from points: [CLLocationCoordinate2D]) -> Double {
    guard let first = points.first else { return 0.0 }
    var prevPoint = first
    return points.reduce(0.0) { (count, point) -> Double in
        let newCount = count + CLLocation(latitude: prevPoint.latitude, longitude: prevPoint.longitude).distance(
            from: CLLocation(latitude: point.latitude, longitude: point.longitude))
        prevPoint = point
        return newCount
    }
}
Dominic Holmes
  • 581
  • 5
  • 13
0

I like to use an extension for that

extension Array where Element: CLLocation {
    
    var distance: Double {
        guard count > 1 else { return 0 }
        var previous = self[0]
        
        return reduce(0) { (result, location) -> Double in
            let distance = location.distance(from: previous)
            previous = location
            return result + distance
        }
    }
    
}

Usage:

locations.distance
Nikaaner
  • 1,022
  • 16
  • 19