Для тех, кто хотел бы понять, как работает метод, написанный Дином Пови выше, вот объяснение:
Метод смотрит на «луч», который начинается в тестируемом месте и простирается до бесконечности справа.оси XДля каждого сегмента полигона он проверяет, пересекает ли его луч.Если общее количество пересечений сегмента нечетное, то проверяемая точка считается внутри многоугольника, в противном случае - снаружи.
Чтобы понять, как рассчитывается пересечение, рассмотрим следующий рисунок:
v2
o
/
/ c (intersection)
o--------x----------------------> to infinity
t /
/
/
o
v1
Для того, чтобы произошло пересечение, tests.y должен находиться между значениями y вершин сегмента (v1 и v2),Это первое условие оператора if в методе.Если это то, что происходит, то горизонтальная линия должна пересекать сегмент.Осталось только установить, происходит ли пересечение справа от тестируемой точки или слева от нее.Для этого необходимо найти координату x точки пересечения, а именно:
t.y - v1.y
c.x = v1.x + ----------- * (v2.x - v1.x)
v2.y - v1.y
Все, что остается сделать, - это изучить тонкости:
- Если v1.y == v2.y тогда луч проходит вдоль сегмента, и, следовательно, сегмент не влияет на результат.Действительно, первая часть оператора if в этом случае возвращает false.
- Код сначала умножается, а затем делится.Это сделано для поддержки очень небольших различий между v1.x и v2.x, которые могут привести к нулю после деления из-за округления.
- Наконец, проблема пересечения именно на вершине должна быть решена.Рассмотрим следующие два случая:
o o
| \ o
| A1 C1 \ /
| \ / C2
o--------x-----------x------------x--------> to infinity
/ / \
A2 / B1 / \ B2
/ / \
o / o
o
Теперь, чтобы проверить, работает ли он, проверьте сами, что возвращается для каждого из 4 сегментов условием if в теле метода.Вы должны обнаружить, что сегменты выше луча (A1, C1, C2) получают положительный результат, а сегменты ниже него (A2, B1, B2) - отрицательный.Это означает, что вершина A добавляет нечетное число (1) к счету пересечений, в то время как B и C дают четное число (0 и 2 соответственно), что является именно тем, что требуется.A действительно является реальным пересечением многоугольника, в то время как B и C являются всего лишь двумя случаями «пролета».