#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)); unsigned int y = lat2y(NUM2DBL(lat)); return UINT2NUM(xy2tile(x, y)); } static VALUE 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); VALUE tiles = rb_ary_new(); unsigned int t; for (t = 0; t < tl.tilec; t++) { rb_ary_push(tiles, UINT2NUM(tl.tilev[tl.tilec])); } free(tl.tilev); return tiles; } 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, 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; }