web-dev-qa-db-ja.com

緯度と経度を含むジオポイントがシェープファイル内にあるかどうかを確認します

ジオポイントが特定のシェープファイルの領域内にあるかどうかを確認するにはどうすればよいですか?

シェープファイルをPythonでロードできましたが、それ以上は取得できません。

21
Gerald Bäck

よすけさばいの答えを改造したものです。

私が探していた点がシェープファイルと同じ投影システムにあることを確認したかったので、そのためのコードを追加しました。

彼がply = feat_in.GetGeometryRef()に対して包含テストを行っている理由が理解できなかったので(私のテストでは、それがなくても同様に機能するように見えました)、それを削除しました。

また、コメントを改善して、何が起こっているのかをわかりやすく説明しました(理解しているとおりです)。

#!/usr/bin/python
import ogr
from IPython import embed
import sys

drv = ogr.GetDriverByName('ESRI Shapefile') #We will load a shape file
ds_in = drv.Open("MN.shp")    #Get the contents of the shape file
lyr_in = ds_in.GetLayer(0)    #Get the shape file's first layer

#Put the title of the field you are interested in here
idx_reg = lyr_in.GetLayerDefn().GetFieldIndex("P_Loc_Nm")

#If the latitude/longitude we're going to use is not in the projection
#of the shapefile, then we will get erroneous results.
#The following assumes that the latitude longitude is in WGS84
#This is identified by the number "4326", as in "EPSG:4326"
#We will create a transformation between this and the shapefile's
#project, whatever it may be
geo_ref = lyr_in.GetSpatialRef()
point_ref=ogr.osr.SpatialReference()
point_ref.ImportFromEPSG(4326)
ctran=ogr.osr.CoordinateTransformation(point_ref,geo_ref)

def check(lon, lat):
    #Transform incoming longitude/latitude to the shapefile's projection
    [lon,lat,z]=ctran.TransformPoint(lon,lat)

    #Create a point
    pt = ogr.Geometry(ogr.wkbPoint)
    pt.SetPoint_2D(0, lon, lat)

    #Set up a spatial filter such that the only features we see when we
    #loop through "lyr_in" are those which overlap the point defined above
    lyr_in.SetSpatialFilter(pt)

    #Loop through the overlapped features and display the field of interest
    for feat_in in lyr_in:
        print lon, lat, feat_in.GetFieldAsString(idx_reg)

#Take command-line input and do all this
check(float(sys.argv[1]),float(sys.argv[2]))
#check(-95,47)

このサイトこのサイト 、および このサイト は、投影チェックに関して役に立ちました。 EPSG:4326

17
Richard

別のオプションは、Shapely(PostScriptのエンジンであるGEOSに基づくPythonライブラリ)とFiona(基本的にファイルの読み取り/書き込み用)を使用することです。

import fiona
import shapely

with fiona.open("path/to/shapefile.shp") as fiona_collection:

    # In this case, we'll assume the shapefile only has one record/layer (e.g., the shapefile
    # is just for the borders of a single country, etc.).
    shapefile_record = fiona_collection.next()

    # Use Shapely to create the polygon
    shape = shapely.geometry.asShape( shapefile_record['geometry'] )

    point = shapely.geometry.Point(32.398516, -39.754028) # longitude, latitude

    # Alternative: if point.within(shape)
    if shape.contains(point):
        print "Found shape for point."

ポリゴンが大きい/複雑な場合(たとえば、海岸線が非常に不規則な一部の国のシェープファイル)、ポイントインポリゴンテストを実行するとコストが高くなる可能性があることに注意してください。場合によっては、バウンディングボックスを使用して、より集中的なテストを行う前に、物事をすばやく除外することができます。

minx, miny, maxx, maxy = shape.bounds
bounding_box = shapely.geometry.box(minx, miny, maxx, maxy)

if bounding_box.contains(point):
    ...

最後に、大きな/不規則なシェープファイルのロードと解析には時間がかかることを覚えておいてください(残念ながら、これらのタイプのポリゴンは、多くの場合、メモリに保持するのにもコストがかかります)。

31
Clint Harris

pyshp および shapely に基づく簡単なソリューションを次に示します。

