R code runs too slow, how to speed and rewrite this code - r

The stu.csv contains 850,000 rows and 3 columns. The 2nd column is the longitude of ID, the 3rd column is the latitude of ID. The data in stu.csv file is like this:
ID longitude latitude
156 41.88367183 12.48777756
187 41.92854333 12.46903667
297 41.89106861 12.49270456
89 41.79317669 12.43212196
79 41.90027472 12.46274618
... ... ...
The pseudocode is as follows. it aims to compute the distance between two IDs on the surface of the earth with longitude and latitude, and outputs the cumulative sum from any two IDs:
dlon = lon2 - lon1
dlat = lat2 - lat1
a = (sin(dlat/2))^2 + cos(lat1) * cos(lat2) * (sin(dlon/2))^2
c = 2 * atan2( sqrt(a), sqrt(1-a) )
distance = 6371000 * c (where 6371000 is the radius of the Earth)
This code is as follows, but it runs too slow. how to speed and rewrite the code? Thank you.
stu<-read.table("stu.csv",header=T,sep=",");
## stu has 850,000 rows and 3 columns.
m<-nrow(stu);
distance<-0;
for (i in 1:(m-1))
{
for (j in (i+1))
{
dlon = stu[j,2] - stu[i,2];
dlat = stu[j,3] - stu[i,3];
a = (sin(dlat/2))^2 + cos(stu[i,3]) * cos(stu[j,3]) * (sin(dlon/2))^2;
c = 2 * atan2( sqrt(a), sqrt(1-a) );
distance <-distance+6371000 * c;
}
}
distance

