I have a problem with calculation angle between lines created by connecting three geopoints.
p1
\ p2
\ /
p3
I implemented many solutions but not gave me expected result. For example I used law of cosinuses Direct way of computing clockwise angle between 2 vectors .
I also used equation
angle = atan2(vector2.y, vector2.x) - atan2(vector1.y, vector1.x).
Each method returned the same incorect result.
For example I have three points:
p3 latitude=52.66346360584388, 19.056108732273625
p1 latitude=52.66321959338828, 19.056379848488714
p2 latitude=52.66348185383115, 19.05648061759354
Law of cosinuses and atan2 returned angle 44.797 degrees. When I marker this points in google maps and measure the angle in gimp program I have about 57 degrees. In other sets of points the differences are the same or greater. What am I doing wrong?
gimp angle
For spherical geometry you need to use special formulas from here
Look at bearing section, calculate bearings from p3 to p2 and from p3 to p1 and find their difference
Formula:
θ = atan2( sin Δλ ⋅ cos φ2 , cos φ1 ⋅ sin φ2 − sin φ1 ⋅ cos φ2 ⋅ cos Δλ )
where φ1,λ1 is the start point,
φ2,λ2 the end point (Δλ is the difference in longitude)
JavaScript: (all angles in radians)
var y = Math.sin(λ2-λ1) * Math.cos(φ2);
var x = Math.cos(φ1)*Math.sin(φ2) -
Math.sin(φ1)*Math.cos(φ2)*Math.cos(λ2-λ1);
var brng = Math.atan2(y, x).toDegrees();
Related
I have two set's of longitude and latitude, i am desperately trying to figure out how many meters point A is displaced from point B, horizontally and vertically.
My goal would be have to +/-X and +/-Y values - I already have the shortest distance between the two points via Location.distanceBetween()....i thought i could use this with the Location.bearingTo() to find the values im looking for via basic trigonometry.
My thinking was i could use the bearing as angle A, 90 degrees as angle C and legnth of Side C (distanceBetween) to calculate the legnth of side A (x axis) and B (y axis) but the results were underwhelming to say the least lol
//CALCULATE ANGLES
double ANGLE_A;
ANGLE_A = current_Bearing; //Location.bearingTo()
ANGLE_A = ANGLE_A*Math.PI/180; //CONVERT DEGREES TO RADIANS
double ANGLE_C;
ANGLE_C = 90; // Always Right Angle
ANGLE_C = ANGLE_C*Math.PI/180; //CONVERT DEGREES TO RADIANS
double ANGLE_B;
ANGLE_B = 180 - ANGLE_A - ANGLE_C; // 3 sides of triangle must add up to 180, if 2 sides known 3rd can be calced
ANGLE_B = ANGLE_B*Math.PI/180; //CONVERT DEGREES TO RADIANS
//CALCULATE DISTANCES
double SIDE_C = calculatedDistance; //Location.distanceTo()
double SIDE_A = Math.sin(ANGLE_A) * SIDE_C /Math.sin(ANGLE_C);
double SIDE_B = Math.sin(ANGLE_B)*SIDE_C/Math.sin(ANGLE_C);
What im noticing is that my bearing changes very little between the two points regardless of how we move, though mind you im testing this at 10 - 100m distance, its always at 64.xxxxxxx and only the last few decimals really change.
All the online references i can find always look at computing the shortest path, and although this awesome site references x and y positions it always ends up combining them into shortest distance again
Would SUPER appreciate any pointers in the right direction!
Since the earth is not flat, your idea with 90 degree angles will not work properly.
What might be better, is this.
Lets say your 2 known points A and B have latitude and longitude latA, longA and latB, longB.
Now you could introduce two additional points C and D with latC = latA, longC = longB, and latD = latB, longD = longA, so the points A, B, C, D form a rectangle on the earth's surface.
Now you can simply use distanceBetween(A, C) and distanceBerween(A, D) to get the required distances.
It may be possible to utilize Location.distanceBetween(), if following conditions meet,
the points are located far apart from polar regions and
distance is short enough (compared to radius of the Earth).
The way is very simple. Just fix either longitude or latitude and vary only the other. Then calculate distance.
Location location1 = new Location("");
Location location2 = new Location("");
location1.setLatitude(37.4184359437);
location1.setLongitude(-122.088038921);
location2.setLatitude(37.3800232707);
location2.setLongitude(-122.073230422);
float[] distance = new float[3];
Location.distanceBetween(
location1.getLatitude(), location1.getLongitude(),
location2.getLatitude(), location2.getLongitude(),
distance
);
double lat_mid = (location1.getLatitude() + location2.getLatitude()) * 0.5;
double long_mid = (location1.getLongitude() + location2.getLongitude()) * 0.5;
float[] distanceLat = new float[3];
Location.distanceBetween(
location1.getLatitude(), long_mid,
location2.getLatitude(), long_mid,
distanceLat
);
float[] distanceLong = new float[3];
Location.distanceBetween(
lat_mid, location1.getLongitude(),
lat_mid, location2.getLongitude(),
distanceLong
);
double distance_approx = Math.sqrt(
Math.pow(distanceLong[0], 2.0) + Math.pow(distanceLat[0], 2.0)
);
Compare distance[0] and distance_approx, check whether accuracy meets your requiement.
If your points are close enough, you may easily calculate x-y distances from latitude / longitude once you know that 1 degree of latitude is 111km, and one degree of longitude is 111km * cos(latitude):
y_dist = abs(a.lat - b.lat) * 111000;
x_dist = abs(a.lon - b.lon) * 111000 * cos(a.lat);
For short distances we could easily ignore that earth is not exactly a sphere, the error is approximately 0.1-0.2% depending on your exact location.
There is no valid answer to this question until you define what projection.
The azimuth of a "straight" line varies along the route unless you are travelling exactly due south or due north. You can only calculate the angles at each node, or azimuth at a specific point along the route. Angles at the nodes will not add up to 180° because you're referring to an ellipsoidal triangle, and calculating an ellipsoidal triangle is a multiple-step process that in all honesty, is better left to the libraries out there such as OSGEO.
If you want to fit the geometry to a plane Cartesian, it is usually using the Lambert projection for areas mostly long on east and west directions, and Transverse Mercator on longer north to south projections. The entire Earth is mapped in the UTM (Universal Transverse Mercator) that will give you Cartesian coordinates anywhere, but in no case will you get perfect Eucldian geometry when dealing with geodetics. For instance, if you go south 10 miles, turn left 90° and go east for 10 miles, turn left 90° again, you can be anywhere from 10 miles from your starting point, to exactly back to where you started, if that point happened to be the North pole. So you may have a mathematically beautiful bearing on the UTM coordinate plane, but on the ground, you cannot turn the same angles as the UTM geometry indicates and follow that same path on ground. You will either follow a straight line on the ground and a curved line on a cartesian plane, or vice-versa.
You could do a distance between two points on the same northings and separately, the same eastings, and derive a north distance and an east distance. However, in reality the angles of this triangle will make sense only on paper, and not on the globe. If a plane took off at the bearing calculated by such a triangle, it would arrive in the wrong continent.
I need to measure angle between two vectors. I have .kml file that is filled with Latitutes and longitutes
54.90627884784906, 23.98023512082725
54.90568158443394, 23.98021489919758
54.9055211876991, 23.97995622451836
...
So here how I made my vectors:
Vector3 firstVec = new Vector3(new Point3((float)54.90627884784906, (float)23.98023512082725, 0),
new Point3((float)54.90568158443394, (float)23.98021489919758, 0));
Vector3 secondVec = new Vector3(new Point3((float)54.90568158443394, (float)23.98021489919758, 0),
new Point3((float)54.9055211876991, (float)23.97995622451836, 0));
here how I measure angle between two vectors
double angle = firstVec.angle(secondVec);
and here's my result:
0.9824845194816589
Here's image image on my phone representing these coordinates.
Obviously my angle is not correct. How to calculate it?
Your vectors are wrong.
Lat and lon are spherical angle coordinates. I'd recommend that you convert them to rectangular coordinates in 3D before you begin. Once you have those it's easy to calculate the angle in radians using the dot product.
You should also know that lat and lon are expressed in degrees - convert them to radians before you start using them in trig functions.
angle between two vector is Math.acos(Dot Product) result is in radiants, thus you'd multiply by Math.Pi/180
I am really struggeling to find the correct way to get the rotation angle around a single axis from an arbitrary quaternion. So other words I want to find the portion of the expressed rotation around a specified axis (in my case the Z-axis of the coordinate system, but an arbitrary solution would be nice) in terms of the angle. Can anyone point out to achieve this? Ideally some java fragment would be nice.
I tried the solution proposed in 1 for attitude, which is:
asin(2*qx*qy + 2*qz*qw)
However, this fails in some cases, e.g. a single rotation around the Z-axis with more than 0.6 * PI.
Angle and rotation axis of a quaternion
Every quaternion q can be decomposed as some kind of polar decomposition
q = r * (c + s * e)
where
r = |q|, s = |imag(q/r)|, c = real(q/r) and e = imag(q/s/r)
The axis of rotation of x ↦ q * x * q^(-1) is e, the angle is twice the angle α of the point (c,s)=(cos(α),sin(α)) on the unit circle.
To just compute the angle of rotation, the scaling by r is not that important, so
angle = 2*atan2( norm(imag(q)), real(q) )
Theory for Euler angles
A rotation about the X-axis is represented by a quaternion ca+sa*i, rotation about the Y axis by quaternion cb+sb*j and Z-axis by cc+sc*k where ca²+sa²=1 represent the cosine-sine pair of half the rotation angle a etc. Later 2a, c2a and s2a etc. will denote the double angle and its cosine and sine values.
Multiplying in the order xyz of application to the object at the origin gives a product
q=qw+qx*i+qy*j+qz*k
=(cc+sc*k)*(cb+sb*j)*(ca+sa*i)
Now interesting things happen in q*i*q^(-1) and q^(-1)*k*q, in that the inner terms commute and cancel, so that
q*i*q^(-1)*(-i) = (cc+sc*k)*(cb+sb*j)*(cb+sb*j)*(cc+sc*k)
= (cc+sc*k)*(c2b+s2b*j)*(cc+sc*k)
= (c2c+s2c*k)*c2b+s2b*j
(-k)*q^(-1)*k*q = (ca+sa*i)*(cb+sb*j)*(cb+sb*j)*(ca+sa*i)
=(ca+sa*i)*(c2b+s2b*j)*(ca+sa*i)
=(c2a+s2a*i)*c2b+s2b*j
which can then be used to isolate the angles 2a, 2b and 2c from
q*i*q^(-1)*(-i) = (q*i)*(i*q)^(-1)
= (qw*i-qx-qy*k+qz*j)*(-qw*i-qx-qy*k+qz*j)
= (qw²+qx²-qy²-qz²)
+ 2*(qw*qy-qx*qz)*j
+ 2*(qw*qz+qx*qy)*k
(-k)*q^(-1)*k*q = (q*k)^(-1)*(k*q)
= (-qw*k+qx*j-qy*i-qz)*(qw*k+qx*j-qy*i-qz)
= (qw²-qx²-qy²+qz²)
+ 2*(qw*qx+qy*qz)*i
+ 2*(qw*qy-qx*qz)*j
Resulting algorithm
Identifying expressions results in
s2b = 2*(qw*qy-qx*qz)
c2b*(c2a+s2a*i) = (qw²-qx²-qy²+qz²) + 2*(qw*qx+qy*qz)*i
c2b*(c2c+s2c*k) = (qw²+qx²-qy²-qz²) + 2*(qw*qz+qx*qy)*k
or
2a = atan2(2*(qw*qx+qy*qz), (qw²-qx²-qy²+qz²))
2b = asin(2*(qw*qy-qx*qz))
2c = atan2(2*(qw*qz+qx*qy), (qw²+qx²-qy²-qz²))
This constructs the angles in a way that
c2b=sqrt( (qw²+qx²+qy²+qz²)²+8*qw*qx*qy*qz )
is positive, so 2b is between -pi/2 and pi/2. By some sign manipulations, one could also obtain a solution where c2b is negative.
Answer to the question on the asin formula
Obviously, a different kind of rotation order was used, where the Z-rotation is the middle rotation. To be precise,
q = (cb+sb*j)*(cc+sc*k)*(ca+sa*i)
where
2b = heading
2a = bank
2c = attitude
To handle attitude rotation angles 2c larger that 0.5*pi, you need to compute the full set of Euler angles, since they will then contain two flips around the other axes before and after the Z-rotation.
Or you need to detect this situation, either by keeping the cosine of bank positive or by checking for overly large angle changes, and apply sign modifications inside the atan formulas, changing their resulting angle by pi (+or-), and change the Z angle computation to pi-asin(...)
Or, to only manipulate the angles after computation, if (2a,2b,2c) is the computed solution, then
(2a-sign(2a)*pi, 2b-sign(2b)*pi, sign(2c)*pi-2c)
is another solution giving the same quaternion and rotation. Chose the one that is closest to the expected behavior.
The answer can be found here Component of a quaternion rotation around an axis
"swing twist decomposition" from http://www.euclideanspace.com/maths/geometry/rotations/for/decomposition/
I have seen similar questions on here but just cannot get the math to work.
I have a circle, with two known points on the circumference (x1,y1,x2,y2) with the center of the circle as cx,cy
If I am stood at cx,cy and looking at point x1,y1 how can I tell which way I need to turn to face x2,y2?
So far I am working out the angle to each point
Atan((cx-x1) / (cy-y1))
Atan((cx-x2) / (cy-y2))
I have then tried a simple subtraction, using mod to ensure both are between -2pi and 2pi but I just get some strange answers. It appears the odd results occur when the two points lie above and below the horizontal line drawn through the center point.
But ill be honest I have tried so many things now my head hurts! It does not have to be a computationally fast solution as its only done once. Thanks in advance.
The answer is given to you by the sign of (x1-cx)(y2-cy) - (y1-cy)(x2-cx).
Proof:
Let A be the direction from C to (x1,y1), expressed as an angle measured anticlockwise from the X axis; B be the direction from C to (x2,y2), expressed the same way; and r be the radius of the circle. Then (x2,y2) is to the right of (x1,y1), as seen from C, if A-B lies between 0 and pi or between -2pi and -pi (that is, if sin(A-B) is positive), and to the left if A-B lies between -pi and 0 or between pi and 2pi (that is, if sin(A-B) is negative).
Now,
(x1,y1)=(Cx + r cos A, Cy + r sin A)
(x2,y2)=(Cx + r cos B, Cy + r sin B)
So
(x1-Cx)(y2-Cy) - (y1-Cy)(x2-Cy)
= (r cos A)(r sin B) - (r sin A)(r cos B)
= - r^2 (sin A cos B - cos A sin B)
= - r^2 (sin (A-B))
which has the opposite sign to sin (A-B).
Let's say A1 is the angle between the vector from (cx, cy) to (x1, y1) and the horizontal axis, and A2 is the angle between the vector from (cx, cy) to (x2, y2) and the horizontal axis. When you sit at (cx, cy) and look at the point (x1, y1), the point (x2, y2) is on your right if and only if the angle between the two vectors is less than pi and on your left if and only if the angle is more than pi.
Since the sine of a positive angle is positive from 0 to pi and negative from pi to 2*pi, then it follows that the point is on your right iff sin(A2-A1) > 0 and on your left iff sin(A2-A1) < 0.
If we use the usual trigonometric identity, we have that
sin(A2-A1) = sin(A2) * cos(A1) - sin(A1) * cos(A2)
Then you just have to replace the sine and cosine by their formula with the cartesian coordinates. The denominator is factored out because the points sit on a circle.
Therefore the sign of sin(A2-A1) is the same as the sign of (x2-cx)*(y1-cy) - (x1-cx)*(y2-cy).
I'm implementing a simulation in Java using a GIS (WGS84). I want to place my agents shifted to each other. The latitude is easy 1 m is 1/111000 degrees. But I want to shift an agent on the longitude side I have to consider earth curvature (I guess!).
I found this formula on Wiki: a= (2*pi*r*cos(phi))/360
r : radius
phi: latitude
a : should be the distance
I tried now multiply my distances to 1/a, but the positions are not logical!
Is it your goal to calculate the distance between your two points?
I would use:
d(P1, P2) = ((r · pi)/180)) · cos−1 (cos(a1) · cos(a2) · cos(b1 − b2) + sin(a1) · sin(a2))
where d is distance, r would be the earth radius, cos-1 is the inverse cosinus and a1,a2,b1,b2 are the angles of your 2 agents
If you know the vertical and horizontal distance (l and h), you can simply calculate b1 = a1 - l/(2*pi*r*cos(angleFromEquator)*360) and a2 = h/(2*pi*r*360) + b2 if you are using spherical coordinates.
If you are at the equator (latitude = 0) and you shift 1.000 km to the east, you would end up ( 1.000 km / 40.000 km ) * 360° = 9° further east.
At a latitude of 45°, that would be ( 1.000 km / 28.000 km ) * 360° = 12.8°
If you'll move 1Km east, and then 1Km north, you'll reach a different location than if you'll move 1Km north and then 1Km east.
On extreme cases (specific latitudes near the north pole), moving 1Km east will bring you back to your original location.
Your concept of separating latitudinal and longitudinal 'shift' is wrong, since it is not suitable for locations on the surface of a sphere/ellipsoid.
Anyway, if your are looking for the earth's circumference at a given latitude, and a spherical model is accurate enough for your needs, look here.