Not getting the correct orientation of the user with respect to Kinect - algorithm

I am using Microsoft Kinect in a project. One of the task that I have to accomplish is to find the orientation of the user w.r.t the Kinect sensor (when the user turns, the orientation changes)
For this, I am trying to find the angle which the line joining the shoulders makes with the x axis of Kinect.
I have come up with the following code, but it gives me very small angle values, even when I turn almost about 40 degrees.
double vector_x=skel.SkeletonPositions[NUI_SKELETON_POSITION_SHOULDER_LEFT].x-skel.SkeletonPositions[NUI_SKELETON_POSITION_SHOULDER_RIGHT].x;
double vector_y=skel.SkeletonPositions[NUI_SKELETON_POSITION_SHOULDER_LEFT].y-skel.SkeletonPositions[NUI_SKELETON_POSITION_SHOULDER_RIGHT].y;
double vector_z=skel.SkeletonPositions[NUI_SKELETON_POSITION_SHOULDER_LEFT].z-skel.SkeletonPositions[NUI_SKELETON_POSITION_SHOULDER_RIGHT].z;
double len1=sqrtf(vector_x * vector_x + vector_y * vector_y + vector_z * vector_z);
double vector_x1=1.0;
double vector_y1=0.0;
double vector_z1=0.0;
double len2=sqrtf(vector_x1 * vector_x1 + vector_y1 * vector_y1 + vector_z1 * vector_z1);
double dot_product = vector_x * vector_x1 + vector_y * vector_y1 + vector_z * vector_z1;
double angle = dot_product / (len1 * len2);
coor_left=Convert(vector_x)+"\t"+Convert(vector_y)+"\t"+Convert(vector_z)+"\n";
OutputDebugStringA(Convert(acos(angle)).c_str());
When I added the conversion of radians to degrees,
double angle1=angle*180.0/3.14;
I get values form -33 to -57(when I am facing the Kinect) and then to -33 again.
But in reality, it should be negative, then 0 and then positive on the other side. Where am I going wrong?

I solved it myself. I realised that I was finding the angle between incorrect vectors.
All I needed to do was to take the projection of the left and the right shoulders on the x-z plane and then reduce the problem to finding the angle between two vectors in a plane.
Here is what I did:
double CalcAngle(double p1x,double p1y, double p2x,double p2y, double p3x,double p3y, double p4x,double p4y)
{
//
// calculate the angle between the line from p1 to p2
// and the line from p3 to p4
//
double x1 = p1x - p2x;
double y1 = p1y - p2y;
double x2 = p3x - p4x;
double y2 = p3y - p4y;
//
double angle1 , angle2 , angle;
//
if (x1 != 0.0f)
angle1 = atan(y1/x1);
else
angle1 = 3.14159 / 2.0; // 90 degrees
//
if (x2 != 0.0f)
angle2 = atan(y2/x2);
else
angle2 = 3.14159 / 2.0; // 90 degrees
//
angle = fabs(angle2-angle1);
angle = angle * 180.0 / 3.14159; // convert to degrees ???
//
return angle;
}
double myangle=CalcAngle(skel.SkeletonPositions[NUI_SKELETON_POSITION_SHOULDER_LEFT].x,skel.SkeletonPositions[NUI_SKELETON_POSITION_SHOULDER_LEFT].z,
skel.SkeletonPositions[NUI_SKELETON_POSITION_SHOULDER_RIGHT].x,skel.SkeletonPositions[NUI_SKELETON_POSITION_SHOULDER_RIGHT].z,
0,0,1,0);
OutputDebugStringA(Convert(myangle).c_str());
OutputDebugStringA("\n");

Related

using spherical coordinates in opengl

I am trying to plot points around a center point using spherical coordinates. I know this is by far not the most efficient way to plot a sphere in OpenGL but i want to do it as an excersive to understand spherical coordinates better.
I want to step through each point by a certain angle so for this i have a nested for loop itterating through theta 0 - 360 and phi 0-360 and i am attempting to get the Cartesian coordinates of each of these steps and display it as a single point.
so far i have this:
float r = 1.0;
for( float theta = 0.0; theta < 360.0; theta += 10.0){
for(float phi = 0.0; phi < 360.0; phi += 10.0){
float x = r * sin(theta) * cos(phi);
float y = r * sin(theta) * sin(phi);
float z = r * cos(theta);
}
}
i store these points a display them. the display function works fine as i have used it to display other point structure before but for some reason i can't get this to work.
I have also tried converting the angles from degrees to radians:
float rTheta = theta * M_PI * 180.0;
float rPhi = phi * M_PI * 18.0;
as sin() and cos() both use radians but it yields the same results.
Am i doing something wrong and badly misunderstanding something?
In the conversion from degrees to radians of angle x, the correct formula is x * M_PI / 180..

Algorithm to detect when and where a point will exit a rectangle area

Assume that we have a rectangle or a square and we know the x,y coordinates of its corners (4 corners).
Also assume that we have a point inside that square for which we know its coordinates (x,y), its speed (km/h), its heading (heading is measured in directional degrees, 0 for north, 180 for south and so on) and the time point it has these attributes (epoch time in seconds).
How can we calculate the time point (epoch time in seconds) in which the point will exit the rectangle as well as the coordinates (x,y) of the exit ?
You need to find what edge is intersected first. Make equations for moving along both coordinates and calculate the first time of intersection.
Note that for geographic coordinates you might need more complex calculations because "rectangle" defined by Lat/Lon coordinates is really curvy trapezoid on the Earth surface. Look at "Intersection of two paths given start points and bearings" chapter on this page to get travel time.
vx = V * Cos(heading + Pi/2) //for y-axis north=0
vy = V * Sin(heading + Pi/2)
x = x0 + vx * t
y = y0 + vy * t
//potential border positions
if vx > 0 then
ex = x2
else
ex = x1
if vy > 0 then
ey = y2
else
ey = y1
//check for horizontal/vertical directions
if vx = 0 then
return cx = x0, cy = ey, ct = (ey - y0) / vy
if vy = 0 then
return cx = ex, cy = y0, ct = (ex - x0) / vx
//in general case find times of intersections with horizontal and vertical edge line
tx = (ex - x0) / vx
ty = (ey - y0) / vy
//and get intersection for smaller parameter value
if tx <= ty then
return cx = ex, cy = y0 + tx * vy, ct = tx
else
return cx = x0 + ty * vx, cy = ey, ct = ty

