class GeoHex::Zone

Attributes

code[RW]
lat[RW]
lon[RW]
x[RW]
y[RW]

Public Class Methods

adjustXY(_x, _y, _level) click to toggle source
# File lib/geohex.rb, line 448
def adjustXY(_x, _y, _level)
    x = _x
    y = _y
    rev = 0
    max_hsteps = 3**(_level+2)
    hsteps = (x - y).abs
    if hsteps == max_hsteps && x>y
            tmp = x
            x = y
            y = tmp
            rev = 1
  elsif hsteps > max_hsteps
            dif = hsteps - max_hsteps
            dif_x = (dif/2).floor
            dif_y = dif - dif_x
            if x > y 
                    edge_x = x - dif_x
                    edge_y = y + dif_y
                    h_xy = edge_x
                    edge_x = edge_y
                    edge_y = h_xy
                    x = edge_x + dif_x
                    y = edge_y - dif_y
    elsif y > x
                    edge_x = x + dif_x
                    edge_y = y - dif_y
                    h_xy = edge_x
                    edge_x = edge_y
                    edge_y = h_xy
                    x = edge_x - dif_x
                    y = edge_y + dif_y
    end
  end
    
  { x: x, y: y, rev: rev }
end
calcHexSize(level) click to toggle source
# File lib/geohex.rb, line 30
def self.calcHexSize(level)
  H_BASE/(3**(level+3))
end
decode(code) click to toggle source

geohex to latlon

# File lib/geohex.rb, line 144
def self.decode(code)
  c_length = code.length 
  level = H_KEY.index(code[0,1]) 
  scl = level 
  h_size =  self.calcHexSize(level) 
  unit_x = 6.0 * h_size 
  unit_y = 6.0 * h_size * H_K 
  h_max = (H_BASE / unit_x + H_BASE / unit_y).round 
  h_x = 0 
  h_y = 0 

  if (h_max >= 12960000 / 2) 
    h_x = H_KEY.index(code[1,1]) * 12960000 + 
      H_KEY.index(code[3,1]) * 216000 + 
      H_KEY.index(code[5,1]) * 3600 + 
      H_KEY.index(code[7,1]) * 60 + 
      H_KEY.index(code[9,1]) 
    h_y = H_KEY.index(code[2,1]) * 12960000 + 
      H_KEY.index(code[4,1]) * 216000 + 
      H_KEY.index(code[6,1]) * 3600 + 
      H_KEY.index(code[8,1]) * 60 + 
      H_KEY.index(code[10,1]) 
  elsif (h_max >= 216000 / 2) 
    h_x = H_KEY.index(code[1,1]) * 216000 + 
      H_KEY.index(code[3,1]) * 3600 + 
      H_KEY.index(code[5,1]) * 60 + 
      H_KEY.index(code[7,1]) 
    h_y = H_KEY.index(code[2,1]) * 216000 + 
      H_KEY.index(code[4,1]) * 3600 + 
      H_KEY.index(code[6,1]) * 60 + 
      H_KEY.index(code[8,1]) 
  elsif (h_max >= 3600 / 2) 
    h_x = H_KEY.index(code[1,1]) * 3600 + 
      H_KEY.index(code[3,1]) * 60 + 
      H_KEY.index(code[5,1]) 
            h_y = H_KEY.index(code[2,1]) * 3600 + 
      H_KEY.index(code[4,1]) * 60 + 
      H_KEY.index(code[6,1]) 
  elsif (h_max >= 60 / 2) 
    h_x = H_KEY.index(code[1,1]) * 60 + 
      H_KEY.index(code[3,1]) 
    h_y = H_KEY.index(code[2,1]) * 60 + 
      H_KEY.index(code[4,1]) 
  else
    h_x = H_KEY.index(code[1,1]) 
    h_y = H_KEY.index(code[2,1]) 
  end
  h_x = (h_x % 2 == 1) ? -(h_x - 1) / 2 : h_x / 2 
  h_y = (h_y % 2 == 1) ? -(h_y - 1) / 2 : h_y / 2 

  h_lat_y = (H_K * h_x * unit_x + h_y * unit_y) / 2 
  h_lon_x = (h_lat_y - h_y * unit_y) / H_K 

  h_loc = xy2loc(h_lon_x, h_lat_y) 
  return [h_loc.lat, h_loc.lon, level]
