Eu tentei vários exemplos de código usando bibliotecas como shapefile, fiona e ogr para tentar verificar se um ponto (x, y) está dentro dos limites de um multipolígono criado com o ArcMap (e, portanto, no formato shapefile). No entanto, nenhum dos exemplos funciona bem com multipolígonos, embora funcione bem com arquivos de forma regulares, de polígono único. Alguns trechos que tentei estão abaixo:
# First example using shapefile and shapely:
from shapely.geometry import Polygon, Point, MultiPolygon
import shapefile
polygon = shapefile.Reader('shapefile.shp')
polygon = polygon.shapes()
shpfilePoints = []
for shape in polygon:
shpfilePoints = shape.points
polygon = shpfilePoints
poly = Polygon(poly)
point = Point(x, y)
# point in polygon test
if polygon.contains(point):
print 'inside'
else:
print 'OUT'
# Second example using ogr and shapely:
from shapely.geometry import Polygon, Point, MultiPolygon
from osgeo import ogr, gdal
driver = ogr.GetDriverByName('ESRI Shapefile')
dataset = driver.Open("shapefile.shp", 0)
layer = dataset.GetLayer()
for index in xrange(layer.GetFeatureCount()):
feature = layer.GetFeature(index)
geometry = feature.GetGeometryRef()
polygon = Polygon(geometry)
print 'polygon points =', polygon # this prints 'multipoint' + all the points fine
point = Point(x, y)
# point in polygon test
if polygon.contains(point):
print 'inside'
else:
print 'OUT'
O primeiro exemplo funciona bem com um único polígono de cada vez, mas quando insiro um ponto em uma das formas no meu arquivo de forma multipolígono, ele retorna "fora", mesmo que caia dentro de uma das muitas partes.
Para o segundo exemplo, recebo o erro "objeto do tipo 'Geometry' has no len ()", que eu assumo é porque o campo geometry não pode ser lido como uma lista / matriz normal indexada.
Além disso, tentei substituir o ponto real no código de polígono, conforme sugerido aqui, para garantir que não fosse a parte do código que não funcionasse. E enquanto os exemplos desse link funcionam bem com arquivos de forma de polígono simples, não consigo fazer com que meu multipolígono complexo seja testado corretamente.
Portanto, não consigo pensar em outra maneira de testar se um ponto se enquadra em um shapefile de vários polígonos via python ... Talvez haja outras bibliotecas por aí que estejam faltando?
fonte
polygon = Polygon(geometry)
por algum tipo de loop de tentativa para onde ele muda,polygon = MultiPolygon(geometry)
se esse erro ocorrer.Respostas:
Os arquivos de forma não têm o tipo MultiPolygon (type = Polygon), mas os suportam de qualquer maneira (todos os anéis são armazenados em um recurso = lista de polígonos, veja Convertendo multipolígonos enormes em polígonos )
O problema
Se eu abrir um shapefile MultiPolygon, a geometria será 'Polygon'
Solução 1 com Fiona
Fiona interpreta o recurso como um MultiPolygon e você pode aplicar a solução apresentada na junção espacial mais eficiente em Python sem QGIS, ArcGIS, PostGIS, etc. (1)
Solução 2 com pyshp (shapefile) e o protocolo geo_interface (como GeoJSON)
Este é um complemento para a resposta do xulnik.
Solução 3 com ogr e o protocolo geo_interface ( aplicativos Python Geo_interface )
Solução 4 com GeoPandas como na junção espacial mais eficiente em Python sem QGIS, ArcGIS, PostGIS, etc (2)
Os pontos 1,3,5,6 estão dentro dos limites do MultiPolygon
fonte
multi = shape(polys.shapeRecords()[0].shape.__geo_interface__)
Solução 2? Não consigo receber uma chamada para um método shape ()shapefile.py
. Eu até tenteishapefile.Shape()
; existe uma classe para isso, mas não funciona.within()
método?from shapely.geometry import shape,mapping, Point, Polygon, MultiPolygon
)File "C:\WinPython\python-3.6.5.amd64\lib\site-packages\geopandas\tools\sjoin.py", line 43, in sjoin if left_df.crs != right_df.crs:
AttributeError: 'MultiPolygon' object has no attribute 'crs'
O problema no seu primeiro exemplo está neste loop:
Acrescenta apenas os últimos pontos de recurso. Eu tentei minha abordagem com este shapefile:
Modifiquei seu código para:
O código acima foi executado no Python Console do QGIS e o resultado foi:
Funciona perfeitamente e agora você pode verificar se um ponto (x, y) se enquadra nos limites de cada recurso.
fonte
Se você estiver tentando verificar um ponto de latitude e longitude dentro de um polígono, verifique se o objeto de ponto foi criado pelo seguinte:
Ponto leva longitude, depois latitude no argumento. Não é a latitude primeiro. Você pode chamar a
polygon_object.within
função para verificar se o ponto está dentro da forma.fonte