index.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. import booleanPointInPolygon from "@turf/boolean-point-in-polygon";
  2. import lineIntersect from "@turf/line-intersect";
  3. import { flattenEach } from "@turf/meta";
  4. import polygonToLine from "@turf/polygon-to-line";
  5. /**
  6. * Boolean-disjoint returns (TRUE) if the intersection of the two geometries is an empty set.
  7. *
  8. * @name booleanDisjoint
  9. * @param {Geometry|Feature<any>} feature1 GeoJSON Feature or Geometry
  10. * @param {Geometry|Feature<any>} feature2 GeoJSON Feature or Geometry
  11. * @returns {boolean} true/false
  12. * @example
  13. * var point = turf.point([2, 2]);
  14. * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]);
  15. *
  16. * turf.booleanDisjoint(line, point);
  17. * //=true
  18. */
  19. function booleanDisjoint(feature1, feature2) {
  20. var bool = true;
  21. flattenEach(feature1, function (flatten1) {
  22. flattenEach(feature2, function (flatten2) {
  23. if (bool === false) {
  24. return false;
  25. }
  26. bool = disjoint(flatten1.geometry, flatten2.geometry);
  27. });
  28. });
  29. return bool;
  30. }
  31. /**
  32. * Disjoint operation for simple Geometries (Point/LineString/Polygon)
  33. *
  34. * @private
  35. * @param {Geometry<any>} geom1 GeoJSON Geometry
  36. * @param {Geometry<any>} geom2 GeoJSON Geometry
  37. * @returns {boolean} true/false
  38. */
  39. function disjoint(geom1, geom2) {
  40. switch (geom1.type) {
  41. case "Point":
  42. switch (geom2.type) {
  43. case "Point":
  44. return !compareCoords(geom1.coordinates, geom2.coordinates);
  45. case "LineString":
  46. return !isPointOnLine(geom2, geom1);
  47. case "Polygon":
  48. return !booleanPointInPolygon(geom1, geom2);
  49. }
  50. /* istanbul ignore next */
  51. break;
  52. case "LineString":
  53. switch (geom2.type) {
  54. case "Point":
  55. return !isPointOnLine(geom1, geom2);
  56. case "LineString":
  57. return !isLineOnLine(geom1, geom2);
  58. case "Polygon":
  59. return !isLineInPoly(geom2, geom1);
  60. }
  61. /* istanbul ignore next */
  62. break;
  63. case "Polygon":
  64. switch (geom2.type) {
  65. case "Point":
  66. return !booleanPointInPolygon(geom2, geom1);
  67. case "LineString":
  68. return !isLineInPoly(geom1, geom2);
  69. case "Polygon":
  70. return !isPolyInPoly(geom2, geom1);
  71. }
  72. }
  73. return false;
  74. }
  75. // http://stackoverflow.com/a/11908158/1979085
  76. function isPointOnLine(lineString, pt) {
  77. for (var i = 0; i < lineString.coordinates.length - 1; i++) {
  78. if (isPointOnLineSegment(lineString.coordinates[i], lineString.coordinates[i + 1], pt.coordinates)) {
  79. return true;
  80. }
  81. }
  82. return false;
  83. }
  84. function isLineOnLine(lineString1, lineString2) {
  85. var doLinesIntersect = lineIntersect(lineString1, lineString2);
  86. if (doLinesIntersect.features.length > 0) {
  87. return true;
  88. }
  89. return false;
  90. }
  91. function isLineInPoly(polygon, lineString) {
  92. for (var _i = 0, _a = lineString.coordinates; _i < _a.length; _i++) {
  93. var coord = _a[_i];
  94. if (booleanPointInPolygon(coord, polygon)) {
  95. return true;
  96. }
  97. }
  98. var doLinesIntersect = lineIntersect(lineString, polygonToLine(polygon));
  99. if (doLinesIntersect.features.length > 0) {
  100. return true;
  101. }
  102. return false;
  103. }
  104. /**
  105. * Is Polygon (geom1) in Polygon (geom2)
  106. * Only takes into account outer rings
  107. * See http://stackoverflow.com/a/4833823/1979085
  108. *
  109. * @private
  110. * @param {Geometry|Feature<Polygon>} feature1 Polygon1
  111. * @param {Geometry|Feature<Polygon>} feature2 Polygon2
  112. * @returns {boolean} true/false
  113. */
  114. function isPolyInPoly(feature1, feature2) {
  115. for (var _i = 0, _a = feature1.coordinates[0]; _i < _a.length; _i++) {
  116. var coord1 = _a[_i];
  117. if (booleanPointInPolygon(coord1, feature2)) {
  118. return true;
  119. }
  120. }
  121. for (var _b = 0, _c = feature2.coordinates[0]; _b < _c.length; _b++) {
  122. var coord2 = _c[_b];
  123. if (booleanPointInPolygon(coord2, feature1)) {
  124. return true;
  125. }
  126. }
  127. var doLinesIntersect = lineIntersect(polygonToLine(feature1), polygonToLine(feature2));
  128. if (doLinesIntersect.features.length > 0) {
  129. return true;
  130. }
  131. return false;
  132. }
  133. function isPointOnLineSegment(lineSegmentStart, lineSegmentEnd, pt) {
  134. var dxc = pt[0] - lineSegmentStart[0];
  135. var dyc = pt[1] - lineSegmentStart[1];
  136. var dxl = lineSegmentEnd[0] - lineSegmentStart[0];
  137. var dyl = lineSegmentEnd[1] - lineSegmentStart[1];
  138. var cross = dxc * dyl - dyc * dxl;
  139. if (cross !== 0) {
  140. return false;
  141. }
  142. if (Math.abs(dxl) >= Math.abs(dyl)) {
  143. if (dxl > 0) {
  144. return lineSegmentStart[0] <= pt[0] && pt[0] <= lineSegmentEnd[0];
  145. }
  146. else {
  147. return lineSegmentEnd[0] <= pt[0] && pt[0] <= lineSegmentStart[0];
  148. }
  149. }
  150. else if (dyl > 0) {
  151. return lineSegmentStart[1] <= pt[1] && pt[1] <= lineSegmentEnd[1];
  152. }
  153. else {
  154. return lineSegmentEnd[1] <= pt[1] && pt[1] <= lineSegmentStart[1];
  155. }
  156. }
  157. /**
  158. * compareCoords
  159. *
  160. * @private
  161. * @param {Position} pair1 point [x,y]
  162. * @param {Position} pair2 point [x,y]
  163. * @returns {boolean} true/false if coord pairs match
  164. */
  165. function compareCoords(pair1, pair2) {
  166. return pair1[0] === pair2[0] && pair1[1] === pair2[1];
  167. }
  168. export default booleanDisjoint;