changed 6 years ago
Linked with GitHub

FOSS4G Niigata 2019: 国連と始めるベクトルタイル

日時
2019-09-13T15:00/18:00 (3時間)
講師
柴本 歩

この資料のために書き下ろした内容は CC0 です。


国連と始めるベクトルタイル

会場 WiFi

SSID
(現場合わせ)
パスワード
(現場合わせ)

国連と始めるベクトルタイル

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →


国連ベクトルタイルツールキットとは 1/2

  • 既存のオープンソースソフトウェアを組み合わせて、ベクトルデータからベクトルタイルを生産してホストすることと、ベクトルタイルをスタイリングして最適化することを支援するツールキット。
  • 国連オープン GIS イニシアティブのプロジェクトで、現在のところ、国連地理空間情報課、国連グローバルサービスセンター、国土地理院、農業環境変動研究センター、OSGeo 日本支部、Mapbox から技術者が参加している。

国連ベクトルタイルツールキットとは 2/2

  • 目下、ツールキット収録した Docker コンテナイメージ rasv を整備中
  • rasv を活用したハンズオンマテリアル ango を開発している。

今回つくるもの: 自然災害伝承碑ベクトルタイルサイト

作業開始


会場 WiFi (再掲)

SSID
(現場合わせ)
パスワード
(現場合わせ)

Docker イメージを動かそう

$ docker run -ti --rm unvt/ango
root@09dc97356d7e:~#

* '09dc97356d7e' の部分は異なる

うまくいかない場合

$ curl -O http://ango.vectortiles.xyz/ango-amd64.tar.gz
$ gunzip ango-amd64.tar.gz | docker load

* Raspberry Pi の場合 amd64 → armhf


コマンドを動かしてみる

