Area of Intersection between Two Circles - math

Given two circles:
C1 at (x1, y1) with radius1
C2 at (x2, y2) with radius2
How do you calculate the area of their intersection? All standard math functions (sin, cos, etc.) are available, of course.

Okay, using the Wolfram link and Misnomer's cue to look at equation 14, I have derived the following Java solution using the variables I listed and the distance between the centers (which can trivially be derived from them):
double r = radius1;
double R = radius2;
double d = distance;
if(R < r){
// swap
r = radius2;
R = radius1;
}
double part1 = r*r*Math.acos((d*d + r*r - R*R)/(2*d*r));
double part2 = R*R*Math.acos((d*d + R*R - r*r)/(2*d*R));
double part3 = 0.5*Math.sqrt((-d+r+R)*(d+r-R)*(d-r+R)*(d+r+R));
double intersectionArea = part1 + part2 - part3;

Here is a JavaScript function that does exactly what Chris was after:
function areaOfIntersection(x0, y0, r0, x1, y1, r1)
{
var rr0 = r0 * r0;
var rr1 = r1 * r1;
var d = Math.sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
var phi = (Math.acos((rr0 + (d * d) - rr1) / (2 * r0 * d))) * 2;
var theta = (Math.acos((rr1 + (d * d) - rr0) / (2 * r1 * d))) * 2;
var area1 = 0.5 * theta * rr1 - 0.5 * rr1 * Math.sin(theta);
var area2 = 0.5 * phi * rr0 - 0.5 * rr0 * Math.sin(phi);
return area1 + area2;
}
However, this method will return NaN if one circle is completely inside the other, or they are not touching at all. A slightly different version that doesn't fail in these conditions is as follows:
function areaOfIntersection(x0, y0, r0, x1, y1, r1)
{
var rr0 = r0 * r0;
var rr1 = r1 * r1;
var d = Math.sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
// Circles do not overlap
if (d > r1 + r0)
{
return 0;
}
// Circle1 is completely inside circle0
else if (d <= Math.abs(r0 - r1) && r0 >= r1)
{
// Return area of circle1
return Math.PI * rr1;
}
// Circle0 is completely inside circle1
else if (d <= Math.abs(r0 - r1) && r0 < r1)
{
// Return area of circle0
return Math.PI * rr0;
}
// Circles partially overlap
else
{
var phi = (Math.acos((rr0 + (d * d) - rr1) / (2 * r0 * d))) * 2;
var theta = (Math.acos((rr1 + (d * d) - rr0) / (2 * r1 * d))) * 2;
var area1 = 0.5 * theta * rr1 - 0.5 * rr1 * Math.sin(theta);
var area2 = 0.5 * phi * rr0 - 0.5 * rr0 * Math.sin(phi);
// Return area of intersection
return area1 + area2;
}
}
I wrote this function by reading the information found at the Math Forum. I found this clearer than the Wolfram MathWorld explanation.

You might want to check out this analytical solution and apply the formula with your input values.
Another Formula is given here for when the radii are equal:
Area = r^2*(q - sin(q)) where q = 2*acos(c/2r),
where c = distance between centers and r is the common radius.

Here is an example in Python.
"""Intersection area of two circles"""
import math
from dataclasses import dataclass
from typing import Tuple
#dataclass
class Circle:
x: float
y: float
r: float
#property
def coord(self):
return self.x, self.y
def find_intersection(c1: Circle, c2: Circle) -> float:
"""Finds intersection area of two circles.
Returns intersection area of two circles otherwise 0
"""
d = math.dist(c1.coord, c2.coord)
rad1sqr = c1.r ** 2
rad2sqr = c2.r ** 2
if d == 0:
# the circle centers are the same
return math.pi * min(c1.r, c2.r) ** 2
angle1 = (rad1sqr + d ** 2 - rad2sqr) / (2 * c1.r * d)
angle2 = (rad2sqr + d ** 2 - rad1sqr) / (2 * c2.r * d)
# check if the circles are overlapping
if (-1 <= angle1 < 1) or (-1 <= angle2 < 1):
theta1 = math.acos(angle1) * 2
theta2 = math.acos(angle2) * 2
area1 = (0.5 * theta2 * rad2sqr) - (0.5 * rad2sqr * math.sin(theta2))
area2 = (0.5 * theta1 * rad1sqr) - (0.5 * rad1sqr * math.sin(theta1))
return area1 + area2
elif angle1 < -1 or angle2 < -1:
# Smaller circle is completely inside the largest circle.
# Intersection area will be area of smaller circle
# return area(c1_r), area(c2_r)
return math.pi * min(c1.r, c2.r) ** 2
return 0
if __name__ == "__main__":
#dataclass
class Test:
data: Tuple[Circle, Circle]
expected: float
tests = [
Test((Circle(2, 4, 2), Circle(3, 9, 3)), 0),
Test((Circle(0, 0, 2), Circle(-1, 1, 2)), 7.0297),
Test((Circle(1, 3, 2), Circle(1, 3, 2.19)), 12.5664),
Test((Circle(0, 0, 2), Circle(-1, 0, 2)), 8.6084),
Test((Circle(4, 3, 2), Circle(2.5, 3.5, 1.4)), 3.7536),
Test((Circle(3, 3, 3), Circle(2, 2, 1)), 3.1416)
]
for test in tests:
result = find_intersection(*test.data)
assert math.isclose(result, test.expected, rel_tol=1e-4), f"{test=}, {result=}"
print("PASSED!!!")

Here here i was making character generation tool, based on circle intersections... you may find it useful.
with dynamically provided circles:
C: {
C1: {id: 'C1',x:105,y:357,r:100,color:'red'},
C2: {id: 'C2',x:137,y:281,r:50, color:'lime'},
C3: {id: 'C3',x:212,y:270,r:75, color:'#00BCD4'}
},
Check FULL fiddle...
FIDDLE

Related

Ionic basic function inside class is not executing fully

calculate_distance(lat1: number, lat2: number, long1: number, long2: number) {
console.log("Inside getting calculate_distance");
console.log(lat1);
console.log(lat2);
console.log(long1);
console.log(long2);
let p = 0.017453292519943295; // Math.PI / 180
let c = Math.cos;
let a = 0.5 - c((lat1 - lat2) * p) / 2 + c(lat2 * p) * c((lat1) * p) * (1 - c(((long1 - long2) * p))) / 2;
let dis = (12742 * Math.asin(Math.sqrt(a))); // 2 * R; R = 6371 km
return dis.toFixed(2);
}
calling this function inside other function and i am not getting the distance value.
i just added a promise return type to my function. So that it will return me the value.
calculateDistance(lat1: number, lat2: number, long1: number, long2: number):Promise<any> {
console.log("Inside getting calculate_distance");
console.log(lat1);
console.log(lat2);
console.log(long1);
console.log(long2);
let p = 0.017453292519943295; // Math.PI / 180
let c = Math.cos;
let a = 0.5 - c((lat1 - lat2) * p) / 2 + c(lat2 * p) * c((lat1) * p) * (1 - c(((long1 - long2) * p))) / 2;
let dis = (12742 * Math.asin(Math.sqrt(a))); // 2 * R; R = 6371 km
return dis.toFixed(2);
}
and called calculateDistance like this
this.calculateDistance(this.my_lat, this.proj_lat, this.my_long, this.proj_long).then(result=>{
this.distance = String(result)
})

Angle between 3 points in 3d space

