Как преобразовать GEOS MultiLineString в Polygon?

Я разрабатываю приложение GeoDjango, в котором пользователи могут загружать файлы карт и выполнять некоторые базовые операции картирования, такие как запросы объектов внутри полигонов.

Я узнал, что иногда пользователи загружают «MultiLineString» вместо «Polygon». Это приводит к сбою запросов, ожидающих закрытой геометрии.

Как лучше всего преобразовать объект MultiLineString в многоугольник в Python?


person onurmatik    schedule 03.06.2010    source источник


Ответы (3)


Хехе, сначала я написал это:

def close_geometry(self, geometry):
   if geometry.empty or geometry[0].empty:
       return geometry # empty

   if(geometry[-1][-1] == geometry[0][0]):
       return geometry  # already closed

   result = None
   for linestring in geom:
      if result is None:
          resultstring = linestring.clone()
      else:
          resultstring.extend(linestring.coords)

   geom = Polygon(resultstring)

   return geom

но потом я обнаружил, что есть изящный маленький метод под названием convex_hull, который автоматически выполняет преобразование полигонов.

>>> s1 = LineString((0, 0), (1, 1), (1, 2), (0, 1))
>>> s1.convex_hull
<Polygon object at ...>
>>> s1.convex_hull.coords
(((0.0, 0.0), (0.0, 1.0), (1.0, 2.0), (1.0, 1.0), (0.0, 0.0)),)

>>> m1=MultiLineString(s1)
>>> m1.convex_hull
<Polygon object at...>
>>> m1.convex_hull.coords
(((0.0, 0.0), (0.0, 1.0), (1.0, 2.0), (1.0, 1.0), (0.0, 0.0)),)
person Andriy Drozdyuk    schedule 04.06.2010
comment
такое неясное название для метода, который спасает положение. Благодарю. если MultiLineString имеет более 1 LineString, convex_hull возвращает 1 Polygon, содержащий их все. если вы хотите, чтобы каждая строка LineString была отдельным многоугольником, вам все равно придется зацикливаться на MultiLineString и применять convex_hull к каждой строке LineString. - person onurmatik; 04.06.2010
comment
Правда, вы просто ни разу не упомянули, что хотите отдельный полигон для каждой линии. :-) - person Andriy Drozdyuk; 04.06.2010
comment
Выпуклая оболочка мультилинии может быть не тем, что вам нужно. Выпуклая оболочка определяет минимальный многоугольник, содержащий фигуру, и может быть не столь точным, как вам нужно, поскольку не будет включать никаких точек на границе фигуры, которые находятся внутри. т. е. если у вас есть фигура с вырванным из нее куском, вы можете не увидеть, что у фигуры есть кусок за границей. - person ianmjones; 17.06.2010
comment
Вы можете использовать shapely.geometry.Polygon, чтобы просто преобразовать строку в многоугольник. Он соединит первую и последнюю координаты. Попробуйте Polygon([(0, 0), (1, 1), (1, 2), (0, 1)]) или Polygon(s1) для получения POLYGON ((0 0, 1 1, 1 2, 0 1 , 0 0)). - person Matt; 09.10.2019

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

import geopandas as gpd
from shapely.geometry import Polygon, mapping

def linestring_to_polygon(fili_shps):
    gdf = gpd.read_file(fili_shps) #LINESTRING
    geom = [x for x in gdf.geometry]
    all_coords = mapping(geom[0])['coordinates']
    lats = [x[1] for x in all_coords]
    lons = [x[0] for x in all_coords]
    polyg = Polygon(zip(lons, lats))
    return gpd.GeoDataFrame(index=[0], crs=gdf.crs, geometry=[polyg])
person Carlos Enciso    schedule 21.07.2019

Вот модификация ответа Карлоса, она проще и возвращает не один элемент, а все строки в исходном файле.

import geopandas as gpd
from shapely.geometry import Polygon, mapping

def linestring_to_polygon(fili_shps):
    gdf = gpd.read_file(fili_shps) #LINESTRING
    gdf['geometry'] = [Polygon(mapping(x)['coordinates']) for x in gdf.geometry]
    return gdf
person Nikita Pestrov    schedule 08.05.2020