end
encode(lat,lon,level=7) click to toggle source

latlon to geohex

# File lib/geohex.rb, line 68
def self.encode(lat,lon,level=7)
  raise ArgumentError, "latitude must be double" unless (lat.is_a?(Numeric))
  raise ArgumentError, "latitude must be between -85 and 85" if (lat < -85.1 || lat > 85.1)
  raise ArgumentError, "latitude must be between -85 and 85" if (lat < -85.1 || lat > 85.1)
  raise ArgumentError, "longitude must be between -180 and 180" if (lon < -180 || lon > 180)
  raise ArgumentError, "level must be between 0 and 24" if (level < 0 || level > 24)
  
  h_size = self.calcHexSize(level)
  z_xy = loc2xy(lon,lat)
  lon_grid = z_xy.x
  lat_grid = z_xy.y
  unit_x = 6.0* h_size 
  unit_y = 6.0* h_size*H_K 
  h_pos_x = (lon_grid + lat_grid / H_K) / unit_x 
  h_pos_y = (lat_grid - H_K*lon_grid) / unit_y 

  h_x_0 = h_pos_x.floor 
  h_y_0 = h_pos_y.floor 
  h_x_q = h_pos_x - h_x_0
  h_y_q = h_pos_y - h_y_0
  h_x = h_pos_x.round 
  h_y = h_pos_y.round 
  
  h_max=(H_BASE/unit_x + H_BASE/unit_y).round 
  
  if ( h_y_q > -h_x_q + 1 ) 
    if ( h_y_q < (2 * h_x_q ) and  h_y_q > (0.5 * h_x_q ) )
      h_x = h_x_0 + 1
      h_y = h_y_0 + 1
    end
  elsif ( h_y_q < -h_x_q + 1 ) 
    if ( (h_y_q > (2 * h_x_q ) - 1 ) && ( h_y_q < ( 0.5 * h_x_q ) + 0.5 ) ) 
      h_x = h_x_0
      h_y = h_y_0
    end
  end

  h_lat = (H_K * h_x * unit_x + h_y * unit_y) / 2 
  h_lon = (h_lat - h_y * unit_y)/H_K 
  
  z_loc = xy2loc(h_lon,h_lat)
  z_loc_x = z_loc.lon
  z_loc_y = z_loc.lat
  
  if (H_BASE - h_lon <h_size)
    z_loc_x = 180.0 
    h_xy = h_x 
    h_x = h_y 
    h_y = h_xy 
  end
  
  h_x_p = (h_x<0) ? 1 : 0 
  h_y_p = (h_y<0) ? 1 : 0 
  h_x_abs = ((h_x).abs * 2 + h_x_p).to_f 
  h_y_abs = ((h_y).abs * 2 + h_y_p).to_f 
  h_x_10000 = ((h_x_abs%777600000)/12960000).floor 
  h_x_1000 = ((h_x_abs%12960000)/216000).floor 
  h_x_100 = ((h_x_abs%216000)/3600).floor 
  h_x_10 = ((h_x_abs%3600)/60).floor 
  h_x_1 = ((h_x_abs%3600)%60).floor 
  h_y_10000 = ((h_y_abs%77600000)/12960000).floor 
  h_y_1000 = ((h_y_abs%12960000)/216000).floor 
  h_y_100 = ((h_y_abs%216000)/3600).floor 
  h_y_10 = ((h_y_abs%3600)/60).floor 
  h_y_1 = ((h_y_abs%3600)%60).floor 
  h_code = H_KEY[level % 60, 1] 
  h_code += H_KEY[h_x_10000, 1]+H_KEY[h_y_10000, 1] if(h_max >=12960000/2)  
  h_code += H_KEY[h_x_1000, 1]+H_KEY[h_y_1000, 1] if(h_max >=216000/2)  
  h_code += H_KEY[h_x_100, 1]+H_KEY[h_y_100, 1] if(h_max >=3600/2)  
  h_code += H_KEY[h_x_10, 1]+H_KEY[h_y_10, 1] if(h_max >=60/2)  
  h_code += H_KEY[h_x_1, 1]+H_KEY[h_y_1, 1] 
  
  return h_code 
