]> granicus.if.org Git - postgis/commitdiff
Initial implementation - should compile; not at all tested.
authorDavid Blasby <dblasby@gmail.com>
Tue, 9 Mar 2004 17:29:52 +0000 (17:29 +0000)
committerDavid Blasby <dblasby@gmail.com>
Tue, 9 Mar 2004 17:29:52 +0000 (17:29 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@481 b70326c6-7e19-0410-871a-916f4a2858ee

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

diff --git a/lwgeom/Makefile b/lwgeom/Makefile
new file mode 100644 (file)
index 0000000..722c1d7
--- /dev/null
@@ -0,0 +1,213 @@
+# Configuration Directives
+
+#---------------------------------------------------------------
+# Set USE_PROJ to 1 for Proj4 reprojection support
+#
+USE_PROJ=1
+ifeq (${PROJ_DIR},) 
+       PROJ_DIR=/usr/local
+endif
+
+#---------------------------------------------------------------
+# Set USE_GEOS to 1 for GEOS spatial predicate and operator
+# support
+#
+USE_GEOS=1
+ifeq (${GEOS_DIR},) 
+       GEOS_DIR=/usr/local
+endif
+
+#---------------------------------------------------------------
+# Set USE_STATS to 1 for new GiST statistics collection support
+# Note that this support requires additional columns in 
+# GEOMETRY_COLUMNS, so see the list archives for info or
+# install a fresh database using postgis.sql
+#
+USE_STATS=1
+
+#---------------------------------------------------------------
+subdir=contrib/postgis
+
+#---------------------------------------------------------------
+# Default the root of the PostgreSQL source tree 
+# To use a non-standard location set the PGSQL_SRC environment
+# variable to the appropriate location.
+#
+ifeq (${PGSQL_SRC},) 
+       top_builddir = ../..
+       include $(top_builddir)/src/Makefile.global
+       #LPATH := $$libdir
+else
+       top_builddir = ${PGSQL_SRC}
+       include $(top_builddir)/src/Makefile.global
+       #LPATH := ${PWD}
+endif
+
+#---------------------------------------------------------------
+# Default missing CXX variable to c++
+# 
+ifeq ($(CXX),) 
+       CXX = c++
+endif
+
+#---------------------------------------------------------------
+# Test the version string and set the USE_VERSION macro
+# appropriately.
+#
+ifneq ($(findstring 7.1,$(VERSION)),)
+       USE_VERSION=71
+else
+       ifneq ($(findstring 7.2,$(VERSION)),)
+               USE_VERSION=72
+       else
+               ifneq ($(findstring 7.3,$(VERSION)),)
+                       USE_VERSION=73
+               else
+                       ifneq ($(findstring 7.4,$(VERSION)),)
+                               USE_VERSION=74
+                       else
+                               USE_VERSION=75
+                       endif
+               endif
+       endif
+endif
+
+#---------------------------------------------------------------
+# Shared library parameters.
+#
+NAME=lwgeom
+SO_MAJOR_VERSION=0
+SO_MINOR_VERSION=1
+ifeq (${USE_VERSION}, 71) 
+       MODULE_FILENAME = $(libdir)/$(shlib)
+       MODULE_INSTALLDIR = $(libdir)
+else
+       MODULE_FILENAME =/net/lion/raid/share/Refractions/Projects/PostGIS/work_dave2/postgis/lwgeom/$(shlib)
+       MODULE_INSTALLDIR = $(pkglibdir)
+endif
+
+#---------------------------------------------------------------
+# Postgis version
+#---------------------------------------------------------------
+
+POSTGIS_VERSION = $(SO_MAJOR_VERSION).$(SO_MINOR_VERSION) USE_GEOS=$(USE_GEOS) USE_PROJ=$(USE_PROJ) USE_STATS=$(USE_STATS)
+
+#---------------------------------------------------------------
+
+override CFLAGS += -g -fexceptions  
+override CFLAGS += -I$(srcdir) -DFRONTEND -DSYSCONFDIR='"$(sysconfdir)"' 
+override CFLAGS += -DUSE_VERSION=$(USE_VERSION)
+
+ifeq ($(USE_GEOS),1)
+       override CFLAGS += -I$(GEOS_DIR)/include/geos -DUSE_GEOS
+endif
+ifeq ($(USE_PROJ),1)
+       override CFLAGS += -I$(PROJ_DIR)/include -DUSE_PROJ 
+endif
+
+override DLLLIBS += $(BE_DLLLIBS) 
+
+override CXXFLAGS := $(CFLAGS)
+# memory debug for gcc 2.91, 2.95, 3.0 and 3.1
+# for gcc >= 3.2.2 set GLIBCPP_FORCE_NEW at runtime instead
+#override CXXFLAGS += -D__USE_MALLOC
+
+#---------------------------------------------------------------
+# Add index selectivity to C flags
+#
+ifeq ($(USE_STATS),1)
+       override CFLAGS += -DUSE_STATS
+endif
+#---------------------------------------------------------------
+# Select proper GiST support C file
+#
+ifeq ($(USE_VERSION),71) 
+       GIST_SUPPORT=71
+       GIST_ESTIMATE=
+else
+       GIST_SUPPORT=72
+       GIST_ESTIMATE=postgis_estimate.o
+endif
+
+ifeq ($(USE_GEOS),1)
+       GEOS_WRAPPER=postgis_geos_wrapper.o
+endif
+
+OBJS=lwgeom_api.o lwgeom_functions_analytic.o lwgeom_geos.o lwgeom_inout.o lwgeom_estimate.o lwgeom_functions_basic.o lwgeom_gist.o lwgeom_transform.o
+
+
+
+#---------------------------------------------------------------
+# Add libraries that libpq depends (or might depend) on into the
+# shared library link.  (The order in which you list them here doesn't
+# matter.)
+
+SHLIB_LINK = $(filter -L%, $(LDFLAGS)) 
+ifeq ($(USE_GEOS),1)
+       SHLIB_LINK += -lstdc++ -L$(GEOS_DIR)/lib -lgeos
+endif
+ifeq ($(USE_PROJ),1)
+       SHLIB_LINK += -L$(PROJ_DIR)/lib -lproj
+endif
+SHLIB_LINK += $(BE_DLLLIBS) 
+
+#---------------------------------------------------------------
+# Makefile targets
+
+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
+
+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'  > $@ 
+
+#postgis_new.sql: postgis.sql.in
+#      cpp -P -traditional-cpp -DUSE_VERSION=$(USE_VERSION) -DMODULE_FILENAME="'$(MODULE_FILENAME)'" -DPOSTGIS_VERSION="'$(POSTGIS_VERSION)'" $< > $@
+
+#postgis_undef.sql: postgis.sql create_undef.pl
+#      perl create_undef.pl $< $(USE_VERSION) > $@ 
+
+#install: all installdirs install-postgis-lib
+#      $(INSTALL_DATA) postgis.sql $(DESTDIR)$(datadir)
+#      $(INSTALL_DATA) postgis_undef.sql $(DESTDIR)$(datadir)
+#      $(INSTALL_DATA) spatial_ref_sys.sql $(DESTDIR)$(datadir)
+#      $(INSTALL_DATA) README.postgis $(DESTDIR)$(datadir)
+#      $(MAKE) DESTDIR=$(DESTDIR) -C loader install
+
+#- This has been copied from postgresql and adapted
+install-postgis-lib: $(shlib)
+       $(INSTALL_SHLIB) $< $(DESTDIR)$(MODULE_INSTALLDIR)/$(shlib)
+ifneq ($(PORTNAME), win)
+ifneq ($(shlib), lib$(NAME)$(DLSUFFIX).$(SO_MAJOR_VERSION))
+       cd $(DESTDIR)$(MODULE_INSTALLDIR) && \
+       rm -f lib$(NAME)$(DLSUFFIX).$(SO_MAJOR_VERSION) && \
+       $(LN_S) $(shlib) lib$(NAME)$(DLSUFFIX).$(SO_MAJOR_VERSION)
+endif
+ifneq ($(shlib), lib$(NAME)$(DLSUFFIX))
+       cd $(DESTDIR)$(MODULE_INSTALLDIR) && \
+       rm -f lib$(NAME)$(DLSUFFIX) && \
+       $(LN_S) $(shlib) lib$(NAME)$(DLSUFFIX)
+endif
+
+endif # not win
+#----------------------------------------------------------
+
+installdirs:
+       $(mkinstalldirs) $(docdir)/contrib $(datadir)/contrib $(libdir)
+
+#uninstall: uninstall-lib
+#      @rm -f $(docdir)/contrib/README.postgis $(datadir)/contrib/postgis.sql
+
+clean distclean maintainer-clean: clean-lib
+       @rm -f $(OBJS) 
+#      $(MAKE) -C loader clean
+#      $(MAKE) -C doc clean
+
index 86406219ffe7007070d832ed41295f522d955c2d..a7ac0710ec7572a6e20f2f06d094b6d0e14b4f66 100644 (file)
@@ -3,6 +3,10 @@
 // basic API for handling the LWGEOM, BOX2DFLOAT4, LWPOINT, LWLINE, and LWPOLY.
 // See below for other support types like POINTARRAY and LWGEOM_INSPECTED
 
+#include <sys/types.h>
+#include "utils/geo_decls.h"
+
+
 
 typedef struct
 {
@@ -13,6 +17,13 @@ typedef struct
 } BOX2DFLOAT4;
 
 
+typedef struct
+{
+        double xmin, ymin, zmin;
+        double xmax, ymax, zmax;
+} BOX3D;
+
+
 // POINT3D already defined in postgis.h
 // ALL LWGEOM structures will use POINT3D as an abstract point.
 // This means a 2d geometry will be stored as (x,y) in its serialized
@@ -21,7 +32,7 @@ typedef struct
 // NOTE: for GEOS integration, we'll probably set z=NaN
 //        so look out - z might be NaN for 2d geometries!
 
-// typedef struct {    double  x,y,z;  } POINT3D;
+ typedef struct {      double  x,y,z;  } POINT3D;
 
 
 // type for 2d points.  When you convert this to 3d, the
@@ -41,37 +52,42 @@ typedef struct
 {
     char  *serialized_pointlist; // probably missaligned. 2d or 3d.  points to a double
     char  is3d; // true if these are 3d points
-    int32 npoints;
+    uint32 npoints;
 }  POINTARRAY;
 
 // copies a point from the point array into the parameter point
 // will set point's z=0 (or NaN) if pa is 2d
 // NOTE: point is a real POINT3D *not* a pointer
-extern POINT3D getPoint3d(POINTARRAY pa, int n);
+extern POINT3D getPoint3d(POINTARRAY *pa, int n);
 
 // copies a point from the point array into the parameter point
 // will set point's z=0 (or NaN) if pa is 2d
 // NOTE: this will modify the point3d pointed to by 'point'.
-extern void getPoint3d_p(POINTARRAY pa, int n, POINT3D *point);
+extern void getPoint3d_p(POINTARRAY *pa, int n, char *point);
 
 
 // copies a point from the point array into the parameter point
 // z value (if present is not returned)
 // NOTE: point is a real POINT3D *not* a pointer
-extern POINT2D getPoint2d(POINTARRAY pa, int n);
+extern POINT2D getPoint2d(POINTARRAY *pa, int n);
 
 // copies a point from the point array into the parameter point
 // z value (if present is not returned)
 // NOTE: this will modify the point2d pointed to by 'point'.
-extern void getPoint2d_p(POINTARRAY pa, int n, POINT2D *point);
+extern void getPoint2d_p(POINTARRAY *pa, int n, char *point);
 
 
 // constructs a POINTARRAY.
 // NOTE: points is *not* copied, so be careful about modification (can be aligned/missaligned)
 // NOTE: is3d is descriptive - it describes what type of data 'points'
 //       points to.  No data conversion is done.
-extern POINTARRAY pointArray_construct(char *points, char is3d, int npoints);
+extern POINTARRAY *pointArray_construct(char *points, char is3d, uint32 npoints);
 
+//calculate the bounding box of a set of points
+// returns a 3d box
+// if pa is 2d, then box3d's zmin/zmax will be either 0 or NaN
+// dont call on an empty pa
+extern BOX3D *pointArray_bbox(POINTARRAY *pa);
 
 /*
 
@@ -98,7 +114,7 @@ WHERE
 */
 
 
-/* already defined in postgis.h
+// already defined in postgis.h
 
  #define       POINTTYPE       1
  #define       LINETYPE        2
@@ -108,13 +124,13 @@ WHERE
  #define       MULTIPOLYGONTYPE        6
  #define       COLLECTIONTYPE  7
 
-*/
+
 
 
 extern bool lwgeom_hasSRID(char type); // true iff S bit is set
 extern bool lwgeom_is3d(char type);    // true iff D bit is set
-extern int     lwgeom_getType(char type); // returns the tttt value
-
+extern int  lwgeom_getType(char type); // returns the tttt value
+extern char lwgeom_makeType(char is3d, char hasSRID, int type);
 
 
 // all the base types (point/line/polygon) will have a
@@ -127,29 +143,33 @@ extern int     lwgeom_getType(char type); // returns the tttt value
 
 typedef struct
 {
-       char        is3d;   // true means points represent 3d points
-       int         SRID;   // spatial ref sys -1=none
-       POINTARRAY *points; // array of POINT3D
+       char          is3d;   // true means points represent 3d points
+       int  SRID;   // spatial ref sys -1=none
+       POINTARRAY    *points; // array of POINT3D
 } LWLINE; //"light-weight line"
 
 // construct a new LWLINE.  points will be copied
 // use SRID=-1 for unknown SRID (will have 8bit type's S = 0)
-extern LWLINE lwline_construct(char is3d, int SRID, int npoints, POINTARRAY *points);
+extern LWLINE *lwline_construct(char is3d, int SRID, POINTARRAY *points);
 
 // given the LWGEOM serialized form (or a pointer into a muli* one)
 // construct a proper LWLINE.
 // serialized_form should point to the 8bit type format (with type = 2)
 // See serialized form doc
-extern LWLINE lwline_deserialize(char *serialized_form);
+extern LWLINE *lwline_deserialize(char *serialized_form);
 
 // convert this line into its serialize form
 // result's first char will be the 8bit type.  See serialized form doc
+// copies data.
 extern char  *lwline_serialize(LWLINE *line);
 
 // find bounding box (standard one)  zmin=zmax=0 if 2d (might change to NaN)
 extern BOX3D *lwline_findbbox(LWLINE *line);
 
 
+//find length of this serialized line
+extern uint32 lwline_findlength(char *serialized_line);
+
 //--------------------------------------------------------
 
 typedef struct
@@ -159,15 +179,15 @@ typedef struct
        POINTARRAY  *point;  // hide 2d/3d (this will be an array of 1 point)
 }  LWPOINT; // "light-weight point"
 
