はじめに
これは、ドリコムAdvent Calendar 2021 の12日目です。11日目は まさ さんによる「無駄遣いサムライ〜So I need to buy one〜」です。
こんにちは、雑用エンジニアの Smith です。
本稿では私が今年の 4月から業務で関わっている AROW というプロダクトで取り扱う地理空間情報と関連技術について紹介します。
地理空間情報を操ると言うと、時間を操る能力の次に強そうな能力ですね。
でもジョジョ3部のスタンドで例えると、時間が DIO のザ・ワールドなら、地理空間はケニーGのティナー・サックスになるので微妙ですね。
技術というものは、あらゆるものをそれが形而下的であるかどうかに関わらず、データや機能及びプロセスとしてデジタルに具象化し、それ単体での価値提供並びに外部のサービスと協同する手段として用いることができます。
もちろん、これは現実の地形や町並みが対象であっても適用可能であり、世の中には実際に技術的に表現されたデジタルな地理空間情報が溢れています。
例えば・・・
- iOS の最新の地図アプリでは、建物の高さが表現される 3D 地図が利用可能です。
- Google Map の飲食店の情報では、地図上の特定の座標が飲食店の名称や営業時間、顧客のレビューなどの地図以外の情報を関連付けてユーザに表示します。
- カーナビゲーションは、 GPS によって測位された現在地座標から、デジタルな地図データ上の現在地を導出し、道路網データとセンシング技術などから集計された交通量情報を組み合わせて、目的地までの最速の経路をユーザに返します。
地理空間情報とは
地図上で見える形状と、座標や領域などの任意の地理空間エンティティに紐ついた情報が地理空間情報です。例えば、建物や道がどの座標にどのような形状で存在しているかという物質的な情報や、この区画の治安の良さなどの無形ではあるが現実の地理空間に関連づいた情報が地理空間情報とされます。
地図
小難しいことは置いておいて、まずは人間にとってわかりやすい OpenStreetMap (以下 OSM) から見ていきましょう。OSM は誰もが編集可能な開かれた地図サービスで、 Open Data Commons Open Database License のもと公開されており、商用利用も可能です。
あのポケG○ も、地図データソースは OSM を用いていると思われますが、 OSM は誰でも編集可能であるがゆえに、適切な編集を呼びかけるブログエントリーが公開されていたりします。
さて、この OSM ですが、地図を読み込んだときの HTTP リクエストでは画像が返ってきます。 地図データをクライアントに投げて描画物を生成するのではなく、サーバ側で生成(あるいはキャッシュ取得)を行った結果を返しています。
これだけだと地図データが何なのか分かりづらいですね。
OSM では右側のメニューに、近辺の地図エンティティを取得する機能が提供されています。
この機能を用いて、例えば新宿駅西口のバスターミナル付近をクリックしたときには、クリックした座標近辺にあるエンティティがリストで表示されますが、これが OSM のデータです。
各要素にマウスオンすると、それが地図上のどこでどのよう形状をしているかがハイライトされます。
画像の例では、 Service Road という、道路の分類の一つにマウスオンしていますが、これはバス停の道路です。
クリックするとより詳細な情報を見ることができます。
このうち Tags の項目は、地図エンティティのセマンティックを表現する情報で、人間にとっても取り扱いやすい情報です。
建物の高さや階層などの構造を表現する情報も Tags に含まれることがあります。
上記エンティティの場合、道路は一方通行であり、バス運行に用いる道路であることが Tags で示されています。
(Tags の読み取り方は OSM の Wiki を参照するとより理解しやすいでしょう)
詳細情報の一番上に Way という記載あるように、この地図エンティティは道などの経路を持つものを示しています。
道は、それを構成する点 (Node) で結ばれていますが、Node の情報は 画像下部の Nodes の項目をクリックすることで確認できます。
実際にクリックしてみると、 Location の項目に座標情報が表示されますが、座標は馴染み深い緯度経度で表現されていることがわかります。
座標あるいは範囲の指定
さて、ここで OSM の地図を全世界広域表示してみましょう、全ての大陸が一画面に表示されますね。 地図の表現には多くの種類がありますが、上図からも分かるように OSM では正角円筒図法であるメルカトル図法で地図を表示しています。メルカトル図法は、地図の見やすさを重視する代わりに緯度に比例して縮尺を歪めています、赤道直下を除いては正確な縮尺ではありません。
例えば、下記は緯度に差がある日本とイギリスを、同じ縮尺のメルカトル図法で国土のほぼ全体が入るように表示した画像です。
これらの画像だけ見た時、日本とイギリスではどちらの国土面積が大きいと感じるでしょうか、またその差はどのくらいでしょう?
思ったよりも差があったのではないでしょうか。
縮尺の正確性を重視したい場合、地図表現ではメルカトル図法以外に舟型多円錐図法やモルワイデ図法などの図法があります。
右: モルワイデ図法 (wikipedia より引用)
しかし、 OSM のようなサービスでこのような地図表示をされると見づらいですよね。
人間が閲覧する分にはメルカトル図法が適しているかと思われます。
さて、 OSM のようにユーザに対して地図画像を表示するようなサービスは、大抵の場合は世界全体ではなく、一部地域の矩形をユーザからリクエストされることが多いでしょう。
ここで取得範囲の指定方法の問題に直面します。
下記のように、取得したい範囲の矩形の対角線を結ぶ2点の緯度経度をいくつか指定するとします。
{ diagonals: [ { southwest: { lat: 0.000, long: 0.000 }, northeast: { lat: 10.000, long: 10.000 } }, { southwest: { lat: 0.000, long: 70.000 }, northeast: { lat: 10.000, long: 80.000 } } ] }上記の場合は diagonals のどちらの要素も緯度、経度同士の差が 10度であるため、数字上はいずれも正方形のように見えます。
しかし実際に取得された矩形を見てみると、メルカトル図法の地図上では大きく異なります。
このように、「メルカトル図法で表現された地図上での正方形範囲を指定する」という場合には、素直に緯度経度の座標系を用いることはできません。
これに対して、例えば同じメルカトル図法を採用している Azure Map では、地図を四分木した正方形で範囲を取得します
https://docs.microsoft.com/en-us/azure/azure-maps/zoom-levels-and-tile-grid?tabs=csharp
四分木で分けられた矩形を更に四分木する、これを繰り返すことで取得範囲が徐々に狭域になってきます。
座標指定はシンプルで、四分木の中のどの矩形であるかを表す 0~3 の数字の羅列です。
これを、四分木を正方形のインデックスで、四分木した数だけ連結したものを座標 (QuadKey) として扱います。
繰り返せば繰り返すほど狭域を取得することになるため、その繰り返しの数(=座標の長さ)を zoom level として表現しています。
こうすることで、理論上は世界をユニークな正方形で 1cm 単位にも分割できます。
また、この矩形座標と緯度経度は相互変換が可能なので、後述するデータ検索にも支障はありません。
おまけ
上記の方法は取得範囲こそ正方形であるものの、メルカトル図法上の地図で正方形であるため、実際に取得される面積は同じズームレベルでも緯度によって異なります。
地図を球面で表現するなど、同じズームレベルでどこでも同じ面積が取得したい、というユースケースにおいては S2Cell という範囲取得方法も有効でしょう。
https://s2geometry.io/
S2Cell はポケG○でも採用されているという話もあります。
正方形での範囲取得ではないものの、地球上のどこでもある程度任意の縮尺で、同じ面積の範囲をユニークな ID で取得できます。
上記の方法は取得範囲こそ正方形であるものの、メルカトル図法上の地図で正方形であるため、実際に取得される面積は同じズームレベルでも緯度によって異なります。
地図を球面で表現するなど、同じズームレベルでどこでも同じ面積が取得したい、というユースケースにおいては S2Cell という範囲取得方法も有効でしょう。
https://s2geometry.io/
S2Cell はポケG○でも採用されているという話もあります。
正方形での範囲取得ではないものの、地球上のどこでもある程度任意の縮尺で、同じ面積の範囲をユニークな ID で取得できます。
地理空間情報検索
データ取得範囲の指定ができたとしても、サービスは大量の地理空間情報から適切に欲しい情報を検索して返す必要があります。大量のデータを扱う場合、デジタルサービスではデータベースを用いることが多いですが、地理空間情報も一部のデータベースで扱うことができます。
PostgreSQL では postgis という拡張機能を追加することで地理空間情報を扱う geometry 型をスキーマに用いることができるようになります。
https://postgis.net/
また、MySQL 8.0 以降でも地理空間情報を扱えるようになっています。
https://dev.mysql.com/doc/refman/8.0/en/spatial-types.html
SQL で地理空間情報を検索する場合、座標で検索できます。
下記は PostgreSQL + postgis の例ですが、緯度経度座標系の 2点、
Point(139.1234, 35.1234)
と Point(139.9876, 35.9876)
を結ぶ直線を対角線に持つ矩形範囲内に存在するレコードを maps テーブルの geometry 型のカラムから検索し、 geometry 型を GeoJson に変換して取得するクエリです。GeoJson については後述します。
SELECT ST_AsGeoJson(geom) FROM maps WHERE ST_Intersects( geom, ST_SetSRID( ST_MakeBox2d( ST_Point(139.1234, 35.1234), ST_Point(139.9876, 35.9876) ), 4326 ) )入力値は緯度経度の座標である浮動小数ですが、これが緯度経度の座標系であることを表すために
ST_SetSRID
関数を実行しています。ST_SetSRID
は、渡した引数が何の座標系であるかを指定する関数で、引数の 4326 は WGS84、つまり緯度経度の座標系を示します。上記の例では geom に保存されている地理空間の座標が WGS84 で保存されているため、入力値も WGS84 の座標系で済んでいますが、 メルカトル図法 (Pseudo-Mercator) で保存されている場合は、下記のように変換しなければなりません。
Pseudo-Mercator の座標系の SRID は 3857 です。
SELECT ST_AsGeoJson(ST_Transform(geom, 4326)) FROM maps WHERE ST_Intersects( geom, ST_Transform( ST_SetSRID( ST_MakeBox2d( ST_Point(139.1234, 35.1234), ST_Point(139.9876, 35.9876) ), 4326 ), 3857 ) )
地理空間情報フォーマット
データ検索ができたとしても、取得されたデータを正しく返却できなければ意味がありません。postgis の geometry 型には、何もしなければ下記のようなデータが入り、そのまま使ったり読んだりする取り回しが良くありません。
0101000020110F00006D6885A92C9B6B412FB0D0C701EA4D41先程の節では、この geometry 型のカラムに対して
ST_AsGeoJson
という関数を用いて処理しやすい JSON 文字列に変換処理をかけていました。GeoJson とは、 JSON 文字列であらゆる地理空間情報を表現するための JSON 構造の定義です。
https://geojson.org/
GeoJson は座標系が何であるかを特定しないため、同じ位置を表すオブジェクトでも異なる座標系で表現できます。
メルカトル (Pseudo-Mercator, SRID: 3857)
{"type":"Point","coordinates":[14473573.3,3920899.56]}
緯度経度 (WGS84, SRID: 4326)
{"type":"Point","coordinates":[130.01832109,33.19262388]}GeoJson のプロパティの
type
では地図上のどのような形状であるかを指定できます。主だった種類は下記のとおりです。
Point
: バス停やポストなど、点で表現できるオブジェクトLineString
: 道路や川のような線で表現されるオブジェクトPolygon
: 敷地や湖沼などのような範囲をもつオブジェクト
MultiPolygon
などの type も存在します。また OSM では、川は川でも川幅を持つオブジェクト (Polygon) と川の経路を表すオブジェクト (LineString) が分けて登録されています。
そのため、川岸と川の境目もデータとして区別ができます。
おまけ
Apple は Indoor Mapping Data Format (以下、IMDF) という、その名の通り屋内構造をデータとして表現するためのフォーマットを公開しています。
この IMDF は GeoJson との互換を担保し、これまでトポロジーを扱うことが主だった GeoJson に対して、ドアや階層などの屋内構造ならではのより具体的な定義を拡張しています。 一方の OSM は、トポロジー以外の地理空間情報をエンティティに関連付ける手法として、独自のデータ定義の Tags を用いています。
Apple は Indoor Mapping Data Format (以下、IMDF) という、その名の通り屋内構造をデータとして表現するためのフォーマットを公開しています。
この IMDF は GeoJson との互換を担保し、これまでトポロジーを扱うことが主だった GeoJson に対して、ドアや階層などの屋内構造ならではのより具体的な定義を拡張しています。 一方の OSM は、トポロジー以外の地理空間情報をエンティティに関連付ける手法として、独自のデータ定義の Tags を用いています。
おさらい
さて、ここまでで OSM という UI から入力値である座標(あるいは範囲)の導出、そして地理空間情報の検索方法と出力値のフォーマットまで見てきました。任意座標から GeoJson を返す地図サービスを想定したとき、一連の流れをまとめると下記のようになります。
- ユーザクライアントが地図サービスを開く
- パラメータとして現在地の GPS 座標と、希望の縮尺がサービスに送られる
- サービス内部で GPS 座標と希望の縮尺を元に地理空間情報の取得範囲を決定する
- データベースから、取得範囲に交差することを条件として地理空間情報を検索する
- 検索結果を GeoJson に変換してユーザクライアントに返す
- ユーザクライアントは GeoJson をパースして任意の地図描画を行いユーザにプレゼンテーションする
現実的な課題
これまでの情報でも地理空間情報を操ることはできますが、それを適切に操ることができるかというとまた別の話です。実際に地理空間情報を運用していると下記のような課題に直面します。
- 膨大なレコードが入っている DB の検索最適化
- 地理空間情報の更新
- GeoJson を受け取る場合のクライアントへの通信量
- サーバでレンダリングしない(できない表現である)場合のクライアント描画負荷
膨大なレコードが入っている DB の検索最適化
AROW では、 例えば Point だけ集めたテーブル、 LineStrings だけ集めたテーブル、などのようにプリミティブなデータ種類別に集約したテーブル群で AROW DB を提供しています。ここから、デベロッパー様の具体的なユースケースに応じて集計したテーブルやマテリアライズドビューなどの作成を提案させていただいています。
例えば、「東京都の情報で十分だよ」などの場合は東京都を表す Polygon と交差するエンティティだけを集めたテーブル(もしくはマテリアライズドビュー)を作成する、などです。
また、同じ LineStrings でも、それが道路なのか川なのかを識別するためのカラムを追加し、そこに対してインデックスを張る、なども行っています。
地理空間情報の更新
ここでの地理空間情報の更新は、デベロッパーによる地理空間情報のカスタマイズと、 AROW DB 自体の更新の 2 つの課題を指します。前者については、オリジナルのデータを汚染せずにカスタマイズが可能な管理ツールを提供することで解決していますが、後者はデベロッパー様の管理・運用体制次第で提案できる内容が変わってきます。
定常メンテなどが許容されるサービスであればメンテ中の更新となりますが、ダウンタイムを持たない方針のサービスの場合は DB インスタンスもしくは参照 DB を切り替えるなど、少しデベロッパー様の運用方針に食い込んだ提案が必要です。
GeoJson を受け取る場合のクライアントへの通信量
AROW のシステムとしてできる範囲が大きくないので、こちらも提案ベースになります。シリアライザをより効率の良いものにしたり、 gzip 圧縮をするなど、データはそのままでサイズを小さくする手法や、取得済みデータのローカルキャッシュを作るなど、様々な対応案を提案しています。
サーバでレンダリングしない(できない表現である)場合のクライアント描画負荷
具体的には Unity などのような 3D でのレンダリング処理が該当するかと思います。Unity の描画処理は AROW Unity SDK として提供されていますが、広範囲の地理空間情報を建物も含めて描画したい、となった場合は頂点数やバッチコール数が肥大するため、デベロッパー様がどのような表現をしたいかに応じて描画処理改善のアップデートやサポートをさせていただいています。
まとめ (そして突然のメタバース)
本稿では地理空間情報に関連する技術を一通り眺めましたが、いかがでしたでしょうか。構造やユーザーなどの実存するエンティティは、必ず地理空間上の座標を有しています。
その座標に対して関連する情報を持たせたり、利用者やサービスプロバイダに応じた情報の多重化を行ったり、多重化した情報の中から欲しい情報をフィルタリングする、ということができるのはデジタルならではの強みです。
更にデジタルでは、実存しないエンティティに対して座標も定義できます、実際にある概念としてはジオフェンシングなどでしょうか。
いずれにせよ、地理空間情報をデジタルで扱えること自体が、発明の大きなポテンシャルを秘めています。
昨今ではメタバースがバズっていますが、地理空間情報の領域においてはメタバースという言葉がバズる以前の数年前から、「コモングラウンド」や「デジタルツイン」という言葉で地理空間情報のデジタルとの相互運用が表現されてきました。
メタバースについては、米投資家のマシュー・ボール氏は下記の 7つの項目がメタバースの定義であると、自身のサイトで記しています。
- Be persistent: 永続する、一時停止やリセットなどはない。
- Be synchronous and live: 同期的でライブである(一過性である)
- Be without any cap to concurrent users, while also providing each user with an individual sense of “presence”: ユーザに上限がなく、ユーザ自身の実在を認識できる
- Be a fully functioning economy: 十分に経済が機能している
- Be an experience that spans both the digital and physical worlds, private and public networks/experiences, and open and closed platforms: デジタルと現実などとの間に垣根がない
- Offer unprecedented interoperability: メタバース間での相互運用性を有する
- Be populated by “content” and “experiences” created and operated by an incredibly wide range of contributors: 様々なユーザから創出されるコンテンツと体験にあふれる
これらの、何がメタバースであるか、何がそうでないか、という定義の一説については、私自身も概ねそうであると思っています。
さて、現実世界は、デジタルの歴史よりも遥かに古くから存在することから、先程のメタバースの定義のうち 2つの要素を前提としていませんでした。
- Be an experience that spans both the digital and physical worlds, private and public networks/experiences, and open and closed platforms: デジタルと現実などとの間に垣根がない
- Offer unprecedented interoperability: メタバース間での相互運用性を有する
メタバースという名称は、一次的な現実のユニバースに対してそれを超越するという意味で「メタ」と冠されたものです。
しかし、我々が普段過ごしている現実自体がメタバースの定義を満たせれば、他の様々なメタバース群の恩恵を受けられる最も身近なメタバースは現実世界になるのではないでしょうか。
幸い、技術は急速に進歩しており、PLATEAU などのオープンデータの成熟や、非中央集権的なパラダイムである web3 の勃興などに牽引され、徐々に現実世界がメタバースの定義を満たせるようになってきています。
web3 が象徴する分散型であるかどうかにかかわらず、サービスやプラットフォームをまたぐ前提の技術や思想の発展により、より垣根のない状態が当たり前になると考えています。
私自身、 AROW に関わる以前より、「デジタルツイン」や「コモングラウンド」といった問題の解決に関心を持っていました。
メタバースの潮流の後押しにより、人々がより価値を享受しやすい形でそれを実現できればと思っています。
それでは、良いお年を、アリーヴェデルチ!
明日は・・・
山﨑 拓也 さんによる「iOSのPWA対応時に気をつけるべきこと」です、お楽しみに!ドリコムでは一緒に働くメンバーを募集しています!
募集一覧はコチラを御覧ください!