우선 축 정렬 사각형의 경우 Kevin Reid의 답변이 가장 좋고 알고리즘이 가장 빠릅니다.
둘째, 간단한 모양의 경우 충돌 감지를 위해 상대 속도 (아래 참조)와 분리 축 정리를 사용하십시오. 그것은 것이다 충돌이 직선 운동 (NO 회전)의 경우 발생 여부를 알려줍니다. 그리고 회전이 있다면, 정밀하게하기 위해 약간의 시간 간격이 필요합니다. 이제 질문에 대답하십시오.
일반적인 경우에 두 개의 볼록한 모양이 교차하는지 어떻게 알 수 있습니까?
육각형뿐만 아니라 모든 볼록한 모양에 작동하는 알고리즘을 제공합니다.
X 와 Y 가 두 개의 볼록한 모양 이라고 가정하십시오 . 공통점이있는 경우에만 교차합니다. 즉, x = y 와 같은 점 x ∈ X 와 점 y ∈ Y가 있습니다. 공간을 벡터 공간으로 간주하면 x-y = 0이 됩니다. 이제 우리는이 Minkowski 비즈니스에 도달합니다.
X 와 Y 의 Minkowski 합 은 x ∈ X 및 y ∈ Y에 대한 모든 x + y 의 집합입니다 .
X와 Y의 예
X, Y 및 Minkowski 합계, X + Y
가정하면 (-Y) 모두의 집합이다 -y 대한 Y ∈ Y는 다음 문단 주어진 X 및 Y 교차하는 경우에만, X + (-Y) 포함 0 원점이다 .
참고 : 왜 X-Y 대신 X + (-Y) 를 쓰 나요? 수학에서 A 와 B 의 Minkowski 차이라는 연산이 있기 때문에 때때로 X-Y로 쓰여지 지만 x ∈ X 및 y ∈ Y에 대한 모든 x-y 세트 (실제 Minkowski) 와는 아무런 관련이 없습니다. 차이는 조금 더 복잡합니다).
그래서 우리는 X 와 -Y 의 Minkowski 합을 계산하고 그 원점이 포함되어 있는지 확인 하고 싶습니다 . 원점은 다른 지점과 비교하여 특별하지 않으므로 원점이 특정 도메인 내에 있는지 확인하기 위해 주어진 지점이 해당 도메인에 속하는지 여부를 알려주는 알고리즘을 사용합니다.
X 와 Y 의 Minkowski 합은 멋진 특성을 지니고 있습니다. 즉, X 와 Y 가 볼록하면 X + Y 도 좋습니다. 그리고 점이 볼록 세트에 속하는지 찾는 것이 그 세트가 볼록하지 않은 것보다 훨씬 쉽습니다.
우리는 가능성을 모두 계산할 수없는 X - Y 에 대한 X ∈ X 와 Y ∈ Y를 같은 지점의 무한대가 있기 때문에 X 와 Y 있기 때문에, 그래서 희망, X , Y 및 X + Y는 볼록, 우리는 사용을 할 수 있습니다 정점 인 모양 X 와 Y를 정의하는 "가장 바깥 쪽"점 이며 , X + Y 의 가장 바깥 쪽 점을 가져옵니다 .
이러한 추가 지점은 X + Y 의 가장 바깥쪽에 의해 "주변" 되므로 새로 얻은 볼록한 모양을 정의하는 데 기여하지 않습니다. 우리는 그것들이 포인트 세트의 " 볼록 껍질 "을 정의하지 않는다고 말합니다 . 그래서 우리가하는 것은 원점이 볼록 껍질 안에 있는지를 알려주는 최종 알고리즘을 준비하면서 그것들을 제거하는 것입니다.
X + Y의 볼록 껍질. "내부"정점을 제거했습니다.
그러므로 우리는 얻는다
최초의 순진한 알고리즘
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));
}
루프는 분명히 복잡도 O (mn) 를 가지며, 여기서 m 과 n 은 각 모양의 꼭짓점 수입니다. minkoswki
세트는 포함 백만 최대 요소. convexHull
알고리즘에 따라 복잡도가 사용한 알고리즘을 , 그리고 당신이 목표로 할 수 O (K 로그 (K)) k는 점 세트의 크기, 그래서 우리의 경우 우리가 얻을 O (백만 로그 (백만)을 ) . 이 contains
알고리즘은 볼록 껍질의 모서리 수 (2D) 또는면 (3D)의 수와 선형적인 복잡성을 가지므로 시작 모양에 따라 달라 지지만 O (mn) 보다 크지 않습니다 .
contains
볼록한 모양 에 대한 알고리즘을 Google에 알려 드리겠습니다 . 그것은 매우 일반적인 것입니다. 시간이 있으면 여기에 둘 수도 있습니다.
하지만 충돌 감지로 인해 많은 것을 최적화 할 수 있습니다.
우리는 원래 두 단계의 몸 A 와 B 가 시간 단계 dt 동안 회전하지 않고 움직였습니다 (사진을 보면서 알 수 있는 것부터 ). 지속 시간 dt 의 시간 단계 동안 일정한 A 와 B 의 각각의 속도를 v A 와 v B 라고합시다 . 우리는 다음을 얻습니다.
그리고 당신이 당신의 그림에서 지적 하듯이,이 몸체들은 그들이 움직일 때 영역 (또는 볼륨, 3D)을 스윕합니다 .
타임 스텝 후에 A ' 와 B' 로 끝납니다 .
여기서 순진 알고리즘을 적용하려면 스윕 된 볼륨 만 계산하면됩니다. 그러나 우리는 이것을하지 않습니다.
B 의 참조 프레임 에서 B 는 움직이지 않습니다 (duh!). 그리고 A 는 v A -v B를 계산하여 얻는 B에 대해 특정 속도 를 갖 습니다 (대화를 할 수 있으며 A 의 참조 프레임에서 B 의 상대 속도를 계산할 수 있습니다 ).
왼쪽에서 오른쪽으로 : 기본 참조 프레임의 속도; 상대 속도; 상대 속도 계산.
관련하여 B 자신의 참조 프레임에서 움직이지 등을, 당신은 단지 볼륨을 계산해야하는 경우 → 그 동안 이동로를 통해 스윕 (DT) 의 상대 속도로 V - V의 B는 .
이렇게하면 Minkowski 합계 계산에 사용될 정점 수가 줄어 듭니다 (때로는 크게).
또 다른 가능한 최적화는 바디 중 하나에 의해 스윕 된 볼륨을 계산하는 지점에 있습니다. A라고 가정 해 봅시다. A를 구성하는 모든 정점을 변환 할 필요는 없습니다. 바깥 쪽 정상 "얼굴"스위핑 방향. 분명히 당신은 이미 사각형의 스윕 영역을 계산할 때 알았습니다. 양수 여야하는 스위핑 방향과 함께 내적을 사용하여 법선이 스위핑 방향을 향하는 지 여부를 알 수 있습니다.
교차점에 대한 귀하의 질문과 관련이없는 마지막 최적화는 우리의 경우 실제로 유용합니다. 그것은 우리가 언급 한 상대 속도와 소위 분리 축 방법을 사용합니다. 분명히 당신은 이미 그것에 대해 알고 있습니다.
질량 중심 (즉, 질량 중심과 가장 먼 정점 사이의 거리)에 대한 A 와 B 의 반지름 을 다음 과 같이 알고 있다고 가정합니다 .
충돌은 가능한 경우에만 발생할 수의 경계 원 의 대회의 B . 우리는 여기가되지 않습니다 참조와의 거리를 계산하는 컴퓨터 말할 수있는 방법 C B를 에 내가 다음 그림과 같이 및 확인이의 반경의 합보다 더 큰 수 있도록 와 B . 더 크면 충돌이 없습니다. 더 작 으면 충돌합니다.
이것은 다소 긴 모양에서는 잘 작동하지 않지만 정사각형이나 다른 모양의 경우 충돌을 배제 하는 매우 휴리스틱 입니다.
그러나 B에 적용된 분리 축 정리 와 A로 스윕 된 볼륨 은 충돌이 발생하는지 여부를 알려줍니다. 관련 알고리즘의 복잡성은 각 볼록한 모양의 꼭짓점 수의 합과 선형이지만 실제로 충돌을 처리 할 때 마법이 덜됩니다.
교차점을 사용 하여 충돌을 감지 하는 데 도움이 되지만 충돌 발생 여부를 알려주 는 분리 축 정리만큼 좋지 않은 새롭고 더 나은 알고리즘
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;
}