openstreetmap-website/lib/quad_tile/quad_tile.c
Peter Gray 95d899786a Refactor bounding box code
Moved duplicated code into the BoundingBox class, and pass around
BoundingBox objects instead of lists of bounds.
2011-11-14 09:42:57 +00:00

148 lines
3.4 KiB
C

#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;
}