index.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. import calcBbox from "@turf/bbox";
  2. import booleanPointInPolygon from "@turf/boolean-point-in-polygon";
  3. import isPointOnLine from "@turf/boolean-point-on-line";
  4. import { getGeom } from "@turf/invariant";
  5. /**
  6. * Boolean-contains returns True if the second geometry is completely contained by the first geometry.
  7. * The interiors of both geometries must intersect and, the interior and boundary of the secondary (geometry b)
  8. * must not intersect the exterior of the primary (geometry a).
  9. * Boolean-contains returns the exact opposite result of the `@turf/boolean-within`.
  10. *
  11. * @name booleanContains
  12. * @param {Geometry|Feature<any>} feature1 GeoJSON Feature or Geometry
  13. * @param {Geometry|Feature<any>} feature2 GeoJSON Feature or Geometry
  14. * @returns {boolean} true/false
  15. * @example
  16. * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]);
  17. * var point = turf.point([1, 2]);
  18. *
  19. * turf.booleanContains(line, point);
  20. * //=true
  21. */
  22. export default function booleanContains(feature1, feature2) {
  23. var geom1 = getGeom(feature1);
  24. var geom2 = getGeom(feature2);
  25. var type1 = geom1.type;
  26. var type2 = geom2.type;
  27. var coords1 = geom1.coordinates;
  28. var coords2 = geom2.coordinates;
  29. switch (type1) {
  30. case "Point":
  31. switch (type2) {
  32. case "Point":
  33. return compareCoords(coords1, coords2);
  34. default:
  35. throw new Error("feature2 " + type2 + " geometry not supported");
  36. }
  37. case "MultiPoint":
  38. switch (type2) {
  39. case "Point":
  40. return isPointInMultiPoint(geom1, geom2);
  41. case "MultiPoint":
  42. return isMultiPointInMultiPoint(geom1, geom2);
  43. default:
  44. throw new Error("feature2 " + type2 + " geometry not supported");
  45. }
  46. case "LineString":
  47. switch (type2) {
  48. case "Point":
  49. return isPointOnLine(geom2, geom1, { ignoreEndVertices: true });
  50. case "LineString":
  51. return isLineOnLine(geom1, geom2);
  52. case "MultiPoint":
  53. return isMultiPointOnLine(geom1, geom2);
  54. default:
  55. throw new Error("feature2 " + type2 + " geometry not supported");
  56. }
  57. case "Polygon":
  58. switch (type2) {
  59. case "Point":
  60. return booleanPointInPolygon(geom2, geom1, { ignoreBoundary: true });
  61. case "LineString":
  62. return isLineInPoly(geom1, geom2);
  63. case "Polygon":
  64. return isPolyInPoly(geom1, geom2);
  65. case "MultiPoint":
  66. return isMultiPointInPoly(geom1, geom2);
  67. default:
  68. throw new Error("feature2 " + type2 + " geometry not supported");
  69. }
  70. default:
  71. throw new Error("feature1 " + type1 + " geometry not supported");
  72. }
  73. }
  74. export function isPointInMultiPoint(multiPoint, pt) {
  75. var i;
  76. var output = false;
  77. for (i = 0; i < multiPoint.coordinates.length; i++) {
  78. if (compareCoords(multiPoint.coordinates[i], pt.coordinates)) {
  79. output = true;
  80. break;
  81. }
  82. }
  83. return output;
  84. }
  85. export function isMultiPointInMultiPoint(multiPoint1, multiPoint2) {
  86. for (var _i = 0, _a = multiPoint2.coordinates; _i < _a.length; _i++) {
  87. var coord2 = _a[_i];
  88. var matchFound = false;
  89. for (var _b = 0, _c = multiPoint1.coordinates; _b < _c.length; _b++) {
  90. var coord1 = _c[_b];
  91. if (compareCoords(coord2, coord1)) {
  92. matchFound = true;
  93. break;
  94. }
  95. }
  96. if (!matchFound) {
  97. return false;
  98. }
  99. }
  100. return true;
  101. }
  102. export function isMultiPointOnLine(lineString, multiPoint) {
  103. var haveFoundInteriorPoint = false;
  104. for (var _i = 0, _a = multiPoint.coordinates; _i < _a.length; _i++) {
  105. var coord = _a[_i];
  106. if (isPointOnLine(coord, lineString, { ignoreEndVertices: true })) {
  107. haveFoundInteriorPoint = true;
  108. }
  109. if (!isPointOnLine(coord, lineString)) {
  110. return false;
  111. }
  112. }
  113. if (haveFoundInteriorPoint) {
  114. return true;
  115. }
  116. return false;
  117. }
  118. export function isMultiPointInPoly(polygon, multiPoint) {
  119. for (var _i = 0, _a = multiPoint.coordinates; _i < _a.length; _i++) {
  120. var coord = _a[_i];
  121. if (!booleanPointInPolygon(coord, polygon, { ignoreBoundary: true })) {
  122. return false;
  123. }
  124. }
  125. return true;
  126. }
  127. export function isLineOnLine(lineString1, lineString2) {
  128. var haveFoundInteriorPoint = false;
  129. for (var _i = 0, _a = lineString2.coordinates; _i < _a.length; _i++) {
  130. var coords = _a[_i];
  131. if (isPointOnLine({ type: "Point", coordinates: coords }, lineString1, {
  132. ignoreEndVertices: true,
  133. })) {
  134. haveFoundInteriorPoint = true;
  135. }
  136. if (!isPointOnLine({ type: "Point", coordinates: coords }, lineString1, {
  137. ignoreEndVertices: false,
  138. })) {
  139. return false;
  140. }
  141. }
  142. return haveFoundInteriorPoint;
  143. }
  144. export function isLineInPoly(polygon, linestring) {
  145. var output = false;
  146. var i = 0;
  147. var polyBbox = calcBbox(polygon);
  148. var lineBbox = calcBbox(linestring);
  149. if (!doBBoxOverlap(polyBbox, lineBbox)) {
  150. return false;
  151. }
  152. for (i; i < linestring.coordinates.length - 1; i++) {
  153. var midPoint = getMidpoint(linestring.coordinates[i], linestring.coordinates[i + 1]);
  154. if (booleanPointInPolygon({ type: "Point", coordinates: midPoint }, polygon, {
  155. ignoreBoundary: true,
  156. })) {
  157. output = true;
  158. break;
  159. }
  160. }
  161. return output;
  162. }
  163. /**
  164. * Is Polygon2 in Polygon1
  165. * Only takes into account outer rings
  166. *
  167. * @private
  168. * @param {Geometry|Feature<Polygon>} feature1 Polygon1
  169. * @param {Geometry|Feature<Polygon>} feature2 Polygon2
  170. * @returns {boolean} true/false
  171. */
  172. export function isPolyInPoly(feature1, feature2) {
  173. // Handle Nulls
  174. if (feature1.type === "Feature" && feature1.geometry === null) {
  175. return false;
  176. }
  177. if (feature2.type === "Feature" && feature2.geometry === null) {
  178. return false;
  179. }
  180. var poly1Bbox = calcBbox(feature1);
  181. var poly2Bbox = calcBbox(feature2);
  182. if (!doBBoxOverlap(poly1Bbox, poly2Bbox)) {
  183. return false;
  184. }
  185. var coords = getGeom(feature2).coordinates;
  186. for (var _i = 0, coords_1 = coords; _i < coords_1.length; _i++) {
  187. var ring = coords_1[_i];
  188. for (var _a = 0, ring_1 = ring; _a < ring_1.length; _a++) {
  189. var coord = ring_1[_a];
  190. if (!booleanPointInPolygon(coord, feature1)) {
  191. return false;
  192. }
  193. }
  194. }
  195. return true;
  196. }
  197. export function doBBoxOverlap(bbox1, bbox2) {
  198. if (bbox1[0] > bbox2[0]) {
  199. return false;
  200. }
  201. if (bbox1[2] < bbox2[2]) {
  202. return false;
  203. }
  204. if (bbox1[1] > bbox2[1]) {
  205. return false;
  206. }
  207. if (bbox1[3] < bbox2[3]) {
  208. return false;
  209. }
  210. return true;
  211. }
  212. /**
  213. * compareCoords
  214. *
  215. * @private
  216. * @param {Position} pair1 point [x,y]
  217. * @param {Position} pair2 point [x,y]
  218. * @returns {boolean} true/false if coord pairs match
  219. */
  220. export function compareCoords(pair1, pair2) {
  221. return pair1[0] === pair2[0] && pair1[1] === pair2[1];
  222. }
  223. export function getMidpoint(pair1, pair2) {
  224. return [(pair1[0] + pair2[0]) / 2, (pair1[1] + pair2[1]) / 2];
  225. }