index.js 3.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. import bearing from "@turf/bearing";
  2. import distance from "@turf/distance";
  3. import destination from "@turf/destination";
  4. import lineIntersects from "@turf/line-intersect";
  5. import { flattenEach } from "@turf/meta";
  6. import { point, lineString, } from "@turf/helpers";
  7. import { getCoords } from "@turf/invariant";
  8. /**
  9. * Takes a {@link Point} and a {@link LineString} and calculates the closest Point on the (Multi)LineString.
  10. *
  11. * @name nearestPointOnLine
  12. * @param {Geometry|Feature<LineString|MultiLineString>} lines lines to snap to
  13. * @param {Geometry|Feature<Point>|number[]} pt point to snap from
  14. * @param {Object} [options={}] Optional parameters
  15. * @param {string} [options.units='kilometers'] can be degrees, radians, miles, or kilometers
  16. * @returns {Feature<Point>} closest point on the `line` to `point`. The properties object will contain three values: `index`: closest point was found on nth line part, `dist`: distance between pt and the closest point, `location`: distance along the line between start and the closest point.
  17. * @example
  18. * var line = turf.lineString([
  19. * [-77.031669, 38.878605],
  20. * [-77.029609, 38.881946],
  21. * [-77.020339, 38.884084],
  22. * [-77.025661, 38.885821],
  23. * [-77.021884, 38.889563],
  24. * [-77.019824, 38.892368]
  25. * ]);
  26. * var pt = turf.point([-77.037076, 38.884017]);
  27. *
  28. * var snapped = turf.nearestPointOnLine(line, pt, {units: 'miles'});
  29. *
  30. * //addToMap
  31. * var addToMap = [line, pt, snapped];
  32. * snapped.properties['marker-color'] = '#00f';
  33. */
  34. function nearestPointOnLine(lines, pt, options) {
  35. if (options === void 0) { options = {}; }
  36. var closestPt = point([Infinity, Infinity], {
  37. dist: Infinity,
  38. });
  39. var length = 0.0;
  40. flattenEach(lines, function (line) {
  41. var coords = getCoords(line);
  42. for (var i = 0; i < coords.length - 1; i++) {
  43. //start
  44. var start = point(coords[i]);
  45. start.properties.dist = distance(pt, start, options);
  46. //stop
  47. var stop_1 = point(coords[i + 1]);
  48. stop_1.properties.dist = distance(pt, stop_1, options);
  49. // sectionLength
  50. var sectionLength = distance(start, stop_1, options);
  51. //perpendicular
  52. var heightDistance = Math.max(start.properties.dist, stop_1.properties.dist);
  53. var direction = bearing(start, stop_1);
  54. var perpendicularPt1 = destination(pt, heightDistance, direction + 90, options);
  55. var perpendicularPt2 = destination(pt, heightDistance, direction - 90, options);
  56. var intersect = lineIntersects(lineString([
  57. perpendicularPt1.geometry.coordinates,
  58. perpendicularPt2.geometry.coordinates,
  59. ]), lineString([start.geometry.coordinates, stop_1.geometry.coordinates]));
  60. var intersectPt = null;
  61. if (intersect.features.length > 0) {
  62. intersectPt = intersect.features[0];
  63. intersectPt.properties.dist = distance(pt, intersectPt, options);
  64. intersectPt.properties.location =
  65. length + distance(start, intersectPt, options);
  66. }
  67. if (start.properties.dist < closestPt.properties.dist) {
  68. closestPt = start;
  69. closestPt.properties.index = i;
  70. closestPt.properties.location = length;
  71. }
  72. if (stop_1.properties.dist < closestPt.properties.dist) {
  73. closestPt = stop_1;
  74. closestPt.properties.index = i + 1;
  75. closestPt.properties.location = length + sectionLength;
  76. }
  77. if (intersectPt &&
  78. intersectPt.properties.dist < closestPt.properties.dist) {
  79. closestPt = intersectPt;
  80. closestPt.properties.index = i;
  81. }
  82. // update length
  83. length += sectionLength;
  84. }
  85. });
  86. return closestPt;
  87. }
  88. export default nearestPointOnLine;