QGISでシン・山手線を描く

# はじめに
この記事は2024年アドベントカレンダー用に急ぎ追加で執筆したものです。
ちょうど忘年会の季節、私は家に引き篭もっていますが終電を気にする生活をしている人もきっと多いことでしょう。
そんな中、都心で路線図を見ていると「山手線って実際は全く円形じゃないよね」と思ったことないでしょうか？
そこで今回は、山手線が円形だったら都内のどこを通るだろう？という疑問にお答えするシン・山手線の描き方を紹介します。

# 使用するソフトウェア

オープンソース地理情報ソフトウェアQGISを使います。その中でOpenStreetMapや国土数値情報のデータを参照しますが、基本的にはQGISで作業は完結します。
なお、バージョンは3.28.11-Firenze、UIは英語表記になります。

# シン・山手線

この記事で作るのは、任意のいくつかの駅を基点として、それらの駅を含む円形・等間隔の30ヶ所を結ぶイマジナリー山手線となります。

今回は一例として「東京駅」「新宿駅」「渋谷駅」の3駅を基点として作成しました。基点3駅を結ぶピンク色の三角形が内包される円の外周に等間隔で仮想の30駅をプロットしたものです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122865/c0f3ecbe-2805-c7fa-bcf7-472b7e24d45d.png)

# 作成手順

それでは、ここからQGISで作成する工程を順を追って説明します。

## 下準備

まず、下準備としてQGISのベースマップにOpenStreetMapを表示し、国土数値情報から取ってきた鉄道駅データを表示しておきます。
なお、国土数値情報の鉄道駅データはライン図形で提供されており、300m圏内にある同名駅をグルーピングするためのコードが振られています。それらを参考に、各駅の中心点を求めてポイントデータとして用意しました。

これは、QGISの[ベクター]=>[Analysis Tools]=>[Mean Coordinates]で中心点の割り出し、[ベクター]=>[Geoprocessing Tools]=>[Dissolve]でグルーピングが出来るかと思います。これを保存し直して表示した状態が下図となります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122865/8599bbf9-a7e6-106a-c4c0-283679479dbb.png)

都内周辺の駅の位置と駅名が表示されました。ここまでで下準備完了です。

## 基点とする駅の選択

次に、基点とする駅を選択します。これは「東京駅」「新宿駅」といった2点でも良いし、3点、4点でも良いと思います。今回は、上述の通り「東京駅」「新宿駅」「渋谷駅」の3点としました。
基点の駅について、QGISの選択ツールで選択したり、別ファイルとして保存したりしておきましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122865/4db37873-1201-8595-d0dc-a2d4cd7a3f28.png)

また、重要な点として、作業の際の座標参照系は平面直角座標系に設定し、基点とする鉄道駅のデータも同じ座標系に変換しておきます。座標値の単位が緯度経度ではなくメートルで設定されていないと、後の工程で齟齬が生じるためです。今回は東京都周辺なのでEPSG:6677（平面直角座標系9系、東京都や関東の一部地域をカバー）に設定しています。

座標参照系の変換は適宜、[ベクター]=>[Data Management Tools]=>[Reproject Layer]などで実行してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122865/2a697f53-c69f-7e20-00b0-7c3735c03b60.png)


## 対象フィーチャを内包する最小図形を生成する

選択したら、次にツールボックスから「**Minimum Bounding Geometry**」ツールを探してください。（日本語表記がわかりませんが、「ジオメトリの最小範囲」とかでしょうか）
下図のように、任意のフィーチャを対象に凸包（Convex Hull）や最小円・最小矩形などを生成することが可能なツールです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122865/798d0474-dc55-2dbe-1c67-f950ddd1aabc.png)

上記の設定で3ヶ所の凸包を生成すると、下図のように三角形が描画されます。（一般的に3点で凸包を作る妥当性があるかは別として、3点以上あればポリゴン化できます）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122865/0b0bc67e-0907-cff9-8ca3-a692b882f03f.png)

ここからが肝ですが、この「Minimum Bounding Geometry」ツールで鉄道駅レイヤの選択したフィーチャ（基点となる3駅）を対象に、Geometry type=Minimum Enclosing Circle（対象を内包する最小の円）を選択して実行してみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122865/51b4b0a8-60ea-5467-b448-ba75dc084046.png)

すると下図のように、基点となる3駅を内包する最小の円が生成されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122865/d06afd46-524f-2537-8b9c-c314db66d926.png)

## フィールド計算機で円周を求める

この生成した円に対して、円周を求めてみます。
QGISで属性テーブルを開いて「フィールド計算機」から ＄perimeter を入力するとフィーチャの外周長を求めることができます。図形がポリゴンであれば ＄perimeter ですが、もしライン図形であれば ＄length で長さを求めることができます。
ここでは下記のように小数点以下第4位までの数値で計算しておきました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122865/9bff3f2f-3d0e-4aec-50d2-0cd64789a52a.png)

その結果、円の外周の長さがわかりました。（単位はメートル）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122865/b254f0a5-d4c3-1d9f-8acc-d5fb307c1d90.png)

