]> granicus.if.org Git - postgis/commitdiff
WKB reader and WKB writer (totally untested)
authorDavid Blasby <dblasby@gmail.com>
Wed, 10 Mar 2004 01:15:06 +0000 (01:15 +0000)
committerDavid Blasby <dblasby@gmail.com>
Wed, 10 Mar 2004 01:15:06 +0000 (01:15 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@482 b70326c6-7e19-0410-871a-916f4a2858ee

lwgeom/Makefile
lwgeom/lwgeom.h
lwgeom/lwgeom.sql.in [new file with mode: 0644]
lwgeom/lwgeom_api.c
lwgeom/lwgeom_inout.c

index 722c1d798bdda6be9e72bd1a346442e271b0f8db..71a7980a1a94afc33ec60859573f27332473bf31 100644 (file)
@@ -159,15 +159,15 @@ include $(top_srcdir)/src/Makefile.shlib
 
 postgis_geos_wrapper.o: postgis_geos_wrapper.cpp
 
-all: all-lib postgis.sql postgis.sql postgis_undef.sql loaderdumper
+all: all-lib lwgeom.sql 
 
 loaderdumper:
        $(MAKE) -C loader
 
 # Shared library stuff
 
-#postgis.sql: postgis_sql_common.sql.in postgis_sql_$(USE_VERSION)_end.sql.in postgis_sql_$(USE_VERSION)_start.sql.in 
-#      cat postgis_sql_$(USE_VERSION)_start.sql.in postgis_sql_common.sql.in postgis_sql_$(USE_VERSION)_end.sql.in | sed -e 's:@MODULE_FILENAME@:$(MODULE_FILENAME):g;s:@POSTGIS_VERSION@:$(POSTGIS_VERSION):g'  > $@ 
+lwgeom.sql:    lwgeom.sql.in
+       cat lwgeom.sql.in | sed -e 's:@MODULE_FILENAME@:$(MODULE_FILENAME):g;s:@POSTGIS_VERSION@:$(POSTGIS_VERSION):g'  > $@ 
 
 #postgis_new.sql: postgis.sql.in
 #      cpp -P -traditional-cpp -DUSE_VERSION=$(USE_VERSION) -DMODULE_FILENAME="'$(MODULE_FILENAME)'" -DPOSTGIS_VERSION="'$(POSTGIS_VERSION)'" $< > $@
index a7ac0710ec7572a6e20f2f06d094b6d0e14b4f66..39c1ebeb4f22f26b3ac2d7b05004a2a4c2bde9ec 100644 (file)
@@ -8,6 +8,10 @@
 
 
 
+#define TWODIMS 00
+#define THREEDIMS 01
+#define FOURDIMS 10
+
 typedef struct
 {
        float xmin;
@@ -44,6 +48,16 @@ typedef struct
 } POINT2D;
 
 
+typedef struct
+{
+        double x;
+        double y;
+        double z;
+        double m;
+} POINT4D;
+
+
+
 // Point array abstracts a lot of the complexity of points and point lists.
 // It handles miss-alignment in the serialized form, 2d/3d translation
 //    (2d points converted to 3d will have z=0 or NaN)
@@ -89,6 +103,12 @@ extern POINTARRAY *pointArray_construct(char *points, char is3d, uint32 npoints)
 // dont call on an empty pa
 extern BOX3D *pointArray_bbox(POINTARRAY *pa);
 
+//size of point represeneted in the POINTARRAY
+// 16 for 2d, 24 for 3d, 32 for 4d
+extern int pointArray_ptsize(POINTARRAY *pa);
+
+
+
 /*
 
  LWGEOM types are an 8-bit char in this format:
@@ -181,7 +201,7 @@ typedef struct
 
 // construct a new point.  point will NOT be copied
 // use SRID=-1 for unknown SRID (will have 8bit type's S = 0)
-extern LWPOINT  *lwpoint_construct(char is3d, int SRID, POINT3D *point);
+extern LWPOINT  *lwpoint_construct(char is3d, int SRID, POINTARRAY *point);
 
 // given the LWPOINT serialized form (or a pointer into a muli* one)
 // construct a proper LWPOINT.
@@ -384,6 +404,11 @@ extern void pfree_polygon  (LWPOLY  *poly);
 extern void pfree_POINTARRAY(POINTARRAY *pa);
 
 
+//***********************************************************
+// utility
+
+extern uint32 get_uint32(char *loc);
+extern int32 get_int32(char *loc);
 
 //------------------------------------------------------------
 //------------------------------------------------------------
@@ -503,3 +528,5 @@ extern void pfree_POINTARRAY(POINTARRAY *pa);
 //   POINT2D getPoint2d(POINTARRAY pa, int n);  (for a 2d/3d point and 2d length)
 // NOTE: make sure your findlength() function knows what to do with z=NaN.
 
+
+
diff --git a/lwgeom/lwgeom.sql.in b/lwgeom/lwgeom.sql.in
new file mode 100644 (file)
index 0000000..e69de29
index e8283bdafa2bf11ffad1f4b074dd7d653544e1e5..77a1eb2f4a2be0fd8b921b3dc808ff9a900efa70 100644 (file)
@@ -23,8 +23,7 @@ extern float nextUp_f(double d);
 extern double nextDown_d(float d);
 extern double nextUp_d(float d);
 
-extern uint32 get_uint32(char *loc);
-extern int32 get_int32(char *loc);
+
 extern  BOX3D *lw_geom_getBB_simple(char *serialized_form);
 
 
@@ -372,6 +371,15 @@ BOX3D *pointArray_bbox(POINTARRAY *pa)
        return result;
 }
 
+//size of point represeneted in the POINTARRAY
+// 16 for 2d, 24 for 3d, 32 for 4d
+int pointArray_ptsize(POINTARRAY *pa)
+{
+       if (pa->is3d)
+               return 24;
+       else
+               return 16;
+}
 
 
 //***************************************************************************
@@ -593,10 +601,9 @@ uint32 lwline_findlength(char *serialized_line)
 
 // construct a new point.  point will not be copied
 // use SRID=-1 for unknown SRID (will have 8bit type's S = 0)
-LWPOINT  *lwpoint_construct(char is3d, int SRID, POINT3D *point)
+LWPOINT  *lwpoint_construct(char is3d, int SRID, POINTARRAY *point)
 {
        LWPOINT *result ;
-       POINTARRAY *pa;
 
        if (point == NULL)
                return NULL; // error
@@ -605,9 +612,7 @@ LWPOINT  *lwpoint_construct(char is3d, int SRID, POINT3D *point)
        result->is3d = is3d;
        result->SRID = SRID;
 
-       pa =pointArray_construct((char *)point, is3d, 1);
-
-       result->point = pa;
+       result->point = point;
 
        return result;
 }
@@ -1620,7 +1625,7 @@ void pfree_inspected(LWGEOM_INSPECTED *inspected)
 
 void pfree_point    (LWPOINT *pt)
 {
-       pfree(pt->point);
+       pfree_POINTARRAY(pt->point);
        pfree(pt);
 }
 
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fe4468b7641eea67d0185bbaddd97dcd28b9913b 100644 (file)
@@ -0,0 +1,520 @@
+#include "postgres.h"
+
+#include <math.h>
+#include <float.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "access/gist.h"
+#include "access/itup.h"
+#include "access/rtree.h"
+
+#include "fmgr.h"
+#include "utils/elog.h"
+
+
+#include "lwgeom.h"
+
+extern char *wkb_to_lwgeom(char *wkb, int SRID,int *size);
+extern char *lwgeom_to_wkb(char *serialized_form,int *wkblength,char desiredWKBEndian);
+extern void swap_char(char     *a,char *b);
+extern void    flip_endian_double(char         *d);
+extern void            flip_endian_int32(char          *i);
+extern char wkb_dims(uint32 type);
+extern char wkb_simpletype (uint32 type);
+extern uint32 constructWKBType(int simple_type, char dims);
+extern bool requiresflip(char WKBendianflag);
+extern void flipPoints(char *pts, int npoints, char dims);
+extern uint32 constructWKBType(int simple_type, char dims);
+
+extern LWPOINT *wkb_point_to_lwpoint(char *wkb,int SRID);
+extern LWLINE *wkb_line_to_lwline(char *wkb,int SRID);
+extern LWPOLY *wkb_poly_to_lwpoly(char *wkb,int SRID);
+
+extern char *lwline_to_wkb(LWLINE *line, char desiredWKBEndian, int *wkbsize);
+extern char *lwpoint_to_wkb(LWPOINT *point, char desiredWKBEndian, int *wkbsize);
+extern char *lwpoly_to_wkb(LWPOLY *poly, char desiredWKBEndian, int *wkbsize);
+
+// 3d or 4d.  There is NOT a (x,y,m) point type!!!
+#define WKB3DOFFSET 0x80000000
+#define WKB4DOFFSET 0x40000000
+
+Datum LWGEOMFromWKB(PG_FUNCTION_ARGS);
+Datum WKBFromLWGEOM(PG_FUNCTION_ARGS);
+
+// LWGEOMFromWKB(wkb,  [SRID] )
+PG_FUNCTION_INFO_V1(LWGEOMFromWKB);
+Datum LWGEOMFromWKB(PG_FUNCTION_ARGS)
+{
+               char   *wkb_input = (char *)  PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+               int    SRID ;
+               int    size;
+               char *lwgeom;
+               char * result;
+
+                               if ( ! PG_ARGISNULL(1) )
+                                       SRID = PG_GETARG_INT32(1);
+                               else
+                                       SRID = -1;
+
+               lwgeom = wkb_to_lwgeom(wkb_input, SRID,&size);
+               result = palloc(size+4);
+
+               memcpy(result+4, lwgeom, size);
+               size+=4;
+               memcpy(result, &size, 4);
+
+               pfree(lwgeom);
+
+               PG_RETURN_POINTER(result);
+}
+
+// WKBFromLWGEOM(wkb)
+PG_FUNCTION_INFO_V1(WKBFromLWGEOM);
+Datum WKBFromLWGEOM(PG_FUNCTION_ARGS)
+{
+               char   *lwgeom_input = (char *)  PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+               int    size;
+               char *wkb = lwgeom_to_wkb(lwgeom_input+4,&size,1); // 0=XDR, 1=NDR
+
+               char *result = palloc(size+4);
+
+               memcpy(result+4, wkb, size);
+               size+=4;
+               memcpy(result, &size, 4);
+               pfree(wkb);
+
+               PG_RETURN_POINTER(result);
+}
+
+
+//given a wkb (with 3d and 4d extension)
+// create the serialized form of an equivelent LWGEOM
+// size of the lwgeom form is also returned
+//
+// note - to actually serialize, you should put the first 4
+// bytes as size (size +4), then the results of this function.
+//
+// because this function modifies the wkb (to make it the
+// server's endian), you should give it a copy of the wkb.
+// The underlying LWGEOM will point into this WKB, so
+// be extreamly careful when you free it!
+//
+// also, wkb should point to the 1st wkb character; NOT
+// the postgresql length int32.
+char *wkb_to_lwgeom(char *wkb, int SRID,int *size)
+{
+       uint32 wkbtype;
+       char   dims;
+       bool need_flip =  requiresflip( wkb[0] );
+
+       LWPOINT *pt;
+       LWLINE  *line;
+       LWPOLY  *poly;
+       char    *multigeom = NULL;
+       char    *result = NULL;
+       int simpletype;
+
+       if (need_flip)
+               flip_endian_int32(wkb+1);
+
+       wkbtype = get_uint32(wkb+1);
+       dims = wkb_dims(wkbtype);
+       simpletype = wkb_simpletype(wkbtype);
+
+       switch (simpletype)
+       {
+               case POINTTYPE:
+                                               pt = wkb_point_to_lwpoint(wkb, SRID);
+                                               result  = lwpoint_serialize(pt);
+                                               *size = lwpoint_findlength(result);
+                                               pfree_point(pt);
+                                               break;
+               case LINETYPE:
+                                               line = wkb_line_to_lwline(wkb, SRID);
+                                               result  = lwline_serialize(line);
+                                               *size = lwline_findlength(result);
+                                               pfree_line(line);
+                                               break;
+               case POLYGONTYPE:
+                                               poly = wkb_poly_to_lwpoly(wkb, SRID);
+                                               result  = lwpoly_serialize(poly);
+                                               *size = lwpoly_findlength(result);
+                                               pfree_polygon(poly);
+                                               break;
+               case MULTIPOINTTYPE:
+                                               result = multigeom;
+                                               break;
+               case MULTILINETYPE:
+                                               break;
+               case MULTIPOLYGONTYPE:
+                                               break;
+               case COLLECTIONTYPE:
+                                               break;
+       }
+       return result;
+}
+
+//NOTE: THIS CHANGES THE ENDIAN OF THE WKB!!
+// we make sure the point is correctly endianed
+// and make a LWPOINT that points into it.
+// wkb --> point to the endian definition of the wkb point
+LWPOINT *wkb_point_to_lwpoint(char *wkb,int SRID)
+{
+       uint32 wkbtype;
+       char   dims;
+       char   simpletype;
+       POINTARRAY *pa;
+
+       bool need_flip =  requiresflip( wkb[0] );
+       if (need_flip)
+               flip_endian_int32(wkb+1);
+
+       wkbtype = get_uint32(wkb+1);
+       dims = wkb_dims(wkbtype);
+       simpletype = wkb_simpletype(wkbtype);
+
+       if (simpletype != POINTTYPE)
+               elog(ERROR,"WKB::point parser - go wrong type");
+
+       pa = pointArray_construct(wkb+5, dims, 1);
+
+       return lwpoint_construct(dims, SRID, pa);
+}
+
+LWLINE *wkb_line_to_lwline(char *wkb,int SRID)
+{
+               uint32 wkbtype;
+               char   dims;
+               char   simpletype;
+               POINTARRAY *pa;
+               int npoints;
+
+       bool need_flip =  requiresflip( wkb[0] );
+       if (need_flip)
+               flip_endian_int32(wkb+1); // type
+
+       wkbtype = get_uint32(wkb+1);
+       dims = wkb_dims(wkbtype);
+       simpletype = wkb_simpletype(wkbtype);
+
+       if (simpletype != LINETYPE)
+               elog(ERROR,"WKB::line parser - go wrong type");
+
+       if (need_flip)
+               flip_endian_int32(wkb+5); // npoints
+
+       npoints = get_uint32(wkb+5);
+
+       if (need_flip)
+               flipPoints(wkb+9,npoints,dims);
+
+       pa = pointArray_construct(wkb+9, dims, npoints);
+
+       return lwline_construct(dims, SRID, pa);
+}
+
+LWPOLY *wkb_poly_to_lwpoly(char *wkb,int SRID)
+{
+               uint32 wkbtype;
+               char   dims;
+               char   simpletype;
+               POINTARRAY *pa;
+               int npoints;
+               POINTARRAY **rings;
+               int nrings;
+               int t;
+               char *loc;
+               int ptsize =16;
+
+               bool need_flip =  requiresflip( wkb[0] );
+               if (need_flip)
+                       flip_endian_int32(wkb+1); // type
+
+               wkbtype = get_uint32(wkb+1);
+               dims = wkb_dims(wkbtype);
+               simpletype = wkb_simpletype(wkbtype);
+
+               if (simpletype != POLYGONTYPE)
+                       elog(ERROR,"WKB::polygon parser - go wrong type");
+
+               if (need_flip)
+                       flip_endian_int32(wkb+5); // nrings
+
+               nrings = get_uint32(wkb+5);
+
+               loc = wkb+5;
+
+                       //point size
+
+               if (dims == FOURDIMS)
+               {
+                       ptsize = 32;
+               }
+               if (dims == THREEDIMS)
+               {
+                       ptsize = 24;
+        }
+
+
+               rings = (POINTARRAY **) palloc(sizeof(POINTARRAY*) * nrings);
+
+               for (t=0;t<nrings;t++)
+               {
+
+                       if (need_flip)
+                               flip_endian_int32(loc); // npoints
+
+                       npoints = get_uint32(loc);
+
+                                       // read a ring
+                       if (need_flip)
+                               flipPoints(loc+4,npoints,dims);
+
+                       pa = pointArray_construct(loc+4, dims, npoints);
+
+                       loc += 4;
+                       loc += npoints * ptsize;
+                       rings[t] = pa;
+               }
+               return lwpoly_construct(dims, SRID, nrings,rings);
+}
+
+
+// takes a lwgeom and converts it to an appropriate wkb
+//
+// length of the wkb is returned in wkblength (this doesnt
+//  include the 4 bytes needed for the postgresql int32 length)
+//
+char *lwgeom_to_wkb(char *serialized_form,int *wkblength,char desiredWKBEndian)
+{
+       char simple_type = lwgeom_getType(serialized_form[0]);
+       char *result = NULL;
+       LWPOINT *pt;
+       LWLINE *line;
+       LWPOLY *poly;
+       char   *multigeom = NULL;
+
+
+       switch (simple_type)
+       {
+               case POINTTYPE:
+                                               pt = lwpoint_deserialize(serialized_form);
+                                               result = lwpoint_to_wkb(pt, desiredWKBEndian, wkblength);
+                                               pfree_point(pt);
+                                               break;
+               case LINETYPE:
+                                               line = lwline_deserialize(serialized_form);
+                                               result = lwline_to_wkb(line, desiredWKBEndian, wkblength);
+                                               pfree_line(line);
+                                               break;
+               case POLYGONTYPE:
+                                               poly = lwpoly_deserialize(serialized_form);
+                                               result = lwpoly_to_wkb(poly, desiredWKBEndian, wkblength);
+                                               pfree_polygon(poly );
+                                               break;
+               case MULTIPOINTTYPE:
+                                               result  = multigeom;
+                                               break;
+               case MULTILINETYPE:
+                                               break;
+               case MULTIPOLYGONTYPE:
+                                               break;
+               case COLLECTIONTYPE:
+                                               break;
+       }
+       return result;
+}
+
+char *lwpoint_to_wkb(LWPOINT *pt, char desiredWKBEndian, int *wkbsize)
+{
+       int ptsize = pointArray_ptsize(pt->point);
+       char * result;
+       uint32 wkbtype ;
+       bool need_flip =  requiresflip( desiredWKBEndian );
+
+
+       *wkbsize = 1+ 4+ ptsize; //endian, type, point
+
+       result = palloc(*wkbsize);
+
+       result[0] = desiredWKBEndian; //endian flag
+
+       wkbtype = constructWKBType(POINTTYPE, pt->point->is3d);
+       memcpy(result+1, &wkbtype, 4);
+       if (need_flip)
+               flip_endian_int32(result+1);
+
+       memcpy(result+5, pt->point->serialized_pointlist, pointArray_ptsize(pt->point) );
+       if (need_flip)
+               flipPoints(result+5, 1, pt->point->is3d);
+
+       return result;
+}
+
+char *lwline_to_wkb(LWLINE *line, char desiredWKBEndian, int *wkbsize)
+{
+               int ptsize = pointArray_ptsize(line->points);
+               char * result;
+               uint32 wkbtype ;
+               bool need_flip =  requiresflip( desiredWKBEndian );
+
+
+               *wkbsize = 1+ 4+ line->points->npoints * ptsize; //endian, type, points
+
+               result = palloc(*wkbsize);
+
+               result[0] = desiredWKBEndian; //endian flag
+
+               wkbtype = constructWKBType(LINETYPE, line->points->is3d);
+               memcpy(result+1, &wkbtype, 4);
+               if (need_flip)
+                       flip_endian_int32(result+1);
+
+               memcpy(result+5, line->points->serialized_pointlist, pointArray_ptsize(line->points) * line->points->npoints);
+               if (need_flip)
+                       flipPoints(result+5, line->points->npoints, line->points->is3d);
+               return result;
+}
+
+char *lwpoly_to_wkb(LWPOLY *poly, char desiredWKBEndian, int *wkbsize)
+{
+               int ptsize = pointArray_ptsize(poly->rings[0]);
+               char * result;
+               uint32 wkbtype ;
+               bool need_flip =  requiresflip( desiredWKBEndian );
+               int total_points =0;
+               char *loc;
+               int t;
+
+
+               for (t=0;t<poly->nrings;t++)
+               {
+                       total_points += poly->rings[t]->npoints;
+               }
+
+               *wkbsize = 1+ 4+ total_points * ptsize + 4* poly->nrings; //endian, type, all points, ring lengths
+
+               result = palloc(*wkbsize);
+
+               result[0] = desiredWKBEndian; //endian flag
+
+               wkbtype = constructWKBType(POLYGONTYPE, poly->is3d);
+               memcpy(result+1, &wkbtype, 4);  // type
+               if (need_flip)
+                       flip_endian_int32(result+1);
+
+               memcpy(result+5, &poly->nrings, 4);     // nrings
+               if (need_flip)
+                       flip_endian_int32(result+5);
+
+               loc = result+9;
+
+               for (t=0;t<poly->nrings;t++)
+               {
+                       int npoints =poly->rings[t]->npoints;
+                       memcpy( loc, &npoints, 4); // npoints
+                       if (need_flip)
+                               flip_endian_int32(loc);
+                       memcpy(loc+4, poly->rings[t]->serialized_pointlist, ptsize * npoints);
+                       if (need_flip)
+                               flipPoints(loc+4, npoints, poly->is3d);
+                       loc += 4+ ptsize * npoints;
+               }
+               return result;
+}
+
+
+bool requiresflip(char WKBendianflag)
+{
+       if (WKBendianflag == 1) // NDR
+               return ( BYTE_ORDER != LITTLE_ENDIAN );
+       if (WKBendianflag == 0) // xDR
+               return ( BYTE_ORDER != BIG_ENDIAN );
+       elog(ERROR,"WKB: endian flag isnt a 0 or 1.  WKB screwed?");
+       return 0; //shouldnt get here
+}
+
+void swap_char(char    *a,char *b)
+{
+       char c;
+
+       c = *a;
+       *a=*b;
+       *b=c;
+}
+
+
+void   flip_endian_double(char         *d)
+{
+       swap_char(d+7, d);
+       swap_char(d+6, d+1);
+       swap_char(d+5, d+2);
+       swap_char(d+4, d+3);
+}
+
+void           flip_endian_int32(char          *i)
+{
+       swap_char (i+3,i);
+       swap_char (i+2,i+1);
+}
+
+// given a wkb type
+// return twoDims, threeDims, or fourDims
+char wkb_dims(uint32 type)
+{
+       if (type & 0x80000000)
+               return THREEDIMS;
+       if (type & 0x40000000)
+               return FOURDIMS;
+       return TWODIMS;
+}
+
+
+char wkb_simpletype (uint32 type)
+{
+       return type & 0x0F;
+}
+
+void flipPoints(char *pts, int npoints, char dims)
+{
+       int t;
+       char *loc = pts;
+       int size =16;
+
+       if (dims == FOURDIMS)
+       {
+               size = 32;
+       }
+       if (dims == THREEDIMS)
+       {
+               size = 24;
+       }
+
+       for (t=0;t<npoints;t++)
+       {
+               flip_endian_double(loc);
+               flip_endian_double(loc+8);
+               if ( (dims == THREEDIMS)  || (dims == FOURDIMS) )
+               {
+                       flip_endian_double(loc+16);
+               }
+               if (dims == FOURDIMS)
+               {
+                       flip_endian_double(loc+24);
+               }
+               loc += size;
+       }
+}
+
+uint32 constructWKBType(int simple_type, char dims)
+{
+       if (dims == TWODIMS)
+               return simple_type;
+       if (dims == THREEDIMS)
+               return simple_type | 0x80000000;
+
+       return simple_type | 0x40000000;
+}
+