module Tsuga::Model::PointTrait
Represents a position in the 0..1 x 0..1 square, modeling points on the Earth as represented by their longitude/latitude coordinates.
Concretions have the following accessors:
-
:geohash (64-bit integer)
-
:lat (float, -90..90)
-
:lng (float, -180..180)
Constants
- Magic
Public Instance Methods
&(other)
click to toggle source
# File lib/tsuga/model/point.rb, line 28 def &(other) distance_to(other) end
=~(other)
click to toggle source
# File lib/tsuga/model/point.rb, line 23 def =~(other) self.geohash == other.geohash end
distance_to(other)
click to toggle source
# File lib/tsuga/model/point.rb, line 18 def distance_to(other) Math.sqrt((self.lat - other.lat) ** 2 + (self.lng - other.lng) ** 2) end
geohash=(value)
click to toggle source
Calls superclass method
# File lib/tsuga/model/point.rb, line 33 def geohash=(value) super(value) _updating_coords { _set_latlng_from_geohash } geohash end
inspect()
click to toggle source
# File lib/tsuga/model/point.rb, line 56 def inspect "<%s lat:%s lng:%s geohash:%s>" % [ (self.class.name || 'Point').gsub(/.*::/, ''), lat ? ("%.3f" % lat) : 'nil', lng ? ("%.3f" % lng) : 'nil', geohash ? geohash : 'nil' ] end
lat=(value)
click to toggle source
Calls superclass method
# File lib/tsuga/model/point.rb, line 40 def lat=(value) _validate_lat(value) if value super(value) _updating_coords { _set_geohash_from_latlng } lat end
lng=(value)
click to toggle source
Calls superclass method
# File lib/tsuga/model/point.rb, line 48 def lng=(value) _validate_lng(value) if value super(value) _updating_coords { _set_geohash_from_latlng } lng end
prefix(depth)
click to toggle source
# File lib/tsuga/model/point.rb, line 65 def prefix(depth) geohash[0...depth] end
Private Instance Methods
_deinterleave_bits(z)
click to toggle source
# File lib/tsuga/model/point.rb, line 146 def _deinterleave_bits(z) x_hi, y_hi = _deinterleave_bits_16b(z >> 32) x_lo, y_lo = _deinterleave_bits_16b(z & 0xFFFFFFFF) [((x_hi << 16) | x_lo), ((y_hi << 16) | y_lo)] end
_deinterleave_bits_16b(z)
click to toggle source
Deinterleave even bits and odd bits (resp.) to a 2-tuple. Rubyfied from fgiesen.wordpress.com/2009/12/13/decoding-morton-codes/
# File lib/tsuga/model/point.rb, line 175 def _deinterleave_bits_16b(z) [_even_bits(z), _even_bits(z >> 1)] end
_even_bits(z)
click to toggle source
# File lib/tsuga/model/point.rb, line 180 def _even_bits(z) x = z & 0x55555555 x = (x ^ (x >> 1)) & 0x33333333 x = (x ^ (x >> 2)) & 0x0f0f0f0f x = (x ^ (x >> 4)) & 0x00ff00ff x = (x ^ (x >> 8)) & 0x0000ffff end
_geohash_to_int(value)
click to toggle source
# File lib/tsuga/model/point.rb, line 95 def _geohash_to_int(value) value.to_i(4) end
_int_to_geohash(value)
click to toggle source
# File lib/tsuga/model/point.rb, line 99 def _int_to_geohash(value) value.to_s(4).rjust(32,'0') end
_interleave_bits(a,b)
click to toggle source
# File lib/tsuga/model/point.rb, line 140 def _interleave_bits(a,b) (_interleave_bits_16b(a >> 16, b >> 16) << 32) | (_interleave_bits_16b(a & 0xffff, b & 0xffff)) end
_interleave_bits_16b(x,y)
click to toggle source
Interleave lower 16 bits of x and y, so the bits of x are in the even positions and bits from y in the odd; z gets the resulting 32-bit Morton Number.
x and y must initially be less than 65536. Rubyfied from graphics.stanford.edu/~seander/bithacks.html
# File lib/tsuga/model/point.rb, line 161 def _interleave_bits_16b(x,y) x = (x | (x << 8)) & Magic[3] x = (x | (x << 4)) & Magic[2] x = (x | (x << 2)) & Magic[1] x = (x | (x << 1)) & Magic[0] y = (y | (y << 8)) & Magic[3] y = (y | (y << 4)) & Magic[2] y = (y | (y << 2)) & Magic[1] y = (y | (y << 1)) & Magic[0] z = x | (y << 1) end
_set_geohash_from_latlng()
click to toggle source
# File lib/tsuga/model/point.rb, line 122 def _set_geohash_from_latlng lat = self.lat lng = self.lng if lat.nil? || lng.nil? self.geohash = nil return end _validate_lat(lat) _validate_lng(lng) normalized_lat = ((lat + 90.0) * (1<<32) / 180.0).to_i normalized_lng = ((lng + 180.0) * (1<<32) / 360.0).to_i geohash_i = _interleave_bits(normalized_lat, normalized_lng) self.geohash = _int_to_geohash(geohash_i) return end
_set_latlng_from_geohash()
click to toggle source
Convert the geohash into lat/lng
# File lib/tsuga/model/point.rb, line 104 def _set_latlng_from_geohash geohash = self.geohash if geohash.nil? self.lat = self.lng = nil return end _validate_geohash(geohash) geohash_i = _geohash_to_int(geohash) lat,lng = _deinterleave_bits(geohash_i) lat = lat * 180.0 / (1<<32) - 90.0 lng = lng * 360.0 / (1<<32) - 180.0 self.lat = lat self.lng = lng return end
_updating_coords() { || ... }
click to toggle source
only the outmost call yields. prevents infinite loops of latlng <-> geohash updates
# File lib/tsuga/model/point.rb, line 73 def _updating_coords return if @_updating @_updating = true yield @_updating = false end
_validate_geohash(value)
click to toggle source
# File lib/tsuga/model/point.rb, line 90 def _validate_geohash(value) raise ArgumentError, 'bad geohash' unless /^[0-3]{32}$/ =~ value end
_validate_lat(_lat)
click to toggle source
# File lib/tsuga/model/point.rb, line 81 def _validate_lat(_lat) raise ArgumentError, 'bad lat' unless ( -90.0 ... 90.0).include?(_lat) end
_validate_lng(_lng)
click to toggle source
# File lib/tsuga/model/point.rb, line 85 def _validate_lng(_lng) raise ArgumentError, 'bad lng' unless (-180.0 ... 180.0).include?(_lng) end