#初めに
この記事は、FOSS4G Advent Calendar 2019、一日目の記事になります!
ともあれ、出来上がりはこちら。農林水産省さまが公開されている農地の区画情報(筆ポリゴン)をMapbox Vector Tile形式に変換して、公開しました。ともあれ、その手順についてまとめます。
#筆ポリゴンってなに?
農林水産省さまの説明によると、
「筆ポリゴン」とは、農林水産省が実施する耕地面積調査等の母集団情報として、全国の土地を隙間なく200メートル四方(北海道は、400メートル四方)の区画に区分し、そのうち耕地が存在する約290万区画について衛星画像等をもとに筆ごとの形状に沿って作成した農地の区画情報です
というものです。見ていただくわかるのですが、農地のGISデータが日本全国でそろっています。自分の調査対象範囲を作るだけでも大変なのに、日本全国作って公開というのは、素晴らしです。**利用規約**はリンク先を見ていただくとして、一部を抜粋すると、以下の通りです。
1)出典の記載について
ア 筆ポリゴンを利用する際は出典を記載してください。
イ 筆ポリゴンを編集・加工等して利用する場合は、上記出典とは別に、編集・加工等を行ったことを記載してください。なお、編集・加工した情報を、あたかも国(又は府省等)が作成したかのような態様で公表・利用してはいけません。
出典:「筆ポリゴンの利用規約」
ということで、Webでの公開等、全く問題ない条件になっています。
折角なのでWebで見られるようにしてみましょう!、と始めました。
#作成手順
##データの入手
筆ポリゴンの利用に関するアンケートのお願いに回答したあと、ダウンロードページに行けます。アンケートを回答するのが面倒ということもあるかもしれませんが、それほど項目が多いわけではないので、我慢しましょう。ダウンロードページのイメージは以下の通りです。都道府県毎にダウンロードできるので、大変便利です。
##データの結合と分割
公開されているデータは、都道府県毎にダウンロード出来るようになっています。一方、MVTに変換する際には、都道府県単位で作業をやると境界部分のデータの処理が面倒になります(同じタイルが二つ発生する)。とはいえ、全国でやるとサイズが大きすぎます。そのため、作業は下の図のようなズームレベル7でデータを作成しました。つまり、都道府県単位のshpを一度結合し、Z=7のタイルに含まれるものを抽出し、一つのGeoJONファイルとしました。
作成されたGeoJSONファイルは、tile07_114_53.geojsonといったファイル名になります。
##tippecanoeのインストール
Ubuntuだと、
sudo apt-get install build-essential libsqlite3-dev zlib1g-dev
git clone https://github.com/mapbox/tippecanoe.git
cd tippecanoe
make -j
make install
といった感じでしょうか? 詳しくは、下を見て(汗
##MVT形式への変更
作成されたgeojsonファイルをmbtile形式に変換します。変換には、Mapboxさんが公開されているtippecanoeを使いました。コマンドは以下の通りです。
for i in *.geojson; do
tippecanoe -f -l fude -o ${i%.geojson}.mbtiles -R ${i:5:1}/${i:7:3}/${i:11:2} -z 16 -pC -pk -P $i
done
それぞれぞれのオプションの意味は、
-f:同名のファイルあった場合上書き
-l:生成されるレイヤ名
-R:範囲指定
-pC:生成されるファイルを圧縮しない
-pk:500Kより大きなタイルをスキップしない
-pf:地物数を200,000に限定しない
-P:ファイル読み込みの並列化
-z:最大ズーム
となります。
そしてこのmbtilesを、MVT形式に出力します。その際には、tile-join というコマンドを使います。具体的には、以下の通りです。簡単ですね
tile-join -e mvt -pk -pC *.mbtiles
このコマンドでは、複数のmbtilesを結合して./mvt
というフォルダにタイルとして出力します。なお、デフォルトは.pbf
になります。
##Webインターフェイス
Webインターフェイスは、leafletを使いました。[サンプル](https://habs.dc.affrc.go.jp/spatial_data/maff_fude_id/index.html#15/36.3642/138.2043)はこちら、コードは以下の通りです。
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet.css"/>
<link rel="stylesheet" href="./plugin/leaflet-gps.css"/>
<title>農地の区画情報(筆ポリゴン)</title>
<style>
html,body {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="//cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet-src.js"></script>
<script src="./plugin/Leaflet.MapboxVectorTile.js"></script>
<script src="./plugin/leaflet-hash.js"></script>
<script src="./plugin/leaflet-gps.js"></script>
<script>
var map = L.map('map',{
minZoom: 7,
maxZoom: 16,
autoZIndex: false,
}).setView([36,138], 7)
var hash = new L.Hash(map)
map.addControl( new L.Control.Gps() )
var popup = L.popup();
var onGsClick = function(e) {
if (!e.feature) return
popup
.setLatLng(e.latlng)
.setContent("<b>ID:</b> "+e.feature.properties.Poly_ID+"<br><b>耕地の種類:</b> "+e.feature.properties.LC)
.openOn(map);
}
var mvtSource = new L.TileLayer.MVTSource({
url: "./mvt/{z}/{x}/{y}.pbf",
minZoom: 14,
maxZoom: 16,
zIndex: 4,
// debug: true,
clickableLayers: ["fude"],
mutexToggle:true,
attribution: "<a href='http://www.maff.go.jp/j/tokei/porigon/index.html' target='_blank'>出典:「筆ポリゴンデータ」(農林水産省)(R1年10月2日に利用)</a>",
getIDForLayerFeature: function(feature) {
return feature.properties["FID"];
},
filter: function(feature, context) {
if (feature.layer.name === 'fude') {
return true;
}
return false;
},
onClick: onGsClick,
style: function (feature) {
var style = {};
var type = feature.type;
switch (type) {
case 1: //'Point'
style.color = 'rgba(255,0,0,1)';
style.radius = function(){
var z = map.getZoom()
var dotsize = 1.5
var radius = dotsize * Math.exp(Math.log(Math.sqrt(z-4)))
return radius
};
break;
case 2: //'LineString'
style.color = 'rgba(161,217,155,0.8)';
style.size = 3;
style.selected = {
color: 'rgba(255,25,0,0.5)',
size: 4
};
break;
case 3: //'Polygon'
var fColor;
if (feature.properties.LC=='田'){
fColor='rgba(255,255,0,0.5)';}
else
if (feature.properties.LC=="畑"){
fColor='rgba(138,95,46,0.5)';}
style.color = fColor;
style.outline = {
color: 'rgba(0,0,0,0.5)',
size: 0.1
};
style.selected = {
color: 'rgba(255,140,0,0.3)',
outline: {
color: 'rgba(255,140,0,1)',
size: 2
}
};
break;
}
return style;
}
});
var habs = L.tileLayer('https://www.finds.jp/ws/tmc/1.0.0/Kanto_Rapid-900913-L/{z}/{x}/{y}.jpg',
{zIndex: 3, attribution: "<a href='http://portal.cyberjapan.jp/help/termsofuse.html' target='_blank'>歴史的農業環境閲覧システム</a>",
maxZoom: 17}).addTo(map);
var seamless = L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/seamlessphoto/{z}/{x}/{y}.jpg',
{zIndex: 2, attribution: "<a href='https://maps.gsi.go.jp/development/ichiran.html' target='_blank'>地理院タイル 全国最新写真(シームレス)・全国ランドサットモザイク画像</a>",
maxZoom: 18
});
var pale = L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/pale/{z}/{x}/{y}.png',
{zIndex: 1, attribution: "<a href='http://portal.cyberjapan.jp/help/termsofuse.html' target='_blank'>地理院タイル 淡色地図</a>",
maxZoom: 18}).addTo(map);
map.addLayer(mvtSource);
var baseMaps = {
"迅速測図" : habs,
"全国最新写真" :seamless,
"淡色地図" : pale
};
var overlayMaps = {
"筆ポリゴン" : mvtSource
};
L.control.layers(baseMaps, overlayMaps).addTo(map);
</script>
</body>
</html>
##おわりに
時間が無く、かなりはしょった説明になりました。そのうち、ちゃんと説明します(汗
明日は、 yoichigmf@github さんになります!