]> git.openstreetmap.org Git - rails.git/blob - lib/quad_tile/quad_tile.c
Add a C implementation of QuadTile.iterate_tiles_for_area
[rails.git] / lib / quad_tile / quad_tile.c
1 #include "ruby.h"
2 #include "quad_tile.h"
3
4 typedef struct {
5    unsigned int *tilev;
6    unsigned int tilec;
7 } tilelist_t;
8
9 static tilelist_t tilelist_for_area(unsigned int minx, unsigned int miny, unsigned int maxx, unsigned int maxy)
10 {
11    unsigned int x;
12    unsigned int y;
13    tilelist_t   tl;
14    unsigned int maxtilec;
15
16    maxtilec = 256;
17    
18    tl.tilev = malloc(maxtilec * sizeof(unsigned int));
19    tl.tilec = 0;
20    
21    for (x = minx; x <= maxx; x++)
22    {
23       for (y = miny; y <= maxy; y++)
24       {
25          if (tl.tilec == maxtilec)
26          {
27             maxtilec = maxtilec * 2;
28
29             tl.tilev = realloc(tl.tilev, maxtilec * sizeof(unsigned int));
30          }
31
32          tl.tilev[tl.tilec++] = xy2tile(x, y);
33       }
34    }
35
36    return tl;
37 }
38
39 static int tile_compare(const void *ap, const void *bp)
40 {
41    unsigned int a = *(unsigned int *)ap;
42    unsigned int b = *(unsigned int *)bp;
43
44    if (a < b)
45    {
46       return -1;
47    }
48    else if (a > b)
49    {
50       return 1;
51    }
52    else
53    {
54       return 0;
55    }
56 }
57
58 static VALUE tile_for_point(VALUE self, VALUE lat, VALUE lon)
59 {
60    unsigned int x = lon2x(NUM2DBL(lon));
61    unsigned int y = lat2y(NUM2DBL(lat));
62
63    return UINT2NUM(xy2tile(x, y));
64 }
65
66 static VALUE tiles_for_area(VALUE self, VALUE minlat, VALUE minlon, VALUE maxlat, VALUE maxlon)
67 {
68    unsigned int minx = lon2x(NUM2DBL(minlon));
69    unsigned int maxx = lon2x(NUM2DBL(maxlon));
70    unsigned int miny = lat2y(NUM2DBL(minlat));
71    unsigned int maxy = lat2y(NUM2DBL(maxlat));
72    tilelist_t   tl = tilelist_for_area(minx, miny, maxx, maxy);
73    VALUE        tiles = rb_ary_new();
74    unsigned int t;
75
76    for (t = 0; t < tl.tilec; t++)
77    {
78       rb_ary_push(tiles, UINT2NUM(tl.tilev[tl.tilec]));
79    }
80
81    free(tl.tilev);
82
83    return tiles;
84 }
85
86 static VALUE tile_for_xy(VALUE self, VALUE x, VALUE y)
87 {
88    return UINT2NUM(xy2tile(NUM2UINT(x), NUM2UINT(y)));
89 }
90
91 static VALUE iterate_tiles_for_area(VALUE self, VALUE minlat, VALUE minlon, VALUE maxlat, VALUE maxlon)
92 {
93    unsigned int minx = lon2x(NUM2DBL(minlon));
94    unsigned int maxx = lon2x(NUM2DBL(maxlon));
95    unsigned int miny = lat2y(NUM2DBL(minlat));
96    unsigned int maxy = lat2y(NUM2DBL(maxlat));
97    tilelist_t   tl = tilelist_for_area(minx, miny, maxx, maxy);
98
99    if (tl.tilec > 0)
100    {
101       unsigned int first;
102       unsigned int last;
103       unsigned int t;
104       VALUE        a = rb_ary_new();
105
106       qsort(tl.tilev, tl.tilec, sizeof(unsigned int), tile_compare);
107
108       first = last = tl.tilev[0];
109
110       for (t = 1; t < tl.tilec; t++)
111       {
112          unsigned int tile = tl.tilev[t];
113
114          if (tile == last + 1)
115          {
116             last = tile;
117          }
118          else
119          {
120             rb_ary_store(a, 0, UINT2NUM(first));
121             rb_ary_store(a, 1, UINT2NUM(last));
122             rb_yield(a);
123
124             first = last = tile;
125          }
126       }
127
128       rb_ary_store(a, 0, UINT2NUM(first));
129       rb_ary_store(a, 1, UINT2NUM(last));
130       rb_yield(a);
131    }
132
133    free(tl.tilev);
134
135    return Qnil;
136 }
137
138 void Init_quad_tile_so(void)
139 {
140    VALUE m = rb_define_module("QuadTile");
141
142    rb_define_module_function(m, "tile_for_point", tile_for_point, 2);
143    rb_define_module_function(m, "tiles_for_area", tiles_for_area, 4);
144    rb_define_module_function(m, "tile_for_xy", tile_for_xy, 2);
145    rb_define_module_function(m, "iterate_tiles_for_area", iterate_tiles_for_area, 4);
146
147    return;
148 }