GeoHexV2SuperOverlay
GeoHexV2 で KML SuperOverlay を実現してみました。
the code
# -*- coding: utf-8 -*- #server.rb require 'rubygems' require 'sinatra/base' require 'haml' require 'gh.rb' # @see http://d.hatena.ne.jp/hfu/20110224 require 'ostruct' HOST = 'localhost' PORT = 8092 module GeoHex # ヘックスの包含矩形が得られるように拡張 class Zone def bbox coords = self.hexCoords @bbox = OpenStruct.new(:north => coords[1][:lat], :south => coords[4][:lat], :east => coords[3][:lon], :west => coords[0][:lon]) end def north bbox unless @bbox @bbox.north end def south bbox unless @bbox @bbox.south end def east bbox unless @bbox @bbox.east end def west bbox unless @bbox @bbox.west end end end class App < Sinatra::Base get '/' do # 日本を包含できるヘックスを返す redirect "/geohex/#{GeoHex::Zone.new(20.0, 140.0, 2).code}" end get '/geohex/:geohex' do |geohex| content_type 'application/vnd.google-earth.kml+xml' # easier than apache! #content_type 'text/plain' # good for testing purpose current_geohex = GeoHex::Zone.new(geohex) coords = current_geohex.hexCoords coords << coords[0] # cause a polygon has to go around hexcenter_lat = GeoHex::Zone.decode(geohex)[0] hexcenter_lng = GeoHex::Zone.decode(geohex)[1] children = [GeoHex::Zone.new(hexcenter_lat, hexcenter_lng, current_geohex.level + 1)] 3.times {|i| children << GeoHex::Zone.new((coords[i][:lat] + coords[i + 1][:lat]) / 2, (coords[i][:lon] + coords[i + 1][:lon]) / 2, current_geohex.level + 1) } children.map! {|child| <<-EOS %NetworkLink %name #{child.code} %Region %Lod %minLodPixels 128 %maxLodPixels -1 %LatLonAltBox %north #{child.north} %south #{child.south} %east #{child.east} %west #{child.west} %Link %href http://#{HOST}:#{PORT}/geohex/#{child.code} %viewRefreshMode onRegion EOS } haml <<-EOS %kml(xmlns='http://earth.google.com/kml/2.0') %Document %Region %LatLonAltBox %north #{current_geohex.north} %south #{current_geohex.south} %east #{current_geohex.east} %west #{current_geohex.west} %Style(id='geohexpolygon') %LineStyle %color ff0000ff %width 2 %PolyStyle %fill 0 %Placemark %name #{geohex} %styleUrl #geohexpolygon %Polygon %extrude 1 %outerBoundaryIs %LinearRing %coordinates #{coords.map{|h| "#{h[:lon]},#{h[:lat]}"}.join(" ")} #{children} EOS end end App.run! :port => PORT
the usage
$ ruby server.rb == Sinatra/0.9.4 has taken the stage on 8092 for development with backup from Thin >> Thin web server (v1.2.5 codename This Is Not A Web Server) >> Maximum connections set to 1024 >> Listening on 0.0.0.0:8092, CTRL+C to stop
↑このようにしてサーバを立ち上げておいて、http://localhost:8092 にアクセスすると、日本を包含するヘックスについて、SuperOverlay が開始されます。
なぜ上側4ヘックスしか呼ばないのか。
コードに「3.times {|i|」(60行目付近)とあるように、レベルを上げるにつれて、上側4ヘックス(自分の直下1ヘックスプラスその上側3ヘックス)しか呼んでいません。この理由を説明します。
これは、下側の3ヘックスも合わせて合計7ヘックス呼んでしまうと、呼び出しの重複が発生してしまうからです。呼び出しの重複が呼び出しの重複を呼んで、ねずみ算的に呼び出しが増えてしまいます。自分の直下及び上側4ヘックスの合計4ヘックスのみを呼ぶことによって、重複なく呼び出すことができます。
4ヘックスを呼べば重複も不足もないことは、面積を考えれば説明できます。GeoHex V2 では、レベルを上げるにつれてサイズが 1/2 になると言います。面積としては 1/2 の二乗の 1/4 です。そのため、レベルが下のタイルを 4 つ呼ぶことで、 1/4 * 4 = 1 = 100% の面積のレベル下タイルを呼び出すことになります。そのため、レベル変更をしても面積カバー率が変化せず、継続的に SuperOverlay できることになります。