Increase Latitude and longitude by given Distance (meter) Using JAVA [duplicate] - java

I want to create 2 new longitude and 2 new latitudes based on a coordinate and a distance in meters, I want to create a nice bounding box around a certain point. It is for a part of a city and max ±1500 meters. I therefore don't think the curvature of earth has to be taken into account.
So I have 50.0452345 (x) and 4.3242234 (y) and I want to know x + 500 meters, x - 500 meters, y - 500 meters, y + 500 meters
I found many algorithms but almost all seem to deal with the distance between points.

The number of kilometers per degree of longitude is approximately
(pi/180) * r_earth * cos(theta*pi/180)
where theta is the latitude in degrees and r_earth is approximately 6378 km.
The number of kilometers per degree of latitude is approximately the same at all locations, approx
(pi/180) * r_earth = 111 km / degree
So you can do:
new_latitude = latitude + (dy / r_earth) * (180 / pi);
new_longitude = longitude + (dx / r_earth) * (180 / pi) / cos(latitude * pi/180);
As long as dx and dy are small compared to the radius of the earth and you don't get too close to the poles.

The accepted answer is perfectly right and works. I made some tweaks and turned into this:
double meters = 50;
// number of km per degree = ~111km (111.32 in google maps, but range varies
// between 110.567km at the equator and 111.699km at the poles)
//
// 111.32km = 111320.0m (".0" is used to make sure the result of division is
// double even if the "meters" variable can't be explicitly declared as double)
double coef = meters / 111320.0;
double new_lat = my_lat + coef;
// pi / 180 ~= 0.01745
double new_long = my_long + coef / Math.cos(my_lat * 0.01745);
Hope this helps too.

For latitude do:
var earth = 6378.137, //radius of the earth in kilometer
pi = Math.PI,
m = (1 / ((2 * pi / 360) * earth)) / 1000; //1 meter in degree
var new_latitude = latitude + (your_meters * m);
For longitude do:
var earth = 6378.137, //radius of the earth in kilometer
pi = Math.PI,
cos = Math.cos,
m = (1 / ((2 * pi / 360) * earth)) / 1000; //1 meter in degree
var new_longitude = longitude + (your_meters * m) / cos(latitude * (pi / 180));
The variable your_meters can contain a positive or a negative value.

I had to spend about two hours to work out the solution by #nibot , I simply needed a method to create a boundary box given its center point and width/height (or radius) in kilometers:
I don't fully understand the solution mathematically/ geographically.
I tweaked the solution (by trial and error) to get the four coordinates. Distances in km, given the current position and distance we shift to the new position in the four coordinates:
North:
private static Position ToNorthPosition(Position center, double northDistance)
{
double r_earth = 6378;
var pi = Math.PI;
var new_latitude = center.Lat + (northDistance / r_earth) * (180 / pi);
return new Position(new_latitude, center.Long);
}
East:
private static Position ToEastPosition(Position center, double eastDistance)
{
double r_earth = 6378;
var pi = Math.PI;
var new_longitude = center.Long + (eastDistance / r_earth) * (180 / pi) / Math.Cos(center.Lat * pi / 180);
return new Position(center.Lat, new_longitude);
}
South:
private static Position ToSouthPosition(Position center, double southDistance)
{
double r_earth = 6378;
var pi = Math.PI;
var new_latitude = center.Lat - (southDistance / r_earth) * (180 / pi);
return new Position(new_latitude, center.Long);
}
West:
private static Position ToWestPosition(Position center, double westDistance)
{
double r_earth = 6378;
var pi = Math.PI;
var new_longitude = center.Long - (westDistance / r_earth) * (180 / pi) / Math.Cos(center.Lat * pi / 180);
return new Position(center.Lat, new_longitude);
}

Have you checked out: How do I find the lat/long that is x km north of a given lat/long ?
These calculations are annoying at best, I've done many of them. The haversine formula will be your friend.
Some reference: http://www.movable-type.co.uk/scripts/latlong.html

