]> granicus.if.org Git - postgis/commitdiff
Initial commit of TWKB implimentation to trunk
authorNicklas Avén <nicklas.aven@jordogskog.no>
Sun, 4 Aug 2013 21:27:27 +0000 (21:27 +0000)
committerNicklas Avén <nicklas.aven@jordogskog.no>
Sun, 4 Aug 2013 21:27:27 +0000 (21:27 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@11736 b70326c6-7e19-0410-871a-916f4a2858ee

doc/reference_output.xml
liblwgeom/Makefile.in
liblwgeom/liblwgeom.h.in
liblwgeom/lwout_twkb.c [new file with mode: 0644]
liblwgeom/lwout_twkb.h [new file with mode: 0644]
libpgcommon/lwgeom_pg.h
postgis/lwgeom_accum.c
postgis/lwgeom_inout.c
postgis/postgis.sql.in

index 182344e042d660d0c609322e3c2bf6c55c4bba5e..c5dd74c977d26956ca79293e2ac3794d09d51441 100644 (file)
@@ -1148,4 +1148,103 @@ SELECT (ST_AsLatLonText('POINT (-302.2342342 -792.32498)'));
                  <!-- Optionally add a "See Also" section -->
        </refentry>
 
+       <refentry id="ST_AsTWKB">
+                 <refnamediv>
+                       <refname>ST_AsTWKB</refname>
+                       <refpurpose>Returns the geometry as TWKB, Tiny WKB</refpurpose>
+                 </refnamediv>
+
+                 <refsynopsisdiv>
+                       <funcsynopsis>
+                         <funcprototype>
+                               <funcdef>bytea <function>ST_AsTWKB</function></funcdef>
+                               <paramdef><type>geometry </type> <parameter>g1</parameter></paramdef>
+                               <paramdef><type>integer </type> <parameter>decimaldigits</parameter></paramdef>
+                               <paramdef><type>integer </type> <parameter>geometryID</parameter></paramdef>
+                               <paramdef><type>text </type> <parameter>NDR_or_XDR</parameter></paramdef>
+                         </funcprototype>
+                       </funcsynopsis>
+                 </refsynopsisdiv>
+
+                 <refsection>
+                       <title>Description</title>
+
+                       <para>Returns the geometry in TWKB format. TWKB is a new compressed binary format. </para>
+
+                       <note>
+                         <para>TWKB is still a moving target. The format is described <ulink url="https://github.com/nicklasaven/TWKB">here</ulink> , and code for building a client can be found <ulink url="https://github.com/nicklasaven/twkb_web">here</ulink></para>
+                       </note>
+                               
+
+                       <para>Availability: 2.2</para>
+                 </refsection>
+
+
+                 <refsection>
+                       <title>Examples</title>
+<programlisting>
+SELECT ST_AsTWKB('LINESTRING(1 1,5 5)'::geometry,0,1,'NDR');
+                 st_astwkb                  
+--------------------------------------------
+ \x0142010000000200000001000000010000000404
+</programlisting>
+                 </refsection>
+
+                 <refsection>
+                       <title>See Also</title>
+                       <para><xref linkend="ST_AsTWKB_agg" /><xref linkend="ST_AsBinary" />, <xref linkend="ST_AsEWKB" />, <xref linkend="ST_AsEWKT" />, <xref linkend="ST_GeomFromText" /></para>
+                 </refsection>
+       </refentry>
+
+       <refentry id="ST_AsTWKB_agg">
+                 <refnamediv>
+                       <refname>ST_AsTWKB_agg</refname>
+                       <refpurpose>Aggregates the geometries and returns as TWKB</refpurpose>
+                 </refnamediv>
+
+                 <refsynopsisdiv>
+                       <funcsynopsis>
+                         <funcprototype>
+                               <funcdef>bytea <function>ST_AsTWKB_agg</function></funcdef>
+                               <paramdef><type>geometry </type> <parameter>g1</parameter></paramdef>
+                               <paramdef><type>integer </type> <parameter>decimaldigits</parameter></paramdef>
+                               <paramdef><type>integer </type> <parameter>geometryID</parameter></paramdef>
+                               <paramdef><type>text </type> <parameter>NDR_or_XDR</parameter></paramdef>
+                         </funcprototype>
+                       </funcsynopsis>
+                 </refsynopsisdiv>
+
+                 <refsection>
+                       <title>Description</title>
+
+                       <para>Returns the geometry in TWKB format. TWKB is a new compressed binary format. </para>
+                       <para>This is the aggregate version of ST_AsTWKB. It aggregates and returns the geoemtry in TWKB-format. In the resulting TWKB-geometry each individual ID of the input geometries is stored. </para>
+
+                       <note>
+                         <para>TWKB is still a moving target. The format is described <ulink url="https://github.com/nicklasaven/TWKB">here</ulink> , and code for building a client can be found <ulink url="https://github.com/nicklasaven/twkb_web">here</ulink></para>
+                       </note>
+                               
+
+                       <para>Availability: 2.2</para>
+                 </refsection>
+
+
+                 <refsection>
+                       <title>Examples</title>
+<programlisting>
+SELECT ST_AsTWKB_agg(geom,0,id,'NDR') FROM
+(SELECT 'LINESTRING(1 1,5 5)'::geometry geom, 1 AS id
+UNION ALL
+SELECT 'LINESTRING(6 5, 1 7)'::geometry AS geom, 2 AS id;
+                               st_astwkb_agg                                
+----------------------------------------------------------------------------
+ \x01560200000001000000020000000100000001000000040402000000020000000100fb02
+</programlisting>
+</refsection>
+                 <!-- Optionally add a "See Also" section -->
+                 <refsection>
+                       <title>See Also</title>
+                       <para><xref linkend="ST_AsTWKB" /><xref linkend="ST_AsBinary" />, <xref linkend="ST_AsEWKB" />, <xref linkend="ST_AsEWKT" />, <xref linkend="ST_GeomFromText" /></para>
+                 </refsection>
+</refentry>
   </sect1>
index 3cc6256fdadca4277fb2f3b4c95c7c181bbc4c36..6f560259012ef8b2d358c0a95892b1bc0ff381ae 100644 (file)
@@ -60,6 +60,7 @@ SA_OBJS = \
        lwin_geojson.o \
        lwin_wkb.o \
        lwout_wkt.o \
+       lwout_twkb.o \
        lwin_wkt_parse.o \
        lwin_wkt_lex.o \
        lwin_wkt.o \
index 3fb60eebecfa3f77a23b928932aaa25965a1c334..688e7830c33fdbb2bf48c4ef537a70f08757f669 100644 (file)
@@ -544,6 +544,27 @@ typedef struct
 }
 LWTIN;
 
+
+typedef struct
+{
+       int id; //Id, from function parameter
+       LWGEOM* geom;   //the geometry from function parameter
+}
+lwgeom_id;
+
+typedef struct
+{
+       lwgeom_id* points;
+       int n_points;
+       lwgeom_id* linestrings;
+       int n_linestrings;
+       lwgeom_id* polygons;
+       int n_polygons;
+       lwgeom_id* collections;
+       int n_collections;
+}
+twkb_geom_arrays;
+
 /* Casts LWGEOM->LW* (return NULL if cast is illegal) */
 extern LWMPOLY *lwgeom_as_lwmpoly(const LWGEOM *lwgeom);
 extern LWMLINE *lwgeom_as_lwmline(const LWGEOM *lwgeom);
@@ -1772,6 +1793,9 @@ extern char*   lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision,
 */
 extern uint8_t*  lwgeom_to_wkb(const LWGEOM *geom, uint8_t variant, size_t *size_out);
 
+extern uint8_t* lwgeom_to_twkb(const LWGEOM *geom, uint8_t variant, size_t *size_out,int8_t prec, uint32_t id,int method);
+extern uint8_t* lwgeom_agg_to_twkb(const twkb_geom_arrays *lwgeom_arrays,uint8_t variant , size_t *size_out,int8_t prec, int method);
+
 /**
 * @param lwgeom geometry to convert to HEXWKB
 * @param variant output format to use
diff --git a/liblwgeom/lwout_twkb.c b/liblwgeom/lwout_twkb.c
new file mode 100644 (file)
index 0000000..f10df76
--- /dev/null
@@ -0,0 +1,1170 @@
+/**********************************************************************
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ *
+ * Copyright (C) 2013 Nicklas Avén
+ *
+ * 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 "lwout_twkb.h"
+
+
+/*
+* GeometryType
+*/
+static uint8_t lwgeom_twkb_type(const LWGEOM *geom, uint8_t variant)
+{
+       uint8_t wkb_type = 0;
+       uint8_t type_flag = 0;
+       int dims;
+       
+       switch ( geom->type )
+       {
+       case POINTTYPE:
+               wkb_type = WKB_POINT_TYPE;
+               break;
+       case LINETYPE:
+               wkb_type = WKB_LINESTRING_TYPE;
+               break;
+       case POLYGONTYPE:
+               wkb_type = WKB_POLYGON_TYPE;
+               break;
+       case MULTIPOINTTYPE:
+               wkb_type = WKB_MULTIPOINT_TYPE;
+               break;
+       case MULTILINETYPE:
+               wkb_type = WKB_MULTILINESTRING_TYPE;
+               break;
+       case MULTIPOLYGONTYPE:
+               wkb_type = WKB_MULTIPOLYGON_TYPE;
+               break;
+       case COLLECTIONTYPE:
+               wkb_type = WKB_GEOMETRYCOLLECTION_TYPE;
+               break;
+       case CIRCSTRINGTYPE:
+               wkb_type = WKB_CIRCULARSTRING_TYPE;
+               break;
+       case COMPOUNDTYPE:
+               wkb_type = WKB_COMPOUNDCURVE_TYPE;
+               break;
+       case CURVEPOLYTYPE:
+               wkb_type = WKB_CURVEPOLYGON_TYPE;
+               break;
+       case MULTICURVETYPE:
+               wkb_type = WKB_MULTICURVE_TYPE;
+               break;
+       case MULTISURFACETYPE:
+               wkb_type = WKB_MULTISURFACE_TYPE;
+               break;
+       case POLYHEDRALSURFACETYPE:
+               wkb_type = WKB_POLYHEDRALSURFACE_TYPE;
+               break;
+       case TINTYPE:
+               wkb_type = WKB_TIN_TYPE;
+               break;
+       case TRIANGLETYPE:
+               wkb_type = WKB_TRIANGLE_TYPE;
+               break;
+       default:
+               lwerror("Unsupported geometry type: %s [%d]",
+                       lwtype_name(geom->type), geom->type);
+       }
+
+       /*Set the type*/
+       TYPE_DIM_SET_TYPE(type_flag,wkb_type);  
+       LWDEBUGF(4, "Writing type '%d'", wkb_type);
+       
+       /*Set number of dimensions*/
+       dims = FLAGS_NDIMS(geom->flags);
+       if (dims>4)
+               lwerror("TWKB only supports 4 dimensions");     
+       TYPE_DIM_SET_DIM(type_flag,dims);       
+       LWDEBUGF(4, "Writing ndims '%d'", dims);
+       
+       return type_flag;
+}
+
+/*
+* SwapBytes?
+*/
+static inline int wkb_swap_bytes(uint8_t variant)
+{
+       /* If requested variant matches machine arch, we don't have to swap! */
+       if ( ((variant & WKB_NDR) && (getMachineEndian() == NDR)) ||
+            ((! (variant & WKB_NDR)) && (getMachineEndian() == XDR)) )
+       {
+               return LW_FALSE;
+       }
+       return LW_TRUE;
+}
+
+/*
+* Integer32
+*/
+static uint8_t* int32_to_twkb_buf(const int ival, uint8_t *buf, uint8_t variant)
+{
+       char *iptr = (char*)(&ival);
+       int i = 0;
+
+       if ( sizeof(int) != WKB_INT_SIZE )
+       {
+               lwerror("Machine int size is not %d bytes!", WKB_INT_SIZE);
+       }
+       LWDEBUGF(4, "Writing value '%u'", ival);
+
+               /* Machine/request arch mismatch, so flip byte order */
+               if ( wkb_swap_bytes(variant) )
+               {
+                       for ( i = 0; i < WKB_INT_SIZE; i++ )
+                       {
+                               buf[i] = iptr[WKB_INT_SIZE - 1 - i];
+                       }
+               }
+               /* If machine arch and requested arch match, don't flip byte order */
+               else
+               {
+                       memcpy(buf, iptr, WKB_INT_SIZE);
+               }
+               return buf + WKB_INT_SIZE;      
+}
+
+/*
+* Byte
+*/
+static uint8_t* uint8_to_twkb_buf(const uint8_t ival, uint8_t *buf)
+{
+               memcpy(buf, &ival, WKB_BYTE_SIZE);
+               return buf + 1;
+}
+
+/*
+* All sizes of integers
+* This is for copying the different storaze sizes of the coordinates to the buffer.
+*/
+static uint8_t* to_twkb_buf(uint8_t *iptr, uint8_t *buf, uint8_t variant, int the_size)
+{
+       int i = 0;
+
+       /* Machine/request arch mismatch, so flip byte order */
+       if ( wkb_swap_bytes(variant)&&the_size>1 )
+       {
+               for ( i = 0; i < the_size; i++ )
+               {
+                       buf[i] = iptr[the_size - 1 - i];
+               }
+       }
+       /* If machine arch and requested arch match, don't flip byte order */
+       else
+       {
+               memcpy(buf, iptr, the_size);
+       }
+       return buf + the_size;
+}
+
+/*
+* Empty
+*/
+static size_t empty_to_twkb_size(const LWGEOM *geom, uint8_t variant)
+{
+
+       /* Endian flag/precision + id + type number + npoints*/
+       size_t size = WKB_BYTE_SIZE + WKB_INT_SIZE + WKB_BYTE_SIZE + WKB_INT_SIZE;
+
+       return size;
+}
+
+static uint8_t* empty_to_twkb_buf(const LWGEOM *geom, uint8_t *buf, uint8_t variant,int8_t prec, uint32_t id)
+{
+       uint32_t wkb_type = lwgeom_twkb_type(geom, variant);
+       if ( geom->type == POINTTYPE )
+       {
+               /* Change POINT to MULTIPOINT */
+               wkb_type &= ~WKB_POINT_TYPE;     /* clear POINT flag */
+               wkb_type |= WKB_MULTIPOINT_TYPE; /* set MULTIPOINT flag */
+       }
+       uint8_t flag=0;
+       
+       /* Set the endian flag */
+       END_PREC_SET__ENDIANESS(flag, ((variant & WKB_NDR) ? 1 : 0));
+       /* Tell what precision to use*/
+       END_PREC_SET__PRECISION(flag,prec);
+       
+       /*Copy the flag to the buffer*/
+       buf = uint8_to_twkb_buf(flag,buf);
+       
+       /* Set the geometry id */
+       buf = int32_to_twkb_buf(id, buf, variant);      
+       
+       /* Set the geometry type */     
+       buf = uint8_to_twkb_buf(wkb_type,buf);  
+       
+
+       /* Set nrings/npoints/ngeoms to zero */
+       buf = int32_to_twkb_buf(0, buf, variant);
+       return buf;
+}
+
+static size_t ptarray_to_twkb_size(const POINTARRAY *pa, uint8_t variant,int prec,int accum_rel[],int method)
+{
+       switch (method)
+       {
+               case 0:
+               return ptarray_to_twkb_size_m0(pa, variant,prec,accum_rel);
+                       break;
+               /* Unknown method! */
+               default:
+                       lwerror("Unsupported compression method: %d",method );
+       }               
+}
+
+
+
+
+/*
+* POINTARRAY
+*/
+static size_t ptarray_to_twkb_size_m0(const POINTARRAY *pa, uint8_t variant,int prec,int accum_rel[])
+{
+       LWDEBUGF(2, "ptarray_to_twkb_size entered%d",0);
+       int dims = FLAGS_NDIMS(pa->flags);
+       int i, j, r, last_size,factor,test_size,r_test,j_test;
+       double *dbl_ptr;
+       size_t size = 0;        
+       last_size=0;
+       int start=0;
+       
+       /*The variable factor is used to "shift" the double float coordinate to keep enough significant digits, 
+       for demanded precision, when cast to integer*/
+       factor=pow(10,prec);    
+       
+       /*This is a multidimmenstional array keeping trac of the three different storage sizes.
+       It holds number of bytes, max-value and min-value*/
+       static int size_array[3][3] = {{1,INT8_MAX,INT8_MIN},{2,INT16_MAX,INT16_MIN},{4,INT32_MAX,INT32_MIN}};
+       
+       /* Include the npoints size if it's not a POINT type) */
+       if ( ! ( variant & WKB_NO_NPOINTS ) )
+       {
+               LWDEBUGF(2, "We add space for npoints",0);
+               size += WKB_INT_SIZE;
+       }
+       /*if we don't have a ref-point yet*/
+       if(accum_rel[1]==INT32_MIN)
+       {
+               LWDEBUGF(2, "We don't have a ref-point yet so we give space for full coordinates",0);
+               /*Get a pointer to the first point of the point array*/
+               dbl_ptr = (double*)getPoint_internal(pa, 0);
+               
+               /*Register the size of the first point
+               it is 4 bytes per dimmension*/
+               size += dims*WKB_INT_SIZE;
+               
+               LWDEBUGF(2, "Our geom have %d dims",dims);
+               /*Load the accum_rel aray with the first points dimmension*/
+               for ( j = 0; j < dims; j++ )
+               {       
+                       LWDEBUGF(4, "dim nr %d",j);
+                       r = round(factor*dbl_ptr[j]);
+                       LWDEBUGF(4, "found value %d",r);
+                       accum_rel[j]=r;
+                       
+                       if(fabs(factor*dbl_ptr[j])>size_array[2][1])
+                               lwerror("The first coordinate exceeds the max_value (%d):%f",size_array[2][1],factor*dbl_ptr[j]);
+                       
+               }       
+               start=1;
+       }
+
+       LWDEBUGF(2, "We have %d points to iterate ",pa->npoints);
+       for ( i = start; i < pa->npoints; i++ )
+       {
+               dbl_ptr = (double*)getPoint_internal(pa, i);
+               for ( j = 0; j < dims; j++ )
+               {
+                       /*To get the relative coordinate we don't get teh distance from the last point
+                       but instead the distance from our accumulated last point
+                       This is important to not build up a accumulated error when rounding the coordinates*/
+                       r=round(factor*dbl_ptr[j]-accum_rel[j]);
+                       
+                       
+                       /*last used size is too small so we have to increase*/
+                       if(fabs(r)>size_array[last_size][1])
+                       {
+                               /*A little ugly, but we sacrify the last possible value fitting into a INT4, just to detect too big values without the need to do the substraction again with a double float instead*/
+                               if(fabs(r)>=size_array[2][1])
+                                       lwerror("The relative coordinate coordinate exceeds the max_value (%d):%d",size_array[2][1],r);
+                               /*minimum value for last used size, used to flag a change in size*/
+                               size +=  size_array[last_size][0];
+                               
+                               /*Find how much space we actually need */
+                               while ( fabs(r)>size_array[(++last_size)][1] && last_size<3) {}
+                               
+                               /*register the one byte needed to tell what size we need*/
+                               size ++;        
+                       }
+                       
+                       /*We don't need that much space so let's investigate if we should decrease*/
+                       else if(last_size>0 && fabs(r)<size_array[last_size-1][1])
+                       {
+                               /*We don't care to change to smaller size if we don't see all dimensions 
+                               in a coordinate fits in that size, so we don't even test if it isn't the first dimension*/
+                               if(j==0)
+                               {
+                                       test_size=0;
+                                       /*Here we test if we can decrease the size for all dimmensions*/
+                                       for ( j_test = 0; j_test < dims;j_test++ )
+                                       {
+                                               r_test=round(factor*dbl_ptr[j_test]-accum_rel[j_test]);
+                                               while ( fabs(r_test)>size_array[(test_size)][1] && test_size<=last_size) 
+                                                       {
+                                                               LWDEBUGF(4, "testing %d bytes for value %d, dim: %d",size_array[test_size][0],r_test,j_test );
+                                                               test_size++;
+                                                       }
+                                       }
+                                       if(test_size<last_size)
+                                       {               
+                                               /*
+                                               OK, we decide to actually do the decrease in size
+                                               minimum value for last used size, to flag a change in size*/
+                                               size +=  size_array[last_size][0];
+                                               
+                                               /*We decrease to the biggest size needed for all dimmensions in the point*/
+                                               last_size=test_size;                                            
+                                               
+                                               /*register the one byte needed to tell what size we need*/
+                                               size++;
+                                       }
+                               }
+                                                                       
+                       }
+                       accum_rel[j]+=r;
+                       //add the size of the coordinate
+                       size +=  size_array[last_size][0];
+               }
+       }
+       return size;
+}
+
+static uint8_t* ptarray_to_twkb_buf(const POINTARRAY *pa, uint8_t *buf, uint8_t variant,int8_t prec,int accum_rel[],int method)
+{
+       switch (method)
+       {
+               case 0:
+                       buf = ptarray_to_twkb_buf_m0(pa, buf, variant,prec,accum_rel);
+               return buf;
+               break;
+               /* Unknown method! */
+               default:
+                       lwerror("Unsupported compression method: %d",method );
+       }               
+}
+static uint8_t* ptarray_to_twkb_buf_m0(const POINTARRAY *pa, uint8_t *buf, uint8_t variant,int8_t prec,int accum_rel[])
+{
+       int dims = FLAGS_NDIMS(pa->flags);
+       int i, j, r, last_size,factor,test_size,r_test,j_test;
+       double *dbl_ptr;
+       factor=pow(10,prec);
+       last_size=0;
+       int start=0;
+       /*This is a multidimmenstional array keeping trac of the three different storage sizes.
+       It holds number of bytes, max-value and min-value*/
+       static int size_array[3][3] = {{1,INT8_MAX,INT8_MIN},{2,INT16_MAX,INT16_MIN},{4,INT32_MAX,INT32_MIN}};
+               
+       /* Set the number of points (if it's not a POINT type) */
+       if ( ! ( variant & WKB_NO_NPOINTS ) )
+       {
+               buf = int32_to_twkb_buf(pa->npoints, buf, variant);
+               LWDEBUGF(4, "Regiter npoints:%d",pa->npoints);  
+       }
+
+       /*if we don't have a ref-point yet*/
+       if(accum_rel[0]==INT32_MIN)
+       {       
+               /*Get a pointer do the first point of the point array*/
+               dbl_ptr = (double*)getPoint_internal(pa, 0);
+               
+               /*the first coordinate for each dimension is copied to the buffer
+               and registered in accum_rel array*/
+                       for ( j = 0; j < dims; j++ )
+                       {       
+                               r = round(factor*dbl_ptr[j]);
+                               accum_rel[j]=r;
+                               LWDEBUGF(4, "Writing dimension #%d (buf = %p)", j, buf);                                
+                               buf = int32_to_twkb_buf(r, buf, variant);
+                       }
+               start=1;
+       }
+               for ( i = start; i < pa->npoints; i++ )
+               {
+                       LWDEBUGF(4, "Writing point #%d", i);
+                       dbl_ptr = (double*)getPoint_internal(pa, i);
+                       for ( j = 0; j < dims; j++ )
+                       {
+                               /*To get the relative coordinate we don't get the distance from the last point
+                               but instead the distance from our accumulated last point
+                               This is important to not build up a accumulated error when rounding the coordinates*/                           
+                               r=round(factor*dbl_ptr[j]-accum_rel[j]);
+                               //accum_rel[j]+=r;
+                               //LWDEBUGF(4, "delta value for dim %d is %d, real coordiinate is %f and accumulated coordinate is%d", j, r,dbl_ptr[j],accum_rel[j]  );
+                               LWDEBUGF(4, "size:%d,dim: %d deltavalue: %d, coordinate: %f accumulated coordinate %d",last_size, j, r,dbl_ptr[j],accum_rel[j]  );
+                               
+                               
+
+                               /*last used size is too small so we have to increase*/                          
+                               if(fabs(r)>size_array[last_size][1])
+                               {
+                                       
+                               LWDEBUGF(4, "increasing size from %d bytes",size_array[last_size][0]);
+                                       /*minimum value for last used size, used to flag a change in size*/
+                                       buf = to_twkb_buf((uint8_t *) &(size_array[last_size][2]),buf,  variant, size_array[last_size][0]);
+                                       
+                                       /*Find how much space we actually need */
+                                       while ( fabs(r)>size_array[(++last_size)][1] && last_size<3) {}
+                                       LWDEBUGF(4, "to size %d bytes",size_array[last_size][0]);
+                                               
+                                       /*register needed space*/
+                                       memcpy( buf, &(size_array[last_size][0]), 1);
+                                       buf++;
+                               }                               
+                               /*We don't need that much space so let's investigate if we should decrease
+                               But if it is just a horizontal or vertical line, one dimmension will have short steps but another will still need bigger steps
+                               So, to avoid size changes up and down for every point we don't decrease size if it is not possible for all dimmensions
+                               We could here look even further forward to find out what is most optimal, but that will cost in computing instead*/
+                               else if (last_size>0 && fabs(r)<size_array[last_size-1][1])
+                               {
+                                       /*We don't care to change to smaller size if we don't see all dimensions 
+                                       in a coordinate fits in that size, so we don't even test if it isn't the first dimension*/
+                                       if(j==0)
+                                       {
+                                               test_size=0;
+                                               /*Here we test if we can decrease the size for all dimmensions*/
+                                               for ( j_test = 0; j_test < dims;j_test++ )
+                                               {
+                                                       r_test=round(factor*dbl_ptr[j_test]-accum_rel[j_test]);
+                                                       LWDEBUGF(4, "r_test = %d against size %d ; %d",r_test, test_size,size_array[(test_size)][1]  ); 
+                                                       while ( fabs(r_test)>size_array[(test_size)][1] && test_size<=last_size) 
+                                                               {
+                                                                       LWDEBUGF(4, "testing %d bytes for value %d, dim: %d",size_array[test_size][0],r_test,j_test );
+                                                                       test_size++;
+                                                               }
+                                               }
+                                               if(test_size<last_size)
+                                               {
+                                                       /*
+                                                       OK, we decide to actually do the decrease in size
+                                                       minimum value for last used size, to flag a change in size*/                                    
+                                                       buf = to_twkb_buf((uint8_t *) &(size_array[last_size][2]), buf,variant, size_array[last_size][0]);
+                                                                                                               
+                                                       LWDEBUGF(4, "decreasing size from %d bytes",size_array[last_size][0]);  
+                                                       
+                                                       /*We decrease to the biggest size needed for all dimmensions in the point*/
+                                                       last_size=test_size;                                                                    
+                                                       LWDEBUGF(4, "to size %d bytes",size_array[last_size][0]);
+                                                       
+                                                       /*register how many bytes we need*/
+                                                       memcpy( buf, &(size_array[last_size][0]), 1);
+                                                       buf++;
+                                               }
+                                       }                                                                               
+                               }                       
+                               accum_rel[j]+=r;
+                               //add the actual coordinate
+                               buf = to_twkb_buf((uint8_t *) &r,buf, variant, size_array[last_size][0]);
+                       }
+               }       
+       //LWDEBUGF(4, "Done (buf = %p)", buf);
+       return buf;
+}
+
+
+
+static size_t  lwgeom_agg_to_twkbpoint_size(lwgeom_id *geom_array,uint8_t variant,int n,int8_t prec,int refpoint[],int method)
+{
+       /*One byte for type declaration*/
+       size_t size = WKB_BYTE_SIZE;
+       /*One integer holding number of points*/
+       size += WKB_INT_SIZE;
+
+       int i;
+       LWPOINT *p;
+       for (i=0;i<n;i++)
+       {
+               p=(LWPOINT *) ((geom_array+i)->geom);
+               size += lwpoint_to_twkb_size(p,variant,prec,refpoint,method);
+       }
+       return size;
+}
+/*
+* POINT
+*/
+static size_t lwpoint_to_twkb_size(const LWPOINT *pt,uint8_t variant, int8_t prec,int refpoint[],int method)
+{
+       size_t size = 0;
+       /* geometry id, if not subgeometry in type 4,5 or 6*/
+       if (!(variant & WKB_NO_ID))
+       size     += WKB_INT_SIZE;
+
+       /* Points */
+       size += ptarray_to_twkb_size(pt->point, variant | WKB_NO_NPOINTS, prec,refpoint,method);
+       return size;
+}
+
+
+static uint8_t* lwgeom_agg_to_twkbpoint_buf(lwgeom_id* geom_array,int n, uint8_t *buf, uint8_t variant,int8_t prec, int refpoint[],int method)
+{
+
+       lwgeom_id *li;
+       uint8_t type_flag = 0;
+       int i,dims;
+       /*Set the type*/
+       TYPE_DIM_SET_TYPE(type_flag,21);        
+       LWDEBUGF(4, "Writing type '%d'", 21);
+       
+       /*Set number of dimensions*/
+       dims = FLAGS_NDIMS(((LWGEOM*) (geom_array->geom))->flags);
+       if (dims>4)
+               lwerror("TWKB only supports 4 dimensions");     
+       TYPE_DIM_SET_DIM(type_flag,dims);       
+       LWDEBUGF(4, "Writing ndims '%d'", dims);
+       buf = uint8_to_twkb_buf(type_flag,buf);
+       
+       /* Set number of geometries */
+       buf = int32_to_twkb_buf(n, buf, variant);
+
+       
+       for (i=0;i<n;i++)
+       {
+               li=(geom_array+i);
+               buf = lwpoint_to_twkb_buf((LWPOINT*) (li->geom),buf,variant,prec,li->id,refpoint,method);
+       }
+       return buf;
+}
+
+static uint8_t* lwpoint_to_twkb_buf(const LWPOINT *pt, uint8_t *buf, uint8_t variant,int8_t prec, uint32_t id,int refpoint[],int method)
+{
+
+       
+       /* Set the geometry id, if not subgeometry in type 4,5 or 6*/
+       if (!(variant & WKB_NO_ID))
+               buf = int32_to_twkb_buf(id, buf, variant);      
+       
+               
+       /* Set the coordinates */
+       buf = ptarray_to_twkb_buf(pt->point, buf, variant | WKB_NO_NPOINTS,prec,refpoint,method);
+       LWDEBUGF(4, "Pointarray set, buf = %p", buf);
+       return buf;
+}
+
+static size_t  lwgeom_agg_to_twkbline_size(lwgeom_id* geom_array,uint8_t variant,int n,int8_t prec,int refpoint[],int method)
+{
+       /*One byte for type declaration*/
+       size_t size = WKB_BYTE_SIZE;
+       /*One integer holding number of collections*/
+       size += WKB_INT_SIZE;
+       int i;
+       for (i=0;i<n;i++)
+       {
+               size += lwline_to_twkb_size((LWLINE*)((geom_array+i)->geom),variant,prec,refpoint,method);
+       }
+       return size;
+}
+/*
+* LINESTRING, CIRCULARSTRING
+*/
+static size_t lwline_to_twkb_size(const LWLINE *line,uint8_t variant, int8_t prec,int refpoint[],int method)
+{      
+       size_t size = 0;
+       /* geometry id, if not subgeometry in type 4,5 or 6*/
+       if (!(variant & WKB_NO_ID))
+       size     += WKB_INT_SIZE;
+
+       /* Size of point array */
+       size += ptarray_to_twkb_size(line->points,variant,prec,refpoint,method);
+       return size;
+}
+
+static uint8_t* lwgeom_agg_to_twkbline_buf(lwgeom_id* geom_array,int n, uint8_t *buf, uint8_t variant,int8_t prec, int refpoint[],int method)
+{
+
+       lwgeom_id *li;
+       uint8_t type_flag = 0;
+       int i,dims;
+       /*Set the type*/
+       TYPE_DIM_SET_TYPE(type_flag,22);        
+       LWDEBUGF(4, "Writing type '%d'",22);
+       
+       /*Set number of dimensions*/
+       dims = FLAGS_NDIMS(((LWGEOM*) (geom_array->geom))->flags);
+       if (dims>4)
+               lwerror("TWKB only supports 4 dimensions");     
+       TYPE_DIM_SET_DIM(type_flag,dims);       
+       LWDEBUGF(4, "Writing ndims '%d'", dims);
+       buf = uint8_to_twkb_buf(type_flag,buf);
+       
+       /* Set number of geometries */
+       buf = int32_to_twkb_buf(n, buf, variant);
+       
+       for (i=0;i<n;i++)
+       {
+               li=(geom_array+i);
+               buf = lwline_to_twkb_buf((LWLINE*) li->geom,buf,variant,prec,li->id,refpoint,method);
+       }
+       return buf;
+}
+
+
+static uint8_t* lwline_to_twkb_buf(const LWLINE *line, uint8_t *buf, uint8_t variant,int8_t prec, uint32_t id,int refpoint[],int method)
+{
+
+       /* Set the geometry id, if not subgeometry in type 4,5 or 6*/
+       if (!(variant & WKB_NO_ID))
+               buf = int32_to_twkb_buf(id, buf, variant);                      
+       
+       
+       /* Set the coordinates */
+       buf = ptarray_to_twkb_buf(line->points, buf, variant,prec,refpoint,method);
+       return buf;
+}
+
+
+static size_t  lwgeom_agg_to_twkbpoly_size(lwgeom_id* geom_array,uint8_t variant,int n,int8_t prec,int refpoint[],int method)
+{
+       /*One byte for type declaration*/
+       size_t size = WKB_BYTE_SIZE;
+       /*One integer holding number of collections*/
+       size += WKB_INT_SIZE;
+       int i;
+       for (i=0;i<n;i++)
+       {
+               size += lwpoly_to_twkb_size((LWPOLY*)((geom_array+i)->geom),variant,prec,refpoint,method);
+       }
+       return size;
+}
+/*
+* POLYGON
+*/
+static size_t lwpoly_to_twkb_size(const LWPOLY *poly,uint8_t variant, int8_t prec,int refpoint[],int method)
+{
+       LWDEBUGF(2, "lwpoly_to_twkb_size entered%d",0);
+       int i;  
+       
+       size_t size = 0;
+       /* geometry id, if not subgeometry in type 4,5 or 6*/
+       if (!(variant & WKB_NO_ID))
+               size     += WKB_INT_SIZE;
+       
+       /*nrings*/
+       size += WKB_INT_SIZE;
+       
+       LWDEBUGF(2, "we have %d rings to iterate",poly->nrings);
+       for ( i = 0; i < poly->nrings; i++ )
+       {
+               /* Size of ring point array */
+               size += ptarray_to_twkb_size(poly->rings[i],variant,prec,refpoint,method);
+       }
+
+       return size;
+}
+
+static uint8_t* lwgeom_agg_to_twkbpoly_buf(lwgeom_id* geom_array,int n, uint8_t *buf, uint8_t variant,int8_t prec, int refpoint[],int method)
+{
+
+       lwgeom_id *li;
+       uint8_t type_flag = 0;
+       int i,dims;
+       /*Set the type*/
+       TYPE_DIM_SET_TYPE(type_flag,23);        
+       LWDEBUGF(4, "Writing type '%d'", 23);
+       
+       /*Set number of dimensions*/
+       dims = FLAGS_NDIMS(((LWGEOM*) (geom_array->geom))->flags);
+       if (dims>4)
+               lwerror("TWKB only supports 4 dimensions");     
+       TYPE_DIM_SET_DIM(type_flag,dims);       
+       LWDEBUGF(4, "Writing ndims '%d'", dims);
+       buf = uint8_to_twkb_buf(type_flag,buf);
+       /* Set number of geometries */
+       buf = int32_to_twkb_buf(n, buf, variant);
+       
+       for (i=0;i<n;i++)
+       {
+               li=(geom_array+i);
+               buf = lwpoly_to_twkb_buf((LWPOLY*) (li->geom),buf,variant,prec,li->id,refpoint,method);
+       }
+       return buf;
+}
+
+static uint8_t* lwpoly_to_twkb_buf(const LWPOLY *poly, uint8_t *buf, uint8_t variant,int8_t prec, uint32_t id,int refpoint[],int method)
+{
+       int i;
+       
+       /* Set the geometry id, if not subgeometry in type 4,5 or 6*/
+       if (!(variant & WKB_NO_ID))
+               buf = int32_to_twkb_buf(id, buf, variant);              
+
+       /* Set the number of rings */
+       buf = int32_to_twkb_buf(poly->nrings, buf, variant);
+
+       for ( i = 0; i < poly->nrings; i++ )
+       {
+               buf = ptarray_to_twkb_buf(poly->rings[i], buf, variant,prec,refpoint,method);
+       }
+
+       return buf;
+}
+
+
+static size_t  lwgeom_agg_to_twkbcollection_size(lwgeom_id* geom_array,uint8_t variant,int n,int8_t prec,int refpoint[],int method)
+{
+       LWDEBUGF(4, "lwgeom_agg_to_twkbcollection_size entered with %d collections",n);
+       /*One byte for type declaration*/
+       size_t size = WKB_BYTE_SIZE;
+       /*One integer holding number of collections*/
+       size += WKB_INT_SIZE;
+       int i;
+       for (i=0;i<n;i++)
+       {
+               size += lwcollection_to_twkb_size((LWCOLLECTION*)((geom_array+i)->geom),variant,prec,refpoint,method);
+       }
+       return size;
+}
+/*
+* MULTIPOINT, MULTILINESTRING, MULTIPOLYGON, GEOMETRYCOLLECTION
+* MULTICURVE, COMPOUNDCURVE, MULTISURFACE, CURVEPOLYGON, TIN, 
+* POLYHEDRALSURFACE
+*/
+static size_t lwcollection_to_twkb_size(const LWCOLLECTION *col,uint8_t variant, int8_t prec,int refpoint[],int method)
+{
+       LWDEBUGF(2, "lwcollection_to_twkb_size entered, %d",0);
+       /* id*/
+       size_t size = WKB_INT_SIZE;
+       /* size of geoms */
+       size += WKB_INT_SIZE; 
+       int i = 0;
+
+       for ( i = 0; i < col->ngeoms; i++ )
+       {
+               /* size of subgeom */
+               size += lwgeom_to_twkb_size((LWGEOM*)col->geoms[i],variant | WKB_NO_ID, prec,refpoint,method);
+       }
+
+       return size;
+}
+
+static uint8_t* lwgeom_agg_to_twkbcollection_buf(lwgeom_id* geom_array,int n, uint8_t *buf, uint8_t variant,int8_t prec, int refpoint[],int method)
+{
+
+       lwgeom_id *li;
+       uint8_t type_flag = 0;
+       int i,dims;
+       /*Set the type*/
+       TYPE_DIM_SET_TYPE(type_flag,24);        
+       LWDEBUGF(4, "Writing type '%d'", 24);
+       
+       /*Set number of dimensions*/
+       dims = FLAGS_NDIMS(((LWGEOM*) (geom_array->geom))->flags);
+       if (dims>4)
+               lwerror("TWKB only supports 4 dimensions");     
+       TYPE_DIM_SET_DIM(type_flag,dims);       
+       LWDEBUGF(4, "Writing ndims '%d'", dims);
+       buf = uint8_to_twkb_buf(type_flag,buf);
+       /* Set number of geometries */
+       buf = int32_to_twkb_buf(n, buf, variant);
+       
+       for (i=0;i<n;i++)
+       {
+               li=(geom_array+i);
+               buf = lwcollection_to_twkb_buf((LWCOLLECTION*) li->geom,buf,variant,prec,li->id,refpoint,method);
+       }
+       return buf;
+}
+
+static uint8_t* lwcollection_to_twkb_buf(const LWCOLLECTION *col, uint8_t *buf, uint8_t variant,int8_t prec, uint32_t id,int refpoint[],int method)
+{
+       int i;
+
+       
+       /* Set the geometry id */
+       buf = int32_to_twkb_buf(id, buf, variant);      
+
+       /* Set the number of rings */
+       buf = int32_to_twkb_buf(col->ngeoms, buf, variant);
+
+       /* Write the sub-geometries. Sub-geometries do not get SRIDs, they
+          inherit from their parents. */
+       for ( i = 0; i < col->ngeoms; i++ )
+       {
+               buf = lwgeom_to_twkb_buf(col->geoms[i], buf, variant | WKB_NO_ID,prec,id,refpoint,method);
+       }
+
+       return buf;
+}
+
+/*
+* GEOMETRY
+*/
+static size_t lwgeom_to_twkb_size(const LWGEOM *geom,uint8_t variant, int8_t prec,int refpoint[],int method)
+{
+       LWDEBUGF(2, "lwgeom_to_twkb_size entered %d",0);
+       size_t size = 0;
+       if ( geom == NULL )
+               return 0;
+
+       /* Short circuit out empty geometries */
+       if ( lwgeom_is_empty(geom) )
+       {
+               return empty_to_twkb_size(geom, variant);
+       }
+       /*add size of type-declaration*/
+       if (!(variant &  WKB_NO_TYPE))
+               size += WKB_BYTE_SIZE;
+       switch ( geom->type )
+       {
+               case POINTTYPE:
+                       size += lwpoint_to_twkb_size((LWPOINT*)geom, variant, prec,refpoint,method);
+                       break;
+
+               /* LineString and CircularString both have points elements */
+               case CIRCSTRINGTYPE:
+               case LINETYPE:
+                       size += lwline_to_twkb_size((LWLINE*)geom, variant, prec,refpoint,method);
+                       break;
+
+               /* Polygon has nrings and rings elements */
+               case POLYGONTYPE:
+                       size += lwpoly_to_twkb_size((LWPOLY*)geom, variant, prec,refpoint,method);
+                       break;
+
+               /* Triangle has one ring of three points 
+               case TRIANGLETYPE:
+                       size += lwtriangle_to_twkb_size((LWTRIANGLE*)geom, variant);
+                       break;*/
+
+               /* All these Collection types have ngeoms and geoms elements */
+               case MULTIPOINTTYPE:
+               case MULTILINETYPE:
+               case MULTIPOLYGONTYPE:
+                       size += lwcollection_to_twkb_size((LWCOLLECTION*)geom, variant | WKB_NO_TYPE, prec,refpoint,method);
+                       break;
+               case COLLECTIONTYPE:
+                       size += lwcollection_to_twkb_size((LWCOLLECTION*)geom, variant, prec,refpoint,method);
+                       break;
+
+               /* Unknown type! */
+               default:
+                       lwerror("Unsupported geometry type: %s [%d]", lwtype_name(geom->type), geom->type);
+       }
+
+       return size;
+}
+
+/* TODO handle the TRIANGLE type properly */
+
+static uint8_t* lwgeom_to_twkb_buf(const LWGEOM *geom, uint8_t *buf, uint8_t variant,int8_t prec, uint32_t id,int refpoint[],int method)
+{
+
+       if ( lwgeom_is_empty(geom) )
+               return empty_to_twkb_buf(geom, buf, variant,prec,id);
+
+       switch ( geom->type )
+       {
+               case POINTTYPE:
+               {
+                       if (!(variant &  WKB_NO_TYPE))
+                               buf = uint8_to_twkb_buf(lwgeom_twkb_type(geom, variant),buf);
+                       return lwpoint_to_twkb_buf((LWPOINT*)geom, buf, variant,prec,id,refpoint,method);
+               }
+               /* LineString and CircularString both have 'points' elements */
+               case CIRCSTRINGTYPE:
+               case LINETYPE:
+               {
+                       if (!(variant &  WKB_NO_TYPE))
+                               buf = uint8_to_twkb_buf(lwgeom_twkb_type(geom, variant),buf);
+                       return lwline_to_twkb_buf((LWLINE*)geom, buf, variant,prec,id,refpoint,method);
+               }
+               /* Polygon has 'nrings' and 'rings' elements */
+               case POLYGONTYPE:
+               {
+                       if (!(variant &  WKB_NO_TYPE))
+                               buf = uint8_to_twkb_buf(lwgeom_twkb_type(geom, variant),buf);
+                       return lwpoly_to_twkb_buf((LWPOLY*)geom, buf, variant,prec,id,refpoint,method);
+               }
+               /* Triangle has one ring of three points 
+               case TRIANGLETYPE:
+                       return lwtriangle_to_twkb_buf((LWTRIANGLE*)geom, buf, variant);
+*/
+               /* All these Collection types have 'ngeoms' and 'geoms' elements */
+               case MULTIPOINTTYPE:
+               case MULTILINETYPE:
+               case MULTIPOLYGONTYPE:
+               {
+                       buf = uint8_to_twkb_buf(lwgeom_twkb_type(geom, variant),buf);
+                       return lwcollection_to_twkb_buf((LWCOLLECTION*)geom, buf, variant | WKB_NO_TYPE,prec,id,refpoint,method);
+               }                       
+               case COLLECTIONTYPE:
+               {
+                       buf = uint8_to_twkb_buf(lwgeom_twkb_type(geom, variant),buf);
+                       return lwcollection_to_twkb_buf((LWCOLLECTION*)geom, buf, variant,prec,id,refpoint,method);
+               }
+               /* Unknown type! */
+               default:
+                       lwerror("Unsupported geometry type: %s [%d]", lwtype_name(geom->type), geom->type);
+       }
+       /* Return value to keep compiler happy. */
+       return 0;
+}
+
+/**
+* Convert LWGEOM to a char* in TWKB format. Caller is responsible for freeing
+* the returned array.
+*/
+uint8_t* lwgeom_to_twkb(const LWGEOM *geom, uint8_t variant, size_t *size_out,int8_t prec, uint32_t id,int method)
+{
+       size_t buf_size;
+       uint8_t *buf = NULL;
+       uint8_t *wkb_out = NULL;
+       uint8_t flag=0;
+       /*an integer array holding the reference point. In most cases the last used point
+       but in the case of pointcloud it is a user defined refpoint.
+       INT32_MIN indicates that the ref-point is not set yet*/
+       int refpoint[4]= {INT32_MIN,INT32_MIN,INT32_MIN,INT32_MIN};
+       int refpoint2[4]= {INT32_MIN,INT32_MIN,INT32_MIN,INT32_MIN};
+       
+       /* Initialize output size */
+       if ( size_out ) *size_out = 0;
+
+       if ( geom == NULL )
+       {
+               LWDEBUG(4,"Cannot convert NULL into WKB.");
+               lwerror("Cannot convert NULL into WKB.");
+               return NULL;
+       }
+
+       /* Calculate the required size of the output buffer */
+       
+       /*Adding the size for the first byte*/
+       buf_size = 1;
+       buf_size += lwgeom_to_twkb_size(geom,variant,prec,refpoint,method);
+       LWDEBUGF(4, "WKB output size: %d", buf_size);
+
+       if ( buf_size == 0 )
+       {
+               LWDEBUG(4,"Error calculating output WKB buffer size.");
+               lwerror("Error calculating output WKB buffer size.");
+               return NULL;
+       }
+
+       /* If neither or both variants are specified, choose the native order */
+       if ( ! (variant & WKB_NDR || variant & WKB_XDR) ||
+              (variant & WKB_NDR && variant & WKB_XDR) )
+       {
+               if ( getMachineEndian() == NDR ) 
+                       variant = variant | WKB_NDR;
+               else
+                       variant = variant | WKB_XDR;
+       }
+
+       /* Allocate the buffer */
+       buf = lwalloc(buf_size);
+
+       if ( buf == NULL )
+       {
+               LWDEBUGF(4,"Unable to allocate %d bytes for WKB output buffer.", buf_size);
+               lwerror("Unable to allocate %d bytes for WKB output buffer.", buf_size);
+               return NULL;
+       }
+
+       /* Retain a pointer to the front of the buffer for later */
+       wkb_out = buf;          
+       
+       /* Set the endian flag */
+       END_PREC_SET__ENDIANESS(flag, ((variant & WKB_NDR) ? 1 : 0));
+       /* Tell what method to use*/
+       END_PREC_SET__METHOD(flag, method);
+       /* Tell what precision to use*/
+       END_PREC_SET__PRECISION(flag,prec);
+       
+       /*Copy the flag to the buffer*/
+       buf = uint8_to_twkb_buf(flag,buf);
+       
+
+       
+       /* Write the WKB into the output buffer */
+       buf = lwgeom_to_twkb_buf(geom, buf,variant, prec,id,refpoint2,method);
+
+       LWDEBUGF(4,"buf (%p) - wkb_out (%p) = %d", buf, wkb_out, buf - wkb_out);
+
+       /* The buffer pointer should now land at the end of the allocated buffer space. Let's check. */
+       if ( buf_size != (buf - wkb_out) )
+       {
+               LWDEBUG(4,"Output WKB is not the same size as the allocated buffer.");
+               lwerror("Output WKB is not the same size as the allocated buffer.");
+               lwfree(wkb_out);
+               return NULL;
+       }
+
+       /* Report output size */
+       if ( size_out ) *size_out = buf_size;
+
+       return wkb_out;
+}
+
+uint8_t* lwgeom_agg_to_twkb(const twkb_geom_arrays *lwgeom_arrays,uint8_t variant , size_t *size_out,int8_t prec,int method)
+{
+       size_t buf_size;
+       uint8_t *buf = NULL;
+       uint8_t flag = 0;
+       uint8_t *wkb_out = NULL;
+       int chk_homogenity=0;
+       uint8_t type_flag = 0;
+       int dims;
+       /*an integer array holding the reference point. In most cases the last used point
+       but in the case of pointcloud it is a user defined refpoint.
+       INT32_MIN indicates that the ref-point is not set yet*/
+       int refpoint[4]= {INT32_MIN,INT32_MIN,INT32_MIN,INT32_MIN};
+       int refpoint2[4]= {INT32_MIN,INT32_MIN,INT32_MIN,INT32_MIN};
+       
+       LWDEBUGF(4, "We have collected: %d points, %d linestrings, %d polygons and %d collections",lwgeom_arrays->n_points,lwgeom_arrays->n_linestrings,lwgeom_arrays->n_polygons,lwgeom_arrays->n_collections );
+
+       
+       /* Initialize output size */
+       if ( size_out ) *size_out = 0;
+       
+       if (lwgeom_arrays->n_points > 0)
+               chk_homogenity++;
+       if (lwgeom_arrays->n_linestrings > 0)
+               chk_homogenity++;
+       if (lwgeom_arrays->n_polygons > 0)
+               chk_homogenity++        ;
+       if (lwgeom_arrays->n_collections > 0)
+               chk_homogenity++;
+       
+       
+       
+       if(chk_homogenity==0)
+               return NULL;
+       if(chk_homogenity>1)
+               buf_size=6;
+       else
+               buf_size=1;
+       
+       
+       if (lwgeom_arrays->n_points > 0)
+               buf_size += lwgeom_agg_to_twkbpoint_size(lwgeom_arrays->points,variant,lwgeom_arrays->n_points, prec,refpoint,method);
+       if (lwgeom_arrays->n_linestrings > 0)
+               buf_size += lwgeom_agg_to_twkbline_size(lwgeom_arrays->linestrings,variant,lwgeom_arrays->n_linestrings, prec,refpoint,method);
+       if (lwgeom_arrays->n_polygons > 0)
+               buf_size += lwgeom_agg_to_twkbpoly_size(lwgeom_arrays->polygons,variant,lwgeom_arrays->n_polygons, prec,refpoint,method);
+       if (lwgeom_arrays->n_collections > 0)
+               buf_size += lwgeom_agg_to_twkbcollection_size(lwgeom_arrays->collections,variant,lwgeom_arrays->n_collections, prec,refpoint,method);
+       
+       
+       
+       
+       
+               LWDEBUGF(4, "WKB output size: %d", buf_size);
+
+       if ( buf_size == 0 )
+       {
+               LWDEBUG(4,"Error calculating output WKB buffer size.");
+               lwerror("Error calculating output WKB buffer size.");
+               return NULL;
+       }
+
+       /* If neither or both variants are specified, choose the native order */
+       if ( ! (variant & WKB_NDR || variant & WKB_XDR) ||
+              (variant & WKB_NDR && variant & WKB_XDR) )
+       {
+               if ( getMachineEndian() == NDR ) 
+                       variant = variant | WKB_NDR;
+               else
+                       variant = variant | WKB_XDR;
+       }
+
+       /* Allocate the buffer */
+       buf = lwalloc(buf_size);
+
+       if ( buf == NULL )
+       {
+               LWDEBUGF(4,"Unable to allocate %d bytes for WKB output buffer.", buf_size);
+               lwerror("Unable to allocate %d bytes for WKB output buffer.", buf_size);
+               return NULL;
+       }
+
+       /* Retain a pointer to the front of the buffer for later */
+       wkb_out = buf;  
+               
+       
+       /* Set the endian flag */
+       END_PREC_SET__ENDIANESS(flag, ((variant & WKB_NDR) ? 1 : 0));
+       /* Tell what method to use*/
+       END_PREC_SET__METHOD(flag, method);
+       /* Tell what precision to use*/
+       END_PREC_SET__PRECISION(flag,prec);
+       
+       /*Copy the flag to the buffer*/
+       buf = uint8_to_twkb_buf(flag,buf);
+
+       /*set type and number of geometries for the top level, if more than 1 type og underlying geometries*/
+       if(chk_homogenity>1)
+       {
+
+               /*Set the type*/
+               TYPE_DIM_SET_TYPE(type_flag,7); 
+               LWDEBUGF(4, "Writing type '%d'",7);
+               
+               /*We just set this to 4 dimmensions. It doesn't matter since all undelying geometries have their own*/
+               dims = 4;
+               TYPE_DIM_SET_DIM(type_flag,dims);       
+               LWDEBUGF(4, "Writing ndims '%d'", dims);
+               buf = uint8_to_twkb_buf(type_flag,buf);
+               
+               /* Set number of geometries */
+               buf = int32_to_twkb_buf(chk_homogenity, buf, variant);
+       }
+       
+       /* Write the WKB into the output buffer 
+       buf = lwgeom_to_twkb_buf(geom, buf,variant, prec,id,refpoint2);*/
+       
+       if (lwgeom_arrays->n_points > 0)
+               buf =lwgeom_agg_to_twkbpoint_buf(lwgeom_arrays->points,lwgeom_arrays->n_points, buf,variant, prec,refpoint2,method);
+       if (lwgeom_arrays->n_linestrings > 0)
+               buf =lwgeom_agg_to_twkbline_buf(lwgeom_arrays->linestrings,lwgeom_arrays->n_linestrings, buf,variant, prec,refpoint2,method);
+       if (lwgeom_arrays->n_polygons > 0)
+               buf =lwgeom_agg_to_twkbpoly_buf(lwgeom_arrays->polygons,lwgeom_arrays->n_polygons, buf,variant, prec,refpoint2,method);
+       if (lwgeom_arrays->n_collections > 0)
+               buf =lwgeom_agg_to_twkbcollection_buf(lwgeom_arrays->collections,lwgeom_arrays->n_collections, buf,variant, prec,refpoint2,method);
+       
+       
+       
+
+       LWDEBUGF(4,"buf (%p) - wkb_out (%p) = %d", buf, wkb_out, buf - wkb_out);
+
+       /* The buffer pointer should now land at the end of the allocated buffer space. Let's check. */
+       if ( buf_size != (buf - wkb_out) )
+       {
+               LWDEBUG(4,"Output WKB is not the same size as the allocated buffer.");
+               lwerror("Output WKB is not the same size as the allocated buffer.");
+               lwfree(wkb_out);
+               return NULL;
+       }
+
+       /* Report output size */
+       if ( size_out ) *size_out = buf_size;
+
+       return wkb_out;
+       
+}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/liblwgeom/lwout_twkb.h b/liblwgeom/lwout_twkb.h
new file mode 100644 (file)
index 0000000..2c5e3d4
--- /dev/null
@@ -0,0 +1,74 @@
+
+/**********************************************************************
+ * $Id: lwout_twkb.h 4715 2009-11-01 17:58:42Z nicklas $
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ * http://postgis.refractions.net
+ * Copyright 2013 Nicklas Avén
+ *
+ * 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 "liblwgeom_internal.h"
+#include "lwgeom_log.h"
+#include <limits.h>
+
+/**
+* Macros for manipulating the 'endian_precision' int. An int8_t used as follows:
+* Endianess 1 bit
+* 3 unused bits
+* Precision  4 bits
+*/
+
+#define END_PREC_SET__ENDIANESS(flag, endianess) ((flag) = (flag & 0xFE) | ((endianess & 0x01)))
+#define END_PREC_SET__METHOD(flag, method) ((flag) = (flag & 0xF1) | ((prec<<1) & 0x0E))
+#define END_PREC_SET__PRECISION(flag, prec) ((flag) = (flag & 0x0F) | ((prec<<4) & 0xF0))
+
+
+/**
+* Macros for manipulating the 'type_dim' int. An int8_t used as follows:
+* Type 5 bits
+* NDims  3 bits
+*/
+
+#define TYPE_DIM_SET_TYPE(flag, type) ((flag) = (flag & 0xE0) | ((type & 0x1F)))
+#define TYPE_DIM_SET_DIM(flag, dim) ((flag) = (flag & 0x1F) | ((dim & 0x07)<<5))
+
+/*For variant variable that holds options when building the twkb*/
+#define WKB_NO_ID 0x01 /* This position has another meaning when building wkb! */
+#define WKB_NO_TYPE 0x02 /* This position has another meaning when building wkb! */
+
+static size_t ptarray_to_twkb_size(const POINTARRAY *pa, uint8_t variant,int prec,int accum_rel[],int method);
+static uint8_t* ptarray_to_twkb_buf(const POINTARRAY *pa, uint8_t *buf, uint8_t variant,int8_t prec,int accum_rel[],int method);
+
+static size_t ptarray_to_twkb_size_m0(const POINTARRAY *pa, uint8_t variant,int prec,int accum_rel[]);
+static uint8_t* ptarray_to_twkb_buf_m0(const POINTARRAY *pa, uint8_t *buf, uint8_t variant,int8_t prec,int accum_rel[]);
+
+static size_t  lwgeom_agg_to_twkbpoint_size(lwgeom_id *geom_array, uint8_t variant,int n,int8_t prec,int refpoint[],int method);
+static size_t lwpoint_to_twkb_size(const LWPOINT *pt, uint8_t variant, int8_t prec,int refpoint[],int method);
+static uint8_t* lwgeom_agg_to_twkbpoint_buf(lwgeom_id* geom_array,int n, uint8_t *buf, uint8_t variant,int8_t prec, int refpoint[],int method);
+static uint8_t* lwpoint_to_twkb_buf(const LWPOINT *pt, uint8_t *buf, uint8_t variant,int8_t prec, uint32_t id,int refpoint[],int method);
+
+static size_t  lwgeom_agg_to_twkbline_size(lwgeom_id *geom_array, uint8_t variant,int n,int8_t prec,int refpoint[],int method);
+static size_t lwline_to_twkb_size(const LWLINE *line, uint8_t variant, int8_t prec,int refpoint[],int method);
+static uint8_t* lwgeom_agg_to_twkbline_buf(lwgeom_id* geom_array,int n, uint8_t *buf, uint8_t variant,int8_t prec, int refpoint[],int method);
+static uint8_t* lwline_to_twkb_buf(const LWLINE *line, uint8_t *buf, uint8_t variant,int8_t prec, uint32_t id,int refpoint[],int method);
+
+static size_t  lwgeom_agg_to_twkbpoly_size(lwgeom_id *geom_array, uint8_t variant,int n,int8_t prec,int refpoint[],int method);
+static size_t lwpoly_to_twkb_size(const LWPOLY *poly, uint8_t variant,int8_t prec,int refpoint[],int method);
+static uint8_t* lwgeom_agg_to_twkbpoly_buf(lwgeom_id* geom_array,int n, uint8_t *buf, uint8_t variant,int8_t prec, int refpoint[],int method);
+static uint8_t* lwpoly_to_twkb_buf(const LWPOLY *poly, uint8_t *buf, uint8_t variant,int8_t prec, uint32_t id,int refpoint[],int method);
+
+static size_t  lwgeom_agg_to_twkbcollection_size(lwgeom_id *geom_array, uint8_t variant,int n,int8_t prec,int refpoint[],int method);
+static size_t lwcollection_to_twkb_size(const LWCOLLECTION *col, uint8_t variant, int8_t prec,int refpoint[],int method);
+static uint8_t* lwgeom_agg_to_twkbcollection_buf(lwgeom_id* geom_array,int n, uint8_t *buf, uint8_t variant,int8_t prec, int refpoint[],int method);
+static uint8_t* lwcollection_to_twkb_buf(const LWCOLLECTION *col, uint8_t *buf, uint8_t variant,int8_t prec, uint32_t id,int refpoint[],int method);
+
+static size_t lwgeom_to_twkb_size(const LWGEOM *geom, uint8_t variant, int8_t prec,int refpoint[],int method);
+static uint8_t* lwgeom_to_twkb_buf(const LWGEOM *geom, uint8_t *buf, uint8_t variant,int8_t prec, uint32_t id,int refpoint[],int method);
+
+
+//static size_t lwgeom_to_twkb_size(const LWGEOM *geom, uint8_t variant,int8_t prec);
+
index 594bff983d6ad6f1cb66d6de8983cfb330acce36..3d392e84f78ccd11131d6fc837b01071e11d9c18 100644 (file)
@@ -153,6 +153,7 @@ Datum LWGEOM_force_multi(PG_FUNCTION_ARGS);
 
 Datum LWGEOMFromWKB(PG_FUNCTION_ARGS);
 Datum WKBFromLWGEOM(PG_FUNCTION_ARGS);
+Datum TWKBFromLWGEOM(PG_FUNCTION_ARGS);
 
 Datum LWGEOM_getBBOX(PG_FUNCTION_ARGS);
 Datum LWGEOM_addBBOX(PG_FUNCTION_ARGS);
index 6df1e0a2458d4092452ebebc3ba3b3d201b5b898..11043f9266d7491242b5fab55dbb30ac86dde45b 100644 (file)
@@ -28,6 +28,8 @@ Datum pgis_geometry_accum_transfn(PG_FUNCTION_ARGS);
 Datum pgis_geometry_accum_finalfn(PG_FUNCTION_ARGS);
 Datum pgis_geometry_union_finalfn(PG_FUNCTION_ARGS);
 Datum pgis_geometry_collect_finalfn(PG_FUNCTION_ARGS);
+Datum pgis_twkb_accum_finalfn(PG_FUNCTION_ARGS);
+Datum pgis_twkb_accum_transfn(PG_FUNCTION_ARGS);
 Datum pgis_geometry_polygonize_finalfn(PG_FUNCTION_ARGS);
 Datum pgis_geometry_makeline_finalfn(PG_FUNCTION_ARGS);
 Datum pgis_abs_in(PG_FUNCTION_ARGS);
@@ -36,6 +38,7 @@ Datum pgis_abs_out(PG_FUNCTION_ARGS);
 /* External prototypes */
 Datum pgis_union_geometry_array(PG_FUNCTION_ARGS);
 Datum LWGEOM_collect_garray(PG_FUNCTION_ARGS);
+Datum LWGEOM_twkb_garray(PG_FUNCTION_ARGS);
 Datum polygonize_garray(PG_FUNCTION_ARGS);
 Datum LWGEOM_makeline_garray(PG_FUNCTION_ARGS);
 
@@ -64,6 +67,26 @@ typedef struct
 }
 pgis_abs;
 
