mkgmapで使用する海タイルのプリコンパイルデータ作成方法についてです。
mkgmapはosmの海岸線から海タイルを生成しますが、あらかじめ海タイルを別データとして用意しておけばそちらを参照して地図データを作成することが出来ます。この記事ではその海タイルのデータを作成する方法について防備録です。
環境
使用したPC環境です。メモリ搭載量の関係で古い1Uサーバを使用しました。
- PC:Fujitsu PRIMERGY RX200 S7
- CPU:Intel Xeon E5-2689
- MEM:256GByte
使用したツールやライブラリです。
- OpenJDK 21.0.8
- mkgmap-r4923
- splitter-r654
- geotools-19.4
はじめに
ことの発端は、当サイトで公開しているGarmin地図データの海タイルが上手く生成されなかったことです。
通常はツール(mkgmap)がosmデータから海を自動生成してくれるのですが、どうしてか八丈島付近が上手く生成されません。たまにある海岸線を突き破って陸地が海に沈むのと違い、海自体が無いのです。何にもないところに島がある状態です。
ツールのオプションを調整してみたものの改善しなかったので、プリコンパイルされた海タイルデータを使用することでようやく解決しました。ただ、プリコンパイルデータは以前はmkgmap本家サイトで提供されていたのですが、最近になって確認するとありません。
手元にある海タイルデータは以前に公式サイトからダウンロードしたもので何年も前のデータです。海岸線などそう頻繁に変化することはないとは思ったのですが、少し気になります。
そこで、地図データに使用するプリコンパイル海データも自分で作成することにしました。
プリコンパイルデータ作成機能付きmkgmapをビルドする
必要なもの
いつも使用しているmkgmapは公式サイトからダウンロードしたものですが、これにはプリコンパイルデータの生成機能はありません。その機能が欲しい場合はソースコードからmkgmapをビルドする必要があります。
ビルドするにあたって用意するものは以下のとおりです。それぞれのサイトからダウンロードしてください。
- mkgmapのソースコード
- splitter.jar
(https://www.mkgmap.org.uk/) - geotools-19.4
(https://geotools.org/)
また、ビルドにはantを使用するので無い場合はインストールしておきます。
$ sudo apt install ant
なお、上記箇条書きにあるgeotoolsは19.4と中途半端に古いバージョンを使用します。これはビルドエラーを回避するためです。
もともとmkgmapのドキュメントではgeotoolsのバージョン2.7.5を使用していますが、これだと古くてビルドエラーが発生します(当時とjavaと互換性が無い)。逆に最新のライブラリはAPI仕様が当時から変化しているようでやはりビルド出来ません。その辺りが丁度いい塩梅なのがgeotools-19.4でした。
ソースコード展開とライブラリ配置
まずダウンロードしたmkgmapのソースコードとgeotoolsを適当なディレクトリに展開します。
$ unzip mkgmap-r4923.zip
$ unzip geotools-19.4
次にビルドに必要なライブラリを以下のディレクトリに配置します(必要なのはgeotoolsに含まれる一部ライブラリとsplitter.jarですが、ここでは面倒なので全部放り込んでいます)。
- mkgmap-r4923/lib/optional
$ mv geotools-19.4/*.jar mkgmap-4923/lib/optional
$ mv splitter.jar mkgmap-4923/lib/optional
build.xmlの修正
海タイルのプリコンパイル機能は通常のmkgmap.jarに含まれません。必要なPrecompSeaGeneratorがcompile対象から除外されているからです。なので、この機能がビルド内容に含まれるようにbuild.xmlを修正する必要があります。
以下のようにbuild.xmlの”<exclud name=… />”とある行をコメントアウトしてください。
build.xml:
<?xml version="1.0"?>
<!--
File: build.xml
・・・
<!-- Compile the product itself (no tests). -->
<target name="compile" depends="prepare, resolve-compile"
description="main compilation">
<javac srcdir="${src}" destdir="${build.classes}" encoding="utf-8" debug="true" includeantruntime="false">
<include name="**/*.java" />
<classpath refid="main"/>
<compilerarg value="-Xlint:all"/>
<compilerarg value="-Xlint:-serial"/>
<compilerarg value="-Xlint:-path"/>
<!-- <exclude name="**/optional/*.java"/> –>
</javac>
</target>
・・・
ソースコード修正
この時点でmkgmapのroot(build.xmlがあるディレクトリ)で以下のようにコンパイルを試みると多数のエラーが発生すると思います。
$ ant compile
プリコンパイルデータ作成関連の機能は普段のビルドに含まれないためか、一部コードが古くなってしまっているようです(BinaryMapWriter、OSMWriter、OSMXMLWriterのパスが変わっている)。
そこで問題箇所を修正します。以下の2ファイルがそれです。
- src/uk/me/parabola/mkgmap/sea/optional/PrecompSeaSaver.java
package uk.me.parabola.mkgmap.sea.optional;
import java.io.File;
import java.io.FileOutputStream;
・・・
//import uk.me.parabola.splitter.BinaryMapWriter;
import uk.me.parabola.splitter.writer.BinaryMapWriter;
import uk.me.parabola.splitter.Node;
//import uk.me.parabola.splitter.OSMWriter;
import uk.me.parabola.splitter.writer.OSMWriter;
//import uk.me.parabola.splitter.OSMXMLWriter;
import uk.me.parabola.splitter.writer.OSMXMLWriter;
・・・
- src/uk/me/parabola/mkgmap/osmstyle/optional/DebugWriter.java
・・・
//import uk.me.parabola.splitter.O5mMapWriter;
import uk.me.parabola.splitter.writer.O5mMapWriter;
・・・
//O5mMapWriter writer = new O5mMapWriter(bounds, outDir, 0, 0, dummyMap, dummyMap);
O5mMapWriter writer = new O5mMapWriter(bounds, outDir, 0, 0);
・・・
ビルドする
あとはビルドすればツールの準備は完了です。
$ ant compile
$ ant dist
$ java -jar ./dist/mkgmap.jar --version
Mkgmap version 4923
4923
海タイルのプリコンパイルデータを作成する
まず以下のサイトから陸地のポリゴンデータ(shapefile形式)をダウンロードします。このデータを元に海タイルが作成されます。
- Land polygons – Data Derived from OpenStreetMap for Download
(https://osmdata.openstreetmap.de/data/land-polygons.html)
ダウンロードしたデータは適当なディレクトリに展開します。
$ unzip land-polygons-complete-4326.zip
次に以下のようにして海タイルのプリコンパイルデータ作成を開始します。実行に必要なライブラリを指定しているのでかなり長いです。
引数でしている”land_polygons.shp”が上記でダウンロードしたデータで、プリコンパイルデータは”../precomp_sea”ディレクトリに出力されます。
$ java -Xmx64g -XX:+UseCompressedOops -XX:ObjectAlignmentInBytes=16 -cp ./build/classes/:./lib/optional/commons-pool-1.5.4.jar:./lib/optional/gt-api-19.4.jar:./lib/optional/gt-cql-19.4.jar:./lib/optional/gt-data-19.4.jar:./lib/optional/gt-main-19.4.jar:./lib/optional/gt-metadata-19.4.jar:./lib/optional/gt-opengis-19.4.jar:./lib/optional/gt-referencing-19.4.jar:./lib/optional/gt-shapefile-19.4.jar:./lib/optional/jsr-275-1.0-beta-2.jar:./lib/optional/jts-core-1.14.0.jar:./lib/optional/vecmath-1.3.2.jar:./lib/compile/fastutil-6.5.15-mkg.1b.jar:./lib/compile/protobuf-java-2.5.0.jar:./lib/compile/osmpbf-1.3.3.jar:./lib/compile/xpp3-1.1.4c.jar:./lib/optional/splitter.jar uk.me.parabola.mkgmap.sea.optional.PrecompSeaGenerator ../land-polygons-complete-4326/land_polygons.shp WGS84 ../precomp_sea
対象が世界中の海なので完了までかなり時間を要します。
また、かなりメモリを必要としているようで、最初に32GByteを割り当てて実行したところメモリ不足で落ちてしまいました。なので64GByteを奢っています(必要量が分からないので適当に設定)。メモリ消費量から思うに32GByte+αくらいだと思うのですが。
・・・
Exception in thread "pool-1-thread-29" java.lang.OutOfMemoryError: Java heap space
1 tiles remaining
1 tiles remaining
Writing index file
Generation took 97096873 ms
Preforming quick check against reference for index file.
Quick check against reference found no problems.
結局、常用しているPCではなく古い1Uサーバ(メモリだけは256GByte)で作業をやり直しました。結果、無事に完了したもののほぼ27時間かかりました。全世界の海データを作ったと思えばこんなものなのかな(古いサーバで遅いのも原因だとは思います)。
完了後、出力先ディレクトリを確認するとOSMファイルが大量に生成されています。これをzipでひと纏めにすれば作業完了です。あとは作成したzipファイルをGarmin地図データを作成するときにオプションで指定してやれば読み込まれます。
$ ll -h sea-202510.zip
-rw-rw-r-- 1 kiri kiri 322M 10月 15 14:57 sea-202510.zip
参考
この記事は以下の内容を参考に記載しました。
- SHP opening : datastore DataStoreFactorySpi is not an ImageIO SPI class
https://stackoverflow.com/questions/47888812/shp-opening-datastore-datastorefactoryspi-is-not-an-imageio-spi-class - GeoTools, the Java GIS toolkit
https://sourceforge.net/projects/geotools/ - Mkgmap/dev – OpenStreetMap Wiki
https://wiki.openstreetmap.org/wiki/Mkgmap/dev - Mkgmap/dev/Building – OpenStreetMap WIki
https://wiki.openstreetmap.org/wiki/Mkgmap/dev/Building - Java の -Xmx を減らしたら OutOfMemoryError が解消した話@hanohrs
https://qiita.com/hanohrs/items/abfc0ccd0effa26f2f5b

コメント