Class: Proxihash

Inherits:
Object
  • Object
show all
Defined in:
lib/proxihash.rb,
lib/proxihash/version.rb

Constant Summary collapse

VERSION =
[0, 0, 1]

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(value, num_bits) ⇒ Proxihash

Returns a new instance of Proxihash.



4
5
6
7
8
9
10
11
# File 'lib/proxihash.rb', line 4

def initialize(value, num_bits)
  @value = value
  @num_bits = num_bits
  num_bits.odd? or
    raise ArgumentError, "bitlength must be odd"
  value < 1 << num_bits or
    raise ArgumentError, "value too large for #{num_bits} bits"
end

Class Attribute Details

.angular_unitsObject

Returns the value of attribute angular_units.



52
53
54
# File 'lib/proxihash.rb', line 52

def angular_units
  @angular_units
end

.max_latObject (readonly)

Returns the value of attribute max_lat.



53
54
55
# File 'lib/proxihash.rb', line 53

def max_lat
  @max_lat
end

.max_lngObject (readonly)

Returns the value of attribute max_lng.



53
54
55
# File 'lib/proxihash.rb', line 53

def max_lng
  @max_lng
end

.min_latObject (readonly)

Returns the value of attribute min_lat.



53
54
55
# File 'lib/proxihash.rb', line 53

def min_lat
  @min_lat
end

.min_lngObject (readonly)

Returns the value of attribute min_lng.



53
54
55
# File 'lib/proxihash.rb', line 53

def min_lng
  @min_lng
end

.radiusObject

Returns the value of attribute radius.



52
53
54
# File 'lib/proxihash.rb', line 52

def radius
  @radius
end

Instance Attribute Details

#num_bitsObject (readonly)

Returns the value of attribute num_bits.



13
14
15
# File 'lib/proxihash.rb', line 13

def num_bits
  @num_bits
end

#valueObject (readonly)

Returns the value of attribute value.



13
14
15
# File 'lib/proxihash.rb', line 13

def value
  @value
end

Class Method Details

.encode(lat, lng, num_bits = 31) ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/proxihash.rb', line 55

def encode(lat, lng, num_bits=31)
  lat = lat.to_f
  lng = lng.to_f

  value = 0

  lat0 = min_lat
  lat1 = max_lat
  lng0 = min_lng
  lng1 = max_lng

  (num_bits - 1).downto(0) do |i|
    if i.odd?
      mid = 0.5 * (lat0 + lat1)
      if lat > mid
        value |= (1 << i)
        lat0 = mid
      else
        lat1 = mid
      end
    else
      mid = 0.5 * (lng0 + lng1)
      if lng > mid
        value |= (1 << i)
        lng0 = mid
      else
        lng1 = mid
      end
    end
  end

  new(value, num_bits)
end

.search_tiles(lat, lng, distance, options = {}) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/proxihash.rb', line 89

def search_tiles(lat, lng, distance, options={})
  lat = lat.to_f
  lng = lng.to_f
  bits = 2*lng_bits(lat, distance.to_f) - 1

  if (min_bits = options[:min_bits]) && bits < min_bits
    return nil
  elsif (max_bits = options[:max_bits]) && bits > max_bits
    # TODO: avoid unnecessary neighboring tiles
    bits = max_bits
  end

  # TODO: can use the next 2 bits to determine quadrant instead
  center = encode(lat, lng, bits)
  tile_lat, tile_lng = center.decode
  dlat = lat < tile_lat ? -1 : 1
  dlng = lng < tile_lng ? -1 : 1
  [
    center,
    center.neighbor(0   , dlng),
    center.neighbor(dlat, dlng),
    center.neighbor(dlat,    0),
  ]
rescue PoleWrapException
  nil
end

Instance Method Details

#==(other) ⇒ Object Also known as: eql?



188
189
190
# File 'lib/proxihash.rb', line 188

def ==(other)
  other.is_a?(Proxihash) && value == other.value && num_bits == other.num_bits
end

#decodeObject



133
134
135
136
# File 'lib/proxihash.rb', line 133

def decode
  lat0, lat1, lng0, lng1 = tile
  [0.5 * (lat0 + lat1), 0.5 * (lng0 + lng1)]
end

#eastObject



180
181
182
# File 'lib/proxihash.rb', line 180

def east
  neighbor(0, 1)
end

#hashObject



192
193
194
# File 'lib/proxihash.rb', line 192

def hash
  value.hash ^ num_bits
end

#idObject



15
16
17
# File 'lib/proxihash.rb', line 15

def id
  value | 1 << num_bits
end

#inspectObject



197
198
199
# File 'lib/proxihash.rb', line 197

def inspect
  "Proxihash[#{value.to_s(2).rjust(num_bits, '0')}]"
end

#neighbor(dlat, dlng) ⇒ Object



165
166
167
168
169
170
# File 'lib/proxihash.rb', line 165

def neighbor(dlat, dlng)
  value = self.value
  value = bump(value, 1, dlat, false) unless dlat.zero?
  value = bump(value, 0, dlng, true ) unless dlng.zero?
  self.class.new(value, num_bits)
end

#northObject



172
173
174
# File 'lib/proxihash.rb', line 172

def north
  neighbor(1, 0)
end

#southObject



176
177
178
# File 'lib/proxihash.rb', line 176

def south
  neighbor(-1, 0)
end

#tileObject



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/proxihash.rb', line 138

def tile
  lat0 = min_lat
  lat1 = max_lat
  lng0 = min_lng
  lng1 = max_lng

  (num_bits - 1).downto(0) do |i|
    if i.odd?
      mid = 0.5 * (lat0 + lat1)
      if value[i] == 1
        lat0 = mid
      else
        lat1 = mid
      end
    else
      mid = 0.5 * (lng0 + lng1)
      if value[i] == 1
        lng0 = mid
      else
        lng1 = mid
      end
    end
  end

  [lat0, lat1, lng0, lng1]
end

#westObject



184
185
186
# File 'lib/proxihash.rb', line 184

def west
  neighbor(0, -1)
end