For your case, if it is the cumulative distance, we can vectorize:
x <- read.table(text = "ID longitude latitude
156 41.88367183 12.48777756
187 41.92854333 12.46903667
297 41.89106861 12.49270456
89 41.79317669 12.43212196
79 41.90027472 12.46274618", header= TRUE)
x$laglon <- dplyr::lead(x$longitude, 1)
x$laglat <- dplyr::lead(x$latitude, 1)
distfunc <- function(long, lat, newlong, newlat){
dlon = newlong - long
dlat = newlat - lat
a = (sin(dlat/2))^2 + cos(lat) * cos(newlat) * (sin(dlon/2))^2
c = 2 * atan2( sqrt(a), sqrt(1-a) )
6371000 * c
}
distfunc(x$longitude, x$latitude, x$laglon, x$laglat)
308784.6 281639.6 730496.0 705004.2 NA
Take the cumsum of the output to get the total distance.
On a million rows, it takes around 0.4 secs on my system

What you're looking for is called "vectorizing a loop." See this related question.
The basic idea is that in a loop, the CPU has to finish processing the first cell before moving on to the second cell, unless it has some guarantee that how the first cell is processed won't effect the state for the second cell. But if it's a vector computation, that guarantee exists, and it can work on as many elements simultaneously as possible, leading to faster speed. (There are other reasons why this works better, but that's the basic motivation.)
See this introduction to apply in R for how to rewrite your code without the loop. (Much of the calculation you should be able to maintain as is.)

Related

Plot a point in 3D space perpendicular to a line vector

I'm attempting to calculate a point in 3D space which is orthogonal/perpendicular to a line vector.
So I have P1 and P2 which form the line. I’m then trying to find a point with a radius centred at P1, which is orthogonal to the line.
I'd like to do this using trigonometry, without any programming language specific functions.
At the moment I'm testing how accurate this function is by potting a circle around the line vector.
I also rotate the line vector in 3D space to see what happens to the plotted circle, this is where my results vary.
Some of the unwanted effects include:
The circle rotating and passing through the line vector.
The circle's radius appearing to reducing to zero before growing as the line vector changes direction.
I used this question to get me started, and have since made some adjustments to the code.
Any help with this would be much appreciated - I've spent 3 days drawing circles now. Here's my code so far
//Define points which form the line vector
dx = p2x - p1x;
dy = p2y - p1y;
dz = p2z - p1z;
// Normalize line vector
d = sqrt(dx*dx + dy*dy + dz*dz);
// Line vector
v3x = dx/d;
v3y = dy/d;
v3z = dz/d;
// Angle and distance to plot point around line vector
angle = 123 * pi/180 //convert to radians
radius = 4;
// Begin calculating point
s = sqrt(v3x*v3x + v3y*v3y + v3z*v3z);
// Calculate v1.
// I have been playing with these variables (v1x, v1y, v1z) to try out different configurations.
v1x = s * v3x;
v1y = s * v3y;
v1z = s * -v3z;
// Calculate v2 as cross product of v3 and v1.
v2x = v3y*v1z - v3z*v1y;
v2y = v3z*v1x - v3x*v1z;
v2z = v3x*v1y - v3y*v1x;
// Point in space around the line vector
px = p1x + (radius * (v1x * cos(angle)) + (v2x * sin(angle)));
py = p1y + (radius * (v1y * cos(angle)) + (v2y * sin(angle)));
pz = p1z + (radius * (v1z * cos(angle)) + (v2z * sin(angle)));
EDIT
After wrestling with this for days while in lockdown, I've finally managed to get this working. I'd like to thank MBo and Futurologist for their invaluable input.
Although I wasn't able to get their examples working (more likely due to me being at fault), their answers pointed me in the right direction and to that eureka moment!
The key was in swapping the correct vectors.
So thank you to you both, you really helped me along with this. This is my final (working) code:
//Set some vars
angle = 123 * pi/180;
radius = 4;
//P1 & P2 represent vectors that form the line.
dx = p2x - p1x;
dy = p2y - p1y;
dz = p2z - p1z;
d = sqrt(dx*dx + dy*dy + dz*dz)
//Normalized vector
v3x = dx/d;
v3y = dy/d;
v3z = dz/d;
//Store vector elements in an array
p = [v3x, v3y, v3z];
//Store vector elements in second array, this time with absolute value
p_abs = [abs(v3x), abs(v3y), abs(v3z)];
//Find elements with MAX and MIN magnitudes
maxval = max(p_abs[0], p_abs[1], p_abs[2]);
minval = min(p_abs[0], p_abs[1], p_abs[2]);
//Initialise 3 variables to store which array indexes contain the (max, medium, min) vector magnitudes.
maxindex = 0;
medindex = 0;
minindex = 0;
//Loop through p_abs array to find which magnitudes are equal to maxval & minval. Store their indexes for use later.
for(i = 0; i < 3; i++) {
if (p_abs[i] == maxval) maxindex = i;
else if (p_abs[i] == minval) minindex = i;
}
//Find the remaining index which has the medium magnitude
for(i = 0; i < 3; i++) {
if (i!=maxindex && i!=minindex) {
medindex = i;
break;
}
}
//Store the maximum magnitude for now.
storemax = (p[maxindex]);
//Swap the 2 indexes that contain the maximum & medium magnitudes, negating maximum. Set minimum magnitude to zero.
p[maxindex] = (p[medindex]);
p[medindex] = -storemax;
p[minindex] = 0;
//Calculate v1. Perpendicular to v3.
s = sqrt(v3x*v3x + v3z*v3z + v3y*v3y);
v1x = s * p[0];
v1y = s * p[1];
v1z = s * p[2];
//Calculate v2 as cross product of v3 and v1.
v2x = v3y*v1z - v3z*v1y;
v2y = v3z*v1x - v3x*v1z;
v2z = v3x*v1y - v3y*v1x;
//For each circle point.
circlepointx = p2x + radius * (v1x * cos(angle) + v2x * sin(angle))
circlepointy = p2y + radius * (v1y * cos(angle) + v2y * sin(angle))
circlepointz = p2z + radius * (v1z * cos(angle) + v2z * sin(angle))
Your question is too vague, but I may suppose what you really want.
You have line through two point p1 and p2. You want to build a circle of radius r centered at p1 and perpendicular to the line.
At first find direction vector of this line - you already know how - normalized vector v3.
Now you need arbitrary vector perpendicular to v3: find components of v3 with the largest magnitude and with the second magnitude. For example, abs(v3y) is the largest and abs(v3x) has the second magnitude. Exchange them, negate the largest, and make the third component zero:
p = (-v3y, v3x, 0)
This vector is normal to v3 (their dot product is zero)
Now normalize it
pp = p / length(p)
Now get binormal vector as cross product of v3 and pp (I has unit length, no need to normalize), it is perpendicular to both v3 and pp
b = v3 x pp
Now build needed circle
circlepoint(theta) = p1 + radius * pp * Cos(theta) + radius * b * Sin(theta)
Aslo note that angle in radians is
angle = degrees * pi / 180
#Input:
# Pair of points which determine line L:
P1 = [x_P1, y_P1, z_P1]
P2 = [x_P1, y_P1, z_P1]
# Radius:
Radius = R
# unit vector aligned with the line passing through the points P1 and P2:
V3 = P1 - P2
V3 = V3 / norm(V3)
# from the three basis vectors, e1 = [1,0,0], e2 = [0,1,0], e3 = [0,0,1]
# pick the one that is the most transverse to vector V3
# this means, look at the entries of V3 = [x_V3, y_V3, z_V3] and check which
# one has the smallest absolute value and record its index. Take the coordinate
# vector that has 1 at that selected index. In other words,
# if min( abs(x_V3), abs(y_V)) = abs(y_V3),
# then argmin( abs(x_V3), abs(y_V3), abs(z_V3)) = 2 and so take e = [0,1,0]:
e = [0,0,0]
i = argmin( abs(V3[1]), abs(V3[2]), abs(V3[3]) )
e[i] = 1
# a unit vector perpendicular to both e and V3:
V1 = cross(e, V3)
V1 = V1 / norm(V1)
# third unit vector perpendicular to both V3 and V1:
V2 = cross(V3, V1)
# an arbitrary point on the circle (i.e. equation of the circle with parameter s):
P = P1 + Radius*( np.cos(s)*V1 + np.sin(s)*V2 )
# E.g. say you want to find point P on the circle, 60 degrees relative to vector V1:
s = pi/3
P = P1 + Radius*( cos(s)*V1 + sin(s)*V2 )
Test example in Python:
import numpy as np
#Input:
# Pair of points which determine line L:
P1 = np.array([1, 1, 1])
P2 = np.array([3, 2, 3])
Radius = 3
V3 = P1 - P2
V3 = V3 / np.linalg.norm(V3)
e = np.array([0,0,0])
e[np.argmin(np.abs(V3))] = 1
V1 = np.cross(e, V3)
V1 = V1 / np.linalg.norm(V3)
V2 = np.cross(V3, V1)
# E.g., say you want to rotate point P along the circle, 60 degrees along rel to V1:
s = np.pi/3
P = P1 + Radius*( np.cos(s)*V1 + np.sin(s)*V2 )

Linear zoom function 2D

I have a canvas and a scale value. The maximum scale is 1, the minimum scale value is something like 0.1 or above.
Let’s say we have discrete time units. I’m looking for a function that zooms linear over an time interval I (lets say 100 time units), from a start zoom s to an end zoom e. Let 0 >= i < I be the current interval.
Example: Zoom from 0.2 to 1.0 in 100 time units.
Obviously zoom(i) = (e-s)/I * i does not produce a linear zoom. Because a step from 0.2 to 0.4 doubles the zoom, while the same amount from 0.8 to 1.0 only increases the zoom by 25%.
I was thinking that this function needs something logarithmic to base 2, but I’m stuck finding the right function.
To provide constant ratio with constant argument difference, you need exponential function (it is possible to use any base, e, 2, 10 and so on with corresponding logarithms)
F(x) = A * Exp(B * x)
To get coefficients A and B for given border conditions (argument x0 corresponds to function value F0):
F0 = A * Exp(B * x0)
F1 = A * Exp(B * x1)
divide the second equation by the first:
Exp(B * (x1 -x0) = F1 / F0
B * (x1 -x0) = ln(F1 / F0)
so
B = ln(F1 / F0) / (x1 - x0)
and
A = F0 * Exp(-B * x0)
For your example
x0=0, x1=100
zoom0 = 0.2, zoom1=1
B = ln(5) / 100 = 0.0161
A = 0.2 * Exp(0) = 0.2
zoom(i) = 0.2 * Exp(0.0161 * i)
zoom(0) = 0.2
zoom(50) = 0.447
zoom(100) = 1
note that
zoom(50) / zoom(0) = zoom(100) / zoom(50)
What you need is not a logarithm but root. You requirements is effectively following: you want to find such sequence A[i] that
A[0] = 0.1
A[N] = 1
A[i+1]/A[i] = k, where kis some constant
The solution for this is obviously
A[i] = 0.1 * k^i
and so k should be
k^N = 1/0.1 = 10
or
k = root(10, N) = 10^(1/N)
For practical reasons it might be better to use N which is power of 2 so you can calculate some intermediate results by multiplying by a lesser root to have less
rounding error accumulated. What I means is that
a[N/2] = sqrt(0.1) = 0.1 * sqrt(1/0.1)
a[N/4] = 0.1 * root(1/0.1, 4)
a[3*N/4] = a[N/2] * root(1/0.1, 4)
It also might make sense to change starting value of 0.1 to something that is itself some power for example 1/9 or 1/16

Implementation of position determination function

I'm attempting to implement position determination function of an aircraft to get "latitude/longitude azimuth"
I attached 3 images for summerized formula as you may see this is 5-step trigonometric equation (Steps 0/4) which is my aim to program. image1; image2 image3
To find aircraft coordinates there are defined 9 input parameters (image1): Station U and S latitude,longitude,altitude; Aircraft altitude and 2 slant ranges.
At the end of problem (image3) we will find 3 outputs: Aircraft latitude/longitude azimuth.
This code implements the solution explained for: How can I triangulate a position using two DMEs? on aviation.se. The code is in Python, which I happen to use instead of C, it's easy to convert into another language as required. I've broken down the calculation in smaller units to make code more legible and to ease your understanding.
The problem involves 3 points in 3D space: U and S are the DMEs, A is the aircraft.
As we just need the coordinates of U and S, to determinate A coordinates, I'm using coordinates of 3 well known DME stations. This will allow to check whether the result is correct. View based on the Low Altitude Enroute Chart:
When the program is run, the output is:
CAN: lat 49.17319, lon -0.4552778, alt 82
EVX: lat 49.03169, lon 1.220861, alt 152
P north: lat 49.386910325692874, lon 0.646650777948733, alt 296
P south: lat 48.78949175956114, lon 0.5265322105880027, alt 296
First are the coordinates of points U (CAN DME) and S (EVX DME) we entered, and
then two lines for the two possible location of the aircraft.
I made another test with DME at longer distance (1241 km for ARE and 557.1 km for GLA) which worked pretty good too:
ARE: lat 48.33264, lon -3.602472, alt 50
GLA: lat 46.40861, lon 6.244222, alt 1000
P north: lat 48.082101174246304, lon 13.210754399535269, alt 10
P south: lat 41.958725412109445, lon 9.470999690780628, alt 10
The actual location of the aircraft is supposed to be SZA navaid, in south of France: Lat 41.937°, lon 9.399°.
from math import asin, sqrt, cos, sin, atan2, acos, pi, radians, degrees
# Earth radius in meters (https://rechneronline.de/earth-radius/)
E_RADIUS = 6367 * 1000 # at 45°N - Adjust as required
def step_0(r_e, h_u, h_s, h_a, d_ua, d_sa):
# Return angular distance between each station U/S and aircraft
# Triangle UCA and SCA: The three sides are known,
a = (d_ua - h_a + h_u) * (d_ua + h_a - h_u)
b = (r_e + h_u) * (r_e + h_a)
theta_ua = 2 * asin(.5 * sqrt(a / b))
a = (d_sa - h_a + h_s) * (d_sa + h_a - h_s)
b = (r_e + h_s) * (r_e + h_a)
theta_sa = 2 * asin(.5 * sqrt(a / b))
# Return angular distances between stations and aircraft
return theta_ua, theta_sa
def step_1(lat_u, lon_u, lat_s, lon_s):
# Determine angular distance between the two stations
# and the relative azimuth of one to the other.
a = sin(.5 * (lat_s - lat_u))
b = sin(.5 * (lon_s - lon_u))
c = sqrt(a * a + cos(lat_s) * cos(lat_u) * b * b)
theta_us = 2 * asin(c)
a = lon_s - lon_u
b = cos(lat_s) * sin(a)
c = sin(lat_s) * cos(lat_u)
d = cos(lat_s) * sin(lat_u) * cos(a)
psi_su = atan2(b, c - d)
return theta_us, psi_su
def step_2(theta_us, theta_ua, theta_sa):
# Determine whether DME spheres intersect
if (theta_ua + theta_sa) < theta_us:
# Spheres are too remote to intersect
return False
if abs(theta_ua - theta_sa) > theta_us:
# Spheres are concentric and don't intersect
return False
# Spheres intersect
return True
def step_3(theta_us, theta_ua, theta_sa):
# Determine one angle of the USA triangle
a = cos(theta_sa) - cos(theta_us) * cos(theta_ua)
b = sin(theta_us) * sin(theta_ua)
beta_u = acos(a / b)
return beta_u
def step_4(ac_south, lat_u, lon_u, beta_u, psi_su, theta_ua):
# Determine aircraft coordinates
psi_au = psi_su
if ac_south:
psi_au += beta_u
else:
psi_au -= beta_u
# Determine aircraft latitude
a = sin(lat_u) * cos(theta_ua)
b = cos(lat_u) * sin(theta_ua) * cos(psi_au)
lat_a = asin(a + b)
# Determine aircraft longitude
a = sin(psi_au) * sin(theta_ua)
b = cos(lat_u) * cos(theta_ua)
c = sin(lat_u) * sin(theta_ua) * cos(psi_au)
lon_a = atan2(a, b - c) + lon_u
return lat_a, lon_a
def main():
# Program entry point
# -------------------
# For this test, I'm using three locations in France:
# VOR Caen, VOR Evreux and VOR L'Aigle.
# The angles and horizontal distances between them are known
# by looking at the low-altitude enroute chart which I've posted
# here: https://i.stack.imgur.com/m8Wmw.png
# We know there coordinates and altitude by looking at the AIP France too.
# For DMS <--> Decimal degrees, this tool is handy:
# https://www.rapidtables.com/convert/number/degrees-minutes-seconds-to-degrees.html
# Let's pretend the aircraft is at LGL
# lat = 48.79061, lon = 0.5302778
# Stations U and S are:
u = {'label': 'CAN', 'lat': 49.17319, 'lon': -0.4552778, 'alt': 82}
s = {'label': 'EVX', 'lat': 49.03169, 'lon': 1.220861, 'alt': 152}
# We know the aircraft altitude
a_alt = 296 # meters
# We know the approximate slant ranges to stations U and S
au_range = 45 * 1852 # 1 NM = 1,852 m
as_range = 31 * 1852
# Compute angles station - earth center - aircraft for U and S
# Expected values UA: 0.0130890288 rad
# SA: 0.0090168045 rad
theta_ua, theta_sa = step_0(
r_e=E_RADIUS, # Earth
h_u=u['alt'], # Station U altitude
h_s=s['alt'], # Station S altitude
h_a=a_alt, d_ua=au_range, d_sa=as_range # aircraft data
)
# Compute angle between station, and their relative azimuth
# We need to convert angles into radians
theta_us, psi_su = step_1(
lat_u=radians(u['lat']), lon_u=radians(u['lon']), # Station U coordinates
lat_s=radians(s['lat']), lon_s=radians(s['lon'])) # Station S coordinates
# Check validity of ranges
if not step_2(
theta_us=theta_us,
theta_ua=theta_ua,
theta_sa=theta_sa):
# Cannot compute, spheres don't intersect
print('Cannot compute, ranges are not consistant')
return 1
# Solve one angle of the USA triangle
beta_u = step_3(
theta_us=theta_us,
theta_ua=theta_ua,
theta_sa=theta_sa)
# Compute aircraft coordinates.
# The first parameter is whether the aircraft is south of the line
# between U and S. If you don't know, then you need to compute
# both, once with ac_south = False, once with ac_south = True.
# You will get the two possible positions, one must be eliminated.
# North position
lat_n, lon_n = step_4(
ac_south=False, # See comment above
lat_u=radians(u['lat']), lon_u=radians(u['lon']), # Station U
beta_u=beta_u, psi_su=psi_su, theta_ua=theta_ua # previously computed
)
pn = {'label': 'P north', 'lat': degrees(lat_n), 'lon': degrees(lon_n), 'alt': a_alt}
# South position
lat_s, lon_s = step_4(
ac_south=True,
lat_u=radians(u['lat']), lon_u=radians(u['lon']),
beta_u=beta_u, psi_su=psi_su, theta_ua=theta_ua)
ps = {'label': 'P south', 'lat': degrees(lat_s), 'lon': degrees(lon_s), 'alt': a_alt}
# Print results
fmt = '{}: lat {}, lon {}, alt {}'
for p in u, s, pn, ps:
print(fmt.format(p['label'], p['lat'], p['lon'], p['alt']))
# The expected result is about:
# CAN: lat 49.17319, lon -0.4552778, alt 82
# EVX: lat 49.03169, lon 1.220861, alt 152
# P north: lat ??????, lon ??????, alt 296
# P south: lat 48.79061, lon 0.5302778, alt 296
if __name__ == '__main__':
main()

How to calculate coordinates of the gunpoint

Good whatever time of day! I have some sprite:
A point has coordinates Actor.x; Actor.y.
AB length = 96
BC length = 86
AC length = 42
All calculations are approximate, I made it with help the ruler in Photoshop.
Sprite always towards mouse, angle (in radians) stores in Actor.direction variable. I draw sprite with scale 0.3.
All bullets toward mouse (that is Bullet.direction == Actor.direction). I need to create bullets in the B point. How I can calculate coordinates of the B point with any angle?
UPD
If I will create bullets in the coordinates:
x = Actor.x + 96 * math.cos(Actor.direction) * 0.3
y = Actor.y + 96 * math.sin(Actor.direction) * 0.3
I get it:
Excuse my bad English! It isn't my native language. Thank you in advance!
Let
cs = math.cos(Actor.direction)
sn = math.sin(Actor.direction)
point B will be shifted from A by
dx = - 42 * sn + 86 * cs
dy = 42 * cs + 86 * sn
Perhaps you will need to change signs before both 42s
(I did not account for scale)

Distance between 2 geocodes

What is the formula for calculating the distance between 2 geocodes? I have seen some of the answers on this site but they basically say to rely on SQL Server 08 functions, I'm not on 08 yet. Any help would be appreciated.
Use an approximation of the earth and the Haversine formula. You can get a javascript version on the following url, which you can translate to your language of choice:
http://www.movable-type.co.uk/scripts/latlong.html
Here is another way: http://escience.anu.edu.au/project/04S2/SE/3DVOT/3DVOT/pHatTrack_Application/Source_code/pHatTrack/Converter.java
Take a look here for a SQL server 2000 version SQL Server Zipcode Latitude/Longitude proximity distance search
This will do it for you in c#.
Within the namespace put these:
public enum DistanceType { Miles, Kilometers };
public struct Position
{
public double Latitude;
public double Longitude;
}
class Haversine
{
public double Distance(Position pos1, Position pos2, DistanceType type)
{
double preDlat = pos2.Latitude - pos1.Latitude;
double preDlon = pos2.Longitude - pos1.Longitude;
double R = (type == DistanceType.Miles) ? 3960 : 6371;
double dLat = this.toRadian(preDlat);
double dLon = this.toRadian(preDlon);
double a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) +
Math.Cos(this.toRadian(pos1.Latitude)) * Math.Cos(this.toRadian(pos2.Latitude)) *
Math.Sin(dLon / 2) * Math.Sin(dLon / 2);
double c = 2 * Math.Asin(Math.Min(1, Math.Sqrt(a)));
double d = R * c;
return d;
}
private double toRadian(double val)
{
return (Math.PI / 180) * val;
}
Then to utilise these in the main code:
Position pos1 = new Position();
pos1.Latitude = Convert.ToDouble(hotelx.latitude);
pos1.Longitude = Convert.ToDouble(hotelx.longitude);
Position pos2 = new Position();
pos2.Latitude = Convert.ToDouble(lat);
pos2.Longitude = Convert.ToDouble(lng);
Haversine calc = new Haversine();
double result = calc.Distance(pos1, pos2, DistanceType.Miles);
If
you know that the 2 points are "not too far from each other"
and you tolerate a "reasonably small" error.
Then, consider that the earth is flat between the 2 points :
The distance difference in the latitude direction is EarthRadius * latitude difference
The distance difference in the longitude direction is EarthRadius * longitude difference * cos(latitude).
We multiply by cos(lat) because the longitude degrees don't make the same km distance if the latitude changes. As P1 and P2 are close, cos(latP1) is close from cos(latP2)
Then Pythagore
In JavaScript :
function ClosePointsDistance(latP1, lngP1, latP2, lngP2) {
var d2r = Math.PI / 180,
R=6371; // Earth Radius in km
latP1 *= d2r; lngP1 *= d2r; latP2 *= d2r; lngP2 *= d2r; // convert to radians
dlat = latP2 - latP1,
dlng = (lngP2 - lngP1) * Math.cos(latP1);
return R * Math.sqrt( dlat*dlat + dlng*dlng );
}
I tested it between Paris and Orleans (France) : the formula finds 110.9 km whereas the (exact) Haversine formula finds 111.0 km.
!!! Beware of situations around the meridian 0 (you may shift it) : if P1 is at Lng 359 and P2 is at Lng 0, the function will consider them abnormally far !!!
The pythagorean theorem as offered up by others here doesn't work so well.
The best, simple answer is to approximate the earth as a sphere (its actually a slightly flattened sphere, but this is very close). In Haskell, for instance you might use the following, but the math can be transcribed into pretty much anything:
distRadians (lat1,lon1) (lat2,lon2) =
radius_of_earth *
acos (cos lat1 * cos lon1 * cos lat2 * cos lon2 +
cos lat1 * sin lon1 * cos lat2 * sin lon2 +
sin lat1 * sin lat2) where
radius_of_earth = 6378 -- kilometers
distDegrees a b = distRadians (coord2rad a) (coord2rad b) where
deg2rad d = d * pi / 180
coord2rad (lat,lon) = (deg2rad lat, deg2rad lon)
distRadians requires your angles to be given in radians.
distDegrees is a helper function that can take lattitudes and longitudes in degrees.
See this series of posts for more information on the derivation of this formula.
If you really need the extra precision granted by assuming the earth is ellipsoidal, see this FAQ: http://www.movable-type.co.uk/scripts/gis-faq-5.1.html
Here is a way to do it if you are using sql server.
CREATE function dist (#Lat1 varchar(50), #Lng1 varchar(50),#Lat2 varchar(50), #Lng2 varchar(50))
returns float
as
begin
declare #p1 geography
declare #p2 geography
set #p1 = geography::STGeomFromText('POINT('+ #Lng1+' '+ #Lat1 +')', 4326)
set #p2 = geography::STGeomFromText('POINT('+ #Lng2+' '+ #Lat2 +')', 4326)
return #p1.STDistance(#p2)
end
You're looking for the length of the Great Circle Path between two points on a sphere. Try looking up "Great Circle Path" or "Great Circle Distance" on Google.
Sorry, I don't know what country you are in even. Are we talking about Easting and Northings (UK, Ordance Survey system) or Lat/Long or some other system?
If we are talking Easting and Northing then you can use
sqr((x1-x2)^2 + (y1-y2)^2)
This does not allow for the fact that the earth is a sphere, but for short distances you won't notice. We use it at work for distances between points within the county.
Be carful about how longer grid reference you use. I think an 8 figure reference will give you a distance in metres. I'll be able to get a definate answer at work next week if no one else has supplied it.
the pythagorean theorem?

Resources