I have a task of being able to program a Class in Java to calculate the bearing from North to a point. The only objects that are known are 2 positions, both have a bearing from North and the distance from 0. So for example - position 1 - 30 degrees and 10m, position 2 - 190 degrees and 50m. How would you calculate the bearing if you wanted to travel from position 1 to position 2 for instance or from position 2 to 1? I can calculate the distance between the 2 positions using the cosine rule, but have no idea how to create a class that will accuratly calculate the bearing in different scenarios?
Any help or advise would be greatly appreciated.
From http://en.wikipedia.org/wiki/Law_of_cosines#Applications:
...once you have all three side lengths, this will give you the third angle of your triangle.
(The Haversine formula is for navigation on a sphere... I think we're just worried about vectors on a plane.)
I believe what you are looking for is the Haversine formula, googling it will yield implementations in various languages.
This is a java version ported from a javascript solution given here:
Using the Haversine Formula in Javascript by talkol
// this was a pojo class we used internally...
public class GisPostalCode {
private String country;
private String postalCode;
private double latitude;
private double longitude;
// getters/setters, etc.
}
public static double distanceBetweenCoordinatesInMiles2(GisPostalCode c1, GisPostalCode c2) {
double lat2 = c2.getLatitude();
double lon2 = c2.getLongitude();
double lat1 = c1.getLatitude();
double lon1 = c1.getLongitude();
double R = 6371; // km
double x1 = lat2 - lat1;
double dLat = x1 * Math.PI / 180;
double x2 = lon2 - lon1;
double dLon = x2 * Math.PI / 180;
double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1*Math.PI/180) * Math.cos(lat2*Math.PI/180) *
Math.sin(dLon/2) * Math.sin(dLon/2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
double d = R * c;
// convert to miles
return d / 1.60934;
}
Related
i am using haversine formula to calculate distance but i am getting wrong distance actually google map distance is 8.1km but haversine formula is showing 4.06
private static final int EARTH_RADIUS = 6371; // Approx Earth radius in KM
public static double distance(double startLat, double startLong, double endLat, double endLong) {
double dLat = Math.toRadians((endLat - startLat));
double dLong = Math.toRadians((endLong - startLong));
startLat = Math.toRadians(startLat);
endLat = Math.toRadians(endLat);
double a = haversin(dLat) + Math.cos(startLat) * Math.cos(endLat) * haversin(dLong);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return EARTH_RADIUS * c; // <-- d
}
public static double haversin(double val) {
return Math.pow(Math.sin(val / 2), 2);
}
Your formula is correct, the problem come from bad use of google map
As suggested by Tim in comments, you need to see the point-to-point distance, not road distance
Using the two distance(17.451955, 78.478187, 17.442504, 78.441323) give 4.06km:
8.1km is probably the distance by road, and not point-to-point
I found the formula to calculate the second coordinates here. But when I converted it to Java, the result is not as I expected.
private Point get(double lat1, double lon1, double tc, int d) {
double lat = Math.asin(
Math.sin(lat1) * Math.cos(d)
+ Math.cos(lat1) * Math.sin(d) * Math.cos(tc)
);
double dlon= Math.atan2(
Math.sin(tc) * Math.sin(d) * Math.cos(lat1)
, Math.cos(d) - Math.sin(lat1) * Math.sin(lat));
double lon = ((lon1 - dlon + Math.PI) % (2 * Math.PI)) - Math.PI;
return new Point(lat, lon);
}
I tested the code above with simple case such as get(50, 10, 0, 0). So expected the result will be as same as the first point, but this is the result I got:
Lat: 1.4432701894877245, lon: -3.8108244707674395
Am I using correct formula to calculate second coordinates?
[EDIT]
Here is the formula that I try to convert to java code
lat =asin(sin(lat1)*cos(d)+cos(lat1)*sin(d)*cos(tc))
dlon=atan2(sin(tc)*sin(d)*cos(lat1),cos(d)-sin(lat1)*sin(lat))
lon=mod( lon1-dlon +pi,2*pi )-pi
As noted in comments, your formulas expect that the latitude, longitude, true course, and distance are all in radians.
If you want to pass in latitude, longitude, true course in degrees, and distance in nautical miles, you will need to do the following conversion below any math:
// convert to radians
lat1 = lat1 * Math.PI / 180;
lon1 = lon1 * Math.PI / 180;
tc = tc * Math.PI / 180;
d = (Math.PI / (180*60)) * d;
and then convert your latitude and longitude back from radians to degrees:
// convert to degrees
lat = lat * 180 / Math.PI;
lon = lon * 180 / Math.PI;
However, two other notes:
1) java.awt.Point (not clear this is what you're using) can only hold integers; you might want to use Point2D.Double instead; and
2) Distance should also be measured including fractions of either nautical miles or radians, so should be a double.
With those edits, get(50, 10, 0, 0) will work. As will the worked example from your page for a waypoint 100nm from LAX on the 66 degree radial - get(33.95, 118.4, 66, 100) (remember that minutes are converted into fractional degrees) returns 34.6141 lat and 116.5499 lon, matching 34d 37m and 116d 33m.
I have a list of Lat/Long coordinates that represents a polygon and a single separate Lat/Long which I know is contained within the polygon.
How do I determine the distance from the single Lat/Long to the closest edge of the polygon? Is there a known Java library for this?
I suggest following solution, which also works in case of a polygon that is around the north pole, where a calculation of the longitude and latitude difference doesn't make sense.
The solution transforms the longitude and latitude of points on the earth into three-dimensional coordinates by using the World Geodetic System 84. With those three-dimensional points, you can calculate the projection of one point on the line defined by two other points in three-dimensional space.
Here is the code doing the calculations. It uses the class javafx.geometry.Point3D, available in Java 8.
/** Semi-major axis of earth in meter */
public static final double WGS84_A = 6378137.0;
/** Semi-minor axis of earth in meter */
public static final double WGS84_B = 6356752.314245;
/** Eccentricity of earth */
public static final double WGS84_E =
Math.sqrt( (WGS84_A * WGS84_A) / (WGS84_B * WGS84_B) - 1);
public static final double DEGREES_TO_RADIANS = Math.PI / 180;
/**
* Calculates a three-dimensional point in the
* World Geodetic System (WGS84) from latitude and longitude.
*/
public static Point3D latLonToPoint3D(double lat, double lon) {
double clat = Math.cos(lat * DEGREES_TO_RADIANS);
double slat = Math.sin(lat * DEGREES_TO_RADIANS);
double clon = Math.cos(lon * DEGREES_TO_RADIANS);
double slon = Math.sin(lon * DEGREES_TO_RADIANS);
double N = WGS84_A / Math.sqrt(1.0 - WGS84_E * WGS84_E * slat * slat);
double x = N * clat * clon;
double y = N * clat * slon;
double z = N * (1.0 - WGS84_E * WGS84_E) * slat;
return new Point3D(x, y, z);
}
/**
* Calculates distance of projection p of vector a on vector b.
*
* Use formula for projection, with p being the projection point:
* <p>
* p = a X b / |b|^2 * b
* </p>
* X being the dot product, * being multiplication of vector and constant
*/
public static Point3D calculateProjection(Point3D a, Point3D b) {
return b.multiply(a.dotProduct(b) / (b.dotProduct(b)));
}
/**
* Calculates shortest distance of vector x and the line defined by
* the vectors a and b.
*/
public static double calculateDistanceToLine(Point3D x, Point3D a, Point3D b) {
Point3D projectionOntoLine =
calculateProjection(x.subtract(a), b.subtract(a)).add(a);
return projectionOntoLine.distance(x);
}
By calling calculateDistanceToLine with the point and the polygon segments' points, you are able to find the nearest line defined by the edge points and extended to infinity. In the case of a concave polygon, this may not be what you want, as you see in the picture.
Taking into account that the distance to the polygon edge must be at least as long as the distance to the nearest edge point, you can get the distance to the edge as:
Math.max(calculateDistanceToLine(x, edgePoint1, edgePoint2),
Math.min(x.distance(edgePoint1), x.distance(edgePoint2)));
Note that this calculation yields also not the distance on the surface of the earth, but the direct distance cutting through the earth. Anyway, it should suffice for choosing the shortest distance.
The function latLonToPoint3Dis a modified version of the function that I found here.
you can just loop through all your edges and calculate the distance between the two points like this:
function double calculateDistance(
double edgeLat1, double edgeLng1,
double edgeLat2, double edgeLng2,
double pointLat, double pointLng) {
//calculate straight/edge
double mS = (edgeLng2 - edgeLng1)/(edgeLat2- edgeLat2);
double tS = edgeLng1 - edgeLng1 * mS;
//calculate helper straight
double mH = -mS;
double tH = pointLng - mH * pointLat;
//calcuate straight intersection
xI = (tH - tS)/(mS - mH);
yI = mH * xI - tH;
//calculate distance
/* in degree
double dInDegree = Math.sqrt((pointLat - xI) * (pointLat - xI)
+ (pointLng - yI) * (pointLng - yI));
return dInDegree;
*/
//in meter
double R = 6371000; // m
double dLat = (pointLat-xI).toRad();
double dLon = (pointLng-yI).toRad();
double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(x1.toRad()) * Math.cos(pointLat.toRad()) *
Math.sin(dLon/2) * Math.sin(dLon/2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
double distanceInMeter = R * c;
return distanceInMeter;
}
I hope this works for you, this is "simple" vector maths.
Check the Single Separate Lat/Long, for the closest coordinate that exists in your list.
Then Gather the two points that are connected to that Coordinate(the one that is closest to your single point) So now you have 4 points.
singlePoint, closestPointToSinglePoint, neighbor1, neighbor2. I'm assuming you have some basic trig experience at this point(no pun intended). What you should do from here is visualize 2 triangles. (singlePoint, closestPointToSinglePoint, neighbor1) and (singlePoint, closestPointToSinglePoint, neighbor2).
At this point, calculate the height of the triangles from the SinglePoint as a reference. You now have 2 distances to the 2 closest edges. Compare, and enjoy your results.
I've got a latitude & longitude of a point. I want all the readings of latitude & longitude within a radius of 500M with respect to that given point. Is any method for that? Is it possible? Is there any algorithm for it?
There are many formulas available to calculate the distance between two lat/long points (it won't be exact due to altitude variation, but very close), and filter your sample points based on distance from your given point.
A nice overview of what's available (with math and source code) is available here: http://www.movable-type.co.uk/scripts/latlong.html
Browse through there and pick the distance formula that fits your needs the best.
Here's a solution on StackOverflow for finding the distance between 2 locations, by Usman Kurd
https://stackoverflow.com/a/14394403/2128327
So with a little tweak, we can use his function:
public double getKmDistance(GeoPoint StartP, GeoPoint EndP) {
int Radius=6371;//radius of earth in Km
double lat1 = StartP.getLatitudeE6()/1E6;
double lat2 = EndP.getLatitudeE6()/1E6;
double lon1 = StartP.getLongitudeE6()/1E6;
double lon2 = EndP.getLongitudeE6()/1E6;
double dLat = Math.toRadians(lat2-lat1);
double dLon = Math.toRadians(lon2-lon1);
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));
double valueResult= Radius*c;
double km=valueResult/1;
DecimalFormat newFormat = new DecimalFormat("####");
kmInDec = Integer.valueOf(newFormat.format(km));
meter=valueResult%1000;
meterInDec= Integer.valueOf(newFormat.format(meter));
Log.i("Radius Value",""+valueResult+" KM "+kmInDec+" Meter "+meterInDec);
return kmInDec;
}
then let's say that you have a list of locations:
ArrayList<GeoPoint> geoPoints = new ArrayList<GeoPoint>();
And we have our current location:
GeoPoint currentLocation = new GeoPoint(..);
then you can do this:
ArrayList<GeoPoint> within500Km = new ArrayList<GeoPoint>();
for (GeoPoint g : geoPoints)
if (getKmDistance(currentLocation, g) <= 500.0)
within500Km.add(g);
for(GeoPoint g : within500Km)
System.out.println("> "+g.getLatitudeE6()+" : "+g.getLongitudeE6()+" ");
I have two Lines: L1 and L2. I want to calculate the angle between the two lines. L1 has points: {(x1, y1), (x2, y2)} and L2 has points: {(x3, y3), (x4, y4)}.
How can I calculate the angle formed between these two lines, without having to calculate the slopes? The problem I am currently having is that sometimes I have horizontal lines (lines along the x-axis) and the following formula fails (divide by zero exception):
arctan((m1 - m2) / (1 - (m1 * m2)))
where m1 and m2 are the slopes of line 1 and line 2 respectively. Is there a formula/algorithm that can calculate the angles between the two lines without ever getting divide-by-zero exceptions? Any help would be highly appreciated.
This is my code snippet:
// Calculates the angle formed between two lines
public static double angleBetween2Lines(Line2D line1, Line2D line2)
{
double slope1 = line1.getY1() - line1.getY2() / line1.getX1() - line1.getX2();
double slope2 = line2.getY1() - line2.getY2() / line2.getX1() - line2.getX2();
double angle = Math.atan((slope1 - slope2) / (1 - (slope1 * slope2)));
return angle;
}
Thanks.
The atan2 function eases the pain of dealing with atan.
It is declared as double atan2(double y, double x) and converts rectangular coordinates (x,y) to the angle theta from the polar coordinates (r,theta)
So I'd rewrite your code as
public static double angleBetween2Lines(Line2D line1, Line2D line2)
{
double angle1 = Math.atan2(line1.getY1() - line1.getY2(),
line1.getX1() - line1.getX2());
double angle2 = Math.atan2(line2.getY1() - line2.getY2(),
line2.getX1() - line2.getX2());
return angle1-angle2;
}
Dot product is probably more useful in this case. Here you can find a geometry package for Java which provides some useful helpers. Below is their calculation for determining the angle between two 3-d points. Hopefully it will get you started:
public static double computeAngle (double[] p0, double[] p1, double[] p2)
{
double[] v0 = Geometry.createVector (p0, p1);
double[] v1 = Geometry.createVector (p0, p2);
double dotProduct = Geometry.computeDotProduct (v0, v1);
double length1 = Geometry.length (v0);
double length2 = Geometry.length (v1);
double denominator = length1 * length2;
double product = denominator != 0.0 ? dotProduct / denominator : 0.0;
double angle = Math.acos (product);
return angle;
}
Good luck!
dx1 = x2-x1;
dy1 = y2-y1;
dx2 = x4-x3;
dy2 = y4-y3;
d = dx1*dx2 + dy1*dy2; // dot product of the 2 vectors
l2 = (dx1*dx1+dy1*dy1)*(dx2*dx2+dy2*dy2) // product of the squared lengths
angle = acos(d/sqrt(l2));
The dot product of 2 vectors is equal to the cosine of the angle time the length of both vectors. This computes the dot product, divides by the length of the vectors and uses the inverse cosine function to recover the angle.
Maybe my approach for Android coordinates system will be useful for someone (used Android PointF class to store points)
/**
* Calculate angle between two lines with two given points
*
* #param A1 First point first line
* #param A2 Second point first line
* #param B1 First point second line
* #param B2 Second point second line
* #return Angle between two lines in degrees
*/
public static float angleBetween2Lines(PointF A1, PointF A2, PointF B1, PointF B2) {
float angle1 = (float) Math.atan2(A2.y - A1.y, A1.x - A2.x);
float angle2 = (float) Math.atan2(B2.y - B1.y, B1.x - B2.x);
float calculatedAngle = (float) Math.toDegrees(angle1 - angle2);
if (calculatedAngle < 0) calculatedAngle += 360;
return calculatedAngle;
}
It return positive value in degrees for any quadrant: 0 <= x < 360
You can checkout my utility class here
The formula for getting the angle is tan a = (slope1-slope2)/(1+slope1*slope2)
You are using:
tan a = (slope1 - slope2) / (1 - slope1 * slope2)
So it should be:
double angle = Math.atan((slope1 - slope2) / (1 + slope1 * slope2));
First, are you sure the brackets are in the right order? I think (could be wrong) it should be this:
double slope1 = (line1.getY1() - line1.getY2()) / (line1.getX1() - line1.getX2());
double slope2 = (line2.getY1() - line2.getY2()) / (line2.getX1() - line2.getX2());
Second, there are two things you could do for the div by zero: you could catch the exception and handle it
double angle;
try
{
angle = Math.atan((slope1 - slope2) / (1 - (slope1 * slope2)));
catch (DivideByZeroException dbze)
{
//Do something about it!
}
...or you could check that your divisors are never zero before you attempt the operation.
if ((1 - (slope1 * slope2))==0)
{
return /*something meaningful to avoid the div by zero*/
}
else
{
double angle = Math.atan((slope1 - slope2) / (1 - (slope1 * slope2)));
return angle;
}
Check this Python code:
import math
def angle(x1,y1,x2,y2,x3,y3):
if (x1==x2==x3 or y1==y2==y3):
return 180
else:
dx1 = x2-x1
dy1 = y2-y1
dx2 = x3-x2
dy2 = y3-y2
if x1==x2:
a1=90
else:
m1=dy1/dx1
a1=math.degrees(math.atan(m1))
if x2==x3:
a2=90
else:
m2=dy2/dx2
a2=math.degrees(math.atan(m2))
angle = abs(a2-a1)
return angle
print angle(0,4,0,0,9,-6)
dx1=x2-x1 ; dy1=y2-y1 ; dx2=x4-x3 ;dy2=y4-y3.
Angle(L1,L2)=pi()/2*((1+sign(dx1))* (1-sign(dy1^2))-(1+sign(dx2))*(1-sign(dy2^2)))
+pi()/4*((2+sign(dx1))*sign(dy1)-(2+sign(dx2))*sign(dy2))
+sign(dx1*dy1)*atan((abs(dx1)-abs(dy1))/(abs(dx1)+abs(dy1)))
-sign(dx2*dy2)*atan((abs(dx2)-abs(dy2))/(abs(dx2)+abs(dy2)))