index.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. // Taken from http://geomalgorithms.com/a02-_lines.html
  2. import getDistance from "@turf/distance";
  3. import { convertLength, feature, lineString, point, } from "@turf/helpers";
  4. import { featureOf } from "@turf/invariant";
  5. import { segmentEach } from "@turf/meta";
  6. import getPlanarDistance from "@turf/rhumb-distance";
  7. /**
  8. * Returns the minimum distance between a {@link Point} and a {@link LineString}, being the distance from a line the
  9. * minimum distance between the point and any segment of the `LineString`.
  10. *
  11. * @name pointToLineDistance
  12. * @param {Feature<Point>|Array<number>} pt Feature or Geometry
  13. * @param {Feature<LineString>} line GeoJSON Feature or Geometry
  14. * @param {Object} [options={}] Optional parameters
  15. * @param {string} [options.units="kilometers"] can be anything supported by turf/convertLength
  16. * (ex: degrees, radians, miles, or kilometers)
  17. * @param {string} [options.method="geodesic"] wether to calculate the distance based on geodesic (spheroid) or
  18. * planar (flat) method. Valid options are 'geodesic' or 'planar'.
  19. * @returns {number} distance between point and line
  20. * @example
  21. * var pt = turf.point([0, 0]);
  22. * var line = turf.lineString([[1, 1],[-1, 1]]);
  23. *
  24. * var distance = turf.pointToLineDistance(pt, line, {units: 'miles'});
  25. * //=69.11854715938406
  26. */
  27. function pointToLineDistance(pt, line, options) {
  28. if (options === void 0) { options = {}; }
  29. // Optional parameters
  30. if (!options.method) {
  31. options.method = "geodesic";
  32. }
  33. if (!options.units) {
  34. options.units = "kilometers";
  35. }
  36. // validation
  37. if (!pt) {
  38. throw new Error("pt is required");
  39. }
  40. if (Array.isArray(pt)) {
  41. pt = point(pt);
  42. }
  43. else if (pt.type === "Point") {
  44. pt = feature(pt);
  45. }
  46. else {
  47. featureOf(pt, "Point", "point");
  48. }
  49. if (!line) {
  50. throw new Error("line is required");
  51. }
  52. if (Array.isArray(line)) {
  53. line = lineString(line);
  54. }
  55. else if (line.type === "LineString") {
  56. line = feature(line);
  57. }
  58. else {
  59. featureOf(line, "LineString", "line");
  60. }
  61. var distance = Infinity;
  62. var p = pt.geometry.coordinates;
  63. segmentEach(line, function (segment) {
  64. var a = segment.geometry.coordinates[0];
  65. var b = segment.geometry.coordinates[1];
  66. var d = distanceToSegment(p, a, b, options);
  67. if (d < distance) {
  68. distance = d;
  69. }
  70. });
  71. return convertLength(distance, "degrees", options.units);
  72. }
  73. /**
  74. * Returns the distance between a point P on a segment AB.
  75. *
  76. * @private
  77. * @param {Array<number>} p external point
  78. * @param {Array<number>} a first segment point
  79. * @param {Array<number>} b second segment point
  80. * @param {Object} [options={}] Optional parameters
  81. * @returns {number} distance
  82. */
  83. function distanceToSegment(p, a, b, options) {
  84. var v = [b[0] - a[0], b[1] - a[1]];
  85. var w = [p[0] - a[0], p[1] - a[1]];
  86. var c1 = dot(w, v);
  87. if (c1 <= 0) {
  88. return calcDistance(p, a, { method: options.method, units: "degrees" });
  89. }
  90. var c2 = dot(v, v);
  91. if (c2 <= c1) {
  92. return calcDistance(p, b, { method: options.method, units: "degrees" });
  93. }
  94. var b2 = c1 / c2;
  95. var Pb = [a[0] + b2 * v[0], a[1] + b2 * v[1]];
  96. return calcDistance(p, Pb, { method: options.method, units: "degrees" });
  97. }
  98. function dot(u, v) {
  99. return u[0] * v[0] + u[1] * v[1];
  100. }
  101. function calcDistance(a, b, options) {
  102. return options.method === "planar"
  103. ? getPlanarDistance(a, b, options)
  104. : getDistance(a, b, options);
  105. }
  106. export default pointToLineDistance;