]> git.openstreetmap.org Git - rails.git/blob - lib/quad_tile.rb
Add a C implementation of QuadTile.iterate_tiles_for_area
[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.to_f + 180) * 65535 / 360).round
7       y = ((lat.to_f + 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
43     def self.iterate_tiles_for_area(minlat, minlon, maxlat, maxlon)
44       tiles = tiles_for_area(minlat, minlon, maxlat, maxlon)
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(minlat, minlon, maxlat, maxlon, prefix)
64     sql = Array.new
65     single = Array.new
66
67     iterate_tiles_for_area(minlat, minlon, maxlat, maxlon) 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(',')})") if single.size > 0
76
77     return "( " + sql.join(" OR ") + " )"
78   end
79
80   private_class_method :tile_for_xy, :iterate_tiles_for_area
81 end