シェープファイルに含まれるポリゴンは1つだけだとしましょう(ただし、複数のポリゴンに簡単に適応できます)。

import shapefile
from shapely.geometry import shape, Point

# read your shapefile
r = shapefile.Reader("your_shapefile.shp")

# get the shapes
shapes = r.shapes()

# build a shapely polygon from your shape
polygon = shape(shapes[0])    

def check(lon, lat):
    # build a shapely point from your geopoint
    point = Point(lon, lat)

    # the contains function does exactly what you want
    return polygon.contains(point)
9
chilladx

私は昨日gdalのogrでpythonバインディングを使用して、あなたがやっていることをほぼ正確に行いました。このように見えました。

import ogr

# load the shape file as a layer
drv    = ogr.GetDriverByName('ESRI Shapefile')
ds_in  = drv.Open("./shp_reg/satreg_etx12_wgs84.shp")
lyr_in = ds_in.GetLayer(0)

# field index for which i want the data extracted 
# ("satreg2" was what i was looking for)
idx_reg = lyr_in.GetLayerDefn().GetFieldIndex("satreg2")


def check(lon, lat):
  # create point geometry
  pt = ogr.Geometry(ogr.wkbPoint)
  pt.SetPoint_2D(0, lon, lat)
  lyr_in.SetSpatialFilter(pt)

  # go over all the polygons in the layer see if one include the point
  for feat_in in lyr_in:
    # roughly subsets features, instead of go over everything
    ply = feat_in.GetGeometryRef()

    # test
    if ply.Contains(pt):
      # TODO do what you need to do here
      print(lon, lat, feat_in.GetFieldAsString(idx_reg))
2
yosukesabai
1
ViennaMike

これを行う1つの方法は、OGRライブラリ http://www.gdal.org/ogr を使用してESRIシェイプファイルを読み取り、GEOSジオメトリライブラリ http:// tracを使用することです。 .osgeo.org/geos / ポイントインポリゴンテストを実行します。これには、いくつかのC/C++プログラミングが必要です。

http://sgillies.net/blog/14/python-geos-module/ には、GEOSへのpythonインターフェイスもあります(これは私が使用したことがありません)。たぶんそれがあなたの望みですか?

別の解決策は http://geotools.org/ ライブラリを使用することです。それはJavaです。

私はこれを行うための独自のJavaソフトウェアも持っています(これは http://www.mapyrus.org)からダウンロードできます plus jts.jar from http:/ /www.vividsolutions.com/products.asp )。 ESRIシェイプファイルの最初のポリゴン内にポイントがあるかどうかを確認するには、次の行を含むテキストコマンドファイルinside.mapyrusのみが必要です。

dataset "shapefile", "us_states.shp"
fetch
print contains(GEOMETRY, -120, 46)

そして実行します:

Java -cp mapyrus.jar:jts-1.8.jar org.mapyrus.Mapyrus inside.mapyrus

ポイントが内側にある場合は1、それ以外の場合は0を出力します。

この質問を https://gis.stackexchange.com/ に投稿すると、良い回答が得られる場合もあります。

1
Simon C

特定のポイントが含まれている(それらでいっぱいのシェープファイルから)ポリゴンを見つけたい場合(そして、ポイントの束もある場合)、最も速い方法はpostgisを使用することです。私は実際にここの答えを使用してフィオナベースのバージョンを実装しましたが、非常に遅くなりました(最初にマルチプロセッシングを使用して、境界ボックスをチェックしていました)。 400分の処理= 50kポイント。 postgisを使用すると、10秒もかかりませんでした。 Bツリーインデックスは効率的です。

shp2pgsql -s 4326 shapes.shp > shapes.sql

これにより、シェープファイルからの情報を含むsqlファイルが生成され、postgisサポート付きのデータベースが作成され、そのsqlが実行されます。 geom列にGistインデックスを作成します。次に、ポリゴンの名前を見つけるには:

sql="SELECT name FROM shapes WHERE ST_Contains(geom,ST_SetSRID(ST_MakePoint(%s,%s),4326));"
cur.execute(sql,(x,y))
0
Fábio Dias