Trước hết, trong trường hợp hình chữ nhật được căn chỉnh theo trục, câu trả lời của Kevin Reid là tốt nhất và thuật toán là nhanh nhất.
Thứ hai, đối với các hình dạng đơn giản, sử dụng vận tốc tương đối (như được thấy dưới đây) và định lý trục tách để phát hiện va chạm. Nó sẽ cho bạn biết liệu một vụ va chạm xảy ra trong trường hợp chuyển động tuyến tính (không quay). Và nếu có vòng quay, bạn cần một dấu thời gian nhỏ để nó chính xác. Bây giờ, để trả lời câu hỏi:
Làm thế nào để biết trong trường hợp chung liệu hai hình lồi có giao nhau không?
Tôi sẽ cung cấp cho bạn một thuật toán hoạt động cho tất cả các hình lồi chứ không chỉ hình lục giác.
Giả sử X và Y là hai hình lồi. Chúng cắt nhau khi và chỉ khi chúng có một điểm chung, tức là có một điểm x ∈ X và một điểm y ∈ Y sao cho x = y . Nếu bạn coi không gian là không gian vectơ, thì điều này có nghĩa là nói x - y = 0 . Và bây giờ chúng ta có được doanh nghiệp Minkowski này:
Các Minkowski tổng của X và Y là tập hợp của tất cả các x + y cho x ∈ X và y ∈ Y .
Một ví dụ cho X và Y
X, Y và tổng số Minkowski của họ, X + Y
Giả sử (-Y) là tập hợp tất cả -y cho y ∈ Y , sau đó đưa ra đoạn trước, X và Y cắt nhau khi và chỉ khi X + (-Y) chứa 0 , nghĩa là gốc .
Nhận xét bên lề: tại sao tôi viết X + (-Y) thay vì X - Y ? Chà, bởi vì trong toán học, có một phép toán gọi là sự khác biệt giữa Minkowski của A và B , đôi khi được viết X - Y nhưng không liên quan gì đến tập hợp tất cả x - y cho x ∈ X và y ∈ Y (thực sự là Minkowski sự khác biệt là một chút phức tạp hơn).
Vì vậy, chúng tôi muốn tính tổng của Minkowski là X và -Y và để xem liệu nó có chứa nguồn gốc hay không. Nguồn gốc không đặc biệt so với bất kỳ điểm nào khác, để tìm xem nguồn gốc có nằm trong một miền nhất định hay không, chúng tôi sử dụng thuật toán có thể cho chúng tôi biết liệu có điểm nào thuộc về miền đó hay không.
Tổng số Minkowski của X và Y có một thuộc tính tuyệt vời, đó là nếu X và Y là lồi thì X + Y cũng vậy. Và việc tìm kiếm cho dù một điểm thuộc về một tập lồi là nhiều dễ dàng hơn nếu thiết lập được không (được gọi là) lồi.
Chúng ta không thể tính tất cả x - y cho x ∈ X và y ∈ Y vì có vô số điểm x và y như vậy, vì vậy, hy vọng, vì X , Y và X + Y là lồi, chúng ta chỉ có thể sử dụng các điểm "ngoài cùng" xác định các hình dạng X và Y , là các đỉnh của chúng và chúng ta sẽ nhận được các điểm ngoài cùng của X + Y , và một số điểm khác.
Các điểm bổ sung này được "bao quanh" bởi các điểm ngoài cùng của X + Y để chúng không góp phần xác định hình dạng lồi mới thu được. Chúng tôi nói rằng họ không định nghĩa " thân lồi " của tập hợp các điểm. Vì vậy, những gì chúng tôi làm là chúng tôi loại bỏ chúng để chuẩn bị cho thuật toán cuối cùng cho chúng tôi biết nguồn gốc có nằm trong thân tàu lồi hay không.
Vỏ lồi của X + Y. Chúng tôi đã loại bỏ các đỉnh "bên trong".
Do đó, chúng tôi nhận được
Một thuật toán đầu tiên, ngây thơ
boolean intersect(Shape X, Shape Y) {
SetOfVertices minkowski = new SetOfVertices();
for (Vertice x in X) {
for (Vertice y in Y) {
minkowski.addVertice(x-y);
}
}
return contains(convexHull(minkowski), Vector2D(0,0));
}
Các vòng lặp rõ ràng có độ phức tạp O (mn) trong đó m và n là số đỉnh của mỗi hình. Bộ minkoswki
chứa nhiều phần tử mn nhất. Các convexHull
thuật toán có độ phức tạp mà phụ thuộc vào các thuật toán bạn sử dụng , và bạn có thể nhằm mục đích cho O (k log (k)) nơi k là kích thước của tập hợp các điểm, vì vậy trong trường hợp của chúng tôi, chúng tôi có được O (mn log (mn) ) . Các contains
thuật toán có độ phức tạp đó là tuyến tính với số cạnh (2D) hoặc khuôn mặt (trong không gian 3D) của thân lồi, vì vậy nó thực sự phụ thuộc vào hình dạng bắt đầu của bạn, nhưng nó sẽ không được lớn hơn O (mn) .
Tôi sẽ cho bạn google contains
thuật toán cho các hình lồi, đây là một thuật toán khá phổ biến. Tôi có thể đặt nó ở đây nếu tôi có thời gian.
Nhưng đó là phát hiện va chạm chúng tôi đang làm, vì vậy chúng tôi có thể tối ưu hóa điều đó rất nhiều
Chúng tôi ban đầu có hai cơ thể A và B di chuyển mà không quay trong thời gian dt (từ những gì tôi có thể nói bằng cách nhìn vào hình ảnh của bạn). Chúng ta hãy gọi v A và v B là tốc độ tương ứng của A và B , không đổi trong khoảng thời gian của chúng tôi là dt . Chúng tôi nhận được như sau:
và, như bạn chỉ ra trong ảnh của mình, các cơ quan này sẽ quét qua các khu vực (hoặc tập, ở chế độ 3D) khi chúng di chuyển:
và chúng kết thúc là A ' và B' sau dấu thời gian.
Để áp dụng thuật toán ngây thơ của chúng tôi ở đây, chúng tôi sẽ chỉ phải tính toán các khối lượng quét. Nhưng chúng tôi không làm điều này.
Trong khung tham chiếu của B , B không di chuyển (duh!). Và A có vận tốc nhất định đối với B mà bạn có được bằng cách tính v A - v B (bạn có thể thực hiện ngược lại, tính vận tốc tương đối của B trong khung tham chiếu của A ).
Từ trái sang phải: vận tốc trong khung tham chiếu cơ sở; vận tốc tương đối; tính toán vận tốc tương đối.
Bằng cách liên quan đến B như bất động trong hệ quy chiếu riêng của mình, bạn chỉ cần tính toán khối lượng Một quét qua khi nó di chuyển trong dt với thân nhân của nó vận tốc v Một - v B .
Điều này làm giảm số lượng đỉnh được sử dụng trong tính toán tổng số Minkowski (đôi khi rất nhiều).
Một tối ưu hóa khác có thể là tại điểm bạn tính toán âm lượng được quét bởi một trong các cơ thể, giả sử A. Bạn không phải dịch tất cả các đỉnh tạo thành A. Chỉ những phần thuộc về các cạnh (khuôn mặt trong 3D) có bên ngoài "mặt" bình thường theo hướng quét. Chắc chắn bạn đã nhận thấy rằng khi bạn tính toán các khu vực quét của mình cho các hình vuông. Bạn có thể biết liệu một bình thường có hướng về hướng quét hay không bằng cách sử dụng sản phẩm chấm của nó với hướng quét, điều này phải là dương.
Tối ưu hóa cuối cùng, không liên quan gì đến câu hỏi của bạn về các giao lộ, thực sự hữu ích trong trường hợp của chúng tôi. Nó sử dụng các vận tốc tương đối mà chúng ta đã đề cập và phương pháp trục tách. Chắc chắn bạn đã biết về nó rồi.
Giả sử bạn biết bán kính của A và B đối với tâm khối lượng của chúng (nghĩa là khoảng cách giữa tâm khối lượng và đỉnh xa nhất so với nó), như thế này:
Một vụ va chạm có thể xảy ra chỉ khi nó có thể là hình tròn giới hạn của một đáp ứng của B . Chúng ta thấy ở đây là nó sẽ không, và cách nào để biết máy tính đó là để tính toán khoảng cách từ C B để tôi như trong hình dưới đây và chắc chắn rằng nó lớn hơn tổng của các bán kính của A và B . Nếu nó lớn hơn, không có va chạm. Nếu nó nhỏ hơn, sau đó va chạm.
Điều này không hoạt động rất tốt với các hình dạng khá dài, nhưng trong trường hợp hình vuông hoặc hình dạng khác, đó là một cách giải quyết rất tốt để loại trừ va chạm .
Tuy nhiên, định lý trục phân tách áp dụng cho B và âm lượng quét bởi A , tuy nhiên, sẽ cho bạn biết liệu va chạm có xảy ra hay không. Độ phức tạp của thuật toán liên quan là tuyến tính với tổng số lượng đỉnh của mỗi hình lồi, nhưng sẽ ít kỳ diệu hơn khi đến lúc thực sự xử lý va chạm.
Thuật toán mới, tốt hơn của chúng tôi sử dụng các giao điểm để giúp phát hiện va chạm, nhưng vẫn không tốt bằng định lý trục tách để thực sự cho biết liệu có xảy ra va chạm hay không
boolean mayCollide(Body A, Body B) {
Vector2D relativeVelocity = A.velocity - B.velocity;
if (radiiHeuristic(A, B, relativeVelocity)) {
return false; // there is a separating axis between them
}
Volume sweptA = sweptVolume(A, relativeVelocity);
return contains(convexHull(minkowskiMinus(sweptA, B)), Vector2D(0,0));
}
boolean radiiHeuristic(A, B, relativeVelocity)) {
// the code here
}
Volume convexHull(SetOfVertices s) {
// the code here
}
boolean contains(Volume v, Vector2D p) {
// the code here
}
SetOfVertices minkowskiMinus(Body X, Body Y) {
SetOfVertices result = new SetOfVertices();
for (Vertice x in X) {
for (Vertice y in Y) {
result.addVertice(x-y);
}
}
return result;
}