turfpy
turf.jsを再実装した地理空間データ分析を実行するための Python ライブラリ
https://turfpy.readthedocs.io/en/latest/index.html
※turf.js:Advanced geospatial analysis for browsers and Node.js
(ブラウザーと Node.js の高度な地理空間分析)
今回は緯度・経度で指定した範囲の内外を判断する処理に使用
範囲指定をあまり考えずに実行したら想定通りの判定をしなかったので
久しぶりに「qiita書こう!」とその内容をまとめました
前提条件
- 地図上で四角形で表示されている豊田スタジアムの競技場の範囲内か判定する
- 指定した範囲の倍の広さ(だいたい)でランダムに位置を2000ポイントを範囲内か判定する
確認方法(成功パターン)
緯度経度で範囲内か判定する関数準備
from turfpy.measurement import boolean_point_in_polygon
from geojson import Point, Polygon, Feature
def point_check(latitude, longitude):
point = Feature(geometry=Point((latitude, longitude)))
polygon = Polygon(
[
[
# 1:左上
(35.08499763901068, 137.17026711732228),
# 2:右上
(35.085190785781094, 137.171211254785),
# 3:右下
(35.08409774461924, 137.1715170265769),
# 4:左下
(35.08391776454962, 137.17057825353157),
]
]
)
return boolean_point_in_polygon(point, polygon)
ion_map = folium.Map(location=[35.084558667377046, 137.17086793207127], zoom_start=20)
範囲表示
import geojson as gj
map3 = folium.Map(location=[35.084558667377046, 137.17086793207127], zoom_start=20)
color = "yellow"
index = 1
# 指定ポイント表示
for y, x in polygon:
folium.Marker(location=[y, x], icon=DivIcon(
icon_size=(25, 25),
icon_anchor=(0, 0),
html='<div style="text-align: center; font-size: 11pt; color : black width: 25px; height: 25px; background: ' + str(color) + '; border:1px solid #666; border-radius: 50%; z-index:1000;">' + str(index) + '</div>'),
popup=str(index)).add_to(map3)
index += 1
# 図形表示用に緯度と経度を入れ替える
def swap(point):
return point[1], point[0]
lng_lat = [list(map(swap, polygon))]
# 図形表示
area = gj.Polygon(lng_lat)
folium.GeoJson(area).add_to(map3)
map3
指定は左上を起点に四隅を順番に回るように指定
いい感じに位置指定できている
ランダムにポイント準備して判定した結果を地図表示
import random
import folium
from folium.features import DivIcon
map = folium.Map(location=[35.084558667377046, 137.17086793207127], zoom_start=20)
for index in range(2000):
y = random.uniform(35.08521712394161, 35.08388264644096)
x = random.uniform(137.16996134553037, 137.17184425603844)
output = point_check(y, x)
match output:
case False:
color = "red"
case True:
color = "skyblue"
folium.Marker(location=[y, x], icon=DivIcon(
icon_size=(10, 10),
icon_anchor=(0, 0),
html='<div style="text-align: center; font-size: 11pt; color : black width: 10px; height: 10px; background: ' + str(color) + '; border:1px solid #666; border-radius: 50%; "></div>'),
popup=str(index)).add_to(map)
map
判定結果
四角で範囲外、内を判定できている
範囲指定の順番を入れ替える
polygon = Polygon(
[
[
# 1:左上
(35.08499763901068, 137.17026711732228),
# 2:右上
(35.085190785781094, 137.171211254785),
# 4:左下
(35.08391776454962, 137.17057825353157),
# 3:右下
(35.08409774461924, 137.1715170265769),
]
]
範囲確認
「Z」を描くように範囲を指定
終点から視点をつなぎ
砂時計のように中央がしぼんだ形状になる
判定結果
おまけ(五角形→星形)
アメリカ国防総省本庁舎:ペンタゴン(五角形)の形で判定
範囲変更
pentagon = [
# 1:左上
(38.87154327182928, -77.05665826702705),
# 2:右上
(38.87166063136013, -77.05554184655043),
# 3:左下
(38.870875785812466, -77.05499070226449),
# 4:最下
(38.870244969090606, -77.05581977401086),
# 5:右下
(38.87067040423856, -77.05686553496363),
]
print(pentagon)
範囲確認
判定確認
五角形で判定できている
星形に変更
pentagon = [
# 1:左上
(38.87154327182928, -77.05665826702705),
# 3:左下
(38.870875785812466, -77.05499070226449),
# 5:右下
(38.87067040423856, -77.05686553496363),
# 2:右上
(38.87166063136013, -77.05554184655043),
# 4:最下
(38.870244969090606, -77.05581977401086),
]
範囲確認
星形にきれいに描けている
よく見ると真ん中が抜けている
判定結果
図を描いたとおりに判定
星形にするには
指定ポイントを増やして
pentagon = [
# 1:左上
(38.87154327182928, -77.05665826702705),
(38.87128784974465, -77.05603043209587),
# 2:右上
(38.87166063136013, -77.05554184655043),
(38.871133274341744, -77.05563029667685),
# 3:左下
(38.870875785812466, -77.05499070226449),
(38.87084552538874, -77.05577996565037),
# 4:最下
(38.870244969090606, -77.05581977401086),
(38.87078607298053, -77.05612817509899),
# 5:右下
(38.87067040423856, -77.05686553496363),
(38.87105004129327, -77.05628089854136),
]
範囲確認
判定確認
成功!☆
まとめ
- 指定したい範囲を移動してまわるように指定しないと意図しない判定になる
- 指定した順番でできる図形を作成することで判定範囲を確認できる
今回まとめる際に図形を表示させる等、
アウトプットすることで新しい操作も経験できたのでレベルアップできたと思います
またアウトプットしようと思いました。