Calculate distance between two points - android

I'm making an application for tracking a user as they run, cycle or walk and display it to the screen.
I know that there is distanceBetween function built into android but is this accurate enough for a fittness application?
I was considering using Haversine formula or other such formula for calculating distances between points the only problem I see about these formulas is that it usually is straight line or as the crow flys distances.
Does anyone have an idea about this?

The Haversine formula is accurate for most distances, but it suffers from rounding errors when the points are (nearly) antipodal. The following formula is accurate for all distances.
> double delta = G1 - G2;
> double p1 = cos(L2) * sin(delta);
> double p2 = cos(L1) * sin(L2) - sin(L1) * cos(L2) * cos(delta);
> double p3 = sin(L1) * sin(L2) + cos(L1) * cos(L2) * cos(delta);
> distance = 60 * Math.atan2(Math.sqrt(p1*p1 + p2*p2), p3);
Here's an example and the implementation.
resource : Here

Tracking their route as they walk is going to involve a series of way points. If you sample at say 1 way point every 10 seconds then you can calculate the distance between the previous point and the new point using either a crow-flys technique like haversine or just make some webservice requests to an external service like google maps and their distance matrix which can give you the snapped-to-streets distance between 2 points using suggested best path.
http://code.google.com/apis/maps/documentation/distancematrix/
You just have to make sure that your sample rate isn't too high or you can go over the 2500 API calls/24-hour-period rate limiter (which is per IP I believe). But 2500 will give you 7 hours at 1 sample per 10 seconds, or you can try a lower rate like 1 per 35 seconds and risk having the route be guessed wrong, but guarantee that your device won't go over 2500 samples.
Personally, if location polling is free, I would just go with distanceBetween and poll every 1-2 seconds. That should be short enough that the accuracy of GPS becomes your biggest source of error.

Related

Find movement turn angle using Location

I need find angle of vehicle turn measured in degrees.
Location points update with equal intervals (1 sec). Therefore device makes like 4-5 points during turn. I schematically displayed that on picture.
Is it possible to calculate the angle of turn using Location? If it is possible, how?
What I tried:
Create two geometric vectors from points 3, 4 and 1, 2 respectively and find angle between those vectors. Coordinates of vectors I calculated like Vector1 (lat2 - lat1; lon2 - lon2). Not sure this approach could be applied to Location coordinates.
Use location1.bearingTo(location2). But this doesn't give expected results. Seems like it gives "compass" results. Perhabs I could use it somehow but not sure.
Also tried few trigonometric formulas like here or here or here. They didn't give expected angle.
EDIT: Solution
The accepted answer works great. But to complete the answer I have to show that method of angleDifference. This one works for me:
public int getAngleDifference(int currentAngle){
int r = 0;
angleList.add(currentAngle);
if (angleList.size() == 4) {
int d = Math.abs(angleList.get(0) - angleList.get(3)) % 360;
r = d > 180 ? 360 - d : d;
angleList.clear();
}
return r;
}
I add points to list untill there're 4 of them and then calculate angle difference between 1st and 4th points for better results.
Hope it will help for someone!
vect1 = LatLon2 - LatLon1; // vector subtraction
vect2 = LatLon4 - LatLon3;
By definition of the dot product has the property:
vect1.vect2 = ||vect1||*||vect2||*Cos(theta)
Here's a breakdown of the notation
The term vect1.vect2 is the dot product of vect1 and vect2.
The general form of a dot product can be broken down component wise let v1 = <x1,y1> and v2=<x2,y2> for two arbitrary vectors v1 and v2 the dot product would be:
v1.v2 = x1*x2 + y1*y2
and the magnitude of some arbitrary vector v is:
||v|| = sqrt(v.v); which is a scalar.
The above is equivalent to the Euclidean distance formula with components x and y:
||v|| = sqrt(x^2 + y^2)
Getting the angle
Find a value for theta given the two vectors vect1 and vect2:
theta = Math.ArcCos(vect1.vect2/(||vect1||*||vect2||))
Approach 1 does not work as you described: Lat, Lon are not cartesian coordinates (One degree of longitude expressed in meters is not one degree of latitide, this is only valid at the equator). You would have first to transform to a (local) cartesian system.
An error is in the drawing: The angle marked with "?" is placed at the wrong side. You most probably want angle: 180 - ?
In your example the car ist turning less than 90°, altough your angle shows more than 90°.
To understand better make another drawing where the car turns left for only 10 degrees. In your drawing this would be 170°, which is wrong.
Approach 2) works better, but you need to sum up the angle differences.
You have to write yourself a method
double angleDifference(double angle1, double angle2);
This look easier than it is, although the code is only a few lines long.
Make sure that you have some test cases that tests the behaviour when crossing the 360° limit.
Example
(turn from bearing 10 to bearing 350), should either give 20 or -20, depending if you want that the method give sthe absolut evalue or the relative angle

