Чи завжди виявлення зіткнення O (n ^ 2)?


14

Чи здатний фізичний двигун зменшити цю складність, наприклад, згрупувавши об'єкти, які знаходяться поруч один з одним, і перевірити наявність зіткнень всередині цієї групи замість усіх об'єктів? (наприклад, далекі об’єкти можна видалити з групи, переглянувши її швидкість і відстань від інших об'єктів).

Якщо ні, то це робить зіткнення тривіальним для сфер (у 3d) або диска (у 2d)? Чи варто робити подвійний цикл чи замість цього створити масив пар?

EDIT: Для двигуна фізики, як куля та box2d, чи виявлення зіткнення все ще O (N ^ 2)?


12
Два слова: Просторовий перегородка
MichaelHouse


1
Будьте впевнені. Я вважаю, що в обох є реалізація SAP ( Sweep і Prune ) (серед інших), що є алгоритмом O (n log (n)). Шукайте "Широкофазне виявлення зіткнень", щоб дізнатися більше.
MichaelHouse

2
@ Byte56 Sweep and Prune має складність O (n log (n)), лише якщо вам потрібно сортувати кожен раз при тестуванні. Ви хочете зберегти відсортований список об'єктів, і кожного разу, коли ви додаєте його, просто сортуйте його у потрібне місце O (log (n)), тому ви отримаєте O (log (n) + n) = O (n). Це стає дуже складним, коли об’єкти починають рухатися, хоча!
MartinTeeVarga

1
@ sm4, якщо рухи обмежені, то за цим можуть потурбуватися кілька проходів сортування бульбашок (просто позначте переміщені об’єкти та перемістіть їх уперед чи назад у масиві, поки вони не будуть відсортовані. просто слідкуйте за іншими об'єктами, що рухаються
храповиком

Відповіді:


14

Просторовий поділ - це завжди O (N ^ 2) у гіршому випадку, і саме в цьому полягає складність інформатики.

Однак існують алгоритми, які працюють у лінійному часі O (N) . Усі вони засновані на якійсь лінії розгортки.

В основному потрібно об'єкти сортувати за однією координатою. Скажімо, X. Якщо ви виконуєте сортування кожного разу перед виявленням зіткнення, складність буде O (N * logN). Трюк полягає в сортуванні лише тоді, коли ви додаєте об'єкти на сцену і пізніше, коли щось на сцені змінюється. Сортування після руху не є тривіальним. Дивіться зв'язаний папір нижче алгоритм, який приймає рух і все ще працює в лінійний час.

Потім ви підмітаєте зліва направо. Кожен раз, коли лінія розгортки перетинає початок об'єкта, ви поміщаєте його у тимчасовий список. Кожен раз, коли ваша лінія розгортки виходить з об'єкта, ви виймаєте її зі списку. Ви вважаєте зіткнення лише всередині цього тимчасового списку.

Наївна лінія розгортки - це O (N ^ 2) і в гіршому випадку (ви робите, що всі об'єкти охоплюють всю карту зліва направо), але ви можете зробити її O (N), зробивши її розумнішою (див. Посилання нижче). Дійсно хороший алгоритм буде досить складним.

Це проста схема, як працює лінія розгортки:

Алгоритм підмітання рядків

Лінія прошивається зліва направо. Об'єкти сортуються за X координатою.

  • Випадок перший: спочатку перевіряються два об'єкти. Нічого іншого не має значення.
  • Випадок другий: Спочатку об'єкт перевіряли і його немає у списку. Два і три перевіряються.
  • Випадок третій: Навіть якщо цей об'єкт стикається, ми не перевіряємо.
  • Випадок четвертий: Тому що ми перевіряємо в цьому випадку!

Такі алгоритми мають складність O (C * N) = O (N).

Джерело: Два роки курсів обчислювальної геометрії.

При виявленні зіткнень це, як правило, називається Sweep і Prune , але сімейство розгортки ліній алгоритмів корисно в багатьох інших сферах.

Далі рекомендується прочитати, що, на мою думку, виходить за рамки цього питання, але, тим не менш, цікаво: Ефективні великомасштабні методи розгортки та підрізання з введенням та видаленням AABB - У цьому документі представлений вдосконалений алгоритм зачистки та підрізання, який використовує обмежувальні вікна, орієнтовані на осі (AABB ) з сортуванням, що враховує рух. Алгоритм, представлений у статті, працює у лінійному часі.


Тепер зауважимо, що це найкращий теоретичний алгоритм . Це не означає, що воно використовується. На практиці алгоритм O (N ^ 2) з просторовим поділом матиме кращу швидкість роботи в типовому випадку (близьку до O (N)) та деяку додаткову вимогу до пам'яті. Це тому, що константа C в O (C * N) може бути дуже високою! Оскільки у нас зазвичай достатньо пам'яті, а типові випадки мають об’єкти рівномірно розподілені в просторі - такий алгоритм виконує КРАЩЕ. Але O (N) - це відповідь на початкове запитання.


це використовує box2d / bullet?
jokoon

3
"Підмітати і підрізати" - це те, що зазвичай називають фізикою. Приємно те, що ви можете постійно оновлювати сортування по мірі вдосконалення моделювання. Крім того, лінія графічного перегляду у вашій графіці трохи відключена з точки зору реалізації (добре для теорії) - ви просто переглянете початкові / кінцеві поля, тому ви будете лише перевіряти фактичні потенційні зіткнення. Цей метод використовується для генерування більш спроможних просторових розділів дерев, а не безпосередньо.
Шон Міддлічч

3
Оскільки технічно насправді можуть бути парні зіткнення O (N ^ 2), не зовсім вірно сказати, що розгортка - це завжди O (N). Скоріше, основна складність алгоритму становить O (N + c), де c - кількість зіткнень, знайдених алгоритмом - він чутливий до виходу , як і багато алгоритмів опуклого корпусу. (Довідка: en.wikipedia.org/wiki/Output-sensitive_algorithm )
Стівен Стадницький

1
Ви повинні підкріпити свої претензії деякими публікаціями або хоча б назвами алгоритмів.
sam hocevar

1
@SamHocevar Я додав посилання на дійсно вдосконалений алгоритм Sweep and Prune, який працює в лінійний час з детальним розбиттям констант. Той факт, що алгоритми називаються "Підмітати і підрізати", був для мене новим, оскільки я ніколи з ним не працював. Я використовував ці алгоритми при виборі карти (це свого роду зіткнення 1 бала з іншими об’єктами), тому я просто застосував знання.
MartinTeeVarga

8

Ні. Виявлення зіткнення не завжди є O (N ^ 2).

Наприклад, скажімо, у нас є простір розміром 100x100 з об'єктами розміром 10x10. Ми могли поділити цей простір у клітинках розміром 10х10 за допомогою сітки.

Кожен об'єкт може містити до 4-х комірок сітки (він може вміститися прямо в блоці або бути "між" осередками). Ми можемо зберігати перелік об’єктів у кожній комірці.

Нам потрібно лише перевірити наявність колізій у цих осередках. Якщо на одну комірку сітки існує максимальна кількість об'єктів (скажімо, ніколи в одному блоці не більше 4 об’єктів), то виявлення зіткнення для кожного об’єкта - O (1), а виявлення зіткнення для всіх об'єктів - O (N).

Це не єдиний спосіб уникнути складності O (N ^ 2). Є й інші методи, більш адекватні для інших випадків використання - часто використовують структури даних на основі дерева.

Описаний мною алгоритм є одним з типів розділення простору , але є й інші алгоритми розподілу простору. Див. Типи структур даних про розподіл простору для деяких інших алгоритмів, які уникають часової складності O (N ^ 2).

Як підтримка механізмів Box2D, так і Bullet, щоб зменшити кількість перевірених пар.

З посібника , розділ 4.15:

Обробку зіткнень на етапі фізики можна розділити на вузькофазну та широкофазну. У вузькофазній обчислюємо точки контактів між парами фігур. Уявіть, у нас N фігур. Використовуючи грубу силу, нам потрібно було б виконати вузькофазну для N * N / 2 пар.

Клас b2BroadPhase зменшує це навантаження, використовуючи динамічне дерево для управління парами. Це значно зменшує кількість дзвінків у вузькій фазі.

Зазвичай ви не взаємодієте із широкофазною безпосередньо. Натомість Box2D створює та керує внутрішньофазною широкою фазою. Крім того, b2BroadPhase розроблений з урахуванням симуляційного циклу Box2D, тому він, ймовірно, не підходить для інших випадків використання.

З кулі Вікі :

Існують різні види широкофазних алгоритмів, які вдосконалюються на наївному алгоритмі O (n ^ 2), який просто повертає повний список пар. Ці оптимізовані широкофази іноді вводять ще більше пар, що не стикаються, але це компенсується загалом покращеним часом їх виконання. Вони мають різні експлуатаційні характеристики і жодна не перевершує інших у будь-яких ситуаціях.

Динамічне дерево AABB

Це реалізовано btDbvtBroadphase у Bullet.

Як випливає з назви, це динамічне дерево AABB . Однією з корисних особливостей цієї широкої фази є те, що структура динамічно адаптується до вимірів світу та його змісту. Це дуже добре оптимізований та дуже хороший широкофазний загального призначення. Він обробляє динамічні світи, де багато об’єктів перебувають у русі, а додавання та видалення об’єктів відбувається швидше, ніж SAP.

Зачистка і чорнослив (SAP)

У Bullet це діапазон класів AxisSweep. Це також хороша широкофаза загального призначення, з обмеженням, що вона потребує фіксованого світового розміру, відомого заздалегідь. Ця широкофазна фаза має найкращі показники для типових динамічних світів, де більшість об’єктів мають малий рух або їх немає. І btAxisSweep3, і bt32AxisSweep3 квантують початкову та кінцеву точки для кожної осі як цілі числа, а не числа з плаваючою комою, щоб підвищити продуктивність.

Наступне посилання - це загальне введення до широкофазного, а також опис алгоритму "Розгортання та пересікання" (хоча він називає його "Сортування та зміщення"):

http://www.ziggyware.com/readarticle.php?article_id=128

Також перегляньте сторінку вікіпедії:

http://en.wikipedia.org/wiki/Sweep_and_prune


Деякі посилання на подібні питання та зовнішні ресурси зробили б це чудовою відповіддю.
MichaelHouse

3
Це неправильно. Ви все ще отримуєте O (N ^ 2). Це буде набагато швидше, щось на зразок N ^ 2/100, але все ж N ^ 2. Як доказ, просто врахуйте, що всі об'єкти трапляються в одній комірці.
MartinTeeVarga

4
@ sm4 Це найгірший випадок O (N ^ 2), що дійсно відбувається, якщо всі об'єкти знаходяться в одній комірці. Однак у двигунах фізики об'єкти, як правило, не знаходяться в одній клітині. У моєму прикладі жоден об’єкт ніколи не може ділити одну й ту ж клітинку з більш ніж 3 іншими об’єктами. Це було б те, що відбувається у фізичному двигуні для "нормальних" об'єктів (а під "нормальним" я маю на увазі "не просто датчик").
люїскубал

Я думаю, що для вашого алгоритму потрібно буде перевірити 8 комірок навколо, а не лише 4 комірки.
jokoon

6
@luiscubal Складність завжди "найгірший випадок". Теоретично ви шукаєте "гарантовану" складність. Це те саме з quicksort, який є O (N ^ 2) і злиттям, що є O (N * logN). Quicksort краще працює на реальних даних та має менші просторові вимоги. Але злиття гарантувало кращу складність. Якщо вам потрібно щось довести, використовуйте mergesort. Якщо вам потрібно щось сортувати, використовуйте квакісорт.
MartinTeeVarga

2

O (N ^ 2) відноситься до того, що якщо у вас N об'єктів, з'ясування того, що стикається з тим, що є, в гіршому випадку , обчислення зіткнення N ^ 2. Скажіть, у вас є 3 об’єкти. Щоб знайти "хто б'є хто", ви повинні знайти:

o1 hitting o2?  o1 hitting o3?
o2 hitting o1?  o2 hitting o3?
o3 hitting o1?  o3 hitting o2?

Це 6 перевірок на зіткнення або N * (N-1) перевірок. В асимптотичному аналізі ми би розширили поліном і наблизимо як O (N ^ 2). Якщо у вас було 100 об’єктів, то це було б 100 * 99, що досить близько до 100 * 100.

Отже, якщо, наприклад, ви розділяєте простір за допомогою octree, середня кількість порівнянь між тілами зменшується. Якщо є можливість, щоб усі об'єкти зібралися на дуже невеликій площі (скажімо, якщо ви робите якесь моделювання потоку частинок, де частинки можуть збиратися в одній області), то O (N ^ 2) все ще може виникати на бали в моделюванні (в яких точках ви побачите уповільнення).

Отже, вся суть O (N ^ 2) існує через характер кожного тіла, що перевіряє кожне інше тіло в сцені. Ось тільки природа обчислень. Дуже багато речей може допомогти зробити це дешевше. Навіть графік сцени (скажімо, виявлення лише між предметами в одній кімнаті ) зменшить кількість обчислень зіткнення, які потрібно зробити значно, але все одно це буде O (M ^ 2) (де M - кількість об'єктів у приміщенні до бути зіткненням виявлено проти). Сферичні обмежувальні об'єми роблять початкову перевірку дуже швидкою ( if( distance( myCenter, hisCenter ) > (myRadius+hisRadius) ) then MISS), тому навіть якщо виявлення зіткнення становить O (N ^ 2), обчислення обмежувальної сфери, ймовірно, відбудуться дуже швидко.


Не потрібно приймати перевірку грубої сили як орієнтир: незалежно від розумних алгоритмів, N об’єктів можуть стикатися з усіма іншими об'єктами, даючи зіткнення O (N ^ 2), які потребують обробки O (N ^ 2). Хороші алгоритми можуть робити краще лише тоді, коли зіткнень менше.
Лоренцо Ґатті
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.