Update to iD v2.9.0
[rails.git] / lib / quad_tile.rb
1 module QuadTile
2   begin
3     require "quad_tile/quad_tile_so"
4   rescue LoadError
5     def self.tile_for_point(lat, lon)
6       x = ((lon.to_f + 180) * 65535 / 360).round
7       y = ((lat.to_f + 90) * 65535 / 180).round
8
9       tile_for_xy(x, y)
10     end
11
12     def self.tiles_for_area(bbox)
13       minx = ((bbox.min_lon + 180) * 65535 / 360).round
14       maxx = ((bbox.max_lon + 180) * 65535 / 360).round
15       miny = ((bbox.min_lat + 90) * 65535 / 180).round
16       maxy = ((bbox.max_lat + 90) * 65535 / 180).round
17       tiles = []
18
19       minx.upto(maxx) do |x|
20         miny.upto(maxy) do |y|
21           tiles << tile_for_xy(x, y)
22         end
23       end
24
25       tiles
26     end
27
28     def self.tile_for_xy(x, y)
29       t = 0
30
31       16.times do
32         t = t << 1
33         t |= 1 unless (x & 0x8000).zero?
34         x <<= 1
35         t = t << 1
36         t |= 1 unless (y & 0x8000).zero?
37         y <<= 1
38       end
39
40       t
41     end
42
43     def self.iterate_tiles_for_area(bbox)
44       tiles = tiles_for_area(bbox)
45       first = last = nil
46
47       tiles.sort.each do |tile|
48         if last.nil?
49           first = last = tile
50         elsif tile == last + 1
51           last = tile
52         else
53           yield first, last
54
55           first = last = tile
56         end
57       end
58
59       yield first, last unless last.nil?
60     end
61   end
62
63   def self.sql_for_area(bbox, prefix)
64     sql = []
65     single = []
66
67     iterate_tiles_for_area(bbox) do |first, last|
68       if first == last
69         single.push(first)
70       else
71         sql.push("#{prefix}tile BETWEEN #{first} AND #{last}")
72       end
73     end
74
75     sql.push("#{prefix}tile IN (#{single.join(',')})") unless single.empty?
76
77     "( " + sql.join(" OR ") + " )"
78   end
79
80   private_class_method :tile_for_xy, :iterate_tiles_for_area
81 end