+typedef struct
+{
+       Datum id;       //Id, from function parameter
+       Datum geom;     //the geometry from function parameter
+}
+geom_id;
+
+
+typedef struct
+{
+       uint8_t variant;
+       int     precision;              //number of decimals in coordinates
+       int     n_rows;         
+       int     max_rows;
+       geom_id *geoms;
+       int method;
+}
+twkb_state;
+
+
 /**
 ** We're never going to use this type externally so the in/out
 ** functions are dummies.
@@ -138,6 +161,91 @@ pgis_geometry_accum_transfn(PG_FUNCTION_ARGS)
        PG_RETURN_POINTER(p);
 }
 
+
+
+PG_FUNCTION_INFO_V1(pgis_twkb_accum_transfn);
+Datum
+pgis_twkb_accum_transfn(PG_FUNCTION_ARGS)
+{
+       MemoryContext aggcontext;
+       MemoryContext oldcontext;       
+       twkb_state* state;
+       int32 newlen;
+       text *endianess;
+       GSERIALIZED *geom;
+       int i;
+       uint8_t variant = 0;
+
+if (!AggCheckCallContext(fcinfo, &aggcontext))
+       {
+               /* cannot be called directly because of dummy-type argument */
+               elog(ERROR, "array_agg_transfn called in non-aggregate context");
+               aggcontext = NULL;  /* keep compiler quiet */
+       }
+oldcontext = MemoryContextSwitchTo(aggcontext);
+       if ( PG_ARGISNULL(0) )
+       {
+               /*state gets palloced and 10 geometry elements too
+               don't forget to free*/
+                       
+
+        
+               state=palloc(sizeof(twkb_state));
+               state->geoms = palloc(10*sizeof(geom_id));
+               state->max_rows = 10;
+               state->n_rows = 0;      
+       
+               /* If user specified precision, respect it */
+               state->precision = PG_ARGISNULL(2) ? (int) 0 : PG_GETARG_INT32(2); 
+               
+               
+               /* If user specified endianness, respect it */
+               //endianess  = PG_ARGISNULL(4) ? 0 : PG_GETARG_TEXT_P(4);       
+
+               endianess = PG_GETARG_TEXT_P(4);
+               if  ( ! strncmp(VARDATA(endianess), "xdr", 3) ||
+                     ! strncmp(VARDATA(endianess), "XDR", 3) )
+               {
+                       variant = variant | WKB_XDR;
+               }
+               else
+               {
+                       variant = variant | WKB_NDR;
+               }
+               state->variant=variant;
+               
+               /* If user specified method, respect it
+               This will probably be taken away when we can decide which compression method that is best       */
+               state->method = PG_ARGISNULL(5) ? (int) 0 : PG_GETARG_INT32(5); 
+
+       }
+       else
+       {
+               state = PG_GETARG_POINTER(0);
+               
+               if(!((state->n_rows)<(state->max_rows)))
+               {
+                           newlen = (state->max_rows)*2;                       
+                           /* switch to aggregate memory context */
+                           
+                           state->geoms = (geom_id*)repalloc((void*)(state->geoms),newlen*sizeof(geom_id));
+                               
+                           state->max_rows = newlen;                       
+               }       
+       
+       }       
+
+       geom = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
+
+       ((state->geoms)+state->n_rows)->geom = PG_ARGISNULL(1) ? (Datum) 0 : PointerGetDatum(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1)));      
+       ((state->geoms)+state->n_rows)->id = PG_ARGISNULL(3) ? (int) 0 : PG_GETARG_INT32(3); 
+
+               (state->n_rows)++;      
+MemoryContextSwitchTo(oldcontext); 
+       
+       PG_RETURN_POINTER(state);
+}
+
 Datum pgis_accum_finalfn(pgis_abs *p, MemoryContext mctx, FunctionCallInfo fcinfo);
 
 /**
@@ -236,6 +344,105 @@ pgis_geometry_collect_finalfn(PG_FUNCTION_ARGS)
        PG_RETURN_DATUM(result);
 }
 
+/**
+* The "twkb" final function passes the geometry[] to a twkb
+* conversion before returning the result.
+*/
+PG_FUNCTION_INFO_V1(pgis_twkb_accum_finalfn);
+Datum
+pgis_twkb_accum_finalfn(PG_FUNCTION_ARGS)
+{
+       int i;
+       twkb_state *state;
+       geom_id *geom_array;
+       twkb_geom_arrays lwgeom_arrays;
+       GSERIALIZED *geom;
+       LWGEOM *lwgeom;
+       size_t twkb_size;       
+       uint8_t *twkb;
+       bytea *result;
+       state = PG_GETARG_POINTER(0);
+       lwgeom_arrays.n_points=lwgeom_arrays.n_linestrings=lwgeom_arrays.n_polygons=lwgeom_arrays.n_collections=0;
+       geom_array=state->geoms;
+
+
+       
+       
+       for (i=0;i<state->n_rows;i++)
+       {
+               geom = (GSERIALIZED*)PG_DETOAST_DATUM((geom_array+i)->geom);
+               lwgeom = lwgeom_from_gserialized(geom);
+               switch ( lwgeom->type )
+               {
+                       case POINTTYPE:
+                               if (lwgeom_arrays.n_points==0)
+                                       lwgeom_arrays.points = palloc(((state->n_rows)-i)*sizeof(geom_id));
+                               
+                               (lwgeom_arrays.points+lwgeom_arrays.n_points)->geom=lwgeom;
+                               (lwgeom_arrays.points+lwgeom_arrays.n_points)->id=(geom_array+i)->id;
+                               (lwgeom_arrays.n_points)++;
+                               break;
+                       /* LineString and CircularString both have 'points' elements */
+                       case LINETYPE:
+                               if (lwgeom_arrays.n_linestrings==0)
+                                       lwgeom_arrays.linestrings = palloc(((state->n_rows)-i)*sizeof(geom_id));
+                               
+                               (lwgeom_arrays.linestrings+lwgeom_arrays.n_linestrings)->geom=lwgeom;
+                               (lwgeom_arrays.linestrings+lwgeom_arrays.n_linestrings)->id=(geom_array+i)->id;
+                               (lwgeom_arrays.n_linestrings)++;
+                               break;
+
+                       /* Polygon has 'nrings' and 'rings' elements */
+                       case POLYGONTYPE:
+                               if (lwgeom_arrays.n_polygons==0)
+                                       lwgeom_arrays.polygons = palloc(((state->n_rows)-i)*sizeof(geom_id));
+                               
+                               (lwgeom_arrays.polygons+lwgeom_arrays.n_polygons)->geom=lwgeom;
+                               (lwgeom_arrays.polygons+lwgeom_arrays.n_polygons)->id=(geom_array+i)->id;
+                               (lwgeom_arrays.n_polygons)++;
+                               break;
+
+                       /* Triangle has one ring of three points 
+                       case TRIANGLETYPE:
+                               return lwtriangle_to_twkb_buf((LWTRIANGLE*)geom, buf, variant);
+       */
+                       /* All these Collection types have 'ngeoms' and 'geoms' elements */
+                       case MULTIPOINTTYPE:
+                       case MULTILINETYPE:
+                       case MULTIPOLYGONTYPE:
+                       case COLLECTIONTYPE:
+                               if (lwgeom_arrays.n_collections==0)
+                                       lwgeom_arrays.collections = palloc(((state->n_rows)-i)*sizeof(geom_id));
+                               
+                               (lwgeom_arrays.collections+lwgeom_arrays.n_collections)->geom=lwgeom;
+                               (lwgeom_arrays.collections+lwgeom_arrays.n_collections)->id=(geom_array+i)->id;
+                               (lwgeom_arrays.n_collections)++;
+                               break;
+
+                       /* Unknown type! */
+                       default:
+                               lwerror("Unsupported geometry type: %s [%d]", lwtype_name(lwgeom->type), lwgeom->type);
+               }
+       
+       }               
+       
+       twkb = lwgeom_agg_to_twkb(&lwgeom_arrays, state->variant , &twkb_size,(int8_t) state->precision,state->method);
+
+
+               /* Clean up and return */
+       /* Prepare the PgSQL text return type */
+       
+       result = palloc(twkb_size + VARHDRSZ);
+       SET_VARSIZE(result, twkb_size+VARHDRSZ);
+       memcpy(VARDATA(result), twkb, twkb_size);
+
+       /* Clean up and return */
+       pfree(twkb);
+
+       PG_RETURN_BYTEA_P(result);
+}
+
+
 /**
 * The "polygonize" final function passes the geometry[] to a polygonization
 * before returning the result.
index e0652fb070e46bacf0fd1edc9f4964c4a3e0f19e..a5f463b75deb381501fd80149ede208d3ec0b092 100644 (file)
@@ -403,6 +403,77 @@ Datum WKBFromLWGEOM(PG_FUNCTION_ARGS)
 }
 
 
+PG_FUNCTION_INFO_V1(TWKBFromLWGEOM);
+Datum TWKBFromLWGEOM(PG_FUNCTION_ARGS)
+{
+       GSERIALIZED *geom = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+       LWGEOM *lwgeom;
+       uint8_t *twkb;
+       size_t twkb_size;
+       uint8_t variant = 0;
+       bytea *result;
+       text *type;
+       int id,prec,method;
+       
+       /* If user specified precision, respect it */
+       if ( (PG_NARGS()>1) && (!PG_ARGISNULL(1)) )
+       {
+               prec = PG_GETARG_INT32(1);
+               if  (fabs(prec)>7)
+                       lwerror("precision cannot be more than 7");
+       }
+       else
+               prec=0;
+       
+               /* If user specified id, respect it */
+       if ( (PG_NARGS()>2) && (!PG_ARGISNULL(2)) )
+       {
+               id = PG_GETARG_INT32(2);
+       }
+       else
+               id=0;
+       
+       /* If user specified endianness, respect it */
+       if ( (PG_NARGS()>3) && (!PG_ARGISNULL(3)) )
+       {
+               type = PG_GETARG_TEXT_P(3);
+
+               if  ( ! strncmp(VARDATA(type), "xdr", 3) ||
+                     ! strncmp(VARDATA(type), "XDR", 3) )
+               {
+                       variant = variant | WKB_XDR;
+               }
+               else
+               {
+                       variant = variant | WKB_NDR;
+               }
+       }
+               /* If user specified method, respect it
+               This will probably be taken away when we can decide which compression method that is best       */
+       if ( (PG_NARGS()>4) && (!PG_ARGISNULL(4)) )
+       {
+               method = PG_GETARG_INT32(4);
+       }
+       else 
+               method=0;
+       
+       /* Create TWKB bin string */
+       lwgeom = lwgeom_from_gserialized(geom);
+       twkb = lwgeom_to_twkb(lwgeom, variant , &twkb_size,(int8_t) prec,(int32_t) id,method);
+       lwgeom_free(lwgeom);
+       
+       /* Prepare the PgSQL text return type */
+       result = palloc(twkb_size + VARHDRSZ);
+       memcpy(VARDATA(result), twkb, twkb_size);
+
+       SET_VARSIZE(result, twkb_size+VARHDRSZ);
+       
+       /* Clean up and return */
+       pfree(twkb);
+       PG_FREE_IF_COPY(geom, 0);
+       PG_RETURN_BYTEA_P(result);
+}
+
 /* puts a bbox inside the geometry */
 PG_FUNCTION_INFO_V1(LWGEOM_addBBOX);
 Datum LWGEOM_addBBOX(PG_FUNCTION_ARGS)