Calculate direction angle from two vectors?

Say I have two 2D vectors, one for an objects current position and one for that objects previous position. How can I work out the angular direction of travel?
This image might help understand what I'm after:
(image) http://files.me.com/james.ingham/crcvmy
The direction vector of travel will be the difference of the two position vectors,
d = (x1, y1) - (x, y) = (x1 - x, y1 - y)
Now when you ask for the direction angle, that depends what direction you want to measure the angle against. Is it against the x axis? Go with Radu's answer. Against an arbitrary vector? See justjeff's answer.
Edit: To get the angle against the y-axis:
tan (theta) = (x1 -x)/(y1 - y)
the tangent of the angle is the ratio of the x-coordinate of the difference vector to the y-coordinate of the difference vector.
So
theta = arctan[(x1 - x)/(y1 - y)]
Where arctan means inverse tangent. Not to be confused with the reciprocal of the tangent, which many people do, since they're both frequently denoted tan^-1. And make sure you know whether you're working in degrees or radians.
If you're in C (or other language that uses the same function set) then you're probably looking for the atan2() function. From your diagram:
double theta = atan2(x1-x, y1-y);
That angle will be from the vertical axis, as you marked, and will be measured in radians (God's own angle unit).
Be careful to use atan2 to avoid quadrant issues and division by zero. That's what it's there for.
float getAngle(CGPoint ptA, CGPoint ptOrigin, CGPoint ptB)
{
CGPoint A = makeVec(ptOrigin, ptA);
CGPoint B = makeVec(ptOrigin, ptB);
// angle with +ve x-axis, in the range (−π, π]
float thetaA = atan2(A.x, A.y);
float thetaB = atan2(B.x, B.y);
float thetaAB = thetaB - thetaA;
// get in range (−π, π]
while (thetaAB <= - M_PI)
thetaAB += 2 * M_PI;
while (thetaAB > M_PI)
thetaAB -= 2 * M_PI;
return thetaAB;
}
However, if you don't care about whether it's a +ve or -ve angle, just use the dot product rule (less CPU load):
float dotProduct(CGPoint p1, CGPoint p2) { return p1.x * p2.x + p1.y * p2.y; }
float getAngle(CGPoint A, CGPoint O, CGPoint B)
{
CGPoint U = makeVec(O, A);
CGPoint V = makeVec(O, B);
float magU = vecGetMag(U);
float magV = vecGetMag(V);
float magUmagV = magU * magV; assert (ABS(magUmagV) > 0.00001);
// U.V = |U| |V| cos t
float cosT = dotProduct(U, V) / magUmagV;
float theta = acos(cosT);
return theta;
}
Note that in either code section above, if one ( or both ) vectors are close to 0 length this is going to fail. So you might want to trap that somehow.
Still not sure what you mean by rotation matrices, but this is a simple case of getting an azimuth from a direction vector.
The complicated answer:
Normally you should pack a few conversion/utility functions with your 2D vectors: one to convert from X,Y (carthesian) to Theta,R (polar coordinates). You should also support basic vector operations like addition, substraction and dot product.
Your answer in this case would be:
double azimuth = (P2 - P1).ToPolarCoordinate().Azimuth;
Where ToPolarCoordinate() and ToCarhtesianCoordinate() are two reciprocal functions switching from one type of vector to another.
The simple one:
double azimuth = acos ((x2-x1)/sqrt((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1));
//then do a quadrant resolution based on the +/- sign of (y2-y1) and (x2-x1)
if (x2-x1)>0 {
if (y2-y1)<0 { azimuth = Pi-azimuth; } //quadrant 2
} else
{ if (y2-y1)> 0 { azimuth = 2*Pi-azimuth;} //quadrant 4
else { azimuth = Pi + azimuth;} //quadrant 3
}

How to calculate an angle from three points? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 4 years ago.
Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
Lets say you have this:
P1 = (x=2, y=50)
P2 = (x=9, y=40)
P3 = (x=5, y=20)
Assume that P1 is the center point of a circle. It is always the same.
I want the angle that is made up by P2 and P3, or in other words the angle that is next to P1. The inner angle to be precise. It will always be an acute angle, so less than -90 degrees.
I thought: Man, that's simple geometry math. But I have looked for a formula for around 6 hours now, and only find people talking about complicated NASA stuff like arccos and vector scalar product stuff. My head feels like it's in a fridge.
Some math gurus here that think this is a simple problem? I don't think the programming language matters here, but for those who think it does: java and objective-c. I need it for both, but haven't tagged it for these.
If you mean the angle that P1 is the vertex of then using the Law of Cosines should work:
arccos((P122
+ P132 - P232) / (2 *
P12 * P13))
where P12 is the length of the segment from P1 to P2, calculated by
sqrt((P1x -
P2x)2 +
(P1y -
P2y)2)
It gets very simple if you think it as two vectors, one from point P1 to P2 and one from P1 to P3
so:
a = (p1.x - p2.x, p1.y - p2.y)
b = (p1.x - p3.x, p1.y - p3.y)
You can then invert the dot product formula:
to get the angle:
Remember that just means:
a1*b1 + a2*b2 (just 2 dimensions here...)
The best way to deal with angle computation is to use atan2(y, x) that given a point x, y returns the angle from that point and the X+ axis in respect to the origin.
Given that the computation is
double result = atan2(P3.y - P1.y, P3.x - P1.x) -
atan2(P2.y - P1.y, P2.x - P1.x);
i.e. you basically translate the two points by -P1 (in other words you translate everything so that P1 ends up in the origin) and then you consider the difference of the absolute angles of P3 and of P2.
The advantages of atan2 is that the full circle is represented (you can get any number between -π and π) where instead with acos you need to handle several cases depending on the signs to compute the correct result.
The only singular point for atan2 is (0, 0)... meaning that both P2 and P3 must be different from P1 as in that case doesn't make sense to talk about an angle.
Let me give an example in JavaScript, I've fought a lot with that:
/**
* Calculates the angle (in radians) between two vectors pointing outward from one center
*
* #param p0 first point
* #param p1 second point
* #param c center point
*/
function find_angle(p0,p1,c) {
var p0c = Math.sqrt(Math.pow(c.x-p0.x,2)+
Math.pow(c.y-p0.y,2)); // p0->c (b)
var p1c = Math.sqrt(Math.pow(c.x-p1.x,2)+
Math.pow(c.y-p1.y,2)); // p1->c (a)
var p0p1 = Math.sqrt(Math.pow(p1.x-p0.x,2)+
Math.pow(p1.y-p0.y,2)); // p0->p1 (c)
return Math.acos((p1c*p1c+p0c*p0c-p0p1*p0p1)/(2*p1c*p0c));
}
Bonus: Example with HTML5-canvas
Basically what you have is two vectors, one vector from P1 to P2 and another from P1 to P3. So all you need is an formula to calculate the angle between two vectors.
Have a look here for a good explanation and the formula.
If you are thinking of P1 as the center of a circle, you are thinking too complicated.
You have a simple triangle, so your problem is solveable with the law of cosines. No need for any polar coordinate tranformation or somesuch. Say the distances are P1-P2 = A, P2-P3 = B and P3-P1 = C:
Angle = arccos ( (B^2-A^2-C^2) / 2AC )
All you need to do is calculate the length of the distances A, B and C.
Those are easily available from the x- and y-coordinates of your points and
Pythagoras' theorem
Length = sqrt( (X2-X1)^2 + (Y2-Y1)^2 )
I ran into a similar problem recently, only I needed to differentiate between a positive and negative angles. In case this is of use to anyone, I recommend the code snippet I grabbed from this mailing list about detecting rotation over a touch event for Android:
#Override
public boolean onTouchEvent(MotionEvent e) {
float x = e.getX();
float y = e.getY();
switch (e.getAction()) {
case MotionEvent.ACTION_MOVE:
//find an approximate angle between them.
float dx = x-cx;
float dy = y-cy;
double a=Math.atan2(dy,dx);
float dpx= mPreviousX-cx;
float dpy= mPreviousY-cy;
double b=Math.atan2(dpy, dpx);
double diff = a-b;
this.bearing -= Math.toDegrees(diff);
this.invalidate();
}
mPreviousX = x;
mPreviousY = y;
return true;
}
Very Simple Geometric Solution with Explanation
Few days ago, a fell into the same problem & had to sit with the math book. I solved the problem by combining and simplifying some basic formulas.
Lets consider this figure-
We want to know ϴ, so we need to find out α and β first. Now, for any straight line-
y = m * x + c
Let- A = (ax, ay), B = (bx, by), and O = (ox, oy). So for the line OA-
oy = m1 * ox + c ⇒ c = oy - m1 * ox ...(eqn-1)
ay = m1 * ax + c ⇒ ay = m1 * ax + oy - m1 * ox [from eqn-1]
⇒ ay = m1 * ax + oy - m1 * ox
⇒ m1 = (ay - oy) / (ax - ox)
⇒ tan α = (ay - oy) / (ax - ox) [m = slope = tan ϴ] ...(eqn-2)
In the same way, for line OB-
tan β = (by - oy) / (bx - ox) ...(eqn-3)
Now, we need ϴ = β - α. In trigonometry we have a formula-
tan (β-α) = (tan β + tan α) / (1 - tan β * tan α) ...(eqn-4)
After replacing the value of tan α (from eqn-2) and tan b (from eqn-3) in eqn-4, and applying simplification we get-
tan (β-α) = ( (ax-ox)*(by-oy)+(ay-oy)*(bx-ox) ) / ( (ax-ox)*(bx-ox)-(ay-oy)*(by-oy) )
So,
ϴ = β-α = tan^(-1) ( ((ax-ox)*(by-oy)+(ay-oy)*(bx-ox)) / ((ax-ox)*(bx-ox)-(ay-oy)*(by-oy)) )
That is it!
Now, take following figure-
This C# or, Java method calculates the angle (ϴ)-
private double calculateAngle(double P1X, double P1Y, double P2X, double P2Y,
double P3X, double P3Y){
double numerator = P2Y*(P1X-P3X) + P1Y*(P3X-P2X) + P3Y*(P2X-P1X);
double denominator = (P2X-P1X)*(P1X-P3X) + (P2Y-P1Y)*(P1Y-P3Y);
double ratio = numerator/denominator;
double angleRad = Math.Atan(ratio);
double angleDeg = (angleRad*180)/Math.PI;
if(angleDeg<0){
angleDeg = 180+angleDeg;
}
return angleDeg;
}
In Objective-C you could do this by
float xpoint = (((atan2((newPoint.x - oldPoint.x) , (newPoint.y - oldPoint.y)))*180)/M_PI);
Or read more here
You mentioned a signed angle (-90). In many applications angles may have signs (positive and negative, see http://en.wikipedia.org/wiki/Angle). If the points are (say) P2(1,0), P1(0,0), P3(0,1) then the angle P3-P1-P2 is conventionally positive (PI/2) whereas the angle P2-P1-P3 is negative. Using the lengths of the sides will not distinguish between + and - so if this matters you will need to use vectors or a function such as Math.atan2(a, b).
Angles can also extend beyond 2*PI and while this is not relevant to the current question it was sufficiently important that I wrote my own Angle class (also to make sure that degrees and radians did not get mixed up). The questions as to whether angle1 is less than angle2 depends critically on how angles are defined. It may also be important to decide whether a line (-1,0)(0,0)(1,0) is represented as Math.PI or -Math.PI
Recently, I too have the same problem... In Delphi
It's very similar to Objective-C.
procedure TForm1.FormPaint(Sender: TObject);
var ARect: TRect;
AWidth, AHeight: Integer;
ABasePoint: TPoint;
AAngle: Extended;
begin
FCenter := Point(Width div 2, Height div 2);
AWidth := Width div 4;
AHeight := Height div 4;
ABasePoint := Point(FCenter.X+AWidth, FCenter.Y);
ARect := Rect(Point(FCenter.X - AWidth, FCenter.Y - AHeight),
Point(FCenter.X + AWidth, FCenter.Y + AHeight));
AAngle := ArcTan2(ClickPoint.Y-Center.Y, ClickPoint.X-Center.X) * 180 / pi;
AngleLabel.Caption := Format('Angle is %5.2f', [AAngle]);
Canvas.Ellipse(ARect);
Canvas.MoveTo(FCenter.X, FCenter.Y);
Canvas.LineTo(FClickPoint.X, FClickPoint.Y);
Canvas.MoveTo(FCenter.X, FCenter.Y);
Canvas.LineTo(ABasePoint.X, ABasePoint.Y);
end;
Here's a C# method to return the angle (0-360) anticlockwise from the horizontal for a point on a circle.
public static double GetAngle(Point centre, Point point1)
{
// Thanks to Dave Hill
// Turn into a vector (from the origin)
double x = point1.X - centre.X;
double y = point1.Y - centre.Y;
// Dot product u dot v = mag u * mag v * cos theta
// Therefore theta = cos -1 ((u dot v) / (mag u * mag v))
// Horizontal v = (1, 0)
// therefore theta = cos -1 (u.x / mag u)
// nb, there are 2 possible angles and if u.y is positive then angle is in first quadrant, negative then second quadrant
double magnitude = Math.Sqrt(x * x + y * y);
double angle = 0;
if(magnitude > 0)
angle = Math.Acos(x / magnitude);
angle = angle * 180 / Math.PI;
if (y < 0)
angle = 360 - angle;
return angle;
}
Cheers,
Paul
function p(x, y) {return {x,y}}
function normaliseToInteriorAngle(angle) {
if (angle < 0) {
angle += (2*Math.PI)
}
if (angle > Math.PI) {
angle = 2*Math.PI - angle
}
return angle
}
function angle(p1, center, p2) {
const transformedP1 = p(p1.x - center.x, p1.y - center.y)
const transformedP2 = p(p2.x - center.x, p2.y - center.y)
const angleToP1 = Math.atan2(transformedP1.y, transformedP1.x)
const angleToP2 = Math.atan2(transformedP2.y, transformedP2.x)
return normaliseToInteriorAngle(angleToP2 - angleToP1)
}
function toDegrees(radians) {
return 360 * radians / (2 * Math.PI)
}
console.log(toDegrees(angle(p(-10, 0), p(0, 0), p(0, -10))))
there IS a simple answer for this using high school math..
Let say that you have 3 points
To get angle from point A to B
angle = atan2(A.x - B.x, B.y - A.y)
To get angle from point B to C
angle2 = atan2(B.x - C.x, C.y - B.y)
Answer = 180 + angle2 - angle
If (answer < 0){
return answer + 360
}else{
return answer
}
I just used this code in the recent project that I made, change the B to P1.. you might as well remove the "180 +" if you want
well, the other answers seem to cover everything required, so I would like to just add this if you are using JMonkeyEngine:
Vector3f.angleBetween(otherVector)
as that is what I came here looking for :)
Atan2 output in degrees
PI/2 +90
| |
| |
PI ---.--- 0 +180 ---.--- 0
| |
| |
-PI/2 +270
public static double CalculateAngleFromHorizontal(double startX, double startY, double endX, double endY)
{
var atan = Math.Atan2(endY - startY, endX - startX); // Angle in radians
var angleDegrees = atan * (180 / Math.PI); // Angle in degrees (can be +/-)
if (angleDegrees < 0.0)
{
angleDegrees = 360.0 + angleDegrees;
}
return angleDegrees;
}
// Angle from point2 to point 3 counter clockwise
public static double CalculateAngle0To360(double centerX, double centerY, double x2, double y2, double x3, double y3)
{
var angle2 = CalculateAngleFromHorizontal(centerX, centerY, x2, y2);
var angle3 = CalculateAngleFromHorizontal(centerX, centerY, x3, y3);
return (360.0 + angle3 - angle2)%360;
}
// Smaller angle from point2 to point 3
public static double CalculateAngle0To180(double centerX, double centerY, double x2, double y2, double x3, double y3)
{
var angle = CalculateAngle0To360(centerX, centerY, x2, y2, x3, y3);
if (angle > 180.0)
{
angle = 360 - angle;
}
return angle;
}
}

How to find distance from the latitude and longitude of two locations?

I have a set of latitudes and longitudes of locations.
How to find distance from one location in the set to another?
Is there a formula ?
The Haversine formula assumes a spherical earth. However, the shape of the earh is more complex. An oblate spheroid model will give better results.
If such accuracy is needed, you should better use Vincenty inverse formula.
See http://en.wikipedia.org/wiki/Vincenty's_formulae for details. Using it, you can get a 0.5mm accuracy for the spheroid model.
There is no perfect formula, since the real shape of the earth is too complex to be expressed by a formula. Moreover, the shape of earth changes due to climate events (see http://www.nasa.gov/centers/goddard/earthandsun/earthshape.html), and also changes over time due to the rotation of the earth.
You should also note that the method above does not take altitudes into account, and assumes a sea-level oblate spheroid.
Edit 10-Jul-2010: I found out that there are rare situations for which Vincenty inverse formula does not converge to the declared accuracy. A better idea is to use GeographicLib (see http://sourceforge.net/projects/geographiclib/) which is also more accurate.
Here's one: http://www.movable-type.co.uk/scripts/latlong.html
Using Haversine formula:
R = earth’s radius (mean radius = 6,371km)
Δlat = lat2− lat1
Δlong = long2− long1
a = sin²(Δlat/2) + cos(lat1).cos(lat2).sin²(Δlong/2)
c = 2.atan2(√a, √(1−a))
d = R.c
Apply the Haversine formula to find the distance. See the C# code below to find the distance between 2 coordinates. Better still if you want to say find a list of stores within a certain radius, you could apply a WHERE clause in SQL or a LINQ filter in C# to it.
The formula here is in kilometres, you will have to change the relevant numbers and it will work for miles.
E.g: Convert 6371.392896 to miles.
DECLARE #radiusInKm AS FLOAT
DECLARE #lat2Compare AS FLOAT
DECLARE #long2Compare AS FLOAT
SET #radiusInKm = 5.000
SET #lat2Compare = insert_your_lat_to_compare_here
SET #long2Compare = insert_you_long_to_compare_here
SELECT * FROM insert_your_table_here WITH(NOLOCK)
WHERE (6371.392896*2*ATN2(SQRT((sin((radians(GeoLatitude - #lat2Compare)) / 2) * sin((radians(GeoLatitude - #lat2Compare)) / 2)) + (cos(radians(GeoLatitude)) * cos(radians(#lat2Compare)) * sin(radians(GeoLongitude - #long2Compare)/2) * sin(radians(GeoLongitude - #long2Compare)/2)))
, SQRT(1-((sin((radians(GeoLatitude - #lat2Compare)) / 2) * sin((radians(GeoLatitude - #lat2Compare)) / 2)) + (cos(radians(GeoLatitude)) * cos(radians(#lat2Compare)) * sin(radians(GeoLongitude - #long2Compare)/2) * sin(radians(GeoLongitude - #long2Compare)/2)))
))) <= #radiusInKm
If you would like to perform the Haversine formula in C#,
double resultDistance = 0.0;
double avgRadiusOfEarth = 6371.392896; //Radius of the earth differ, I'm taking the average.
//Haversine formula
//distance = R * 2 * aTan2 ( square root of A, square root of 1 - A )
// where A = sinus squared (difference in latitude / 2) + (cosine of latitude 1 * cosine of latitude 2 * sinus squared (difference in longitude / 2))
// and R = the circumference of the earth
double differenceInLat = DegreeToRadian(currentLatitude - latitudeToCompare);
double differenceInLong = DegreeToRadian(currentLongitude - longtitudeToCompare);
double aInnerFormula = Math.Cos(DegreeToRadian(currentLatitude)) * Math.Cos(DegreeToRadian(latitudeToCompare)) * Math.Sin(differenceInLong / 2) * Math.Sin(differenceInLong / 2);
double aFormula = (Math.Sin((differenceInLat) / 2) * Math.Sin((differenceInLat) / 2)) + (aInnerFormula);
resultDistance = avgRadiusOfEarth * 2 * Math.Atan2(Math.Sqrt(aFormula), Math.Sqrt(1 - aFormula));
DegreesToRadian is a function I custom created, its is a simple 1 liner of"Math.PI * angle / 180.0
My blog entry - SQL Haversine
Are you looking for
Haversine formula
The haversine formula is an equation
important in navigation, giving
great-circle distances between two
points on a sphere from their
longitudes and latitudes. It is a
special case of a more general formula
in spherical trigonometry, the law of
haversines, relating the sides and
angles of spherical "triangles".
Have a look at this.. has a javascript example as well.
Find Distance
Use the Great Circle Distance Formula.
here is a fiddle with finding locations / near locations to long/lat by given IP:
http://jsfiddle.net/bassta/zrgd9qc3/2/
And here is the function I use to calculate the distance in straight line:
function distance(lat1, lng1, lat2, lng2) {
var radlat1 = Math.PI * lat1 / 180;
var radlat2 = Math.PI * lat2 / 180;
var radlon1 = Math.PI * lng1 / 180;
var radlon2 = Math.PI * lng2 / 180;
var theta = lng1 - lng2;
var radtheta = Math.PI * theta / 180;
var dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
dist = Math.acos(dist);
dist = dist * 180 / Math.PI;
dist = dist * 60 * 1.1515;
//Get in in kilometers
dist = dist * 1.609344;
return dist;
}
It returns the distance in Kilometers
If you are measuring distances less than (perhaps) 1 degree lat/long change, are looking for a very high performance approximation, and are willing to accept more inaccuracy than Haversine formula, consider these two alternatives:
(1) "Polar Coordinate Flat-Earth Formula" from Computing Distances:
a = pi/2 - lat1
b = pi/2 - lat2
c = sqrt( a^2 + b^2 - 2 * a * b * cos(lon2 - lon1) )
d = R * c
(2) Pythagorean theorem adjusted for latitude, as seen in Ewan Todd's SO post:
d_ew = (long1 - long0) * cos(average(lat0, lat1))
d_ns = (lat1 - lat0)
d = sqrt(d_ew * d_ew + d_ns * d_ns)
NOTES:
Compared to Ewan's post, I've substituted average(lat0, lat1) for lat0 inside of cos( lat0 ).
#2 is vague on whether values are degrees, radians, or kilometers; you will need some conversion code as well. See my complete code at bottom of this post.
#1 is designed to work well even near the poles, though if you are measuring a distance whose endpoints are on "opposite" sides of the pole (longitudes differ by more than 90 degrees?), Haversine is recommended instead, even for small distances.
I haven't thoroughly measured errors of these approaches, so you should take representative points for your application, and compare results to some high-quality library, to decide if the accuracies are acceptable. For distances less than a few kilometers my gut sense is that these are within 1% of correct measurement.
An alternative way to gain high performance (when applicable):
If you have a large set of static points, within one or two degrees of longitude/latitude, that you will then be calculating distances from a small number of dynamic (moving) points, consider converting your static points ONCE to the containing UTM zone (or to any other local Cartesian coordinate system), and then doing all your math in that Cartesian coordinate system.
Cartesian = flat earth = Pythagorean theorem applies, so distance = sqrt(dx^2 + dy^2).
Then the cost of accurately converting the few moving points to UTM is easily afforded.
CAVEAT for #1 (Polar): May be very wrong for distances less than 0.1 (?) meter. Even with double precision math, the following coordinates, whose true distance is about 0.005 meters, was given as "zero" by my implementation of Polar algorithm:
inputs:
lon1Xdeg 16.6564465477996 double
lat1Ydeg 57.7760262271983 double
lon2Xdeg 16.6564466358281 double
lat2Ydeg 57.776026248554 double
results:
Oblate spheroid formula:
0.00575254911118364 double
Haversine:
0.00573422966122257 double
Polar:
0
this was due to the two factors u and v exactly canceling each other:
u 0.632619944868587 double
v -0.632619944868587 double
In another case, it gave a distance of 0.067129 m when the oblate spheroid answer was 0.002887 m. The problem was that cos(lon2 - lon1) was too close to 1, so cos function returned exactly 1.
Other than measuring sub-meter distances, the max errors (compared to an oblate spheroid formula) I found for the limited small-distance data I've fed in so far:
maxHaversineErrorRatio 0.00350976281908381 double
maxPolarErrorRatio 0.0510789996931342 double
where "1" would represent a 100% error in the answer; e.g. when it returned "0", that was an error of "1" (excluded from above "maxPolar"). So "0.01" would be an error of "1 part in 100" or 1%.
Comparing Polar error with Haversine error over distances less than 2000 meters to see how much worse this simpler formula is. So far, the worst I've seen is 51 parts per 1000 for Polar vs 4 parts per 1000 for Haversine. At about 58 degrees latitude.
Now implemented "Pythagorean with Latitude Adjustment".
It is MUCH more consistent than Polar for distances < 2000 m.
I originally thought the Polar problems were only when < 1 m,
but the result shown immediately below is quite troubling.
As distances approach zero, pythagorean/latitude approaches haversine.
For example this measurement ~ 217 meters:
lon1Xdeg 16.6531667510102 double
lat1Ydeg 57.7751705615804 double
lon2Xdeg 16.6564468739869 double
lat2Ydeg 57.7760263007586 double
oblate 217.201200413731
haversine 216.518428601051
polar 226.128616011973
pythag-cos 216.518428631907
havErrRatio 0.00314349925958048
polErrRatio 0.041102054598393
pycErrRatio 0.00314349911751603
Polar has a much worse error with these inputs; either there is some mistake in my code, or in Cos function I am running on, or I have to recommend not using Polar, even though most Polar measurements were much closer than this.
OTOH, Pythagorean, even with * cos(latitude) adjustment, has error that increases more rapidly than distance (ratio of max_error/distance increases for larger distances), so you need to carefully consider the maximum distance you will measure, and the acceptable error. In addition, it is not advisable to COMPARE two nearly-equal distances using Pythagorean, to decide which is shorter, as the error is different in different DIRECTIONS (evidence not shown).
Worst case measurements, errorRatio = Abs(error) / distance (Sweden; up to 2000 m):
t_maxHaversineErrorRatio 0.00351012021578681 double
t_maxPolarErrorRatio 66.0825360597085 double
t_maxPythagoreanErrorRatio 0.00350976281416454 double
As mentioned before, the extreme polar errors are for sub-meter distances, where it could report zero instead of 6 cm, or report over 0.5 m for a distance of 1 cm (hence the "66 x" worst case shown in t_maxPolarErrorRatio), but there are also some poor results at larger distances. [Needs to be tested again with a Cosine function that is known to be highly accurate.]
Measurements taken in C# code in Xamarin.Android running on a Moto E4.
C# code:
// x=longitude, y= latitude. oblate spheroid formula. TODO: From where?
public static double calculateDistanceDD_AED( double lon1Xdeg, double lat1Ydeg, double lon2Xdeg, double lat2Ydeg )
{
double c_dblEarthRadius = 6378.135; // km
double c_dblFlattening = 1.0 / 298.257223563; // WGS84 inverse
// flattening
// Q: Why "-" for longitudes??
double p1x = -degreesToRadians( lon1Xdeg );
double p1y = degreesToRadians( lat1Ydeg );
double p2x = -degreesToRadians( lon2Xdeg );
double p2y = degreesToRadians( lat2Ydeg );
double F = (p1y + p2y) / 2;
double G = (p1y - p2y) / 2;
double L = (p1x - p2x) / 2;
double sing = Math.Sin( G );
double cosl = Math.Cos( L );
double cosf = Math.Cos( F );
double sinl = Math.Sin( L );
double sinf = Math.Sin( F );
double cosg = Math.Cos( G );
double S = sing * sing * cosl * cosl + cosf * cosf * sinl * sinl;
double C = cosg * cosg * cosl * cosl + sinf * sinf * sinl * sinl;
double W = Math.Atan2( Math.Sqrt( S ), Math.Sqrt( C ) );
if (W == 0.0)
return 0.0;
double R = Math.Sqrt( (S * C) ) / W;
double H1 = (3 * R - 1.0) / (2.0 * C);
double H2 = (3 * R + 1.0) / (2.0 * S);
double D = 2 * W * c_dblEarthRadius;
// Apply flattening factor
D = D * (1.0 + c_dblFlattening * H1 * sinf * sinf * cosg * cosg - c_dblFlattening * H2 * cosf * cosf * sing * sing);
// Transform to meters
D = D * 1000.0;
// tmstest
if (true)
{
// Compare Haversine.
double haversine = HaversineApproxDistanceGeo( lon1Xdeg, lat1Ydeg, lon2Xdeg, lat2Ydeg );
double error = haversine - D;
double absError = Math.Abs( error );
double errorRatio = absError / D;
if (errorRatio > t_maxHaversineErrorRatio)
{
if (errorRatio > t_maxHaversineErrorRatio * 1.1)
Helper.test();
t_maxHaversineErrorRatio = errorRatio;
}
// Compare Polar Coordinate Flat Earth.
double polarDistanceGeo = ApproxDistanceGeo_Polar( lon1Xdeg, lat1Ydeg, lon2Xdeg, lat2Ydeg, D );
double error2 = polarDistanceGeo - D;
double absError2 = Math.Abs( error2 );
double errorRatio2 = absError2 / D;
if (errorRatio2 > t_maxPolarErrorRatio)
{
if (polarDistanceGeo > 0)
{
if (errorRatio2 > t_maxPolarErrorRatio * 1.1)
Helper.test();
t_maxPolarErrorRatio = errorRatio2;
}
else
Helper.dubious();
}
// Compare Pythagorean Theorem with Latitude Adjustment.
double pythagoreanDistanceGeo = ApproxDistanceGeo_PythagoreanCosLatitude( lon1Xdeg, lat1Ydeg, lon2Xdeg, lat2Ydeg, D );
double error3 = pythagoreanDistanceGeo - D;
double absError3 = Math.Abs( error3 );
double errorRatio3 = absError3 / D;
if (errorRatio3 > t_maxPythagoreanErrorRatio)
{
if (D < 2000)
{
if (errorRatio3 > t_maxPythagoreanErrorRatio * 1.05)
Helper.test();
t_maxPythagoreanErrorRatio = errorRatio3;
}
}
}
return D;
}
// As a fraction of the distance.
private static double t_maxHaversineErrorRatio, t_maxPolarErrorRatio, t_maxPythagoreanErrorRatio;
// Average of equatorial and polar radii (meters).
public const double EarthAvgRadius = 6371000;
public const double EarthAvgCircumference = EarthAvgRadius * 2 * PI;
// CAUTION: This is an average of great circles; won't be the actual distance of any longitude or latitude degree.
public const double EarthAvgMeterPerGreatCircleDegree = EarthAvgCircumference / 360;
// Haversine formula (assumes Earth is sphere).
// "deg" = degrees.
// Perhaps based on Haversine Formula in https://cs.nyu.edu/visual/home/proj/tiger/gisfaq.html
public static double HaversineApproxDistanceGeo(double lon1Xdeg, double lat1Ydeg, double lon2Xdeg, double lat2Ydeg)
{
double lon1 = degreesToRadians( lon1Xdeg );
double lat1 = degreesToRadians( lat1Ydeg );
double lon2 = degreesToRadians( lon2Xdeg );
double lat2 = degreesToRadians( lat2Ydeg );
double dlon = lon2 - lon1;
double dlat = lat2 - lat1;
double sinDLat2 = Sin( dlat / 2 );
double sinDLon2 = Sin( dlon / 2 );
double a = sinDLat2 * sinDLat2 + Cos( lat1 ) * Cos( lat2 ) * sinDLon2 * sinDLon2;
double c = 2 * Atan2( Sqrt( a ), Sqrt( 1 - a ) );
double d = EarthAvgRadius * c;
return d;
}
// From https://stackoverflow.com/a/19772119/199364
// Based on Polar Coordinate Flat Earth in https://cs.nyu.edu/visual/home/proj/tiger/gisfaq.html
public static double ApproxDistanceGeo_Polar( double lon1deg, double lat1deg, double lon2deg, double lat2deg, double D = 0 )
{
double approxUnitDistSq = ApproxUnitDistSq_Polar(lon1deg, lat1deg, lon2deg, lat2deg, D);
double c = Sqrt( approxUnitDistSq );
return EarthAvgRadius * c;
}
// Might be useful to avoid taking Sqrt, when comparing to some threshold.
// Threshold would have to be adjusted to match: Power(threshold / EarthAvgRadius, 2)
private static double ApproxUnitDistSq_Polar(double lon1deg, double lat1deg, double lon2deg, double lat2deg, double D = 0 )
{
const double HalfPi = PI / 2; //1.5707963267949;
double lon1 = degreesToRadians(lon1deg);
double lat1 = degreesToRadians(lat1deg);
double lon2 = degreesToRadians(lon2deg);
double lat2 = degreesToRadians(lat2deg);
double a = HalfPi - lat1;
double b = HalfPi - lat2;
double u = a * a + b * b;
double dlon21 = lon2 - lon1;
double cosDeltaLon = Cos( dlon21 );
double v = -2 * a * b * cosDeltaLon;
// TBD: Is "Abs" necessary? That is, is "u + v" ever negative?
// (I think not; "v" looks like a secondary term. Though might be round-off issue near zero when a~=b.)
double approxUnitDistSq = Abs(u + v);
//if (approxUnitDistSq.nearlyEquals(0, 1E-16))
// Helper.dubious();
//else if (D > 0)
//{
// double dba = b - a;
// double unitD = D / EarthAvgRadius;
// double unitDSq = unitD * unitD;
// if (approxUnitDistSq > 2 * unitDSq)
// Helper.dubious();
// else if (approxUnitDistSq * 2 < unitDSq)
// Helper.dubious();
//}
return approxUnitDistSq;
}
// Pythagorean Theorem with Latitude Adjustment - from Ewan Todd - https://stackoverflow.com/a/1664836/199364
// Refined by ToolmakerSteve - https://stackoverflow.com/a/53468745/199364
public static double ApproxDistanceGeo_PythagoreanCosLatitude( double lon1deg, double lat1deg, double lon2deg, double lat2deg, double D = 0 )
{
double approxDegreesSq = ApproxDegreesSq_PythagoreanCosLatitude( lon1deg, lat1deg, lon2deg, lat2deg );
// approximate degrees on the great circle between the points.
double d_degrees = Sqrt( approxDegreesSq );
return d_degrees * EarthAvgMeterPerGreatCircleDegree;
}
public static double ApproxDegreesSq_PythagoreanCosLatitude( double lon1deg, double lat1deg, double lon2deg, double lat2deg )
{
double avgLatDeg = average( lat1deg , lat2deg );
double avgLat = degreesToRadians( avgLatDeg );
double d_ew = (lon2deg - lon1deg) * Cos( avgLat );
double d_ns = (lat2deg - lat1deg);
double approxDegreesSq = d_ew * d_ew + d_ns * d_ns;
return approxDegreesSq;
}
I am done using SQL query
select *, (acos(sin(input_lat* 0.01745329)*sin(lattitude *0.01745329) + cos(input_lat *0.01745329)*cos(lattitude *0.01745329)*cos((input_long -longitude)*0.01745329))* 57.29577951 )* 69.16 As D from table_name
Following is the module (coded in f90) containing three formulas discussed in the previous answers. You can either put this module at the top of your program
(before PROGRAM MAIN) or compile it separately and include the module directory during compilation. The following module contains three formulas. First two are great-circle distances based on the assumption that earth is spherical.
module spherical_dists
contains
subroutine great_circle_distance(lon1,lat1,lon2,lat2,dist)
!https://en.wikipedia.org/wiki/Great-circle_distance
! It takes lon, lats of two points on an assumed spherical earth and
! calculates the distance between them along the great circle connecting the two points
implicit none
real,intent(in)::lon1,lon2,lat1,lat2
real,intent(out)::dist
real,parameter::pi=3.141592,mean_earth_radius=6371.0088
real::lonr1,lonr2,latr1,latr2
real::delangl,dellon
lonr1=lon1*(pi/180.);lonr2=lon2*(pi/180.)
latr1=lat1*(pi/180.);latr2=lat2*(pi/180.)
dellon=lonr2-lonr1
delangl=acos(sin(latr1)*sin(latr2)+cos(latr1)*cos(latr2)*cos(dellon))
dist=delangl*mean_earth_radius
end subroutine
subroutine haversine_formula(lon1,lat1,lon2,lat2,dist)
! https://en.wikipedia.org/wiki/Haversine_formula
! This is similar above but numerically better conditioned for small distances
implicit none
real,intent(in)::lon1,lon2,lat1,lat2
!lon, lats of two points
real,intent(out)::dist
real,parameter::pi=3.141592,mean_earth_radius=6371.0088
real::lonr1,lonr2,latr1,latr2
real::delangl,dellon,dellat,a
! degrees are converted to radians
lonr1=lon1*(pi/180.);lonr2=lon2*(pi/180.)
latr1=lat1*(pi/180.);latr2=lat2*(pi/180.)
dellon=lonr2-lonr1 ! These dels simplify the haversine formula
dellat=latr2-latr1
! The actual haversine formula
a=(sin(dellat/2))**2+cos(latr1)*cos(latr2)*(sin(dellon/2))**2
delangl=2*asin(sqrt(a)) !2*asin(sqrt(a))
dist=delangl*mean_earth_radius
end subroutine
subroutine vincenty_formula(lon1,lat1,lon2,lat2,dist)
!https://en.wikipedia.org/wiki/Vincenty%27s_formulae
!It's a better approximation over previous two, since it considers earth to in oblate spheroid, which better approximates the shape of the earth
implicit none
real,intent(in)::lon1,lon2,lat1,lat2
real,intent(out)::dist
real,parameter::pi=3.141592,mean_earth_radius=6371.0088
real::lonr1,lonr2,latr1,latr2
real::delangl,dellon,nom,denom
lonr1=lon1*(pi/180.);lonr2=lon2*(pi/180.)
latr1=lat1*(pi/180.);latr2=lat2*(pi/180.)
dellon=lonr2-lonr1
nom=sqrt((cos(latr2)*sin(dellon))**2. + (cos(latr1)*sin(latr2)-sin(latr1)*cos(latr2)*cos(dellon))**2.)
denom=sin(latr1)*sin(latr2)+cos(latr1)*cos(latr2)*cos(dellon)
delangl=atan2(nom,denom)
dist=delangl*mean_earth_radius
end subroutine
end module
On this page you can see the whole code and formulas how distances of locations are calculated in Android Location class
android/location/Location.java
EDIT: According the hint from #Richard I put the code of the linked function into my answer, to avoid invalidated link:
private static void computeDistanceAndBearing(double lat1, double lon1,
double lat2, double lon2, BearingDistanceCache results) {
// Based on http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
// using the "Inverse Formula" (section 4)
int MAXITERS = 20;
// Convert lat/long to radians
lat1 *= Math.PI / 180.0;
lat2 *= Math.PI / 180.0;
lon1 *= Math.PI / 180.0;
lon2 *= Math.PI / 180.0;
double a = 6378137.0; // WGS84 major axis
double b = 6356752.3142; // WGS84 semi-major axis
double f = (a - b) / a;
double aSqMinusBSqOverBSq = (a * a - b * b) / (b * b);
double L = lon2 - lon1;
double A = 0.0;
double U1 = Math.atan((1.0 - f) * Math.tan(lat1));
double U2 = Math.atan((1.0 - f) * Math.tan(lat2));
double cosU1 = Math.cos(U1);
double cosU2 = Math.cos(U2);
double sinU1 = Math.sin(U1);
double sinU2 = Math.sin(U2);
double cosU1cosU2 = cosU1 * cosU2;
double sinU1sinU2 = sinU1 * sinU2;
double sigma = 0.0;
double deltaSigma = 0.0;
double cosSqAlpha = 0.0;
double cos2SM = 0.0;
double cosSigma = 0.0;
double sinSigma = 0.0;
double cosLambda = 0.0;
double sinLambda = 0.0;
double lambda = L; // initial guess
for (int iter = 0; iter < MAXITERS; iter++) {
double lambdaOrig = lambda;
cosLambda = Math.cos(lambda);
sinLambda = Math.sin(lambda);
double t1 = cosU2 * sinLambda;
double t2 = cosU1 * sinU2 - sinU1 * cosU2 * cosLambda;
double sinSqSigma = t1 * t1 + t2 * t2; // (14)
sinSigma = Math.sqrt(sinSqSigma);
cosSigma = sinU1sinU2 + cosU1cosU2 * cosLambda; // (15)
sigma = Math.atan2(sinSigma, cosSigma); // (16)
double sinAlpha = (sinSigma == 0) ? 0.0 :
cosU1cosU2 * sinLambda / sinSigma; // (17)
cosSqAlpha = 1.0 - sinAlpha * sinAlpha;
cos2SM = (cosSqAlpha == 0) ? 0.0 :
cosSigma - 2.0 * sinU1sinU2 / cosSqAlpha; // (18)
double uSquared = cosSqAlpha * aSqMinusBSqOverBSq; // defn
A = 1 + (uSquared / 16384.0) * // (3)
(4096.0 + uSquared *
(-768 + uSquared * (320.0 - 175.0 * uSquared)));
double B = (uSquared / 1024.0) * // (4)
(256.0 + uSquared *
(-128.0 + uSquared * (74.0 - 47.0 * uSquared)));
double C = (f / 16.0) *
cosSqAlpha *
(4.0 + f * (4.0 - 3.0 * cosSqAlpha)); // (10)
double cos2SMSq = cos2SM * cos2SM;
deltaSigma = B * sinSigma * // (6)
(cos2SM + (B / 4.0) *
(cosSigma * (-1.0 + 2.0 * cos2SMSq) -
(B / 6.0) * cos2SM *
(-3.0 + 4.0 * sinSigma * sinSigma) *
(-3.0 + 4.0 * cos2SMSq)));
lambda = L +
(1.0 - C) * f * sinAlpha *
(sigma + C * sinSigma *
(cos2SM + C * cosSigma *
(-1.0 + 2.0 * cos2SM * cos2SM))); // (11)
double delta = (lambda - lambdaOrig) / lambda;
if (Math.abs(delta) < 1.0e-12) {
break;
}
}
float distance = (float) (b * A * (sigma - deltaSigma));
results.mDistance = distance;
float initialBearing = (float) Math.atan2(cosU2 * sinLambda,
cosU1 * sinU2 - sinU1 * cosU2 * cosLambda);
initialBearing *= 180.0 / Math.PI;
results.mInitialBearing = initialBearing;
float finalBearing = (float) Math.atan2(cosU1 * sinLambda,
-sinU1 * cosU2 + cosU1 * sinU2 * cosLambda);
finalBearing *= 180.0 / Math.PI;
results.mFinalBearing = finalBearing;
results.mLat1 = lat1;
results.mLat2 = lat2;
results.mLon1 = lon1;
results.mLon2 = lon2;
}
just use the distance formula Sqrt( (x2-x1)^2 + (y2-y1)^2 )

Resources