end
getXYByCode(code) click to toggle source
# File lib/geohex.rb, line 343
def self.getXYByCode(code)
    level = code.length - 2
    h_size =  calcHexSize(level)
    unit_x = 6 * h_size
    unit_y = 6 * h_size * H_K
    h_x = 0
    h_y = 0

    h_dec9 = (( H_KEY.index(code[0]) * 30 + H_KEY.index(code[1])).to_s + code[2..-1].to_s)
  
    if h_dec9[0].match(/[15]/) && h_dec9[1].match(/[^125]/) && h_dec9[2].match(/[^125]/)
      if h_dec9[0] == 5
              h_dec9 = "7" + h_dec9[1..(h_dec9.length-1)]
    elsif h_dec9[0] == 1
              h_dec9 = "3" + h_dec9[1..h_dec9.length-1]
    end
  end

  d9xlen = h_dec9.length
  state = (level + 3 - d9xlen)
  if state != 0 
    (0..state-1).each do |i|
      h_dec9 = "0" + h_dec9
      d9xlen += 1
    end
  end
  
    h_dec3 = String.new()
          
  (0..(d9xlen-1)).each do |i|
      h_dec0 = h_dec9[i].to_i.to_s(3)

      if !h_dec0 
        h_dec3 += "00"
    elsif h_dec0.length == 1
        h_dec3 += "0"
    end
      h_dec3 += h_dec0;
  end

    h_decx =[]
    h_decy =[]
    
  (0..((h_dec3.length/2)-1)).each do |i|
      x = i*2
    y = i*2+1
    h_decx[i] = h_dec3[x]
      h_decy[i] = h_dec3[y]
  end

    (0..level+2).each do |i|
        h_pow = 3**(level+2-i)

        if h_decx[i].to_i == 0
            h_x -= h_pow;
        elsif h_decx[i].to_i == 2
            h_x += h_pow;
    end
    
    if h_decy[i].to_i == 0
            h_y -= h_pow
        elsif h_decy[i].to_i == 2
            h_y += h_pow
    end
  
  end


  
    inner_xy = adjustXY(h_x,h_y,level)
    h_x = inner_xy[:x]
    h_y = inner_xy[:y]
    
    {
    x: h_x, 
    y: h_y
  }
end
getXYByLocation(lat, lon, _level) click to toggle source
# File lib/geohex.rb, line 298
def self.getXYByLocation(lat, lon, _level)
    h_size = calcHexSize(_level)
    z_xy = loc2xy(lon, lat)
    lon_grid = z_xy.x
    lat_grid = z_xy.y
    unit_x = 6 * h_size
    unit_y = 6 * h_size * H_K
    h_pos_x = (lon_grid + lat_grid / H_K) / unit_x
    h_pos_y = (lat_grid - H_K * lon_grid) / unit_y
    h_x_0 = (h_pos_x).floor
    h_y_0 = (h_pos_y).floor
    h_x_q = h_pos_x - h_x_0;
    h_y_q = h_pos_y - h_y_0
    h_x = (h_pos_x).round
    h_y = (h_pos_y).round
    
    if h_y_q > -h_x_q + 1
            if h_y_q < 2 * h_x_q && h_y_q > 0.5 * h_x_q
                    h_x = h_x_0 + 1
                    h_y = h_y_0 + 1
    end
  elsif h_y_q < -h_x_q + 1
            if h_y_q > (2 * h_x_q) - 1 && h_y_q < 0.5 * h_x_q + 0.5
                    h_x = h_x_0
                    h_y = h_y_0
    end
  end
    
    inner_xy = adjustXY(h_x, h_y, _level)
    h_x = inner_xy[:x]
    h_y = inner_xy[:y]
    
  {
    x: h_x, 
    y: h_y 
  };
end
getZoneByCode(code) click to toggle source
# File lib/geohex.rb, line 422
def self.getZoneByCode(code)
    xy = getXYByCode(code)
    level = code.length - 2
  zone = getZoneByXy(xy[:x], xy[:y], level)
  
  zone
