Предикат "левый поворот" — различия между версиями
Строка 22: | Строка 22: | ||
}} | }} | ||
Распишем подробнее: | Распишем подробнее: | ||
− | <tex dpi = | + | <tex dpi = 120>(b - a)\times(c - a) = (b_x - a_x)(c_y - a_y) - (b_y - a_y)(c_x - a_x) = A - B</tex> |
Какие при этом у нас будут погрешности? | Какие при этом у нас будут погрешности? | ||
Допустим, что все числа положительные и будем писать без модулей: | Допустим, что все числа положительные и будем писать без модулей: | ||
− | + | '''Замечание:''' при сложении складываются абс. погрешности,при умножении складываются отн. погрешности. | |
<tex dpi = "150"> \delta (b - a)\times(c - a) = A \epsilon (\frac{(b_x + a_x)}{(b_x \cdot a_x)} + \frac{(c_y + a_y)}{(c_y \cdot a_y)}) + B \epsilon (\frac{(b_y + a_y)}{(b_y \cdot a_y)} + \frac{(c_x + a_x)}{(c_x \cdot a_x)})</tex> | <tex dpi = "150"> \delta (b - a)\times(c - a) = A \epsilon (\frac{(b_x + a_x)}{(b_x \cdot a_x)} + \frac{(c_y + a_y)}{(c_y \cdot a_y)}) + B \epsilon (\frac{(b_y + a_y)}{(b_y \cdot a_y)} + \frac{(c_x + a_x)}{(c_x \cdot a_x)})</tex> | ||
− | Заметим, что все координаты (а значит и наши вычисления) производятся в вещественных числах, а это значит, что при вычислениях мы можем допустить ошибку. | + | Заметим, что все координаты (а значит и наши вычисления) производятся в вещественных числах, а это значит, что при вычислениях мы можем допустить ошибку. Более точно определить знак нашего выражения поможет вычисление с [[Интервальная арифметика |"интервальной арифметикой"]]. Все исходные переменные будут вырожденными интервалами. Из-за погрешностей, возникающих при округлении вещественных чисел, истинные значения операций нам будут неизвестны, но они обязательно будет содержаться в посчитанных интервалах. Для точного вычисления необходимо |
+ | фильтрованное вычисление предикатов. | ||
<tex dpi = 140>\overbrace {(b - a)\times(c - a)}^{v} \approx \overbrace{(b_x \ominus a_x)\otimes(c_y \ominus a_y) \ominus (b_y \ominus a_y)\otimes(c_x \ominus a_x)}^{\tilde{v}} =</tex> | <tex dpi = 140>\overbrace {(b - a)\times(c - a)}^{v} \approx \overbrace{(b_x \ominus a_x)\otimes(c_y \ominus a_y) \ominus (b_y \ominus a_y)\otimes(c_x \ominus a_x)}^{\tilde{v}} =</tex> | ||
Строка 64: | Строка 65: | ||
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)) | 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))) | || ((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))) | ||
− | + | вернуть false; | |
− | + | вернуть true; |
Версия 22:29, 30 ноября 2011
Даны два отрезка, которые задаются начальной и конечной точками
и определяются как множества точек . Требуется проверить существование множества их общих точек. Для определения этого факта в вычислительной геометрии используется предикат "левый поворот" (или "по часовой стрелке"). Рассмотрим возможные расположения точек и самих отрезков относительно друг друга:Определим, лежат ли точки концов отрезков по разные стороны от другого отрезка.
Определение: |
Распишем подробнее:
Какие при этом у нас будут погрешности? Допустим, что все числа положительные и будем писать без модулей:
Замечание: при сложении складываются абс. погрешности,при умножении складываются отн. погрешности.
Заметим, что все координаты (а значит и наши вычисления) производятся в вещественных числах, а это значит, что при вычислениях мы можем допустить ошибку. Более точно определить знак нашего выражения поможет вычисление с "интервальной арифметикой". Все исходные переменные будут вырожденными интервалами. Из-за погрешностей, возникающих при округлении вещественных чисел, истинные значения операций нам будут неизвестны, но они обязательно будет содержаться в посчитанных интервалах. Для точного вычисления необходимо фильтрованное вычисление предикатов.
;
Именно поэтому, когда угол между отрезками АВ и АС крайне мал, мы можем получить неверное значение предиката.
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))) вернуть false; вернуть true;