Алгоритм Бентлі — Оттманна

Алгоритм Бентлі — Оттманна в обчислювальній геометрії використовує метод замітання прямою для пошуку всіх точок перетину прямолінійних відрізків на площині. Він узагальнює алгоритм Шеймоса-Нойї, який задану множину відрізків перевіряв на наявність будь-якого перетину. Для вхідних даних, які містять відрізків, що мають переринів, алгоритм Бентлі — Оттманна виконується за час . У випадку, коли , його можна розглядати як удосконалення алгоритму повного перебору, який виконується за час .

Перетин відрізків

Алгоритм був розроблений Джоном Бентлі та Томасом Оттманном у 1979 році. Більш детально він описаний у книгах Preparata та Shamos, (1985), O'Rourke, (1998), та de Berg та ін., (2000). Хоча й відомі асимптотично більш швідкі алгоритми, алгоритм Бентлі — Оттманна залишається затребуваним завдяки простоті та використанню низького об'єму пам'яті[джерело?].

Загальний опис

В алгоритмі застосовується метод замітаючої прямої (замітаючої прямої[1], що рухається прямо, скануючи лінії[2]; англ. sweeping line). У методі використовується вертикальна вимітаюча пряма, що рухається зліва направо, при цьому відрізки, які вона перетинає при даній координаті , можна впорядкувати за координатою , тим самим їх можна порівнювати між собою (котрий вище, котрий нижче). Це порівняння можна здійснити, наприклад, використовуючи рівняння прямої, що проходить через дві точки (відрізки задано двома своїми кінцевими точками): , де , і ,  — координати, відповідно, першої та другої точок відрізка. Вимітаюча пряма переміщається по так званим точкам подіям (лівим і правим кінцям відрізків, а також точкам перетину відрізків). Після точки перетину відрізки варто міняти місцями, оскільки, наприклад, самий верхній із відрізків, які перетинаються після точки перетину стає самим нижнім. Наведений нижче алгоритм не розрахований на випадок, коли два відрізки перетинаються більше, ніж в одній точці.

NB Вимітаючу пряму можна також представити як горизонтальну, що рухається згори до низу за координатою , і порівнювати відрізки, що її перетинають за координатою .

Обробка вертикальних відрізків

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

Квадрат пам'яті

У гіршому випадку, коли, наприклад, усі відрізки, перетинаючись між собою, утворюють прямокутну сітку, буде точок перетину, які потрібно буде зберігати. Щоб уникнути використання квадрата пам'яті в алгоритмі, можна видаляти точку перетину відрізків, котрі тимчасово перестають бути сусідніми при даному положенні вимітаючою прямою. Ці точки все рівно будуть знову знайдені при подальших кроках алгоритму, коли дані відрізки знову стануть сусідніми (Печ, Шерір 1991).

Алгоритм

У наведеному нижче псевдокоді використовуються:

  • Q — динамічні структура даних без повторень з логарифмічним часом пошуку, вставки, видалення точок подій і пошуку мінімального елемента (наприклад, червоно-чорне дерево, 2-3-дерево).
  • T — динамічні структура даних без повторень з логарифмічним часом пошуку, вставки, видалення відрізків. У ній зберігаються всі відрізки, що перетинають вимітаючу пряму (наприклад, червоно-чорне дерево, 2-3-дерево).
  • q — точка події.
  • newq — щойно знайдена точка перетину відрізків, точка події.
  • L(q) — безліч відрізків, лівий кінець яких — q (для вертикальних відрізків лівим вважається нижній кінець).
  • R(q) — безліч відрізків, правим кінцем яких є q.
  • I(q) — безліч відрізків, що перетинаються в q.
segmentsIntersections(points[])
    1) Ініціалізуються Q і T. До Q заносяться всі кінці відрізків, впорядковані за координатою x, при цьому, якщо дві точки збігаються,
       то ліва кінцева точка відрізка поміщається перед правою. Якщо збігаються лише x, то точка з меншим y є меншою.
       T ← ∅
    2) while Q != ∅
           q ← min(Q);
           processPoint(q);
