Vincenty Distance

Developed In: SQL — Contributed by: bramsi

Calculate/measure distance between two poins using Vincenty Distance WGS-84 algorithm.

Code translate from geopy http://code.google.com/p/geopy/.


bramsi
SQL
  1. DELIMITER ;;
  2. DROP FUNCTION IF EXISTS `vd`;;
  3.  
  4. CREATE FUNCTION `vd`(lng1 DOUBLE, lat1 DOUBLE, lng2 DOUBLE, lat2 DOUBLE, metric VARCHAR(2)) RETURNS DOUBLE
  5. DETERMINISTIC
  6. COMMENT 'Vincenty Distance WGS-84 http://code.google.com/p/geopy/'
  7. BEGIN
  8. DECLARE gcdx DOUBLE;
  9. DECLARE lng_rad1 DOUBLE;
  10. DECLARE lat_rad1 DOUBLE;
  11. DECLARE lng_rad2 DOUBLE;
  12. DECLARE lat_rad2 DOUBLE;
  13.  
  14. DECLARE wgs84_major DOUBLE;
  15. DECLARE wgs84_minor DOUBLE;
  16. DECLARE wgs84_flattening DOUBLE;
  17.  
  18. DECLARE delta_lng DOUBLE;
  19. DECLARE reduced_lat1 DOUBLE;
  20. DECLARE reduced_lat2 DOUBLE;
  21. DECLARE sin_reduced1 DOUBLE;
  22. DECLARE cos_reduced1 DOUBLE;
  23. DECLARE sin_reduced2 DOUBLE;
  24. DECLARE cos_reduced2 DOUBLE;
  25.  
  26. DECLARE lambda_lng DOUBLE;
  27. DECLARE lambda_prime DOUBLE;
  28.  
  29. DECLARE iter_limit INT;
  30.  
  31. DECLARE sin_lambda_lng DOUBLE;
  32. DECLARE cos_lambda_lng DOUBLE;
  33. DECLARE sin_sigma DOUBLE;
  34. DECLARE cos_sigma DOUBLE;
  35. DECLARE sigma DOUBLE;
  36. DECLARE sin_alpha DOUBLE;
  37. DECLARE cos_sq_alpha DOUBLE;
  38. DECLARE cos2_sigma_m DOUBLE;
  39. DECLARE C DOUBLE;
  40. DECLARE u_sq DOUBLE;
  41. DECLARE A DOUBLE;
  42. DECLARE B DOUBLE;
  43. DECLARE delta_sigma DOUBLE;
  44.  
  45. SET lng_rad1 := RADIANS(lng1);
  46. SET lat_rad1 := RADIANS(lat1);
  47. SET lng_rad2 := RADIANS(lng2);
  48. SET lat_rad2 := RADIANS(lat2);
  49.  
  50. SET wgs84_major := 6378.137;
  51. SET wgs84_minor := 6356.7523142;
  52. SET wgs84_flattening := 1 / 298.257223563;
  53.  
  54. SET delta_lng := lng_rad2 - lng_rad1;
  55.  
  56. SET reduced_lat1 := atan((1 - wgs84_flattening) * tan(lat_rad1));
  57. SET reduced_lat2 := atan((1 - wgs84_flattening) * tan(lat_rad2));
  58.  
  59. SET sin_reduced1 := sin(reduced_lat1);
  60. SET cos_reduced1 := cos(reduced_lat1);
  61. SET sin_reduced2 := sin(reduced_lat2);
  62. SET cos_reduced2 := cos(reduced_lat2);
  63.  
  64. SET lambda_lng := delta_lng;
  65. SET lambda_prime := 2 * pi();
  66.  
  67. SET iter_limit = 20;
  68.  
  69. WHILE abs(lambda_lng - lambda_prime) > pow(10, -11) AND iter_limit > 0 DO
  70. SET sin_lambda_lng := sin(lambda_lng);
  71. SET cos_lambda_lng := cos(lambda_lng);
  72.  
  73. SET sin_sigma := sqrt(pow((cos_reduced2 * sin_lambda_lng), 2) +
  74. pow((cos_reduced1 * sin_reduced2 - sin_reduced1 *
  75. cos_reduced2 * cos_lambda_lng), 2));
  76.  
  77. IF sin_sigma = 0 THEN
  78. RETURN 0;
  79. END IF;
  80.  
  81. SET cos_sigma := (sin_reduced1 * sin_reduced2 +
  82. cos_reduced1 * cos_reduced2 * cos_lambda_lng);
  83.  
  84. SET sigma := atan2(sin_sigma, cos_sigma);
  85.  
  86. SET sin_alpha := cos_reduced1 * cos_reduced2 * sin_lambda_lng / sin_sigma;
  87. SET cos_sq_alpha := 1 - pow(sin_alpha, 2);
  88.  
  89. IF cos_sq_alpha != 0 THEN
  90. SET cos2_sigma_m := cos_sigma - 2 * (sin_reduced1 * sin_reduced2 /
  91. cos_sq_alpha);
  92. ELSE
  93. SET cos2_sigma_m := 0.0;
  94. END IF;
  95.  
  96. SET C := wgs84_flattening / 16.0 * cos_sq_alpha * (4 + wgs84_flattening * (4 - 3 * cos_sq_alpha));
  97.  
  98. SET lambda_prime := lambda_lng;
  99. SET lambda_lng := (delta_lng + (1 - C) * wgs84_flattening * sin_alpha *
  100. (sigma + C * sin_sigma *
  101. (cos2_sigma_m + C * cos_sigma *
  102. (-1 + 2 * pow(cos2_sigma_m, 2)))));
  103. SET iter_limit := iter_limit - 1;
  104. END WHILE;
  105.  
  106. IF iter_limit = 0 THEN
  107. RETURN NULL;
  108. END IF;
  109.  
  110. SET u_sq := cos_sq_alpha * (pow(wgs84_major, 2) - pow(wgs84_minor, 2)) / pow(wgs84_minor, 2);
  111.  
  112. SET A := 1 + u_sq / 16384.0 * (4096 + u_sq * (-768 + u_sq *
  113. (320 - 175 * u_sq)));
  114.  
  115. SET B := u_sq / 1024.0 * (256 + u_sq * (-128 + u_sq * (74 - 47 * u_sq)));
  116.  
  117. SET delta_sigma := (B * sin_sigma *
  118. (cos2_sigma_m + B / 4. *
  119. (cos_sigma * (-1 + 2 * pow(cos2_sigma_m, 2)) -
  120. B / 6. * cos2_sigma_m * (-3 + 4 * pow(sin_sigma, 2)) *
  121. (-3 + 4 * pow(cos2_sigma_m, 2)))));
  122.  
  123. SET gcdx := wgs84_minor * A * (sigma - delta_sigma);
  124.  
  125. IF metric = 'km' THEN
  126. RETURN gcdx;
  127. ELSEIF metric = 'mi' THEN
  128. RETURN gcdx * 0.621371192;
  129. ELSEIF metric = 'nm' THEN
  130. RETURN gcdx / 1.852;
  131. ELSE
  132. RETURN gcdx;
  133. END IF;
  134. END;;
  135.  
  136. DELIMITER ;

Current Tags

You must be logged in to tag this tool

No Comments yet

Votes

Not yet rated.
You must be logged in to vote.

Watches

0 members are watching this tool
You must be logged in to track this tool.

Provide Feedback

Please note:
HTML will be purified, but we allow for a number of HTML tags so that you have the flexibility to decorate your comment text to some extent. The comments allow the following HTML tags:

strong, b, em, blockquote, a, code, pre

To put code into your comment, simply encapsulate your code with
[code language="XXX"][/code], where XXX is any common language, for instance "PHP", "SQL", "C", etc.



You must be logged in to comment