国土地理院ベクトルタイルをO-map風にスタイル設定する
↓で紹介した手順のうち、オリエンテーリング地図(O-map)風にスタイル設定するところをnoteに記録をつけながらやっていきます。
できあがったものを先に貼っておきます。
やること
国土地理院ベクトルタイルをISOM2017-2になるべく寄せて表示するためのスタイル設定を、Maputnikというオンラインエディタで作成します。そのための下準備を主にやっていきます。
作業
ミリメートルからピクセルに単位換算
ISOM2017-2では線の幅などの単位がミリメートルで指定されていますが、MapLibre GL JSで指定できる数値の単位はピクセルなので、単位換算する必要があります。
まず検索して、公式情報は見つけられませんでしたがMapLibre GL JSでは96ピクセルが1インチらしいという複数の情報を見つけたのでこの値を信じて使うことにします。
1インチは25.4ミリメートルなので、96ピクセルが25.4ミリメートルということになり、電卓で計算して、1ミリメートルが約3.77952755905518ピクセルという数字が出ました。
小数点以下を四捨五入して、MapLibre GL JS上の表示で1ミリメートルは4 ピクセルということにします。
国土地理院ベクトルタイルから使う地物を選ぶ
O-mapの原図によく使われることでおなじみの基盤地図情報と同じように、国土地理院ベクトルタイルにも、行政区画の境界線などのオリエンテーリングでは使わない地物が多数含まれているため、必要なものだけを選んで抜き出す必要があります。
国土地理院ベクトルタイルに含まれる地物を「地物コード及び表示ズームレベル一覧」、「地物等の属性一覧」から確認し、ISOM2017-2と対応できるものをピックアップしていきます。
そうしてピックアップした地物とISOM2017-2の記号番号をOpenOrienteering Mapper(以下OOM)のCRTファイルの形式でまとめて、以下のようになりました。
# 等高線
101 ftCode = 7351 OR ftCode = 7352 OR ftCode = 7353
# 砂礫地
210 ftCode = 7403
# 水域面
301.1 ftCode = 5000
# 水涯線
## 河川
301.4 ftCode = 5201 OR ftCode = 5202 OR ftCode = 5203
## 湖池
301.4 ftCode = 5231 OR ftCode = 5232 OR ftCode = 5233
## 海岸線
301.4 ftCode = 5101 OR ftCode = 5102 OR ftCode = 5103
# 一条河川
304 ftCode = 5301
# 枯れ川
306 ftCode = 5302
# 湿地
307.1 ftCode = 7401
# 道路縁
## 道路-通常部-通常部
501.2 ftCode = 2201 OR ftCode = 2241 OR ftCode = 2204 OR ftCode = 2244
## 道路-通常部-橋・高架
501.2 ftCode = 2203 OR ftCode = 2243
## 道路-庭園路-通常部
501.2 ftCode = 2221 OR ftCode = 2251 OR ftCode = 2224
## 道路-庭園路-橋・高架
501.2ftCode = 2223
# 広い道路
## 幅員区分5.5m-13m未満。トンネルを除外。
502 rnkWidth = 2 AND ftCode != 2704 AND ftCode != 2714
## 幅員区分13m以上19.5m未満。トンネルを除外。
502 rnkWidth = 3 AND ftCode != 2704 AND ftCode != 2714
## 幅員区分19.5m以上。トンネルを除外。
502 rnkWidth = 4 AND ftCode != 2704 AND ftCode != 2714
# 道路
## 幅員区分 3m未満。徒歩道・石段・トンネルを除外。
503 rnkWidth = 0 AND NOT ftCode ~= 272 AND NOT ftCode ~= 273 AND NOT ftCode ~= 4
## 幅員区分 3m以上5.5m未満。石段・トンネルを除外。
503 rnkWidth = 1 AND NOT ftCode ~= 273 AND NOT ftCode ~= 4
# 徒歩道
505 ftCode = 2721 OR ftCode = 2722 OR ftCode = 2723
# 電車。地下部分・索道を除外
509 ftCode = 8201 AND railState != 2 AND railState != 3 AND NOT rtCode ~= 40206
# 索道・送電線
510 rtCode ~= 40206 OR ftCode = 8202
# 建物
521.3 ftCode = 3101 OR ftCode = 3102 OR ftCode = 3103
# 無壁舎
522.1 ftCode = 3111 OR ftCode = 3112
# パイプライン
528 ftCode = 5321
# 階段
532 ftCode = 2731 OR ftCode = 2732 OR ftCode = 2733
また、上の地物を表示方法で以下のように分類しました。
線
実線
101 Contour
(今回は使わない)
301.4 Uncrossable body of water, bank line
304 Crossable watercourse
501.2 Paved area, bounding line
(今回は使わない)
503 Road
実線(枠線あり)
502 Wide road, minimum width
破線
306 Minor/seasonal water channel
505 Footpath
組み合わせ
509 Railway
510 Power line, cableway or skilift
(今回は使わない)
532 Stairway
面
単純な塗りつぶし
301.1 Uncrossable body of water (full colour)
521.3 Large building
522.1 Canopy
パターン
210 Stony ground, slow running
(今回は使わない)
307.1 Uncrossable marsh
(今回は使わない)
スタイル設定に含める情報を決める
MapLibre Style Spec を参照し、上の表示方法の分類ごとにスタイル設定に必要な情報を検討します。
線
実線
「line-color」に線の色をカラーコードで指定します。
「line-width」に線の幅をピクセル単位で指定します。
「line-cap」に線の端の処理を「butt」、「round」、「square」から指定します。「round」、「square」はOOMにそのままあります。「butt」はOOMのラインキャップ「flat」に対応できそうです。
「line-join」に線の角の処理を「bevel」、「round」、「miter」から指定します。これはOOMにそのままあります。
他に不透明度などの設定もできますが今回は使わないことにします。
実線(枠線あり)
MapLibre/Mapboxでは、線の枠線は別のレイヤを下に重ねて表現します。たとえば、線に幅1ピクセルの枠線を引きたい場合、もともとの線と同じ場所に幅が2ピクセル広い線を下に重ねて、両側に1ピクセルずつはみ出させるような書き方になります。なので、必要な情報としては実線と基本的には同じで、「line-color」、「line-width」の値を内側の線と枠線の両方に用意します。
破線
通常の線と同じ設定項目に加えて、「line-dasharray」に、線の長さと空白の長さをピクセルで指定します。
組み合わせ
同じ地物に対して破線と実線のレイヤを重ねて表現します。たとえば509 Railwayの場合は黒い実線の上にそれより少し細い白い破線を重ねるような書き方ができます。
面
単純な塗りつぶし
「fill-color」に塗りつぶしの色をカラーコードで指定します。
他にも、不透明度やアンチエイリアス、輪郭線なども設定できますが今回は使わず、色だけ指定することにします。
パターン
縞模様などを数値で指定することはできなくて、「fill-pattern」で画像ファイルを並べる方法しか用意されていないようです。今後の課題ということにして今回の対象からは外すことにします。
道路の幅について
ISOM2017-2で502 Wide roadの道幅は実際の幅で書かれるべきとあります。
今回、国土地理院ベクトルタイルの以下それぞれの幅員区分について、下限の幅を1:15000の縮尺で表示したときの地図上の幅をline-widthにいれることにします。
幅員区分5.5m-13m未満
1.5px
幅員区分13m以上19.5m未満
3.5px
幅員区分19.5m以上
5.2px
ズームレベルの変更に合わせて道の太さを変えることもできるはずで、それは今後の課題とします。
値を入れていく
OOMの記号セットから必要な情報を拾っていきます。
実線
301.4 Uncrossable body of water, bank line
line-color
#000000
(Black 100%)
line-width
0.72px
(0.18mm)
line-cap
butt
line-join
bevel
304 Crossable watercourse
line-color
#00FFFF
(Blue 100%)
line-width
1.2px
(0.30mm)
line-cap
butt
line-join
miter
503 Road
line-color
#000000
(Black 100%)
line-width
1.40px
(0.35mm)
line-cap
butt
line-join
miter
実線(枠線あり)
502 Wide road, minimum width
line-color(内側)
#e8ae80
(Upper brown 50%)
line-color(枠線)
#000000
(Black below lower brown 50%)
line-width(内側)
rnkWidth=2のとき
1.5px
rnkWidth=3のとき
3.5px
rnkWidth=4のとき
5.2px
line-width(枠線)
rnkWidth=2のとき
2.5px
rnkWidth=3のとき
4.5px
rnkWidth=4のとき
6.2px
line-cap
butt
line-join
miter
破線
306 Minor/seasonal water channel
line-color
#00FFFF
(Blue 100%)
line-width
0.72px
(0.18mm)
line-cap
butt
line-join
miter
line-dasharray
[5.00px, 1.00px]
([1.25mm, 0.25mm])
505 Footpath
line-color
#000000
(Black 100%)
line-width
1.00px
(0.25mm)
line-cap
butt
line-join
miter
line-dasharray
[8.00px, 1.00px]
([2.00mm, 0.25mm])
組み合わせ
509 Railway
line-color(黒実線)
#000000
(Black 100%)
line-color(白破線)
#ffffff
(White for railway)
line-width(黒実線)
1.40px
(0.35mm)
line-width(白破線)
1.00px
(0.25mm)
line-cap
butt
line-join
miter
line-dasharray(白破線)
[4.00px, 6.00px]
([1.00mm, 1.50mm])
532 Stairway
line-color(黒実線)
#000000
(Black 100%)
line-color(白破線)
#ffffff
(White over green)
line-width(黒実線)
2.00px
(0.50mm)
line-width(白破線)
1.60px
(0.40mm)
line-cap
butt
line-join
miter
line-dasharray(白破線)
[1.60px, 0.40px]
([0.40mm, 0.10mm])
面
301.1 Uncrossable body of water (full colour)
fill-color
#00ffff
(Blue 100% for area features)
521.3 Large building
fill-color
#595959
(Black 65%)
522.1 Canopy
fill-color
#cccccc
(Black 20%)
Maputnikで入力していく
ざっくり手順:
Maputnikを開きます。
Open > Empty Styleで画面を初期化して、Data Sources > Add New Sourceで国土地理院ベクトルタイルを追加します。
Add Layer で、「地物コード及び表示ズームレベル一覧」を参照してSource Layerを選び、レイヤを追加します。
filterで同じレイヤの中の対象地物を絞り込み、先に準備した値を入れていきます。
そんで一通り入力したら、ExportでJSONファイルを保存します。こんな感じになりました。 今回の作業はここまでとします。
{
"version": 8,
"name": "gsivt2omap",
"metadata": {"maputnik:renderer": "mlgljs"},
"sources": {
"gsivt": {
"type": "vector",
"tiles": [
"https://cyberjapandata.gsi.go.jp/xyz/experimental_bvmap/{z}/{x}/{y}.pbf"
],
"minzoom": 0,
"maxzoom": 16
}
},
"sprite": "",
"glyphs": "https://orangemug.github.io/font-glyphs/glyphs/{fontstack}/{range}.pbf",
"layers": [
{
"id": "301-水域-gsivt",
"type": "fill",
"source": "gsivt",
"source-layer": "waterarea",
"paint": {"fill-color": "#00ffff"}
},
{
"id": "301-水涯線(海)-gsivt",
"type": "line",
"source": "gsivt",
"source-layer": "coastline",
"filter": [
"any",
["==", "ftCode", 5101],
["==", "ftCode", 5102],
["==", "ftCode", 5103]
],
"paint": {"line-width": 0.72}
},
{
"id": "301-水涯線(川)-gsivt",
"type": "line",
"source": "gsivt",
"source-layer": "river",
"filter": [
"any",
["==", "ftCode", 5201],
["==", "ftCode", 5202],
["==", "ftCode", 5203]
],
"paint": {"line-width": 0.72}
},
{
"id": "301-水涯線(湖)-gsivt",
"type": "line",
"source": "gsivt",
"source-layer": "lake",
"filter": [
"any",
["==", "ftCode", 5231],
["==", "ftCode", 5232],
["==", "ftCode", 5233]
],
"layout": {"line-join": "bevel"},
"paint": {"line-width": 0.72}
},
{
"id": "304-水路-gsivt",
"type": "line",
"source": "gsivt",
"source-layer": "river",
"filter": ["any", ["==", "ftCode", 5301]],
"paint": {"line-color": "#00ffff", "line-width": 1.2}
},
{
"id": "306-細い水路-gsivt",
"type": "line",
"source": "gsivt",
"source-layer": "river",
"filter": ["any", ["==", "ftCode", 5302]],
"layout": {"line-join": "miter"},
"paint": {
"line-color": "#00ffff",
"line-width": 0.72,
"line-dasharray": [1.25, 0.25]
}
},
{
"id": "503-道路-rW0-gsivt",
"type": "line",
"source": "gsivt",
"source-layer": "road",
"filter": [
"all",
["==", "rnkWidth", 0],
[">=", "ftCode", 2701],
["<=", "ftCode", 2713],
["!=", "ftCode", 2704]
],
"layout": {"visibility": "visible"},
"paint": {"line-color": "#000000", "line-width": 1.4}
},
{
"id": "503-道路-rW1-gsivt",
"type": "line",
"source": "gsivt",
"source-layer": "road",
"filter": [
"all",
["==", "rnkWidth", 1],
[">=", "ftCode", 2701],
["<=", "ftCode", 2713],
["!=", "ftCode", 2704]
],
"layout": {"visibility": "visible"},
"paint": {"line-color": "#000000", "line-width": 1.4}
},
{
"id": "505-徒歩道-gsivt",
"type": "line",
"source": "gsivt",
"source-layer": "road",
"filter": [
"any",
["==", "ftCode", 2721],
["==", "ftCode", 2722],
["==", "ftCode", 2723]
],
"layout": {
"visibility": "visible",
"line-join": "miter",
"line-cap": "butt"
},
"paint": {"line-color": "#000000", "line-dasharray": [8, 1]}
},
{
"id": "532-階段-黒部分-gsivt",
"type": "line",
"source": "gsivt",
"source-layer": "road",
"filter": [
"any",
["==", "ftCode", 2731],
["==", "ftCode", 2732],
["==", "ftCode", 2733]
],
"layout": {
"visibility": "visible",
"line-join": "miter",
"line-cap": "butt"
},
"paint": {"line-color": "#000000", "line-width": 2}
},
{
"id": "532-階段-白部分-gsivt",
"type": "line",
"source": "gsivt",
"source-layer": "road",
"filter": [
"any",
["==", "ftCode", 2731],
["==", "ftCode", 2732],
["==", "ftCode", 2733]
],
"layout": {
"visibility": "visible",
"line-join": "miter",
"line-cap": "butt"
},
"paint": {
"line-color": "#ffffff",
"line-width": 1.6,
"line-dasharray": [1.6, 0.4]
}
},
{
"id": "502-道路-rW2-枠線-gsivt",
"type": "line",
"source": "gsivt",
"source-layer": "road",
"filter": [
"all",
["==", "rnkWidth", 2],
["!=", "ftCode", 2704],
["!=", "ftCode", 2714]
],
"layout": {"visibility": "visible"},
"paint": {"line-width": 2.5}
},
{
"id": "502-道路-rW2-gsivt",
"type": "line",
"source": "gsivt",
"source-layer": "road",
"filter": [
"all",
["==", "rnkWidth", 2],
["!=", "ftCode", 2704],
["!=", "ftCode", 2714]
],
"layout": {"visibility": "visible"},
"paint": {"line-width": 1.5, "line-color": "#e8ae80"}
},
{
"id": "502-道路-rW3-枠線-gsivt",
"type": "line",
"source": "gsivt",
"source-layer": "road",
"filter": [
"all",
["==", "rnkWidth", 3],
["!=", "ftCode", 2704],
["!=", "ftCode", 2714]
],
"layout": {"visibility": "visible"},
"paint": {"line-width": 4.5}
},
{
"id": "502-道路-rW3-gsivt",
"type": "line",
"source": "gsivt",
"source-layer": "road",
"filter": [
"all",
["==", "rnkWidth", 3],
["!=", "ftCode", 2704],
["!=", "ftCode", 2714]
],
"layout": {"visibility": "visible"},
"paint": {"line-width": 3.5, "line-color": "#e8ae80"}
},
{
"id": "502-道路-rW4-枠線-gsivt",
"type": "line",
"source": "gsivt",
"source-layer": "road",
"filter": [
"all",
["==", "rnkWidth", 4],
["!=", "ftCode", 2704],
["!=", "ftCode", 2714]
],
"layout": {"visibility": "visible", "line-join": "miter"},
"paint": {"line-width": 6.2}
},
{
"id": "502-道路-rW4-gsivt",
"type": "line",
"source": "gsivt",
"source-layer": "road",
"filter": [
"all",
["==", "rnkWidth", 4],
["!=", "ftCode", 2704],
["!=", "ftCode", 2714]
],
"layout": {"visibility": "visible", "line-join": "miter"},
"paint": {"line-width": 5.2, "line-color": "#e8ae80"}
},
{
"id": "509-線路-黒部分-gsivt",
"type": "line",
"source": "gsivt",
"source-layer": "railway",
"filter": [
"all",
["==", "ftCode", 8201],
["!=", "railState", 2],
["!=", "railState", 3],
["!in", "rtCode", 40206]
],
"layout": {"visibility": "visible"},
"paint": {"line-color": "#000000", "line-width": 1.4}
},
{
"id": "509-線路-白部分-gsi",
"type": "line",
"source": "gsivt",
"source-layer": "railway",
"filter": [
"all",
["==", "ftCode", 8201],
["!=", "railState", 2],
["!=", "railState", 3],
["!in", "rtCode", 40206]
],
"layout": {"visibility": "visible"},
"paint": {
"line-color": "#ffffff",
"line-width": 1.0,
"line-dasharray": [2, 1]
}
},
{
"id": "521-建物-gsivt",
"type": "fill",
"source": "gsivt",
"source-layer": "building",
"filter": [
"any",
["==", "ftCode", 3101],
["==", "ftCode", 3102],
["==", "ftCode", 3103]
],
"paint": {"fill-color": "#595959"}
},
{
"id": "522-天蓋-gsivt",
"type": "fill",
"source": "gsivt",
"source-layer": "building",
"filter": ["any", ["==", "ftCode", 3111], ["==", "ftCode", 3112]],
"paint": {"fill-color": "#cccccc"}
}
],
"id": "uc5dhss"
}