Изящный метод .contains (), но включая границы?

Я работаю с многоугольниками Shapely, и мне нужен способ удалить все более мелкие многоугольники в большом многоугольнике. Я пробовал использовать метод .contains(), который предоставляет Shapely, но метод не возвращает True, если меньший многоугольник не полностью находится внутри большого многоугольника.

В принципе, мне нужен метод типа .contains(), но он возвращает True, если многоугольник находится на границе внешнего многоугольника, как на картинке.

здесь.

Вот полигоны с картинки, представленные в формате wkt:

Зеленая:

POLYGON Z ((14.4265764858233823 45.3396418051734784 0.0000000000000000, 14.4267228266679606 45.3395430970275015 0.0000000000000000, 14.4266753563381904 45.3394727193694536 0.0000000000000000, 14.4265290154936121 45.3395714275154376 0.0000000000000000, 14.4265764858233823 45.3396418051734784 0.0000000000000000))`  

Красный:

POLYGON Z ((14.4265450394689161 45.3395951840357725 0.0000000000000000, 14.4265695507109317 45.3395786509942837 0.0000000000000000, 14.4265802185605700 45.3395944667317679 0.0000000000000000, 14.4265982245953417 45.3395823215079616 0.0000000000000000, 14.4265715327703994 45.3395427492501426 0.0000000000000000, 14.4265290154936121 45.3395714275154376 0.0000000000000000, 14.4265450394689161 45.3395951840357725 0.0000000000000000))

Я также пробовал использовать метод .intersects(), но он возвращает True для многоугольников за пределами данного многоугольника, у которых есть некоторые общие границы, которые мне не нужны.

Надеюсь, вы понимаете, что мне нужно, и я благодарен, если кто-то знает решение этой проблемы.


person kfilipcic    schedule 06.07.2019    source источник
comment
contains должно нормально работать. Создайте, например, два простых квадратных многоугольника один внутри другого с общей стороной, чтобы убедиться, что это работает. В вашем случае, вероятно, проблема с точностью. Не могли бы вы дать определение обоих полигонов, чтобы мы могли воспроизвести проблему?   -  person Georgy    schedule 06.07.2019
comment
Я добавил к вопросу wkt строк многоугольников. Я полагаю, что информации о многоугольниках достаточно? Это может быть проблемой с точностью, но мне нужна именно эта точность. Также спасибо за ответ и правки от вас и @eyllanesc. Это мой первый вопрос, поэтому я не совсем уверен, что делаю.   -  person kfilipcic    schedule 06.07.2019
comment
Примеры многоугольников в формате wkt, которые вы предоставили, фактически обрезаны и не отображают все цифры (вы, вероятно, только что сделали polygon.wkt, верно?). Потому что, если я загружу их и использую green.contains(red), он покажет True. Чтобы получить все цифры, не могли бы вы использовать _4 _ с trim=False аргументом и добавить их в вопрос? Итак, это будет: from shapely import wkt; wkt.dumps(polygon, trim=False)   -  person Georgy    schedule 06.07.2019
comment
Я добавил вывод из wkt.dumps. Да, я просто использовал polygon.wkt. (Я не очень опытен в использовании shapely). Спасибо за информацию   -  person kfilipcic    schedule 06.07.2019


Ответы (1)


Обычно метод contains должен работать при проверке, находится ли один многоугольник внутри другой, и у них есть общие границы. Например, если вы возьмете следующий простой пример, он будет работать должным образом:

from shapely.geometry import Polygon

a = Polygon([(0, 0), (2, 0), (2, 2), (0, 2)])
b = Polygon([(0, 0), (1, 0), (1, 1), (0, 1)])
a.contains(b)
# True

введите описание изображения здесь

Но довольно часто случается, что из-за ошибок точности внутренний многоугольник немного выходит за пределы внешнего, и тест не проходит.

Вот, например, я нарисовал ваши многоугольники и увеличил левую верхнюю точку пересечения:

import matplotlib.pyplot as plt

plt.plot(*green.exterior.xy, c='g')
plt.plot(*red.exterior.xy, c='r')

Вы можете видеть, что линии не идеально ложатся друг на друга:

введите описание изображения здесь

Есть несколько способов справиться с этой проблемой. Первый, например, был предложен в Как бороться с ошибками округления в Shapely и в некоторых проблемах Shapely на GitHub:

  1. Уменьшите меньший многоугольник или немного увеличьте больший:

    big.contains(small.buffer(-1e-14))
    # True
    big.buffer(1e-14).contains(small)
    # True
    
  2. Убедитесь, что площадь меньшего многоугольника, лежащего вне большого, близка к нулю:

    small.difference(big).area < 1e-14
    # True
    
  3. Проверьте, близки ли расстояния от каждой вершины меньшего многоугольника к большему к нулю:

    from shapely.geometry import Point
    
    vertices = map(Point, small.exterior.coords)
    distances = map(big.distance, vertices)
    all(distance < 1e-14 for distance in distances) 
    # True
    

Возможно, есть и другие способы выполнить тест, но я думаю, что этого будет достаточно.

person Georgy    schedule 06.07.2019
comment
Первое предоставленное вами решение делает свое дело. Спасибо! Второе решение действительно работает, но я не уверен, будет ли оно иногда возвращать True для полигонов, близких к большему полигону. Что касается третьего решения, оно не работает в моем случае, потому что оно возвращает True для внешних полигонов, близких к большему, что мне не нужно в моем случае. - person kfilipcic; 06.07.2019
comment
@kfilipcic просмотрите тур - person eyllanesc; 06.07.2019