GMaps: Crazy values for computeDistanceBetween in android?

I'm using google.maps.geometry.spherical.computeDistanceBetween() to compute the distance between relatively close points (10-30 meters). This works perfectly in Linux (Chrome and Firefox), but sometimes gives me crazy results in Android. One case that I got was with this:
var p1 = new google.maps.LatLng(-22.960584,-43.206687999999986);
var p2 = new google.maps.LatLng(-22.960584,-43.206939000000034);
alert(google.maps.geometry.spherical.computeDistanceBetween(p1,p2));
It should give 25 meters or so, yet once I got hundred of thousands of meters. Again, it is not always that I get crazy values, just "sometimes", probably related with lots of computations?
Is this a well known bug? If it is, I cannot use this method and would have to make my own.
Thanks,
L.
As far as I can tell, this is an Android bug. I think this could very well explain why in the MyTracks app I usually get randomly points in other continents and huge distances.
I computed the distance function with the method below, and now I always get the correct values. In particular, if this is what it looks, this is a very serious bug for Android app that uses this function.
In case anyone cares, this is the distance function between to LatLng p and q:
function dist(p,q) {
var c = Math.PI/180;
// Google (gives randomly wrong results in Android!)
//return google.maps.geometry.spherical.computeDistanceBetween(p,q);
// Chord
//return 9019995.5222 * Math.sqrt((1-Math.cos(c*(p.lat()-q.lat())))
// + (1-Math.cos(c*(p.lng()-q.lng()))) * Math.cos(c*p.lat()) * Math.cos(c*q.lat()));
// Taylor for chord
return 111318.845 * Math.sqrt(Math.pow(p.lat()-q.lat(),2)
+ Math.pow(p.lng()-q.lng(),2) * Math.cos(c*p.lat()) * Math.cos(c*q.lat()));
}
Notice that these are the computations for the chord, that is, the distance in R^3, not the geodesic distance in the sphere. Certainly more than enough for hiking/car travel computations using GPS. I ended up using the Taylor expansion since it is precise to 1/10 mm, and less tough with the CPU.

Check if device is really moving

