はじめに
前回までで、2つのジオメトリーオブジェクトの間の距離を知る方法を紹介しました。今回からは2回にわたって、その手法を応用して地球の形や大きさをより深く理解するために役立ててみましょう。今回は「経度」の話です。
赤道における経度一度は何キロ?
今回はまず、みなさんへの質問から始めましょう。みなさんは、経度の1度が何キロぐらいになるか知っていますか?
「場所による」
そうですね。経度1度は赤道付近で最も広く、極方向に近づくにつれて狭くなっていきます。
それで最初の質問に「赤道付近では?」という条件を加えたらどうでしょうか。「地球の1周(赤道周長が約40,000kmである」ということを知っていれば、それを360度で割って「111.11kmぐらいかな」と求めた人もいるかもしれませんね。
今回は、MySQLの関数を使って、それを求めてみましょう。
MySQLで経度1度を求める
実際にMySQLを使って経度1度を求めてみましょう。赤道付近は緯度0度です。さしあたって、緯度0度における、経度0度から1度までの距離を求めてみましょう。座標系は WGS84(SRID=4326)で良いでしょう。
以下のSQLは、「北緯0度(=南緯0度)、東経0度(=西経0度)」から「北緯0度、東経1度」までの経度1度の距離を、ST_Distance()関数を使って求めたものです。
mysql> SELECT ST_Distance(
-> ST_GeomFromText('POINT(0 0)', 4326),
-> ST_GeomFromText('POINT(0 1)', 4326)
-> ) d;
+--------------------+
| d |
+--------------------+
| 111319.49079326246 |
+--------------------+
1 row in set (0.000 sec)結果は、約111319m(111.319km)となりました。周長を360で割って求めた値とも、かなり近い数値になっていますね。
同じ緯度ならどこでも1度の長さは同じ
今回は赤道上の、東経0度から1度までの距離を求めました。では、同じく赤道上の他の部分でも経度1度は同じ長さでしょうか。
例えば、赤道上での東経121度と122度の間、あるいは東経37度から東経38度といった範囲の長さを見れば良いわけです。当然同じ長さであってほしいですが、このことを MySQLを使って確認してみましょう。
先ほどの(0 0)から(0 1)の距離を確認したSQLを書き換えて、例えば(0 121)から(0 122)にしたり、(0 37)から(0 38)にしたりすれば、個別の場所での距離を求められます。しかし今回は1箇所や2箇所ではなく、色々な場所での「赤道上の経度1度」を確認したいので、1つ1つ確認するのは少々手間がかかります。そこでここでは、少しテクニックを使いましょう。
CTE(WITH句)と呼ばれるSQLの書き方があります。SQLの中に一時的な名前付きクエリを定義できる仕組みです。これを使うと、-165度(=西経165度)から東経175度までの、20度おきの「経度1度」といった情報を1つのSQLで求めることができます。
mysql> WITH RECURSIVE lons AS (
-> SELECT -165 AS lon
-> UNION ALL SELECT lon + 20 FROM lons WHERE lon < 156
-> )
-> SELECT lon, lon+1,
-> ST_DISTANCE(
-> ST_GeomFromText(CONCAT('POINT(0 ',lon,')'), 4326),
-> ST_GeomFromText(CONCAT('POINT(0 ',lon+1,')'), 4326)
-> ) d
-> FROM lons;
+------+-------+--------------------+
| lon | lon+1 | d |
+------+-------+--------------------+
| -165 | -164 | 111319.49079326246 |
| -145 | -144 | 111319.49079326246 |
| -125 | -124 | 111319.49079326246 |
| -105 | -104 | 111319.49079326246 |
| -85 | -84 | 111319.49079326246 |
| -65 | -64 | 111319.49079326246 |
| -45 | -44 | 111319.49079326246 |
| -25 | -24 | 111319.49079326246 |
| -5 | -4 | 111319.49079326246 |
| 15 | 16 | 111319.49079326246 |
| 35 | 36 | 111319.49079326246 |
| 55 | 56 | 111319.49079326246 |
| 75 | 76 | 111319.49079326246 |
| 95 | 96 | 111319.49079326246 |
| 115 | 116 | 111319.49079326246 |
| 135 | 136 | 111319.49079326246 |
| 155 | 156 | 111319.49079326246 |
| 175 | 176 | 111319.49079326246 |
+------+-------+--------------------+
18 rows in set (0.000 sec)同じ緯度(赤道上)であれば、どの地点でも経度1度の長さは同じであることを、たった1つのSQL文で確認することができました。
高緯度ほど経度1度の長さは短い
次に、赤道付近ではなく、より緯度の高い場所での経度1度の長さを確認してみましょう。日本が含まれる付近として、北緯35度を取り上げます。
本連載ではおなじみの北緯35度、東経135度における経度1度(東経136度まで)を求めてみます(便宜上、東経135度を使いましたが、赤道で計算してみたとおり、同じ緯度であれば経度1度はどこでも同じです。気になる方は先ほどのSQLを書き換えて北緯35度上の様々な場所で経度1度が同じ値になることを確認してみてください)。
mysql> SELECT ST_DISTANCE(
-> ST_GeomFromText('POINT(35 135)', 4326),
-> ST_GeomFromText('POINT(35 136)', 4326)
-> ) d;
+-------------------+
| d |
+-------------------+
| 91287.79089928864 |
+-------------------+
1 row in set (0.000 sec)結果は、約91288mとなりました。約91kmです。赤道付近が約111kmだったので、それと比べるとずいぶん短いですね。
さらに北極点に近い場所として、例えば北緯88度付近ではどうなるでしょうか。相当短くなることが予想できますが、どれくらいでしょう。これもSQLで確認してみましょう。
mysql> SELECT ST_DISTANCE(
-> ST_GeomFromText('POINT(88 135)', 4326),
-> ST_GeomFromText('POINT(88 136)', 4326)
-> ) d;
+--------------------+
| d |
+--------------------+
| 3897.9545727125737 |
+--------------------+
1 row in set (0.000 sec)なんと、赤道付近では111kmもあった経度1度が、北緯88度では4km弱になってしまいました。もはや歩ける距離ですね。
このように、緯度が変われば経度1度の長さは大きく変化します。
参考までに、北緯89.9度、そして北緯89.999度まで北極点に近づいた際の経度1度も示しておきます。北緯89.9度では約195m、北緯89.999度に至っては2mにも満たない値になります。
mysql> SELECT ST_DISTANCE(
-> ST_GeomFromText('POINT(89.9 135)', 4326),
-> ST_GeomFromText('POINT(89.9 136)', 4326)
-> ) d;
+--------------------+
| d |
+--------------------+
| 194.93798933953775 |
+--------------------+
1 row in set (0.000 sec)mysql> SELECT ST_DISTANCE(
-> ST_GeomFromText('POINT(89.999 135)', 4326),
-> ST_GeomFromText('POINT(89.999 136)', 4326)
-> ) d;
+--------------------+
| d |
+--------------------+
| 1.9496460253550336 |
+--------------------+
1 row in set (0.000 sec)緯度ごとの経度1度の一覧を作成する
CTEを使うと、緯度を変化させたときの経度1度の長さを一覧表示できます。紙幅を考慮して緯度15度ごとの表にしましたが、もっと細かく見てみたい場合はインタバルの数値を変更してみたり、あるいは小数点以下を丸めてみたりなど、工夫して活用してください。
mysql> WITH RECURSIVE lats AS (
-> SELECT -89 AS lat
-> UNION ALL SELECT lat + 15 FROM lats WHERE lat < 75
-> )
-> SELECT lat,
-> ST_DISTANCE(
-> ST_GeomFromText(CONCAT('POINT(',lat,' 135)'), 4326),
-> ST_GeomFromText(CONCAT('POINT(',lat,' 136)'), 4326)
-> ) d
-> FROM lats;
+------+--------------------+
| lat | d |
+------+--------------------+
| -89 | 1949.28009810421 |
| -74 | 30778.50994408699 |
| -59 | 57474.47799123532 |
| -44 | 80205.60483935187 |
| -29 | 97438.6556416161 |
| -14 | 108033.94097689069 |
| 1 | 111302.64952973522 |
| 16 | 107034.31754658499 |
| 31 | 95503.97008175393 |
| 46 | 77462.66627857221 |
| 61 | 54106.65189645881 |
| 76 | 27015.30816037382 |
+------+--------------------+
12 rows in set (0.000 sec)
