X-Git-Url: https://git.openstreetmap.org/rails.git/blobdiff_plain/cfbdd3f7e1c688e2c875ded9fd847fcc1c3a4caf..8688edf992a909ca914834a00be58bbcd175f2e1:/lib/quad_tile/quad_tile.c?ds=sidebyside diff --git a/lib/quad_tile/quad_tile.c b/lib/quad_tile/quad_tile.c index 137963bd0..cd45e6e76 100644 --- a/lib/quad_tile/quad_tile.c +++ b/lib/quad_tile/quad_tile.c @@ -1,6 +1,60 @@ #include "ruby.h" #include "quad_tile.h" +typedef struct { + unsigned int *tilev; + unsigned int tilec; +} tilelist_t; + +static tilelist_t tilelist_for_area(unsigned int minx, unsigned int miny, unsigned int maxx, unsigned int maxy) +{ + unsigned int x; + unsigned int y; + tilelist_t tl; + unsigned int maxtilec; + + maxtilec = 256; + + tl.tilev = malloc(maxtilec * sizeof(unsigned int)); + tl.tilec = 0; + + for (x = minx; x <= maxx; x++) + { + for (y = miny; y <= maxy; y++) + { + if (tl.tilec == maxtilec) + { + maxtilec = maxtilec * 2; + + tl.tilev = realloc(tl.tilev, maxtilec * sizeof(unsigned int)); + } + + tl.tilev[tl.tilec++] = xy2tile(x, y); + } + } + + return tl; +} + +static int tile_compare(const void *ap, const void *bp) +{ + unsigned int a = *(unsigned int *)ap; + unsigned int b = *(unsigned int *)bp; + + if (a < b) + { + return -1; + } + else if (a > b) + { + return 1; + } + else + { + return 0; + } +} + static VALUE tile_for_point(VALUE self, VALUE lat, VALUE lon) { unsigned int x = lon2x(NUM2DBL(lon)); @@ -9,24 +63,23 @@ static VALUE tile_for_point(VALUE self, VALUE lat, VALUE lon) return UINT2NUM(xy2tile(x, y)); } -static VALUE tiles_for_area(VALUE self, VALUE minlat, VALUE minlon, VALUE maxlat, VALUE maxlon) +static VALUE tiles_for_area(VALUE self, VALUE bbox) { - unsigned int minx = lon2x(NUM2DBL(minlon)); - unsigned int maxx = lon2x(NUM2DBL(maxlon)); - unsigned int miny = lat2y(NUM2DBL(minlat)); - unsigned int maxy = lat2y(NUM2DBL(maxlat)); + unsigned int minx = lon2x(NUM2DBL(rb_iv_get(bbox, "@min_lon"))); + unsigned int maxx = lon2x(NUM2DBL(rb_iv_get(bbox, "@max_lon"))); + unsigned int miny = lat2y(NUM2DBL(rb_iv_get(bbox, "@min_lat"))); + unsigned int maxy = lat2y(NUM2DBL(rb_iv_get(bbox, "@max_lat"))); + tilelist_t tl = tilelist_for_area(minx, miny, maxx, maxy); VALUE tiles = rb_ary_new(); - unsigned int x; - unsigned int y; + unsigned int t; - for (x = minx; x <= maxx; x++) + for (t = 0; t < tl.tilec; t++) { - for (y = miny; y <= maxy; y++) - { - rb_ary_push(tiles, UINT2NUM(xy2tile(x, y))); - } + rb_ary_push(tiles, UINT2NUM(tl.tilev[tl.tilec])); } + free(tl.tilev); + return tiles; } @@ -35,13 +88,61 @@ static VALUE tile_for_xy(VALUE self, VALUE x, VALUE y) return UINT2NUM(xy2tile(NUM2UINT(x), NUM2UINT(y))); } +static VALUE iterate_tiles_for_area(VALUE self, VALUE bbox) +{ + unsigned int minx = lon2x(NUM2DBL(rb_iv_get(bbox, "@min_lon"))); + unsigned int maxx = lon2x(NUM2DBL(rb_iv_get(bbox, "@max_lon"))); + unsigned int miny = lat2y(NUM2DBL(rb_iv_get(bbox, "@min_lat"))); + unsigned int maxy = lat2y(NUM2DBL(rb_iv_get(bbox, "@max_lat"))); + tilelist_t tl = tilelist_for_area(minx, miny, maxx, maxy); + + if (tl.tilec > 0) + { + unsigned int first; + unsigned int last; + unsigned int t; + VALUE a = rb_ary_new(); + + qsort(tl.tilev, tl.tilec, sizeof(unsigned int), tile_compare); + + first = last = tl.tilev[0]; + + for (t = 1; t < tl.tilec; t++) + { + unsigned int tile = tl.tilev[t]; + + if (tile == last + 1) + { + last = tile; + } + else + { + rb_ary_store(a, 0, UINT2NUM(first)); + rb_ary_store(a, 1, UINT2NUM(last)); + rb_yield(a); + + first = last = tile; + } + } + + rb_ary_store(a, 0, UINT2NUM(first)); + rb_ary_store(a, 1, UINT2NUM(last)); + rb_yield(a); + } + + free(tl.tilev); + + return Qnil; +} + void Init_quad_tile_so(void) { VALUE m = rb_define_module("QuadTile"); rb_define_module_function(m, "tile_for_point", tile_for_point, 2); - rb_define_module_function(m, "tiles_for_area", tiles_for_area, 4); + rb_define_module_function(m, "tiles_for_area", tiles_for_area, 1); rb_define_module_function(m, "tile_for_xy", tile_for_xy, 2); + rb_define_module_function(m, "iterate_tiles_for_area", iterate_tiles_for_area, 1); return; }