アプリで使える日本国内の地形/建物の3Dモデルをつくる


日本国内でも様々なデータが公開されるようになってきました。今回はこのうちプレゼン資料やXRなどにも利用できそうな地形データや建物データについてアプリケーションで利用しやすいWavefront OBJ (.obj)形式に変換することを試してみました。
出力される.objファイルは、PowerPoint などの Microsoft Office 製品やUnityなどのゲームエンジン、各種3Dソフトウェアなどで開けるよう互換性を考慮しています(例えば、PLATEAUで配布されている.objファイルはそのままでは読めないアプリケーションがあります) ので、いろいろ活用してみてください。

地形の3Dモデルを利用する

地理院地図は、従来よりSTL, VRML, WebGL向けの3Dモデルを作成することができるようになっています。このうち他のアプリケーションで利用可能そうに見えるVRMLは、最近(2.79より新しい)のBlenderでは下記のようなエラーで開くことができなくなっています。このエラーはどうやらしばらく修正されなさそうなため3.0で修正されましたが、GitHubで公開されている地理院地図のコードをOBJ形式で出力できるように修正してみました

appearance_LoadTexture
   bpyima.use_clamp_x = not repeat_s
AttributeError: 'Image' object has no attribute 'use_clamp_x'

location: <unknown location>:-1

利用方法

  1. https://ksasao.github.io/gsimaps/ を開き、左上の地図をクリック、写真を選択、右上のツールをクリック、右側のバーの3Dをクリック、カスタムをクリック
  2. 緯度・経度の範囲を指定して OK をクリック
  3. 一番下にあるOBJファイルのダウンロードをクリックして、dem.obj, dem.mtl, texture.png の3ファイルを同じフォルダにダウンロード
  4. アプリケーションで開く

Windowsの場合

dem.obj をクリックすると 3Dビューアーが起動します

PowerPoint の場合(他のMicrosoft Office製品でも同様)

dem.obj をドラッグ&ドロップすれば開けます。向きなどを調整可能です。PowerPointを保存すると、内部では .glb 形式で保持されます(.pptxの拡張子を.zipに変更して解凍し、ppt/media フォルダに格納)。

Unity の場合

dem.obj, dem.mtl, texture.png を Project の Assets フォルダ以下にドラッグ&ドロップするとインポートできます。

Project PLATEAU の3D都市モデルを利用する

Project PLATEAU3D都市モデルのうち、東京23区では、アプリケーションで利用しやすいFBX形式、OBJ形式のファイルが提供されているのですが、それ以外の都市では CityGML形式のみとなっています。そこで CityGML(bldg/dem)をOBJ形式に変換して表示するツールを作成しました。テクスチャにも対応しています。詳細な利用方法についてはリンク先を参照してください。


dem(地盤の高さを示す数値標高モデル)については前述の地理院地図のデータのほうが対応エリアが広く、また、テクスチャは別途用意する必要があるので、こちらをあえて利用する必要はないかもしれません。
なお、PLATEAU の CityGML に何種類かあるようでうまく変換されない可能性があります。そのような都市を見つけましたら @ksasaoまでご連絡ください。

(おまけ) 緯度・経度から住所を検索する

 住所から緯度・経度を求めることをジオコーディング、緯度・経度から住所を検索することを 逆ジオコーディング といいます。無料で利用可能なサービスとして、国土地理院APIを利用したものOpenStreetMapを利用したもの などがあります。
 今回は、Geolonia 住所データというオープンデータを利用してみます。このデータでは日本国内の住所、住所カナ、緯度経度の組み合わせが、CSV形式で提供されています。ライセンスはCC BY 4.0 です。
 以下は、緯度・経度から住所等を求めるコードです。

from urllib import request
import os
import pandas as pd
from scipy import spatial

# 住所一覧をダウンロード
url = "https://raw.githubusercontent.com/geolonia/japanese-addresses/master/data/latest.csv"
file = "latest.csv"
if not os.path.exists(file):
    request.urlretrieve(url, file)

# データ読み込み
df = pd.read_csv(file).fillna("")  # データがない要素は空文字に置換
latlon_list = df[["緯度", "経度"]].values
tree = spatial.KDTree(latlon_list) # 検索用に緯度経度のkd木を作る

# 最近傍を探す(ユークリッド距離なので実際の距離とは異なるがおおよそ正しい)
latlon = [35.5311682,139.6970126] # 川崎駅付近
dist, idx = tree.query(latlon)

# 表示
d = df.iloc[idx]
name = d["都道府県名"]+d["市区町村名"]+d["大字町丁目名"]+d["小字・通称名"]
print(name)
print("---")
print(d)

実行結果は下記のようになります。

神奈川県川崎市川崎区駅前本町
---
都道府県コード                             14
都道府県名                             神奈川県
都道府県名カナ                         カナガワケン
都道府県名ローマ字                 KANAGAWA KEN
市区町村コード                        14131.0
市区町村名                           川崎市川崎区
市区町村名カナ                     カワサキシカワサキク
市区町村名ローマ字     KAWASAKI SHI KAWASAKI KU
大字町丁目名                            駅前本町
大字町丁目名カナ                     エキマエホンチョウ
大字町丁目名ローマ字                EKIMAEHONCHO
小字・通称名
緯度                           35.532434
経度                            139.6996
Name: 115783, dtype: object

なお、ジオコーディングについては、公式の JavaScript API があります。こちらも静的ファイルのみで動作するようになっています。