I am trying to write a simple application which uses Google Maps V2 API in android.
In a timer I am reading the lat long values from the googleMap mylocation function.
altitude = googleMap.getMyLocation().getAltitude();
latitude = googleMap.getMyLocation().getLatitude();
longitude = googleMap.getMyLocation().getLongitude();
I Plotted the lat,long using addPolyline() method.
The problem I am facing is while walking on road with this app in foreground, I was walking in straight line but the plot was going in nearby buildings. I have ensured that 2 lat,longs are at a distance of 10m.
I use the formula,
public double calcDistance(double lat1, double lng1, double lat2,
double lng2) {
int r = 6371; // average radius of the earth in km
double dLat = Math.toRadians(lat2 - lat1);
double dLon = Math.toRadians(lng2 - lng1);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
+ Math.cos(Math.toRadians(lat1))
* Math.cos(Math.toRadians(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;
return d;
}
Questions
- How to get a straight line, how to get the accurancy or margin or error so that while walking on road I dont get into buildings
There are errors in maps and there are errors in GPS readings. Nearby big buildings will increase the errors in GPS readings due to blocked satellites and multipath from visible satellites. You might want to consider limiting your initial experiments to areas without buildings.
Concerning straight lines, if you are fortunate enough to have the map data, you could project the GPS readings to their closest points on the road.
If you are relying solely on you location returned from a LocationManager of google maps location and then plotting off that you will get points that are off sometimes due to a bad GPS lock, there really isnt anything you can do about that. You are more than welcome to not use the google maps location and use the Fused location API to try to get better results.
Google maps API does not provide nodes for roads so it is nearly impossible to tell how far away a point is from the road to try to straighten it out
Related
Is it possible to track the speed and the acceleration through an android app using the GPS data it provides? I'm planning to create a react native app with these features. But I want to know whether it's possible to do it with the data we can get. Even in native android?
You can do it in pure JS.
For the speed part you have the core React Native Geolocation API where you can find the method watchPosition. On each position update, an object is returned with the current speed amongst other attributes (location, altitude...).
For the acceleration part you have the react-native-motion-manager library. You can listen to the accelerometer updates and get the acceleration.
Is it possible to track the speed and the acceleration through an
android app using the GPS data it provides?
Answer: yes
location.getSpeed() only returns what was set with
location.setSpeed(). This is a value that you can set for a location
object.
To calculate the speed using GPS, you'll have to do a little math:
Speed = distance / time
so how to do that
(currentGPSPoint - lastGPSPoint) / (time between GPS points)
Each location provided by all LocationProviders has the instant speed at the point where the location was taken, which is unstable and it can differ between devices. The average speed is more precise, you have to calculate distance and time. This is how I calculate distance between 2 locations:
static double distance (Location in1, Location in2) {
double R = 6371000;
double la1 = in1.getLatitude()* Math.PI/180;
double la2 = in2.getLatitude()* Math.PI/180;
double lo1 = in1.getLongitude()* Math.PI/180;
double lo2 = in2.getLongitude()* Math.PI/180;
double tmp1 = Math.sin((la1-la2)/2)*Math.sin((la1-la2)/2) + Math.cos(la1)*Math.cos(la2) * Math.sin((lo1-lo2)/2) * Math.sin((lo1-lo2)/2);
double tmp2 = Math.sqrt(tmp1);
double d = Math.abs(2 * R * Math.asin(tmp2) * 100000) / 100000;
return d;
}
You can use this function as well, but I'd rather use the other one, which stores the result in "results" :)
Location.distanceBetween(in1.getLatitude(),in1.getLongitude(),in2.getLatitude(),in2.getLongitude(),results);
So getting the speed in m/s (that's the 1000* for) is quite straightforward:
double avgSpeed = 1000 * distance(loc1,loc2) / (loc2.getTime()-loc1.getTime)
I am developing an app which is more of a time-shift racing between your friends.
I need to calculate speed of a moving vehicle, and I don't want to use Location.getSpeed() method. (Explained in detail in the bottom why I don't want to use it)
I am trying to calculate speed with the help of Latitude and Longitude available to me, and this is where I need help.
The help needed: I would want to know is:
If the algorithm is correct
Should I calculate in Centimeters instead of meters
And if there's any code/library already available which does it.
I am using the following code:
This gives me distance between two LatLng points:
long getDistanceBetweenPoints(double lat1, double lng1, double lat2, double lng2 ){
double dLat = Math.toRadians(lat2 - lat1);
double dLon = Math.toRadians(lng2 - lng1);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
+ Math.cos(Math.toRadians(lat1))
* Math.cos(Math.toRadians(lat2)) * Math.sin(dLon / 2)
* Math.sin(dLon / 2);
double c = 2 * Math.asin(Math.sqrt(a));
long distanceInMeters = Math.round(6371000 * c);
return distanceInMeters;
}
And the following code is how it is being used:
if(lastLat == -1 && lastLng == -1){
lastLat = location.getLatitude();
lastLng = location.getLongitude();
lastTimeStamp = location.getTime();
return;
}
long distanceInMeters = getDistanceBetweenPointsAndSetTotal(lastLat, lastLng, location.getLatitude(), location.getLongitude());
long timeDelta = (location.getTime() - lastTimeStamp)/1000;
long speed = 0;
if(timeDelta > 0){
speed = (distanceInMeters/timeDelta);
}
Log.d("Calculations","Distance: "+distanceInMeters+", TimeDelta: "+timeDelta+" seconds"+",speed: "+speed+" Accuracy: "+location.getAccuracy());
lastLat = location.getLatitude();
lastLng = location.getLongitude();
lastTimeStamp = location.getTime();
When I run it, I get following output from that LogCat:
Distance: 0, TimeDelta: 0 seconds,speed: 0 Accuracy: 5.0
Detailed Reasons
The target consumers are not supposed to have high quality devices with high-quality GPS chips, thus always getting a very accurate fix when the device is on the move is not possible.
I thus don't want to depend on the Location.getSpeed() method, since I have observed it gives out speed values only when the accuracy is in the range of 5~8 metres.
The normal accuracy ranges I am getting in general circumstances is 10-15 metres, and getSpeed() doesn't give any speed. Even hasSpeed() starts returning false.
I have been tinkering my head around this thing for more than 3 days, any help in this would be deeply appreciated.
Much Thanks in Advance!
I develop MyTrails, an Android mapping and tracking app, and like you I struggled at first with the very crude location APIs Google has seen fit to include in Android.
hasSpeed() is false when the GPS chip doesn't have a good enough fix to compute speed based on dopler effect. Even when it does, I usually don't trust the speed if it's less than 5km/h or thereabouts.
The way I handle speed calculations is by using a crude low-pass filter: I record a trackpoint every second (and a minimum of 5m apart, based on LocationManager.requestLocationUpdates(), and to calculate the recent speed, I go back a few samples to get one that is a sufficient distance apart (but no more than 30s prior), and perform the averaging you're doing.
I'm using Location.distanceBetween() for the actual distance calculation. Beware that it fails on a very small (but unfortunate) number of devices, so the haversine method you have may be a better bet. You may want to check it though, what I have is
/**
* Gets distance in meters, coordinates in RADIAN
*/
private static double getDistance(double lat1, double lon1, double lat2, double lon2) {
double R = 6371000; // for haversine use R = 6372.8 km instead of 6371 km
double dLat = lat2 - lat1;
double dLon = lon2 - lon1;
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(lat1) * Math.cos(lat2) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
//double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
return 2 * R * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
// simplify haversine:
//return 2 * R * 1000 * Math.asin(Math.sqrt(a));
}
(note the 1000 factor)
I agree with Pierre, also you are rounding the results. If the points are not far enough apart, you're rounding may just provide 0. I don't see how the rounding tolerance is defined.
I always calculate in meters - it makes things much easier. I'd suggest following the SI standard units in your code.
Your output also shows that the timeDelta is zero, so no distance was actually calculated.
Omg.....
Location
Check this method - it allows you to calculate distance between 2 geo points, just divide it by your time. It should be much more accurate than yours as it calculates distances with much better approximation (WGS83 instead of using sin, cos and rest of this stuff).
Good, general idea is to keep all your data in plain units like m, s, kg etc. and make changes only for showing data to user.
If the algorithm is correct?
The distance calculation looks like the haversine formula which is correct.
(There are much faster formulas for small distances (and you only use small distances), but haversine will work)
Should I calculate in Centimeters instead of meters?
Never use centimeter, stay with SI units, the unit of speed is meter/s. just use meter as floating point (double).
Ios, where I am developping a tracking App, seems to be more friendly related to the getSpeed() nethod from Location class.
But I (again?) warn you to use speeds at slow speed. If you get an invalid speed, then just stop calculation or mark it as invalid in your app.
If the GPS chip cannot deliver a valid speed, it has good reason to do so, and it's an interesting question whether you will do it better.
At low speed GPS tends to randomly jump around the true position, giving 5-30m jumps.
It's very likely that your self calculated speed shows much more speed that the device is (not) moving.
Try to fix your app, that it does not need speeds at low speeds.
I'am trying to measure the distance between two coordinates, i've implemented the haversine function, just like this:
package Services;
public class Route {
private double latitude1;
private double longitude1;
private double latitude2;
private double longitude2;
public Route(double latitude1, double longitude1, double latitude2, double longitude2) {
this.latitude1 = latitude1;
this.longitude1 = longitude1;
this.latitude2 = latitude2;
this.longitude2 = longitude2;
}
public double measureDistance() {
double earthRadius = 3958.75;
double dLat = Math.toRadians(latitude2-latitude1);
double dLng = Math.toRadians(longitude2-longitude1);
double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(Math.toRadians(latitude1)) * Math.cos(Math.toRadians(latitude2)) *
Math.sin(dLng/2) * Math.sin(dLng/2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
double dist = earthRadius * c;
return dist;
}
}
The code works fine and ouputting something. But as I use the haversine formula, the code just measure the distance in skyline, not the roads if you know what I mean. Is there any possible way to measure distance like google maps does? Without using the google maps API, suddly google takes cash after 2500 API calls in a day or something..
Google Maps API pricing basically only affects web maps: http://code.google.com/apis/maps/faq.html#usage_apis
Google Maps for Android API is still free.
OTOH, there is no routing or navigation functionality in Google Maps for Android, so there is no way to calculate route distance with this API.
Also, you might find this handy: Geographical distance
You should try the Bing Maps Android SDK. They don't have an explicit usage quota.
Bing Maps does have a usage quota, however this does not apply for mobile apps. Bing Maps is definatelty worth looking into. You can use Bing Maps with Android in one of two ways. The first is to use the Bing Maps Android SDK: http://bingmapsandroidsdk.codeplex.com/
The second is to use Bing Maps V7 AJAX control with PhoneGap.
I tried to do with BearingTo(), but i don't know how to use it. myLocation.bearingTo(BuildingLocation) gives me 0º if i am facing the Building and North direction, gives me 90º if i am facing the Building and East Direction, gives me -180º if i am facing the Building and South direction. Then bearingTo doesn't works for my needs.
I need to do that because i need to calculate when the phone camera is facing the object...
Try this link:
http://www.movable-type.co.uk/scripts/latlong.html
Edit-- This would be the example, use locations or get the long/lat in other ways
Location destination;
Location from;
double dLon = Math.abs(destination.getLongitude()-from.getLongitude()); //Delta Longitude
double y = Math.sin(dLon) * Math.cos(destination.getLatitude());
double x = Math.cos(from.getLatitude())*Math.sin(destination.getLatitude()) -
Math.sin(from.getLatitude())*Math.cos(destination.getLatitude())*Math.cos(dLon);
double brng = Math.atan2(y, x);
double brngdegrees = Math.toDegrees(brng);
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.