39

I want to calculate actual distance traveled by mobile (iOS and Android). I know through google map API, we can find optimum route distance between 2 coordinates. But I want to calculate distance, actual path mobile(in vehicle) has covered.

One Algo I came to know is saving coordinates after x seconds, lets say after 5 or 10 seconds, and then calculate distance between consecutive coordinates, and there sum will give total distance.

I want to discuss better approach of its solution , Is there any better solution?

Edit : How Apps like Nike running app and Uber works?

Haris
  • 1,822
  • 2
  • 22
  • 44
  • 2
    I believe that what you suggest for GPS tracking is the best solution for now. Giving smaller gaps than 5 sec will give a more accurate result for this. – gerardnimo Jan 03 '16 at 08:09
  • 1
    Let say I want to go office from home, it should calculate distance of path I went through, weather I took longer path or shorter. – Haris Jan 03 '16 at 09:48
  • 1
    Apps like Nike and Uber sample the GPS continually – Srikanth K. Jan 08 '16 at 23:10
  • 1
    @srikanthk how they do that? by getting lat,long every x seconds ? and calculating distances ? – Haris Jan 08 '16 at 23:21
  • Yes. They get lat/long every often enough and just compute distances between adjacent points. – Srikanth K. Jan 14 '16 at 22:03
  • @Haris Got any concrete answer? – VishalKale May 21 '16 at 16:34
  • @VishalKale I can't say yet there is one definite answer. but there are methods and strategies which can improve accuracy and you can see them in comments. – Haris May 22 '16 at 13:08

10 Answers10

23

------------------UPDATE----------------------

There is two major point in your question.

1) get the phone coordinates (which has been treated in the first part of this response)

2) Calculate the real distance between this two coordinates

IMHO, calculus could be done by a web service: calculation based only on the distance between two coordinates can lead to really wrong result.

Here is an exemple of such a web service https://graphhopper.com/#directions-api

The demo app: https://graphhopper.com/api/1/examples/

It's based on traffic flow (as many of this tools) So you have to be careful with the order of the coordinates because it can bring wrong result.

For exemple with two point in the right order: enter image description here

This gives a good result

But if you give wrong order (with the same coordinates) enter image description here

For the same coordinates, it can lead to an extremely different result.

So for coordinates ABCD (in chrnological order) you need to do:

A->B B->C C->D

Graphhopper seems able to do offline distance calculus

Here are the lib on iOS and Android

https://github.com/graphhopper/graphhopper-ios/

https://github.com/graphhopper/graphhopper/tree/master/android

---------------------------------------------------

You have to define how your app work. Foreground or background?

As said in other responses, you'll have to get the user position every X seconds. Then calculate the distance.

For iOS:

  1. You can use information on this website: http://mobileoop.com/

It talks about tracking user location on iOS when the app is in background.

  1. Here is the github: https://github.com/voyage11/Location

Then you have to convert the point thanks to

CLLocationDistance distance = [aCLLocationA distanceFromLocation:aCLLocationB];

You can also check this (from apple doc) https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/LocationAwarenessPG/CoreLocation/CoreLocation.html:

Make sure the location manager’s pausesLocationUpdatesAutomatically property is set to YES. When this property is set to YES, Core Location pauses location updates (and powers down the location hardware) whenever it makes sense to do so, such as when the user is unlikely to be moving anyway. (Core Location also pauses updates when it can’t obtain a location fix.)

Assign an appropriate value to the location manager’s activityType property. The value in this property helps the location manager determine when it is safe to pause location updates. For an app that provides turn-by-turn automobile navigation, setting the property to CLActivityTypeAutomotiveNavigation causes the location manager to pause events only when the user does not move a significant distance over a period of time.

CLActivityTypeAutomotiveNavigation insure you to get a position which is on a road.

For Android:

  1. You can use this project: https://github.com/quentin7b/android-location-tracker

That can easily helps you to get the user's position thru time Thanks to the TrackerSettings object

TrackerSettings settings =
        new TrackerSettings()
            .setUseGPS(true)
            .setUseNetwork(true)
            .setUsePassive(true)
            .setTimeBetweenUpdates(30 * 60 * 1000)
            .setMetersBetweenUpdates(100);
  1. To find the distance between two point on Android, you can check this: Get the distance between two geo points

