From: Nicklas Avén Date: Tue, 30 Jun 2015 22:30:25 +0000 (+0000) Subject: Fix handling of different ingoing precision in collectTWKB and more X-Git-Tag: 2.2.0rc1~268 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e53772b996fa9bc3b82604aed8f9452ecd0aea8a;p=postgis Fix handling of different ingoing precision in collectTWKB and more git-svn-id: http://svn.osgeo.org/postgis/trunk@13771 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/liblwgeom/lwin_twkb.c b/liblwgeom/lwin_twkb.c index d79e6748a..309a835f7 100644 --- a/liblwgeom/lwin_twkb.c +++ b/liblwgeom/lwin_twkb.c @@ -2,6 +2,7 @@ * * PostGIS - Spatial Types for PostgreSQL * + * Copyright (C) 2015 Paul Ramsey * Copyright (C) 2014 Nicklas Avén * * This is free software; you can redistribute and/or modify it under @@ -9,48 +10,7 @@ * **********************************************************************/ -#include -#include "liblwgeom_internal.h" -#include "lwgeom_log.h" -#include "varint.h" - -#define TWKB_IN_MAXCOORDS 4 - -/** -* Used for passing the parse state between the parsing functions. -*/ -typedef struct -{ - /* Pointers to the bytes */ - uint8_t *twkb; /* Points to start of TWKB */ - uint8_t *twkb_end; /* Points to end of TWKB */ - uint8_t *pos; /* Current read position */ - - uint32_t check; /* Simple validity checks on geometries */ - uint32_t lwtype; /* Current type we are handling */ - - uint8_t has_bbox; - uint8_t has_size; - uint8_t has_idlist; - uint8_t has_z; - uint8_t has_m; - uint8_t is_empty; - - /* Precision factors to convert ints to double */ - double factor; - double factor_z; - double factor_m; - - uint64_t size; - - /* Info about current geometry */ - uint8_t magic_byte; /* the magic byte contain info about if twkb contain id, size info, bboxes and precision */ - - int ndims; /* Number of dimensions */ - - int64_t *coords; /* An array to keep delta values from 4 dimensions */ - -} twkb_parse_state; +#include "lwin_twkb.h" /** @@ -92,7 +52,7 @@ static inline uint64_t twkb_parse_state_uvarint(twkb_parse_state *s) return val; } -static inline double twkb_parse_state_double(twkb_parse_state *s, double factor) +inline double twkb_parse_state_double(twkb_parse_state *s, double factor) { size_t size; int64_t val = varint_s64_decode(s->pos, s->twkb_end, &size); @@ -473,7 +433,7 @@ static LWCOLLECTION* lwcollection_from_twkb_state(twkb_parse_state *s) } -static void header_from_twkb_state(twkb_parse_state *s) +void header_from_twkb_state(twkb_parse_state *s) { LWDEBUG(2,"Entering magicbyte_from_twkb_state"); diff --git a/liblwgeom/lwin_twkb.h b/liblwgeom/lwin_twkb.h new file mode 100644 index 000000000..35575042a --- /dev/null +++ b/liblwgeom/lwin_twkb.h @@ -0,0 +1,57 @@ +/********************************************************************** + * + * PostGIS - Spatial Types for PostgreSQL + * + * Copyright (C) 2015 Paul Ramsey + * + * This is free software; you can redistribute and/or modify it under + * the terms of the GNU General Public Licence. See the COPYING file. + * + **********************************************************************/ + +#include +#include "liblwgeom_internal.h" +#include "lwgeom_log.h" +#include "varint.h" + +#define TWKB_IN_MAXCOORDS 4 + +/** +* Used for passing the parse state between the parsing functions. +*/ +typedef struct +{ + /* Pointers to the bytes */ + uint8_t *twkb; /* Points to start of TWKB */ + uint8_t *twkb_end; /* Points to end of TWKB */ + uint8_t *pos; /* Current read position */ + + uint32_t check; /* Simple validity checks on geometries */ + uint32_t lwtype; /* Current type we are handling */ + + uint8_t has_bbox; + uint8_t has_size; + uint8_t has_idlist; + uint8_t has_z; + uint8_t has_m; + uint8_t is_empty; + + /* Precision factors to convert ints to double */ + double factor; + double factor_z; + double factor_m; + + uint64_t size; + + /* Info about current geometry */ + uint8_t magic_byte; /* the magic byte contain info about if twkb contain id, size info, bboxes and precision */ + + int ndims; /* Number of dimensions */ + + int64_t *coords; /* An array to keep delta values from 4 dimensions */ + +} twkb_parse_state; + + +void header_from_twkb_state(twkb_parse_state *s); +inline double twkb_parse_state_double(twkb_parse_state *s, double factor); diff --git a/liblwgeom/twkb_tools.c b/liblwgeom/twkb_tools.c index 33fa5fe1d..aa6a22f5a 100644 --- a/liblwgeom/twkb_tools.c +++ b/liblwgeom/twkb_tools.c @@ -14,97 +14,133 @@ #include "lwgeom_log.h" #include "varint.h" #include "lwout_twkb.h" +#include "lwin_twkb.h" /**********************************************************************/ +typedef struct +{ + int64_t bbox_min[MAX_N_DIMS]; + int64_t bbox_max[MAX_N_DIMS]; + double min_factor; + double min_factor_z; + double min_factor_m; + int has_z; + int has_m; + int is_empty; +} twkb_collection_data; + + /** * A function to collect many twkb-buffers into one collection */ -uint8_t* twkb_to_twkbcoll(uint8_t **twkb, size_t *sizes,size_t *out_size, int64_t *idlist, int n) +static twkb_collection_data twkb_get_bboxes(uint8_t **twkb, size_t *sizes, int n) { - LWDEBUG(2,"Entering twkb_to_twkbcoll"); - TWKB_STATE ts; - int i,b; - uint8_t *buf; - uint8_t metabyte; - int has_bbox = 0; - int has_size = 0; - int extended_dims = 0; - int is_empty = 0; - size_t size; - int cursor; - int64_t max, min; - int n_dims=0; - uint8_t type_prec = 0; - uint8_t flag = 0; - size_t size_to_register=0; - uint8_t *twkb_out; - size_t buf_size; - int has_z, has_m; - - for ( i = 0; i < MAX_N_DIMS; i++ ) - { - /* Reset bbox calculation */ - ts.bbox_max[i] = INT64_MIN; - ts.bbox_min[i] = INT64_MAX; - } + LWDEBUG(2,"Entering box_maxmin"); + twkb_parse_state s; + double min, max; + int i; + twkb_collection_data res; + GBOX bbox; + res.has_z = 0; + res.has_m = 0; + res.min_factor = res.min_factor_z = res.min_factor_m = 100000000; + res.is_empty = 1; + bbox.xmin = bbox.ymin = bbox.zmin = bbox.mmin = FLT_MAX; + bbox.xmax = bbox.ymax = bbox.zmax = bbox.mmax = FLT_MIN; /*For each buffer, collect their bounding box*/ for (i=0;i> 1; - extended_dims = (metabyte & 0x08) >> 3; - is_empty = (metabyte & 0x10) >> 4; + if(!s.is_empty) + res.is_empty = 0; + if(!s.has_bbox) + lwerror("We can only collect twkb with included bbox"); - if ( extended_dims ) - { - extended_dims = *(buf+cursor); - cursor++; - - has_z = (extended_dims & 0x01); - has_m = (extended_dims & 0x02) >> 1; - } - else - { - has_z = 0; - has_m = 0; - } + /*read bbox and expand to all*/ - n_dims=2+has_z+has_m; - if(has_size) + if(s.factor bbox.xmax) + bbox.xmax=max; + /* Y */ + min = twkb_parse_state_double(&s, s.factor); + if(min < bbox.ymin) + bbox.ymin=min; + max = min + twkb_parse_state_double(&s, s.factor); + if(max > bbox.ymax) + bbox.ymax=max; + /* Z */ + if ( s.has_z ) { - /*jump over size_value*/ - cursor+=varint_size(buf+cursor, buf+buf_size); + if(s.factor_z bbox.zmax) + bbox.zmax=max; } - - if(!has_bbox) - lwerror("We can only collect twkb with included bbox"); - - /*read bbox and expand to all*/ - for(b=0;bts.bbox_max[b]) - ts.bbox_max[b]=max; - } + if(s.factor_m bbox.mmax) + bbox.mmax=max; + } + } + + res.bbox_min[0] = (int64_t) lround(bbox.xmin*res.min_factor); + res.bbox_max[0] = (int64_t) lround(bbox.xmax*res.min_factor); + res.bbox_min[1] = (int64_t) lround(bbox.ymin*res.min_factor); + res.bbox_max[1] = (int64_t) lround(bbox.ymax*res.min_factor); + + if ( res.has_z ) + { + res.bbox_min[2] = (int64_t) lround(bbox.zmin*res.min_factor); + res.bbox_max[2] = (int64_t) lround(bbox.zmax*res.min_factor); + } + if ( res.has_m ) + { + res.bbox_min[2+res.has_z] = (int64_t) lround(bbox.mmin*res.min_factor); + res.bbox_max[2+res.has_z] = (int64_t) lround(bbox.mmax*res.min_factor); } + return res; +} + +static uint8_t* twkb_write_new_buffer(twkb_collection_data ts_data,uint8_t **twkb, size_t *sizes, size_t *out_size, int64_t *idlist, int n) +{ + TWKB_STATE ts; + int i; + uint8_t type_prec = 0; + uint8_t flag = 0; + size_t size_to_register=0; + uint8_t *twkb_out; + int n_dims; + int has_extended = (int) (ts_data.has_z||ts_data.has_m); /*Ok, we have all bounding boxes, then it's time to write*/ ts.header_buf = bytebuffer_create_with_size(16); @@ -112,8 +148,8 @@ uint8_t* twkb_to_twkbcoll(uint8_t **twkb, size_t *sizes,size_t *out_size, int64_ /* The type will always be COLLECTIONTYPE */ TYPE_PREC_SET_TYPE(type_prec,COLLECTIONTYPE); - /* Precision has no meaning here. All subgeoemtries holds their own precision */ - TYPE_PREC_SET_PREC(type_prec,0); + /* Precision here is only for bbox. We use the worst precission we have found */ + TYPE_PREC_SET_PREC(type_prec, zigzag8((int) log10(ts_data.min_factor))); /* Write the type and precision byte */ bytebuffer_append_byte(ts.header_buf, type_prec); @@ -123,12 +159,29 @@ uint8_t* twkb_to_twkbcoll(uint8_t **twkb, size_t *sizes,size_t *out_size, int64_ /* Always sizes */ FIRST_BYTE_SET_SIZES(flag,1); /* Is there idlist? */ - FIRST_BYTE_SET_IDLIST(flag, idlist && ! is_empty); + FIRST_BYTE_SET_IDLIST(flag, idlist && !ts_data.is_empty); /* No extended byte */ - FIRST_BYTE_SET_EXTENDED(flag, 0); + FIRST_BYTE_SET_EXTENDED(flag, has_extended); /* Write the header byte */ bytebuffer_append_byte(ts.header_buf, flag); + if(has_extended) + { + uint8_t flag = 0; + + if ( ts_data.has_z && (log10(ts_data.min_factor_z) > 7 || log10(ts_data.min_factor_z) < 0 ) ) + lwerror("%s: Z precision cannot be negative or greater than 7", __func__); + + if ( ts_data.has_m && ( log10(ts_data.min_factor_m) > 7 || log10(ts_data.min_factor_m)) ) + lwerror("%s: M precision cannot be negative or greater than 7", __func__); + + HIGHER_DIM_SET_HASZ(flag, ts_data.has_z); + HIGHER_DIM_SET_HASM(flag, ts_data.has_m); + HIGHER_DIM_SET_PRECZ(flag,(int) log10(ts_data.min_factor_z)); + HIGHER_DIM_SET_PRECM(flag,(int) log10(ts_data.min_factor_m)); + bytebuffer_append_byte(ts.header_buf, flag); + + } /*Write number of geometries*/ bytebuffer_append_uvarint(ts.geom_buf, n); @@ -142,6 +195,16 @@ uint8_t* twkb_to_twkbcoll(uint8_t **twkb, size_t *sizes,size_t *out_size, int64_ } } + n_dims = 2 + ts_data.has_z+ts_data.has_m; + + for ( i = 0; i < n_dims; i++ ) + { + ts.bbox_min[i]=ts_data.bbox_min[i]; + ts.bbox_max[i]=ts_data.bbox_max[i]; + + size_to_register += sizes[i]; + } + /*Write the size of our new collection from size-info to the end*/ size_to_register += sizeof_bbox(&ts,n_dims) + bytebuffer_getlength(ts.geom_buf); bytebuffer_append_uvarint(ts.header_buf, size_to_register); @@ -166,7 +229,18 @@ uint8_t* twkb_to_twkbcoll(uint8_t **twkb, size_t *sizes,size_t *out_size, int64_ twkb_out = ts.header_buf->buf_start; - lwfree(ts.header_buf); + lwfree(ts.header_buf); return twkb_out; } +/** +* A function to collect many twkb-buffers into one collection +*/ +uint8_t* twkb_to_twkbcoll(uint8_t **twkb, size_t *sizes,size_t *out_size, int64_t *idlist, int n) +{ + LWDEBUG(2,"Entering twkb_to_twkbcoll"); + + twkb_collection_data ts_data = twkb_get_bboxes(twkb, sizes, n); + + return twkb_write_new_buffer(ts_data,twkb, sizes, out_size, idlist, n); +}