Wednesday, February 14, 2007

This is a free SQL Server 2000/2005 function that will calculate the distance in miles between 2 latitude/longitude points

The latitude/longitude points are input as decimal degrees, e.g.: 36.098217314. For those that are interested, it uses (a derivation of) the Haversine formula using the Great Circle Sphere earth radius. It can easily be adjusted to return kilometers or any other distance conversion.  Its intended use is to enable geographic (e.g.: zip, address) radius/proximty search by evaluating distance in a query WHERE statement on the table contains latitude and longitude columns.

But, I need code for .NET, not T-SQL!

For the .NETers among you, this can also easily be converted to .NET code -- just remember to use the Math namespace for all the math/trig functions (e.g.: Math.Asin(), Math.Round(), etc.).

CREATE FUNCTION [dbo].[LatLonRadiusDistance] 
(
	@lat1Degrees decimal(15,12),
	@lon1Degrees decimal(15,12),
	@lat2Degrees decimal(15,12),
	@lon2Degrees decimal(15,12)
)
RETURNS decimal(9,4)
AS
BEGIN

	DECLARE @earthSphereRadiusNauticalMiles as decimal(10,6)
	DECLARE @nauticalMileConversionToMilesFactor as decimal(7,6)
	SELECT @earthSphereRadiusNauticalMiles = 6366.707019
	SELECT @nauticalMileConversionToMilesFactor = .621371

	-- convert degrees to radians
	DECLARE @lat1Radians decimal(15,12)
	DECLARE @lon1Radians decimal(15,12)
	DECLARE @lat2Radians decimal(15,12)
	DECLARE @lon2Radians decimal(15,12)
	SELECT @lat1Radians = (@lat1Degrees / 180) * PI()
	SELECT @lon1Radians = (@lon1Degrees / 180) * PI()
	SELECT @lat2Radians = (@lat2Degrees / 180) * PI()
	SELECT @lon2Radians = (@lon2Degrees / 180) * PI()

	-- formula for distance from [lat1,lon1] to [lat2,lon2]
	RETURN ROUND(2 * ASIN(SQRT(POWER(SIN((@lat1Radians - @lat2Radians) / 2) ,2)
        + COS(@lat1Radians) * COS(@lat2Radians) * POWER(SIN((@lon1Radians - @lon2Radians) / 2), 2)))
        * (@earthSphereRadiusNauticalMiles * @nauticalMileConversionToMilesFactor), 4)

END

12/30/2007 1:14:04 PM (Central Standard Time, UTC-06:00)
This looks great. However, have you ever run into any performance problems?
1/2/2008 11:12:46 AM (Central Standard Time, UTC-06:00)
Nothing noticable for my particular uses.

It is worth noting, however, that if you are running the function inline (inside a query), I would recommend "geographically boxing" the dataset, i.e.: narrowing the WHERE statement with the min/max latitude and longitude. This prevents evaluating the _entire_ dataset where logically there is no chance the latitude/longitude falls within the particular radius.

I created another SQL function to determine this min/max latitude longitude to "box" given the central lat/lon and the radius. If you'd like me to post that function, I'll see if I can dig it up from my archives (was a project for a past employer).

- Troy
1/17/2008 4:48:13 PM (Central Standard Time, UTC-06:00)

Linked this article from my own blog. Very useful function Troy!

http://geekswithblogs.net/TheNinja/archive/2008/01/17/how_to_calculate_the_distance_in_calculate_the_distance_in_miles_between_2_latitude_longitude_points.aspx

The Ninja
1/18/2008 1:14:47 PM (Central Standard Time, UTC-06:00)
Thanks! Glad you found it useful.
Troy DeMonbreun
4/3/2008 11:16:54 AM (Central Daylight Time, UTC-05:00)
Awesome function! Saved me a ton of time. Thanks a lot!
5/6/2008 8:07:45 PM (Central Daylight Time, UTC-05:00)
Thank you. This is a big help. You mentioned that you had a complimentary "box" routine that you might be willing to post. Would be grateful. Best regards.
Name
E-mail
Home page

Comment (HTML not allowed)  

Enter the code shown (prevents robots):