index.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. var helpers_1 = require("@turf/helpers");
  4. /**
  5. * Takes a {@link LineString|linestring}, {@link MultiLineString|multi-linestring},
  6. * {@link MultiPolygon|multi-polygon} or {@link Polygon|polygon} and
  7. * returns {@link Point|points} at all self-intersections.
  8. *
  9. * @name kinks
  10. * @param {Feature<LineString|MultiLineString|MultiPolygon|Polygon>} featureIn input feature
  11. * @returns {FeatureCollection<Point>} self-intersections
  12. * @example
  13. * var poly = turf.polygon([[
  14. * [-12.034835, 8.901183],
  15. * [-12.060413, 8.899826],
  16. * [-12.03638, 8.873199],
  17. * [-12.059383, 8.871418],
  18. * [-12.034835, 8.901183]
  19. * ]]);
  20. *
  21. * var kinks = turf.kinks(poly);
  22. *
  23. * //addToMap
  24. * var addToMap = [poly, kinks]
  25. */
  26. function kinks(featureIn) {
  27. var coordinates;
  28. var feature;
  29. var results = {
  30. type: "FeatureCollection",
  31. features: [],
  32. };
  33. if (featureIn.type === "Feature") {
  34. feature = featureIn.geometry;
  35. }
  36. else {
  37. feature = featureIn;
  38. }
  39. if (feature.type === "LineString") {
  40. coordinates = [feature.coordinates];
  41. }
  42. else if (feature.type === "MultiLineString") {
  43. coordinates = feature.coordinates;
  44. }
  45. else if (feature.type === "MultiPolygon") {
  46. coordinates = [].concat.apply([], feature.coordinates);
  47. }
  48. else if (feature.type === "Polygon") {
  49. coordinates = feature.coordinates;
  50. }
  51. else {
  52. throw new Error("Input must be a LineString, MultiLineString, " +
  53. "Polygon, or MultiPolygon Feature or Geometry");
  54. }
  55. coordinates.forEach(function (line1) {
  56. coordinates.forEach(function (line2) {
  57. for (var i = 0; i < line1.length - 1; i++) {
  58. // start iteration at i, intersections for k < i have already
  59. // been checked in previous outer loop iterations
  60. for (var k = i; k < line2.length - 1; k++) {
  61. if (line1 === line2) {
  62. // segments are adjacent and always share a vertex, not a kink
  63. if (Math.abs(i - k) === 1) {
  64. continue;
  65. }
  66. // first and last segment in a closed lineString or ring always share a vertex, not a kink
  67. if (
  68. // segments are first and last segment of lineString
  69. i === 0 &&
  70. k === line1.length - 2 &&
  71. // lineString is closed
  72. line1[i][0] === line1[line1.length - 1][0] &&
  73. line1[i][1] === line1[line1.length - 1][1]) {
  74. continue;
  75. }
  76. }
  77. var intersection = lineIntersects(line1[i][0], line1[i][1], line1[i + 1][0], line1[i + 1][1], line2[k][0], line2[k][1], line2[k + 1][0], line2[k + 1][1]);
  78. if (intersection) {
  79. results.features.push(helpers_1.point([intersection[0], intersection[1]]));
  80. }
  81. }
  82. }
  83. });
  84. });
  85. return results;
  86. }
  87. exports.default = kinks;
  88. // modified from http://jsfiddle.net/justin_c_rounds/Gd2S2/light/
  89. function lineIntersects(line1StartX, line1StartY, line1EndX, line1EndY, line2StartX, line2StartY, line2EndX, line2EndY) {
  90. // if the lines intersect, the result contains the x and y of the
  91. // intersection (treating the lines as infinite) and booleans for whether
  92. // line segment 1 or line segment 2 contain the point
  93. var denominator;
  94. var a;
  95. var b;
  96. var numerator1;
  97. var numerator2;
  98. var result = {
  99. x: null,
  100. y: null,
  101. onLine1: false,
  102. onLine2: false,
  103. };
  104. denominator =
  105. (line2EndY - line2StartY) * (line1EndX - line1StartX) -
  106. (line2EndX - line2StartX) * (line1EndY - line1StartY);
  107. if (denominator === 0) {
  108. if (result.x !== null && result.y !== null) {
  109. return result;
  110. }
  111. else {
  112. return false;
  113. }
  114. }
  115. a = line1StartY - line2StartY;
  116. b = line1StartX - line2StartX;
  117. numerator1 = (line2EndX - line2StartX) * a - (line2EndY - line2StartY) * b;
  118. numerator2 = (line1EndX - line1StartX) * a - (line1EndY - line1StartY) * b;
  119. a = numerator1 / denominator;
  120. b = numerator2 / denominator;
  121. // if we cast these lines infinitely in both directions, they intersect here:
  122. result.x = line1StartX + a * (line1EndX - line1StartX);
  123. result.y = line1StartY + a * (line1EndY - line1StartY);
  124. // if line1 is a segment and line2 is infinite, they intersect if:
  125. if (a >= 0 && a <= 1) {
  126. result.onLine1 = true;
  127. }
  128. // if line2 is a segment and line1 is infinite, they intersect if:
  129. if (b >= 0 && b <= 1) {
  130. result.onLine2 = true;
  131. }
  132. // if line1 and line2 are segments, they intersect if both of the above are true
  133. if (result.onLine1 && result.onLine2) {
  134. return [result.x, result.y];
  135. }
  136. else {
  137. return false;
  138. }
  139. }