解決:高緯度ほど緯度1度が広くなる謎(追記あり)

数日前の日記の中で、「緯度1度あたりの長さは、緯度の高低に依らず一定と予想して、MySQLで計算してみたところ、差が出てびっくり」という実験結果を紹介しました。
http://sakaik.hateblo.jp/entry/20191202/mysql_gis_metre_per_degree

これは、地球が(そして今回計算に使用した JGD2011が)真球ではなく回転楕円体だからということに起因するものであると、すぐに想像できましたが、いやまて、よく見ると高緯度のほうが1度あたりの距離が長い。 

mysql> SELECT id, ST_Distance(pos1, pos2)  FROM g3 ORDER BY ID;
+------+-------------------------+
| id   | ST_Distance(pos1, pos2) |
+------+-------------------------+
|    0 |      110573.13812416371 |
|   10 |      110610.23595555034 |
|   20 |      110710.37167306663 |
|   30 |      110861.46743133431 |
|   35 |      110950.61420268985 |
|   40 |      111045.29885197058 |
|   50 |      111239.69315258414 |
|   60 |      111421.20351156592 |
|   70 |      111567.93710081652 |
|   80 |       111662.1956839133 |
|   90 |      111692.61028462648 |
+------+-------------------------+

 地球楕円体(赤道方向のほうが極方向よりも長い回転楕円体)は、赤道付近の半径が真球の場合に比べて伸びているのだから、普通に考えれば低緯度(赤道に近いほう)が1度あたりの距離は長くなるはず。 なのに、緯度0度よりも90度に近くなるに従って1度あたりの距離が長くなっているのは、直観に反する! というのが前回の日記での疑問でした。

なぜそう思ったのか

 イメージが掴みやすいように、扁平率を思いっきり大きくした以下のような楕円を地球だと考えてみます。この地球上に点Aと点Bがあるときを考えます。
f:id:sakaik:20191208215200p:plain

 以下のように、点A、点Bそれぞれに地球の中心から線をひっぱります。
f:id:sakaik:20191208215318p:plain

 このとき、これらの線が長軸となす角度を、緯度と考えました。
f:id:sakaik:20191208215502p:plain
 つまりこのとき、点A付近(低緯度)付近の1度と、点B付近(高緯度)付近の1度を比べると、明らかに点A付近のほうが長くなります。MySQLで計算した結果の値と逆の感覚です。「明らかに」の部分がピンと来ない人は、中心の角度を45度にした線を描いてみて、赤道~45度の弧の長さと、45度~90度の弧の長さを比較してみると良いでしょう。MySQLの結果の値自体が誤っているわけではないことは、他のソースで確認済なので、「明らかに」感じたほうが誤っているとしか考えようがありません。何がおかしいのでしょうか。


ほんとの緯度の定義

 実は「緯度」の定義が、上で書いたようなものとは異なっていることがわかりました。 これがわかったのは高校の教科書のおかげです。高校の教科書、すごい!
元はと言えば、先日のセミナーで「ベッセル楕円体って中学あたりで習ったよね」と発言してしまったことが、どうも庶民感覚(笑)とずれていたらしいと知ったことで、教科書を取り扱っている本屋さんに中高の地学の教科書を確認しに行ったのですが、まぁこの話自体は「高校で、地球の形について習う。回転楕円体(出版社によっては地球楕円体)という用語はあるが、GRS80については出て来ない」というのが結論でした。 これを確認している際、あるひとつの教科書(出版社名失念)で、緯度の定義についてさらりと触れられていたのです。教科書、すごい!

 まず、観測点Aにおける楕円体の接線を考えます。
 f:id:sakaik:20191208220416p:plain

 その接線に直交する線を引きます(=観測点における鉛直方向)
f:id:sakaik:20191208220923p:plain

 その線が長軸と交わるところの角度、これが「緯度」なのです。
f:id:sakaik:20191208220932p:plain
 考えてみれば人工衛星による観測のない時代、「真下」を知る根拠は重力なわけで、その「真下」は必ずしも地球中心を向いていない。なお、地球回転による遠心力もあるので、更にすこしずれるらしいですが、遠心力の影響は重力の力に比べてかなり小さいそうです。

 参考までに点Bにおける鉛直方向の図も示しておきます。
f:id:sakaik:20191208221424p:plain

 これらの図を見てみると、高緯度における1度のほうが距離が長くなるのも納得できますね。実際の地球は扁平率が 298分の1程度なのでその差は微々たるものですが、それでも緯度10度隔てると1度あたりの距離は100m(0.1%ほど)くらい差がでるようです。

そもそもの歴史的な話として

 そもそもが、高緯度における1度の長さを測ろうとしていた人たちがいて、どうも思っていたのよりも大きくなる。なんでだ?と疑問に思ったところから、地球が回転楕円体である(真球ではない)と気づいたということのようで、なるほど勉強になります。地球の形、奥が深い!

(2019/12/14追記) "ほんとの定義" などない!

 「ほんとの緯度の定義」と私が書いた点に対して、ご指摘をいただきました。

 JGD2011とかWGS84とかを見ている上では、緯度の定義は上に書いたとおりということで間違いはないのですが、これが「緯度の本当の定義」と呼ぶのは、言い過ぎだったようです。今回結論とした緯度の定義は「地理緯度」(地理座標系での緯度ってことですかね)であり、これとは別に、ちゃんと「地心緯度」というものもあるとのこと(この日記の冒頭で「こうだと思っていたんですが」と書いたほう)。
 ご指摘いただきありがとうございました。 不正確なことを書いちゃったけど、こうやって指摘いただけた時、あぁ書いてよかったなぁと思います。ひとつ賢くなった^^