Both OS

Based on a position picked up every X second you have to reduce time between picking location data to improve accuracy.

As you want to calculate distance on a road context, setup the Location manager in navigation mode, this mode gives you coordinates that are on road.

Finally

If you want to improve the accuracy of your distance calculus, you can use a google API: https://developers.google.com/maps/documentation/distance-matrix/intro

By setting the right mode parameter:

Optional parameters

mode (defaults to driving) — Specifies the mode of transport to use when calculating distance. Valid values and other request details are specified in the Travel Modes section of this document.

Community
  • 1
  • 1
Alban
  • 1,624
  • 11
  • 21
  • Also have a look at the map matching component from GraphHopper: https://github.com/graphhopper/map-matching – Karussell Jun 15 '16 at 20:11
  • 1
    @Alban thanks. Earlier I tried calculating distance traveled using Google Map way points API. Problem is moving device in a car sometimes gives inaccurate location. Say, on the wrong side of a small road. This disrupts the distance calculation as route registered is incorrect. Any idea about how well the location accuracy is factored in above mentioned libraries? – Ruturaj Patil Jun 22 '16 at 06:25
10

I'm working on something similar on Andoriod, but the principals are the same for iOS either:

  1. For each GPS sample, check its accuracy. If it's over some threshold (say 20 meters) - ignore it.
  2. Remember that even if the mobile device is static, different GPS samples will give you different locations, depending on the accuracy. A car standing still for a long time in a traffic light, will show that you've advanced few dozens of meters, so add a method that detects if the mobile is static or not. I've implemented this by reading the accelerometer - if the delta between two readings if bigger than some threshold - the device is moving. If it's too small - ignore the GPS.
  3. If you intend to use it in a car, you can read the GPS whenever it has a new reading (in Android use the onLocationChanged method). If you use it for running/walking, take into account that your speed is slow - two consecutive readings will be relativly close, but due to the GPS's accuracy, you can get quite a large distance betwwen them. It can be fixed by increasing the time between two consecutive readings, or by ignoring some of them (i.e. take into account only each 10th reading).
  4. Use the Haversine formula to calculate the distance between two consecutive readings. In Android it can be done with the Location.distanceTo() method.

You'll have to test it against the odometer in your car and adjust the thresholds for the accelerometer.

TDG
  • 5,909
  • 3
  • 30
  • 51
7

You can achieve more accuracy with a combination of the following strategies.

  1. As mentioned in other Answers, you can store the position of the mobile every X seconds(say 10 seconds) using GPS and measure the consecutive time between the points.

  2. Also when the user makes quick turns, make sure to read that by using Magnetic Sensor values too, so in such event, decrease the "timing between position storing" to say 1-2 seconds(Will be needed for accuracy)

  3. As a final step, use Map data(such as Google Maps etc.) to make sure you are being tracked properly(if on road).

And then sum up all the values to get the accurate distance.

P.S. I gave information about the strategies alone since I'm not sure about its implementation in Android(or iOS).

Hope this helps :)

Snazzy Sanoj
  • 804
  • 1
  • 11
  • 28
  • Could you elaborate part 2. of your answer? How can i detect that the user is making "quick turns"? Thanks in advance – Royz Mar 22 '18 at 08:13
  • 1
    Check @Alban answer for more details on sharp turn stuff https://stackoverflow.com/a/34596071/3831833 – Snazzy Sanoj Mar 23 '18 at 11:56
7

4 years ago, I just made an app called Landsurvayor that calculates the actual distance of two geo-graphical points drawn on Google Map. I don't know that might help you or not but there is a formula called Haversine formula that calculates the actual distance between two geo-graphical points. You might give it a try and see whether it is useful for you or not. Below is the sample code of Haversine formula:

public double CalculationByDistance(double initialLat, double initialLong,
                            double finalLat, double finalLong){
int R = 6371; // km
double dLat = toRadians(finalLat-initialLat);
double dLon = toRadians(finalLong-initialLong);
lat1 = toRadians(lat1);
lat2 = toRadians(lat2);

double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
        Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2); 
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
return R * c;
}

public double toRadians(deg) {
  return deg * (Math.PI/180)
}

