index.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. import { feature, featureCollection, point, } from "@turf/helpers";
  2. import { getCoords } from "@turf/invariant";
  3. import lineSegment from "@turf/line-segment";
  4. import { featureEach } from "@turf/meta";
  5. import rbush from "geojson-rbush";
  6. /**
  7. * Takes any LineString or Polygon GeoJSON and returns the intersecting point(s).
  8. *
  9. * @name lineIntersect
  10. * @param {GeoJSON} line1 any LineString or Polygon
  11. * @param {GeoJSON} line2 any LineString or Polygon
  12. * @returns {FeatureCollection<Point>} point(s) that intersect both
  13. * @example
  14. * var line1 = turf.lineString([[126, -11], [129, -21]]);
  15. * var line2 = turf.lineString([[123, -18], [131, -14]]);
  16. * var intersects = turf.lineIntersect(line1, line2);
  17. *
  18. * //addToMap
  19. * var addToMap = [line1, line2, intersects]
  20. */
  21. function lineIntersect(line1, line2) {
  22. var unique = {};
  23. var results = [];
  24. // First, normalize geometries to features
  25. // Then, handle simple 2-vertex segments
  26. if (line1.type === "LineString") {
  27. line1 = feature(line1);
  28. }
  29. if (line2.type === "LineString") {
  30. line2 = feature(line2);
  31. }
  32. if (line1.type === "Feature" &&
  33. line2.type === "Feature" &&
  34. line1.geometry !== null &&
  35. line2.geometry !== null &&
  36. line1.geometry.type === "LineString" &&
  37. line2.geometry.type === "LineString" &&
  38. line1.geometry.coordinates.length === 2 &&
  39. line2.geometry.coordinates.length === 2) {
  40. var intersect = intersects(line1, line2);
  41. if (intersect) {
  42. results.push(intersect);
  43. }
  44. return featureCollection(results);
  45. }
  46. // Handles complex GeoJSON Geometries
  47. var tree = rbush();
  48. tree.load(lineSegment(line2));
  49. featureEach(lineSegment(line1), function (segment) {
  50. featureEach(tree.search(segment), function (match) {
  51. var intersect = intersects(segment, match);
  52. if (intersect) {
  53. // prevent duplicate points https://github.com/Turfjs/turf/issues/688
  54. var key = getCoords(intersect).join(",");
  55. if (!unique[key]) {
  56. unique[key] = true;
  57. results.push(intersect);
  58. }
  59. }
  60. });
  61. });
  62. return featureCollection(results);
  63. }
  64. /**
  65. * Find a point that intersects LineStrings with two coordinates each
  66. *
  67. * @private
  68. * @param {Feature<LineString>} line1 GeoJSON LineString (Must only contain 2 coordinates)
  69. * @param {Feature<LineString>} line2 GeoJSON LineString (Must only contain 2 coordinates)
  70. * @returns {Feature<Point>} intersecting GeoJSON Point
  71. */
  72. function intersects(line1, line2) {
  73. var coords1 = getCoords(line1);
  74. var coords2 = getCoords(line2);
  75. if (coords1.length !== 2) {
  76. throw new Error("<intersects> line1 must only contain 2 coordinates");
  77. }
  78. if (coords2.length !== 2) {
  79. throw new Error("<intersects> line2 must only contain 2 coordinates");
  80. }
  81. var x1 = coords1[0][0];
  82. var y1 = coords1[0][1];
  83. var x2 = coords1[1][0];
  84. var y2 = coords1[1][1];
  85. var x3 = coords2[0][0];
  86. var y3 = coords2[0][1];
  87. var x4 = coords2[1][0];
  88. var y4 = coords2[1][1];
  89. var denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
  90. var numeA = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3);
  91. var numeB = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3);
  92. if (denom === 0) {
  93. if (numeA === 0 && numeB === 0) {
  94. return null;
  95. }
  96. return null;
  97. }
  98. var uA = numeA / denom;
  99. var uB = numeB / denom;
  100. if (uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1) {
  101. var x = x1 + uA * (x2 - x1);
  102. var y = y1 + uA * (y2 - y1);
  103. return point([x, y]);
  104. }
  105. return null;
  106. }
  107. export default lineIntersect;