(# exit) # さっき試した docker run から抜ける
$ docker run -ti --rm -p 3000:3000 -p 8888:8888 unvt/ango
root@fef54f77bc33:~# tippecanoe -v
tippecanoe v1.34.4
root@fef54f77bc33:~# node -v
v10.15.2

上級者向け: ホストボリュームマウント

作業データを保存したり、持ち込みデータを扱う場合はマウントすることをお勧めします。

-v (ホスト側のディレクトリの絶対パス):/media
$ # /Users/hfu を /media として触れるようにする
$ docker run -ti --rm \
-v /Users/hfu/:/media \
-p 3000:3000 -p 8888:8888 unvt/ango

収録されているコマンドの紹介 - 生産

$ tippecanoe -v # ベクトルタイルを生産
tippecanoe v1.34.5
$ tile-join # ベクトルタイルを操作
Usage: tile-join [-f] [-i] [-pk] [-pC] [-c joins.csv] [-X] [-x exclude ...] -o new.mbtiles source.mbtiles ...
$ ogr2ogr --version # データ変換
GDAL 2.4.2, released 2019/06/28
$ osmium --version # OpenStreetMap のデータ変換
osmium version 1.10.0 (v1.10.0-76-g26674e1)
...

収録されているコマンドの紹介 - ホスト

$ node -v # サーバは Node.js で作ります
v10.15.2
$ budo --version # 開発用サーバ
budo v11.6.3
$ pm2 --version # サーバ
3.5.1
$ browserify --version # JavaScript 変換
16.5.0
...

収録されているコマンドの紹介 - スタイル

$ vi --version # スタイルを HJSON 形式で書く
VIM - Vi IMproved 8.1 (2018 May 18, compiled Jun 15 2019 16:41:15)
...
$ hjson -v # HJSON を JSON に変換する
Hjson.js 3.1.2
$ gl-style-validate # Mapbox Style を検証する
usage: ...

収録されているコマンドの紹介 - 最適化

$ node ~/vt-optimizer/index.js --help # ベクトルタイルサイズ最適化

Vector Tile Weight Loser...

ハンズオン作業

  1. 生産
  2. ホスト
  3. (スタイル)
  4. (最適化)

今回のハンズオンでは、基礎編として 1., 2.。

3., 4. は進度に合わせたバリエーションルート。


(1) 生産

GeoJSONS をベクトルタイルに変換

$ cd ango-produce
$ rake
tippecanoe --output=tiles.mbtiles    --read-parallel --force --layer=ndm    --minimum-zoom=7 --maximum-zoom=10    --prefilter='node prefilter.js'    ../geojsons-natural-disaster-monuments/data.geojsons
255 features, 14316 bytes of geometry, 2 bytes of separate metadata, 109216 bytes of string pool
  99.9%  10/900/404  
tile-join --force    --output-to-directory=zxy tiles.mbtiles    --no-tile-compression

まずは実行してみてください


実行された内容

$ cat Rakefile
task :default do
  sh "tippecanoe --output=tiles.mbtiles\
    --read-parallel --force --layer=ndm\
    --minimum-zoom=7 --maximum-zoom=10\
    --prefilter='node prefilter.js'\
    ../geojsons-natural-disaster-monuments/data.geojsons"
  sh "tile-join --force\
    --output-to-directory=zxy tiles.mbtiles\
    --no-tile-compression"
end

ソースデータ

# more ../geojsons-natural-disaster-monuments/data.geojsons
{"geometry":{"type":"Point","coordinates":[128.042983,26.554941]},"type":"Feature","properties":{"ID":"47209-001","LoreName":"津波襲来の碑","LoreYear":"2012","Address":"沖縄県名護市字大浦","DisasterName":"津波<br>(1960年5月24日)","DisasterKind":"津波","DisasterInfo":"昭和35年(1960)5月南米チリでM8.5の地震が起き大津波が発生、津波は太平洋を横
断し日本近海を襲った。当地には数回に亘り襲来。津波高5mにも及び大浦橋が全壊、護岸も決壊した。","Image":"https://maps.gsi.go.jp/legend/disaster_lore/47209/47209-001.jpg","ImageWidth":"1200","ImageHeight":"900"}}
...

一行ごとに GeoJSON Feature が書いてある

RFC 8142: ogr2ogr は GeoJSONS と呼ぶ


tippecanoe

tippecanoe --output=tiles.mbtiles\
    --read-parallel --force --layer=ndm\
    --minimum-zoom=7 --maximum-zoom=10\
    --prefilter='node prefilter.js'\
    ../geojsons-natural-disaster-monuments/data.geojsons
output
出力するベクトルタイルパッケージのパス
layer
レイヤ名 (protips: 複数レイヤを含む場合には、feature.tippecanoe.layer にセット)
prefilter
タイルに切った後にかけるフィルタ

プレフィルタ: 地物ごとの調整

// prefilter.js: 標準入力の各行を `modify()` して出力
const modify = require('./modify.js')
const readline = require('readline')

const rl = readline.createInterface(process.stdin, {})

rl.on('line', (line) => {
  console.log(JSON.stringify(modify(JSON.parse(line))))
})
// modify.js: 与えられた地物を修正して返す
module.exports = (f) => {
  for (k of [
    'DisasterKind', 'DisasterName', 'DisasterInfo', 'LoreName'
  ]) {
    // 余計な <br> タグをとる
    f.properties[k] = f.properties[k].replace(/<br>/g, " ")
  }
  return f
}

tippecanoe で使用したその他のオプション

read-parallel
地物を並列に読む → 速くなる
force
ベクトルタイルパッケージを上書きする
minimum-zoom
生産する最小ズーム (protips: 地物ごとなら feature.tippecanoe.minzoom にセット)
maximum-zoom
生産する最大ズーム (protips: 地物ごとなら feature.tippecanoe.maxzoom にセット)

tile-join

tile-join --force\
    --output-to-directory=zxy tiles.mbtiles\
    --no-tile-compression
force
出力フォルダを上書きする
output-to-directory
出力フォルダ
no-tile-compression
ベクトルタイルを gzip 圧縮せず出力

雑学: gzip 圧縮とベクトルタイルの関係

  1. ウェブではベクトルタイルは gzip 圧縮されて送られるのが普通。そのときは content-encoding: gzip ヘッダをつけて送る。
  2. このため、MBTiles にはもとから gzip 圧縮して格納するのがデフォルト。
  3. プレインなウェブサーバでは content-encoding: gzip つきはデフォルトではなく、非圧縮 で送る。
  4. よって「MBTiles の中では gzip 圧縮済み、ファイルシステムに展開する場合には gzip 圧縮しない」がグッドプラクティス

(2) ホスト

ベクトルタイルパッケージをブラウザで見ることができるようにする。

$ cd ~/ango-host    # ホストプログラムに移動
$ yarn              # 必要なライブラリを導入
$ rake build        # 地図サイトを構築
$ rake start        # サーバをスタート

まずは実行してみてください。

http://localhost:3000


$ rake stop      # サーバを止める

解説: rake build

task :build do # サイトのファイルを作る
  sh "hjson -j htdocs/style.hjson > htdocs/style.json"
  sh "browserify -o htdocs/bundle.js -t " +
    "[ babelify --presets [ @babel/preset-env ] ] app.js"
end
  • htdocs/style.hjson → htdocs/style.json
  • app.js → htdocs/bundle.js

htdocs/style.hjson

{
  version: 8
  center: [135, 35]
  zoom: 7
  sources: {
    v: {
...
          255
        ]
        text-halo-width: 1
      }
    }
  ]
}

Mapbox Style を簡明のため HJSON で書いたもの


なぜスタイルを HJSON で手書きするのか

  • スタイルは意外と論理的なもの
  • Maputnik のような GUI エディタでは見通しが立てにくく、スタイル記述をコンパクトにしにくい
  • Maputnik は特有のメタデータを吐き、expressionsに対応していない
  • より複雑なスタイルは今後 HOCON で書くかも

app.js

const map = new mapboxgl.Map({
  container: 'map',
  style: 'style.json',
  attributionControl: true,
  hash: true
})

単なるウェブ地図起動の JavaScript だが、モダンに書きたいので browserify/babelify で変換している。


解説: rake start

task :start do
  sh "pm2 start process.yml"
end

process.yml

apps:
  - script: index.js
    name: ango
    instances: 4
    exec_mode: cluster

4インスタンスのクラスタモードで起動


解説: rake stop

task :stop do
  sh "pm2 stop ango; pm2 delete ango"
end

解説: rake _mapbox

task :_mapbox do
  sh "cp ../mapbox-gl-js/dist/mapbox-gl.js htdocs"
  sh "cp ../mapbox-gl-js/dist/mapbox-gl.js.map htdocs"
  sh "cp ../mapbox-gl-js/dist/mapbox-gl.css htdocs"
end

別途ビルドした Mapbox GL JS から必要ファイルをコピー


バリエーションルート


  • 別データに挑戦
  • gh-pages を用いたホスティング (要 GitHub アカウント)
  • Vector Tile optimizer を用いた最適化
  • Maputnik を用いたスタイル調整

まとめ

  • 成果紹介
  • 国連ベクトルタイルツールキットのこれから
  • 全体を通しての質疑
  • ラップアップ
  • 集合写真撮影

おわり


参考



オープンジオデータをベクトルタイルに変換する取り組みのアンブレラです。

Select a repo