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

hfu2007-12-12

d:id:hfu:20071211 の続きです。地球地図日本バージョン 1.1 行政区画の Shapefile 版データ bnda.shp はなぜか 3D ポリゴン形式でしたので、これを 2D ポリゴンに直す処理をしています。(本題については、その3をご覧ください。)

Geo::FeatureList#size が地物読み込み前でも良い値を返すよう、geotools.rb を更新

d:id:hfu:20071211 のコードで、Ruby 配列を Java 配列に直す部分が気に入らなかったので、最初から Java 配列で作業できるようにしようと思いました。
Java 配列は、生成時点でその大きさを明示しなければならないので、geotools.rb の Geo::FeatureList#size で Shapefile のレコード数を得ることにしました。しかし、これまでの geotools.rb では、地物を読み始めるまで Geo::FeatureList#size は正しい値を返しませんでした。
そこで、Geo::FeatureList#each からデータ読み込みを準備する部分を独立させたプライベートメソッド Geo::FeatureList#setup_store_for_reading を新設しました。Geo::FeatureList#size からは必要に応じて setup_store_for_reading を呼び出すようにし、地物読み込み前でも Shapefile のレコード数が得られるようにしました。これによって、

geoms = com.vividsolutions.jts.geom.Geometry[fl.size].new

とすることができるようになりました。
新しい geotools.rb を、http://svgmapdata.sakura.ne.jp/geotools/ にアップロードしました。このエントリで公開するスクリプトを実行されるようなことがある場合には、お手持ちの geotools.rb を新しいもの(Time-stamp: <2007-12-12 04:55:31 hfu>)で書き換えてください。

3D Polygon を 2D Polygon に変換

地球地図日本バージョン 1.1 行政区画の Shapefile 版データ bnda.shp はなぜか 3D ポリゴン形式でした。z 値はすべて 0 です。これが気持ち悪いので、2D ポリゴンに変換することにしました。
これは、ポリゴンを構成するすべての座標 (クラス Coordinate のインスタンス) のフィールド z を NaN で書き換え、最後にもとの幾何のメソッド geometryChanged を呼び出すことで実現できます:

coords = multi_polygon.getCoordinates
coords.length.times {|i| coords[i].z = nan}
multi_polygon.geometryChanged

更新された odai.rb

「お題の海岸線ポリゴンデータを模擬するデータを作成するスクリプト」odai.rb は、以下のように書き換えられました。

# this code works only with JRuby, not CRuby + Rjb. 
require 'geotools'

gf = Geo::Tools::GeometryFactory.new
nan = Geo::Tools::Coordinate.new.z

Geo::FeatureList.open('odai.shp') do |w|
  Geo::FeatureList.open('/Users/hfu/src/bnda_1_1/bnda_1_1.shp',
                           {:whitelist => []}) do |fl|
    geoms = com.vividsolutions.jts.geom.Geometry[fl.size].new
    c = 0
    fl.each do |f|
      multi_polygon = f[:the_geom]
      coords = multi_polygon.getCoordinates
      coords.length.times {|i| coords[i].z = nan}
      multi_polygon.geometryChanged
      geoms[c] = multi_polygon
      c += 1
    end
    geom = gf.createGeometryCollection(geoms).buffer(0)
    w.write({:the_geom => geom})
  end
end

d:id:hfu:20071211 にある旧版と比べると、コードが少しだけすっきりした気がします。
できあがった Shapefile は、以下のようなものになっています:

このエントリは、その3に続きます。