]> granicus.if.org Git - postgis/commitdiff
Fix handling of different ingoing precision in collectTWKB and more
authorNicklas Avén <nicklas.aven@jordogskog.no>
Tue, 30 Jun 2015 22:30:25 +0000 (22:30 +0000)
committerNicklas Avén <nicklas.aven@jordogskog.no>
Tue, 30 Jun 2015 22:30:25 +0000 (22:30 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@13771 b70326c6-7e19-0410-871a-916f4a2858ee

liblwgeom/lwin_twkb.c
liblwgeom/lwin_twkb.h [new file with mode: 0644]
liblwgeom/twkb_tools.c

index d79e6748a0a4bb58d9453967214e030511382d05..309a835f76585e6a37bdd21d53a2ee56a4c08aff 100644 (file)
@@ -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 <math.h>
-#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 (file)
index 0000000..3557504
--- /dev/null
@@ -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 <math.h>
+#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);
index 33fa5fe1d6edf4959782c17911b29d2ef6e28410..aa6a22f5adb44ef7e815c33cf99601802a4e30d9 100644 (file)
 #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<n;i++)
        {               
-               LWDEBUGF(2,"Read header of buffer %d",i);
-               cursor = 0;             
-               buf = twkb[i];
-               buf_size=sizes[i];
-               size_to_register+=buf_size;
+               LWDEBUGF(2,"Read header of buffer %d",i);               
+                       
+               /* Zero out the state */
+               memset(&s, 0, sizeof(twkb_parse_state));        
+               /* Initialize the state appropriately */
+               s.twkb = s.pos = twkb[i];
+               s.twkb_end = twkb[i] + sizes[i];
+               header_from_twkb_state(&s);
                
-               /*jump over type byte*/
-               cursor++;               
-               metabyte = *(buf+cursor);
-               cursor++;
-
-               has_bbox   =  metabyte & 0x01;
-               has_size   = (metabyte & 0x02) >> 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<res.min_factor)
+                       res.min_factor=s.factor;                
+               
+               /* X */
+               min = twkb_parse_state_double(&s, s.factor);
+               if(min < bbox.xmin)
+                       bbox.xmin=min;
+               max = min + twkb_parse_state_double(&s, s.factor);
+               if(max > 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<res.min_factor_z)
+                               res.min_factor_z=s.factor_z;
+                       res.has_z= 1;
+                       min = twkb_parse_state_double(&s, s.factor_z);
+                       if(min < bbox.zmin)
+                               bbox.zmin=min;
+                       max = min + twkb_parse_state_double(&s, s.factor_z);
+                       if(max > 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;b<n_dims;b++)
+               /* M */
+               if ( s.has_m )
                {
-                       min = varint_s64_decode(buf+cursor, buf+buf_size, &size);
-                       cursor+=size;
-                       if(min<ts.bbox_min[b])
-                               ts.bbox_min[b]=min;
-                       max = min + varint_s64_decode(buf+cursor, buf+buf_size, &size);
-                       cursor+=size;                                   
-                       if(max>ts.bbox_max[b])
-                               ts.bbox_max[b]=max;                     
-               }                       
+                       if(s.factor_m<res.min_factor_m)
+                               res.min_factor_m=s.factor_m;
+                       res.has_m= 1;
+                       min = twkb_parse_state_double(&s, s.factor_m);
+                       if(min < bbox.mmin)
+                               bbox.mmin=min;
+                       max = min + twkb_parse_state_double(&s, s.factor_m);
+                       if(max > 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);
+}