파이썬으로 점이 다중 다각형 내에 있는지 확인하십시오.


13

점 (x, y)가 ArcMap으로 작성된 다중 다각형의 경계 (및 shapefile 형식) 내에 있는지 확인하기 위해 shapefile, fiona 및 ogr과 같은 라이브러리를 사용하여 몇 가지 코드 예제를 시도했습니다. 그러나 멀티 폴리곤에서는 잘 작동하지 않지만 일반적인 단일 폴리곤 쉐이프 파일에서는 잘 작동합니다. 내가 시도한 일부 스 니펫은 다음과 같습니다.

# 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'

첫 번째 예제는 한 번에 하나의 다각형으로 잘 작동하지만 다중 다각형 모양 파일의 모양 중 하나에 점을 입력하면 여러 부분 중 하나에 속하더라도 "out"을 반환합니다.

두 번째 예제에서는 지오메트리 필드를 색인화 된 일반 목록 / 배열로 읽을 수 없기 때문에 " 'Geometry'유형의 객체에 len ()이 없습니다"라는 오류가 발생합니다.

추가로 작동하지 않는 코드의 일부가 아닌지 확인하기 위해 여기 에 제안 된대로 다각형 코드의 실제 지점을 바꾸려고 했습니다. 링크의 예제는 간단한 다각형 모양 파일로 잘 작동하지만 복잡한 다중 다각형을 올바르게 테스트 할 수는 없습니다.

그래서 파이썬을 통해 점이 다중 다각형 모양 파일 내에 있는지 여부를 테스트하는 다른 방법을 생각할 수 없습니다 ... 아마도 내가 누락 된 다른 라이브러리가 있습니까?


두 번째 예는 다중 다각형을 다각형으로 강제 변환하는 것 같습니다. 다중 다각형의 첫 번째 부분에 대해서만 점을 확인하는 것일 수 있습니다. 포인트를 다른 부분으로 옮기고 검사가 성공했는지 확인하십시오.
obrl_soil

@obrl_soil 제안 해 주셔서 감사합니다. 그러나 두 번째 예는 위에서 설명한 오류 메시지 ( 'Geometry'유형의 객체에는 len ()이 없습니다) "때문에 작동하지 않습니다." . 첫 번째 예와는 메인 다각형 일 이내에 그 희망이 설명이 도움이됩니다.
spartmar

예, 오류가 발생하면 polygon = Polygon(geometry)스위치가있는 try 루프 로 교체해야한다고 생각 polygon = MultiPolygon(geometry)합니다.
obrl_soil

첫 번째 예제의 문제는 첫 번째 루프에 있습니다.
xunilk

답변:


24

셰이프 파일에는 MultiPolygon (유형 = 다각형) 유형이 없지만 어쨌든 지원합니다 (모든 링은 하나의 기능에 저장됩니다 = 다각형 목록, 거대한 다중 다각형을 다각형으로 변환 참조)

문제

여기에 이미지 설명을 입력하십시오

MultiPolygon shapefile을 열면 형상은 'Polygon'입니다

multipolys = fiona.open("multipol.shp")
multipolys.schema
{'geometry': 'Polygon', 'properties': OrderedDict([(u'id', 'int:10')])}
len(multipolys)
1

Fiona를 사용한 솔루션 1

