index.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. // https://en.wikipedia.org/wiki/Rhumb_line
  2. import { convertLength, earthRadius } from "@turf/helpers";
  3. import { getCoord } from "@turf/invariant";
  4. /**
  5. * Calculates the distance along a rhumb line between two {@link Point|points} in degrees, radians,
  6. * miles, or kilometers.
  7. *
  8. * @name rhumbDistance
  9. * @param {Coord} from origin point
  10. * @param {Coord} to destination point
  11. * @param {Object} [options] Optional parameters
  12. * @param {string} [options.units="kilometers"] can be degrees, radians, miles, or kilometers
  13. * @returns {number} distance between the two points
  14. * @example
  15. * var from = turf.point([-75.343, 39.984]);
  16. * var to = turf.point([-75.534, 39.123]);
  17. * var options = {units: 'miles'};
  18. *
  19. * var distance = turf.rhumbDistance(from, to, options);
  20. *
  21. * //addToMap
  22. * var addToMap = [from, to];
  23. * from.properties.distance = distance;
  24. * to.properties.distance = distance;
  25. */
  26. function rhumbDistance(from, to, options) {
  27. if (options === void 0) { options = {}; }
  28. var origin = getCoord(from);
  29. var destination = getCoord(to);
  30. // compensate the crossing of the 180th meridian (https://macwright.org/2016/09/26/the-180th-meridian.html)
  31. // solution from https://github.com/mapbox/mapbox-gl-js/issues/3250#issuecomment-294887678
  32. destination[0] +=
  33. destination[0] - origin[0] > 180
  34. ? -360
  35. : origin[0] - destination[0] > 180
  36. ? 360
  37. : 0;
  38. var distanceInMeters = calculateRhumbDistance(origin, destination);
  39. var distance = convertLength(distanceInMeters, "meters", options.units);
  40. return distance;
  41. }
  42. /**
  43. * Returns the distance travelling from ‘this’ point to destination point along a rhumb line.
  44. * Adapted from Geodesy: https://github.com/chrisveness/geodesy/blob/master/latlon-spherical.js
  45. *
  46. * @private
  47. * @param {Array<number>} origin point.
  48. * @param {Array<number>} destination point.
  49. * @param {number} [radius=6371e3] - (Mean) radius of earth (defaults to radius in metres).
  50. * @returns {number} Distance in km between this point and destination point (same units as radius).
  51. *
  52. * @example
  53. * var p1 = new LatLon(51.127, 1.338);
  54. * var p2 = new LatLon(50.964, 1.853);
  55. * var d = p1.distanceTo(p2); // 40.31 km
  56. */
  57. function calculateRhumbDistance(origin, destination, radius) {
  58. // φ => phi
  59. // λ => lambda
  60. // ψ => psi
  61. // Δ => Delta
  62. // δ => delta
  63. // θ => theta
  64. radius = radius === undefined ? earthRadius : Number(radius);
  65. // see www.edwilliams.org/avform.htm#Rhumb
  66. var R = radius;
  67. var phi1 = (origin[1] * Math.PI) / 180;
  68. var phi2 = (destination[1] * Math.PI) / 180;
  69. var DeltaPhi = phi2 - phi1;
  70. var DeltaLambda = (Math.abs(destination[0] - origin[0]) * Math.PI) / 180;
  71. // if dLon over 180° take shorter rhumb line across the anti-meridian:
  72. if (DeltaLambda > Math.PI) {
  73. DeltaLambda -= 2 * Math.PI;
  74. }
  75. // on Mercator projection, longitude distances shrink by latitude; q is the 'stretch factor'
  76. // q becomes ill-conditioned along E-W line (0/0); use empirical tolerance to avoid it
  77. var DeltaPsi = Math.log(Math.tan(phi2 / 2 + Math.PI / 4) / Math.tan(phi1 / 2 + Math.PI / 4));
  78. var q = Math.abs(DeltaPsi) > 10e-12 ? DeltaPhi / DeltaPsi : Math.cos(phi1);
  79. // distance is pythagoras on 'stretched' Mercator projection
  80. var delta = Math.sqrt(DeltaPhi * DeltaPhi + q * q * DeltaLambda * DeltaLambda); // angular distance in radians
  81. var dist = delta * R;
  82. return dist;
  83. }
  84. export default rhumbDistance;