class SphericalMercator
Constants
- A
900913 properties.
- D2R
- EPSLN
Closures including constants and other precalculated values.
- MAX_EXTENT
- R2D
Attributes
Public Class Methods
# File lib/spherical_mercator/version.rb, line 2 def self.gem_version Gem::Version.new VERSION::STRING end
SphericalMercator
constructor: precaches calculations for fast tile lookups.
# File lib/spherical_mercator.rb, line 23 def initialize(opts = {}) @cache = {} @options = opts || {} self.size = (options[:size] || 256).to_f # Whether to round output values for integer zoom levels. Defaults to true. self.round = (options[:round].nil?) ? true : options[:round] if cache[size].nil? size = self.size c = cache[self.size] = {} c['Bc'] = [] c['Cc'] = [] c['zc'] = [] c['Ac'] = [] 30.times do c['Ac'].push(size.to_i) c['Bc'].push(size / 360) c['Cc'].push(size / (2 * Math::PI)) c['zc'].push((size / 2).to_i) size *= 2 end end @ac = cache[self.size]['Ac'] @bc = cache[self.size]['Bc'] @cc = cache[self.size]['Cc'] @zc = cache[self.size]['zc'] end
Public Instance Methods
Convert tile xyz value to bbox of the form `[w, s, e, n]`
-
`x` {Number} x (longitude) number.
-
`y` {Number} y (latitude) number.
-
`zoom` {Number} zoom.
-
`tms_style` {Boolean} whether to compute using tms-style.
-
`srs` {String} projection for resulting bbox (WGS84|900913).
-
`return` {Array} bbox array of values in form `[w, s, e, n]`.
# File lib/spherical_mercator.rb, line 127 def bbox(x, y, zoom, tms_style = false, srs = 'WGS84') # Convert xyz into bbox with srs WGS84 y = ((2**zoom) - 1) - y if tms_style lower_left = [x * @size, (y + 1) * @size] # lower left upper_right = [(x + 1) * @size, y * @size] # upper right bbox = ll(lower_left, zoom).concat(ll(upper_right, zoom)) # If web mercator requested reproject to 900913. if srs == '900913' convert(bbox, '900913') else bbox end end
Convert projection of given bbox.
-
`bbox` {Number} bbox in the form `[w, s, e, n]`.
-
`to` {String} projection of output bbox (WGS84|900913). Input bbox assumed to be the “other” projection.
-
`@return` {Object} bbox with reprojected coordinates.
# File lib/spherical_mercator.rb, line 190 def convert(bbox, to = 'WGS84') if to == '900913' forward(bbox.slice(0, 2)).concat(forward(bbox.slice(2, 4))) else inverse(bbox.slice(0, 2)).concat(inverse(bbox.slice(2, 4))) end end
function isFloat(n)
# File lib/spherical_mercator.rb, line 56 def float?(value) number = Float(value) number % 1 != 0 rescue ArgumentError false end
Convert lon/lat values to 900913 x/y.
# File lib/spherical_mercator.rb, line 199 def forward(lon_lat) xy = [ A * lon_lat[0] * D2R, A * Math.log(Math.tan((Math::PI * 0.25) + (0.5 * lon_lat[1] * D2R))) ] # if xy value is beyond maxextent (e.g. poles), return maxextent. (xy[0] > MAX_EXTENT) && (xy[0] = MAX_EXTENT) (xy[0] < -MAX_EXTENT) && (xy[0] = -MAX_EXTENT) (xy[1] > MAX_EXTENT) && (xy[1] = MAX_EXTENT) (xy[1] < -MAX_EXTENT) && (xy[1] = -MAX_EXTENT) xy end
Convert 900913 x/y values to lon/lat.
# File lib/spherical_mercator.rb, line 214 def inverse(xy) [ (xy[0] * R2D / A), ((Math::PI * 0.5) - 2.0 * Math.atan(Math.exp(-xy[1] / A))) * R2D ] end
Convert screen pixel value to lon lat
-
`px` {Array} `[x, y]` array of geographic coordinates.
-
`zoom` {Number} zoom level.
# File lib/spherical_mercator.rb, line 101 def ll(px, zoom) if float?(zoom) size = @size * (2**zoom) bc = (size / 360) cc = (size / (2 * Math::PI)) zc = size / 2 g = (px[1] - zc) / -cc lon = (px[0] - zc) / bc lat = R2D * (2 * Math.atan(Math.exp(g)) - 0.5 * Math::PI) [lon, lat] else g = (px[1] - @zc[zoom]) / (-@cc[zoom]) lon = (px[0] - @zc[zoom]) / @bc[zoom] lat = R2D * (2 * Math.atan(Math.exp(g)) - 0.5 * Math::PI) [lon, lat] end end
Convert lon lat to screen pixel value
-
`ll` {Array} `[lon, lat]` array of geographic coordinates.
-
`zoom` {Number} zoom level.
# File lib/spherical_mercator.rb, line 67 def px(lon_lat, zoom) if float?(zoom) || !self.round size = @size * (2**zoom) d = size / 2 bc = (size / 360) cc = (size / (2 * Math::PI)) ac = size f = [[Math.sin(D2R * lon_lat[1]), -0.9999].max, 0.9999].min x = d + lon_lat[0] * bc y = d + 0.5 * Math.log((1 + f) / (1 - f)) * -cc (x > ac) && (x = ac) (y > ac) && (y = ac) # (x < 0) && (x = 0) # (y < 0) && (y = 0) [x, y] else d = @zc[zoom] # JS: Math.min(Math.max(Math.sin(D2R * ll[1]), -0.9999), 0.9999) f = [[Math.sin(D2R * lon_lat[1]), -0.9999].max, 0.9999].min x = (d + lon_lat[0] * @bc[zoom]).round y = (d + 0.5 * Math.log((1 + f) / (1 - f)) * (-@cc[zoom])).round (x > @ac[zoom]) && (x = @ac[zoom]) (y > @ac[zoom]) && (y = @ac[zoom]) # (x < 0) && (x = 0) # (y < 0) && (y = 0) [x, y] end end
Convert bbox to xyx bounds
-
`bbox` {Number} bbox in the form `[w, s, e, n]`.
-
`zoom` {Number} zoom.
-
`tms_style` {Boolean} whether to compute using tms-style.
-
`srs` {String} projection of input bbox (WGS84|900913).
-
`@return` {Object} XYZ bounds containing minX, maxX, minY, maxY properties
# File lib/spherical_mercator.rb, line 151 def xyz(bbox, zoom, tms_style = false, srs = 'WGS84') # If web mercator provided reproject to WGS84. bbox = convert(bbox, 'WGS84') if srs == '900913' lower_left = [bbox[0], bbox[1]] # lower left upper_right = [bbox[2], bbox[3]] # upper right px_ll = px(lower_left, zoom) px_ur = px(upper_right, zoom) # Y = 0 for XYZ is the top hence minY uses px_ur[1]. x = [(px_ll[0] / @size).floor, ((px_ur[0] - 1) / @size).floor] y = [(px_ur[1] / @size).floor, ((px_ll[1] - 1) / @size).floor] bounds = { minX: x.min < 0 ? 0 : x.min, # JS: Math.min.apply(Math, x) minY: y.min < 0 ? 0 : y.min, maxX: x.max, maxY: y.max } if tms_style tms = { minY: ((2**zoom) - 1) - bounds[:maxY], maxY: ((2**zoom) - 1) - bounds[:minY] } bounds[:minY] = tms[:minY] bounds[:maxY] = tms[:maxY] end bounds end