タイル地図APIを古地図や非メルカトル地図ビューアに使う場合、最大ズームを固定すべき理由


Google Maps APIにせよOpenLayers/Leafletにせよ、或いはネイティブアプリならMapKit、MapBox、Nutiteq等等、 **タイル地図APIを流用して、古地図ビューアや非メルカトルの地域地図ビューアにする**事はよくあるユースケースと思います。
**タイル地図APIで使うためにタイル化する場合、どういう座標系を使ってどういうタイルセットでタイル化するかは悩むところ** で、私もちずぶらりを開発していた頃は、 **元画像を2のべき乗分の1した画像のうち256x256px以内に収まるものを最小ズーム=ズーム0として、そこから拡大する方向にタイルを作って**いっていました。

が、最近は、ズーム18でも20でもいいのですが、 **最大ズームの方を固定し、固定した最大ズーム値の上で元解像度の地図画像をタイル化し、その後縮小する方向でタイルを作っていった方がよい**と考えています。
その理由がいくつかあるので、それをここで述べます。

## ズーム0等の低ズームでの地図描画は、地球が丸い影響を受ける

**どんなタイル地図APIも、基本は地球の地図を表すために設計**されています。
**Google Mapsをズーム0で表示したりすれば判りますが、地図の東の端と西の端は繋がって表示**されます。

![continuous.png](https://qiita-image-store.s3.amazonaws.com/0/10108/a96ddb35-0c65-39e7-c4a7-c7a71a674330.png "continuous.png")

メルカトルの全世界地図を使うにはあって当然の機能ですが、端と端が繋がっていない一般の古地図、地域地図を表示するには厄介な機能です。
**同じ地図が水平方向に、無限に表示されてしまいます**。
オフにできるスイッチのあるAPIもありますが、相当Hackしないと使えないAPIもまた多いです。

![continuous2.png](https://qiita-image-store.s3.amazonaws.com/0/10108/ee1e04fb-e121-50e5-9304-78f5ab3adea4.png "continuous2.png")


また最近は、 **広域ズームになると、地図ではなく地球になる**タイル地図APIも増えています。
たとえば、以前の記事でも紹介したAltusMapあたりがそうです。

![sphere.png](https://qiita-image-store.s3.amazonaws.com/0/10108/5563ad08-c81d-73ae-28ec-30a4b848a19f.png "sphere.png")

これも、古地図や地域地図ビューアとして使うには不便ですね。

また、見た目の問題だけでなく、 **多くのAPIの内部処理で、ズーム0での左右端面では、地球が球である事を前提とした決め打ち実装が多い**です。
WGS84（EPSG:4326）以外の座標系を許すAPIもあるにはありますが、それですら結構いろんなところで座標の最大値は-180〜180を前提としたコードが混じっていたりして（オープンソースで多人数開発してるので当然ちゃあ当然）、 **「てめえらが地図は全球図だけと思ってるなら、まずはそのふざけた幻想をぶち殺す！」**みたいなHackが必要になるので、結構疲れます。

が、最大ズーム側を固定してタイルを作成すると、 **これらの不便が完全に解消**されます。
どんな地域地図であれ、辺が何百万ピクセルもあるとかでない限り、 **ズーム18〜20あたりで使っていれば、日付変更線まで到達する事は絶対にありません**。
よって、 **地図が無限に表示されてしまう問題から解放**されます。

APIの端面処理問題も、地図APIの左上原点を地域地図でも原点にしているとズーム18〜20でも同じ問題に遭遇しますが、広大なピクセル座標空間があるのですから、真ん中当たりを原点にしてしまえば無問題です。
真ん中…そうですね、 **経緯度0,0、メルカトル座標系でも0,0の地点を、地域地図ピクセルでも原点にしてしまいましょう。**
**通称「ガーナ沖」ですね。**

広域で球になってしまうAPIでも、ズーム18〜20では事実上面です。
おかしな見え方になる事はありません。

このように、最大ズーム側を大縮尺に固定すると、タイル地図APIを流用する際に遭遇する困難のほとんどが解消されます。

## 地図上のピクセル座標系を、あらゆる地図について単一の座標系定義で使い回せる

地域地図/古地図をタイル地図API上でビューできるようになったのはいいとして、今度は **地域地図上のピクセル座標系と、タイル地図APIで使っている座標系との間の変換**が出来ないと、マーカーを立てたりすらできません。
ピクセル座標系の定義は **正味の解像度とそれに対応するズームレベルの関係によって決まり**ますから、 **ズーム0を合わせてしまうと、ピクセル座標系は個々の地図毎に計算して定義しないといけない**事になります。

が、 **最大ズームを固定してしまうと、どんな地域地図をタイル化しようと、単一の座標系定義が使い回せます**。
以前、 **独自タイル座標系はproj4textでも表現できる**事を記事に挙げましたが、それでいくと、 **ズーム18〜20で経緯度0,0を地域地図原点に合わせた場合のピクセル座標系proj4定義**は

```text:ズーム20基準：proj4定義
+proj=merc +a=42722829.72352698 +b=42722829.72352698 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +axis=esu +units=m +nadgrids=@null +no_defs
```

```text:ズーム18基準：proj4定義
+proj=merc +a=10680707.430881744 +b=10680707.430881744 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +axis=esu +units=m +nadgrids=@null +no_defs
```

になるはず（ざっと計算しただけなので、間違ってたら後で修正）ですから、極端な話 **OpenLayersだと、普通の地図でマーカーを立てる際にいちいちEPSG:4326からEPSG:3857に変換している、あの処理の代わりにこのprojtextからEPSG:3857への変換結果でマーカーを立ててやると、望みの場所にマーカーが立つはず**で、世界地図を扱ってる時と手間的には全く変わらず地域地図が扱えるようになります。
**Leafletの場合、EPSG:3857を意識しない作りなのでここまで簡単じゃないですが、それでも単にピクセル座標をこのprojtext=>EPSG:4326に変換後マーカーを立ててやれば、それで完了**です。

これまで地域地図タイルを作っても、タイル地図API上で扱う際の座標変換係数が違うので、他人に伝えようと思うとタイルURLだけでなく、タイルのピクセルサイズ等のメタ情報を一緒に伝えるか、専用のビューアを一緒に送ってやる必要がありました。
が、 **最大ズーム側を合わせると、単にタイルURLを伝えるだけで、教えてもらった側は汎用ビューアでタイルURLを置き換えてやればさえ、地図を共有できる**のです。
これ、地味に便利な気がするのです（もっとも、初期表示位置を全体を収めて、とかしようとすると、メタデータはどうしても必要ですが）。

## なので、地域地図/古地図タイルは最大ズーム側を固定すべき

他にも細かいメリットはたくさんあるのですが、大きくはこの2つの理由で、地域地図/古地図タイルは最大ズーム側を固定してタイル化すべき、と私は考えます。