Hình chữ nhật nhanh đến giao điểm hình chữ nhật


81

Cách nhanh để kiểm tra xem 2 hình chữ nhật có giao nhau không?


Một tìm kiếm trên internet đã tìm ra một chữ cái này (WOOT!), Nhưng tôi không hiểu cách viết nó bằng Javascript, nó có vẻ được viết bằng một dạng C ++ cổ.

struct
{
    LONG    left;
    LONG    top;
    LONG    right;
    LONG    bottom;
} RECT; 

bool IntersectRect(const RECT * r1, const RECT * r2)
{
    return ! ( r2->left > r1->right
        || r2->right < r1->left
        || r2->top > r1->bottom
        || r2->bottom < r1->top
        );
}

5
Tôi nghĩ rằng bạn đã mắc lỗi đánh máy trong bản sao / dán của mình
fmark

5
Bài báo gốc có lỗi đánh máy. r2->right leftkhông có ý nghĩa. Nó có thể bị hỏng do sự cố thoát HTML.
Marcelo Cantos

42
Tôi tò mò muốn biết bạn nghĩ đoạn mã trên sẽ khác như thế nào ở dạng C ++ "hiện đại".
jamesdlin

3
Tôi chắc chắn rằng các ký tự bị thiếu là <ký hiệu do thoát html.
devos1

1
@jamesdlin bạn sẽ đặt hàm làm hàm thành viên của cấu trúc, nhận một tham số. Thứ hai, bạn thường sử dụng const & thay vì const *. Bạn có thể sử dụng các mẫu để có cả phiên bản int, long và double, thay vì sử dụng một số macro Win32 ... (Nó cũng không biên dịch, vì RECT kết thúc là một thể hiện của cấu trúc không tên, không phải tên kiểu.) : ideone.com/bnzwl3
Sebastian Wahl

Câu trả lời:


142

Đây là cách mã đó có thể được dịch sang JavaScript. Lưu ý rằng có một lỗi đánh máy trong mã của bạn và trong bài viết, như các nhận xét đã đề xuất. Cụ thể là r2->right leftnên r2->right < r1->leftr2->bottom topnên r2->bottom < r1->topđể chức năng hoạt động.

function intersectRect(r1, r2) {
  return !(r2.left > r1.right || 
           r2.right < r1.left || 
           r2.top > r1.bottom ||
           r2.bottom < r1.top);
}

Trường hợp thử nghiệm:

var rectA = {
  left:   10,
  top:    10,
  right:  30,
  bottom: 30
};

var rectB = {
  left:   20,
  top:    20,
  right:  50,
  bottom: 50
};

var rectC = {
  left:   70,
  top:    70,
  right:  90,
  bottom: 90
};

intersectRect(rectA, rectB);  // returns true
intersectRect(rectA, rectC);  // returns false

Chỉ cần thêm / xác nhận - đây là thử nghiệm ba hộp đó là 20px x 20px, trừ rectB, đó là 30px x 30px
verenion

6
nếu r1 và r2 là giống hệt nhau, hàm intersectRect sẽ trả về false
zumalifeguard

Triển khai hùng hồn tuyệt vời. Yêu nó! +1, hoạt động hoàn hảo cho trò chơi của tôi.
Unome

1
@zumalifeguard Tại sao bạn lại nghĩ như vậy?
Minix

Chức năng này là rất thiên tài. Tôi sẽ không bao giờ nghĩ đến điều đó, thay vào đó tôi đã cố gắng làm cho hai hộp giao nhau.
nikk wong

69
function intersect(a, b) {
  return (a.left <= b.right &&
          b.left <= a.right &&
          a.top <= b.bottom &&
          b.top <= a.bottom)
}

Điều này giả định rằng topbình thường nhỏ hơn bottom(tức là ytọa độ tăng xuống dưới).


Giải pháp tốt và hoạt động, nhưng sẽ chậm hơn một chút vì tất cả các điều kiện phải được đánh giá. Giải pháp khác được thực hiện ngay khi một trong các điều kiện được đánh giá là đúng.
Gigo

21
Điều này cũng được thực hiện ngay khi một trong các điều kiện được đánh giá là sai. Tức là trong các trường hợp giống hệt như trường hợp kia.
DS.

3
Điều này tốt hơn vì nó loại bỏ hành động phủ định.
Discipol

4
+1, gọn gàng hơn nhiều so với câu trả lời được chấp nhận. nếu sử dụng phạm vi nửa mở (nghĩa là hình chữ nhật bao gồm trên cùng và bên trái nhưng không bao gồm dưới cùng và bên phải, như phổ biến trong nhiều hệ thống đồ họa), thay đổi <=thành <sẽ hoạt động.
Jules

Tôi thích giải pháp này vì tôi có thể loại bỏ các =điều kiện cho từng điều kiện và nó cho phép các hình chữ nhật "chạm" vào các đường viền.
lập trình viên

19

Đây là cách .NET Framework triển khai Rectangle.Intersect

public bool IntersectsWith(Rectangle rect)
{
  if (rect.X < this.X + this.Width && this.X < rect.X + rect.Width && rect.Y < this.Y + this.Height)
    return this.Y < rect.Y + rect.Height;
  else
    return false;
}

Hoặc phiên bản tĩnh:

public static Rectangle Intersect(Rectangle a, Rectangle b)
{
  int x = Math.Max(a.X, b.X);
  int num1 = Math.Min(a.X + a.Width, b.X + b.Width);
  int y = Math.Max(a.Y, b.Y);
  int num2 = Math.Min(a.Y + a.Height, b.Y + b.Height);
  if (num1 >= x && num2 >= y)
    return new Rectangle(x, y, num1 - x, num2 - y);
  else
    return Rectangle.Empty;
}

6

Một cách khác đơn giản hơn. (Điều này giả sử trục y tăng xuống dưới).

function intersect(a, b) {
  return Math.max(a.left, b.left) < Math.min(a.right, b.right) &&
          Math.max(a.top, b.top) < Math.min(a.bottom, b.bottom);
}

4 số (max's và min's) trong điều kiện trên cũng cho biết các giao điểm.



0

Tôi đã sử dụng một hỗn hợp các phương pháp, để phát hiện một hình chữ nhật nhỏ hơn bên trong một hình chữ nhật lớn. Đây là một phương pháp nodejs và sử dụng chiều rộng / chiều cao nhưng có thể dễ dàng điều chỉnh.

            isIntersectingRect: function (r1, r2) {
              var quickCheck = (r1.x <= r2.x + r2.w &&
                      r2.x <= r1.x + r1.w &&
                      r1.y <= r2.y + r2.h &&
                      r2.y <= r1.y + r1.h)
              if (quickCheck) return true;
              var x_overlap = Math.max(0, Math.min(r1.x + r1.w, r2.x + r2.w) - Math.max(r1.x, r2.x));
              var y_overlap = Math.max(0, Math.min(r1.y + r1.h, r2.y + r2.h) - Math.max(r1.y, r2.y));
              var overlapArea = x_overlap * y_overlap;
              return overlapArea == 0;
            }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.