Изменения

Перейти к: навигация, поиск
м
rollbackEdits.php mass rollback
{{ready}}
== Выпуклый многоугольник ==
Начнём с того, что выпуклый Выпуклый многоугольник нам задан как замкнутая полилиния. Поэтому , поэтому для любой вершины этого многоугольника все остальные точки будут отсортированы по углу. Возьмём первую точку многоугольника и мысленно проведём от неё все лучи, содержащие диагонали. За Бинпоиском за логарифм можно пройтись бинпоиском по углам и {{Acronym|понять, в каком из них лежит точка|Для альтернативно одарённых: повороты должны различаться. А ещё кому-то может показаться неочевидным тот факт, что точка может лежать левее самой левой грани или правее самой правой. Это тоже надо сразу проверить}}. Когда мы нашли найден угол, за константное время {{Acronym|проверяемможно проверить, с какой стороны от противолежащего первой точке ребра многоугольника лежит точка|для альтернативно одарённых. Итоговый алгоритм: это проверяется поворотом * если искомая точка <tex>q</tex> лежит левее самой левой грани или правее самой правой, сразу возвращаем false* бинпоиском ищем такое ребро <tex>a_i a_{i+1}</tex>, не инцидентное самой первой точке <tex>a_0</tex> заданного многоугольника, что повороты точек <tex>a_0, a_i, q</tex> и <tex>a_0, a_{i+1}, q</tex> различаются* проверяем поворот точек <tex>a_i, a_{i+1}. , q</tex>, если он левый — точка лежит внутри, если правый — снаружи Итоговое время работы: <tex>O(\log n)</tex>.
== Невыпуклый многоугольник ==
Если [[Файл:Point in polygon.png|400px|thumb|right|Отмечены только те точки, которые являются верхними для какого-либо ребра]]Очевидно, что если пустить из точки луч, то по чётности числа пересечений с рёбрами многоугольника можно определить, внутри точка лежит или снаружи. Пустим луч, например, по иксу, переберём все рёбра и проверим их на ребрепересечение с лучом. Луч может попасть в точку, при этом прохождение через точку учтётся два раза (по разу для каждого отрезка, к которым принадлежит точка). Иногда это и есть то, сразу вернём trueчего нам хочется (когда фигура находится выше или ниже луча), но иногда нам хочется учесть только один раз. Для этого для каждого отрезка учитываем только верхнюю точку. Все случаи попадания луча в точку показаны на рисунке.
Очевидно, что, если пустить из точки луч, то по чётности числа пересечений с рёбрами многоугольника можно определить, внутри точка лежит или снаружи.Получившийся алгоритм:
Пустим луч* заведём счётчик пересечений и проинициализируем его нулём (либо просто заведём переменную типа bool, напримерпоказывающую чётность числа пересечений)* для каждого ребра <tex>ab</tex> многоугольника:** если точка запроса <tex>q</tex> лежит на этом ребре, по иксу то сразу возвращаем true** если <tex>a_y=b_y</tex>, пропускаем этот отрезок, он не влияет на чётность числа пересечений** если <tex>q_y=max(a_y, b_y)</tex> и за <tex>Oq_x < min(na_x, b_x)</tex> переберём все рёбра и проверим их на пересечение с лучом. Как проверять: сначала проверим, что ордината точки увеличим счётчик пересечений** если <tex>q_y=min(a_y, b_y)</tex>, пропустим это ребро** если <tex>q_y</tex> лежит между ординатами концов ребра<tex>a_y</tex> и <tex>b_y</tex> и поворот точек <tex>a,b,q</tex> левый, то увеличим счётчик пересечений* если число пересечений чётно, затем {{Acronym|посмотримвернём false, до ребра или после него начался луч|для альтернативно одарённых: это делается тоже поворотом}}.иначе вернём true
Луч может попасть в точку, при этом прохождение через точку учтётся два раза Время работы алгоритма составляет <tex>O(по разу для каждого отрезка, к которым принадлежит точкаn). Иногда это и есть то, чего нам хочется (когда фигура находится выше или ниже луча), но иногда нам хочется учесть только один раз. Для этого делаем такую штуку: для каждого отрезка учитываем {{Acronym|только верхнюю точку|А если отрезок горизонтальный, то забиваем на него, если точка не лежит на нём. После недолгих раздумий и разглядываний смежных отрезков станет очевидно, что на чётность числа пересечений он никак не влияет}}. Дальше {{Acronym|всё очевидно|Кому не очевидно, тот может порисовать картинки с лучом, попадающим в точку, и посчитать, сколько раз в каком случае учитывается пересечение}}</tex>.
[https://github.com/BorisMinaev/cg/blob/master/include/cg/algo/point_inside_polygon.h Реализация]
[[Категория: Вычислительная геометрия]]
1632
правки

Навигация