Remove quad_tile library and extract to gem

Quad tile functions are now installed via a gem with native extension
automatically. This improves the run time of the test suite by ~30% for
users that didn't bother to build the C version of the functions.

Closes #1314
Closes #1899
This commit is contained in:
Benjamin Reynolds 2018-06-14 18:25:35 +01:00 committed by Tom Hughes
parent 39a1600c3a
commit d5672aed4a
10 changed files with 6 additions and 292 deletions

View file

@ -1,81 +0,0 @@
module QuadTile
begin
require "quad_tile/quad_tile_so"
rescue LoadError
def self.tile_for_point(lat, lon)
x = ((lon.to_f + 180) * 65535 / 360).round
y = ((lat.to_f + 90) * 65535 / 180).round
tile_for_xy(x, y)
end
def self.tiles_for_area(bbox)
minx = ((bbox.min_lon + 180) * 65535 / 360).round
maxx = ((bbox.max_lon + 180) * 65535 / 360).round
miny = ((bbox.min_lat + 90) * 65535 / 180).round
maxy = ((bbox.max_lat + 90) * 65535 / 180).round
tiles = []
minx.upto(maxx) do |x|
miny.upto(maxy) do |y|
tiles << tile_for_xy(x, y)
end
end
tiles
end
def self.tile_for_xy(x, y)
t = 0
16.times do
t = t << 1
t |= 1 unless (x & 0x8000).zero?
x <<= 1
t = t << 1
t |= 1 unless (y & 0x8000).zero?
y <<= 1
end
t
end
def self.iterate_tiles_for_area(bbox)
tiles = tiles_for_area(bbox)
first = last = nil
tiles.sort.each do |tile|
if last.nil?
first = last = tile
elsif tile == last + 1
last = tile
else
yield first, last
first = last = tile
end
end
yield first, last unless last.nil?
end
end
def self.sql_for_area(bbox, prefix)
sql = []
single = []
iterate_tiles_for_area(bbox) do |first, last|
if first == last
single.push(first)
else
sql.push("#{prefix}tile BETWEEN #{first} AND #{last}")
end
end
sql.push("#{prefix}tile IN (#{single.join(',')})") unless single.empty?
"( " + sql.join(" OR ") + " )"
end
private_class_method :tile_for_xy, :iterate_tiles_for_area
end

View file

@ -1,3 +0,0 @@
Makefile
quad_tile.o
quad_tile_so.so

View file

@ -1,5 +0,0 @@
require "mkmf"
with_cflags("-std=c99 #{$CFLAGS}") do
create_makefile("quad_tile_so")
end

View file

@ -1,148 +0,0 @@
#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[t]));
}
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;
}

View file

@ -1,25 +0,0 @@
#include <math.h>
static inline unsigned int xy2tile(unsigned int x, unsigned int y)
{
unsigned int tile = 0;
int i;
for (i = 15; i >= 0; i--)
{
tile = (tile << 1) | ((x >> i) & 1);
tile = (tile << 1) | ((y >> i) & 1);
}
return tile;
}
static inline unsigned int lon2x(double lon)
{
return round((lon + 180.0) * 65535.0 / 360.0);
}
static inline unsigned int lat2y(double lat)
{
return round((lat + 90.0) * 65535.0 / 180.0);
}