From 042f7cd031648f7a4eced5bc0d86bf6b54708273 Mon Sep 17 00:00:00 2001 From: David Blasby Date: Tue, 9 Mar 2004 17:29:52 +0000 Subject: [PATCH] Initial implementation - should compile; not at all tested. git-svn-id: http://svn.osgeo.org/postgis/trunk@481 b70326c6-7e19-0410-871a-916f4a2858ee --- lwgeom/Makefile | 213 ++++++ lwgeom/lwgeom.h | 128 ++-- lwgeom/lwgeom_api.c | 1653 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1954 insertions(+), 40 deletions(-) create mode 100644 lwgeom/Makefile diff --git a/lwgeom/Makefile b/lwgeom/Makefile new file mode 100644 index 000000000..722c1d798 --- /dev/null +++ b/lwgeom/Makefile @@ -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 + diff --git a/lwgeom/lwgeom.h b/lwgeom/lwgeom.h index 86406219f..a7ac0710e 100644 --- a/lwgeom/lwgeom.h +++ b/lwgeom/lwgeom.h @@ -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 +#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); diff --git a/lwgeom/lwgeom_api.c b/lwgeom/lwgeom_api.c index e69de29bb..e8283bdaf 100644 --- a/lwgeom/lwgeom_api.c +++ b/lwgeom/lwgeom_api.c @@ -0,0 +1,1653 @@ + +#include "postgres.h" + +#include +#include +#include +#include +#include + +#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;tnpoints;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;trings[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;tnrings;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;tnrings;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;urings[0]; + result = pointArray_bbox(pa); + + for (t=1;tnrings;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;tserialized_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;tngeometries; 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, -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;tsub_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;tngeometries;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;tnrings;t++) + { + pfree_POINTARRAY(poly->rings[t]); + } + + pfree(poly); +} + +void pfree_POINTARRAY(POINTARRAY *pa) +{ + pfree(pa); +} + + + + + -- 2.40.0