陸地も OSMデータで描画する。しかし、広域森林や水域などとは描画方法が少し異なる。
OSMの海岸線Wayデータを繋ぎ合わせると、巨大なポリゴンとなる。 小さな島程度であれば、森林や湖と同じように描画できる。しかし、大陸は余りにも巨大であり、 日本地図に限っても、本州、北海道、九州などは巨大なポリゴンであるから、 森林や湖などと同じように、描画するのは無理である。
低ズームの場合は分割は要らないが、高ズームでは、 強大なポリゴンをプログラムで無数の小さいポリゴンに分割して、この小さくしたポリゴンを描画する。
サイト[1]からland-polygons-split-4326.zipおよびsimplified-land-polygons-complete-3857.zipをダウンロードした。
座標系は 4326系にするが、低ズーム用はこれが提供されていないため 3857系とした。いずれ、PostgreSQL/PostGIS で 4326系で CSV出力する。
低ズーム用ファイルを QGIS に読込み、異常がないことを確かめた。QGISで CSVファイルにエクスポートできるはずだが、 今回は、見送った。
データベース osm を作り、create extension postgis を実行して置く。
shp2pgsql -I -s 3857 d:/downloads/simplified-land-polygons-complete-3857/simplified_land_polygons.shp land_polygons > imp.sql psql -h localhost -p 5432 -d osm -U postgres -f imp.sql
データベース osm に テーブル land_polygons が作られる。
COPY (select gid, ST_AsText(ST_Transform(geom,4326)) AS way from land_polygons) TO 'c:/map/simplified_land_polygons.tsv' WITH CSV DELIMITER E'\t';
高ズーム用は以下のようにする。
shp2pgsql -I -s 4326 d:/downloads/land-polygons-split-4326/land_polygons.shp land_polygons_split > imp2.sql psql -h localhost -p 5432 -d osm -U postgres -f imp2.sql
COPY (select gid, ST_AsText(ST_Transform(geom,4326)) AS way from land_polygons_split) TO 'c:/map/land_polygons_split.tsv' WITH CSV DELIMITER E'\t';
2024.4.19に tsvファイルを再出力した。
GISにおけるMultipolygonは一般に複数の outer polygon があり、それぞれの outer polygon が複数の inner polygon を持つものを言う。上で得られた TSVファイルは Multipolygon 形式であるが、以前は、inner polygon を持たない outer polygon が一つ だけのシンプルな Polygon であった。
しかし、2024年2月1日にダウンロードしたデータには inner polygon が含まれているようである。
標準OSM地図のレンダリングは osm2pgsql で PostgreSQL/PostGISデータベースに OSMデータを取り込むが、この場合の マルチポリゴンは outer polygon は一つである。複数の outer polygon がある場合、複数のレコードとする。 Map4 もこれに従っている。multipolygon の場合、先頭が outer polygon で、その後ろに複数の inner polygon が続く。 それぞれのノード数は先頭にまとめて置かれる。
陸地ポリゴンは実態に合わせて polygon データとする。{key,val} は {'natural','land'} とする。 数年前に作ったプログラムを参考にして、変換プログラムを作る。
TSVファイルの各行は次のようなものである。座標値は経度、緯度の順である。
173 MULTIPOLYGON(((17.6338182 59.0056128,17.6332013 59.0057863,17.6326863 59.0059161,17.632712 59.0061304)))
先頭の ID は当面、無視する。必要に応じて、osm_id と同じ扱いとする。
head(2), [num_nds(4)], {lon,lat}*, tags_length(2), {key,val}* ... polygon head(2), {num_nds(4)}*, {lon,lat}*, tags_length(2), {key,val}* ... multipolygon head: 第0,1bit(0x03) 0: point、 1: line、 2: polygon、 3: multipolygon num_nodes: multipolygonの場合、最終要素(最終inner polygonノード数)の最上位ビットは 1 とする。
outer polygon は一つであるが、inner polygon は一つ以上である。
inner が二つの場合 MULTIPOLYGON(((outer),(inner 1),(inner 2))) となり、outer と inner、inner 同士は "),(" で区切られる。
今回のデータには低ズーム用で1つ(inner 1)、高ズーム用で3つのマルチポリゴン(inner 3, 1, 2)があることが分かった。
低ズームでのマルチポリゴンはカスピ海のようだ。高ズームではカスピ海は分割により、inner polygon ではなくなっていた。 しかし、別の地域にいくつかの multipolygon がある。
c:\map>java -Dfile.encoding=UTF-8 -Xmx5g -classpath ./class OSMUtil -land high 215342: 4 449441: 2 744401: 3 c:\map>java -Dfile.encoding=UTF-8 -Xmx5g -classpath ./class OSMUtil -land low 63912: 2LandPolygon.java
ポリゴンが大きいため、一般のOSMバイナリレコードよりも小さいzoom値で分割する。 取りあえず、低ズーム用は zoom 0(分割なし)、高ズーム用は zoom 6 で分割する。
プログラムは OSMバイナリレコードファイル用と共通である。
java -Dfile.encoding=UTF-8 -Xmx5g -classpath ./class OSMUtil -devide lands low 0 0 java -Dfile.encoding=UTF-8 -Xmx5g -classpath ./class OSMUtil -devide lands high 6 6
高ズームの極座標の精度は小数点以下7桁とした。中低ズームではそれだけの精度は不要なので、 中ズームは小数点以下6桁、中ズームは小数点以下5桁とした。
c:\map>java -Dfile.encoding=UTF-8 -Xmx5g -classpath ./class OSMUtil -devide lands low 0 0 レコード数=63930, 最大レコード長=878586, 平均レコード長=249.8, 平均タグ長=4.0B, 最大タグ長=4B 実行時間: 0.10分 c:\map>java -Dfile.encoding=UTF-8 -Xmx5g -classpath ./class OSMUtil -devide lands high 6 6 レコード数=750423, 最大レコード長=665086, 平均レコード長=1322.2, 平均タグ長=4.0B, 最大タグ長=4B 実行時間: 2.63分 c:\map>java -Dfile.encoding=UTF-8 -Xmx5g -classpath ./class OSMUtil -bbox lands low 0 BBox max 8921KB c:\map\data1\lands-low0\0\0.dat 実行時間: 0.01分 c:\map>java -Dfile.encoding=UTF-8 -Xmx5g -classpath ./class OSMUtil -bbox lands high 6 BBox max 11699KB c:\map\data1\lands-high6\35\18.dat 実行時間: 0.49分