जाँचें कि क्या एक बिंदु पायथन के साथ एक बहुभुज के भीतर आता है


13

मैंने पुस्तकालयों का उपयोग करके कोड के कई उदाहरणों की कोशिश की है जैसे कि आकृतिफाइल, फियोना, और ओगर यह जांचने का प्रयास करना कि क्या एक बिंदु (x, y) आर्कपॉप (और इस प्रकार आकृति स्वरूप में) के साथ बनाई गई एक बहुभुज की सीमाओं के भीतर आता है। हालांकि कोई भी उदाहरण मल्टीप्लगॉन के साथ अच्छी तरह से काम नहीं करता है, हालांकि वे नियमित, एकल बहुभुज आकार के साथ ठीक करते हैं। कुछ स्निपेट मैंने आज़माए हैं:

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

पहला उदाहरण एक समय में एक एकल बहुभुज के साथ ठीक काम करता है, लेकिन जब मैं अपने मल्टीप्लगॉन शेपइल में किसी एक आकृति के भीतर एक बिंदु को इनपुट करता हूं तो यह "आउट" हो जाता है, भले ही यह कई हिस्सों में से एक के अंदर पड़ता हो।

दूसरे उदाहरण के लिए मुझे एक त्रुटि मिलती है "ऑब्जेक्ट का प्रकार 'ज्योमेट्री' में कोई लेन () नहीं है" जो मुझे लगता है क्योंकि ज्यामिति क्षेत्र को सामान्य, अनुक्रमित सूची / सरणी के रूप में नहीं पढ़ा जा सकता है।

मैंने अतिरिक्त रूप से बहुभुज कोड में वास्तविक बिंदु को बदलने की कोशिश की जैसा कि यह सुनिश्चित करने के लिए यहां बताया गया है कि यह उस कोड का हिस्सा नहीं था जो काम नहीं करता था। और जब कि लिंक के उदाहरण सरल बहुभुज आकार के साथ ठीक काम करते हैं तो मुझे ठीक से परीक्षण करने के लिए मेरे जटिल मल्टीप्लगॉन नहीं मिल सकते हैं।

इसलिए मैं परीक्षण के लिए किसी अन्य तरीके के बारे में नहीं सोच सकता कि क्या एक बिंदु एक बहुभुज आकार के भीतर अजगर के माध्यम से गिरता है ... हो सकता है कि वहाँ अन्य पुस्तकालय हैं जो मुझे याद आ रहे हैं?


आपका दूसरा उदाहरण ऐसा लग रहा है जैसे बहुभुज को बहुभुज से जोड़ सकता है? यह केवल बहुभुज के पहले भाग के खिलाफ बिंदु की जाँच कर सकता है। बिंदु को विभिन्न भागों में घुमाने का प्रयास करें और देखें कि क्या चेक कभी सफल होता है।
obrl_soil

@obrl_soil आपके सुझाव के लिए धन्यवाद। हालाँकि, दूसरा उदाहरण कभी भी त्रुटि संदेश के कारण काम नहीं करता है जो मैंने ऊपर वर्णित किया था (प्रकार की वस्तु 'ज्योमेट्री' का कोई लेन नहीं है ()) "क्या मैं मल्टीपॉलगॉन (ज्यामिति) या बस बहुभुज (ज्यामिति) की कोशिश करता हूं। मैंने कई बिंदुओं की कोशिश की है। पहला उदाहरण और केवल मुख्य बहुभुज के भीतर काम करने वाले। आशा है कि यह स्पष्टीकरण मदद करता है।
संयमी

हाँ, मुझे लगता है कि आपको polygon = Polygon(geometry)किसी प्रकार के प्रयास लूप से बदलने की आवश्यकता है जहां यह स्विच polygon = MultiPolygon(geometry)होता है यदि वह त्रुटि होती है।
obrl_soil

आपके पहले उदाहरण में समस्या पहले लूप में है।
xunilk

जवाबों:


24

शेपफाइल्स के पास कोई प्रकार मल्टीपॉलीगॉन (प्रकार = बहुभुज) नहीं है, लेकिन वे वैसे भी उनका समर्थन करते हैं (सभी छल्ले एक विशेषता में संग्रहीत हैं = बहुभुजों की सूची, बहुभुज को बहुभुज में परिवर्तित करने पर देखें )

समस्या

यहां छवि विवरण दर्ज करें

यदि मैं एक मल्टीप्लगॉन शेपफाइल खोलता हूं, तो ज्यामिति 'बहुभुज' है

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

फियोना के साथ समाधान 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)])}

फियोना ने मल्टीपॉलिगन के रूप में फीचर की व्याख्या की और आप क्यूजीआईएस, आर्कजीआईएस, पोस्टजीआईएस, आदि (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)

समाधान 2 pyshp (शेपफाइल) और geo_interface (GeoJSON like) प्रोटोकॉल के साथ

यह 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)

ओग्रा और जियोइंटरफेस प्रोटोकॉल के साथ समाधान 3 ( पायथन जियोइंटरफेस एप्लिकेशन )

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)

जियोपैन्डस के साथ समाधान 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 मल्टीपोलियन की सीमाओं के भीतर आता है


यहाँ थोड़ा पुराना धागा, लेकिन आप multi = shape(polys.shapeRecords()[0].shape.__geo_interface__)समाधान 2 में कैसे कॉल करते हैं ? मुझे किसी आकार () पद्धति से कॉल नहीं मिल सकती है shapefile.py। मैंने भी कोशिश की है shapefile.Shape(); इसके लिए एक वर्ग है, लेकिन यह काम नहीं करता है।
pstatix

आगे, आपको within()विधि कहां से मिलेगी ?
pstatix

1
शेपली ( 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'
एरॉन ब्रैमसन

6

आपके पहले उदाहरण में समस्या इस लूप में है:

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

यह केवल अंतिम सुविधा बिंदुओं को जोड़ता है। मैंने इस आकृति के साथ अपने दृष्टिकोण की कोशिश की:

यहां छवि विवरण दर्ज करें

मैंने आपका कोड संशोधित किया है:

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 के पायथन कंसोल पर चलाया गया था और परिणाम था:

यहां छवि विवरण दर्ज करें

यह पूरी तरह से और अब काम करता है, आप जांच सकते हैं कि क्या एक बिंदु (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फ़ंक्शन को यह जांचने के लिए कॉल कर सकते हैं कि क्या बिंदु आकृति के भीतर है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.