GeoTools で地球地図起源の海岸線データを単純化する その3

hfu2007-12-13

d:id:hfu:20071211, d:id:hfu:20071212 の続きとして、ポリゴンの単純化を実際にやってみました。

geotools.rb の改変

geotools.rb を改変し、ポリゴンの単純化に必要なクラスを取り込むようにしました。このエントリのスクリプトを実行するには、http://svgmapdata.sakura.ne.jp/geotools/ にある geotools.rb (Time-stamp: <2007-12-13 05 : 47 : 35 hfu> 以降)を使ってください。

ポリゴンの単純化に必要なクラスとは

ポリゴンの単純化をしてくれるクラスには以下の2つがあります:

com.vividsolutions.jts.simplify.DouglasPeuckerSimplifier
地図学的なベクトルデータの単純化アルゴリズムとしては古典的であるらしい、Douglas-Peucker アルゴリズムを使って幾何を単純化するクラスです。ポリゴンを単純化する場合、単純化後のポリゴンも valid であることは保証されるそうです。ただし、単純化の結果、ポリゴンが分割されたり線分になったり、穴ができたり消えたりすることがあり、それがいやなら後者の TopologyPreservingSimplifier を使う必要があるとのことです。また、後者の TopologyPreservingSimplifier よりも処理が高速であるそうです。
com.vividsolutions.jts.simplify.TopologyPreservingSimplifier
入力幾何と同じ次元と、入力幾何と同じ構成要素数を確保しつつ単純化をしてくれるクラスです。

上記のクラスのいずれも、

static Geometry simplify(Geometry geom, double distanceTolerance)

なるメソッドを持っており*1、これを使うことができます。第二引数の distanceTolerance で、単純化の強さを指定することができます。

純化実験スクリプト

いくつかの distanceTolerance でこれらの Simplifier を試し、その結果を Shapefile に格納するプログラムは、以下のようになります。

require 'geotools'

simplifiers = %w{TopologyPreservingSimplifier DouglasPeuckerSimplifier}

5.times do |i|
  simplifiers.each do |simplifier|
    tolerance = 0.1 ** i
    fn = "#{simplifier}_#{sprintf('%.4f', tolerance)}"
    Geo::FeatureList.open("#{fn}.shp") do |w|
      Geo::FeatureList.foreach('odai.shp') do |f|
        g = f[:the_geom]
        eval "g = Geo::Tools::#{simplifier}.simplify(g, #{tolerance})"
        print "#{fn} has #{g.getNumPoints} points.\n"
        w.write({:the_geom => g})
      end
    end
  end
end

十進経緯度のまま単純化をしているので、地上の長さの尺度で考えると、単純化の強さが南北方向と東西方向で異なり、また南方地域と北方地域で異なることになります。より性質の良い単純化が必要な場合には、表示用の座標系に投影してから単純化する必要があるかもしれません。

純化実験の結果

上記のスクリプトで単純化したデータを以下に示します。

純化前のデータ


純化前のデータ、odai.shp です。構成点の数は全国分で 54504 点となっています。

Douglas-Peucker, toleranceDistance 0.0001 度


構成点の数は全国分で 51840 点となっています。オリジナルのデータからそれほど構成点数が変わっていませんので、この単純化設定には、それほど価値はないかもしれません。

Douglas-Peucker, toleranceDistance 0.001 度


構成点の数は全国分で 36309 点となっています。構成点数は半分程度で、見た目はあまり変わらないという点で、使える設定かもしれません。

Douglas-Peucker, toleranceDistance 0.01 度


構成点の数は全国分で 5166 点となっています。構成点の数が 1/10 程度で概略が分かるという点で、なかなか良い単純化になっています。

Douglas-Peucker, toleranceDistance 0.1 度


構成点の数は全国分で 336 点となっています。ずいぶん単純になってしまいました。

Douglas-Peucker, toleranceDistance 1 度


構成点の数は全国分で 19 点となっています。思い切った単純化になっています。

Topology preserving, toleranceDistance 0.0001 度


構成点の数は全国分で 51846 点となっています。オリジナルのデータからそれほど構成点数が変わっていませんので、この単純化設定には、それほど価値はないかもしれません。

Topology preserving, toleranceDistance 0.001 度


構成点の数は全国分で 36755 点となっています。見た目遜色なく、島の数え落としもなく、データ量が半分程度ということで、この単純化設定も使いでがあるでしょう。

Topology preserving, toleranceDistance 0.01 度


構成点の数は全国分で 9153 点となっています。島を数え落とさずにデータ量を 1/5 にして、このくらいの綺麗さなので、この単純化設定もなかなか良いかもしれません。

Topology preserving, toleranceDistance 0.1 度


構成点の数は全国分で 5513 点となっています。ちょっと気持ち悪い単純化になってしまいました。Topology preserving といっても、マルチポリゴンの構成ポリゴンの間での重なりを回避してくれるわけではないようです。

Topology preserving, toleranceDistance 1 度


構成点の数は全国分で 5206 点となっています。不思議な地図です。

まとめ

ベクトルデータの単純化を無償で行う方法として、JTS を使う方法があります。
JTSグッドラッパーを目指すラッパーでもある geotools.rb を使えば、気楽に単純化を行えます。

*1:ただし、Java にしては珍しく、何らかの共通インタフェースを実装しているわけではありません。