-// construct a new point.  point will be copied
+// 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, POINT3D *point);
 
 // given the LWPOINT serialized form (or a pointer into a muli* one)
 // construct a proper LWPOINT.
 // serialized_form should point to the 8bit type format (with type = 1)
 // See serialized form doc
-extern LWPOINT lwpoint_deserialize(char *serialized_form);
+extern LWPOINT *lwpoint_deserialize(char *serialized_form);
 
 // convert this line into its serialize form
 // result's first char will be the 8bit type.  See serialized form doc
@@ -180,31 +200,44 @@ extern BOX3D *lwpoint_findbbox(LWPOINT *point);
 extern POINT2D lwpoint_getPoint2d(LWPOINT *point);
 extern POINT3D lwpoint_getPoint3d(LWPOINT *point);
 
+//find length of this serialized point
+extern uint32 lwpoint_findlength(char *serialized_line);
+
 //--------------------------------------------------------
 
+//DONT MIX 2D and 3D POINTS!  *EVERYTHING* is either one or the other
 
 typedef struct
 {
+       int32 SRID;
        char is3d;
-       int  SRID;
        int  nrings;
        POINTARRAY **rings; // list of rings (list of points)
 } LWPOLY; // "light-weight polygon"
 
 // construct a new LWLINE.  arrays (points/points per ring) will NOT be copied
 // use SRID=-1 for unknown SRID (will have 8bit type's S = 0)
-extern LWLINE lwpoly_construct(char is3d, int SRID, int nrings,POINTARRAY **points);
+extern LWPOLY *lwpoly_construct(char is3d, int SRID, int nrings,POINTARRAY **points);
 
 
 // given the LWPOLY serialized form (or a pointer into a muli* one)
 // construct a proper LWPOLY.
 // serialized_form should point to the 8bit type format (with type = 3)
 // See serialized form doc
-extern LWPOLY lwpoly_deserialize(char *serialized_form);
+extern LWPOLY *lwpoly_deserialize(char *serialized_form);
+
+// create the serialized form of the polygon
+// result's first char will be the 8bit type.  See serialized form doc
+// points copied
+extern char *lwpoly_serialize(LWPOLY *poly);
+
 
 // find bounding box (standard one)  zmin=zmax=0 if 2d (might change to NaN)
-extern BOX3D *lwpoly_findbbox(LWPOLY *line);
+extern BOX3D *lwpoly_findbbox(LWPOLY *poly);
+
 
+//find length of this serialized polygon
+extern uint32 lwpoly_findlength(char *serialized_line);
 
 
 //------------------------------------------------------