Posting this method for sake of completeness.
Use this method "as it is" to:
Move any (lat,long) point by given meters in either axis.
Python method to move any point by defined meters.
def translate_latlong(lat,long,lat_translation_meters,long_translation_meters):
''' method to move any lat,long point by provided meters in lat and long direction.
params :
lat,long: lattitude and longitude in degrees as decimal values, e.g. 37.43609517497065, -122.17226450150885
lat_translation_meters: movement of point in meters in lattitude direction.
positive value: up move, negative value: down move
long_translation_meters: movement of point in meters in longitude direction.
positive value: left move, negative value: right move
'''
earth_radius = 6378.137
#Calculate top, which is lat_translation_meters above
m_lat = (1 / ((2 * math.pi / 360) * earth_radius)) / 1000;
lat_new = lat + (lat_translation_meters * m_lat)
#Calculate right, which is long_translation_meters right
m_long = (1 / ((2 * math.pi / 360) * earth_radius)) / 1000; # 1 meter in degree
long_new = long + (long_translation_meters * m_long) / math.cos(lat * (math.pi / 180));
return lat_new,long_new

Working Python code to offset coordinates by 10 metres.
def add_blur(lat, long):
meters = 10
blur_factor = meters * 0.000006279
new_lat = lat + blur_factor
new_long = long + blur_factor / math.cos(lat * 0.018)
return new_lat, new_long

if you don't have to be very exact then: each 10000 meters is about 0.1 for latitude and longitude.
for example I want to load locations 3000 meters around point_A from my database:
double newMeter = 3000 * 0.1 / 10000;
double lat1 = point_A.latitude - newMeter;
double lat2 = point_A.latitude + newMeter;
double lon1 = point_A.longitude - newMeter;
double lon1 = point_A.longitude + newMeter;
Cursor c = mDb.rawQuery("select * from TABLE1 where lat >= " + lat1 + " and lat <= " + lat2 + " and lon >= " + lon1 + " and lon <= " + lon2 + " order by id", null);

public double MeterToDegree(double meters, double latitude)
{
return meters / (111.32 * 1000 * Math.Cos(latitude * (Math.PI / 180)));
}

var meters = 50;
var coef = meters * 0.0000089;
var new_lat = map.getCenter().lat.apply() + coef;
var new_long = map.getCenter().lng.apply() + coef / Math.cos(new_lat * 0.018);
map.setCenter({lat:new_lat, lng:new_long});

