Рассчитать перекрытие двух угловых интервалов - PullRequest
2 голосов
/ 20 марта 2019

Допустим, у меня есть два интервала,

[a1, a2] and [b1, b2]

Где a1,a2,b1,b2 все находятся в диапазоне [0, 2 pi].Теперь, учитывая эти два интервала, я хочу найти их перекрывающийся интервал.Это довольно сложно.Поскольку примером двух интервалов является

[5, 1] and [0, 6]

, которые приведены ниже (красные области - это интервалы).

enter image description here

Обратите внимание, что эти два интервала возвращают перекрывающийся интервал, состоящий из двух интервалов:

[0,1] and [5,6]

Существует несколько различных случаев, которые необходимо обработать, есть ли какой-нибудь известный алгоритм, который это делает?

Ответы [ 2 ]

1 голос
/ 21 марта 2019

Я не знаю о существующем алгоритме (что не означает, что его нет), но вот один, который я придумал.

Как уже упоминал @Michael Kenzel, числа не увеличиваются монотонно, что делает все очень сложным.

Но мы можем заметить, что мы можем развернуть круг на числовой линии. Тогда каждый интервал появляется бесконечно много раз с периодом 2π.

Давайте сначала определим нормализовать операцию следующим образом:

normalize([a, b]):
    if (a > b):
        a -= 2π

Используя эту операцию, мы развертываем оба наших интервала в [-2π, 2π] часть числовой линии.

Пример интервалов:

[2, 5] -> [2, 5]

[4, π] -> [-2, π]

illustration on a circle

mapping onto a number line

Два интервала на окружности могут перекрываться не более 2 раз.

(У меня нет правильного доказательства этого, но интуитивно понятно: перекрытие начинается, когда один интервал начался, а другой не закончился. Это может произойти только один раз в числовой строке и дважды в нашем случае.)

Просто глядя на нормализованные интервалы, мы можем пропустить одно из совпадений. В приведенном выше примере мы обнаружили бы перекрытие [2, π] и пропуск [4, 5]. Это происходит потому, что мы развернули исходные интервалы не на [0, 2π], а на вдвое большую часть числовой линии, [-2π, 2π].

Чтобы исправить , для этого мы можем, например, взять часть, которая падает на отрицательную линию, и сдвинуть ее на 2π вправо, таким образом, имея все части в оригинале [0, 2π ]. Но это вычислительно неэффективно, так как в худшем случае нам придется тестировать 2 фрагмента за один интервал против 2 фрагментов другого интервала - всего 4 операции.

Вот иллюстрация такого неудачного примера, который потребует 4 сравнений: an unlucky example with 4 comparisons

Если мы хотим быть немного более эффективными, мы попытаемся выполнить только 2 операции интервал-интервал. Нам не нужно больше, поскольку будет не более двух перекрытий. Поскольку интервалы повторяются бесконечно на числовой линии с периодом 2π, мы можем просто взять 2 соседних дубликата первого интервала и сравнить их со вторым. Чтобы убедиться, что второй интервал будет, так сказать, между этими дубликатами, мы можем взять тот, который начинается раньше, и добавить 2π к его обоим концам. Или вычтите 2π из того, что начинается позже.

Будет не более двух перекрытий, которые затем могут быть возвращены к интервалу [0, 2π] путем сложения / вычитания 2π.

В нашем исходном примере это будет выглядеть так: result for the original example

Подводя итог:

given [a, b], [c, d]
[A, B] = normalize([a, b])
[C, D] = normalize([c, d])
if (A < C):
    [E, F] = [A + 2π, B + 2π]
else:
    [E, F] = [A - 2π, B - 2π]
I_1 = intersect([A, B], [C, D])
I_2 = intersect([E, F], [C, D])
bring I_1 and I_2 back to the [0, 2π]

Я думаю, что не пропустил ни одного углового случая, но не стесняйтесь указывать на любую ошибку в моей логике.

0 голосов
/ 21 марта 2019

Пока у вас есть интервалы, когда числа просто монотонно растут, все просто;вы просто берете max() минимумов и min() максимумов и все готово.Казалось бы, основным источником осложнений является тот факт, что у вас могут быть интервалы, которые заключаются в 0, т. Е. Числа, являющиеся частью интервала, не монотонно увеличиваются.Мне кажется, что один из способов обойти эту проблему - просто рассматривать интервалы, которые обертывают, как не один интервал, а объединение двух интервалов.Например, представьте [5, 1] ​​как [5, 2 pi] ∪ [0, 1].Тогда задача нахождения пересечения [5, 1] ​​и [0, 6] превращается в задачу нахождения пересечения [5, 2 pi] и [0, 6], а также пересечения [0, 1] и [0, 6].Математически вы бы воспользовались законом распределения пересечений множеств , т. Е. (A ∪ B) ∩ C = (A ∩ C) ∪ (B ∩ C).Таким образом, учитывая два интервала A и B, мы начнем с разбиения каждого на два интервала, A1 и A2, и B1 и B2, где A1 и B1 начинаются после 0 и заканчиваются до 2 pi, а A2 и B2 начинаются до 2 pi иконец до 2 пи.Разрезая вот так, мы можем вычислить наши пересечения как

(A1 ∪ A2) ∩ (B1 ∪ B2) = (A1 ∩ (B1 ∪ B2)) ∪ (A2 ∩ (B1 ∪ B2) = (A1 ∩B1) ∪ (A1 ∩ B2) ∪ (A2 ∩ B1) ∪ (A2 ∩ B2)

, т. Е. Вычисление пересечения всех комбинаций A1, A2, B1 и B2…

...