More about Haversine formula: https://en.wikipedia.org/wiki/Haversine_formula

There is another simple Android SDK built-in approach to calculate distance between two lat, lng:

Location locationA = new Location("point A");     
locationA.setLatitude(latA); 
locationA.setLongitude(lngA);
Location locationB = new Location("point B");
locationB.setLatitude(latB); 
LocationB.setLongitude(lngB);
distance = locationA.distanceTo(locationB) ;

I hope it might help you.

Geeky Singh
  • 1,003
  • 9
  • 20
4

One problem with using GPS coordinates is that they (obviously) are not accurate. If you are travelling in a straight line, the GPS coordinates might show you travelling on a zig-zag path, hence returning a greater distance travelled than the true distance. Even with good GPS accuracy this error can be significant. Using less coordinates could result in a more accurate calculation, or not.

What you need is a way to smooth the GPS path plotted, with due consideration to your required accuracy (again a trade-off).

My first thought is to break the points into groups, and fit line segments to each group (look up "linear regression"). Then find where each consecutive line-pair overlap to define each line segment. Then simply sum the line segment lengths.

You could curve-fit segments, but that's much more intense mathematically, and might not yield a better result (and which curve formula to use?). There may be better mathematical ways I'm not aware of.

Hope this helps.

John Cook
  • 117
  • 3
3

If you are looking for exact (or nearly exact) distance information, you need to track the path followed, which means checking coordinates every few seconds (depending upon expected speed traveled). You can save space by discarding the old coordinates after calculating each segment and just storing current distance traveled.

Calteran
  • 1,063
  • 8
  • 12
3

Android :: how to calculate distance while walking in android?

There are different ways to do this:

1.GPS: Keep adding GPS distance between 2 points every X seconds (say 10 sec). Check Android Location.distanceTo or distanceBetween. Check My Tracks app, it is open source. GPS is not available indoors and would have error if user is changing direction very frequently (read every 1-2 second) 2.Accelerometer: Look for code/library for step detection using accelerometer. Distance comes from double integration of acceleration, errors can add up very quickly here. 3.Step detector: Built-in in Nexus 5. Google must have taken care of accelerometer errors to extent possible. This is hardware-based computation, consumes less battery but not available in most of handsets as of date.

The 2nd option seem very similar to what you suggested and I do think its the best way to achieve it since iOS and Android defer in code and in functionality therefor the best method to achieve it is saving currentLocation and previousLocation in a while loop that will .sleep() and just sum the entire loop as the distance traveled. the bigger question is this supposedly app is a distance summerizing app? does it just a small function inside of it? how do you decide when to stop calculating the distance?

Community
  • 1
  • 1
Daniel Netzer
  • 2,151
  • 14
  • 22
3

If accuracy is critical, you can use data from accelerometer and gyroscope. You can find very simple formula for solving simple cinematic task so you get acc in global axis. Than you just have to use integral twice (first to get velocity, than to get position). Just to show another perspective.

muminers
  • 1,190
  • 10
  • 19
2

Use GPS to get lat lon of both places and after getting both pass it below method.Its will return distance in km

public static double getDistanceFromLatLonInKm(double lat1, double lon1,
        double lat2, double lon2) {



    double R = 6371; // Radius of the earth in km
    double dLat = deg2rad(lat2 - lat1); // deg2rad below
    double dLon = deg2rad(lon2 - lon1);
    double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
            + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2))
            * Math.sin(dLon / 2) * Math.sin(dLon / 2);
    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    double d = R * c; // Distance in km


    return d;

}

public static double deg2rad(double deg) {
    return deg * (Math.PI / 180);
}

}

Jotiram Chavan
  • 375
  • 1
  • 8
  • Your method is actually the Haversine formula. It is implemented in android's Location class, so there is no need to re--code it... – TDG Jan 09 '16 at 20:42
2

Log points every x seconds (maybe 2-3?) and use distance formula below for every point logged.

Distance = sqrt((x2−x1)^2+(y2−y1)^2)

Sum them all up and you get distance

lawonga
  • 832
  • 10
  • 20
  • 4
    This is the Euclidian distance, not the total distance you pass from point A to point B. For short paths it may do the job, but for longer paths it is not accurate. – TDG Jan 08 '16 at 18:20