android - how can I get the bearing degree between two locations? - android

As title said, I have current location, and want to know the bearing in degree from my current location to other location. I have read this post, is the value return by location.getBearing() my answer?
Let say it simply: from the picture, I expect the value of 45 degree.

I was having trouble doing this and managed to figure it out converting the C? approach to working out the bearing degree.
I worked this out using 4 coordinate points
Start Latitude
Start Longitude
End Latitude
End Longitude
Here's the code:
protected double bearing(double startLat, double startLng, double endLat, double endLng){
double latitude1 = Math.toRadians(startLat);
double latitude2 = Math.toRadians(endLat);
double longDiff= Math.toRadians(endLng - startLng);
double y= Math.sin(longDiff)*Math.cos(latitude2);
double x=Math.cos(latitude1)*Math.sin(latitude2)-Math.sin(latitude1)*Math.cos(latitude2)*Math.cos(longDiff);
return (Math.toDegrees(Math.atan2(y, x))+360)%360;
}
Just change the variable names were needed.
Output bearing to a TextView
Hope it helped!

Location have method bearingTo:
float bearingTo(Location dest)
Location from = new Location(LocationManager.GPS_PROVIDER);
Location to = new Location(LocationManager.GPS_PROVIDER);
from.setLatitude(0);
from.setLongitude(0);
to.setLongitude(10);
to.setLatitude(10);
float bearingTo = from.bearingTo(to);

Here is the code for calculating bearing angle between two points(startPoint, endPoint):
public float CalculateBearingAngle(double startLatitude,double startLongitude, double endLatitude, double endLongitude){
double Phi1 = Math.toRadians(startLatitude);
double Phi2 = Math.toRadians(endLatitude);
double DeltaLambda = Math.toRadians(endLongitude - startLongitude);
double Theta = atan2((sin(DeltaLambda)*cos(Phi2)) , (cos(Phi1)*sin(Phi2) - sin(Phi1)*cos(Phi2)*cos(DeltaLambda)));
return (float)Math.toDegrees(Theta);
}
Call for function:
float angle = CalculateBearingAngle(startLatitude, startLongitude, endLatitude, endLongitude);

I found best method for calculating "Bearing between two point " from this answer and convert it to java from python. And this method work like charm for me!
here is the code:
public static double getBearing(double startLat, double startLng, double endLat, double endLng) {
double latitude1 = Math.toRadians(startLat);
double longitude1 = Math.toRadians(-startLng);
double latitude2 = Math.toRadians(endLat);
double longitude2 = Math.toRadians(-endLng);
double dLong = longitude2 - longitude1;
double dPhi = Math.log(Math.tan(latitude2 / 2.0 + Math.PI / 4.0) / Math.tan(latitude1 / 2.0 + Math.PI / 4.0));
if (abs(dLong) > Math.PI)
if (dLong > 0.0)
dLong = -(2.0 * Math.PI - dLong);
else
dLong = (2.0 * Math.PI + dLong);
return (Math.toDegrees(Math.atan2(dLong, dPhi)) + 360.0) % 360.0;
}

Related

How to get all possible latitude and longitude based specific distance from location

I want to restrict map to specific distance as example 15 km from my current location to restrict user navigate to another locations.
I can calculate the distance between 2 points correctly based on the following function
public static double distFrom(double lat1, double lng1, double lat2, double lng2) {
double earthRadius = 6371.0; // earth radius in km
double dLat = Math.toRadians(lat2 - lat1);
double dLng = Math.toRadians(lng2 - lng1);
double sindLat = Math.sin(dLat / 2);
double sindLng = Math.sin(dLng / 2);
double a = Math.pow(sindLat, 2) + Math.pow(sindLng, 2)
* Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2));
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double dist = earthRadius * c;
return dist;
}
but cannot get possible latitude and longitude from my location in all sides based on specific distance because user can navigate in any side in map.
I tried this example but not give my accurate result.
Check this answer here:
https://stackoverflow.com/a/7478827/1397821
Now put all angles 0-360 in the equations mentioned in the above answer to get all the Lat Longs.
Hope this helps

Find geopoints in a radius near me