I have 3 points containing X, Y, Z coordinates:
var A = {x: 100, y: 100, z: 80},
B = {x: 100, y: 175, z: 80},
C = {x: 100, y: 100, z: 120};
The coordinates are pixels from a 3d CSS transform.
How can I get the angle between vectors BA and BC?
A math formula will do, JavaScript code will be better.
Thank you.
In pseudo-code, the vector BA (call it v1) is:
v1 = {A.x - B.x, A.y - B.y, A.z - B.z}
Similarly the vector BC (call it v2) is:
v2 = {C.x - B.x, C.y - B.y, C.z - B.z}
The dot product of v1 and v2 is a function of the cosine of the angle between them (it's scaled by the product of their magnitudes). So first normalize v1 and v2:
v1mag = sqrt(v1.x * v1.x + v1.y * v1.y + v1.z * v1.z)
v1norm = {v1.x / v1mag, v1.y / v1mag, v1.z / v1mag}
v2mag = sqrt(v2.x * v2.x + v2.y * v2.y + v2.z * v2.z)
v2norm = {v2.x / v2mag, v2.y / v2mag, v2.z / v2mag}
Then calculate the dot product:
res = v1norm.x * v2norm.x + v1norm.y * v2norm.y + v1norm.z * v2norm.z
And finally, recover the angle:
angle = acos(res)
double GetAngleABC( double* a, double* b, double* c )
{
double ab[3] = { b[0] - a[0], b[1] - a[1], b[2] - a[2] };
double bc[3] = { c[0] - b[0], c[1] - b[1], c[2] - b[2] };
double abVec = sqrt(ab[0] * ab[0] + ab[1] * ab[1] + ab[2] * ab[2]);
double bcVec = sqrt(bc[0] * bc[0] + bc[1] * bc[1] + bc[2] * bc[2]);
double abNorm[3] = {ab[0] / abVec, ab[1] / abVec, ab[2] / abVec};
double bcNorm[3] = {bc[0] / bcVec, bc[1] / bcVec, bc[2] / bcVec};
double res = abNorm[0] * bcNorm[0] + abNorm[1] * bcNorm[1] + abNorm[2] * bcNorm[2];
return acos(res)*180.0/ 3.141592653589793;
}
double a[] = {1, 0, 0};
double b[] = {0, 0, 0};
double c[] = {0, 1, 0};
std::cout<< "The angle of ABC is " << GetAngleABC(a,b,c)<< "º " << std::endl;
#Roger algorithm in swift
func SCNVector3Angle(start: SCNVector3, mid: SCNVector3, end: SCNVector3) -> Double {
let v1 = (start - mid)
let v2 = (end - mid)
let v1norm = v1.normalized()
let v2norm = v2.normalized()
let res = v1norm.x * v2norm.x + v1norm.y * v2norm.y + v1norm.z * v2norm.z
let angle: Double = Double(GLKMathRadiansToDegrees(acos(res)))
return angle
}
/**
* Subtracts two SCNVector3 vectors and returns the result as a new SCNVector3.
*/
func - (left: SCNVector3, right: SCNVector3) -> SCNVector3 {
return SCNVector3Make(left.x - right.x, left.y - right.y, left.z - right.z)
}
extension SCNVector3
{
/**
* Returns the length (magnitude) of the vector described by the SCNVector3
*/
func length() -> Float {
return sqrtf(x*x + y*y + z*z)
}
/**
* Normalizes the vector described by the SCNVector3 to length 1.0 and returns
* the result as a new SCNVector3.
*/
func normalized() -> SCNVector3 {
return self / length()
}
}
The same in python (with output in degrees):
import numpy as np
import math
import time
def angle_2p_3d(a, b, c):
v1 = np.array([ a[0] - b[0], a[1] - b[1], a[2] - b[2] ])
v2 = np.array([ c[0] - b[0], c[1] - b[1], c[2] - b[2] ])
v1mag = np.sqrt([ v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2] ])
v1norm = np.array([ v1[0] / v1mag, v1[1] / v1mag, v1[2] / v1mag ])
v2mag = np.sqrt(v2[0] * v2[0] + v2[1] * v2[1] + v2[2] * v2[2])
v2norm = np.array([ v2[0] / v2mag, v2[1] / v2mag, v2[2] / v2mag ])
res = v1norm[0] * v2norm[0] + v1norm[1] * v2norm[1] + v1norm[2] * v2norm[2]
angle_rad = np.arccos(res)
return math.degrees(angle_rad)
p1 = np.array([1,0,0])
p2 = np.array([0,0,0])
p3 = np.array([0,0,1])
start = time.time()
angle= angle_2p_3d(p1, p2, p3)
end = time.time()
print("angle: ", angle)
print("elapsed in: ", end - start)
Output:
angle: 90.0
elapsed in: 8.392333984375e-05

Intersection between a line and a sphere

