PowerShell覚え書き
背景
個人的お遊びです。地球上の2地点間の距離を計算してみたくなりました。お題
地球上の2地点について、Google Geocoding APIで住所から緯度経度を取得し、その距離(キロメートルとマイル)を計算して表示する。param( [String]$address1="関西国際空港",[String]$address2="北京国際空港") $radius = 6378.137 #地球の赤道半径(単位:キロメートル) function address2latlng([String]$address) { $encoded_address=[System.Uri]::EscapeDataString($address) $google_geocode_api_uri="http://maps.googleapis.com/maps/api/geocode/xml?address="+ $encoded_address+"&sensor=false&language=ja" $enc = [System.Text.Encoding]::GetEncoding("utf-8") $bytes=(New-Object System.Net.WebClient).DownloadData($google_geocode_api_uri) $xml=[XML]$enc.getString($bytes) $xml.GeocodeResponse.result| %{ @{ lat = $_.geometry.location.lat; lng = $_.geometry.location.lng; address = $_.formatted_address} } } function sin($r){[math]::sin($r)} function cos($r){[math]::cos($r)} function acos($r){[math]::acos($r)} function d2r($d){ $d /180 * [math]::pi } #degreeからradianに変換 function distance($latlng1,$latlng2) { $x1 = d2r $latlng1["lng"] ;$y1 = d2r $latlng1["lat"] $x2 = d2r $latlng2["lng"] ;$y2 = d2r $latlng2["lat"] $delta_x = $x2 - $x1 $radius * (acos ( (sin $y1) * (sin $y2) + (cos $y1) * (cos $y2) * (cos $delta_x) ) ) } $l1 = address2latlng $address1 $l2 = address2latlng $address2 $d = distance $l1 $l2 $l1;$l2; $d.ToString() + "km" ($d/1.609334).ToString() + "mi"
結果
-
Name Value
---- -----
address 日本, 〒549-0001 大阪府泉佐野市泉州空港北1 関西国際空港
lat 34.4348875
lng 135.2443930
address 中華人民共和国 北京 朝陽区 首都国际机场 (PEK)北京首都国際空港 (PEK) 邮政编码: 100621
lat 40.0753910
lng 116.5921350
1763.70556211725km
1095.92263763597mi
メモ
- 2点間の距離についてはこのページを参考にしました。この計算は地球が完全な球形と仮定している(今回は赤道半径を使用)ので、実際とは誤差が出るそうです。(極半径は赤道半径より約21km小さいので、計算結果は極に近づくほど実際より少し大きめになる)
- 関西国際空港と北京国際空港の場合にはマイレージ表とほぼ一致するのですが、成田国際空港と北京国際空港ではけっこう(10マイル以上)誤差が出ました。計算の誤差なのか、マイル計算が前提とする空港の緯度経度がgeocoding apiの結果と違うのかは不明です。おそらく後者なんでしょうね。(数10mから1km以下のような短距離については特に誤差が確認できなかった。)
- 距離計算の式を完結にするために三角関数のラッパー関数を定義しましたが、単純に[math]の関数を呼び出しているだけなので冗長な気がします。javaのimportのようなやり方はないものか。
- 手元のマシンではdistance関数1回あたり2.3msかかっている。遅いが、[system.math]の問題か。