I am working on an application where I need to get the speed of a car. To get the speed, I know I can use something like double speed =locationB.getSpeed();` however when I am testing, the speed varies between 0.0 and 40 km/h when I am just sitting right behind my laptop not moving at all. In the car, the speed actually comes close to the cars speed, so that shouldn't be a problem.
What would be the best way to check if the device is really moving? I've already tried to get the distance between locationA and locationB and use that with the time it took to get the 2 locations, to get the speed.
double distance = locationA.distanceTo(locationB);
double speed = (distance / time) * 3600 / 1000;
However this seems to be not stable at all, like the getSpeed() method.
Is there a way to only display the speed if the device is moving? And would it be reliable?
Any help is appreciated,
Thanks.
Check the horicontal accuracy attribute of Location.
If it is under 30m you can ignore the location.
If you are sitting on your laptop and get speed = 40km/h (which I never saw in good GPS devices), then look what the hor. accuracy is.
It probably is much over 30m.
In GPS based systems, never ever calculate the speed by positional change in time,
just use the location.getSpeed().
The reason is that the GPS chip internally calculates the speed via physical doppler effect, not via positional change.
While standing still, or at very low speeds this does not work well, so you have to filter out very low speeds, and bad gps signal. (via horicontal accuracy estimate)
I think you should limit the distance between A and B to be a minimum length. Small distances will introduce more error into your speed calculations.
Boolean moving - false;
double distance = locationA.distanceTo(locationB);
double speed = (distance / time) * 3600 / 1000;
if (distance > SOME_THRESHOLD) {
moving = true
}

gps speed compensation of location

I am using GPS with Android and need to have the location compensated for speed to remove the error due to the lag of the calculation of location. My speeds of interest are in the 5 to 10 mph range as this is for a sailboat.
Here is my code:
public double[] correctLocation(double pLat,double pLong,double pAngle,double pSpeed, double factor){
double[] latLong = new double[2];
latLong[0] = pLat + factor * pSpeed * Math.cos(pAngle * Math.PI / 180);
latLong[1] = pLong + factor * pSpeed * Math.sin(pAngle * Math.PI / 180) / Math.cos(pLat * Math.PI / 180);
return latLong;
}
I did a test run at 25mph in a car and calculated that the factor should be 3E-6 but in trying it out at running and walking speed it is clear that a factor more like 6E-6 is needed. I can't find any references to this through Google although I know people do this for example in the Google self driving car. I assume others do these kind of corrections.
Can anyone help me out here? The GPS is a Qstarz A1000XT with a MTK chipset. There are probable things I am missing with this simplistic approach. (I am assuming I don't need acceleration as this is a heavy boat with a 1 minute time constant for acceleration).
The 6E-6 was correct. I had a couple of errors and was confused for some time on this. I ended up testing by traveling at a spot from both directions at 25MPH and pinging the spot. I interpolated between GPS readings so that the timing and update rate were not a factor. I did this 10 times. That gave me two clusters of points and using a graphical method I adjusted the correction factor until the clusters overlapped. An alternate method is to use the difference in latitude and longitude between the last two readings, which are 1 second apart, and apply a correction factor in seconds. In my case that was 1.25 seconds. Both methods produced the same result in terms of the clusters. The speed correction was a tad closer in the scatter but not by much. Speed on GPS is measured off the carrier and not derived from differences in position and is more accurate.

Calculating speed from 2 points

I know this question has been asked a lot, but not yet to my satisfaction. I am trying to use the GPS of an Android device to calculate speed. A lot of people seem to reply by saying to simply use the getSpeed() function of the Location object. From what I understand though, getSpeed() will only work on certain devices that have a speed sensor built into the GPS receiver chip. I want my application to work regardless of this, so I am using the following haversine formula:
private double CalculateHaversineMI(double lat1, double long1, double lat2,double long2) {
double dlong = (long2 - long1) * (Math.PI / 180.0f);
double dlat = (lat2 - lat1) * (Math.PI / 180.0f);
double a = Math.pow(Math.sin(dlat / 2.0), 2)
+ Math.cos(lat1 * (Math.PI / 180.0f))
* Math.cos(lat2 * (Math.PI / 180.0f))
* Math.pow(Math.sin(dlong / 2.0), 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double d = 3956 * c;
return d;
}
Now what I'm trying to do is figure out how to calculate speed from this. Can anyone help me please?
What I can see is that your function returns correct path distance between 2 points on a sphere - it is d. But, this formula is needed only if you have 2 points on a sphere that are not close to each other (means central angle of their separation is not small, central angle of 1 degree corresponds to distance of 111 km approx, just to get feeling). If they are close to each other (which is the case for people moving and slow speed vehicles), then you do not need this formula. You can simply and very accurately approximate arc on the sphere with the straight line, and then calculation becomes trivial.
Sample GPS position at regular time periods. Calculate distance from the last position obtained. For that purpose you may use distanceTo() function from android.location.Location.
Calculate speed by dividing distance with time elapsed between 2 measurements.
Average calculated speeds for more accurate results, but ensure that you do not lose sensitivity to speed changes. So, you would need some trade-off on number of samples averaged.
That calculates the distance. Now as you may recall, speed = distance / time, so somewhere along the line you need to capture the time as well as the position.
On another note, the formula that you are using is way OTT for what you are trying to do. You would be better off making a number of approximations based on the fact that the path you are traversing is much less than the circumference of the earth. Then you could arrive at a much simpler formula.

Categories

Resources