Geo::Reader の Deegree 版と JUMP 版を雑に作ってみました

Geo::Reader を、GeoTools と同じく Java の地理情報処理ライブラリである Deegree と JUMP でも作ってみました。今回の作業の趣旨は、

もし Deegree や JUMP で実装すると 10 倍速いというようなことがあったら悔しいから、一応試しておこう

という程度のもので、今まで以上に雑なテストですのでご了承ください。実は、型変換もきちんとはそろえていません。
テストの結果、Shapefile 形式の同一ファイルを読むのに要する時間は、以下のようになりました:

geotools.rb on GeoTools 41秒
degree.rb on Deegree 46秒
jump.rb on JUMP 39秒、但し -Xmx1024m とする必要あり

この結果、Deegree や JUMP が GeoTools と比べて劇的に速いということはないことが分かりましたので、当面は GeoTools に対して geotools.rb を作っていきたいと思います。
JUMP の、「Shapefile の内容をいったん全部メモリにロードして FeatureCollection として返す」という実装は「すごい」なあと思いました。標準化によるミスリードの典型例だと思います。この話題については、あとで書くかもしれません。

現時点の deegree.rb & jump.rb

雑で恐縮ですが、ご参考のため。deegree.rb:

# this code is under development and subject to major change.

module Geo
  module Deegree
    QUALIFIED_NAMES = %w{org.deegree.io.shpapi.ShapeFile}
    begin
      require 'rjb'
      QUALIFIED_NAMES.each do |qn|
        sn = qn.split('.').last
        module_eval "#{sn} = Rjb::import('#{qn}')"
      end
      IMPLEMENTATION = 'rjb'
    rescue LoadError
      require 'java'
      QUALIFIED_NAMES.each do |qn|
        include_class qn
      end
      IMPLEMENTATION = 'java'
    end
  end

  class Reader
    def Reader::foreach(file_name, sjis_workaround = false)
      sf = Geo::Deegree::ShapeFile.new(file_name.sub(/.shp$/, ''))
      keys = sf.getProperties
      sf.getRecordNum.times do |i|
        feat = sf.getFeatureByRecNo(i + 1)
        attrs = {}
        keys.each do |key|
          attrs[key] = feat.getAttribute(key)
        end
        yield feat.getDefaultGeometryPropertyValue, attrs
      end
    end
  end
end

# ad hoc tests
if __FILE__ == $0
  ## TODO: better separate tests as unit tests.
  start_time = Time.now
  Geo::Reader.foreach('transl_1_1.shp', false) do |geom, attrs|
    #print "#{geom} #{attrs.inspect}\n"
  end
  print "#{Time.now - start_time} sec.\n"
end

それから jump.rb

# this code is under development and subject to major change.

module Geo
  module Jump
    QUALIFIED_NAMES = %w{com.vividsolutions.jump.io.ShapefileReader com.vividsolutions.jump.io.DriverProperties}
    begin
      require 'rjb'
      Rjb::primitive_conversion = true
      Rjb::load(nil, ['-Xmx1024m'])
      QUALIFIED_NAMES.each do |qn|
        sn = qn.split('.').last
        module_eval "#{sn} = Rjb::import('#{qn}')"
      end
      IMPLEMENTATION = 'rjb'
    rescue LoadError
      require 'java'
      QUALIFIED_NAMES.each do |qn|
        include_class qn
      end
      IMPLEMENTATION = 'java'
    end
  end

  class Reader
    def Reader::foreach(file_name, sjis_workaround = false)
      dp = Geo::Jump::DriverProperties.new(file_name)
      r = Geo::Jump::ShapefileReader.new()
      fc = r.read(dp)
      fs = fc.getFeatureSchema
      keys = []
      fs.getAttributeCount.times do |i|
        key = fs.getAttributeName(i)
        keys << key unless key == 'GEOMETRY'
      end
      iter = fc.iterator
      while(iter.hasNext)
        feat = iter.next
        attrs = {}
        keys.each do |key|
          attrs[key] = feat.getAttribute(key)
        end
        yield feat.getGeometry, attrs
      end
    end
  end
end

# ad hoc tests
if __FILE__ == $0
  ## TODO: better separate tests as unit tests.
  start_time = Time.now
  Geo::Reader.foreach('transl_1_1.shp', false) do |geom, attrs|
    #print "#{geom} #{attrs.inspect}\n"
  end
  print "#{Time.now - start_time} sec.\n"
end

余談ですが

Deegree, JUMP, GeoTools を PC UNIX のそれぞれと対比してみるとおもしろいかもしれないと思いました。JUMP が分派してきているのを今日知りました。