geohex-gem 2.0.1 の GeoHex::Zone.hexCoords を今すぐ使いたいための黒魔術

geohex-gem 2.0.1 の GeoHex::Zone.hexCoords を今すぐ使いたいために、後から手を入れてみました。本来は github できちんと貢献すべきですが、とりいそぎ。

the code

https://github.com/geohex/geohex-gem/blob/master/lib/geohex.rb を参照しながら、ちょっといじってみました。

#gh.rb
require 'rubygems'
require 'geohex'

# quick hacks
module GeoHex
  class Zone
    # copied from GeoHex::Zone#hexCoords, modified.
    def hexCoords
      h_lat = self.lat;
      h_lon = self.lon;
      h_xy = GeoHex::Zone.loc2xy(h_lon, h_lat);
      h_x = h_xy.x
      h_y = h_xy.y
      h_deg = Math.tan(Math::PI * (60.0 / 180)); # 60.0 was 60
      h_size = self.hexSize
      h_top = xy2loc(h_x, h_y + h_deg *  h_size).lat;
      h_btm = xy2loc(h_x, h_y - h_deg *  h_size).lat;
      
      h_l = xy2loc(h_x - 2 * h_size, h_y).lon;
      h_r = xy2loc(h_x + 2 * h_size, h_y).lon;
      h_cl = xy2loc(h_x - 1 * h_size, h_y).lon;
      h_cr = xy2loc(h_x + 1 * h_size, h_y).lon;
      
      [
       {:lat => h_lat, :lon => h_l},
       {:lat => h_top, :lon => h_cl},
       {:lat => h_top, :lon => h_cr},
       {:lat => h_lat, :lon => h_r},
       {:lat => h_btm, :lon => h_cr},
       {:lat => h_btm, :lon => h_cl}
      ]
    end

    # copied from GeoHex::Zone::calcHexSize
    def calcHexSize(level)
      H_BASE / (2 ** level) / 3
    end

    # copied from (class << GeoHex::Zone)
    def loc2xy(_lon,_lat) 
      x=_lon*H_BASE/180;
      y= Math.log(Math.tan((90+_lat)*Math::PI/360)) / (Math::PI / 180 );
      y= y * H_BASE / 180;
      return OpenStruct.new("x"=>x, "y"=>y);
    end
    
    # copied from (class << GeoHex::Zone)
    def xy2loc(_x,_y) 
      lon=(_x/H_BASE)*180;
      lat=(_y/H_BASE)*180;
    lat=180.0/Math::PI*(2.0*Math.atan(Math.exp(lat*Math::PI/180))-Math::PI/2);
      return OpenStruct.new("lon" => lon,"lat" => lat);
    end
  end
end

# quick tests
if __FILE__ == $0
  p GeoHex::Zone.new(35.0, 135.0).hexCoords
end
$ ruby gh.rb
[{:lon=>134.0625, :lat=>35.0}, {:lon=>134.53125, :lat=>35.6623583418946}, {:lon=>135.46875, :lat=>35.6623583418946}, {:lon=>135.9375, :lat=>35.0}, {:lon=>135.46875, :lat=>34.3322364177067}, {:lon=>134.53125, :lat=>34.3322364177067}]

とりあえず何かの座標が出るようになりました。この方法で正しい GeoHex が出ていないとすれば、妙ないじり方をした私の責任だと思っています。

とりあえず、これで作業を進めます。

Ruby の黒魔術

Ruby においては自分の足を撃つことは認められていて、活きているクラスに勝手にメソッドを定義できたりします。こういうことについて「Rubyの黒魔術」 http://www.slideshare.net/tmtm/ruby-3424591 というプレゼンテーションがまとめられたりしているようです。Ruby といえば赤なので、黒魔術をうまく使った Ruby プログラムを、むしろ赤マジック/赤魔術と呼びたい、などと思いました。例えば、rails では標準クラスを拡張します*1 が、こういうのは Ruby らしい赤マジックだなと思います。

*1:http://doruby.kbmj.com/yoppi_on_rails/20080226/Rails_Ruby_String_1 ... ひょっとすると、古いかもしれません。rails を使っていないので、分かりません。