# Ruby: Calculating the orthodromic distance using the Haversine formula

As part of the UI I'm building around my football stadiums data set I wanted to calculate the distance from a football stadium to a point on the map in Ruby since cypher doesn't currently return this value.

I had the following cypher query to return the football stadiums near Westminster along with their lat/long values:

``````
lat, long, distance = ["51.55786291569685", "0.144195556640625", 10]
query =  " START node = node:geom('withinDistance:[#{lat}, #{long}, #{distance}]')"
query << " RETURN node.name, node.team, node.lat, node.lon"

rows = result["data"].map do |row|
{ :team => row,
:lat => row,
:lon => row
}
p rows
``````

which returns the following:

``````
``````

In the neo4j spatial code the distance between two points is referred to as the 'orthodromic distance' but searching for that didn't come up with anything. However, I did eventually come across the following post which referred to the Haversine formula which is exactly what we want.

There is a good explanation of the formula on the Ask Dr Math forum which defines the formula like so:

``````
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))
d = R * c
``````

where:

• R - the radius of the Earth
• c - the great circle distance in radians
• c - the great circle distance in the same units as R
• lat1, lat2, lon1, lon2 - latitude and longitudes in radians

To convert decimal degrees to radians we need to multiply the number of degrees by pi/180 radians/degree.

The Ruby translation of that formula looks like this:

``````
def haversine(lat1, long1, lat2, long2)
rlat1, rlong1, rlat2, rlong2 = [lat1, long1, lat2, long2].map { |d| as_radians(d)}

dlon = rlong1 - rlong2
dlat = rlat1 - rlat2

a = power(Math::sin(dlat/2), 2) + Math::cos(rlat1) * Math::cos(rlat2) * power(Math::sin(dlon/2), 2)
great_circle_distance = 2 * Math::atan2(Math::sqrt(a), Math::sqrt(1-a))
end

degrees * Math::PI/180
end

def power(num, pow)
num ** pow
end
``````

And if we change our initial code to use it:

``````
lat, long, distance = ["51.55786291569685", "0.144195556640625", 10]
query =  " START node = node:geom('withinDistance:[#{lat}, #{long}, #{distance}]')"
query << " RETURN node.name, node.team, node.lat, node.lon"

rows = result["data"].map do |row|
{ :team => row,