I have a DB with Geopoints.
I need to do a query to get all geopoints in the radius of X meters of me.
How can i do this?
I think the best way is get the minimal lat/long possible point, and the max lat/long point and get all of them for which: geopoint > minPoint AND geopoint < MaxPoint
Other ideas?
You can use this class to get de distance between to points:
How to use:
double distInKm = GeoMath.getDistance(12.345, -8.788, 12.33, -8.77);
Or, if point1 and point2 are GeoPoint:
double distInKm = GeoMath.getDistance(point1, point2);
You can also calculate a Geopoint that is a distance of you and along a bearing.
This computes a point that is 5 km northward from point1:
GeoPoint northPointAt5 = GeoMath.getGeoPointAlongBearing(point1, 0, 5);
You can calculate the other points at 90 degrees, 180 degrees and 270 degrees to calculate minPoint AND MaxPoint.
GeoMath class:
public class GeoMath {
public static final int EARTH_MEAN_RADIUS = 6371; // earth's mean radius in Km
public static double getDistance(double startLatitude, double startLongitude,
double endLatitude, double endLongitude){
return distHaversine(startLatitude,startLongitude,endLatitude,endLongitude);
}
public static double getDistance(GeoPoint point1, GeoPoint point2){
return distHaversine(point1.getLatitudeE6()/1E6, point1.getLongitudeE6()/1E6,
point2.getLatitudeE6()/1E6, point2.getLongitudeE6()/1E6);
}
private static double getSpanInRadians(double max, double min){
return Math.toRadians(max - min);
}
//Distance in Km between point1 (lat1,lon1) and point2 (lat2,lon2) Haversine formula
private static double distHaversine(double lat1, double lon1, double lat2, double lon2) {
double dLat = getSpanInRadians(lat2,lat1);
double dLon = getSpanInRadians(lon2,lon1);
lat1 = Math.toRadians(lat1);
lat2 = Math.toRadians(lat2);
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));
double dist = EARTH_MEAN_RADIUS * c;
return Math.round(dist * 1000)/1000; //3 decimal places
}
// Get GeoPoint at distance along a bearing
// bearing in degrees
// distance in Km
public static GeoPoint getGeoPointAlongBearing(GeoPoint location, double bearing, double distance){
double PI = Math.PI;
double NM = 1.852; //1 nm = 1.852 Km -> nm = Km/NM
GeoPoint geoPointAlongBearing;
double locationLatRad = Math.toRadians(location.getLatitudeE6()/1E6);
double locationLongRad = Math.toRadians(location.getLongitudeE6()/1E6)*(-1.0d);
double distanceRad = distance/NM * PI/(180*60);
double bearingRad = Math.toRadians(bearing);
double latAlongBearingRad = Math.asin(Math.sin(locationLatRad) *
Math.cos(distanceRad) +
Math.cos(locationLatRad) *
Math.sin(distanceRad) *
Math.cos(bearingRad));
double lonAlongBearingRad = mod(locationLongRad -
Math.asin(Math.sin(bearingRad) *
Math.sin(distanceRad) /
Math.cos(latAlongBearingRad)) + PI, 2 * PI) - PI;
double latAlongBearing = rad2lat(latAlongBearingRad);
double lonAlongBearing = rad2lng(lonAlongBearingRad) * (-1);
geoPointAlongBearing = new GeoPoint((int)(latAlongBearing*1E6),(int)(lonAlongBearing*1E6));
return geoPointAlongBearing;
}
private static double mod(double y, double x) {
return y - x * Math.floor(y/x);
}
}
With your query I think that you will find all points inside a square centered at your location and with a side length X.
After that, yuo can get all the points that are inside a circle centered at your location with radius X.
What about this pseudo code:
//create your location
Location yourLocation=new Location("myLoc");
double latitude = geoPointYourLocation.getLatitudeE6() / 1E6;
double longitude = geoPointYourLocation.getLongitudeE6() / 1E6;
yourLocation.setLatitude(latitude);
yourLocation.setLongitude(longitude);
//Browse geopoints from DB, convert to GeoPoint and check if it is at a distance less than X
for (geoPointTemp in in query geopoint of your DDBB inside square) {
//create the location of the geopoint
Location locTemp=new Location("locTemp");
double latitude = geoPointTemp.getLatitudeE6() / 1E6;
double longitude = geoPointTemp.getLongitudeE6() / 1E6;
locTemp.setLatitude(latitude);
locTemp.setLongitude(longitude);
//calculate the distance between you and de temporary location
double distance=yourLocation.distanceTo(locTemp);
if(distance<X){
//do something
}
With Mysql, you can use built-in spacial functions such as GLength, linestring ....

How can I calculate a current distance to polyline points on google maps v2 in android?

I have used tutorial from the link below to display Google map route in Android app. My question is how can I calculate distance to polyline points on map? Like when I use Google maps app and it tells when a street turn is getting close. I want to implement similar feature in my app. I am able to display the route polyline on the map and it updates itself while I drive along it but I want it to warn me 500 feet in advance of a coming turn. How can I do that?
Here is the link:
http://jigarlikes.wordpress.com/2013/04/26/driving-distance-and-travel-time-duration-between-two-locations-in-google-map-android-api-v2/
I use this method for Markers. Assuming you have Latitude and Longitude of the points that make up the Polyline this should do:
public class MapUtils {
public static float distBetween(LatLng pos1, LatLng pos2) {
return distBetween(pos1.latitude, pos1.longitude, pos2.latitude,
pos2.longitude);
}
/** distance in meters **/
public static float distBetween(double lat1, double lng1, double lat2, double lng2) {
double earthRadius = 3958.75;
double dLat = Math.toRadians(lat2 - lat1);
double dLng = 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(dLng / 2)
* Math.sin(dLng / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double dist = earthRadius * c;
int meterConversion = 1609;
return (float) (dist * meterConversion);
}
}
To determine wether the road is turning, I would look into euclidean angle between vectors (x being current location and y being a polyline point)
Simply take your current location and a LatLng from some distance ahead for this.
Calculation is based on: http://en.wikipedia.org/wiki/Euclidean_space#Angle
Location currentLocation; // obtained somewhere in your code
LatLng polylinePoint; // a point further ahead
double cLat = currentLocation.getLatitude();
double cLon = currentLocation.getLongitude();
double pLat = polylinePoint.latitude;
double pLon = polylinePoint.longitude;
double angle = Math.acos(
(cLat*pLat+cLon+pLon) / norm(cLat,cLon)*norm(pLat,cLon));
private double norm(double x, double y) {
return Math.sqrt(Math.pow(x, 2)*Math.pow(y, 2));
}
This is untested so might contain error.

Nan in calculating Distance using Latitude and Longitude

I am calculating the Distance between two Latitudes and Longitudes. I get the results for some distances but sometimes,I get the results as NAN.
This is the Latitude and Longitude which I have got for 2 places.
For eg:
38.655553,-121.091611
38.654875,-121.091324
I am using the below code to calculate the distance with reference to the below link
Calculating distance between two geographic locations
public static double distanceBetween (double currentLat2, double currentLong2, double mallLat2, double mallLong2)
{
float pk = (float) (180/3.14169);
double a1 = currentLat2 / pk;
double a2 = currentLong2 / pk;
double b1 = mallLat2 / pk;
double b2 = mallLong2 / pk;
double t1 = FloatMath.cos((float) a1)*FloatMath.cos((float) a2)*FloatMath.cos((float) b1)*FloatMath.cos((float) b2);
double t2 = FloatMath.cos((float) a1)*FloatMath.sin((float) a2)*FloatMath.cos((float) b1)*FloatMath.sin((float) b2);
double t3 = FloatMath.sin((float) a1)*FloatMath.sin((float) b1);
double tt = Math.acos(t1 + t2 + t3);
return 6366000*tt;
}
Any Help?
Thanks.
MathFloat together with float casts is the cause of your problem.
I rewrote, now it works, it gives 79.34m
But the main problem is that you use the wrong formula for this task, you use here the greater circle distance formula with law of cosines, which is well know to be "ill conditioned" for floating point arithmetic. Then to make it even worse, you use that with single precision only, instead of double.
The more robust formula is the haversine formula.
It was designed to overcome the disadvantage of the greater circle formula.
Here your original code fixed, (but i still recommend use the haversine formula instead)
public void test1() {
// 79.34253285803419
double lat1 = 38.655553;
double lon1 = -121.091611;
double lat2 = 38.654875;
double lon2 = -121.091324;
System.out.println(distanceBetween(lat1, lon1, lat2, lon2));
}
public static double distanceBetween (double currentLat2, double currentLong2, double mallLat2, double mallLong2)
{
double pk = 180 / Math.PI;
double a1 = currentLat2 / pk;
double a2 = currentLong2 / pk;
double b1 = mallLat2 / pk;
double b2 = mallLong2 / pk;
double t1 = Math.cos( a1) * Math.cos(a2) * Math.cos(b1) * Math.cos(b2);
double t2 = Math.cos( a1) * Math.sin(a2) * Math.cos(b1) * Math.sin(b2);
double t3 = Math.sin( a1) * Math.sin(b1);
double tt = Math.acos(t1 + t2 + t3);
return 6366000*tt;
}
the doc for Location.distanceTo(LOcation) says:
Returns the approximate distance in meters between this location and
the given location. Distance is defined using the WGS84 ellipsoid.
So you can try this way:
public static float distanceBetween (double currentLat2, double currentLong2, double mallLat2, double mallLong2) {
Location loc1 = new Location("");
loc1.setLatitude(currentLat2);
loc1.setLongitude(currentLong2);
Location loc2 = new Location("");
loc2.setLatitude(mallLat2);
loc2.setLongitude(mallLong2);
return loc1.distanceTo(loc2);
}
Can you log the outputs for t1, t2, t3? I have a feeling that the argument for Math.acos() is out of range. Also not sure why you're needlessly casting to float and back to double when you can just use Math.sin and Math.cos.
Edit
Use Math.PI instead of 3.14169. This approximation is causing your error.

Calculate bearing between two locations (lat, long)

I'm trying to develop my own augmented reality engine.
Searching on internet, I've found this useful tutorial. Reading it I see that the important thing is bearing between user location, point location and north.
The following picture is from that tutorial.
Following it, I wrote an Objective-C method to obtain beta:
+ (float) calculateBetaFrom:(CLLocationCoordinate2D)user to:(CLLocationCoordinate2D)destination
{
double beta = 0;
double a, b = 0;
a = destination.latitude - user.latitude;
b = destination.longitude - user.longitude;
beta = atan2(a, b) * 180.0 / M_PI;
if (beta < 0.0)
beta += 360.0;
else if (beta > 360.0)
beta -= 360;
return beta;
}
But, when I try it, it doesn't work very well.
So, I checked iPhone AR Toolkit, to see how it works (I've been working with this toolkit, but it is so big for me).
And, in ARGeoCoordinate.m there is another implementation of how to obtain beta:
- (float)angleFromCoordinate:(CLLocationCoordinate2D)first toCoordinate:(CLLocationCoordinate2D)second {
float longitudinalDifference = second.longitude - first.longitude;
float latitudinalDifference = second.latitude - first.latitude;
float possibleAzimuth = (M_PI * .5f) - atan(latitudinalDifference / longitudinalDifference);
if (longitudinalDifference > 0)
return possibleAzimuth;
else if (longitudinalDifference < 0)
return possibleAzimuth + M_PI;
else if (latitudinalDifference < 0)
return M_PI;
return 0.0f;
}
It uses this formula:
float possibleAzimuth = (M_PI * .5f) - atan(latitudinalDifference / longitudinalDifference);
Why is (M_PI * .5f) in this formula? I don't understand it.
And continue searching, I've found another page talking about how to calculate distance and bearing of 2 locations. In this page there is another implementation:
/**
* Returns the (initial) bearing from this point to the supplied point, in degrees
* see http://williams.best.vwh.net/avform.htm#Crs
*
* #param {LatLon} point: Latitude/longitude of destination point
* #returns {Number} Initial bearing in degrees from North
*/
LatLon.prototype.bearingTo = function(point) {
var lat1 = this._lat.toRad(), lat2 = point._lat.toRad();
var dLon = (point._lon-this._lon).toRad();
var y = Math.sin(dLon) * Math.cos(lat2);
var x = Math.cos(lat1)*Math.sin(lat2) -
Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
var brng = Math.atan2(y, x);
return (brng.toDeg()+360) % 360;
}
Which one is the right one?
Calculate bearing
//Source
JSONObject source = step.getJSONObject("start_location");
double lat1 = Double.parseDouble(source.getString("lat"));
double lng1 = Double.parseDouble(source.getString("lng"));
// destination
JSONObject destination = step.getJSONObject("end_location");
double lat2 = Double.parseDouble(destination.getString("lat"));
double lng2 = Double.parseDouble(destination.getString("lng"));
double dLon = (lng2-lng1);
double y = Math.sin(dLon) * Math.cos(lat2);
double x = Math.cos(lat1)*Math.sin(lat2) - Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
double brng = Math.toDegrees((Math.atan2(y, x)));
brng = (360 - ((brng + 360) % 360));
Convert Degrees into Radians
Radians = Degrees * PI / 180
Convert Radians into Degrees
Degrees = Radians * 180 / PI
I know this question is old, but here is an easier solution:
float bearing = loc1.bearingTo(loc2);
Try this for accurate result:
private static double degreeToRadians(double latLong) {
return (Math.PI * latLong / 180.0);
}
private static double radiansToDegree(double latLong) {
return (latLong * 180.0 / Math.PI);
}
public static double getBearing() {
//Source
JSONObject source = step.getJSONObject("start_location");
double lat1 = Double.parseDouble(source.getString("lat"));
double lng1 = Double.parseDouble(source.getString("lng"));
// destination
JSONObject destination = step.getJSONObject("end_location");
double lat2 = Double.parseDouble(destination.getString("lat"));
double lng2 = Double.parseDouble(destination.getString("lng"));
double fLat = degreeToRadians(lat1);
double fLong = degreeToRadians(lng1);
double tLat = degreeToRadians(lat2);
double tLong = degreeToRadians(lng2);
double dLon = (tLong - fLong);
double degree = radiansToDegree(Math.atan2(sin(dLon) * cos(tLat),
cos(fLat) * sin(tLat) - sin(fLat) * cos(tLat) * cos(dLon)));
if (degree >= 0) {
return degree;
} else {
return 360 + degree;
}
}
You can test bearing result on http://www.sunearthtools.com/tools/distance.php .
In the formula
float possibleAzimuth = (M_PI * .5f) - atan(latitudinalDifference / longitudinalDifference);
the term (M_PI * .5f) means π/2 which is 90°. That means that it is the same formula that you stated at first, because regarding to the figure above it holds
β = arctan (a/b) = 90° - arctan(b/a).
So both formulas are similar if a refers to the difference in longitude and b in the difference in latitude. The last formula calculates again the same using the first part of my equation.
a in the diagram is the longitude difference, b is the latitude difference therefore in the method you have written you've got them the wrong way round.
a = destination.latitude - user.latitude; // should be b
b = destination.longitude - user.longitude; // should be a
Try switching them and see what happens.
See Palund's response for answers to the rest of your questions.
/*
Kirit vaghela answer has been modified..
Math.sin gives the radian value so to get degree value we need to pass Math.toRadians(value) inside Math.sin() or Math.cos()
*/
double lat1 = 39.099912;
double lat2 = 38.627089;
double lng1 = -94.581213;
double lng2 = -90.200203;
double dLon = (lng2-lng1);
double x = Math.sin(Math.toRadians(dLon)) * Math.cos(Math.toRadians(lat2));
double y = Math.cos(Math.toRadians(lat1))*Math.sin(Math.toRadians(lat2)) - Math.sin(Math.toRadians(lat1))*Math.cos(Math.toRadians(lat2))*Math.cos(Math.toRadians(dLon));
double bearing = Math.toDegrees((Math.atan2(x, y)));
System.out.println("BearingAngle : "+bearing);
If you want you can take a look at the code used in mixare augmented reality engine, it's on github and there's an iPhone version as well: github.com/mixare
inputs are in degrees.
#define PI 3.14159265358979323846
#define RADIO_TERRESTRE 6372797.56085
#define GRADOS_RADIANES PI / 180
#define RADIANES_GRADOS 180 / PI
double calculateBearing(double lon1, double lat1, double lon2, double lat2)
{
double longitude1 = lon1;
double longitude2 = lon2;
double latitude1 = lat1 * GRADOS_RADIANES;
double latitude2 = lat2 * GRADOS_RADIANES;
double longDiff= (longitude2-longitude1) * GRADOS_RADIANES;
double y= sin(longDiff) * cos(latitude2);
double x= cos(latitude1) * sin(latitude2) - sin(latitude1) * cos(latitude2) * cos(longDiff);
// std::cout <<__FILE__ << "." << __FUNCTION__ << " line:" << __LINE__ << " "
return fmod(((RADIANES_GRADOS *(atan2(y, x)))+360),360);
}

Categories

Resources