« 24時間ぶりに食事を | メイン | Simple FON Maps »

2006年12月17日

世界測地系の座標計算

Google Maps を使ったウェブアプリを書いていたので、その派生物(関数)を。

# IN: latitude(from), longitude(from), latitude(to), longitude(to)
# OUT: distance(meter)
sub dist {
    my ($lat_1, $lon_1, $lat_2, $lon_2) = @_;
    my $pi = atan2(1, 1) * 4;
    my $radius = 6378140;

    $lat_1 = $lat_1 * $pi / 180;
    $lon_1 = $lon_1 * $pi / 180;
    $lat_2 = $lat_2 * $pi / 180;
    $lon_2 = $lon_2 * $pi / 180;

    my $deg = sin($lat_1) * sin($lat_2) + cos($lat_1) * cos($lat_2) * cos($lon_2 - $lon_1);

    my $dist = $radius * (atan2(-$deg, sqrt(-$deg * $deg + 1)) + $pi / 2);

    return $dist;
}

2点の座標から距離を計算します。地球を真球と仮定して計算するので誤差が生じます。2点の座標があまりにも離れている場合は、その誤差が大きくなります。地球は、経線と赤道では赤道の方が長いです。

# IN: latitude(central), longitude(central), distance(meter)
# OUT: SouthWestLat, SouthWestLng, NorthEastlat, NorthEastLng
sub bounds {
    my ($lat, $lon, $dist) = @_;
    my $pi = atan2(1, 1) * 4;
    my $radius = 6378140;

    my $deg_lat = ($dist / $radius) * (180 / $pi);
    my $deg_lon = ($dist / $radius) * (180 / $pi) / cos($lat * $pi / 180);

    my $sWLat = $lat - $deg_lat;
    my $sWLng = $lon - $deg_lon;
    my $nELat = $lat + $deg_lat;
    my $nELng = $lon + $deg_lon;

    return $sWLat, $sWLng, $nELat, $nELng;
}

座標と距離から、その座標を囲む線(4点)を求めます。こちらも前記同様に誤差が出ます。

Google Maps API に getBounds という関数があり、この関数では getSouthWest と getNorthEast が取り出せ、それぞれから lat と lng を取り出すことが出来ます。この関数は、表示しているマップの端(南西と北西)の座標を取り出しているわけです。この関数を距離からエミュレートしたかったのです。

ラジアンなどをすっかり忘れていたおかげで、とても時間がかかりました…。そもそも正しいかどうかすら分からない。国内の座標を使う限りでは、それなりに正しい結果が出るようだけど。

後者は、なかなか便利なんだけどいかがでしょうか?多分 CPAN を探せば見つかるだろうけど。

2006年12月17日 23:16 | Programming

トラックバック

コメント