QuadTile infrastructure.
[rails.git] / lib / quad_tile.rb
1 module QuadTile
2   begin
3     require "quad_tile/quad_tile_so"
4   rescue MissingSourceFile
5     def self.tile_for_point(lat, lon)
6       x = ((lon + 180) * 65535 / 360).round
7       y = ((lat + 90) * 65535 / 180).round
8
9       return tile_for_xy(x, y)
10     end
11
12     def self.tiles_for_area(minlat, minlon, maxlat, maxlon)
13       minx = ((minlon + 180) * 65535 / 360).round
14       maxx = ((maxlon + 180) * 65535 / 360).round
15       miny = ((minlat + 90) * 65535 / 180).round
16       maxy = ((maxlat + 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       return 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 = t | 1 unless (x & 0x8000).zero?
34         x <<= 1
35         t = t << 1
36         t = t | 1 unless (y & 0x8000).zero?
37         y <<= 1
38       end
39
40       return t
41     end
42   end
43
44   def self.sql_for_area(minlat, minlon, maxlat, maxlon)
45     sql = Array.new
46     single = Array.new
47
48     iterate_tiles_for_area(minlat, minlon, maxlat, maxlon) do |first,last|
49       if first == last
50         single.push(first)
51       else
52         sql.push("tile BETWEEN #{first} AND #{last}")
53       end
54     end
55
56     sql.push("tile IN (#{single.join(',')})") if single.size > 0
57
58     return "( " + sql.join(" OR ") + " )"
59   end
60
61   def self.iterate_tiles_for_area(minlat, minlon, maxlat, maxlon)
62     tiles = tiles_for_area(minlat, minlon, maxlat, maxlon)
63     first = last = nil
64
65     tiles.sort.each do |tile|
66       if last.nil?
67         first = last = tile
68       elsif tile == last + 1
69         last = tile
70       else
71         yield first, last
72
73         first = last = tile
74       end
75     end
76
77     yield first, last unless last.nil?
78   end
79
80   private_class_method :tile_for_xy, :iterate_tiles_for_area
81 end