## 円周上に等間隔でn個の点を生成する

続いて、円周上に等間隔でn個の点を生成します。今回は山手線の駅数として30個に分割します。この数は適当に変更して良いです。
ここは手計算で、20565.293 / 30 = 685.51(m)を1区間と算出しました。

ツールボックスから「Points along Geometry」（ジオメトリに沿った点を作成）を探して、下記のように点同士の距離間隔を入力して実行しましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122865/ef5d6af6-cd1c-a81e-b44a-206a53fb1b41.png)

良い感じに等間隔の点が30個生成されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122865/4b116c14-51ee-30a0-1b75-738abeccd8e3.png)

ここで注意点ですが、生成した等間隔の点は基点とした3駅にぴったり重なるわけではありません。
必要に応じて、30個のポイントフィーチャを全選択してから[編集]メニューの[ジオメトリ編集]=>[フィーチャの回転]で回転させて重ねるなど、出来るだけ基点駅に寄せるように調整しておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122865/d92cd5a4-212d-fffe-0eee-1e781c9a72ba.png)

## 駅名を決める

さて、これで路線となる円図形と、その円周上に等間隔で置いた駅の点データが生成できました。
次は駅名を考えていきます。基本的な命名ルールは下記の要領にしました。

- 最寄りの鉄道駅が300m以内に存在する場合はその駅名を採用する
- それ以外の箇所は、最寄駅名を参考にしつつ、OpenStreetMapから取得した地点名・住所を参考にする

最寄駅300m圏というのは、国土数値情報の鉄道駅データがその範囲内の同名駅を同一駅グループとして整理していることに起因します。

### 最寄駅を判定する

さて、生成した30点に対応する最寄駅とそこからの距離の算出を行います。
これには、[ベクター]=>[Analysis Tools]=>[Distance Matrix]を使います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122865/5478ff6f-b76f-8017-23c3-b23c7b5fae1c.png)

上記のように、生成した30駅の地点ポイントデータと、実際の鉄道駅の位置データ（ターゲットIDフィールド：S12_001には駅名が属性値として格納されている）を対象に、[Use only the nearest target points]の数値は1に設定することで最寄1駅とそこまでの距離を表形式で出力してくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122865/bb89dcdd-c5f0-aa7d-1323-b23efb9638d2.png)

出力結果は上記のような形になります。ここでの注意点としては下記2点あります。

- 元データがマルチポイント形式になっていると処理に失敗しますので、その場合は[ベクター]=>[Geometry Tools]=>[Multipart to Singleparts]でシングルポイントに変換しておきます
- 生成した30駅にはfidなどでユニークな番号が振られていないと、後でDistance Matrixの出力データを地物データと紐付けができないので、ユニーク番号が振られていない場合は何らかの方法で振っておく

Distance Matrixで出力された距離表は、その入力レイヤである30地点のポイントデータと紐付けておきます。これはレイヤのプロパティからJoinにて実施します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122865/cd171ea0-fb2c-9814-78ad-c3a500163c84.png)

これで今回生成した30地点に対して最寄駅とそこまでの距離が判定できました。

### OpenStreetMapから地名を取得する

次に、今回生成した30地点に対してOpenStreetMap Nominatimから地名を取得してみます。いくつか方法があると思いますが、これにはMMQGISというプラグインにあるReverse Geocode機能を利用しました。外部プラグインとなりますので、プラグインメニューから適宜インストールしてみてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122865/3ece463e-563f-1afa-cf9c-1299bd55053b.png)

上記のように設定した上で、Applyを押すとOpenStreetMap Nominatim APIを通じた処理が走ります。あまり多くの負荷をOSMサーバ側にかけられませんが、30地点くらいなら問題なしと判断しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122865/d1db56f2-f8e3-5ddb-4c02-854ed65fe4a3.png)

出力結果を確認すると、上記のように各地点の地名・住所情報が取得できています。

ここで上図の選択箇所に注目すると、fid=1とfid=2の2箇所は両方とも最寄駅が「神楽坂」ですが、距離はそれぞれ194.6m, 554.4mとなっています。
そのため、fid=1は最寄駅と同じ「神楽坂」を駅名とし、fid=2は地名から「築土八幡町」と命名しました。
このような要領で30ヶ所の地点に対して駅名を設定していきます。

## デザインを調整して完成

以上でデータは揃いましたので、あとは円の外周や30駅のラベル表示などを好みに合わせて調整して完成です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122865/8c3f0e5c-887f-5974-fe1a-be3ca40fde64.png)

# おわりに

本記事では、QGISを使った円形・等間隔の30地点によるシン・山手線のデータ生成と描画手順について紹介しました。
テーマ自体はある種のネタ画像にすぎませんが、その過程で得た処理方法は個人的に学びがありました。
特に、「Minimum bounding geometry」による円の生成、「Distance Matrix」による最寄地点の距離表の生成、MMQGISプラグインを用いたOpenStreetMap Nominatim APIによる地名取得、といった要素は便利で応用可能性を感じました。

少々説明が雑多な部分もありましたら、何らかの参考になれば幸いです。