index 06313e3d4edaca92065cb2d6cb9e8f4e0fb49a14..42d871dc676f93b1fac27fb58a07244c9739a58c 100644 (file)
@@ -1343,6 +1343,37 @@ CREATE OR REPLACE FUNCTION ST_AsEWKT(geometry)
        AS 'MODULE_PATHNAME','LWGEOM_asEWKT'
        LANGUAGE 'c' IMMUTABLE STRICT;
 
+-- Availability: 2.2.0
+CREATE OR REPLACE FUNCTION ST_AsTWKB(geometry)
+       RETURNS bytea
+       AS 'MODULE_PATHNAME','TWKBFromLWGEOM'
+       LANGUAGE 'c' IMMUTABLE STRICT;
+
+               
+-- Availability: 2.2.0
+CREATE OR REPLACE FUNCTION ST_AsTWKB(geometry,int4)
+       RETURNS bytea
+       AS 'MODULE_PATHNAME','TWKBFromLWGEOM'
+       LANGUAGE 'c' IMMUTABLE STRICT;
+               
+-- Availability: 2.2.0
+CREATE OR REPLACE FUNCTION ST_AsTWKB(geometry,int4,int4)
+       RETURNS bytea
+       AS 'MODULE_PATHNAME','TWKBFromLWGEOM'
+       LANGUAGE 'c' IMMUTABLE STRICT;
+               
+-- Availability: 2.2.0
+CREATE OR REPLACE FUNCTION ST_AsTWKB(geometry,int4,int4,text)
+       RETURNS bytea
+       AS 'MODULE_PATHNAME','TWKBFromLWGEOM'
+       LANGUAGE 'c' IMMUTABLE STRICT;
+       
+-- Availability: 2.2.0
+CREATE OR REPLACE FUNCTION ST_AsTWKB(geometry,int4,int4,text,int)
+       RETURNS bytea
+       AS 'MODULE_PATHNAME','TWKBFromLWGEOM'
+       LANGUAGE 'c' IMMUTABLE STRICT;
+       
 -- Availability: 1.2.2
 CREATE OR REPLACE FUNCTION ST_AsEWKB(geometry)
        RETURNS BYTEA
