diff --git a/docs/GEOBIN.md b/docs/GEOBIN.md index 4ce8301..a5e85ef 100644 --- a/docs/GEOBIN.md +++ b/docs/GEOBIN.md @@ -53,8 +53,7 @@ dimensions, followed by a series of coordinates that define the rectangle. - 1-byte integer: number of dimensions (4) - 8-byte float[8]: `[xmin, ymin, zmin, mmin, xmax, ymax, zmax, mmax]` -GeoBIN only supports 2, 3, or 4 dimensions; or zero to omit this section -altogether. +GeoBIN only supports 2, 3, or 4 dimensions. ### Extra JSON Section diff --git a/tests/test_geobin.c b/tests/test_geobin.c index ac285c7..eeb2419 100644 --- a/tests/test_geobin.c +++ b/tests/test_geobin.c @@ -30,6 +30,30 @@ void perfect_match(const char *geojson_or_wkt, const char *expect, int dims, dou cmpfullrect(gdims, gmin, gmax, dims, min, max); + struct tg_rect rect = tg_geobin_rect(geobin, geobinlen); + gdims = 2; + gmin[0] = rect.min.x; + gmin[1] = rect.min.y; + gmax[0] = rect.max.x; + gmax[1] = rect.max.y; + cmpfullrect(gdims, gmin, gmax, 2, min, max); + + struct tg_point point = tg_geobin_point(geobin, geobinlen); + gdims = 2; + gmin[0] = point.x; + gmin[1] = point.y; + gmax[0] = point.x; + gmax[1] = point.y; + + double min2[4], max2[4]; + min2[0] = (gmin[0]+gmax[0])/2; + min2[1] = (gmin[1]+gmax[1])/2; + max2[0] = min2[0]; + max2[1] = min2[1]; + cmpfullrect(gdims, gmin, gmax, 2, min2, max2); + + + char geojson_or_wkt2[100000]; size_t geojson_or_wkt2len; if (geojson_or_wkt[0] == '{') { @@ -169,5 +193,6 @@ int main(int argc, char **argv) { do_test(test_geobin_fail); do_test(test_geobin_max_depth); do_chaos_test(test_geobin_chaos); + do_test(test_geobin_basic_syntax); return 0; } diff --git a/tg.c b/tg.c index fe1ca39..d351d3c 100644 --- a/tg.c +++ b/tg.c @@ -14810,3 +14810,57 @@ int tg_geobin_fullrect(const uint8_t *geobin, size_t len, double min[4], } return dims; } + +struct tg_rect tg_geobin_rect(const uint8_t *geobin, size_t len) { + struct tg_rect rect = { 0 }; + if (geobin && len > 2 && geobin[0] >= 0x01 && geobin[0] <= 0x04) { + if (geobin[0] == 0x01 && len >= 21) { + // Read Point + uint32_t type; + memcpy(&type, geobin+1, 4); + if (type == 1 || type == 1001 || type == 2001 || type == 3001) { + memcpy(&rect.min.x, geobin+5, 8); + memcpy(&rect.min.y, geobin+5+8, 8); + rect.max.x = rect.min.x; + rect.max.y = rect.min.y; + } + } else if (geobin[0] != 0x01 && len >= 2+8*(size_t)geobin[1]*2){ + // Read MBR + int dims = geobin[1]; + if (dims >= 2) { + memcpy(&rect.min.x, geobin+2, 8); + memcpy(&rect.min.y, geobin+2+8, 8); + memcpy(&rect.max.x, geobin+2+8*dims, 8); + memcpy(&rect.max.y, geobin+2+8*dims+8, 8); + } + } + } + return rect; +} + +struct tg_point tg_geobin_point(const uint8_t *geobin, size_t len) { + struct tg_point point = { 0 }; + if (geobin && len > 2 && geobin[0] >= 0x01 && geobin[0] <= 0x04) { + if (geobin[0] == 0x01 && len >= 21) { + // Read Point + uint32_t type; + memcpy(&type, geobin+1, 4); + if (type == 1 || type == 1001 || type == 2001 || type == 3001) { + memcpy(&point.x, geobin+5, 8); + memcpy(&point.y, geobin+5+8, 8); + } + } else if (geobin[0] != 0x01 && len >= 2+8*(size_t)geobin[1]*2){ + // Read MBR + struct tg_rect rect = { 0 }; + int dims = geobin[1]; + if (dims >= 2) { + memcpy(&rect.min.x, geobin+2, 8); + memcpy(&rect.min.y, geobin+2+8, 8); + memcpy(&rect.max.x, geobin+2+8*dims, 8); + memcpy(&rect.max.y, geobin+2+8*dims+8, 8); + } + point = tg_rect_center(rect); + } + } + return point; +} diff --git a/tg.h b/tg.h index d865384..9b4ede9 100644 --- a/tg.h +++ b/tg.h @@ -164,6 +164,8 @@ struct tg_geom *tg_parse(const void *data, size_t len); struct tg_geom *tg_parse_ix(const void *data, size_t len, enum tg_index ix); const char *tg_geom_error(const struct tg_geom *geom); int tg_geobin_fullrect(const uint8_t *geobin, size_t len, double min[4], double max[4]); +struct tg_rect tg_geobin_rect(const uint8_t *geobin, size_t len); +struct tg_point tg_geobin_point(const uint8_t *geobin, size_t len); /// @}