(Этот подход основан на идее, аналогичной подходу @GarethRees: во-первых, дешево определите, какие пары многоугольников вам не нужно проверять на включение. Как только количество пар, все еще необходимое для проверки, станет приемлемым, выполните точное (дорогое) геометрическое проверить.)
Для каждого многоугольника p легко вычислить ограничивающий прямоугольник, то есть левый, правый, верхний и нижний, так что давайте сделаем это в первую очередь. Например. слева: p.L = min { x : (x,y) is a vertex of p }
Время линейно зависит от количества точек.
Чтобы не сравнивать каждый многоугольник друг с другом, вы можете разделить область на сетку 2x2. Предположим, что ширина и высота области соответственно задаются Dx
и Dy
, тогда вы можете создать девять наборов top,bottom,left,right,topright,topleft,bottomright,bottomleft,rest
и сделать следующее:
for p in polygons:
in_top = p.B > Dy/2
in_bottom = p.T < Dy/2
in_left = p.R < Dx/2
in_right = p.L > Dx/2
if in_top:
if in_left:
add p to topleft
elsif in_right:
add p to topright
else:
add p to top
elsif in_bottom:
if in_left:
add p to bottomleft
elsif in_right:
add p to bottomright
else:
add p to bottom
if in_right and not (in_top or in_bottom):
add p to right
elsif in_left and not (in_top or in_bottom):
add p to left
if not (in_top or in_bottom or in_left or in_right):
add p to rest
Это снова линейное время. Каждый многоугольник был разделен на наиболее "плотно" содержащий сектор. Что вы этим приобрели? Что ж, вы знаете, например, что для любого многоугольника p
в left
не может быть никаких отношений включения с набором right
, поэтому вам не нужно их сравнивать. Аналогично между bottomleft
и right
, bottomleft
и topleft
и так далее. Вот как это будет выглядеть на вашем примере:
Dx/2
+----------------------|---------------------+
| | |
| +----------------+ | +--------+ |
| | | | / | |
| | +--------+ | | / | |
|___|___|________|___|_|____ /__+===d(2)=+___|_ Dy/2
| | | | | | / | |
| | +---b(3)-+ | | / | +---+ |
| | | | +-----+ | | |
| +-----------c(2)-+ | e(2)+ |
| | |
+----------------------|----------------a(1)-+
So rest = {a}, top = {}, bottom = {}, left = {b,c}, right = {d}
topleft = {}, topright = {}, bottomleft = {}, bottomright = {e}
Итак, теперь вам нужно сравнить (с дорогостоящим точным чеком) не более b
с c
, d
с e
и a
со всеми остальными - на самом деле, если вы заказываете чеки с умом, вам не нужно будет сравните a
со всеми остальными, потому что включение является транзитивным, поэтому, если вы заметили, что c
включает b
, а a
включает c
, тогда вам не нужно проверять, включает ли a
b
.
Другой момент заключается в том, что вы можете применить приведенное выше рассуждение рекурсивно. Скажем, например, набор topright
слишком велик на ваш вкус; затем вы можете применить тот же метод, дополнительно разделив этот субрегион (просто необходимо правильно вести бухгалтерский учет).
person
mitchus
schedule
29.01.2013
O(n log n)
, но да, это усложняется ... - person Samuel Audet   schedule 23.01.2013