@@ -3314,6 +3345,35 @@ CREATE OR REPLACE FUNCTION pgis_geometry_makeline_finalfn(pgis_abs)
        AS 'MODULE_PATHNAME'
        LANGUAGE 'c';
 
+--Availability: 2.2.0
+
+CREATE OR REPLACE FUNCTION pgis_twkb_accum_transfn(internal, geometry,int,int,text)
+  RETURNS internal
+       AS 'MODULE_PATHNAME'
+  LANGUAGE c ;
+  
+CREATE OR REPLACE FUNCTION pgis_twkb_accum_transfn(internal, geometry,int,int,text,int)
+  RETURNS internal
+       AS 'MODULE_PATHNAME'
+  LANGUAGE c ;
+
+CREATE OR REPLACE FUNCTION pgis_twkb_accum_finalfn(internal)
+  RETURNS bytea
+       AS 'MODULE_PATHNAME'
+  LANGUAGE c ;
+
+CREATE AGGREGATE st_astwkb_agg(geometry,int,int,text) (
+  SFUNC=pgis_twkb_accum_transfn,
+  STYPE=internal,
+  FINALFUNC=pgis_twkb_accum_finalfn
+);
+
+CREATE AGGREGATE st_astwkb_agg(geometry,int,int,text,int) (
+  SFUNC=pgis_twkb_accum_transfn,
+  STYPE=internal,
+  FINALFUNC=pgis_twkb_accum_finalfn
+);
+
 -- Availability: 1.2.2
 CREATE AGGREGATE ST_Accum (
        sfunc = pgis_geometry_accum_transfn,