processPoint(q)
    1) Знайти в Q всі відрізки, які містять q; // вони в Q будуть сусідніми, оскільки точки події, що містяться в цих відрізках, мають однакові координати;
    2) if (|L(q)| + |R(q)| + |I(q)| > 1) АБО (|I(q)| > 0)
           then Видати у відповідь точку q;
    3) if (|I(q)| = 0) І (|L(q)|+|R(q)| > 0) // у точці, яка розглядається, всі відрізки лише починаються або закінчуються;
           then I(q) ← I(q) ∪ L(q) ∪ R(q); // додати в I(q) L(q) і R(q)
    4) Видалити з T R(q) і I(q);
    5) Вставити в T I(q) і L(q);
    // із T були видалені всі відрізки з безліччю I(q), тепер же вставляються назад у зміненому порядку після точки перетину;
    6) if (L(q)∪I(q) = ∅) АБО (|I(q)| = |R(q)| - 1)
           then Знайти в T верхнього та нижнього сусідів q su і sl;
                newq = findIntersect(su, sl);
                if newq != NULL
                    then add(Q, newq);
    7) else
           Нехай s′ — самий верхній відрізок із L(q)∪I(q);
           Нехай su — верхній сусід s′ в T;
           Нехай s′′ — самий нижній відрізок із L(q)∪ I(q);
           Нехай sl — нижній сусід s′′ в T;
           newq = findIntersect(su, s′);
           if newq != NULL
               then add(Q, newq);
           newq = findIntersect(sl, s′′);
           if newq != NULL
               then add(Q, newq);
           // далі прибираємо квадрат пам'яті;
           newq = findIntersect(sl, su);
           if newq != NULL
               then delete(Q, newq);
           newq = findIntersect(s′′, su);
           if newq != NULL
               then delete(Q, newq);
           newq = findIntersect(sl, s′);
           if newq != NULL
               then delete(Q, newq);
findIntersect(sl, su)
    if sl і su перетинаються праворуч від замітаючої прямої (або на замітаючій прямій вище поточної точки подій)
        then return newq;
    else return NULL;

Аналіз

Нехай  — число відрізків,  — число відрізків, що перетинають точку . Тоді час на ініціалізацію Q дорівнює , на ініціалізацію T . На пошук усіх відрізків, що проходять через точку і оновлення Q, потрібно часу. На оновлення T також часу. Сумарно: , де  — число точок перетину . .

Пам'ять , завдяки тому, що віддаляються точки перетину відрізків, котрі перестали бути сусідніми, інакше було б , де .

Примітки

  1. Прапарата Ф., Шеймос М. Обчислювальна геометрія: Вступ = Computational Geometry An introduction. — М. : Мир, 1989. — 478 с.
  2. Ласло М. Обчислювальна геометрія та комп'ютерна графіка на C++. — М. : БИНОМ, 1997. — 304 с.

Література

  • Берг М., Чеонг О., Кревельд М., Овермарс М. Вычислительная геометрия. Алгоритмы и приложения = Computational Geometry: Algorithms and Applications. — М. : ДМК-Пресс, 2016. — 438 с. — ISBN 978-5-97060-406-9.
  • Mark de Berg, Marc van Kreveld, Mark Overmars, Otfried Schwarzkopf. Computational Geometry: Algorithms and Applications. — Springer, 2000. — 368 с.
  • Прапарата Ф., Шеймос М. Вычислительная геометрия: Введение = Computational Geometry An introduction. — М. : Мир, 1989. — 478 с.
  • Ласло М. Вычислительная геометрия и компьютерная графика на C++. — М. : БИНОМ, 1997. — 304 с.
  • Т. Кормен, Ч. Лейзерсон, Р. Рівест, К. Штайн. Алгоритми. Побудова й аналіз = Introduction to Algorithms. — 2-e вид. — “Вільямс”, 2005. — 1296 с.

Посилання

This article is issued from Wikipedia. The text is licensed under Creative Commons - Attribution - Sharealike. Additional terms may apply for the media files.