See from Official Google Maps Documentation (link below) as they solve on easy/simple maps the problems with distance by countries :)
I recommended this solution to easy/simply solve issue with boundaries that you can know which area you're solving the problem with boundaries (not recommended globally)
Note:
Latitude lines run west-east and mark the position south-north of a point. Lines of latitude are called parallels and in total there are 180 degrees of latitude. The distance between each degree of latitude is about 69 miles (110 kilometers).
The distance between longitudes narrows the further away from the equator. The distance between longitudes at the equator is the same as latitude, roughly 69 miles (110 kilometers) . At 45 degrees north or south, the distance between is about 49 miles (79 kilometers). The distance between longitudes reaches zero at the poles as the lines of meridian converge at that point.
Original source 1
Original source 2
Official Google Maps Documentation: Code Example: Autocomplete Restricted to Multiple Countries
See the part of their code how they solve problem with distance center + 10 kilometers by +/- 0.1 degree
function initMap(): void {
const map = new google.maps.Map(
document.getElementById("map") as HTMLElement,
{
center: { lat: 50.064192, lng: -130.605469 },
zoom: 3,
}
);
const card = document.getElementById("pac-card") as HTMLElement;
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(card);
const center = { lat: 50.064192, lng: -130.605469 };
// Create a bounding box with sides ~10km away from the center point
const defaultBounds = {
north: center.lat + 0.1,
south: center.lat - 0.1,
east: center.lng + 0.1,
west: center.lng - 0.1,
};
const input = document.getElementById("pac-input") as HTMLInputElement;
const options = {
bounds: defaultBounds,
componentRestrictions: { country: "us" },
fields: ["address_components", "geometry", "icon", "name"],
origin: center,
strictBounds: false,
types: ["establishment"],
};

This is what I did in VBA that seems to be working for me. Calculation is in feet not meters though
Public Function CalcLong(OrigLong As Double, OrigLat As Double, DirLong As String, DirLat As String, DistLong As Double, DistLat As Double)
Dim FT As Double
Dim NewLong, NewLat As Double
FT = 1 / ((2 * WorksheetFunction.Pi / 360) * 20902230.971129)
If DirLong = "W" Then
NewLat = CalcLat(OrigLong, OrigLat, DirLong, DirLat, DistLong, DistLat)
NewLong = OrigLong - ((FT * DistLong) / Cos(NewLat * (WorksheetFunction.Pi / 180)))
CalcLong = NewLong
Else
NewLong = OrigLong + ((FT * DistLong) / Math.Cos(CalcLat(OrigLong, OrigLat, DirLong, DirLat, DistLong, DistLat) * (WorksheetFunction.Pi / 180)))
CalcLong = NewLong
End If
End Function
Public Function CalcLat(OrigLong As Double, OrigLat As Double, DirLong As String, DirLat As String, DistLong As Double, DistLat As Double) As Double
Dim FT As Double
Dim NewLat As Double
FT = 1 / ((2 * WorksheetFunction.Pi / 360) * 20902230.971129)
If DirLat = "S" Then
NewLat = (OrigLat - (FT * DistLat))
CalcLat = NewLat
Else
NewLat = (OrigLat + (FT * DistLat))
CalcLat = NewLat
End If
End Function

Original poster said:
"So I have 50.0452345 (x) and 4.3242234 (y) and I want to know x + 500 meters..."
I will assume the units of the x and y values he gave there were in meters (and not degrees Longitude, Latitude). If so then he is stating measurements to 0.1 micrometer, so I will assume he needs similar accuracy for the translated output. I also will assume by "+500 meters" etc. he meant
the direction to be due North-South and due East-West.
He refers to a reference point:
"2 new latitudes based on a coordinate";
but he did not give the Longitude and Latitude,
so to explain the procedure concretely I will give
the Latitudes and Longitudes for the corners of the
500 meter box he requested around the point
[30 degrees Longitude,30 degrees Latitude].
The exact solution on the surface of the GRS80 Ellipsoid is
given with the following set of functions
(I wrote these for the free-open-source-mac-pc math program called "PARI"
which allows any number of digits precision to be setup):
\\=======Arc lengths along Latitude and Longitude and the respective scales:
dms(u)=[truncate(u),truncate((u-truncate(u))*60),((u-truncate(u))*60-truncate((u-truncate(u))*60))*60];
SpinEarthRadiansPerSec=7.292115e-5;\
GMearth=3986005e8;\
J2earth=108263e-8;\
re=6378137;\
ecc=solve(ecc=.0001,.9999,eccp=ecc/sqrt(1-ecc^2);qecc=(1+3/eccp^2)*atan(eccp)-3/eccp;ecc^2-(3*J2earth+4/15*SpinEarthRadiansPerSec^2*re^3/GMearth*ecc^3/qecc));\
e2=ecc^2;\
b2=1-e2;\
b=sqrt(b2);\
fl=1-b;\
rfl=1/fl;\
U0=GMearth/ecc/re*atan(eccp)+1/3*SpinEarthRadiansPerSec^2*re^2;\
HeightAboveEllipsoid=0;\
reh=re+HeightAboveEllipsoid;\
longscale(lat)=reh*Pi/648000/sqrt(1+b2*(tan(lat))^2);
latscale(lat)=reh*b*Pi/648000/(1-e2*(sin(lat))^2)^(3/2);
longarc(lat,long1,long2)=longscale(lat)*648000/Pi*(long2-long1);
latarc(lat1,lat2)=(intnum(th=lat1,lat2,sqrt(1-e2*(sin(th))^2))+e2/2*sin(2*lat1)/sqrt(1-e2*(sin(lat1))^2)-e2/2*sin(2*lat2)/sqrt(1-e2*(sin(lat2))^2))*reh;
\\=======
I then plugged the reference point [30,30]
into those functions at the PARI command prompt
and had PARI solve for the point +/- 500 meters away
from it, giving the two new Longitudes and
two new Latitudes that the original poster asked for.
Here is the input and output showing that:
? dms(solve(x=29,31,longarc(30*Pi/180,30*Pi/180,x*Pi/180)+500))
cpu time = 1 ms, real time = 1 ms.
%1172 = [29, 59, 41.3444979398934670450280297216509190843055]
? dms(solve(x=29,31,longarc(30*Pi/180,30*Pi/180,x*Pi/180)-500))
cpu time = 1 ms, real time = 1 ms.
%1173 = [30, 0, 18.6555020601065329549719702783490809156945]
? dms(solve(x=29,31,latarc(30*Pi/180,x*Pi/180)+500))
cpu time = 1,357 ms, real time = 1,358 ms.
%1174 = [29, 59, 43.7621925447500548285775757329518579545513]
? dms(solve(x=29,31,latarc(30*Pi/180,x*Pi/180)-500))
cpu time = 1,365 ms, real time = 1,368 ms.
%1175 = [30, 0, 16.2377963202802863245716034907838199823349]
?

Related

I am trying to calculate sine of an angle without using the Math.sin() in java

I am trying to calculate sine of an angle without using the Math.sin(). I got stuck in it's equation as I keep getting the wrong results
note I have a method that changes the angle from degrees to radians
public static double sin(double x, int precision) {
//this method is simply the sine function
double answer = 1, power = 1;
int n = 2,factorial = 1;
while (n<=precision) {
power = (power * x * x *-1) +1 ;
factorial = (factorial * (n +1))* (n-1);
answer = answer + ((power/factorial ));
n = n + 2;
}
return answer;
}
It looks like you're attempting to calculate the sine of angle given in radians using the Maclaurin series, a special case of Taylor series.
sin(x) = x - x^3/3! + x^5/5! - x^7/7! + ...
Your initial answer is 1 when it should be x. Your initial power is 1 when it should be x also.
double answer = x, power = x;
For some reason you're adding one to the power part of the result when you shouldn't be.
power = (power * x * x * -1);
You'll also need to fix your factorial calculation. Multiply by n + 1 and n, not n + 1 and n - 1.
factorial = (factorial * (n + 1)) * (n);
With these fixes, testing:
for (double angle = 0; angle <= Math.PI; angle += Math.PI / 4)
{
System.out.println("sin(" + angle + ") = " + sin(angle, 10));
}
The results are pretty good considering the limitations of precision for floating point arithmetic.
sin(0.0) = 0.0
sin(0.7853981633974483) = 0.7071067811796194
sin(1.5707963267948966) = 0.999999943741051
sin(2.356194490192345) = 0.7070959900908971
sin(3.141592653589793) = -4.4516023820965686E-4
Note that this will get more inaccurate as the values of x get larger, not just because of the inaccuracy to represent pi, but also because of the floating point calculations for adding and subtracting large values.

Java - Calculate second coordinates from a given coordinates, bearing, and distance

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.

Haversin formula for distance less than 5 meter

I am trying to use the haversin formula to prevent updating the mysql table. I am implementing an app based on crowdsorucing where the data mac, route, lat, long is being recorded by the devices of the passangers im bus and send to the server.
My database table has mac address as UNIQUE KEY. So to avoid that other passanger in the same bus to store their data in the table I would filter these requests by using the Haversin formula but I tried it with tow point which are roughly 20 meter close to each other but I am gettig number of 4803.800129810092
//calculate the distance between the request's sender and all other request in the ArrayList.
private double haversineDistance(LatLong x, LatLong y) {
final int R = 6371; // Radious of the earth
double xLat = x.getLatitude();
double xLon = x.getLongitude();
double yLat = y.getLongitude();
double yLon = y.getLongitude();
;
double latDistance = toRad(yLat - xLat);
double lonDistance = toRad(yLon - xLon);
double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2)
+ Math.cos(toRad(xLat)) * Math.cos(toRad(yLat))
* Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double distance = R * c;
System.out.println("The distance between two lat and long is:" + distance);
return distance;
}
Haversine is overkill for this. Pythagoras is adequate.
Below is javascript function to return distances in metres. I am sure you can convert to Java'
function Pyth(lat1,lat2,lng1,lng2){
x = toRad(lng2-lng1) ;
y = toRad(lat2-lat1);
R = 6371000; // gives d in metres
d = sqrt(x*x + y*y) * R;
return d;
}

