先日Mapbox GL JS v2.6 にアダプティブ・プロジェクションをリリースしました。これは、ユーザーエクスペリエンス、レンダリング品質、ストリートレベルの精度に一切妥協することなく、インタラクティブマップをより正確にするための方法です。
Mapboxは、たった1行のコードを追加するだけで、あらゆる種類の地図アプリでこの機能を採用できるよう工夫を凝らしました。
この記事では、なぜこのような機能を実現したのか、また、どのような仕組みになっているのか、詳しく見ていきましょう。
地図投影法入門
私たちが画面や紙で見る地図は、いずれかの地図投影法、つまり地球を平面に表現する方法を用いています。これは、古代ギリシャ人が「地球は球体である」と定めて以来、数千年前から研究されてきたテーマです。1つだけ確かなことは、完全な投影法は存在しないということです。球体を平面に投影しようとすると、どうしても歪んでしまいます(1777年にオイラーによって数学的に証明されたことが有名です)。
どの投影法も形、大きさ、距離を歪めるので、その選択はトレードオフの関係です。
- 地図によっては、実際のサイズよりも大きく見えないように、相対的なサイズを維持する必要があります。例えば、国土地図にはアルバース投影を、世界地図には等緯経度図法を使用します。
- 地図によっては、形状を保持する必要があります。これは、ナビゲーション(メルカトル図法)や航空地図(ランベルト正角円錐図法)にとって特に重要ですが、サイズは歪んでしまいます。
- 両方の歪みのバランスを取ろうとする投影法は、形の歪みも、サイズの歪みも大きすぎないようにします。これらは「見た目が正しいこと」を目指すもので、世界地図のビジュアライゼーションによく使われます(ヴィンケル図法、ナチュラル・アース図法)。
このようなトレードオフは、私たちが日常的に経験しているもので、結果、Web地図製作の黎明期に、Webメルカトル図法が採用されました。当時、インタラクティブマップはナビゲーションのために考案されたもので、メルカトル図法が最適でした。線と線の間の角度を保ち、形状が伸びるのを避け、どの地点でも北が上になるようにします。
その一方で、メルカトル図法は地球規模でのサイズを大きく歪め、赤道から離れるほど形が膨らんでいきます。そのため、14倍も小さいグリーンランドがアフリカと同じ大きさだと思っている人がたくさんいます。
インタラクティブマップにおける投影法
地図投影は地図製作の基本概念の一つであるにもかかわらず、インタラクティブマップにメルカトル図法以外を採用することは、信じられないほど困難であり、Webメルカトルは依然としてメインの投影法です。
その理由の一つは、地図業界が投影法とともに、それに対応するタイル方式を採用したことです。この方式は、ズーム0でメルカトル投影された正方形のタイルから始まり、次のズームレベルでは各タイルを4つに分割します。このシンプルで効率的な地図データの配布方式は、広く普及していきました。そのため、別の投影法を使用するには、すべてのデータを異なる投影タイルに再処理する必要がありますが、これには膨大なコストがかかります。
例えば、Mapboxでは、ベースマップスタイル用にズーム16までのタイルを生成しますが、これは合計57億タイル以上にも及びます。すべてのデータセットについて、投影法ごとに個別のタイルセットを生成するのは非現実的です。
ラスターマップのタイルを再投影すると、テキストラベルが歪んだり、シャープな線やアイコンがぼやけたりするため、選択肢に入らないことが多くありました。
また、地図投影法をインタラクティブマップに適用する際の基本的な問題として、投影法は紙のために設計されており、ユーザーが世界地図からストリートレベルまでズームするWebインタラクティブマップの場合にはうまく機能しないことが挙げられます。世界規模のズームレべルではうまく機能する投影図も、ズームインすると大きく歪みますし(下図のモールヴァイデの例)、その逆もあります(メルカトル図法)。
2012年にオレゴン州立大学のベルンハルト・ジェニー氏によって、地図投影法をインタラクティブマップに適応させるという注目すべき試みがありました。しかし、残念ながらコンセプトの実証にとどまりました。このアプローチでは、レンダリングフレームごとにジオメトリを再投影する必要があり、既存のメルカトルタイルとの互換性を保ちつつ、画面上の数百万点を一度にレンダリングすることが多い現代のベクターレンダリング標準に対応させることは困難でした。さらに、投影法が変更されたマップを突然操作すると、混乱することもあります。
▲オレゴン州立大学のアダプティブ合成地図投影デモ
これらの制限により、メルカトル図法以外は通常のWebマップではほとんど見られず、D3ベースの目的型ビジュアライゼーションに限定されています。ベクターレンダリング技術の進歩は、より広く採用されるための唯一の現実的な道であるように思われました。
Mapbox GJ JSの投影法
MapboxがGL JSとそのベクターレンダリング技術を導入して地図業界を変えて以来、投影法の問題は、プロジェクトの8年の歴史の中で最もリクエストの多かった機能でした。最終的に投影法の問題に取り組むことになったとき、このような大規模で複雑な機能は、一度デザインを決めてしまうと、後から変更するのは難しいため、最初の開発を大切にしなければなりませんでした。結果、Mapboxでは以下のような指針に落ち着きました。
- 既存のソースやスタイルとの互換性を確保し、誰でもすぐに Mapbox マップで異なる投影法を使用できるようにする。そのためには、Webメルカトルタイルをロードし、クライアント上でデータを再投影する必要がある。
- ラスター再投影ではなくベクター再投影を行うことで、ベクターレンダリングをシャープかつ正確に保つ。
- 歪みをなくすため、ズームインしながら投影をダイナミックに調整する。
- ズームと回転の意味を再定義し、異なる投影法への切り替えを直感的かつシームレスに行うことができるようにする。
- レンダリングパフォーマンスのオーバーヘッドをゼロにし、異なる投影法を使用したマップが通常のマップと同じように高速に感じられるようにする。
投影法とズームレベル
投影法を設計する際に、Mapboxが最初に尋ねた質問は、「ズームレベルとは何を意味するのか」という些細なものでした。歴史的に、メルカトル図法の場合、ズームは全世界を含む1つのタイルの地図に対して0と定義され、1増加するごとにサイズが2倍になりました。
メルカトル図法以外の投影法では、タイルも世界も正方形ではないので、同じ定義には頼れません。直感的には、どのような投影法を選んでも、ある地図のズームと中心配置によって、地図はほぼ同じ面積になり、図形の大きさも比較的同じにしたいと考えました。そのためには、次のような手順で行います。
- 地図上の任意の領域を基準点とする(例:下の赤い四角)。
- 再投影された座標でその大きさを計算する。
- メルカトル座標での大きさを計算する。
- これらの大きさが一致するように、投影地図の縮尺を調整する。
ただ一つ、どの点を基準にするかという問題があります。マップビューの中心を基準にすると、カメラ視点を移動したときに地図が目に見えてズームしてしまい、画面酔いをしてしまいます。また、地図上の固定点(例えば世界の中心)を基準にすると、その点から遠ざかるにつれて、サイズのズレが大きくなってしまいます。
そこで、これらのアプローチを組み合わせた解決策を考えました。
- 低いズームレベルでは、固定点(投影中心)を使用する。この方法では、世界の形状は変わらず、カメラ視点の移動中にサイズが拡大・縮小しない。
- 高ズームレベルでは、画面の中心を使用する。カメラ視点の移動は比較的小さな距離に限定されるため、サイズが変化しても気づかない。
- 中間のズームレベルでは、両方を使用し、ユーザーが低ズームから高ズームへ移動したり戻ったりするときに、2つの間をスムーズに移行する。
このため、さまざまな投影法に対応した地図を設計し、適切な投影法を選ぶことができます。
投影法と地図の回転
ズームと同様に、インタラクティブマップを使用する際にも、地図の向きについて先入観があります。ユーザーはメルカトル図法に習い、回転させない限り、上は北に位置すると直感的に思ってしまいます。また、どのような地図表示設定(中心、ズーム、方位)でも、投影法に関係なく同じ方位になることを期待しています。
そこで、ズームと同じように、この直感に合うように自動的に地図を回転させるのが重要です。
- 低ズームレベルでは、北が投影中心から真上になるように地図を配置する。そうすれば、カメラ視点を移動したときに地図が回転することはない。
- 高いズームレベルでは、北が画面の中心から真上に来るように地図を方向付けする。こうすると、地球上のどの地点を表示してもメルカトル図法のように北が上になり、カメラ視点を移動した時の回転が目立たなくなる。
- 中間のズームレベルでは、この2つのアプローチをスムーズに切り替えることができる。
▲回転補正の極端な例:アルベルス正積円錐図法でアラスカにズームインした場合
ズームイン時の歪み補正
上記のズームと方位の調整を行った後、1つ問題が残りました。それは、ズームインすると、地図の傾きが目立つということです。
▲歪み補正なしのヴィンケル図法でサンフランシスコにズームアップ
これは、ヴィンケル図法のような非整形投影の自然な性質で、図形の相対的な大きさは保たれますが、子午線と平行線は互いに垂直ではないので、拡大すると図形が歪んで見えます。これをどう補正するのでしょうか。十分に拡大すると、地球のほぼ平らな部分が表示されます。その結果、形や大きさを妥協する必要がなくなるので、別の投影法を使う必要がなくなります。
地図を拡大すると、子午線と平行線を表す曲線がまっすぐになり、高いズームレベルでは直線に近くなっていることにご注目ください。これらの線が垂直になるように地図を斜めに戻し、垂直方向と水平方向の距離が等しくなるように伸ばします。こうすることで地図は等角になり、メルカトル図法とほぼ完全に一致するようになります。
このスキュー/ストレッチングはアフィン変換と呼ばれ、WebGL のビュー行列を補正することで GPU 上でリアルタイムに適用することができます。この方法では、タイルがロードされたときに座標の再投影を一度適用し、その後ユーザーがズームしたときにその座標の表示を調整することができます。また、マップを操作する際、ビューを不均一にねじったり歪めたりするような高度な変換よりも、ずっと自然な感じがします。
これまでの補正と同じように、低いズームレベルでは調整せず、ユーザーがズームインするにつれてスムーズに完全な補正に移行することで、両者の長所を生かした補正を行っています。
▲歪み補正を施したヴィンケル図法でサンフランシスコにズームインした場合
タイルローディングの変更
回転、ピッチ、そして最近では3D地形機能により、ロードするタイルを決定するコードは非常に複雑になっています。投影法によっては、さらに複雑になります。タイルはもはや完全な正方形ではなく、代わりに使用する投影によってさまざまな形状をとります。
さらに、同じズームレベルのタイルでも、再投影すると大きくなるものと小さくなるものがあるため、タイルの読み込みロジックを調整し、サイズに応じて同じビューに異なるズームレベルのタイルを取り込みました。
ベクタージオメトリのリサンプリング
メルカトル図法のベクタータイルデータを別の図法に再投影する場合、新しい座標値を計算するだけでは不十分です。それまで直線だった線やポリゴンの線分が曲線になる可能性があるので、曲線に沿うように間に点を追加する必要があります。
あまりに多くの点を追加すると、レンダリングパフォーマンスに影響が出ます。また、点数が少なすぎると、線が投影図と一致しなくなります。線の真ん中に点を追加し、新しくできた2つの線の真ん中に点を追加し、各線が十分な精度でカーブに近似するまで再帰的に続けるという適応的アルゴリズムでバランスを取ることができます。
これは、よく知られているDouglas-Peuckerポリライン簡略化アルゴリズムと非常によく似ていますが、その逆です。この手法により、一般的な地図ではわずか2~3%の点の追加で、再投影されたジオメトリを正確にレンダリングすることができます。
ラスタータイルの再投影
衛星画像レイヤーのようなラスタータイルを異なる投影法でレンダリングするには、メルカトル画像をロードし、それを歪んだタイルの形状にマッピングする必要があります。WebGL でこれを行うには、タイルを多くの小さな三角形に分割し、それぞれの三角形で画像のごく一部を表現する必要があります。一般に、三角形の数が少なければ少ないほど、レンダリングは高速になります。
2年前に、ラスター高度マップから3D地形メッシュをリアルタイムに生成するオープンソースライブラリ「MARTINI」を紹介し、その仕組みについて詳しく説明した記事も掲載しましたが、今回はその続きです。
ラスタータイルを再投影するための三角メッシュの生成にも、全く同じアプローチが使えることがわかりました。個々の三角形の辺がどの程度地形に近いかを測定する(さらに分割するかどうかを決める)代わりに、再投影によって辺がどの程度湾曲するかを測定しているのです。
その結果、歪みの少ない領域では三角形の数が少なくなり、歪みの多い領域では三角形の数が多くなるような三角形メッシュが得られます。
アダプティブ・プロジェクションを始める
これらの工夫の結果として、高速で美しく、詳細なMapboxのインタラクティブマップを様々な投影法で簡単に使用できるようになりました。ここまで長文をお読みいただきありがとうございました。
このデモで新機能を遊び、例とドキュメントをチェックし、あなたのマップで試し(コードまたは Mapbox Studio で)、何か問題が発生したらお知らせください。また、今後Mapbox コミュニティが長い間待ち望んでいた、もう一つの素晴らしい次期機能にご期待ください!