@@ -226,6 +259,7 @@ extern BOX3D *lwpoly_findbbox(LWPOLY *line);
 // use this version for speed.  READ-ONLY!
 typedef struct
 {
+       int   SRID;
        char  *serialized_form; // orginal structure
        char  type;            // 8-bit type for the LWGEOM
        int   ngeometries;     // number of sub-geometries
@@ -237,29 +271,29 @@ typedef struct
 // This function just computes the length of each sub-object and pre-caches this info.
 // For a geometry collection of multi* geometries, you can inspect the sub-components
 // as well.
-extern LWGEOM_INSPECTED lwgeom_inspect(char *serialized_form);
+extern LWGEOM_INSPECTED *lwgeom_inspect(char *serialized_form);
 
 
 // 1st geometry has geom_number = 0
 // if the actual sub-geometry isnt a POINT, null is returned (see _gettype()).
 // if there arent enough geometries, return null.
 // this is fine to call on a point (with geom_num=0), multipoint or geometrycollection
-extern LWPOINT lwgeom_getpoint(char *serialized_form, int geom_number);
-extern LWPOINT lwgeom_getpoint_inspected(LWGEOM_INSPECTED *inspected, int geom_number);
+extern LWPOINT *lwgeom_getpoint(char *serialized_form, int geom_number);
+extern LWPOINT *lwgeom_getpoint_inspected(LWGEOM_INSPECTED *inspected, int geom_number);
 
 // 1st geometry has geom_number = 0
 // if the actual geometry isnt a LINE, null is returned (see _gettype()).
 // if there arent enough geometries, return null.
 // this is fine to call on a line, multiline or geometrycollection
-extern LWLINE lwgeom_getline(char *serialized_form, int geom_number);
-extern LWLINE lwgeom_getline_inspected(LWGEOM_INSPECTED *inspected, int geom_number);
+extern LWLINE *lwgeom_getline(char *serialized_form, int geom_number);
+extern LWLINE *lwgeom_getline_inspected(LWGEOM_INSPECTED *inspected, int geom_number);
 
 // 1st geometry has geom_number = 0
 // if the actual geometry isnt a POLYGON, null is returned (see _gettype()).
 // if there arent enough geometries, return null.
 // this is fine to call on a polygon, multipolygon or geometrycollection
-extern LWPOLY lwgeom_getpoly(char *serialized_form, int geom_number);
-extern LWPOLY lwgeom_getpoly_inspected(LWGEOM_INSPECTED *inspected, int geom_number);
+extern LWPOLY *lwgeom_getpoly(char *serialized_form, int geom_number);
+extern LWPOLY *lwgeom_getpoly_inspected(LWGEOM_INSPECTED *inspected, int geom_number);
 
 // this gets the serialized form of a sub-geometry
 // 1st geometry has geom_number = 0
@@ -283,8 +317,8 @@ extern char *lwgeom_getsubgeometry_inspected(LWGEOM_INSPECTED *inspected, int ge
 //   ie lwgeom_gettype( <'MULTIPOINT(0 0, 1 1)'>, 0)
 //                 --> point
 // gets the 8bit type of the geometry at location geom_number
-extern char lwgeom_gettype(char *serialized_form, int geom_number);
-extern char lwgeom_gettype_inspected(LWGEOM_INSPECTED *inspected, int geom_number);
+extern char lwgeom_getsubtype(char *serialized_form, int geom_number);
+extern char lwgeom_getsubtype_inspected(LWGEOM_INSPECTED *inspected, int geom_number);
 
 
 // how many sub-geometries are there?
@@ -293,17 +327,17 @@ extern int lwgeom_getnumgeometries(char *serialized_form);
 extern int lwgeom_getnumgeometries_inspected(LWGEOM_INSPECTED *inspected);
 
 
-// set finalType to 0 and this will choose an appropriate type
-//  if you specify a wrong type, the best type will be chosen
-//   (ie. give it 2 points and ask it to be a multilinestring)
+
+// set finalType to COLLECTIONTYPE or 0 (0 means choose a best type)
+//   (ie. give it 2 points and ask it to be a multipoint)
 //  use SRID=-1 for unknown SRID  (will have 8bit type's S = 0)
 // all subgeometries must have the same SRID
 // if you want to construct an inspected, call this then inspect the result...
-extern char *lwgeom_construct(int SRID,int finalType, int nsubgeometries, char **serialized_subs);
+extern char *lwgeom_construct(int SRID,int finalType,char is3d, int nsubgeometries, char **serialized_subs);
 
 
 // construct the empty geometry (GEOMETRYCOLLECTION(EMPTY))
-extern char *lwgeom_constructempty();
+extern char *lwgeom_constructempty(int SRID,char is3d);
 
 // helper function (not for general use)
 // find the size a geometry (or a sub-geometry)
@@ -313,13 +347,14 @@ extern char *lwgeom_constructempty();
 //                 --> size of the multipoint
 //   ie lwgeom_gettype( <'MULTIPOINT(0 0, 1 1)'>, 0)
 //                 --> size of the point
+extern int lwgeom_seralizedformlength_simple(char *serialized_form);
 extern int lwgeom_seralizedformlength(char *serialized_form, int geom_number);
 extern int lwgeom_seralizedformlength_inspected(LWGEOM_INSPECTED *inspected, int geom_number);
 
 
 //get bounding box of LWGEOM (automatically calls the sub-geometries bbox generators)
-extern BOX3D lw_geom_getBB(char *serialized_form);
-extern BOX3D lw_geom_getBB_inspected(LWGEOM_INSPECTED *inspected);
+extern BOX3D *lw_geom_getBB(char *serialized_form);
+extern BOX3D *lw_geom_getBB_inspected(LWGEOM_INSPECTED *inspected);
 
 
 //------------------------------------------------------
@@ -333,7 +368,20 @@ extern BOX2DFLOAT4 box3d_to_box2df(BOX3D *box);
 extern BOX2DFLOAT4 box_to_box2df(BOX *box);  // postgresql standard type
 
 extern BOX3D box2df_to_box3d(BOX2DFLOAT4 *box);
-extern BOX   box2df_to_box(BOX *box);  // postgresql standard type
+extern BOX   box2df_to_box(BOX2DFLOAT4 *box);  // postgresql standard type
+extern BOX3D *combine_boxes(BOX3D *b1, BOX3D *b2);
+
+
+//****************************************************************
+// memory management -- these only delete the memory associated
+//  directly with the structure - NOT the stuff pointing into
+//  the original de-serialized info
+
+extern void pfree_inspected(LWGEOM_INSPECTED *inspected);
+extern void pfree_point    (LWPOINT *pt);
+extern void pfree_line     (LWLINE  *line);
+extern void pfree_polygon  (LWPOLY  *poly);
+extern void pfree_POINTARRAY(POINTARRAY *pa);
 
 
 
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e8283bdafa2bf11ffad1f4b074dd7d653544e1e5 100644 (file)
+
+#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 float nextDown_f(double d);
+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);
+
+
+// this will change to NaN when I figure out how to
+// get NaN in a platform-independent way
+
+#define NO_Z_VALUE 0
+
+
+//*********************************************************************
+// BOX routines
+
+// returns the float thats very close to the input, but <=
+//  handles the funny differences in float4 and float8 reps.
+float nextDown_f(double d)
+{
+       float result  = d;
+
+       if ( ((double) result) <=d)
+               return result;
+
+       return nextafterf(result, result - 1000000);
+}
+
+// returns the float thats very close to the input, but >=
+//  handles the funny differences in float4 and float8 reps.
+float nextUp_f(double d)
+{
+               float result  = d;
+
+               if ( ((double) result) >=d)
+                       return result;
+
+               return nextafterf(result, result + 1000000);
+}
+
+
+// returns the double thats very close to the input, but <
+//  handles the funny differences in float4 and float8 reps.
+double nextDown_d(float d)
+{
+               double result  = d;
+
+               if ( result < d)
+                       return result;
+
+               return nextafterf(result, result - 1000000);
+}
+
+// returns the double thats very close to the input, but >
+//  handles the funny differences in float4 and float8 reps.
+double nextUp_d(float d)
+{
+                       double result  = d;
+
+                       if ( result > d)
+                               return result;
+
+                       return nextafterf(result, result + 1000000);
+}
+
+
+BOX2DFLOAT4 box3d_to_box2df(BOX3D *box)
+{
+       BOX2DFLOAT4 result;
+
+       if (box == NULL)
+               return result;
+
+       result.xmin = nextDown_f(box->xmin);
+       result.ymin = nextDown_f(box->ymin);
+
+       result.xmax = nextUp_f(box->xmax);
+       result.ymax = nextUp_f(box->ymax);
+
+       return result;
+}
+
+
+BOX2DFLOAT4 box_to_box2df(BOX *box)
+{
+       BOX2DFLOAT4 result;
+
+       if (box == NULL)
+               return result;
+
+       result.xmin = nextDown_f(box->low.x);
+       result.ymin = nextDown_f(box->low.y);
+
+       result.xmax = nextUp_f(box->high.x);
+       result.ymax = nextUp_f(box->high.x);
+
+       return result;
+}
+
+BOX3D box2df_to_box3d(BOX2DFLOAT4 *box)
+{
+       BOX3D result;
+
+       if (box == NULL)
+               return result;
+
+       result.xmin = nextDown_d(box->xmin);
+       result.ymin = nextDown_d(box->ymin);
+
+       result.xmax = nextUp_d(box->xmax);
+       result.ymax = nextUp_d(box->ymax);
+
+       return result;
+}
+
+BOX   box2df_to_box(BOX2DFLOAT4 *box)
+{
+       BOX result;
+
+       if (box == NULL)
+               return result;
+
+       result.low.x = nextDown_d(box->xmin);
+       result.low.y = nextDown_d(box->ymin);
+
+       result.high.x = nextUp_d(box->xmax);
+       result.high.y = nextUp_d(box->ymax);
+
+       return result;
+}
+
+BOX3D *combine_boxes(BOX3D *b1, BOX3D *b2)
+{
+       BOX3D *result;
+
+       result =(BOX3D*) palloc(sizeof(BOX3D));
+
+       if ( (b1 == NULL) && (b2 == NULL) )
+       {
+               return NULL;
+       }
+
+       if  (b1 == NULL)
+       {
+               //return b2
+               memcpy(result, b2, sizeof(BOX3D));
+       }
+       if (b2 == NULL)
+       {
+               //return b1
+               memcpy(result, b1, sizeof(BOX3D));
+       }
+
+       if (b1->xmin < b2->xmin)
+               result->xmin = b1->xmin;
+       else
+               result->xmin = b2->xmin;
+
+       if (b1->ymin < b2->ymin)
+                       result->ymin = b1->ymin;
+       else
+               result->ymin = b2->ymin;
+
+
+       if (b1->xmax > b2->xmax)
+               result->xmax = b1->xmax;
+       else
+               result->ymax = b2->ymax;
+       if (b1->ymax > b2->ymax)
+                               result->ymax = b1->ymax;
+       else
+               result->ymax = b2->ymax;
+
+       if (b1->zmax > b2->zmax)
+                       result->zmax = b1->zmax;
+       else
+                       result->zmax = b2->zmax;
+       if (b1->zmin > b2->zmin)
+                       result->zmin = b1->zmin;
+       else
+               result->zmin = b2->zmin;
+
+       return result;
+}
+
+
+//************************************************************************
+// POINTARRAY support functions
+
+
+
+// copies a point from the point array into the parameter point
+// will set point's z=0 (or NaN) if pa is 2d
+// NOTE: point is a real POINT3D *not* a pointer
+ POINT3D getPoint3d(POINTARRAY *pa, int n)
+ {
+        POINT3D result;
+        int size;
+
+        if ( (n<0) || (n>=pa->npoints))
+        {
+                return result; //error
+        }
+
+        size = sizeof(double)*2; // x,y
+        if (pa->is3d)
+               size += sizeof(double); //(x,y) & z
+
+               // this does x,y
+        memcpy(&result.x, &pa->serialized_pointlist[size*n],sizeof(double)*2 );
+        if (pa->is3d)
+               memcpy(&result.z, &pa->serialized_pointlist[size*n + sizeof(double)*2],sizeof(double) );
+        else
+               result.z = NO_Z_VALUE;
+        return result;
+ }
+
+// copies a point from the point array into the parameter point
+// will set point's z=0 (or NaN) if pa is 2d
+// NOTE: this will modify the point3d pointed to by 'point'.
+// we use a char* instead of a POINT3D because we want to use this function
+//  for serialization/de-serialization
+void getPoint3d_p(POINTARRAY *pa, int n, char *point)
+{
+       int size;
+
+        if ( (n<0) || (n>=pa->npoints))
+        {
+                return ; //error
+        }
+
+        size = sizeof(double)*2; // x,y
+        if (pa->is3d)
+               size += sizeof(double); //(x,y) & z
+
+               // this does x,y
+        memcpy(point, &pa->serialized_pointlist[size*n],sizeof(double)*2 );
+        if (pa->is3d)
+               memcpy(point+16, &pa->serialized_pointlist[size*n + sizeof(double)*2],sizeof(double) );
+        else
+        {
+                double bad=NO_Z_VALUE;
+               memcpy(point+24, &bad,sizeof(double) );
+               //point->z = NO_Z_VALUE;
+        }
+ }
+
+
+// copies a point from the point array into the parameter point
+// z value (if present is not returned)
+// NOTE: point is a real POINT3D *not* a pointer
+POINT2D getPoint2d(POINTARRAY *pa, int n)
+{
+                POINT2D result;
+                int size;
+
+                if ( (n<0) || (n>=pa->npoints))
+                {
+                        return result; //error
+                }
+
+                size = sizeof(double)*2; // x,y
+                if (pa->is3d)
+                       size += sizeof(double); //(x,y) & z
+
+                       // this does x,y
+                memcpy(&result.x, &pa->serialized_pointlist[size*n],sizeof(double)*2 );
+                return result;
+}
+
+// copies a point from the point array into the parameter point
+// z value (if present is not returned)
+// NOTE: this will modify the point2d pointed to by 'point'.
+// we use a char* instead of a POINT2D because we want to use this function
+//  for serialization/de-serialization
+void getPoint2d_p(POINTARRAY *pa, int n, char *point)
+{
+                int size;
+
+                if ( (n<0) || (n>=pa->npoints))
+                {
+                        return; //error
+                }
+
+                size = sizeof(double)*2; // x,y
+                if (pa->is3d)
+                       size += sizeof(double); //(x,y) & z
+
+                       // this does x,y
+                memcpy(point, &pa->serialized_pointlist[size*n],sizeof(double)*2 );
+}
+
+
+// constructs a POINTARRAY.
+// NOTE: points is *not* copied, so be careful about modification (can be aligned/missaligned)
+// NOTE: is3d is descriptive - it describes what type of data 'points'
+//       points to.  No data conversion is done.
+POINTARRAY *pointArray_construct(char *points, char is3d, uint32 npoints)
+{
+       POINTARRAY  *pa;
+       pa = (POINTARRAY*)palloc(sizeof(pa));
+
+       pa->is3d = is3d;
+       pa->npoints = npoints;
+       pa->serialized_pointlist = points;
+
+       return pa;
+}
+
+//calculate the bounding box of a set of points
+// returns a postgresql box
+BOX3D *pointArray_bbox(POINTARRAY *pa)
+{
+       int t;
+       BOX3D *result;
+       POINT3D pt;
+
+       result = (BOX3D*) palloc(sizeof(BOX3D));
+
+       if (pa->npoints ==0)
+               return result;
+
+       getPoint3d_p(pa,0,(char*)&pt);
+       result->xmin = pt.x;
+       result->ymin = pt.y;
+       result->zmin = pt.z;
+
+       result->xmax = pt.x;
+       result->ymax = pt.y;
+       result->zmax = pt.z;
+
+       for (t=0;t<pa->npoints;t++)
+       {
+               getPoint3d_p(pa,t,(char*)&pt);
+               if (pt.x < result->xmin)
+                       result->xmin = pt.x;
+               if (pt.y < result->ymin)
+                       result->ymin = pt.y;
+               if (pt.x > result->xmax)
+                       result->xmax = pt.x;
+               if (pt.y > result->ymax)
+                       result->ymax = pt.y;
+
+               if (pt.z > result->zmax)
+                       result->zmax = pt.z;
+               if (pt.z < result->zmax)
+                       result->zmax = pt.z;
+       }
+       return result;
+}
+
+
+
+//***************************************************************************
+// basic type handling
+
+
+bool lwgeom_hasSRID(char type)
+{
+       return (type & 0x20);
+}
+
+bool lwgeom_is3d(char type)
+{
+       return (type & 0x10);
+}
+
+int  lwgeom_getType(char type)
+{
+       return (type & 0x0F);
+}
+
+char lwgeom_makeType(char is3d, char hasSRID, int type)
+{
+       char result = type;
+
+       if (is3d)
+               result = result | 0x10;
+       if (hasSRID)
+               result = result | 0x20;
+
+       return result;
+}
+
+//*****************************************************************************
+// basic sub-geometry types
+
+// handle missaligned unsigned int32 data
+uint32 get_uint32(char *loc)
+{
+       uint32 result;
+
+       memcpy(&result,loc, sizeof(uint32));
+       return result;
+}
+
+// handle missaligned signed int32 data
+int32 get_int32(char *loc)
+{
+       int32 result;
+
+       memcpy(&result,loc, sizeof(int32));
+       return result;
+}
+
+
+
+//******************************************************************************
+// basic LWLINE functions
+
+
+// construct a new LWLINE.  points will be copied
+// use SRID=-1 for unknown SRID (will have 8bit type's S = 0)
+LWLINE *lwline_construct(char is3d, int SRID,  POINTARRAY *points)
+{
+       LWLINE *result;
+       result = (LWLINE*) palloc( sizeof(LWLINE));
+
+       result->is3d =is3d;
+       result->SRID = SRID;
+       result->points = points;
+
+       return result;
+}
+
+// given the LWGEOM serialized form (or a pointer into a muli* one)
+// construct a proper LWLINE.
+// serialized_form should point to the 8bit type format (with type = 2)
+// See serialized form doc
+LWLINE *lwline_deserialize(char *serialized_form)
+{
+       char type;
+       LWLINE *result;
+       char *loc =NULL;
+       uint32 npoints;
+       POINTARRAY *pa;
+
+       result = (LWLINE*) palloc( sizeof(LWLINE)) ;
+
+       type = serialized_form[0];
+
+
+       if ( lwgeom_getType(type) != LINETYPE)
+               return NULL;
+
+       if ( lwgeom_hasSRID(type))
+       {
+               result->SRID = get_int32(loc+1);
+               loc = serialized_form+ 5; // type + SRID
+       }
+       else
+       {
+               result->SRID = -1;
+               loc = serialized_form +1;
+       }
+
+       // we've read the type (1 byte) and SRID (4 bytes, if present)
+
+       npoints = get_uint32(loc);
+       loc +=4;
+       pa = pointArray_construct( loc, lwgeom_is3d(type), npoints);
+
+       result->points = pa;
+       result->is3d = lwgeom_is3d(type);
+
+       return result;
+}
+
+// convert this line into its serialize form
+// result's first char will be the 8bit type.  See serialized form doc
+char  *lwline_serialize(LWLINE *line)
+{
+       int size=1;  // type byte
+       char hasSRID;
+       char * result;
+       int t;
+       char *loc;
+
+       hasSRID = (line->SRID != -1);
+
+       if (hasSRID)
+               size +=4;  //4 byte SRID
+
+       if (line->is3d)
+       {
+               size += 24 * line->points->npoints; //x,y,z
+       }
+       else
+       {
+               size += 16 * line->points->npoints; //x,y,z
+       }
+
+       result = palloc(size);
+
+       result[0] = lwgeom_makeType(line->is3d,hasSRID, LINETYPE);
+       loc = result+1;
+
+       if (hasSRID)
+       {
+               memcpy(loc, &line->SRID, sizeof(int32));
+               loc += 4;
+       }
+
+       //copy in points
+
+       if (line->is3d)
+       {
+               for (t=0; t< line->points->npoints;t++)
+               {
+                       getPoint3d_p(line->points, t, loc);
+                       loc += 24; // size of a 3d point
+               }
+       }
+       else
+       {
+               for (t=0; t< line->points->npoints;t++)
+               {
+                       getPoint2d_p(line->points, t, loc);
+                       loc += 16; // size of a 2d point
+               }
+       }
+       return result;
+}
+
+// find bounding box (standard one)  zmin=zmax=0 if 2d (might change to NaN)
+BOX3D *lwline_findbbox(LWLINE *line)
+{
+       if (line == NULL)
+               return NULL;
+
+       return pointArray_bbox(line->points);
+}
+
+//find length of this serialized line
+uint32 lwline_findlength(char *serialized_line)
+{
+               int type = serialized_line[0];
+               uint32 result =1;  //type
+               char *loc;
+               uint32 npoints;
+
+               if ( lwgeom_getType(type) != LINETYPE)
+                       return -9999;
+
+               if ( lwgeom_hasSRID(type))
+               {
+                       loc = serialized_line+ 5; // type + SRID
+                       result +=4;
+               }
+               else
+               {
+                       loc = serialized_line +1;
+               }
+
+               // we've read the type (1 byte) and SRID (4 bytes, if present)
+
+               npoints = get_uint32(loc);
+               if (lwgeom_is3d(type) )
+               {
+                       return result + npoints * 24;
+               }
+               else
+               {
+                       return result+ npoints * 16;
+               }
+}
+
+//********************************************************************
+// support for the LWPOINT sub-type
+
+// 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 *result ;
+       POINTARRAY *pa;
+
+       if (point == NULL)
+               return NULL; // error
+
+       result = palloc(sizeof(LWPOINT));
+       result->is3d = is3d;
+       result->SRID = SRID;
+
+       pa =pointArray_construct((char *)point, is3d, 1);
+
+       result->point = pa;
+
+       return result;
+}
+
+// given the LWPOINT serialized form (or a pointer into a muli* one)
+// construct a proper LWPOINT.
+// serialized_form should point to the 8bit type format (with type = 1)
+// See serialized form doc
+LWPOINT *lwpoint_deserialize(char *serialized_form)
+{
+               char type;
+               LWPOINT *result;
+               char *loc = NULL;
+               POINTARRAY *pa;
+
+               result = (LWPOINT*) palloc( sizeof(LWPOINT)) ;
+
+               type = serialized_form[0];
+
+
+               if ( lwgeom_getType(type) != POINTTYPE)
+                       return NULL;
+
+               if ( lwgeom_hasSRID(type))
+               {
+                       result->SRID = get_int32(loc+1);
+                       loc = serialized_form+ 5; // type + SRID
+               }
+               else
+               {
+                       result->SRID = -1;
+                       loc = serialized_form +1;
+               }
+
+               // we've read the type (1 byte) and SRID (4 bytes, if present)
+
+               pa = pointArray_construct( loc, lwgeom_is3d(type), 1);
+
+               result->point = pa;
+               result->is3d = lwgeom_is3d(type);
+
+       return result;
+
+}
+
+// convert this line into its serialize form
+// result's first char will be the 8bit type.  See serialized form doc
+char  *lwpoint_serialize(LWPOINT *point)
+{
+               int size=1;  // type byte
+               char hasSRID;
+               char * result;
+               char *loc;
+
+               hasSRID = (point->SRID != -1);
+
+               if (hasSRID)
+                       size +=4;  //4 byte SRID
+
+               if (point->is3d)
+               {
+                       size += 24; //x,y,z
+               }
+               else
+               {
+                       size += 16 ; //x,y,z
+               }
+
+               result = palloc(size);
+
+               result[0] = lwgeom_makeType(point->is3d,hasSRID, POINTTYPE);
+               loc = result+1;
+
+               if (hasSRID)
+               {
+                       memcpy(loc, &point->SRID, sizeof(int32));
+                       loc += 4;
+               }
+
+               //copy in points
+
+               if (point->is3d)
+               {
+                               getPoint3d_p(point->point, 0, loc);
+               }
+               else
+               {
+
+                               getPoint2d_p(point->point, 0, loc);
+               }
+       return result;
+}
+
+// find bounding box (standard one)  zmin=zmax=0 if 2d (might change to NaN)
+BOX3D *lwpoint_findbbox(LWPOINT *point)
+{
+       if (point == NULL)
+                       return NULL;
+
+       return pointArray_bbox(point->point);
+}
+
+// convenience functions to hide the POINTARRAY
+POINT2D lwpoint_getPoint2d(LWPOINT *point)
+{
+       POINT2D result;
+
+       if (point == NULL)
+                       return result;
+
+       return getPoint2d(point->point,0);
+}
+
+POINT3D lwpoint_getPoint3d(LWPOINT *point)
+{
+       POINT3D result;
+
+       if (point == NULL)
+                       return result;
+
+       return getPoint3d(point->point,0);
+}
+
+
+//find length of this serialized point
+uint32 lwpoint_findlength(char *serialized_point)
+{
+               uint  result = 1; // type char
+               char type;
+               char *loc;
+
+
+               type = serialized_point[0];
+
+
+               if ( lwgeom_getType(type) != POINTTYPE)
+                       return -9999;
+
+               if ( lwgeom_hasSRID(type))
+               {
+                       loc = serialized_point+ 5; // type + SRID
+                       result +=4;
+               }
+               else
+               {
+                       loc = serialized_point +1;
+               }
+
+               if (lwgeom_is3d(type))
+               {
+                       return result + 24;
+               }
+               else
+               {
+                       return result + 16;
+               }
+}
+
+
+//********************************************************************
+// basic polygon manipulation
+
+// construct a new LWLINE.  arrays (points/points per ring) will NOT be copied
+// use SRID=-1 for unknown SRID (will have 8bit type's S = 0)
+LWPOLY *lwpoly_construct(char is3d, int SRID, int nrings,POINTARRAY **points)
+{
+       LWPOLY *result;
+
+       result = (LWPOLY*) palloc(sizeof(LWPOLY));
+       result->is3d = is3d;
+       result->SRID = SRID;
+       result->nrings = nrings;
+       result->rings = points;
+
+       return result;
+}
+
+
+// given the LWPOLY serialized form (or a pointer into a muli* one)
+// construct a proper LWPOLY.
+// serialized_form should point to the 8bit type format (with type = 3)
+// See serialized form doc
+LWPOLY *lwpoly_deserialize(char *serialized_form)
+{
+
+       LWPOLY *result;
+       uint32 nrings;
+       bool   is3d;
+       uint32 npoints;
+       char type;
+       char  *loc;
+       int t;
+
+       if (serialized_form == NULL)
+               return NULL;
+
+       result = (LWPOLY*) palloc(sizeof(LWPOLY));
+
+
+       type = serialized_form[0];
+       is3d = lwgeom_is3d(type);
+       loc = serialized_form;
+
+       if ( lwgeom_getType(type) != POLYGONTYPE)
+               return NULL;
+
+       if ( lwgeom_hasSRID(type))
+       {
+               result->SRID = get_int32(loc+1);
+               loc = serialized_form+ 5; // type + SRID
+       }
+       else
+       {
+               result->SRID = -1;
+               loc = serialized_form +1;
+       }
+
+       nrings = get_uint32(loc);
+       loc +=4;
+
+       result->rings = (POINTARRAY**) palloc(nrings* sizeof(POINTARRAY*));
+
+       for (t =0;t<nrings;t++)
+       {
+               //read in a single ring and make a PA
+               npoints = get_uint32(loc);
+               loc +=4;
+
+               result->rings[t] = pointArray_construct(loc, is3d, npoints);
+               if (is3d)
+                       loc += 24*npoints;
+               else
+                       loc += 16*npoints;
+       }
+       result->is3d = is3d;
+
+       return result;
+}
+
+// create the serialized form of the polygon
+// result's first char will be the 8bit type.  See serialized form doc
+// points copied
+char *lwpoly_serialize(LWPOLY *poly)
+{
+               int size=1;  // type byte
+               char hasSRID;
+               char *result;
+               int t,u;
+               int total_points = 0;
+               int npoints;
+               char *loc;
+
+               hasSRID = (poly->SRID != -1);
+
+               if (hasSRID)
+                       size +=4;  //4 byte SRID
+
+               size += 4; // nrings
+               size += 4*poly->nrings; //npoints/ring
+
+
+               for (t=0;t<poly->nrings;t++)
+               {
+                       total_points  += poly->rings[t]->npoints;
+               }
+               if (poly->is3d)
+                       size += 24*npoints;
+               else
+                       size += 16*npoints;
+
+               result = palloc(size);
+
+               result[0] = lwgeom_makeType(poly->is3d,hasSRID, POLYGONTYPE);
+               loc = result+1;
+
+               if (hasSRID)
+               {
+                       memcpy(loc, &poly->SRID, sizeof(int32));
+                       loc += 4;
+               }
+
+               memcpy(loc, &poly->nrings, sizeof(int32));  // nrings
+
+               for (t=0;t<poly->nrings;t++)
+               {
+                       POINTARRAY *pa = poly->rings[t];
+                       npoints = poly->rings[t]->npoints;
+
+                       memcpy(loc, &npoints, sizeof(int32)); //npoints this ring
+                       loc+=4;
+                       if (poly->is3d)
+                       {
+                               for (u=0;u<npoints;u++)
+                               {
+                                       getPoint3d_p(pa, u, loc);
+                                       loc+= 24*npoints;
+                               }
+                       }
+                       else
+                       {
+                               for (u=0;u<npoints;u++)
+                               {
+                                       getPoint2d_p(pa, u, loc);
+                                       loc+= 16*npoints;
+                               }
+                       }
+               }
+
+               return result;
+}
+
+
+// find bounding box (standard one)  zmin=zmax=0 if 2d (might change to NaN)
+BOX3D *lwpoly_findbbox(LWPOLY *poly)
+{
+       int t;
+
+       BOX3D *result, *abox,*abox2;
+
+       POINTARRAY *pa = poly->rings[0];
+       result  = pointArray_bbox(pa);
+
+       for (t=1;t<poly->nrings;t++)
+       {
+               pa = poly->rings[t];
+               abox  = pointArray_bbox(pa);
+               abox2 = result;
+               result = combine_boxes( abox, abox2);
+               pfree(abox);
+               pfree(abox2);
+    }
+
+    return result;
+}
+
+//find length of this serialized polygon
+uint32 lwpoly_findlength(char *serialized_poly)
+{
+               uint32 result = 1; // char type
+               uint32 nrings;
+               bool   is3d;
+               int t;
+               char type;
+               uint32 npoints;
+               char *loc;
+
+               if (serialized_poly == NULL)
+                       return -9999;
+
+
+               type = serialized_poly[0];
+               is3d = lwgeom_is3d(type);
+
+               if ( lwgeom_getType(type) != POLYGONTYPE)
+                       return -9999;
+
+               if ( lwgeom_hasSRID(type))
+               {
+                       loc = serialized_poly+ 5; // type + SRID
+                       result += 4;
+               }
+               else
+               {
+                       loc = serialized_poly +1;
+               }
+
+               nrings = get_uint32(loc);
+               loc +=4;
+               result +=4;
+
+
+               for (t =0;t<nrings;t++)
+               {
+                       //read in a single ring and make a PA
+                       npoints = get_uint32(loc);
+                       loc +=4;
+                       result +=4;
+
+                       if (is3d)
+                       {
+                               loc += 24*npoints;
+                               result += 24*npoints;
+                       }
+                       else
+                       {
+                               loc += 16*npoints;
+                               result += 16*npoints;
+                       }
+               }
+       return result;
+}
+
+
+//*************************************************************************
+// multi-geometry support
+
+
+
+// note - for a simple type (ie. point), this will have sub_geom[0] = serialized_form.
+// for multi-geomtries sub_geom[0] will be a few bytes into the serialized form
+// This function just computes the length of each sub-object and pre-caches this info.
+// For a geometry collection of multi* geometries, you can inspect the sub-components
+// as well.
+LWGEOM_INSPECTED *lwgeom_inspect(char *serialized_form)
+{
+       LWGEOM_INSPECTED *result = palloc(sizeof(LWGEOM_INSPECTED));
+       char type;
+       char **sub_geoms;
+       char *loc;
+       int     t;
+
+       if (serialized_form == NULL)
+               return NULL;
+
+       result->serialized_form = serialized_form;
+       result->type = serialized_form[0];
+
+       type = lwgeom_getType(serialized_form[0]);
+
+       if ( (type==POINTTYPE) || (type==LINETYPE) || (type==POLYGONTYPE) )
+       {
+               if (lwgeom_hasSRID(serialized_form[0]) )
+               {
+                       result->SRID=  get_int32(serialized_form+1);
+               }
+               //simple geometry (point/line/polygon)-- not multi!
+               result->ngeometries = 1;
+               sub_geoms = (char**) palloc(sizeof(char*));
+               sub_geoms[0] = serialized_form;
+               result->sub_geoms = sub_geoms;
+               return result;
+       }
+       else
+       {
+                       loc =serialized_form + 1;
+                       if (lwgeom_hasSRID(serialized_form[0]) )
+                       {
+                               result->SRID=  get_int32(loc);
+                               loc += 4;
+                       }
+                       //its a GeometryCollection or multi* geometry
+                       result->ngeometries = get_uint32(loc);
+                       loc +=4;
+                       sub_geoms = (char**) palloc(sizeof(char*) * result->ngeometries );
+
+                       sub_geoms[0] = loc;
+                       for (t=1;t<result->ngeometries; t++)
+                       {
+                               int sub_length = lwgeom_seralizedformlength(sub_geoms[t-1], -1);//-1 = entire object
+                               sub_geoms[t] = sub_geoms[t-1] + sub_length;
+                       }
+
+                       return result;
+       }
+
+}
+
+
+// 1st geometry has geom_number = 0
+// if the actual sub-geometry isnt a POINT, null is returned (see _gettype()).
+// if there arent enough geometries, return null.
+// this is fine to call on a point (with geom_num=0), multipoint or geometrycollection
+LWPOINT *lwgeom_getpoint(char *serialized_form, int geom_number)
+{
+       char type = lwgeom_getType(serialized_form[0]);
+       char *sub_geom;
+
+       if ((type == POINTTYPE)  && (geom_number == 0))
+       {
+               //be nice and do as they want instead of what they say
+               return lwpoint_deserialize(serialized_form);
+       }
+
+       if ((type != MULTIPOINTTYPE) && (type != COLLECTIONTYPE) )
+               return NULL;
+
+       sub_geom = lwgeom_getsubgeometry(serialized_form, geom_number);
+       if (sub_geom == NULL)
+               return NULL;
+
+       type = lwgeom_getType(sub_geom[0]);
+       if (type != POINTTYPE)
+               return NULL;
+
+       return lwpoint_deserialize(sub_geom);
+}
+
+LWPOINT *lwgeom_getpoint_inspected(LWGEOM_INSPECTED *inspected, int geom_number)
+{
+               char *sub_geom;
+               char type;
+
+               sub_geom = lwgeom_getsubgeometry_inspected(inspected, geom_number);
+
+               if (sub_geom == NULL)
+                       return NULL;
+
+               type = lwgeom_getType(sub_geom[0]);
+               if (type != POINTTYPE)
+                       return NULL;
+
+               return lwpoint_deserialize(sub_geom);
+}
+
+
+// 1st geometry has geom_number = 0
+// if the actual geometry isnt a LINE, null is returned (see _gettype()).
+// if there arent enough geometries, return null.
+// this is fine to call on a line, multiline or geometrycollection
+LWLINE *lwgeom_getline(char *serialized_form, int geom_number)
+{
+               char type = lwgeom_getType(serialized_form[0]);
+               char *sub_geom;
+
+               if ((type == LINETYPE)  && (geom_number == 0))
+               {
+                       //be nice and do as they want instead of what they say
+                       return lwline_deserialize(serialized_form);
+               }
+
+               if ((type != MULTILINETYPE) && (type != COLLECTIONTYPE) )
+                       return NULL;
+
+               sub_geom = lwgeom_getsubgeometry(serialized_form, geom_number);
+               if (sub_geom == NULL)
+                       return NULL;
+
+               type = lwgeom_getType(sub_geom[0]);
+               if (type != LINETYPE)
+                       return NULL;
+
+       return lwline_deserialize(sub_geom);
+}
+
+LWLINE *lwgeom_getline_inspected(LWGEOM_INSPECTED *inspected, int geom_number)
+{
+               char *sub_geom;
+               char type;
+
+               sub_geom = lwgeom_getsubgeometry_inspected(inspected, geom_number);
+
+               if (sub_geom == NULL)
+                       return NULL;
+
+               type = lwgeom_getType(sub_geom[0]);
+               if (type != LINETYPE)
+                       return NULL;
+
+               return lwline_deserialize(sub_geom);
+}
+
+// 1st geometry has geom_number = 0
+// if the actual geometry isnt a POLYGON, null is returned (see _gettype()).
+// if there arent enough geometries, return null.
+// this is fine to call on a polygon, multipolygon or geometrycollection
+LWPOLY *lwgeom_getpoly(char *serialized_form, int geom_number)
+{
+               char type = lwgeom_getType(serialized_form[0]);
+               char *sub_geom;
+
+               if ((type == POLYGONTYPE)  && (geom_number == 0))
+               {
+                       //be nice and do as they want instead of what they say
+                       return lwpoly_deserialize(serialized_form);
+               }
+
+               if ((type != MULTIPOLYGONTYPE) && (type != COLLECTIONTYPE) )
+                       return NULL;
+
+               sub_geom = lwgeom_getsubgeometry(serialized_form, geom_number);
+               if (sub_geom == NULL)
+                       return NULL;
+
+               type = lwgeom_getType(sub_geom[0]);
+               if (type != POLYGONTYPE)
+                       return NULL;
+
+               return lwpoly_deserialize(sub_geom);
+}
+
+LWPOLY *lwgeom_getpoly_inspected(LWGEOM_INSPECTED *inspected, int geom_number)
+{
+               char *sub_geom;
+               char type;
+
+               sub_geom = lwgeom_getsubgeometry_inspected(inspected, geom_number);
+
+               if (sub_geom == NULL)
+                       return NULL;
+
+               type = lwgeom_getType(sub_geom[0]);
+               if (type != POLYGONTYPE)
+                       return NULL;
+
+               return lwpoly_deserialize(sub_geom);
+}
+
+// this gets the serialized form of a sub-geometry
+// 1st geometry has geom_number = 0
+// if this isnt a multi* geometry, and geom_number ==0 then it returns
+// itself
+// returns null on problems.
+// in the future this is how you would access a muli* portion of a
+// geometry collection.
+//    GEOMETRYCOLLECTION(MULTIPOINT(0 0, 1 1), LINESTRING(0 0, 1 1))
+//   ie. lwgeom_getpoint( lwgeom_getsubgeometry( serialized, 0), 1)
+//           --> POINT(1 1)
+// you can inspect the sub-geometry as well if you wish.
+char *lwgeom_getsubgeometry(char *serialized_form, int geom_number)
+{
+       //major cheat!!
+       char * result;
+       LWGEOM_INSPECTED *inspected = lwgeom_inspect(serialized_form);
+
+       result = lwgeom_getsubgeometry_inspected(inspected, geom_number);
+       pfree_inspected(inspected);
+       return result;
+}
+
+char *lwgeom_getsubgeometry_inspected(LWGEOM_INSPECTED *inspected, int geom_number)
+{
+       if ((geom_number <0) || (geom_number >= inspected->ngeometries) )
+               return NULL;
+
+       return inspected->sub_geoms[geom_number];
+}
+
+
+// 1st geometry has geom_number = 0
+//  use geom_number = -1 to find the actual type of the serialized form.
+//    ie lwgeom_gettype( <'MULTIPOINT(0 0, 1 1)'>, -1)
+//                 --> multipoint
+//   ie lwgeom_gettype( <'MULTIPOINT(0 0, 1 1)'>, 0)
+//                 --> point
+// gets the 8bit type of the geometry at location geom_number
+char lwgeom_getsubtype(char *serialized_form, int geom_number)
+{
+               //major cheat!!
+               char  result;
+               LWGEOM_INSPECTED *inspected = lwgeom_inspect(serialized_form);
+
+               result = lwgeom_getsubtype_inspected(inspected, geom_number);
+               pfree_inspected(inspected);
+               return result;
+
+}
+char lwgeom_getsubtype_inspected(LWGEOM_INSPECTED *inspected, int geom_number)
+{
+               if ((geom_number <0) || (geom_number >= inspected->ngeometries) )
+                       return 99;
+
+               return inspected->sub_geoms[geom_number][0]; // 1st byte is type
+}
+
+
+// how many sub-geometries are there?
+//  for point,line,polygon will return 1.
+int lwgeom_getnumgeometries(char *serialized_form)
+{
+               char type = lwgeom_getType(serialized_form[0]);
+               char *loc;
+
+               if ( (type==POINTTYPE) || (type==LINETYPE) || (type==POLYGONTYPE) )
+               {
+                       return 1;
+               }
+
+               loc =serialized_form + 1;
+               if (lwgeom_hasSRID(serialized_form[0]) )
+               {
+                       loc += 4;
+               }
+               //its a GeometryCollection or multi* geometry
+               return get_uint32(loc);
+}
+
+int lwgeom_getnumgeometries_inspected(LWGEOM_INSPECTED *inspected)
+{
+       return inspected->ngeometries;
+}
+
+
+// set finalType to COLLECTIONTYPE or 0 (0 means choose a best type)
+//   (ie. give it 2 points and ask it to be a multipoint)
+//  use SRID=-1 for unknown SRID  (will have 8bit type's S = 0)
+// all subgeometries must have the same SRID
+// if you want to construct an inspected, call this then inspect the result...
+extern char *lwgeom_construct(int SRID,int finalType,char is3d, int nsubgeometries, char **serialized_subs)
+{
+       uint32 *lengths;
+       int t;
+       int total_length = 0;
+       char type = -1;
+       char this_type = -1;
+       char *result;
+       char *loc;
+
+       if (nsubgeometries == 0)
+               return lwgeom_constructempty(SRID,is3d);
+
+       lengths = palloc(sizeof(int32) * nsubgeometries);
+
+       for (t=0;t<nsubgeometries;t++)
+       {
+               lengths[t] = lwgeom_seralizedformlength(serialized_subs[t],-1);
+               total_length += lengths[t];
+               this_type = lwgeom_getType(serialized_subs[t][0]);
+               if (type == -1)
+               {
+                       type = this_type;
+               }
+               else if (type == COLLECTIONTYPE)
+               {
+                               //still a collection type...
+               }
+               else
+               {
+                       if ( (this_type == MULTIPOINTTYPE) || (this_type == MULTILINETYPE)  || (this_type == MULTIPOLYGONTYPE) || (this_type == COLLECTIONTYPE) )
+                       {
+                               type = COLLECTIONTYPE;
+                       }
+                       else
+                       {
+                               if ( (this_type == POINTTYPE)  && (type==POINTTYPE) )
+                                       type=MULTIPOINTTYPE;
+                               else if ( (this_type == LINETYPE)  && (type==LINETYPE) )
+                                       type=MULTILINETYPE;
+                               else if ( (this_type == POLYGONTYPE)  && (type==POLYGONTYPE) )
+                                       type=MULTIPOLYGONTYPE;
+                               else if ( (this_type == POLYGONTYPE)  && (type==MULTIPOLYGONTYPE) )
+                                       ;//nop
+                               else if ( (this_type == LINETYPE)  && (type==MULTILINETYPE) )
+                                       ;//nop
+                               else if ( (this_type == POINTTYPE)  && (type==MULTIPOINTTYPE) )
+                                       ;//nop
+                               else
+                                       type = COLLECTIONTYPE;
+                       }
+               }
+       }
+
+       if (type == POINTTYPE)
+               type = MULTIPOINTTYPE;
+       if (type == LINETYPE)
+               type = MULTILINETYPE;
+       if (type == POINTTYPE)
+               type = MULTIPOINTTYPE;
+
+       if (finalType == COLLECTIONTYPE)
+               type = COLLECTIONTYPE;
+
+       // now we have a mutli* or GEOMETRYCOLLECTION, lets serialize it
+
+       if (SRID != -1)
+               total_length +=4; // space for SRID
+
+       total_length +=1 ;   // main type;
+       total_length +=4 ;   // nsubgeometries
+
+       result = palloc(total_length);
+       result[0] = lwgeom_makeType( is3d, SRID != -1,  type);
+       if (SRID != -1)
+       {
+               memcpy(&result[1],&SRID,4);
+               loc = result+5;
+       }
+       else
+               loc = result+1;
+
+       memcpy(loc,&nsubgeometries,4);
+       loc +=4;
+
+       for (t=0;t<nsubgeometries;t++)
+       {
+               memcpy(loc, serialized_subs[t], lengths[t] );
+               loc += lengths[t] ;
+       }
+
+       pfree(lengths);
+       return result;
+}
+
+
+// construct the empty geometry (GEOMETRYCOLLECTION(EMPTY))
+//returns serialized form
+char *lwgeom_constructempty(int SRID,char is3d)
+{
+       int size = 0;
+       char *result;
+       int ngeoms = 0;
+       char *loc;
+
+       if (SRID != -1)
+               size +=4;
+
+       size += 5;
+
+       result = palloc(size);
+
+       result[0] = lwgeom_makeType( is3d, SRID != -1,  COLLECTIONTYPE);
+       if (SRID != -1)
+       {
+               memcpy(&result[1],&SRID,4);
+               loc = result+5;
+       }
+       else
+               loc = result+1;
+
+       memcpy(loc,&ngeoms,4);
+       return result;
+}
+
+// helper function (not for general use)
+// find the size a geometry (or a sub-geometry)
+// 1st geometry has geom_number = 0
+//  use geom_number = -1 to find the actual type of the serialized form.
+//    ie lwgeom_gettype( <'MULTIPOINT(0 0, 1 1)'>, -1)
+//                 --> size of the multipoint
+//   ie lwgeom_gettype( <'MULTIPOINT(0 0, 1 1)'>, 0)
+//         --> size of the point
+
+// take a geometry, and find its length
+int lwgeom_seralizedformlength_simple(char *serialized_form)
+{
+       char type = lwgeom_getType( serialized_form[0]);
+       int t;
+       char *loc;
+       uint32 ngeoms;
+       int sub_size;
+       int result = 1; //"type"
+
+       if (type == POINTTYPE)
+               return lwpoint_findlength(serialized_form);
+       else if (type == LINETYPE)
+               return lwline_findlength(serialized_form);
+       else if (type == POLYGONTYPE)
+               return lwpoly_findlength(serialized_form);
+
+       //handle all the multi* and geometrycollections the same
+           //NOTE: for a geometry collection of GC of GC of GC we will be recursing...
+
+       if (lwgeom_hasSRID( serialized_form[0]) )
+       {
+               result +=4;
+               loc = serialized_form+5;
+       }
+       else
+       {
+               loc =serialized_form+1;
+       }
+
+       ngeoms =  get_uint32(loc);
+       loc +=4;
+
+       for (t=0;t<ngeoms;t++)
+       {
+               sub_size = lwgeom_seralizedformlength_simple(loc);
+               loc += sub_size;
+               result += sub_size;
+       }
+
+       return result;
+}
+
+int lwgeom_seralizedformlength(char *serialized_form, int geom_number)
+{
+       if (geom_number == -1)
+       {
+               return lwgeom_seralizedformlength_simple(serialized_form);
+       }
+       return lwgeom_seralizedformlength_simple( lwgeom_getsubgeometry(serialized_form,geom_number));
+}
+
+
+
+int lwgeom_seralizedformlength_inspected(LWGEOM_INSPECTED *inspected, int geom_number)
+{
+               return lwgeom_seralizedformlength( inspected->sub_geoms[geom_number], -1);
+}
+
+
+//get bounding box of LWGEOM (automatically calls the sub-geometries bbox generators)
+//dont forget to pfree()
+BOX3D *lw_geom_getBB(char *serialized_form)
+{
+         LWGEOM_INSPECTED *inspected = lwgeom_inspect(serialized_form);
+
+         BOX3D *result = lw_geom_getBB_inspected(inspected);
+
+         pfree_inspected(inspected);
+         return result;
+}
+
+BOX3D *lw_geom_getBB_simple(char *serialized_form)
+{
+               char type = lwgeom_getType( serialized_form[0]);
+               int t;
+               char *loc;
+               uint32 ngeoms;
+               BOX3D *result;
+               BOX3D *b1,*b2;
+               int sub_size;
+
+
+               if (type == POINTTYPE)
+               {
+                       LWPOINT *pt = lwpoint_deserialize(serialized_form);
+                       result = lwpoint_findbbox(pt);
+                       pfree_point(pt);
+                       return result;
+               }
+
+               else if (type == LINETYPE)
+               {
+                       LWLINE *line = lwline_deserialize(serialized_form);
+                       result = lwline_findbbox(line);
+                       pfree_line(line);
+                       return result;
+               }
+               else if (type == POLYGONTYPE)
+               {
+                       LWPOLY *poly = lwpoly_deserialize(serialized_form);
+                       result = lwpoly_findbbox(poly);
+                       pfree_polygon(poly);
+                       return result;
+               }
+
+               if (lwgeom_hasSRID( serialized_form[0]) )
+               {
+                       loc = serialized_form+5;
+               }
+               else
+               {
+                       loc =serialized_form+1;
+               }
+
+               ngeoms =  get_uint32(loc);
+               loc +=4;
+
+               result = NULL;
+
+               for (t=0;t<ngeoms;t++)
+               {
+                       b1 = lw_geom_getBB_simple(loc);
+                       sub_size = lwgeom_seralizedformlength_simple(loc);
+                       loc += sub_size;
+                       if (result != NULL)
+                       {
+                               b2= result;
+                               result = combine_boxes(b2, b1);
+                               pfree(b1);
+                               pfree(b2);
+                       }
+                       else
+                       {
+                               result = b1;
+                       }
+               }
+
+       return result;
+
+}
+
+
+//dont forget to pfree()
+BOX3D *lw_geom_getBB_inspected(LWGEOM_INSPECTED *inspected)
+{
+               int t;
+               BOX3D *b1,*b2,*result;
+
+               result = NULL;
+
+               //handle all the multi* and geometrycollections the same
+                   //NOTE: for a geometry collection of GC of GC of GC we will be recursing...
+               for (t=0;t<inspected->ngeometries;t++)
+               {
+                       b1 = lw_geom_getBB_simple( inspected->sub_geoms[t] );
+                       if (result != NULL)
+                       {
+                               b2= result;
+                               result = combine_boxes(b2, b1);
+                               pfree(b1);
+                               pfree(b2);
+                       }
+                       else
+                       {
+                               result = b1;
+                       }
+
+               }
+
+       return result;
+}
+
+
+
+
+
+
+//****************************************************************
+// memory management -- these only delete the memory associated
+//  directly with the structure - NOT the stuff pointing into
+//  the original de-serialized info
+
+void pfree_inspected(LWGEOM_INSPECTED *inspected)
+{
+       pfree(inspected->sub_geoms);
+       pfree(inspected);
+}
+
+void pfree_point    (LWPOINT *pt)
+{
+       pfree(pt->point);
+       pfree(pt);
+}
+
+void pfree_line     (LWLINE  *line)
+{
+       pfree(line->points);
+       pfree(line);
+}
+
+void pfree_polygon  (LWPOLY  *poly)
+{
+       int t;
+
+       for (t=0;t<poly->nrings;t++)
+       {
+               pfree_POINTARRAY(poly->rings[t]);
+       }
+
+       pfree(poly);
+}
+
+void pfree_POINTARRAY(POINTARRAY *pa)
+{
+       pfree(pa);
+}
+
+
+
+
+