import fiona
from shapely.geometry import shape,mapping, Point, Polygon, MultiPolygon
multipol = fiona.open("multipol.shp")
multi= multipol.next() # only one feature in the shapefile
print multi
{'geometry': {'type': 'MultiPolygon', 'coordinates': [[[(-0.5275288092189501, 0.5569782330345711), (-0.11779769526248396, 0.29065300896286816), (-0.25608194622279135, 0.01920614596670933), (-0.709346991037132, -0.08834827144686286), (-0.8629961587708066, 0.18309859154929575), (-0.734955185659411, 0.39820742637644047), (-0.5275288092189501, 0.5569782330345711)]], [[(0.19974391805377723, 0.060179257362355965), (0.5480153649167734, 0.1293213828425096), (0.729833546734955, 0.03969270166453265), (0.8143405889884763, -0.13956466069142115), (0.701664532650448, -0.38540332906530095), (0.4763124199743918, -0.5006402048655569), (0.26888604353393086, -0.4238156209987196), (0.18950064020486557, -0.2291933418693981), (0.19974391805377723, 0.060179257362355965)]], [[(-0.3764404609475033, -0.295774647887324), (-0.11523687580025621, -0.3597951344430217), (-0.033290653008962945, -0.5800256081946222), (-0.11523687580025621, -0.7413572343149808), (-0.3072983354673495, -0.8591549295774648), (-0.58898847631242, -0.6927016645326505), (-0.6555697823303457, -0.4750320102432779), (-0.3764404609475033, -0.295774647887324)]]]}, 'type': 'Feature', 'id': '0', 'properties': OrderedDict([(u'id', 1)])}

Fiona는이 기능을 MultiPolygon으로 해석하고 QGIS, ArcGIS, PostGIS 등을 사용하지 않고도 Python 에서 보다 효율적인 공간 조인으로 제공되는 솔루션을 적용 할 수 있습니다 (1).

points= ([pt for pt  in fiona.open("points.shp")])
for i, pt in enumerate(points):
    point = shape(pt['geometry'])
    if point.within(shape(multi['geometry'])):
         print i, shape(points[i]['geometry'])
1 POINT (-0.58898847631242 0.17797695262484)
3 POINT (0.4993597951344431 -0.06017925736235585)
5 POINT (-0.3764404609475033 -0.4750320102432779)
6 POINT (-0.3098591549295775 -0.6312419974391805)

pyshp (shapefile)geo_interface (GeoJSON like) 프로토콜을 사용 하는 솔루션 2

이것은 xulnik의 답변에 대한 보충입니다.

import shapefile
pts = shapefile.Reader("points.shp")
polys = shapefile.Reader("multipol.shp")
points = [pt.shape.__geo_interface__ for pt in pts.shapeRecords()]
multi = shape(polys.shapeRecords()[0].shape.__geo_interface__) # 1 polygon
print multi
MULTIPOLYGON (((-0.5275288092189501 0.5569782330345711, -0.117797695262484 0.2906530089628682, -0.2560819462227913 0.01920614596670933, -0.7093469910371319 -0.08834827144686286, -0.8629961587708066 0.1830985915492958, -0.734955185659411 0.3982074263764405, -0.5275288092189501 0.5569782330345711)), ((0.1997439180537772 0.06017925736235596, 0.5480153649167734 0.1293213828425096, 0.729833546734955 0.03969270166453265, 0.8143405889884763 -0.1395646606914211, 0.701664532650448 -0.3854033290653009, 0.4763124199743918 -0.5006402048655569, 0.2688860435339309 -0.4238156209987196, 0.1895006402048656 -0.2291933418693981, 0.1997439180537772 0.06017925736235596)), ((-0.3764404609475033 -0.295774647887324, -0.1152368758002562 -0.3597951344430217, -0.03329065300896294 -0.5800256081946222, -0.1152368758002562 -0.7413572343149808, -0.3072983354673495 -0.8591549295774648, -0.58898847631242 -0.6927016645326505, -0.6555697823303457 -0.4750320102432779, -0.3764404609475033 -0.295774647887324)))
for i, pt in enumerate(points):
    point = shape(pt)
    if point.within(multi): 
        print i, shape(points[i])
1 POINT (-0.58898847631242 0.17797695262484)
3 POINT (0.4993597951344431 -0.06017925736235585)
5 POINT (-0.3764404609475033 -0.4750320102432779)
6 POINT (-0.3098591549295775 -0.6312419974391805)

ogrgeo_interface 프로토콜을 사용 하는 솔루션 3 ( Python Geo_interface 응용 프로그램 )

from osgeo import ogr
import json
def records(file):  
    # generator 
    reader = ogr.Open(file)
    layer = reader.GetLayer(0)
    for i in range(layer.GetFeatureCount()):
        feature = layer.GetFeature(i)
        yield json.loads(feature.ExportToJson())

