Перш за все, у випадку прямокутників, що вирівнюються по осі, відповідь Кевіна Рейда найкраща, а алгоритм - найшвидший.
По-друге, для простих фігур використовуйте відносні швидкості (як показано нижче) і теорему роздільної осі для виявлення зіткнень. Це буде сказати, чи відбувається зіткнення в разі лінійного руху (без обертання). І якщо є обертання, вам потрібен невеликий часовий крок, щоб він був точним. Тепер, щоб відповісти на запитання:
Як сказати в загальному випадку, чи перетинаються дві опуклі форми?
Я дам вам алгоритм, який працює для всіх опуклих фігур, а не лише для шестикутників.
Припустимо, X і Y - дві опуклі форми. Вони перетинаються тоді і лише тоді, коли мають спільну точку, тобто є точка x ∈ X і точка y ∈ Y така, що x = y . Якщо ви розглядаєте простір як векторний простір, то це означає вислів x - y = 0 . А тепер ми переходимо до цієї справи Міньковського:
Сума Маньківського з X і Y являє собою безліч всіх х + у для х ∈ X і Y ∈ Y .
Приклад для X і Y
X, Y та їх сума Minkowski, X + Y
Припустимо, що (-Y) - це множина всіх -y для y ∈ Y , тоді, з огляду на попередній абзац, X і Y перетинаються тоді і тільки тоді, коли X + (-Y) містить 0 , тобто походження .
Побічне зауваження: чому я пишу X + (-Y) замість X - Y ? Отже, оскільки в математиці існує операція, яка називається різницею Міньковського A і B, яка іноді пишеться X - Y, але не має нічого спільного з множиною всіх x - y для x ∈ X і y ∈ Y (справжній Міньковський різниця трохи складніша).
Отже, ми хотіли б обчислити суму Міньковського X і -Y та дізнатись, чи містить вона походження. Походження не є особливим порівняно з будь-яким іншим моментом, так що для того, щоб знайти, чи є джерело в межах певного домену, ми використовуємо алгоритм, який міг би сказати нам, чи належить якась дана точка до цього домену.
Сума Міньковського X і Y має класну властивість, яка полягає в тому, що якщо 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 (до балці (к)) , де до є розміром безлічі точок, так що в нашому випадку ми отримуємо O (млн журналу (млн) ) . contains
Алгоритм має складність, лінійно з числом ребер (в 2D) або особа (в 3D) опуклої оболонки, так що це дійсно залежить від ваших вихідних форм, але це буде не більше , ніж O (млн) .
Я дозволю вам google для contains
алгоритму опуклих фігур, це досить поширений. Я можу поставити його тут, якщо матиму час.
Але це ми виявляємо зіткнення, тому ми можемо оптимізувати це багато
Ми спочатку мали два тіла і B переміщення без обертання під час Timestep DT (від того, що я можу сказати, дивлячись на ваші фотографії). Назвемо v A і v B відповідні швидкості A і B , постійні протягом нашого часового кроку тривалості dt . Ми отримуємо наступне:
і, як ви вказуєте на своїх фотографіях, ці тіла під час руху рухаються по областях (або томах у 3D):
і вони закінчуються як A ' і B' після часового кроку.
Щоб застосувати тут наш наївний алгоритм, нам слід було б лише обчислити нечисті обсяги. Але ми цього не робимо.
У системі відліку B , B не рухається (так!). І A має певну швидкість відносно B, яку ви отримуєте, обчислюючи v A - v B (ви можете зробити зворотне, обчислити відносну швидкість B у референтному кадрі A ).
Зліва направо: швидкості в базовій системі відліку; відносні швидкості; обчислення відносних швидкостей.
Розглядаючи B як нерухомий у своїй власній системі відліку, ви тільки обчислити об'єм, А мете через , як вона рухається під час ДТ з його відносної швидкості про - про B .
Це зменшує кількість вершин, які будуть використані при обчисленні суми Міньковського (іноді сильно).
Інша можлива оптимізація - це місце, коли ви обчислюєте об'єм, пронесений одним із тіл, скажімо, A. Не потрібно перекладати всі вершини, що складаються з A. Тільки ті, що належать до ребер (граней у 3D), чиї зовнішнє нормальне «обличчя» напрям підмітання. Звичайно, ви це помітили вже під час обчислення розміщених площ для площ. Ви можете сказати, чи нормальна в напрямку змітання, використовуючи крапковий добуток із напрямком зміщення, який повинен бути позитивним.
Остання оптимізація, яка не має нічого спільного з вашим питанням щодо перехресть, насправді корисна в нашому випадку. Він використовує ті відносні швидкості, про які ми згадували, і так званий метод роздільної осі. Напевно ви про це вже знаєте.
Припустимо , ви знаєте радіуси в A і B щодо їх центрів мас (тобто, відстань між центром мас і вершиною далекому від нього), як це:
Зіткнення може відбутися тільки в тому випадку, можливо , що обмежує коло А зустрічаються у B . Тут ми бачимо , що він не буде, і так би мовити , комп'ютер , який повинен обчислити відстань від C B до I , як на малюнку нижче і переконайтеся , що це більше , ніж сума радіусів A і 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;
}