参考:緯度 - Wikipedia

(2021/07/10追記) 地心緯度と測地緯度

 ちょうどいま読んでいた本に、地心緯度と測地緯度についての言及が出てきて、「あ、これだ」とこの記事を思い出したので追記しておきます。
 地心緯度:楕円体の中心を基準とする緯度
 測地緯度:楕円体面の法線が赤道面となす確度
とのことで(久保信明著 『図解よくわかる 衛星測位と位置情報』4章28)、地上にいるときは測地緯度が自然に感じるけど、確かにGNSSだと地心緯度が自然だよなと感じました。

MySQL Technology cafe #6 でMySQLのGISの話をしてきました

 そんなわけで、12月5日に開催された Oracle Technology Cafe #6 にて、発表の機会をいただき、あんなことやこんなことを語ってきました。
 この2年間、色々なところでMySQLGISについてお話をしてきて、そろそろ「測地系というのが色々あるらしい」「緯度経度で表すらしい(地理座標系)」「内部バイナリと人間可読な記法の間で変換を明示する必要があるらしい」というあたりは浸透してきているかな、という感触を持っています。それほど難しいわけではないけれども、最初に考え方を理解するのに少しハードルがある部分なので、ここを乗り越えたらあとはみんなが盛り上げてくれるのを楽しく見守るようになれたらいいなぁと思っています。
 今回、これまでの総括的な意味合いも持ち、ゼロベースで構成を作り上げて発表をいたしました。今まで説明してこなかった最後の大ネタである投影座標系の説明も(それなりにたぶんしっかりと)することができて、「伝えることはすべて伝えたぞ!次はきみたちの番だ!」の気分です(笑)。
 発表資料はこちら。

www.slideshare.net