points  = [pt for pt in records("point_multi_contains.shp")]
multipol = records("multipol.shp")
multi = multipol.next() # 1 feature
for i, pt in enumerate(points):
     point = shape(pt['geometry'])
     if point.within(shape(multi['geometry'])):
          print i, shape(points[i]['geometry'])

1 POINT (-0.58898847631242 0.17797695262484)
3 POINT (0.499359795134443 -0.060179257362356)
5 POINT (-0.376440460947503 -0.475032010243278)
6 POINT (-0.309859154929577 -0.631241997439181)

QGIS, ArcGIS, PostGIS 등을 사용하지 않고 Python 에서 보다 효율적인 공간 조인 과 같은 GeoPandas 를 사용한 솔루션 4 (2)

import geopandas
point = geopandas.GeoDataFrame.from_file('points.shp') 
poly  = geopandas.GeoDataFrame.from_file('multipol.shp')
from geopandas.tools import sjoin
pointInPolys = sjoin(point, poly, how='left')
grouped = pointInPolys.groupby('index_right')
list(grouped)
[(0.0,      geometry                               id_left  index_right id_right  

1  POINT (-0.58898847631242 0.17797695262484)       None      0.0        1.0 
3  POINT (0.4993597951344431 -0.06017925736235585)  None      0.0        1.0
5  POINT (-0.3764404609475033 -0.4750320102432779)  None      0.0        1.0 
6  POINT (-0.3098591549295775 -0.6312419974391805)  None      0.0        1.0 ]
print grouped.groups
{0.0: [1, 3, 5, 6]} 

점 1,3,5,6은 MultiPolygon의 경계 내에 있습니다.


여기에 약간 오래된 스레드가 있지만 multi = shape(polys.shapeRecords()[0].shape.__geo_interface__)솔루션 2에서 어떻게 전화 합니까? 에서 shape () 메서드를 호출 할 수 없습니다 shapefile.py. 나는 심지어 시도했다 shapefile.Shape(); 그것에 대한 수업이 있지만 작동하지 않습니다.
pstatix

또한, within()방법을 어디서 얻 습니까?
pstatix

1
from Shapely ( from shapely.geometry import shape,mapping, Point, Polygon, MultiPolygon)
유전자

솔루션 4를 사용하여이 오류가 발생합니다.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'
Aaron Bramson

6

첫 번째 예제의 문제는 다음과 같습니다.

...
shpfilePoints = []
for shape in polygon:
    shpfilePoints = shape.points
...

마지막 특징점 만 추가합니다. 이 shapefile을 사용하여 접근 방식을 시도했습니다.

여기에 이미지 설명을 입력하십시오

코드를 다음과 같이 수정했습니다.

from shapely.geometry import Polygon, Point, MultiPolygon
import shapefile 

path = '/home/zeito/pyqgis_data/polygon8.shp'

polygon = shapefile.Reader(path) 

polygon = polygon.shapes() 

shpfilePoints = [ shape.points for shape in polygon ]

print shpfilePoints

polygons = shpfilePoints

for polygon in polygons:
    poly = Polygon(polygon)
    print poly

위 코드는 QGIS의 Python 콘솔에서 실행되었으며 결과는 다음과 같습니다.

여기에 이미지 설명을 입력하십시오

완벽하게 작동하며 이제 점 (x, y)이 각 피처의 경계 내에 있는지 여부를 확인할 수 있습니다.


0

다각형 내에서 위도, 경도 점을 확인하려는 경우 다음에 의해 점 개체가 작성되어 있는지 확인하십시오.

from shapely.geometry.point import Point
Point(LONGITUDE, LATITUDE)
..
poly.within(point) # Returns true if the point within the 

점은 경도를 취한 다음 논쟁에서 위도를 취합니다. 우선 위도가 아닙니다. polygon_object.within점이 도형 내에 있는지 확인하기 위해 함수를 호출 할 수 있습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.