I'm trying to find the point of intersection between a sphere and a line but honestly, I don't have any idea of how to do so.
Could anyone help me on this one ?
Express the line as an function of t:
{ x(t) = x0*(1-t) + t*x1
{ y(t) = y0*(1-t) + t*y1
{ z(t) = z0*(1-t) + t*z1
When t = 0, it will be at one end-point (x0,y0,z0). When t = 1, it will be at the other end-point (x1,y1,z1).
Write a formula for the distance to the center of the sphere (squared) in t (where (xc,yc,zc) is the center of the sphere):
f(t) = (x(t) - xc)^2 + (y(t) - yc)^2 + (z(t) - zc)^2
Solve for t when f(t) equals R^2 (R being the radius of the sphere):
(x(t) - xc)^2 + (y(t) - yc)^2 + (z(t) - zc)^2 = R^2
A = (x0-xc)^2 + (y0-yc)^2 + (z0-zc)^2 - R^2
B = (x1-xc)^2 + (y1-yc)^2 + (z1-zc)^2 - A - C - R^2
C = (x0-x1)^2 + (y0-y1)^2 + (z0-z1)^2
Solve A + B*t + C*t^2 = 0 for t. This is a normal quadratic equation.
You can get up to two solutions. Any solution where t lies between 0 and 1 are valid.
If you got a valid solution for t, plug it in the first equations to get the point of intersection.
I assumed you meant a line segment (two end-points). If you instead want a full line (infinite length), then you could pick two points along the line (not too close), and use them. Also let t be any real value, not just between 0 and 1.
Edit: I fixed the formula for B. I was mixing up the signs. Thanks M Katz, for mentioning that it didn't work.
I believe there is an inaccuracy in the solution by Markus Jarderot. Not sure what the problem is, but I'm pretty sure I translated it faithfully to code, and when I tried to find the intersection of a line segment known to cross into a sphere, I got a negative discriminant (no solutions).
I found this: http://www.codeproject.com/Articles/19799/Simple-Ray-Tracing-in-C-Part-II-Triangles-Intersec, which gives a similar but slightly different derivation.
I turned that into the following C# code and it works for me:
public static Point3D[] FindLineSphereIntersections( Point3D linePoint0, Point3D linePoint1, Point3D circleCenter, double circleRadius )
{
// http://www.codeproject.com/Articles/19799/Simple-Ray-Tracing-in-C-Part-II-Triangles-Intersec
double cx = circleCenter.X;
double cy = circleCenter.Y;
double cz = circleCenter.Z;
double px = linePoint0.X;
double py = linePoint0.Y;
double pz = linePoint0.Z;
double vx = linePoint1.X - px;
double vy = linePoint1.Y - py;
double vz = linePoint1.Z - pz;
double A = vx * vx + vy * vy + vz * vz;
double B = 2.0 * (px * vx + py * vy + pz * vz - vx * cx - vy * cy - vz * cz);
double C = px * px - 2 * px * cx + cx * cx + py * py - 2 * py * cy + cy * cy +
pz * pz - 2 * pz * cz + cz * cz - circleRadius * circleRadius;
// discriminant
double D = B * B - 4 * A * C;
if ( D < 0 )
{
return new Point3D[ 0 ];
}
double t1 = ( -B - Math.Sqrt ( D ) ) / ( 2.0 * A );
Point3D solution1 = new Point3D( linePoint0.X * ( 1 - t1 ) + t1 * linePoint1.X,
linePoint0.Y * ( 1 - t1 ) + t1 * linePoint1.Y,
linePoint0.Z * ( 1 - t1 ) + t1 * linePoint1.Z );
if ( D == 0 )
{
return new Point3D[] { solution1 };
}
double t2 = ( -B + Math.Sqrt( D ) ) / ( 2.0 * A );
Point3D solution2 = new Point3D( linePoint0.X * ( 1 - t2 ) + t2 * linePoint1.X,
linePoint0.Y * ( 1 - t2 ) + t2 * linePoint1.Y,
linePoint0.Z * ( 1 - t2 ) + t2 * linePoint1.Z );
// prefer a solution that's on the line segment itself
if ( Math.Abs( t1 - 0.5 ) < Math.Abs( t2 - 0.5 ) )
{
return new Point3D[] { solution1, solution2 };
}
return new Point3D[] { solution2, solution1 };
}
Don't have enough reputation to comment on M Katz answer, but his answer assumes that the line can go on infinitely in each direction. If you need only the line SEGMENT's intersection points, you need t1 and t2 to be less than one (based on the definition of a parameterized equation). Please see my answer in C# below:
public static Point3D[] FindLineSphereIntersections(Point3D linePoint0, Point3D linePoint1, Point3D circleCenter, double circleRadius)
{
double cx = circleCenter.X;
double cy = circleCenter.Y;
double cz = circleCenter.Z;
double px = linePoint0.X;
double py = linePoint0.Y;
double pz = linePoint0.Z;
double vx = linePoint1.X - px;
double vy = linePoint1.Y - py;
double vz = linePoint1.Z - pz;
double A = vx * vx + vy * vy + vz * vz;
double B = 2.0 * (px * vx + py * vy + pz * vz - vx * cx - vy * cy - vz * cz);
double C = px * px - 2 * px * cx + cx * cx + py * py - 2 * py * cy + cy * cy +
pz * pz - 2 * pz * cz + cz * cz - circleRadius * circleRadius;
// discriminant
double D = B * B - 4 * A * C;
double t1 = (-B - Math.Sqrt(D)) / (2.0 * A);
Point3D solution1 = new Point3D(linePoint0.X * (1 - t1) + t1 * linePoint1.X,
linePoint0.Y * (1 - t1) + t1 * linePoint1.Y,
linePoint0.Z * (1 - t1) + t1 * linePoint1.Z);
double t2 = (-B + Math.Sqrt(D)) / (2.0 * A);
Point3D solution2 = new Point3D(linePoint0.X * (1 - t2) + t2 * linePoint1.X,
linePoint0.Y * (1 - t2) + t2 * linePoint1.Y,
linePoint0.Z * (1 - t2) + t2 * linePoint1.Z);
if (D < 0 || t1 > 1 || t2 >1)
{
return new Point3D[0];
}
else if (D == 0)
{
return new [] { solution1 };
}
else
{
return new [] { solution1, solution2 };
}
}
You may use Wolfram Alpha to solve it in the coordinate system where the sphere is centered.
In this system, the equations are:
Sphere:
x^2 + y^2 + z^2 = r^2
Straight line:
x = x0 + Cos[x1] t
y = y0 + Cos[y1] t
z = z0 + Cos[z1] t
Then we ask Wolfram Alpha to solve for t: (Try it!)
and after that you may change again to your original coordinate system (a simple translation)
Find the solution of the two equations in (x,y,z) describing the line and the sphere.
There may be 0, 1 or 2 solutions.
0 implies they don't intersect
1 implies the line is a tangent to the sphere
2 implies the line passes through the sphere.
Here's a more concise formulation using inner products, less than 100 LOCs, and no external links. Also, the question was asked for a line, not a line segment.
Assume that the sphere is centered at C with radius r. The line is described by P+l*D where D*D=1. P and C are points, D is a vector, l is a number.
We set PC = P-C, pd = PC*D and s = pd*pd - PC*PC + r*r. If s < 0 there are no solutions, if s == 0 there is just one, otherwise there are two. For the solutions we set l = -pd +- sqrt(s), then plug into P+l*D.
Or you can just find the formula of both:
line: (x-x0)/a=(y-y0)/b=(z-z0)/c, which are symmetric equations of the line segment between the points you can find.
sphere: (x-xc)^2+(y-yc)^2+(z-zc)^2 = R^2.
Use the symmetric equation to find relationship between x and y, and x and z.
Then plug in y and z in terms of x into the equation of the sphere.
Then find x, and then you can find y and z.
If x gives you an imaginary result, that means the line and the sphere doesn't intersect.
I don't have the reputation to comment on Ashavsky's solution, but the check at the end needed a bit more tweaking.
if (D < 0)
return new Point3D[0];
else if ((t1 > 1 || t1 < 0) && (t2 > 1 || t2 < 0))
return new Point3D[0];
else if (!(t1 > 1 || t1 < 0) && (t2 > 1 || t2 < 0))
return new [] { solution1 };
else if ((t1 > 1 || t1 < 0) && !(t2 > 1 || t2 < 0))
return new [] { solution2 };
else if (D == 0)
return new [] { solution1 };
else
return new [] { solution1, solution2 };

Mapping A Sphere To A Cube

There is a special way of mapping a cube to a sphere described here:
http://mathproofs.blogspot.com/2005/07/mapping-cube-to-sphere.html
It is not your basic "normalize the point and you're done" approach and gives a much more evenly spaced mapping.
I've tried to do the inverse of the mapping going from sphere coords to cube coords and have been unable to come up the working equations. It's a rather complex system of equations with lots of square roots.
Any math geniuses want to take a crack at it?
Here's the equations in c++ code:
sx = x * sqrtf(1.0f - y * y * 0.5f - z * z * 0.5f + y * y * z * z / 3.0f);
sy = y * sqrtf(1.0f - z * z * 0.5f - x * x * 0.5f + z * z * x * x / 3.0f);
sz = z * sqrtf(1.0f - x * x * 0.5f - y * y * 0.5f + x * x * y * y / 3.0f);
sx,sy,sz are the sphere coords and x,y,z are the cube coords.
I want to give gmatt credit for this because he's done a lot of the work. The only difference in our answers is the equation for x.
To do the inverse mapping from sphere to cube first determine the cube face the sphere point projects to. This step is simple - just find the component of the sphere vector with the greatest length like so:
// map the given unit sphere position to a unit cube position
void cubizePoint(Vector3& position) {
double x,y,z;
x = position.x;
y = position.y;
z = position.z;
double fx, fy, fz;
fx = fabsf(x);
fy = fabsf(y);
fz = fabsf(z);
if (fy >= fx && fy >= fz) {
if (y > 0) {
// top face
position.y = 1.0;
}
else {
// bottom face
position.y = -1.0;
}
}
else if (fx >= fy && fx >= fz) {
if (x > 0) {
// right face
position.x = 1.0;
}
else {
// left face
position.x = -1.0;
}
}
else {
if (z > 0) {
// front face
position.z = 1.0;
}
else {
// back face
position.z = -1.0;
}
}
}
For each face - take the remaining cube vector components denoted as s and t and solve for them using these equations, which are based on the remaining sphere vector components denoted as a and b:
s = sqrt(-sqrt((2 a^2-2 b^2-3)^2-24 a^2)+2 a^2-2 b^2+3)/sqrt(2)
t = sqrt(-sqrt((2 a^2-2 b^2-3)^2-24 a^2)-2 a^2+2 b^2+3)/sqrt(2)
You should see that the inner square root is used in both equations so only do that part once.
Here's the final function with the equations thrown in and checks for 0.0 and -0.0 and the code to properly set the sign of the cube component - it should be equal to the sign of the sphere component.
void cubizePoint2(Vector3& position)
{
double x,y,z;
x = position.x;
y = position.y;
z = position.z;
double fx, fy, fz;
fx = fabsf(x);
fy = fabsf(y);
fz = fabsf(z);
const double inverseSqrt2 = 0.70710676908493042;
if (fy >= fx && fy >= fz) {
double a2 = x * x * 2.0;
double b2 = z * z * 2.0;
double inner = -a2 + b2 -3;
double innersqrt = -sqrtf((inner * inner) - 12.0 * a2);
if(x == 0.0 || x == -0.0) {
position.x = 0.0;
}
else {
position.x = sqrtf(innersqrt + a2 - b2 + 3.0) * inverseSqrt2;
}
if(z == 0.0 || z == -0.0) {
position.z = 0.0;
}
else {
position.z = sqrtf(innersqrt - a2 + b2 + 3.0) * inverseSqrt2;
}
if(position.x > 1.0) position.x = 1.0;
if(position.z > 1.0) position.z = 1.0;
if(x < 0) position.x = -position.x;
if(z < 0) position.z = -position.z;
if (y > 0) {
// top face
position.y = 1.0;
}
else {
// bottom face
position.y = -1.0;
}
}
else if (fx >= fy && fx >= fz) {
double a2 = y * y * 2.0;
double b2 = z * z * 2.0;
double inner = -a2 + b2 -3;
double innersqrt = -sqrtf((inner * inner) - 12.0 * a2);
if(y == 0.0 || y == -0.0) {
position.y = 0.0;
}
else {
position.y = sqrtf(innersqrt + a2 - b2 + 3.0) * inverseSqrt2;
}
if(z == 0.0 || z == -0.0) {
position.z = 0.0;
}
else {
position.z = sqrtf(innersqrt - a2 + b2 + 3.0) * inverseSqrt2;
}
if(position.y > 1.0) position.y = 1.0;
if(position.z > 1.0) position.z = 1.0;
if(y < 0) position.y = -position.y;
if(z < 0) position.z = -position.z;
if (x > 0) {
// right face
position.x = 1.0;
}
else {
// left face
position.x = -1.0;
}
}
else {
double a2 = x * x * 2.0;
double b2 = y * y * 2.0;
double inner = -a2 + b2 -3;
double innersqrt = -sqrtf((inner * inner) - 12.0 * a2);
if(x == 0.0 || x == -0.0) {
position.x = 0.0;
}
else {
position.x = sqrtf(innersqrt + a2 - b2 + 3.0) * inverseSqrt2;
}
if(y == 0.0 || y == -0.0) {
position.y = 0.0;
}
else {
position.y = sqrtf(innersqrt - a2 + b2 + 3.0) * inverseSqrt2;
}
if(position.x > 1.0) position.x = 1.0;
if(position.y > 1.0) position.y = 1.0;
if(x < 0) position.x = -position.x;
if(y < 0) position.y = -position.y;
if (z > 0) {
// front face
position.z = 1.0;
}
else {
// back face
position.z = -1.0;
}
}
So, this solution isn't nearly as pretty as the cube to sphere mapping, but it gets the job done!
Any suggestions to improve the efficiency or read ability of the code above are appreciated!
--- edit ---
I should mention that I have tested this and so far in my tests the code appears correct with the results being accurate to at least the 7th decimal place. And that was from when I was using floats, it's probably more accurate now with doubles.
--- edit ---
Here's an optimized glsl fragment shader version by Daniel to show that it doesn't have to be such a big scary function. Daniel uses this to filter sampling on cube maps! Great idea!
const float isqrt2 = 0.70710676908493042;
vec3 cubify(const in vec3 s)
{
float xx2 = s.x * s.x * 2.0;
float yy2 = s.y * s.y * 2.0;
vec2 v = vec2(xx2 – yy2, yy2 – xx2);
float ii = v.y – 3.0;
ii *= ii;
float isqrt = -sqrt(ii – 12.0 * xx2) + 3.0;
v = sqrt(v + isqrt);
v *= isqrt2;
return sign(s) * vec3(v, 1.0);
}
vec3 sphere2cube(const in vec3 sphere)
{
vec3 f = abs(sphere);
bool a = f.y >= f.x && f.y >= f.z;
bool b = f.x >= f.z;
return a ? cubify(sphere.xzy).xzy : b ? cubify(sphere.yzx).zxy : cubify(sphere);
}
After some rearranging you can get the "nice" forms
(1) 1/2 z^2 = (alpha) / ( y^2 - x^2) + 1
(2) 1/2 y^2 = (beta) / ( z^2 - x^2) + 1
(3) 1/2 x^2 = (gamma) / ( y^2 - z^2) + 1
where alpha = sx^2-sy^2 , beta = sx^2 - sz^2 and gamma = sz^2 - sy^2. Verify this yourself.
Now I neither have the motivation nor the time but from this point on its pretty straightforward to solve:
Substitute (1) into (2). Rearrange (2) until you get a polynomial (root) equation of the form
(4) a(x) * y^4 + b(x) * y^2 + c(x) = 0
this can be solved using the quadratic formula for y^2. Note that a(x),b(x),c(x) are some functions of x. The quadratic formula yields 2 roots for (4) which you will have to keep in mind.
Using (1),(2),(4) figure out an expression for z^2 in terms of only x^2.
Using (3) write out a polynomial root equation of the form:
(5) a * x^4 + b * x^2 + c = 0
where a,b,c are not functions but constants. Solve this using the quadratic formula. In total you will have 2*2=4 possible solutions for x^2,y^2,z^2 pair meaning you will
have 4*2=8 total solutions for possible x,y,z pairs satisfying these equations. Check conditions on each x,y,z pair and (hopefully) eliminate all but one (otherwise an inverse mapping does not exist.)
Good luck.
PS. It very well may be that the inverse mapping does not exist, think about the geometry: the sphere has surface area 4*pi*r^2 while the cube has surface area 6*d^2=6*(2r)^2=24r^2 so intuitively you have many more points on the cube that get mapped to the sphere. This means a many to one mapping, and any such mapping is not injective and hence is not bijective (i.e. the mapping has no inverse.) Sorry but I think you are out of luck.
----- edit --------------
if you follow the advice from MO, setting z=1 means you are looking at the solid square in the plane z=1.
Use your first two equations to solve for x,y, wolfram alpha gives the result:
x = (sqrt(6) s^2 sqrt(1/2 (sqrt((2 s^2-2 t^2-3)^2-24 t^2)+2 s^2-2 t^2-3)+3)-sqrt(6) t^2 sqrt(1/2 (sqrt((2 s^2-2 t^2-3)^2-24 t^2)+2 s^2-2 t^2-3)+3)-sqrt(3/2) sqrt((2 s^2-2 t^2-3)^2-24 t^2) sqrt(1/2 (sqrt((2 s^2-2 t^2-3)^2-24 t^2)+2 s^2-2 t^2-3)+3)+3 sqrt(3/2) sqrt(1/2 (sqrt((2 s^2-2 t^2-3)^2-24 t^2)+2 s^2-2 t^2-3)+3))/(6 s)
and
y = sqrt(-sqrt((2 s^2-2 t^2-3)^2-24 t^2)-2 s^2+2 t^2+3)/sqrt(2)
where above I use s=sx and t=sy, and I will use u=sz. Then you can use the third equation you have for u=sz. That is lets say that you want to map the top part of the sphere to the cube. Then for any 0 <= s,t <= 1 (where s,t are in the sphere's coordinate frame ) then the tuple (s,t,u) maps to (x,y,1) (here x,y are in the cubes coordinate frame.) The only thing left is for you to figure out what u is. You can figure this out by using s,t to solve for x,y then using x,y to solve for u.
Note that this will only map the top part of the cube to only the top plane of the cube z=1. You will have to do this for all 6 sides (x=1, y=1, z=0 ... etc ). I suggest using wolfram alpha to solve the resulting equations you get for each sub-case, because they will be as ugly or uglier as those above.
This answer contains the cube2sphere and sphere2cube without the restriction of a = 1. So the cube has side 2a from -a to a and the radius of the sphere is a.
I know it's been 10 years since this question was asked. Nevertheless, I am giving the answer in case someone needs it. The implementation is in Python,
I am using (x, y, z) for the cube coordinates, (p, q, r) for the sphere coordinates and the relevant underscore variables (x_, y_, z_) meaning they have been produced by using the inverse function.
import math
from random import randint # for testing
def sign_aux(x):
return lambda y: math.copysign(x, y)
sign = sign_aux(1) # no built-in sign function in python, I know...
def cube2sphere(x, y, z):
if (all([x == 0, y == 0, z == 0])):
return 0, 0, 0
def aux(x, y_2, z_2, a, a_2):
return x * math.sqrt(a_2 - y_2/2 - z_2/2 + y_2*z_2/(3*a_2))/a
x_2 = x*x
y_2 = y*y
z_2 = z*z
a = max(abs(x), abs(y), abs(z))
a_2 = a*a
return aux(x, y_2, z_2, a, a_2), aux(y, x_2, z_2, a, a_2), aux(z, x_2, y_2, a, a_2)
def sphere2cube(p, q, r):
if (all([p == 0, q == 0, r == 0])):
return 0, 0, 0
def aux(s, t, radius):
A = 3*radius*radius
R = 2*(s*s - t*t)
S = math.sqrt( max(0, (A+R)*(A+R) - 8*A*s*s) ) # use max 0 for accuraccy error
iot = math.sqrt(2)/2
s_ = sign(s) * iot * math.sqrt(max(0, A + R - S)) # use max 0 for accuraccy error
t_ = sign(t) * iot * math.sqrt(max(0, A - R - S)) # use max 0 for accuraccy error
return s_, t_
norm_p, norm_q, norm_r = abs(p), abs(q), abs(r)
norm_max = max(norm_p, norm_q, norm_r)
radius = math.sqrt(p*p + q*q + r*r)
if (norm_max == norm_p):
y, z = aux(q, r, radius)
x = sign(p) * radius
return x, y, z
if (norm_max == norm_q):
z, x = aux(r, p, radius)
y = sign(q) * radius
return x, y, z
x, y = aux(p, q, radius)
z = sign(r) * radius
return x, y, z
# measuring accuracy
max_mse = 0
for i in range(100000):
x = randint(-20, 20)
y = randint(-20, 20)
z = randint(-20, 20)
p, q, r = cube2sphere(x, y, z)
x_, y_, z_ = sphere2cube(p, q, r)
max_mse = max(max_mse, math.sqrt(((x-x_)**2 + (y-y_)**2 + (z-z_)**2))/3)
print(max_mse)
# 1.1239159602905078e-07
max_mse = 0
for i in range(100000):
p = randint(-20, 20)
q = randint(-20, 20)
r = randint(-20, 20)
x, y, z = sphere2cube(p, q, r)
p_, q_, r_ = cube2sphere(x, y, z)
max_mse = max(max_mse, math.sqrt(((p-p_)**2 + (q-q_)**2 + (r-r_)**2))/3)
print(max_mse)
# 9.832883321715792e-08
Also, I mapped some points to check the function visually and these are the results.
Here's one way you can think about it: for a given point P in the sphere, take the segment that starts at the origin, passes through P, and ends at the surface of the cube. Let L be the length of this segment. Now all you need to do is multiply P by L; this is equivalent to mapping ||P|| from the interval [0, 1] to the interval [0, L]. This mapping should be one-to-one - every point in the sphere goes to a unique point in the cube (and points on the surface stay on the surface). Note that this is assuming a unit sphere and cube; the idea should hold elsewhere, you'll just have a few scale factors involved.
I've glossed over the hard part (finding the segment), but this is a standard raycasting problem. There are some links here that explain how to compute this for an arbitrary ray versus axis-aligned bounding box; you can probably simplify things since your ray starts at the origin and goes to the unit cube. If you need help simplify the equations, let me know and I'll take a stab at it.
It looks like there is a much cleaner solution if you're not afraid of trig and pi, not sure if it's faster/comparable though.
Just take the remaining components after determining the face and do:
u = asin ( x ) / half_pi
v = asin ( y ) / half_pi
This is an intuitive leap, but this seems to back it up ( though not exactly the same topic ), so please correct me if I'm wrong.
I'm too lazy to post an illustration that explains why. :D

Calculate distance between 2 GPS coordinates

How do I calculate distance between two GPS coordinates (using latitude and longitude)?
Calculate the distance between two coordinates by latitude and longitude, including a Javascript implementation.
West and South locations are negative.
Remember minutes and seconds are out of 60 so S31 30' is -31.50 degrees.
Don't forget to convert degrees to radians. Many languages have this function. Or its a simple calculation: radians = degrees * PI / 180.
function degreesToRadians(degrees) {
return degrees * Math.PI / 180;
}
function distanceInKmBetweenEarthCoordinates(lat1, lon1, lat2, lon2) {
var earthRadiusKm = 6371;
var dLat = degreesToRadians(lat2-lat1);
var dLon = degreesToRadians(lon2-lon1);
lat1 = degreesToRadians(lat1);
lat2 = degreesToRadians(lat2);
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
return earthRadiusKm * c;
}
Here are some examples of usage:
distanceInKmBetweenEarthCoordinates(0,0,0,0) // Distance between same
// points should be 0
0
distanceInKmBetweenEarthCoordinates(51.5, 0, 38.8, -77.1) // From London
// to Arlington
5918.185064088764
Look for haversine with Google; here is my solution:
#include <math.h>
#include "haversine.h"
#define d2r (M_PI / 180.0)
//calculate haversine distance for linear distance
double haversine_km(double lat1, double long1, double lat2, double long2)
{
double dlong = (long2 - long1) * d2r;
double dlat = (lat2 - lat1) * d2r;
double a = pow(sin(dlat/2.0), 2) + cos(lat1*d2r) * cos(lat2*d2r) * pow(sin(dlong/2.0), 2);
double c = 2 * atan2(sqrt(a), sqrt(1-a));
double d = 6367 * c;
return d;
}
double haversine_mi(double lat1, double long1, double lat2, double long2)
{
double dlong = (long2 - long1) * d2r;
double dlat = (lat2 - lat1) * d2r;
double a = pow(sin(dlat/2.0), 2) + cos(lat1*d2r) * cos(lat2*d2r) * pow(sin(dlong/2.0), 2);
double c = 2 * atan2(sqrt(a), sqrt(1-a));
double d = 3956 * c;
return d;
}
C# Version of Haversine
double _eQuatorialEarthRadius = 6378.1370D;
double _d2r = (Math.PI / 180D);
private int HaversineInM(double lat1, double long1, double lat2, double long2)
{
return (int)(1000D * HaversineInKM(lat1, long1, lat2, long2));
}
private double HaversineInKM(double lat1, double long1, double lat2, double long2)
{
double dlong = (long2 - long1) * _d2r;
double dlat = (lat2 - lat1) * _d2r;
double a = Math.Pow(Math.Sin(dlat / 2D), 2D) + Math.Cos(lat1 * _d2r) * Math.Cos(lat2 * _d2r) * Math.Pow(Math.Sin(dlong / 2D), 2D);
double c = 2D * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1D - a));
double d = _eQuatorialEarthRadius * c;
return d;
}
Here's a .NET Fiddle of this, so you can test it out with your own Lat/Longs.
Java Version of Haversine Algorithm based on Roman Makarov`s reply to this thread
public class HaversineAlgorithm {
static final double _eQuatorialEarthRadius = 6378.1370D;
static final double _d2r = (Math.PI / 180D);
public static int HaversineInM(double lat1, double long1, double lat2, double long2) {
return (int) (1000D * HaversineInKM(lat1, long1, lat2, long2));
}
public static double HaversineInKM(double lat1, double long1, double lat2, double long2) {
double dlong = (long2 - long1) * _d2r;
double dlat = (lat2 - lat1) * _d2r;
double a = Math.pow(Math.sin(dlat / 2D), 2D) + Math.cos(lat1 * _d2r) * Math.cos(lat2 * _d2r)
* Math.pow(Math.sin(dlong / 2D), 2D);
double c = 2D * Math.atan2(Math.sqrt(a), Math.sqrt(1D - a));
double d = _eQuatorialEarthRadius * c;
return d;
}
}
This is very easy to do with geography type in SQL Server 2008.
SELECT geography::Point(lat1, lon1, 4326).STDistance(geography::Point(lat2, lon2, 4326))
-- computes distance in meters using eliptical model, accurate to the mm
4326 is SRID for WGS84 elipsoidal Earth model
Here's a Haversine function in Python that I use:
from math import pi,sqrt,sin,cos,atan2
def haversine(pos1, pos2):
lat1 = float(pos1['lat'])
long1 = float(pos1['long'])
lat2 = float(pos2['lat'])
long2 = float(pos2['long'])
degree_to_rad = float(pi / 180.0)
d_lat = (lat2 - lat1) * degree_to_rad
d_long = (long2 - long1) * degree_to_rad
a = pow(sin(d_lat / 2), 2) + cos(lat1 * degree_to_rad) * cos(lat2 * degree_to_rad) * pow(sin(d_long / 2), 2)
c = 2 * atan2(sqrt(a), sqrt(1 - a))
km = 6367 * c
mi = 3956 * c
return {"km":km, "miles":mi}
I needed to calculate a lot of distances between the points for my project, so I went ahead and tried to optimize the code, I have found here. On average in different browsers my new implementation runs 2 times faster than the most upvoted answer.
function distance(lat1, lon1, lat2, lon2) {
var p = 0.017453292519943295; // Math.PI / 180
var c = Math.cos;
var a = 0.5 - c((lat2 - lat1) * p)/2 +
c(lat1 * p) * c(lat2 * p) *
(1 - c((lon2 - lon1) * p))/2;
return 12742 * Math.asin(Math.sqrt(a)); // 2 * R; R = 6371 km
}
You can play with my jsPerf and see the results here.
Recently I needed to do the same in python, so here is a python implementation:
from math import cos, asin, sqrt
def distance(lat1, lon1, lat2, lon2):
p = 0.017453292519943295
a = 0.5 - cos((lat2 - lat1) * p)/2 + cos(lat1 * p) * cos(lat2 * p) * (1 - cos((lon2 - lon1) * p)) / 2
return 12742 * asin(sqrt(a))
And for the sake of completeness: Haversine on wiki.
It depends on how accurate you need it to be. If you need pinpoint accuracy, it is best to look at an algorithm which uses an ellipsoid, rather than a sphere, such as Vincenty's algorithm, which is accurate to the mm.
Here it is in C# (lat and long in radians):
double CalculateGreatCircleDistance(double lat1, double long1, double lat2, double long2, double radius)
{
return radius * Math.Acos(
Math.Sin(lat1) * Math.Sin(lat2)
+ Math.Cos(lat1) * Math.Cos(lat2) * Math.Cos(long2 - long1));
}
If your lat and long are in degrees then divide by 180/PI to convert to radians.
PHP version:
(Remove all deg2rad() if your coordinates are already in radians.)
$R = 6371; // km
$dLat = deg2rad($lat2-$lat1);
$dLon = deg2rad($lon2-$lon1);
$lat1 = deg2rad($lat1);
$lat2 = deg2rad($lat2);
$a = sin($dLat/2) * sin($dLat/2) +
sin($dLon/2) * sin($dLon/2) * cos($lat1) * cos($lat2);
$c = 2 * atan2(sqrt($a), sqrt(1-$a));
$d = $R * $c;
A T-SQL function, that I use to select records by distance for a center
Create Function [dbo].[DistanceInMiles]
( #fromLatitude float ,
#fromLongitude float ,
#toLatitude float,
#toLongitude float
)
returns float
AS
BEGIN
declare #distance float
select #distance = cast((3963 * ACOS(round(COS(RADIANS(90-#fromLatitude))*COS(RADIANS(90-#toLatitude))+
SIN(RADIANS(90-#fromLatitude))*SIN(RADIANS(90-#toLatitude))*COS(RADIANS(#fromLongitude-#toLongitude)),15))
)as float)
return round(#distance,1)
END
I. Regarding "Breadcrumbs" method
Earth radius is different on different Lat. This must be taken into consideration in Haversine algorithm.
Consider Bearing change, which turns straight lines to arches (which are longer)
Taking Speed change into account will turn arches to spirals (which are longer or shorter than arches)
Altitude change will turn flat spirals to 3D spirals (which are longer again). This is very important for hilly areas.
Below see the function in C which takes #1 and #2 into account:
double calcDistanceByHaversine(double rLat1, double rLon1, double rHeading1,
double rLat2, double rLon2, double rHeading2){
double rDLatRad = 0.0;
double rDLonRad = 0.0;
double rLat1Rad = 0.0;
double rLat2Rad = 0.0;
double a = 0.0;
double c = 0.0;
double rResult = 0.0;
double rEarthRadius = 0.0;
double rDHeading = 0.0;
double rDHeadingRad = 0.0;
if ((rLat1 < -90.0) || (rLat1 > 90.0) || (rLat2 < -90.0) || (rLat2 > 90.0)
|| (rLon1 < -180.0) || (rLon1 > 180.0) || (rLon2 < -180.0)
|| (rLon2 > 180.0)) {
return -1;
};
rDLatRad = (rLat2 - rLat1) * DEGREE_TO_RADIANS;
rDLonRad = (rLon2 - rLon1) * DEGREE_TO_RADIANS;
rLat1Rad = rLat1 * DEGREE_TO_RADIANS;
rLat2Rad = rLat2 * DEGREE_TO_RADIANS;
a = sin(rDLatRad / 2) * sin(rDLatRad / 2) + sin(rDLonRad / 2) * sin(
rDLonRad / 2) * cos(rLat1Rad) * cos(rLat2Rad);
if (a == 0.0) {
return 0.0;
}
c = 2 * atan2(sqrt(a), sqrt(1 - a));
rEarthRadius = 6378.1370 - (21.3847 * 90.0 / ((fabs(rLat1) + fabs(rLat2))
/ 2.0));
rResult = rEarthRadius * c;
// Chord to Arc Correction based on Heading changes. Important for routes with many turns and U-turns
if ((rHeading1 >= 0.0) && (rHeading1 < 360.0) && (rHeading2 >= 0.0)
&& (rHeading2 < 360.0)) {
rDHeading = fabs(rHeading1 - rHeading2);
if (rDHeading > 180.0) {
rDHeading -= 180.0;
}
rDHeadingRad = rDHeading * DEGREE_TO_RADIANS;
if (rDHeading > 5.0) {
rResult = rResult * (rDHeadingRad / (2.0 * sin(rDHeadingRad / 2)));
} else {
rResult = rResult / cos(rDHeadingRad);
}
}
return rResult;
}
II. There is an easier way which gives pretty good results.
By Average Speed.
Trip_distance = Trip_average_speed * Trip_time
Since GPS Speed is detected by Doppler effect and is not directly related to [Lon,Lat] it can be at least considered as secondary (backup or correction) if not as main distance calculation method.
If you need something more accurate then have a look at this.
Vincenty's formulae are two related iterative methods used in geodesy
to calculate the distance between two points on the surface of a
spheroid, developed by Thaddeus Vincenty (1975a) They are based on the
assumption that the figure of the Earth is an oblate spheroid, and
hence are more accurate than methods such as great-circle distance
which assume a spherical Earth.
The first (direct) method computes the location of a point which is a
given distance and azimuth (direction) from another point. The second
(inverse) method computes the geographical distance and azimuth
between two given points. They have been widely used in geodesy
because they are accurate to within 0.5 mm (0.020″) on the Earth
ellipsoid.
If you're using .NET don't reivent the wheel. See System.Device.Location. Credit to fnx in the comments in another answer.
using System.Device.Location;
double lat1 = 45.421527862548828D;
double long1 = -75.697189331054688D;
double lat2 = 53.64135D;
double long2 = -113.59273D;
GeoCoordinate geo1 = new GeoCoordinate(lat1, long1);
GeoCoordinate geo2 = new GeoCoordinate(lat2, long2);
double distance = geo1.GetDistanceTo(geo2);
here is the Swift implementation from the answer
func degreesToRadians(degrees: Double) -> Double {
return degrees * Double.pi / 180
}
func distanceInKmBetweenEarthCoordinates(lat1: Double, lon1: Double, lat2: Double, lon2: Double) -> Double {
let earthRadiusKm: Double = 6371
let dLat = degreesToRadians(degrees: lat2 - lat1)
let dLon = degreesToRadians(degrees: lon2 - lon1)
let lat1 = degreesToRadians(degrees: lat1)
let lat2 = degreesToRadians(degrees: lat2)
let a = sin(dLat/2) * sin(dLat/2) +
sin(dLon/2) * sin(dLon/2) * cos(lat1) * cos(lat2)
let c = 2 * atan2(sqrt(a), sqrt(1 - a))
return earthRadiusKm * c
}
This is version from "Henry Vilinskiy" adapted for MySQL and Kilometers:
CREATE FUNCTION `CalculateDistanceInKm`(
fromLatitude float,
fromLongitude float,
toLatitude float,
toLongitude float
) RETURNS float
BEGIN
declare distance float;
select
6367 * ACOS(
round(
COS(RADIANS(90-fromLatitude)) *
COS(RADIANS(90-toLatitude)) +
SIN(RADIANS(90-fromLatitude)) *
SIN(RADIANS(90-toLatitude)) *
COS(RADIANS(fromLongitude-toLongitude))
,15)
)
into distance;
return round(distance,3);
END;
This Lua code is adapted from stuff found on Wikipedia and in Robert Lipe's GPSbabel tool:
local EARTH_RAD = 6378137.0
-- earth's radius in meters (official geoid datum, not 20,000km / pi)
local radmiles = EARTH_RAD*100.0/2.54/12.0/5280.0;
-- earth's radius in miles
local multipliers = {
radians = 1, miles = radmiles, mi = radmiles, feet = radmiles * 5280,
meters = EARTH_RAD, m = EARTH_RAD, km = EARTH_RAD / 1000,
degrees = 360 / (2 * math.pi), min = 60 * 360 / (2 * math.pi)
}
function gcdist(pt1, pt2, units) -- return distance in radians or given units
--- this formula works best for points close together or antipodal
--- rounding error strikes when distance is one-quarter Earth's circumference
--- (ref: wikipedia Great-circle distance)
if not pt1.radians then pt1 = rad(pt1) end
if not pt2.radians then pt2 = rad(pt2) end
local sdlat = sin((pt1.lat - pt2.lat) / 2.0);
local sdlon = sin((pt1.lon - pt2.lon) / 2.0);
local res = sqrt(sdlat * sdlat + cos(pt1.lat) * cos(pt2.lat) * sdlon * sdlon);
res = res > 1 and 1 or res < -1 and -1 or res
res = 2 * asin(res);
if units then return res * assert(multipliers[units])
else return res
end
end
private double deg2rad(double deg)
{
return (deg * Math.PI / 180.0);
}
private double rad2deg(double rad)
{
return (rad / Math.PI * 180.0);
}
private double GetDistance(double lat1, double lon1, double lat2, double lon2)
{
//code for Distance in Kilo Meter
double theta = lon1 - lon2;
double dist = Math.Sin(deg2rad(lat1)) * Math.Sin(deg2rad(lat2)) + Math.Cos(deg2rad(lat1)) * Math.Cos(deg2rad(lat2)) * Math.Cos(deg2rad(theta));
dist = Math.Abs(Math.Round(rad2deg(Math.Acos(dist)) * 60 * 1.1515 * 1.609344 * 1000, 0));
return (dist);
}
private double GetDirection(double lat1, double lon1, double lat2, double lon2)
{
//code for Direction in Degrees
double dlat = deg2rad(lat1) - deg2rad(lat2);
double dlon = deg2rad(lon1) - deg2rad(lon2);
double y = Math.Sin(dlon) * Math.Cos(lat2);
double x = Math.Cos(deg2rad(lat1)) * Math.Sin(deg2rad(lat2)) - Math.Sin(deg2rad(lat1)) * Math.Cos(deg2rad(lat2)) * Math.Cos(dlon);
double direct = Math.Round(rad2deg(Math.Atan2(y, x)), 0);
if (direct < 0)
direct = direct + 360;
return (direct);
}
private double GetSpeed(double lat1, double lon1, double lat2, double lon2, DateTime CurTime, DateTime PrevTime)
{
//code for speed in Kilo Meter/Hour
TimeSpan TimeDifference = CurTime.Subtract(PrevTime);
double TimeDifferenceInSeconds = Math.Round(TimeDifference.TotalSeconds, 0);
double theta = lon1 - lon2;
double dist = Math.Sin(deg2rad(lat1)) * Math.Sin(deg2rad(lat2)) + Math.Cos(deg2rad(lat1)) * Math.Cos(deg2rad(lat2)) * Math.Cos(deg2rad(theta));
dist = rad2deg(Math.Acos(dist)) * 60 * 1.1515 * 1.609344;
double Speed = Math.Abs(Math.Round((dist / Math.Abs(TimeDifferenceInSeconds)) * 60 * 60, 0));
return (Speed);
}
private double GetDuration(DateTime CurTime, DateTime PrevTime)
{
//code for speed in Kilo Meter/Hour
TimeSpan TimeDifference = CurTime.Subtract(PrevTime);
double TimeDifferenceInSeconds = Math.Abs(Math.Round(TimeDifference.TotalSeconds, 0));
return (TimeDifferenceInSeconds);
}
i took the top answer and used it in a Scala program
import java.lang.Math.{atan2, cos, sin, sqrt}
def latLonDistance(lat1: Double, lon1: Double)(lat2: Double, lon2: Double): Double = {
val earthRadiusKm = 6371
val dLat = (lat2 - lat1).toRadians
val dLon = (lon2 - lon1).toRadians
val latRad1 = lat1.toRadians
val latRad2 = lat2.toRadians
val a = sin(dLat / 2) * sin(dLat / 2) + sin(dLon / 2) * sin(dLon / 2) * cos(latRad1) * cos(latRad2)
val c = 2 * atan2(sqrt(a), sqrt(1 - a))
earthRadiusKm * c
}
i curried the function in order to be able to easily produce functions that have one of the two locations fixed and require only a pair of lat/lon to produce distance.
Here's a Kotlin variation:
import kotlin.math.*
class HaversineAlgorithm {
companion object {
private const val MEAN_EARTH_RADIUS = 6371.008
private const val D2R = Math.PI / 180.0
}
private fun haversineInKm(lat1: Double, lon1: Double, lat2: Double, lon2: Double): Double {
val lonDiff = (lon2 - lon1) * D2R
val latDiff = (lat2 - lat1) * D2R
val latSin = sin(latDiff / 2.0)
val lonSin = sin(lonDiff / 2.0)
val a = latSin * latSin + (cos(lat1 * D2R) * cos(lat2 * D2R) * lonSin * lonSin)
val c = 2.0 * atan2(sqrt(a), sqrt(1.0 - a))
return MEAN_EARTH_RADIUS * c
}
}
you can find a implementation of this (with some good explanation) in F# on fssnip
here are the important parts:
let GreatCircleDistance&lt[&ltMeasure&gt] 'u&gt (R : float&lt'u&gt) (p1 : Location) (p2 : Location) =
let degToRad (x : float&ltdeg&gt) = System.Math.PI * x / 180.0&ltdeg/rad&gt
let sq x = x * x
// take the sin of the half and square the result
let sinSqHf (a : float&ltrad&gt) = (System.Math.Sin &gt&gt sq) (a / 2.0&ltrad&gt)
let cos (a : float&ltdeg&gt) = System.Math.Cos (degToRad a / 1.0&ltrad&gt)
let dLat = (p2.Latitude - p1.Latitude) |&gt degToRad
let dLon = (p2.Longitude - p1.Longitude) |&gt degToRad
let a = sinSqHf dLat + cos p1.Latitude * cos p2.Latitude * sinSqHf dLon
let c = 2.0 * System.Math.Atan2(System.Math.Sqrt(a), System.Math.Sqrt(1.0-a))
R * c
I needed to implement this in PowerShell, hope it can help someone else.
Some notes about this method
Don't split any of the lines or the calculation will be wrong
To calculate in KM remove the * 1000 in the calculation of $distance
Change $earthsRadius = 3963.19059 and remove * 1000 in the calculation of $distance the to calulate the distance in miles
I'm using Haversine, as other posts have pointed out Vincenty's formulae is much more accurate
Function MetresDistanceBetweenTwoGPSCoordinates($latitude1, $longitude1, $latitude2, $longitude2)
{
$Rad = ([math]::PI / 180);
$earthsRadius = 6378.1370 # Earth's Radius in KM
$dLat = ($latitude2 - $latitude1) * $Rad
$dLon = ($longitude2 - $longitude1) * $Rad
$latitude1 = $latitude1 * $Rad
$latitude2 = $latitude2 * $Rad
$a = [math]::Sin($dLat / 2) * [math]::Sin($dLat / 2) + [math]::Sin($dLon / 2) * [math]::Sin($dLon / 2) * [math]::Cos($latitude1) * [math]::Cos($latitude2)
$c = 2 * [math]::ATan2([math]::Sqrt($a), [math]::Sqrt(1-$a))
$distance = [math]::Round($earthsRadius * $c * 1000, 0) #Multiple by 1000 to get metres
Return $distance
}
Scala version
def deg2rad(deg: Double) = deg * Math.PI / 180.0
def rad2deg(rad: Double) = rad / Math.PI * 180.0
def getDistanceMeters(lat1: Double, lon1: Double, lat2: Double, lon2: Double) = {
val theta = lon1 - lon2
val dist = Math.sin(deg2rad(lat1)) * Math.sin(deg2rad(lat2)) + Math.cos(deg2rad(lat1)) *
Math.cos(deg2rad(lat2)) * Math.cos(deg2rad(theta))
Math.abs(
Math.round(
rad2deg(Math.acos(dist)) * 60 * 1.1515 * 1.609344 * 1000)
)
}
Here's my implementation in Elixir
defmodule Geo do
#earth_radius_km 6371
#earth_radius_sm 3958.748
#earth_radius_nm 3440.065
#feet_per_sm 5280
#d2r :math.pi / 180
def deg_to_rad(deg), do: deg * #d2r
def great_circle_distance(p1, p2, :km), do: haversine(p1, p2) * #earth_radius_km
def great_circle_distance(p1, p2, :sm), do: haversine(p1, p2) * #earth_radius_sm
def great_circle_distance(p1, p2, :nm), do: haversine(p1, p2) * #earth_radius_nm
def great_circle_distance(p1, p2, :m), do: great_circle_distance(p1, p2, :km) * 1000
def great_circle_distance(p1, p2, :ft), do: great_circle_distance(p1, p2, :sm) * #feet_per_sm
#doc """
Calculate the [Haversine](https://en.wikipedia.org/wiki/Haversine_formula)
distance between two coordinates. Result is in radians. This result can be
multiplied by the sphere's radius in any unit to get the distance in that unit.
For example, multiple the result of this function by the Earth's radius in
kilometres and you get the distance between the two given points in kilometres.
"""
def haversine({lat1, lon1}, {lat2, lon2}) do
dlat = deg_to_rad(lat2 - lat1)
dlon = deg_to_rad(lon2 - lon1)
radlat1 = deg_to_rad(lat1)
radlat2 = deg_to_rad(lat2)
a = :math.pow(:math.sin(dlat / 2), 2) +
:math.pow(:math.sin(dlon / 2), 2) *
:math.cos(radlat1) * :math.cos(radlat2)
2 * :math.atan2(:math.sqrt(a), :math.sqrt(1 - a))
end
end
Dart Version
Haversine Algorithm.
import 'dart:math';
class GeoUtils {
static double _degreesToRadians(degrees) {
return degrees * pi / 180;
}
static double distanceInKmBetweenEarthCoordinates(lat1, lon1, lat2, lon2) {
var earthRadiusKm = 6371;
var dLat = _degreesToRadians(lat2-lat1);
var dLon = _degreesToRadians(lon2-lon1);
lat1 = _degreesToRadians(lat1);
lat2 = _degreesToRadians(lat2);
var a = sin(dLat/2) * sin(dLat/2) +
sin(dLon/2) * sin(dLon/2) * cos(lat1) * cos(lat2);
var c = 2 * atan2(sqrt(a), sqrt(1-a));
return earthRadiusKm * c;
}
}
In Python, you can use the geopy library to compute the geodesic distance using the WGS84 ellipsoid:
from geopy.distance import geodesic
newport_ri = (41.49008, -71.312796)
cleveland_oh = (41.499498, -81.695391)
print(geodesic(newport_ri, cleveland_oh).km)
TypeScript Version
export const degreeToRadian = (degree: number) => {
return degree * Math.PI / 180;
}
export const distanceBetweenEarthCoordinatesInKm = (lat1: number, lon1: number, lat2: number, lon2: number) => {
const earthRadiusInKm = 6371;
const dLat = degreeToRadian(lat2 - lat1);
const dLon = degreeToRadian(lon2 - lon1);
lat1 = degreeToRadian(lat1);
lat2 = degreeToRadian(lat2);
const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return earthRadiusInKm * c;
}
I think a version of the algorithm in R is still missing:
gpsdistance<-function(lat1,lon1,lat2,lon2){
# internal function to change deg to rad
degreesToRadians<- function (degrees) {
return (degrees * pi / 180)
}
R<-6371e3 #radius of Earth in meters
phi1<-degreesToRadians(lat1) # latitude 1
phi2<-degreesToRadians(lat2) # latitude 2
lambda1<-degreesToRadians(lon1) # longitude 1
lambda2<-degreesToRadians(lon2) # longitude 2
delta_phi<-phi1-phi2 # latitude-distance
delta_lambda<-lambda1-lambda2 # longitude-distance
a<-sin(delta_phi/2)*sin(delta_phi/2)+
cos(phi1)*cos(phi2)*sin(delta_lambda/2)*
sin(delta_lambda/2)
cc<-2*atan2(sqrt(a),sqrt(1-a))
distance<- R * cc
return(distance) # in meters
}
For java
public static double degreesToRadians(double degrees) {
return degrees * Math.PI / 180;
}
public static double distanceInKmBetweenEarthCoordinates(Location location1, Location location2) {
double earthRadiusKm = 6371;
double dLat = degreesToRadians(location2.getLatitude()-location1.getLatitude());
double dLon = degreesToRadians(location2.getLongitude()-location1.getLongitude());
double lat1 = degreesToRadians(location1.getLatitude());
double lat2 = degreesToRadians(location2.getLatitude());
double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
return earthRadiusKm * c;
}
For anyone searching for a Delphi/Pascal version:
function GreatCircleDistance(const Lat1, Long1, Lat2, Long2: Double): Double;
var
Lat1Rad, Long1Rad, Lat2Rad, Long2Rad: Double;
const
EARTH_RADIUS_KM = 6378;
begin
Lat1Rad := DegToRad(Lat1);
Long1Rad := DegToRad(Long1);
Lat2Rad := DegToRad(Lat2);
Long2Rad := DegToRad(Long2);
Result := EARTH_RADIUS_KM * ArcCos(Cos(Lat1Rad) * Cos(Lat2Rad) * Cos(Long1Rad - Long2Rad) + Sin(Lat1Rad) * Sin(Lat2Rad));
end;
I take no credit for this code, I originally found it posted by Gary William on a public forum.

Resources