9系原点の場所を勘違い

 日本の平面直角座標系の9系(東京など関東付近)の原点位置を、セミナーの中で何度か「埼玉県の千葉県寄りのあたり」とお話をしましたが、これは誤りでした。自分の発表後にtwitterを見たら、指摘をいただいていました。千葉県民としては、これは不覚!


 1系から19系の各原点は36.0度とか、131.0度とか、129.5度のように切りの良い数字になるように設定されていることが多いのです。対象エリアの真ん中付近にあれば、物理的になにか設置するわけでもないので、ある程度自由に原点を決めることができるからです。ところが、この9系は北緯36度、東経139度50分というちょっと半端な場所が原点として定められています。これはどこかなーと目視で地図を確認した際、私、なぜか139度50分を 139.5度と勘違いして地図を見てしまったみたいなんですよね。
 ひとつ前の記事(http://sakaik.hateblo.jp/entry/20191202/mysql_gis_metre_per_degree)で調べたとおり、北緯35度付近では経度1度はおよそ91kmとなるので、139度50分(≒ 139.833度)と139.5度との差、0.333度 はおよそ30km。30km西側を見てしまったので埼玉県になってしまったのした。次のセミナーでも埼玉県と言い続けていた可能性も高く、ご指摘、感謝です!

「たのしかったです」

 小学生並みの感想ですが、今回本当に楽しかったです。オラクルさん主催の会なので、イベントの告知先も普段のユーザベースの勉強会とは異なるのか、いつもと少し客層の違うたくさんの人が来てくださいました。中にはGISにお詳しい方もいたり、逆にMySQL(をはじめとするRDBMS)でこんなデータを扱えるのかと感心してくださる方もいたり、とにかく「伝わった」感がビシバシ感じられるセミナーでした。楽しかった。
 理想では、もっとゆったりと、アルコール燃料を補給しながら進めたかったのですが、伝えたいことが多く、凄い勢いでまくしたててしまいました(笑)。まだ話し足りないw

GeoHashとかの解説資料

 私の過去の発表の中に、GeoHashや「標高」に関する説明があります。以下の資料が一番整理されているかなと思いますので、よかったらご覧ください。山﨑さんの発表の中で、GeoHash以外の位置の符号化手法について提案がありましたが、その中で「GeoHashは長方形なんですよ」と言っていた意味も、この資料でわかるかと思います(桁数が増えるごとに、タテ・ヨコに交互に長方形になる)

www.slideshare.net

GeoHashは SRID:4326にのみ対応

 山﨑さんの発表のなかで、ちらっと「WGS84にだけ対応しています」という話が出てきました。いくつかの関数でそうだった気がしますが、話題の(?) GeoHashもこれに該当します。少し解説してみますね。

 実験用のテーブルを作ってデータを投入、内容を確認します。

mysql> CREATE TABLE g4 (id INTEGER, g GEOMETRY SRID 6668);                                                                       
mysql> INSERT INTO g4 VALUES (1, ST_GeomFromText('POINT(35.678 136.984)', 6668));
mysql> INSERT INTO g4 VALUES (2, ST_GeomFromText('POINT(36.876 137.011)', 6668));

 内容を確認する際、GEOMETRY系の型はバイナリで格納されているため、テキスト(WKT)に変換する必要があります。ついでに、この位置情報がどの測地系(SRID)で格納されているかも確認してみましょう。ST_SRID()関数で見ることができます。

mysql> SELECT id, ST_AsText(g), ST_SRID(g) FROM g4;
+------+-----------------------+------------+
| id   | ST_AsText(g)          | ST_SRID(g) |
+------+-----------------------+------------+
|    1 | POINT(35.678 136.984) |       6668 |
|    2 | POINT(36.876 137.011) |       6668 |
+------+-----------------------+------------+

 投入したとおりの内容が得られますね(あたりまえ)。
では、もうひとつ取得カラムを追加して、GeoHashを得てみましょうか。ST_GeoHash() という関数があります。第1引数に GEOMETRY、第2引数に得たいハッシュの桁数を指定します。

mysql> SELECT id, ST_AsText(g), ST_SRID(g), ST_GeoHash(g, 6) FROM g4;
ERROR 3682 (22S00): Function st_geohash is only defined for SRID 0 and SRID 4326.

 
 おやおや。 st_geohash は SRID 0と4326 にだけ対応しているそうです。
丁寧に処理をしたければ、今回の JGD2011(6668) の緯度経度を、WGS84(4326)に変換してから ST_GeoHash()に与えるべきですが、幸いにも JGD2011と WGS84はほぼ一致します(数センチくらいの差、だったかな)。なので今回は、(本当は)JGD2011で表した緯度経度なのですが、強引にそのままエイヤとWGS84の緯度経度であるかのように読み替えてしまいましょう。先ほど使った ST_SRID() は、緯度経度の数字は変更せずに測地系だけを読み替える機能も持っています(互いの測地系によっては全然違う場所を指してしまうことになります。たとえば Tokyo 測地系で表された緯度経度をそのままWGS84として読むと、数百メートルずれた場所を指すことになります)。

 ST_SRIDの第2引数に WGS84(4326)を与えて変換し、ST_GeoHash() に喰わせた実行結果が、以下になります。

mysql> SELECT id, ST_AsText(g), ST_SRID(g), ST_GeoHash(ST_SRID(g, 4326), 6) FROM g4;
+------+-----------------------+------------+---------------------------------+
| id   | ST_AsText(g)          | ST_SRID(g) | ST_GeoHash(ST_SRID(g, 4326), 6) |
+------+-----------------------+------------+---------------------------------+
|    1 | POINT(35.678 136.984) |       6668 | xn36vn                          |
|    2 | POINT(36.876 137.011) |       6668 | xn93vc                          |
+------+-----------------------+------------+---------------------------------+

 めでたく GeoHash 値が得られました。
 

ラクルさんのMySQLイベントで発表しよう!

 今回オラクルさんのMySQLイベントに登壇したごほうびに、MySQLのイルカ(sakila)のぬいぐるみをいただきました。大きくて手触り良く、絶対これは良い品! さっそく我が家の先住イルたちに熱烈な歓迎を受けていました。

 

f:id:sakaik:20191207110709j:plain
我が家のイルカたちによる歓迎式典の様子

 オラクルの(いくつかの?)MySQLイベントでは、発表をした人にプレゼントしてくれるらしいので、イルカが欲しい人も、そうでない人も、「発表してみたいなー」という意思表示をしてみると良いかと思います。
 併せて、MySQLユーザ会もときどきセミナー形式のイベントや交流会形式のイベントなどを開催していまして、ユーザ会としても特に「若手」「初心者」「登壇未経験者」に発表の機会を持ってもらいたいと考えています。ちょっと不器用なユーザ会ですので、募集のアピールがうまく伝わらないこともあるかと思いますが、かように熱烈歓迎しておりますので、twitterハッシュタグ #mysql_jp などをウォッチしながら、チャンスだ!と思ったらぜひ手をあげてみていただけたらと思います。

f:id:sakaik:20191207110958j:plain
sakila

参考情報

 この日記は、RDBMS-GIS(MySQL,PostgreSQLなど) Advent Calendar 2019 の5日目の記事として投稿しました。
RDBMS-GIS(MySQL,PostgreSQLなど) Advent Calendar 2019 - Qiitaqiita.com

 今回のイベントのリンクはこちら(各資料へのリンクそしてtwitterまとめへのリンクなども貼られています)
oracle-code-tokyo-dev.connpass.com

経度一度はどれくらいの長さ?MySQLをつかって調べてみよう

この日記は、RDBMS-GIS(MySQL,PostgreSQLなど) Advent Calendar 2019 の2日目の記事です。
( https://qiita.com/advent-calendar/2019/rdbms_gis )

経度一度ってどれくらい?

 赤道付近の一周の長さが だいたい 40,000km だというのはみんな知っていますよね。実際はもう少し長いのですが、とりあえず感覚的なものでいいです。で、経度というのは、緯度が上がっていくごとに円が小さくなりますから、1度の長さもどんどん短くなるはずです。どんな感じなのかな、とMySQLを使って見てみました。
 MySQL、まだまだ関数が少ないので(とくに集約系や分析的なもの)、関数が少ないうちに、少ないこれらの関数を遊び倒しましょう。できることが限られているというのは、アイデアを膨らませるという点でメリットでもあります!

経度1度を求める

 まず、テーブル g1 を作って適当にデータを入れます。ここでは、緯度0度から10度刻みで、緯度135度と136度の2つの位置情報をカラムに入れることにしました。測地系は、JGD2011を使います。

CREATE TABLE g1 (
    id integer, 
    pos1 GEOMETRY SRID 6668, 
    pos2 GEOMETRY SRID 6668
);

INSERT INTO g1 VALUES (0, ST_GeomFromText('POINT(0 135)', 6668), ST_GeomFromText('POINT(0 136)', 6668));
INSERT INTO g1 VALUES (10, ST_GeomFromText('POINT(10 135)', 6668), ST_GeomFromText('POINT(10 136)', 6668));
INSERT INTO g1 VALUES (20, ST_GeomFromText('POINT(20 135)', 6668), ST_GeomFromText('POINT(20 136)', 6668));
INSERT INTO g1 VALUES (30, ST_GeomFromText('POINT(30 135)', 6668), ST_GeomFromText('POINT(30 136)', 6668));
INSERT INTO g1 VALUES (35, ST_GeomFromText('POINT(35 135)', 6668), ST_GeomFromText('POINT(35 136)', 6668));
INSERT INTO g1 VALUES (40, ST_GeomFromText('POINT(40 135)', 6668), ST_GeomFromText('POINT(40 136)', 6668));
INSERT INTO g1 VALUES (50, ST_GeomFromText('POINT(50 135)', 6668), ST_GeomFromText('POINT(50 136)', 6668));
INSERT INTO g1 VALUES (60, ST_GeomFromText('POINT(60 135)', 6668), ST_GeomFromText('POINT(60 136)', 6668));
INSERT INTO g1 VALUES (70, ST_GeomFromText('POINT(70 135)', 6668), ST_GeomFromText('POINT(70 136)', 6668));
INSERT INTO g1 VALUES (80, ST_GeomFromText('POINT(80 135)', 6668), ST_GeomFromText('POINT(80 136)', 6668));
INSERT INTO g1 VALUES (90, ST_GeomFromText('POINT(90 135)', 6668), ST_GeomFromText('POINT(90 136)', 6668));

 このテーブルの各レコードの長さは、以下のSQLで求めることができます。

SELECT id, ST_Distance(pos1, pos2)  FROM g1 ORDER BY ID;
+------+-------------------------+
| id   | ST_Distance(pos1, pos2) |
+------+-------------------------+
|    0 |      111319.49079326246 |
|   10 |      109639.3390102644  |
|   20 |      104646.97563995633 |
|   30 |       96486.0081494232  |
|   35 |       91287.79089978167 |
|   40 |       85393.3619519223  |
|   50 |       71695.04015879167 |
|   60 |       55799.17666195067 |
|   70 |       38185.80088710373 |
|   80 |       19393.044953483724|
|   90 |                       0 |
+------+-------------------------+
11 rows in set (0.00 sec)

 赤道付近で、1度あたり111km、日本がある北緯35度付近では91km、70度で38km、80度で19kmと一気に狭くなっていくのがわかりますね。感覚とも一致します。

1度ではなく1分は?

 何十キロもの長さは日常でイメージしにくいので、もう少し小さい単位である「分」の単位で距離を求めてみましょう。1分は約 0.0167度 なので以下のようなデータを作ります。各緯度で、経度135度から135.0167度を表すデータ群です。

CREATE TABLE g2 (id integer, pos1 GEOMETRY SRID 6668, pos2 GEOMETRY SRID 6668);

INSERT INTO g2 VALUES (0, ST_GeomFromText('POINT(0 135)', 6668), ST_GeomFromText('POINT(0 135.0167)', 6668));
INSERT INTO g2 VALUES (10, ST_GeomFromText('POINT(10 135)', 6668), ST_GeomFromText('POINT(10 135.0167)', 6668));
INSERT INTO g2 VALUES (20, ST_GeomFromText('POINT(20 135)', 6668), ST_GeomFromText('POINT(20 135.0167)', 6668));
INSERT INTO g2 VALUES (30, ST_GeomFromText('POINT(30 135)', 6668), ST_GeomFromText('POINT(30 135.0167)', 6668));
INSERT INTO g2 VALUES (35, ST_GeomFromText('POINT(35 135)', 6668), ST_GeomFromText('POINT(35 135.0167)', 6668));
INSERT INTO g2 VALUES (40, ST_GeomFromText('POINT(40 135)', 6668), ST_GeomFromText('POINT(40 135.0167)', 6668));
INSERT INTO g2 VALUES (50, ST_GeomFromText('POINT(50 135)', 6668), ST_GeomFromText('POINT(50 135.0167)', 6668));
INSERT INTO g2 VALUES (60, ST_GeomFromText('POINT(60 135)', 6668), ST_GeomFromText('POINT(60 135.0167)', 6668));
INSERT INTO g2 VALUES (70, ST_GeomFromText('POINT(70 135)', 6668), ST_GeomFromText('POINT(70 135.0167)', 6668));
INSERT INTO g2 VALUES (80, ST_GeomFromText('POINT(80 135)', 6668), ST_GeomFromText('POINT(80 135.0167)', 6668));
INSERT INTO g2 VALUES (90, ST_GeomFromText('POINT(90 135)', 6668), ST_GeomFromText('POINT(90 135.0167)', 6668));
SELECT id, ST_Distance(pos1, pos2)  FROM g2 ORDER BY ID;
+------+-------------------------+
| id   | ST_Distance(pos1, pos2) |
+------+-------------------------+
|    0 |      1859.0354970687047 |
|   10 |      1830.9776594574585 |
|   20 |      1747.607087970476  |
|   30 |      1611.3214483744373 |
|   35 |      1524.512474129115  |
|   40 |      1426.0766207422205 |
|   50 |      1197.3160879967666 |
|   60 |       931.8551188371557 |
|   70 |       637.7100204965047 |
|   80 |       323.86784178140675|
|   90 |                       0 |
+------+-------------------------+

 赤道付近で1.9km、北緯35度付近で1.5kmです。念のため赤道付近の「分」の結果を60倍して答え合わせをしてみましょうか。

mysql> SELECT 1859.0354970687047 * 60  ;
+-----------------------+
| 1859.0354970687047*60 |
+-----------------------+
|  111542.1298241222820 |
+-----------------------+
1 row in set (0.00 sec)

 あれれ。本来の赤道付近の距離 111319.49079326246 よりも 少し大きくなっていまいましたね。考えてみたら、
「1度」を 0.0167 としましたが、これがちょっと切り上げが雑すぎたのかもしれません。0.016666666666667くらいでやるべきだったのでしょうか。まぁこれは感覚とも一致するのでよしとしましょう。
 というかそもそも、0.0166666....とか言っている時点で誤差許容なので、もうちょっとまともな計算をしましょうか。

経度1度、1分、1秒の長さを求める(別解)

 最初に「度」を求めたのですから、度を60で割って分を求めたり、度を60*60で割って秒を求めたりするほうが(先ほどみたいに途中で不正確な小数を持ち出すよりも)正確な値が求まります。ここでは、そのやり方で。最初に作った g1 テーブルを使います。

WITH cte_g1 AS (
  SELECT id, ST_Distance(pos1, pos2) dist FROM g1
)
SELECT id, round(dist,2) do, round(dist/60,2) fun, round(dist/60/60,2) byou 
  FROM cte_g1;
+------+-----------+---------+-------+
| id   | do        | fun     | byou  |
+------+-----------+---------+-------+
|    0 | 111319.49 | 1855.32 | 30.92 |
|   10 | 109639.34 | 1827.32 | 30.46 |
|   20 | 104646.98 | 1744.12 | 29.07 |
|   30 |  96486.01 | 1608.10 | 26.80 |
|   35 |  91287.79 | 1521.46 | 25.36 |
|   40 |  85393.36 | 1423.22 | 23.72 |
|   50 |  71695.04 | 1194.92 | 19.92 |
|   60 |  55799.18 |  929.99 | 15.50 |
|   70 |  38185.80 |  636.43 | 10.61 |
|   80 |  19393.04 |  323.22 |  5.39 |
|   90 |      0.00 |    0.00 |  0.00 |
+------+-----------+---------+-------+
11 rows in set (0.00 sec)

 うーん、CTE便利! MySQL 8.0 最高! まぁこの程度なら、FROMのサブクエリに書いてもいいんですけどね。
少数以下が長くあっても仕方がないので、ここでは小数第2位(センチメートル)で丸めて出力しました。
赤道付近での1秒は30.92m、北緯35度では 25.36m だとわかります。これくらいの長さだと、そのへんの通り道を眺めながら「あそこまでで1秒かー」とイメージが湧きやすいですね。

緯度はどうなるか

 ここまでやったらならば、一方の緯度はどうなるか確認してみたくなります。
緯度は経度みたいには細くなっていかないので、一定のままだろう、と予想して、テーブルg3とそのデータを作って試します。

CREATE TABLE g3 (id integer, pos1 GEOMETRY SRID 6668, pos2 GEOMETRY SRID 6668);

INSERT INTO g3 VALUES (0,  ST_GeomFromText('POINT(0  135)', 6668), ST_GeomFromText('POINT(1  135)', 6668));
INSERT INTO g3 VALUES (10, ST_GeomFromText('POINT(10 135)', 6668), ST_GeomFromText('POINT(11 135)', 6668));
INSERT INTO g3 VALUES (20, ST_GeomFromText('POINT(20 135)', 6668), ST_GeomFromText('POINT(21 135)', 6668));
INSERT INTO g3 VALUES (30, ST_GeomFromText('POINT(30 135)', 6668), ST_GeomFromText('POINT(31 135)', 6668));
INSERT INTO g3 VALUES (35, ST_GeomFromText('POINT(35 135)', 6668), ST_GeomFromText('POINT(36 135)', 6668));
INSERT INTO g3 VALUES (40, ST_GeomFromText('POINT(40 135)', 6668), ST_GeomFromText('POINT(41 135)', 6668));
INSERT INTO g3 VALUES (50, ST_GeomFromText('POINT(50 135)', 6668), ST_GeomFromText('POINT(51 135)', 6668));
INSERT INTO g3 VALUES (60, ST_GeomFromText('POINT(60 135)', 6668), ST_GeomFromText('POINT(61 135)', 6668));
INSERT INTO g3 VALUES (70, ST_GeomFromText('POINT(70 135)', 6668), ST_GeomFromText('POINT(71 135)', 6668));
INSERT INTO g3 VALUES (80, ST_GeomFromText('POINT(80 135)', 6668), ST_GeomFromText('POINT(81 135)', 6668));
INSERT INTO g3 VALUES (90, ST_GeomFromText('POINT(89 135)', 6668), ST_GeomFromText('POINT(90 135)', 6668));
mysql> SELECT id, ST_Distance(pos1, pos2)  FROM g3 ORDER BY ID;
+------+-------------------------+
| id   | ST_Distance(pos1, pos2) |
+------+-------------------------+
|    0 |      110573.13812416371 |
|   10 |      110610.23595555034 |
|   20 |      110710.37167306663 |
|   30 |      110861.46743133431 |
|   35 |      110950.61420268985 |
|   40 |      111045.29885197058 |
|   50 |      111239.69315258414 |
|   60 |      111421.20351156592 |
|   70 |      111567.93710081652 |
|   80 |       111662.1956839133 |
|   90 |      111692.61028462648 |
+------+-------------------------+

 あれれ。みんなだいたい111kmではありますが(赤道付近の経度1度ともほぼ合致していますね)、よく見ると少しずつ値が異なりますね。そうか、地球(JGD2011でのモデルであるGRS80)は真球ではなく回転楕円体だから、緯度があがるごとに少しずつ値が変化するわけですね。確かにそうだ。

 いや、でもよく見てみると、、、、緯度があがるほうが1度あたりの距離が長くなっていますね。イメージを真球から極半径を共有した回転楕円体へと拡張していくと、赤道付近のほうがぐーっと伸びているのだから、そちらのほうが1度あたりの距離が(真球と比べて)より長くなるようなイメージを持っていたのですが・・・・・かるく調べてみると値が間違っているわけではないようですが、感覚的に納得できません。。ここまでで今日の私はギブアップ。
 誰か、「なぜ極付近のほうが緯度1度の距離が長くなるのか」、わかりやすくおしえてください!

おまけ

 つくば市国土地理院内にある「地図と測量の科学館」には、地球のミニチュアモデルがあります。曲面に乗っかった日本の形とか、なかなか面白いものですよ。そしてその周りには、「1秒の距離をあるいてみよう」という看板と標石が設置されていて、実際にその場所での1秒(南北30.8m、東西25mくらい)を歩いて体験できるしかけがあります。なかなか面白いですよ。

f:id:sakaik:20181220115619j:plain

MyNA(日本MySQLユーザ会) 望年LT大会2019@赤坂 開催しました

 今年も、赤坂のワインバーnomunoを貸切利用させていただいての、日本MySQLユーザ会(MyNA)望年LT大会 というイベントを開催しました。
一応、いわゆる忘年会的な位置づけではあるのですが、前後の各種イベントとの兼ね合いを考え、今年はちょっと早めのこの時期の開催となりました。

mysql.connpass.com


 昨年の反省を踏まえ、参加申込を開催直前まで受け付けるようにしたり、学生さんに対する割引を思い切った設定にしたり、幹事想定最低人数を公開するなど、細かい工夫をしてみました。そのおかげもあってか、早い時期にたくさんの申込をいただき、また、昨年ゼロだった学生さん枠で2人の方が参加してくださったり、イベントとして一歩前進した気がします。ありがとうございました。
 
 ひとつ心残りと言えば、私自身がLTをできなかったこと。事前の用意をする時間が全然なくて、もしLTやってくれる人が少なかったら見に行ったあちこちの三角点の話でもしようかと思っていたけど、濃厚なMySQL話をたっぷり聞かせて貰って、まぁいいかという気分になりました(笑)。ただ、後ほど耳に入った話だと、「LT用意はしていたんだけど・・・・」とか「やろうかなと思っていたけど手を挙げられなくて」といった声があったそうで、幹事の至らなさ故、申し訳ございません。 「次だれやるー?」と手を挙げてもらう方式は結構勇気いりますよね。来年開催の場合は、事前に募集(もちろん当日飛び入りも歓迎)という形にすると、覚悟も決まって良い気もしてきました。まだまだ工夫ポイントがある感じで、イベント開催って奥深く楽しいです。

 ともかく、参加してくださった皆様、LTをしてくれたみんな、どうもありがとうございました。とても疲れたけど幹事もとても楽しかったです!
それから、今年も昨年に引き続き、ノーショウ(無連絡欠席)がゼロでした! ノーノーショウ! 幹事自腹切らずにすみました。ありがとうございます!
 そして、最後になりましたが、今年も本イベントを経済的にサポートしてくださった、SCSK様どうもありがとうございました!!


scsk-db.jp



f:id:sakaik:20191118175841j:plain
f:id:sakaik:20191118210042j:plain
f:id:sakaik:20191118184212j:plain





参考:昨年の開催
sakaik.hateblo.jp

OSC2019 Fukuoka 参画

 OSC2019 Fukuoka に参加してきました。日本MySQLユーザ会としてセミナー1枠の開催とブース出展です。
今年の福岡の会場は、久々の 九州産業大学九産大)。

www.ospn.jp


 セミナーは、松久さん(@hmatsu47)と一緒に『「MySQL8.0の薄い本」に見るMySQL』と題するトークショーをやらせていただきました。「薄い本」は、hmatsuさんが個人で作られているもので、MySQL 8.0 の主に新機能に注目してまとめあげたものです。以下のURLで無料配布されていて誰でもダウンロードできます。また、hmatsuさんが自費で印刷して、参加イベントなどで配ってくれることもあります。

薄い本:
github.com

 セミナーでは、この薄い本を作るモチベーションは何か、から、MySQL 8.0 での注目機能などについて、だらだらと(笑)おしゃべりをしてきました。聞きに来てくださった方には、それなりに楽しんでもらえたのではないかと思います。しっかり資料を準備した「教育的(役に立つ)セミナー」も良いですが、OSCではこういった、「そこそこの経験を積んだ(というと偉そうですが、世間平均よりは興味を持って試したり情報収集をした人、くらいの意味だと思ってください)人が」「会場の反応を見ながら」「ライブ感を持って自然に」おしゃべりするのを聞いていただいたり、一緒にディスカッションに参加してもらったり、という場にするのも面白いんじゃないかな、と思い、最近、このスタイルに挑戦してみています。(一応書いておくと、このスタイルだからといって何の準備もなく会場入りして、いきなり適当に話すわけではなく、構成とか、会場の反応に応じた分岐だとか、引き出しの準備だとか、普通に45分間をストレートなシナリオでお話するのと比べて、結構準備が大変だったりします。資料が完成したから準備完了!みたいなのとは違って、準備の終わりがないので、直前までいつもドキドキなのです。始まると、楽しんじゃうんですけどね(笑))

 ブースは、一日中比較的おちついた感じだったと思います。他のブースでお話を聞いたりする余裕もあり、私自身も出展しながらも楽しんだOSCでした。ETロボコンのブースでは、九州地区で活躍されている(今回OSCには参加されていない)先生が、私の大学時代の大先輩(たぶんあちらは覚えていない)だということが確認できたりもして、いろいろな人たちがいろいろな所で繋がっている社会の面白さを感じました。

 実は今年から、OSCへの参加を少し減らす方向で、「行く理由(時間と費用をかけるに見合う:発表したいものがある、会いたい人がいる、食べたいものがある)があるところだけ厳選して参加する」という方針に変わりました。福岡に関しても第1回の開催から「無条件で参加する」場所だったところから、一旦ゼロベースで検討ということで、昨年の訪問の際には「来年来ないかも」と宣言していたのですが、幸いなことに熊本に行きたい場所ができたことから(時期は自分で決められたので)今回のOSCに合わせることで、参加できることになった次第。
 実際に参加すると、たくさんの人が歓迎してくれて、いろんな人とお話ができて、見知らぬ情報にも出会うことができる充実のOSC2019-Fukuoka でした。ラーメンも一応食べられたし。

#そしてここで再開した人の何人かとは、翌週のPostgreSQLカンファレンスですぐに再開することになります(笑)
f:id:sakaik:20191109181938j:plain
f:id:sakaik:20191109092728j:plain
f:id:sakaik:20191109214231j:plain

OneMix 3 をてにいれた。結構よさげな印象

最近の日常生活では、外で自分のモバイルPCを使う機会があまりないのですが、ここぞという時に、スマホタブレットでは面倒な(あるいはできない)作業をやりたいこともあるため、何らかのモバイルPCは持ち歩きたいと思っています。今まで、その目的に合いそうだということで Surface Go を持ち歩いていたのですが、これが意外と私の「ちょっと用」には使い勝手が悪く、困っていました。とにかくディスプレイ(というか本体)が自立しないのが問題で、ちょっと出してちょっとキーボード打って、ちょっとしまう、ということをやりたいだけのために、画面の裏側のスタンドを立てて水平な場所を確保して、そして置いてしか使えない、というのがネックで、事実上「ほとんど使っていない」、日々の荷物がちょっと重くなるだけの筋トレ用途(にもならないか)としてのみ、役割を果たしている状態でした。

 そんな中で知ったのが、OneMix 3。公称 659g はSurfaceGo よりもやや軽いですが、見かけの小ささからは、持った瞬間に少しびっくりするくらいに重くは感じました。とにかくディスプレイが自立してくれるのがいい(笑)。左手手のひらに載せたまま、右手で打てる! 

f:id:sakaik:20191020151647j:plain
f:id:sakaik:20191020151713j:plain
(単3電池はサイズ比較用。単3電池で動作するわけではありません)

OneMix3 を選択したポイント

  • まず、先にも述べたように「ディスプレイの自立」
  • 重さ。もう少し軽いと嬉しいけど、700g以下で、なんとかギリギリ私の「許容範囲」
  • 解像度 2560x1600
  • microSD 使用可能
  • m.2 ひとつあいてる!これが最大の選択ポイントと言ってもいいくらいです(OneMix 3S には無いらしいので注意)
  • 一応 microHDMI出力もついている(将来的にはこれだけでプレゼンまでできるとラクかも)
  • タッチパネル画面。もう画面タッチできないPCは使いたくない・・・・・
  • 質素、シンプル、質実剛健な外観。うるさくないのが一番。

OneMix3 で少し惜しいところ

  • RAM 8GB。まぁ通常の作業には問題ないのですが、3Sは 16GB ということで、ちょっと羨ましい
  • SSD 256GB。3Sが512GBなので、、、、ただし 3 は自前の拡張ができるのでここはOK
  • 英語キーボード。自分は他のPCで日本語刻印キーボードで(ソフト的に)英語配列になってしまっても一応は打てるくらいには英語キーボードも使えますが、それでもアタマが混乱するときもあるのでできれば日本語キーボードが嬉しかった

SSD の増設

 お気に入りポイントで「これが最大の選択ポイント」と書いたとおり、m.2 がひとつ空いています。 M.2 2242 が刺さります。
1TBを刺したい気分でしたが、私の観測範囲であまりなじみのないメーカーばかりだったので、今回は512GB増設することにしました。

f:id:sakaik:20191023225108j:plain
OneMix 3 と 512GB SSD


 増設は簡単。小さいプラスドライバ(なんていうサイズなんですかね。私は家にあった眼鏡用のプラスドライバを使いました)で、まず、裏蓋の6つのネジをはずします。ネジのひとつには封印らしきものがしてあるので、呪文を唱えて解除します。たぶん保証が効かなくなるとか、そういう作用があると思うので、もう保証なんか使わない!という覚悟はある程度必要かと思います。ご自身の責任において封印解除してくださいませ。


f:id:sakaik:20191026115810j:plain
OneMix 3 内部

 写真右上にあるのが M.2 です。ここに刺します。フラットケーブルが少し浮いていて、やや干渉しますが、折らないように片方(私は右側)にケーブルを寄せつつ、取り付けます。取り付けには、M2・2mm のねじを自分で用意しておく必要があります。あとネジ穴にカバーというかガードがしてあったので、剥がしてから作業しました。

f:id:sakaik:20191023225537j:plain
SSD取り付け途中

電源投入後にやったことメモ

 備忘として、電源投入後にやったことを書いておきます。

  • まずはWifiの設定。おうちネットワークへと接続。
  • bluetooth マウスの接続設定
  • なにはなくとも、Windows Update
  • 標準SSDのドライブの1本化。購入時は 100GB程度のCドライブと130GB程度のDドライブに分かれていました。Dドライブはカラ。これは(これから増設することを考えると)分かれている必要はないので、230GB程度のCドライブひとつにまとめました。 「コンピュータの管理」-「ディスクの管理」から、Dドライブの領域を削除し、Cドライブの領域を「ボリュームの拡張」で。
  • SSD の増設。上記通り。私の好みもあり、10GB程度のEドライブを確保した上で残りをDドライブとしてクイックフォーマットした。
  • 画面表示の設定。最初は「250%」表示になっていたので、150%や200%あたりで好みに設定
  • ソフト類のインストール。ATOK(passportライセンスに余裕あり)、Office(365ライセンス台数に余裕あり)、ESET Internet security (ライセンスに余裕あり)、秀丸エディタPoderosaEvernoteDropbox。これで一応最低限の作業はできそう。あとは必要になったときにぼちぼち。あ、Ubuntu(WSL)は入れておきたいな。
  • 外で使うための、スマホとのテザリング接続設定


 さて、これで少し機動力が増したので、生活が便利になりそうです。楽しみだ。
あとは刺しっぱなし前提で、microSDの512GBか1TBあたりを導入すれば、最強マシにになる予感。あーあと、目隠しシートが欲しいかも。常時貼りっぱなしでなくて、まわりに人の多いときだけ使う、下敷きみたいな感じの。

アイネックス M.2 SSD固定用ミリネジ PB-044

アイネックス M.2 SSD固定用ミリネジ PB-044

MySQL: ストアドで度分秒変換

GIS関係のデータを探していると、緯度経度を表す数値として、度で表されているものと、度分秒で表されているものがあります。MySQLで扱えるのは、度(「35.65810012度」のような数字)です。度分秒(「35度39分29.172秒」のような表現)で公開されているデータを度単位に直すのが意外と面倒くさいので、こんなストアドを試しに作ってみました。

delimiter //
CREATE FUNCTION dfb2deg(d float, f float, b float)
                RETURNS float DETERMINISTIC
  RETURN d+f/60+b/60/60
//
delimiter ;

こうやって使います。

mysql> SELECT dfb2deg(139, 44, 28.8869);
+---------------------------+
| dfb2deg(139, 44, 28.8869) |
+---------------------------+
|        139.74136352539062 |
+---------------------------+

 ちょっとした手作業の中で、度分秒を少数単位に変換したい場合は、上のような使い方で得た数字をコピーするなどして使えば良いですし、もう変換しながら処理に供したいような場合は以下のように、一旦変数に入れて ST_GeomFromText() かける方法がありそうです。(この例自体は、一旦内部バイナリに変換したものを、そのままテキストに戻しているだけなので意味はありませんが、利用法の例として)
 なおこの緯度経度があらわすのは、日本経緯度原点の十字の交点です。

mysql> set @lon=dfb2deg(139, 44, 28.8869);
mysql> set @lat=dfb2deg( 35, 39, 29.1572);
mysql> set @mypointwkt=CONCAT("POINT(",@lat," ", @lon, ")")

mysql> SELECT ST_AsText(ST_GeomFromText(@mypointwkt));                                                                         
+---------------------------------------------+
| ST_AsText(ST_GeomFromText(@mypointwkt))     |
+---------------------------------------------+
| POINT(35.65810012817383 139.74136352539062) |
+---------------------------------------------+


 MySQLでストアドを日常的に使っている人はあまりいないかもしれませんが、こうやって使うと便利だよという例としても、紹介いたしました。