is-polygons-intersect.ts 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. import isPointInPolygon from './point-in-polygon';
  2. import getLineIntersect from './get-line-intersect';
  3. import { each } from 'lodash-es';
  4. function parseToLines(points) {
  5. const lines = [];
  6. const count = points.length;
  7. for (let i = 0; i < count - 1; i++) {
  8. const point = points[i];
  9. const next = points[i + 1];
  10. lines.push({
  11. from: {
  12. x: point[0],
  13. y: point[1],
  14. },
  15. to: {
  16. x: next[0],
  17. y: next[1],
  18. },
  19. });
  20. }
  21. if (lines.length > 1) {
  22. const first = points[0];
  23. const last = points[count - 1];
  24. lines.push({
  25. from: {
  26. x: last[0],
  27. y: last[1],
  28. },
  29. to: {
  30. x: first[0],
  31. y: first[1],
  32. },
  33. });
  34. }
  35. return lines;
  36. }
  37. function lineIntersectPolygon(lines, line) {
  38. let isIntersect = false;
  39. each(lines, (l) => {
  40. if (getLineIntersect(l.from, l.to, line.from, line.to)) {
  41. isIntersect = true;
  42. return false;
  43. }
  44. });
  45. return isIntersect;
  46. }
  47. type BBox = {
  48. minX: number;
  49. minY: number;
  50. maxX: number;
  51. maxY: number;
  52. };
  53. function getBBox(points): BBox {
  54. const xArr = points.map((p) => p[0]);
  55. const yArr = points.map((p) => p[1]);
  56. return {
  57. minX: Math.min.apply(null, xArr),
  58. maxX: Math.max.apply(null, xArr),
  59. minY: Math.min.apply(null, yArr),
  60. maxY: Math.max.apply(null, yArr),
  61. };
  62. }
  63. function intersectBBox(box1: BBox, box2: BBox) {
  64. return !(box2.minX > box1.maxX || box2.maxX < box1.minX || box2.minY > box1.maxY || box2.maxY < box1.minY);
  65. }
  66. export default function isPolygonsIntersect(points1, points2) {
  67. // 空数组,或者一个点返回 false
  68. if (points1.length < 2 || points2.length < 2) {
  69. return false;
  70. }
  71. const bbox1 = getBBox(points1);
  72. const bbox2 = getBBox(points2);
  73. // 判定包围盒是否相交,比判定点是否在多边形内要快的多,可以筛选掉大多数情况
  74. if (!intersectBBox(bbox1, bbox2)) {
  75. return false;
  76. }
  77. let isIn = false;
  78. // 判定点是否在多边形内部,一旦有一个点在另一个多边形内,则返回
  79. each(points2, (point) => {
  80. if (isPointInPolygon(points1, point[0], point[1])) {
  81. isIn = true;
  82. return false;
  83. }
  84. });
  85. if (isIn) {
  86. return true;
  87. }
  88. // 两个多边形都需要判定
  89. each(points1, (point) => {
  90. if (isPointInPolygon(points2, point[0], point[1])) {
  91. isIn = true;
  92. return false;
  93. }
  94. });
  95. if (isIn) {
  96. return true;
  97. }
  98. const lines1 = parseToLines(points1);
  99. const lines2 = parseToLines(points2);
  100. let isIntersect = false;
  101. each(lines2, (line) => {
  102. if (lineIntersectPolygon(lines1, line)) {
  103. isIntersect = true;
  104. return false;
  105. }
  106. });
  107. return isIntersect;
  108. }