index.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. import bearing from '@turf/bearing';
  2. import distance from '@turf/distance';
  3. import destination from '@turf/destination';
  4. import { isObject, lineString } from '@turf/helpers';
  5. /**
  6. * Takes a {@link LineString|line}, a specified distance along the line to a start {@link Point},
  7. * and a specified distance along the line to a stop point
  8. * and returns a subsection of the line in-between those points.
  9. *
  10. * This can be useful for extracting only the part of a route between two distances.
  11. *
  12. * @name lineSliceAlong
  13. * @param {Feature<LineString>|LineString} line input line
  14. * @param {number} startDist distance along the line to starting point
  15. * @param {number} stopDist distance along the line to ending point
  16. * @param {Object} [options={}] Optional parameters
  17. * @param {string} [options.units='kilometers'] can be degrees, radians, miles, or kilometers
  18. * @returns {Feature<LineString>} sliced line
  19. * @example
  20. * var line = turf.lineString([[7, 45], [9, 45], [14, 40], [14, 41]]);
  21. * var start = 12.5;
  22. * var stop = 25;
  23. * var sliced = turf.lineSliceAlong(line, start, stop, {units: 'miles'});
  24. *
  25. * //addToMap
  26. * var addToMap = [line, start, stop, sliced]
  27. */
  28. function lineSliceAlong(line, startDist, stopDist, options) {
  29. // Optional parameters
  30. options = options || {};
  31. if (!isObject(options)) throw new Error("options is invalid");
  32. var coords;
  33. var slice = [];
  34. // Validation
  35. if (line.type === "Feature") coords = line.geometry.coordinates;
  36. else if (line.type === "LineString") coords = line.coordinates;
  37. else throw new Error("input must be a LineString Feature or Geometry");
  38. var origCoordsLength = coords.length;
  39. var travelled = 0;
  40. var overshot, direction, interpolated;
  41. for (var i = 0; i < coords.length; i++) {
  42. if (startDist >= travelled && i === coords.length - 1) break;
  43. else if (travelled > startDist && slice.length === 0) {
  44. overshot = startDist - travelled;
  45. if (!overshot) {
  46. slice.push(coords[i]);
  47. return lineString(slice);
  48. }
  49. direction = bearing(coords[i], coords[i - 1]) - 180;
  50. interpolated = destination(coords[i], overshot, direction, options);
  51. slice.push(interpolated.geometry.coordinates);
  52. }
  53. if (travelled >= stopDist) {
  54. overshot = stopDist - travelled;
  55. if (!overshot) {
  56. slice.push(coords[i]);
  57. return lineString(slice);
  58. }
  59. direction = bearing(coords[i], coords[i - 1]) - 180;
  60. interpolated = destination(coords[i], overshot, direction, options);
  61. slice.push(interpolated.geometry.coordinates);
  62. return lineString(slice);
  63. }
  64. if (travelled >= startDist) {
  65. slice.push(coords[i]);
  66. }
  67. if (i === coords.length - 1) {
  68. return lineString(slice);
  69. }
  70. travelled += distance(coords[i], coords[i + 1], options);
  71. }
  72. if (travelled < startDist && coords.length === origCoordsLength)
  73. throw new Error("Start position is beyond line");
  74. var last = coords[coords.length - 1];
  75. return lineString([last, last]);
  76. }
  77. export default lineSliceAlong;