Предикат "левый поворот"
Даны два отрезка AB и CD (они могут вырождаться в точки). Требуется проверить, пересекаются они на плоскости или нет. Для упрощения определения этого факта в вычислительной геометрии используется предикат "левый поворот" (или "по часовой стрелке"). Рассмотрим возможные расположения точек и самих отрезков относительно друг друга:
Одно из решений - определить, лежат ли точки концов отрезков по разные стороны от другого отрезка.
Определение: |
Распишем подробнее:
Какие при этом у нас будут погрешности? Допустим, что все числа положительные и будем писать без модулей:
NB: при сложении складываются абс. погрешности,при умножении складываются отн. погрешности.
Заметим, что все координаты (а значит и наши вычисления) производятся в вещественных числах, а это значит, что при вычислениях мы можем допустить ошибку. Точно определить знак нашего выражения поможет вычисление с "интервальной арифметикой". Все исходные переменные будут вырожденными интервалами. Из-за погрешностей, возникающих при округлении вещественных чисел, истинные значения операций нам будут неизвестны, но они обязательно будет содержаться в посчитанных интервалах.
TODO: тут еще чего-то написать...
Посмотрим внимательнее на наш предикат. Ошибка раскрывается тогда, когда угол между отрезками АВ и АС крайне мал.
Bounding box
Ещё следует обратить внимание на граничные случаи, когда какие-то точки попадают на саму прямую. При этом возникает единственный особый случай, когда вышеописанные проверки ничего не дадут — случай, когда оба отрезка лежат на одной прямой. Этот случай надо рассмотреть отдельно. Для этого достаточно проверить, что проекции этих двух отрезков на оси X и Y пересекаются (часто эту проверку называют "проверкой на bounding box").
Псевдокод:
boolean Bounding_Box(точка A, точка B, точка C) if ((A.xx >= C.xx && C.xx >= B.xx || A.xx <= C.xx && C.xx <= B.xx) && (A.yy >= C.yy && C.yy >= B.yy || A.yy <= C.yy && C.yy <= B.yy)) вернуть true вернуть false
или
boolean Bounding_Box(точка A, точка B, точка C, точка D) if ((A.xx > C.xx && A.xx > D.xx && B.xx > C.xx && B.xx > D.xx || A.xx < C.xx && A.xx < D.xx && B.xx < C.xx && B.xx < D.xx) || (A.yy > C.yy && A.yy > D.yy && B.yy > C.yy && B.yy > D.yy || A.yy < C.yy && A.yy < D.yy && B.yy < C.yy && B.yy < D.yy)) return false; return true;