Get Longitude Laltitude of a point in my Worldmap in Mollweide projection

I searched about a day now, but didnt find any example for my problem in Javacode.
I have a worldmap with a size of 2000*1400 Pixels with a 'Mollweide' projection.
How can I find out what is the longitude and laltitude of the point (500,300) in my map ?
I would like to code this in Java.
I tried to do this with the 'Java Map Projection Library' :
Point2D.Double pointonmap = null;
Point2D.Double latlon = null;
MolleweideProjection molproj=new MolleweideProjection();
pointonmap = new Point2D.Double (1400,1000);
latlon=molproj.inverseTransform(pointonmap,new Point2D.Double ());
System.out.println("latlon: " + latlon.getX() + ", " + latlon.getY());
Could anyone help me with that ? Codeexample or hint.
thanks and regards
Wikipedia has most of the information you need:
These formulas assume a few things, as usual.
They speak in projected dimension, which is smaller than the component.
[0,0] is at the centre, not top left.
Y coordinate goes up rather than goes down.
And the result is in radius instead of degree.
Fix these and they'll work for you.
Since you didn't provide a link, I assume you are using the Java Map Projection Library on GitHub.
Without documentation and with limited time, I can't understand inverseTransform well enough to fix your code; but the bundled MapComponent is simpler to code:
map.addMouseListener( new MouseAdapter() { #Override public void mouseClicked( MouseEvent e ) {
double x = e.getX() - map.getWidth() / 2, // Mouse X with [0,0] at centre.
y = e.getY() - map.getHeight() / 2, // Mouse Y with [0,0] at centre.
// Max Y of projected map, in pixel with [0,0] at centre.
maxY = map.getMapExtension().getMaxY() * map.getScaleToShowAll(),
sqrt2 = Math.sqrt( 2 ), // Can be optimised away, but let's be faithful.
R = maxY / sqrt2, // Radius of projection, in pixel.
theta = Math.asin( y / ( R * sqrt2 ) );
int delta_long = -lon0Slider.getValue(); // Longtitude shift from -180 to 180.
// Find lat long in radius and converts to degree.
double latInRad = Math.asin( -( 2 * theta + Math.sin( 2 * theta ) ) / Math.PI ),
latitude = Math.toDegrees( latInRad ),
longInRad = Math.PI * x / ( 2 * R * sqrt2 * Math.cos( theta ) ),
longitude = Math.toDegrees( longInRad ) + delta_long;
System.out.println( "Lat: " + latitude + ", Long: " + longitude );
}
You can paste this code into the constructor of ch.ethz.karto.gui.ProjectionSelectionPanel.
The IDE should reports that two methods of the map is private, and you need to change them to public first (or use reflection).
Then launch it, select Mollweide, click on the globe and watch the console. Feel free to resize the window.
This answer uses information from the English Wikipedia entry on Mollweide projection. I've pretty much transcribed the formula from there verbatim.
The short answer, so you can write your own code:
Get the map's radius, r:
projectionWidth /(2 * √2)
Get theta, the point's angle along the map:
arcsine(y / (r * √2))
Note: Arcsine is the inverse of sine. Use Math.asin(a) in java
Get the latitude:
arcsine((2 * theta + sine(2 * theta)) / PI)
Get the longitude:
PI * x / (2 * R * √2 * cosine(theta)) + central meridian.
Or you can copyPasta this.
It's not very efficient; x and y are spec as doubles becaus too lazy to write typecast avoid narrowing
no-setters no-getters all-vars public
all-world-one-love Dr. Bronner's TV-dinners solve your problems for you
and stuff
enoj
public class MolleweidePoint
{
public double x, y, latitude, longitude;
public MolleweidePoint(double projectionWidth, double x, double y)
{
double rootTwo = Math.sqrt(2);
double r = projectionWidth / 2 / rootTwo;
double theta = Math.asin(y / r / rootTwo);
this.x = x;
this.y = y;
longitude = Math.PI * x / 2 / r / rootTwo / Math.cos(theta);
latitude = Math.asin(2 * theta + Math.sin(2 * theta) / Math.PI);
}
}
After calling the constructor like
MolleweidePoint ted = new MolleweidePoint(projection.width, 300, 500)
you can get the latitude and longitude from ted.longitude and ted.latitude. Also, longitude may have to be adjusted based on where the central meridian is placed on your projection.

Calculating the angle between two lines without having to calculate the slope? (Java)

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)))

Categories