end
getZoneByLocation(_lat, _lon, _level) click to toggle source
# File lib/geohex.rb, line 336
def self.getZoneByLocation(_lat, _lon, _level) 
    xy = self.getXYByLocation(_lat, _lon, _level)
    zone = self.getZoneByXy(xy[:x], xy[:y], _level)
    
  zone
end
getZoneByXy(_x,_y, _level) click to toggle source
# File lib/geohex.rb, line 201
def self.getZoneByXy(_x,_y, _level)

    h_size = self.calcHexSize(_level) 
    
    h_x = _x
    h_y = _y
  
    unit_x = 6 * h_size
    unit_y = 6 * h_size * H_K

    h_lat = (H_K * h_x * unit_x + h_y * unit_y) / 2
    h_lon = (h_lat - h_y * unit_y) / H_K

    z_loc = self.xy2loc(h_lon, h_lat)
    z_loc_x = z_loc.lon
    z_loc_y = z_loc.lat
  
    max_hsteps = 3**(_level + 2)
    hsteps = (h_x - h_y).abs

    if hsteps == max_hsteps
            if h_x > h_y
            tmp = h_x
            h_x = h_y
            h_y = tmp
    end
            z_loc_x = -180
  end
  
    h_code = ""
   
    code3_x = Array.new
    code3_y = Array.new
    code3 = ""
    code9 = ""
    mod_x = h_x
    mod_y = h_y

    (0..(_level + 2)).each do |i| 
      h_pow = 3**(_level + 2 - i)
    
      if mod_x >= ((h_pow.to_f)/2).ceil 
        code3_x[i] =2 
        mod_x -= h_pow 
    elsif mod_x <= -((h_pow.to_f)/2).ceil 
        code3_x[i] =0 
        mod_x += h_pow 
    else
        code3_x[i] =1 
    end
    

    
      if mod_y >= ((h_pow.to_f)/2).ceil
        code3_y[i] = 2 
        mod_y -= h_pow 
    elsif mod_y <= -((h_pow.to_f)/2).ceil
        code3_y[i] = 0 
        mod_y += h_pow 
      else
        code3_y[i] = 1 
    end
  

    
      if i==2 && (z_loc_x==-180 || z_loc_x>=0) 
              if code3_x[0] == 2 && code3_y[0] == 1 && code3_x[1] == code3_y[1] && code3_x[2] == code3_y[2] 
                    code3_x[0] = 1
                    code3_y[0] = 2
      elsif code3_x[0] == 1 && code3_y[0] == 0 && code3_x[1] == code3_y[1] && code3_x[2] == code3_y[2] 
                    code3_x[0] = 0
                    code3_y[0] = 1
      end
    end
  end
     
    code3_x.each_with_index do |x,i|
      code3  += "#{code3_x[i]}#{code3_y[i]}"
      code9  += code3.to_i(3).to_s
      h_code += code9
      code9 = ""
      code3 = ""
  end
  
    h_2 = h_code[3..h_code.length]
    h_1 = h_code[0..2]
    h_a1 = (h_1.to_f/30).floor
    h_a2 = h_1.to_i%30
  
    
    h_code ="#{H_KEY[h_a1]}#{H_KEY[h_a2]}#{h_2}"


 return GeoHex::Zone.new(z_loc_y, z_loc_x, _x, _y, h_code) 
  
end
loc2xy(_lon,_lat) click to toggle source
# File lib/geohex.rb, line 434
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
new(*params) click to toggle source
# File lib/geohex.rb, line 19
def initialize(*params)
  raise ArgumentError, "latlng or code is needed" if params.size == 0

  @lat = params[0]
  @lon = params[1]
  @x   = params[2]
  @y   = params[3]
  @code= params[4]
  
end
xy2loc(_x,_y) click to toggle source
# File lib/geohex.rb, line 441
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

Public Instance Methods

hexCoords() click to toggle source
# File lib/geohex.rb, line 41
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 / 180)) 
  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
hexSize() click to toggle source
# File lib/geohex.rb, line 37
def hexSize
  self.calcHexSize(self.level)
end
level() click to toggle source
# File lib/geohex.rb, line 34
def level
  H_KEY.index(code[0,1])
end