Предикат "левый поворот" — различия между версиями
м |
|||
Строка 55: | Строка 55: | ||
boolean Bounding_Box(точка A, точка B, точка C, точка D) | boolean Bounding_Box(точка A, точка B, точка C, точка D) | ||
− | if ( | + | 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; |
Версия 21:41, 26 октября 2011
Даны два отрезка 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;