From: Sandro Santilli Date: Fri, 8 Oct 2004 07:01:43 +0000 (+0000) Subject: Dropped HWGEOM from this branch. X-Git-Tag: pgis_1_0_0RC1~316 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1949014f063070e37e9733c488357a181014b6d4;p=postgis Dropped HWGEOM from this branch. git-svn-id: http://svn.osgeo.org/postgis/trunk@962 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/hwgeom/Makefile b/hwgeom/Makefile deleted file mode 100644 index d7ad5a359..000000000 --- a/hwgeom/Makefile +++ /dev/null @@ -1,203 +0,0 @@ -include ../Makefile.config - -#--------------------------------------------------------------- -# Configuration Directives -# - -#--------------------------------------------------------------- -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},) - PGSQL_SRC = ../.. -endif - -#--------------------------------------------------------------- -# Path to library (to be specified in CREATE FUNCTION queries) -# Defaults to $libdir. -# Set LPATH environment variable to change it. -# -ifeq (${LPATH},) - LPATH := \$$libdir -endif - -#--------------------------------------------------------------- -#top_builddir = ${PGSQL_SRC} -#include $(top_builddir)/src/Makefile.global - -#--------------------------------------------------------------- -# 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=80 - endif - endif - endif -endif - -#--------------------------------------------------------------- -# Shared library parameters. -# -NAME=postgis -SO_MAJOR_VERSION=0 -SO_MINOR_VERSION=9 -SO_MICRO_VERSION=0 -SCRIPTS_VERSION=0.0.1 -ifeq (${USE_VERSION}, 71) - MODULE_FILENAME = $(LPATH)/$(shlib) - MODULE_INSTALLDIR = $(libdir) -else - MODULE_FILENAME = $(LPATH)/$(shlib) - MODULE_INSTALLDIR = $(pkglibdir) -endif - -#--------------------------------------------------------------- -# Postgis version -#--------------------------------------------------------------- - -POSTGIS_LIB_VERSION = $(SO_MAJOR_VERSION).$(SO_MINOR_VERSION).$(SO_MICRO_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) -override CFLAGS += -DPOSTGIS_LIB_VERSION='"$(POSTGIS_LIB_VERSION)"' -override CFLAGS += -DPOSTGIS_SCRIPTS_VERSION='"$(SCRIPTS_VERSION)"' - -ifeq ($(USE_GEOS),1) - override CFLAGS += -I$(GEOS_DIR)/include -DUSE_GEOS - GEOS_RULES=detect_geos_version -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 - -# this seems to be needed by gcc3.3.2 / Solaris7 combination -# as reported by Havard Tveite -override CXXFLAGS += -fPIC - -#--------------------------------------------------------------- -# 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=postgis_debug.o postgis_ops.o postgis_fn.o postgis_inout.o postgis_proj.o postgis_chip.o postgis_transform.o postgis_svg.o postgis_gist_$(GIST_SUPPORT).o $(GIST_ESTIMATE) postgis_geos.o $(GEOS_WRAPPER) postgis_algo.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: $(GEOS_RULES) all-lib postgis.sql postgis_undef.sql - -# Shared library stuff - -postgis_old.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.sql: postgis.sql.in - cpp -P -traditional-cpp -DUSE_VERSION=$(USE_VERSION) $< | sed -e 's:@MODULE_FILENAME@:$(MODULE_FILENAME):g;s:@POSTGIS_VERSION@:$(POSTGIS_VERSION):g;s:@POSTGIS_SCRIPTS_VERSION@:$(SCRIPTS_VERSION):g' > $@ - -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) - -#- 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 -#---------------------------------------------------------- - -detect_geos_version: - ../geos_version.sh $(GEOS_DIR) > postgis_geos_version.h - -installdirs: - $(mkinstalldirs) $(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) postgis.sql postgis_undef.sql postgis_geos_version.h - diff --git a/hwgeom/postgis.h b/hwgeom/postgis.h deleted file mode 100644 index ed1671f31..000000000 --- a/hwgeom/postgis.h +++ /dev/null @@ -1,716 +0,0 @@ - -/********************************************************************** - * $Id$ - * - * PostGIS - Spatial Types for PostgreSQL - * http://postgis.refractions.net - * Copyright 2001-2003 Refractions Research Inc. - * - * This is free software; you can redistribute and/or modify it under - * the terms of hte GNU General Public Licence. See the COPYING file. - * - ********************************************************************** - * $Log$ - * Revision 1.1 2004/09/20 07:50:06 strk - * prepared to contain old internal representation code - * - * Revision 1.51 2004/09/16 15:50:59 mleslie - * Added the distance_sphere function to calculate the distance between two points - * on an earth-sized sphere using an algorithm implemented by Bruno Wolff III. - * Added the postgresql loader function. - * - * Revision 1.50 2004/08/19 06:15:58 strk - * USE_VERSION gets 80 where it got 75 - * - * Revision 1.49 2004/07/28 13:37:43 strk - * Added postgis_uses_stats and postgis_scripts_version. - * Experimented with PIP short-circuit in within/contains functions. - * Documented new version functions. - * - * Revision 1.48 2004/07/23 21:24:33 strk - * Added postgis_proj_version() - * - * Revision 1.47 2004/07/22 16:20:09 strk - * Added postgis_lib_version() and postgis_geos_version() - * - * Revision 1.46 2004/06/09 09:06:55 strk - * Added Romi's Win32 patches. - * - * Revision 1.45 2004/06/08 15:18:12 strk - * Deleted prototype for isspace() in postgis.h - * and included in postgis_inout.c, - * which is the only module calling isspace(). - * This was needed to compile postgis against PG75(CVS). - * - * Revision 1.44 2004/06/03 16:44:56 strk - * Added expand_geometry - expand(geometry, int8) - * - * Revision 1.43 2004/03/26 00:54:09 dblasby - * added full support for fluffType() - * postgis09=# select fluffType('POINT(0 0)'); - * flufftype - * ------------------------- - * SRID=-1;MULTIPOINT(0 0) - * - * Revision 1.42 2004/02/23 12:18:55 strk - * added skeleton functions for pg75 stats integration - * - * Revision 1.41 2004/01/25 19:33:00 pramsey - * Test commit on new CVS archive. - * - * Revision 1.40 2004/01/21 19:04:03 strk - * Added line_interpolate_point function by jsunday@rochgrp.com - * - * Revision 1.39 2003/11/28 11:06:49 strk - * Added WKB_recv function for binary WKB input - * - * Revision 1.38 2003/11/19 15:44:51 strk - * added prototypes for geometry_{le,ge,cmp} - * - * Revision 1.37 2003/10/28 16:57:35 strk - * Added collect_garray() function. - * - * Revision 1.36 2003/10/28 15:16:17 strk - * unite_sfunc() from postgis_geos.c renamed to geom_accum() and moved in postgis_fn.c - * - * Revision 1.35 2003/10/28 11:16:46 strk - * Added postgis_algo.c prototypes - * - * Revision 1.34 2003/10/16 16:35:42 dblasby - * added #include for people using freeBSD (strk@keybit.net patch) - * - * Revision 1.33 2003/08/08 18:19:20 dblasby - * Conformance changes. - * Removed junk from postgis_debug.c and added the first run of the long - * transaction locking support. (this will change - dont use it) - * conformance tests were corrected - * some dos cr/lf removed - * empty geometries i.e. GEOMETRYCOLLECT(EMPTY) added (with indexing support) - * pointN(,1) now returns the first point (used to return 2nd) - * - * Revision 1.32 2003/08/06 19:31:18 dblasby - * Added the WKB parser. Added all the functions like - * PolyFromWKB(,[]). - * - * Added all the functions like PolyFromText(,[]) - * - * Minor problem in GEOS library fixed. - * - * Revision 1.31 2003/07/25 17:08:37 pramsey - * Moved Cygwin endian define out of source files into postgis.h common - * header file. - * - * Revision 1.30 2003/07/01 18:30:55 pramsey - * Added CVS revision headers. - * - * - **********************************************************************/ - -/* - * Everything is stored in a geometry3d, which is just a conglomeration - * of the base types (and a little bit of other info). - */ - -#include -#include "utils/geo_decls.h" - -#define POINTTYPE 1 -#define LINETYPE 2 -#define POLYGONTYPE 3 -#define MULTIPOINTTYPE 4 -#define MULTILINETYPE 5 -#define MULTIPOLYGONTYPE 6 -#define COLLECTIONTYPE 7 -#define BBOXONLYTYPE 99 - -/* - * Norman Vine found this problem for compiling under cygwin - * it defines BYTE_ORDER and LITTLE_ENDIAN - */ - -#if defined(__CYGWIN__) || defined(__MINGW32__) -#include // FOR ENDIAN DEFINES -#endif - - -/* - * standard definition of an ellipsoid (what wkt calls a spheroid) - * f = (a-b)/a - * e_sq = (a*a - b*b)/(a*a) - * b = a - fa - */ - -typedef struct -{ - double a; //semimajor axis - double b; //semiminor axis - double f; //flattening - double e; //eccentricity (first) - double e_sq; //eccentricity (first), squared - char name[20]; //name of ellipse -} SPHEROID; - - -/*--------------------------------------------------------------------- - * POINT3D - (x,y,z) - * Base type for all geometries - * Also used for POINT type and MULTIPOINT type - *-------------------------------------------------------------------*/ -typedef struct -{ - double x,y,z; //for lat/long x=long, y=lat -} POINT3D; - -/*--------------------------------------------------------------------- - * BOX3D - Specified by two corner points, which are - * sorted to save calculation time later. - * - * LLB -- lower right bottom point (ie. South West, Z low) - * URT -- upper right top point (ie. North East, Z high) - * - * this is the long diagonal - * - * example: - * BOX([0.0,0.0,0.0],[10.0,10.0,10.0]) - * - * NOTE: You CAN make columns in your database of this type - * IT IS NOT A TRUE GEOMETRY! - *-------------------------------------------------------------------*/ -typedef struct -{ - POINT3D LLB,URT; /* corner POINT3Ds on long diagonal */ -} BOX3D; - - - - -/*--------------------------------------------------------------------- - * LINE - set of points (directed arcs) - * P1->P2->P3->P4...->Pn - *-------------------------------------------------------------------*/ -typedef struct -{ - int32 npoints; // how many points in the line - int32 junk; // double-word alignment - POINT3D points[1]; // array of actual points -} LINE3D; - -/*--------------------------------------------------------------------- - * POLYGON - set of closed rings. First ring in outer boundary - * other rings are "holes" - * - * NOTE: this is acually stored a bit differently. It is more like: - * int32 nrings - * char filler[] - * - * where the 1st 4 byes of filler[] is npoints[0] the next 4 bytes - * are npoints[1], etc... - * - * points[0] is either at filler[ 4 * nrings] - * or at filler [ 4* nrings + 4] - * Which ever one is double-word-aligned - *-------------------------------------------------------------------*/ -typedef struct -{ - int32 nrings; // how many rings in this polygon - int32 npoints[1]; //how many points in each ring - /* could be 4 byes of filler here to make sure points[] is - double-word aligned*/ - POINT3D points[1]; // array of actual points -} POLYGON3D; - - -/*--------------------------------------------------------------------- - * Geometry - all columns in postgres are of this type - * - * Geometries are collections of simple geometry types - * (point, line, polygon). - * - * A Point is a geometry with a single point in it. - * A MultiPoint is a geometry with a list of 'point' in it. - * A Line is a geometry with a single line in it. - * A MultiLine is a geometry with a list of 'line' in it. - * A Polygon is a geometry with a single polygon in it. - * A MultiPolygon is a geometry with a list of 'polygon' in it. - * A Collection is a geometry with a (mixed) list of - * point, line, and polygon. - * - * The bvol is the bounding volume of all the subobjects. - * - * is3d is true if the original data was sent in a 3d data. - * 2d data is 3d data with z=0.0. - * - * 'type' has values: - * Point -> POINTTYPE - * MultiPoint -> MULTIPOINTTYPE - * Line -> LINETYPE - * MultiLine -> MULTILINETYPE - * Polygon -> POLYGONTYPE - * MultiPolygon -> MULTIPOLYGONTYPE - * Collection -> COLLECTIOMTYPE - * - * 'objType' has values: - * Point -> POINTTYPE - * Line -> LINETYPE - * Polygon -> POLYGONTYPE - * - * 'objOffset' is an offset (in bytes) into this structure of where - * the subobject is defined. THESE ARE ALWAYS DOUBLE-WORD ALIGNED. - * - * - * In reality the structure looks like: - * int32 size; - * int32 type; - * bool is3d; - * - * BOX3D bvol; - * int32 nobjs; - * char data[...]; - * - * AND: - * &objType[0] = &data[0] - * &objType[1] = &data[4] - * ... - * &obgOffset[0] = &data[ 4* nobjs] - * &obgOffset[1] = &data[ 4* nobjs + 4] - * ... - * &objData[0] = &GEOMETRY + objOffset[0] //always double-word aligned - * &objData[1] = &GEOMETRY + objOffset[1] //always double-word aligned - * ... - * - * ALL GEOMETRY COLUMNS IN YOUR DATABASE SHOULD BE OF THIS TYPE - *-------------------------------------------------------------------*/ -typedef struct -{ - int32 size; // postgres variable-length type requirement - int32 SRID; // spatial reference system id - double offsetX; // for precision grid (future improvement) - double offsetY; // for precision grid (future improvement) - double scale; // for precision grid (future improvement) - int32 type; // this type of geometry - bool is3d; // true if the points are 3d (only for output) - BOX3D bvol; // bounding volume of all the geo objects - int32 nobjs; // how many sub-objects in this object - int32 objType[1]; // type of object - int32 objOffset[1];// offset (in bytes) into this structure where - // the object is located - char objData[1]; // store for actual objects - -} GEOMETRY; - - -typedef struct chiptag -{ - int size; //unused (for use by postgresql) - - int endian_hint; // the number 1 in the endian of this datastruct - - BOX3D bvol; - int SRID; - char future[4]; - float factor; //usually 1.0. Integer values are multiplied by this number - //to get the actual height value (for sub-meter accuracy - //height data). - - int datatype; // 1 = float32, 5 = 24bit integer, 6 = 16bit integer (short) - // 101 = float32 (NDR), 105 = 24bit integer (NDR), 106=16bit int (NDR) - int height; - int width; - int compression; //# 0 = no compression, 1 = differencer - // 0x80 = new value - // 0x7F = nodata - - // this is provided for convenience, it should be set to - // sizeof(chip) bytes into the struct because the serialized form is: - //
- // NULL when serialized - void *data; // data[0] = bottm left, data[width] = 1st pixel, 2nd row (uncompressed) -} CHIP; - - -//for GiST indexing - -//This is the BOX type from geo_decls.h -// Its included here for the GiST index. -// Originally, we used BOXONLYTYPE geometries as our keys, but after -// Oleg and teodor (http://www.sai.msu.su/~megera/postgres/gist/) -// have released a more generic rtree/gist index for geo_decls.h polygon -// type. I am using a slightly modified version of this, so -// it will be easier to maintain. -// -// Their indexing is based on the BOX object, so we include it here. - - -// ONLY FOR INDEXING -typedef struct geomkey { - int32 size; /* size in varlena terms */ - BOX key; - int32 SRID; //spatial reference system identifier -} GEOMETRYKEY; - - -// WKB structure -- exactly the same as TEXT -typedef struct Well_known_bin { - int32 size; // total size of this structure - unsigned char data[1]; //THIS HOLD VARIABLE LENGTH DATA -} WellKnownBinary; - -// -------------------------------------------- -// histogram2d type - -// 2d histogram is a bounding box with a bunch of cells in it. -// The cells will have width (xmax-xmin)/boxesPerSide -// and height(ymax-ymin)/boxesPerSide -// The first box is the ll corner's box, the send is directly to the right -// (row-major). -// -// Size of structure is: -// 4 (size) + 32 (box) + 4 (boxesPerSide) + -// boxesPerSide*boxesPerSide*4 (data) -typedef struct histotag -{ - int32 size; // postgres variable-length type requirement - int boxesPerSide; //boxesPerSide * boxesPerSide = total boxes in grid - double avgFeatureArea; // average bbox area of features in this histogram - // double will be correctly aligned - double xmin,ymin, xmax, ymax; // BOX of area - unsigned int value[1]; // variable length # of ints for histogram -} HISTOGRAM2D; - - - -//prototypes - - -/* constructors*/ -POLYGON3D *make_polygon(int nrings, int *pts_per_ring, POINT3D *pts, int npoints, int *size); -void set_point( POINT3D *pt,double x, double y, double z); -GEOMETRY *make_oneobj_geometry(int sub_obj_size, char *sub_obj, int type, bool is3d, int SRID,double scale, double offx,double offy); - - -void print_point(char *result, POINT3D *pt,bool is3d); -void print_many_points(char *result, POINT3D *pt ,int npoints, bool is3d); -void swap(double *d1, double *d2); -int numb_points_in_list(char *str); -bool parse_points_in_list(char *str, POINT3D *points, int32 max_points, bool *is3d); -bool parse_points_in_list_exact(char *str, POINT3D *points, int32 max_points, bool *is3d); -int find_outer_list_length(char *str); -bool points_per_sublist( char *str, int32 *npoints, int32 max_lists); -char *scan_to_same_level(char *str); -int objects_inside_point(char *str); -int objects_inside_line(char *str); -int objects_inside_polygon(char *str); -int objects_inside_multipoint(char *str); -int objects_inside_multiline(char *str); -int objects_inside_multipolygon(char *str); -int objects_inside_collection(char *str); -int objects_inside(char *str); -bool parse_objects_inside_point(int32 *obj_size,char **objs, int32 *obj_types, int32 nobjs, char *str, int *offset, bool* is3d); -bool parse_objects_inside_multipoint(int32 *obj_size,char **objs, int32 *obj_types, int32 nobjs, char *str, int *offset, bool* is3d); -bool parse_objects_inside_line(int32 *obj_size,char **objs, int32 *obj_types, int32 nobjs, char *str, int *offset, bool* is3d); -bool parse_objects_inside_multiline(int32 *obj_size,char **objs, int32 *obj_types, int32 nobjs, char *str, int *offset, bool* is3d); -bool parse_objects_inside_polygon(int32 *obj_size,char **objs, int32 *obj_types, int32 nobjs, char *str, int *offset, bool* is3d); -bool parse_objects_inside_multipolygon(int32 *obj_size,char **objs, int32 *obj_types, int32 nobjs, char *str, int *offset, bool* is3d); -bool parse_objects(int32 *obj_size,char **objs,int32 *obj_types,int32 nobjs,char *str, int *offset, bool *is3d); -bool parse_objects_inside_collection(int32 *obj_size,char **objs, int32 *obj_types, int32 nobjs, char *str, int *offset, bool* is3d); -BOX3D *bbox_of_point(POINT3D *pt); -BOX3D *bbox_of_polygon(POLYGON3D *polygon); -BOX3D *bbox_of_line(LINE3D *line); -BOX3D *union_box3d(BOX3D *a, BOX3D *b); -BOX3D *bbox_of_geometry(GEOMETRY *geom); -GEOMETRY *make_bvol_geometry(BOX3D *box); - bool box3d_ov(BOX3D *box1, BOX3D *box2); -bool is_same_point(POINT3D *p1, POINT3D *p2); -bool is_same_line(LINE3D *l1, LINE3D *l2); -bool is_same_polygon(POLYGON3D *poly1, POLYGON3D *poly2); -BOX *convert_box3d_to_box(BOX3D *in); -double line_length2d(LINE3D *line); -double line_length3d(LINE3D *line); -double polygon_area2d_old(POLYGON3D *poly1); -double polygon_perimeter3d(POLYGON3D *poly1); -double polygon_perimeter2d(POLYGON3D *poly1); -int PIP( POINT3D *P, POINT3D *V, int n ); -bool point_truely_inside(POINT3D *point, BOX3D *box); -int compute_outcode( POINT3D *p, BOX3D *box); -bool lineseg_inside_box( POINT3D *P1, POINT3D *P2, BOX3D *box); -bool linestring_inside_box(POINT3D *pts, int npoints, BOX3D *box); -bool polygon_truely_inside(POLYGON3D *poly, BOX3D *box); -bool line_truely_inside( LINE3D *line, BOX3D *box); -void translate_points(POINT3D *pt, int npoints,double x_off, double y_off, double z_off); -int size_subobject (char *sub_obj, int type); -GEOMETRY *add_to_geometry(GEOMETRY *geom,int sub_obj_size, char *sub_obj, int type); -LINE3D *make_line(int npoints, POINT3D *pts, int *size); -//bool point_within_polygon(POINT3D *, POLYGON3D *); - -void swap_char(char *a, char*b); -void flip_endian_double(char *dd); -void flip_endian_int32(char *ii); - -char *to_wkb(GEOMETRY *geom, bool flip_endian); -char *wkb_multipolygon(POLYGON3D **polys,int numb_polys,int32 *size, bool flipbytes, char byte_order,bool use3d); -char *wkb_polygon(POLYGON3D *poly,int32 *size, bool flipbytes, char byte_order,bool use3d, char *mem); -char *wkb_multiline(LINE3D **lines,int32 *size, int numb_lines, bool flipbytes, char byte_order,bool use3d); -char *wkb_line(LINE3D *line,int32 *size, bool flipbytes, char byte_order,bool use3d, char *mem); -char *wkb_point(POINT3D *pt,int32 *size, bool flipbytes, char byte_order, bool use3d); -char *wkb_multipoint(POINT3D *pt,int32 numb_points,int32 *size, bool flipbytes, char byte_order,bool use3d); - -char *to_wkb_collection(GEOMETRY *geom, bool flip_endian, int32 *size); -char *to_wkb_sub(GEOMETRY *geom, bool flip_endian, int32 *wkb_size); - - - -double deltaLongitude(double azimuth, double sigma, double tsm,SPHEROID *sphere); -double bigA(double u2); -double bigB(double u2); -double distance_ellipse(double lat1, double long1, - double lat2, double long2, - SPHEROID *sphere); -double mu2(double azimuth,SPHEROID *sphere); - -double length2d_ellipse_linestring(LINE3D *line, SPHEROID *sphere); -double length3d_ellipse_linestring(LINE3D *line, SPHEROID *sphere); - -double distance_pt_pt(POINT3D *p1, POINT3D *p2); -double distance_pt_line(POINT3D *p1, LINE3D *l2); -double distance_pt_poly(POINT3D *p1, POLYGON3D *poly2); -double distance_line_line(LINE3D *l1, LINE3D *l2); -double distance_line_poly(LINE3D *l1, POLYGON3D *poly2); -double distance_poly_poly(POLYGON3D *poly1, POLYGON3D *poly2); -double distance_pt_seg(POINT3D *p, POINT3D *A, POINT3D *B); -double distance_seg_seg(POINT3D *A, POINT3D *B, POINT3D *C, POINT3D *D); -bool point_in_poly(POINT3D *p, POLYGON3D *poly); - -POINT3D *segmentize_ring(POINT3D *points, double dist, int num_points_in, int *num_points_out); - - -Datum optimistic_overlap(PG_FUNCTION_ARGS); - - - -unsigned char parse_hex(char *str); -void deparse_hex(unsigned char str, unsigned char *result); - - -char *geometry_to_text(GEOMETRY *geometry); - -BOX3D *parse_box3d(char *str); - -int getint(char *c); -double getdouble(char *c); -GEOMETRY *WKBtoGeometry(char *WKB, int length, int *bytes_read); - -POINT3D *wkb_linearring(char *WKB,char is3d, char flip_endian, int *numbPoints, int *bytes,int bytes_in_stream); - -GEOMETRY *makeNullGeometry(int SRID); - -void compressType(GEOMETRY *g); - -void DP_findsplit(POINT3D *, int, int, int, int *, double *); -void DP_simplify(POINT3D *, int, POINT3D **, int *, double); -char *simplify_line3d(LINE3D *, double); -char *simplify_polygon3d(POLYGON3D *, double); -char *simplify_point3d(POINT3D *, double); - -//exposed to psql - -Datum box3d_in(PG_FUNCTION_ARGS); -Datum box3d_out(PG_FUNCTION_ARGS); -Datum geometry_in(PG_FUNCTION_ARGS); -Datum geometry_out(PG_FUNCTION_ARGS); - -Datum astext_geometry(PG_FUNCTION_ARGS); - -Datum geometry_text(PG_FUNCTION_ARGS); - - -Datum get_bbox_of_geometry(PG_FUNCTION_ARGS); -Datum get_geometry_of_bbox(PG_FUNCTION_ARGS); -Datum box3d_same(PG_FUNCTION_ARGS); -Datum geometry_overleft(PG_FUNCTION_ARGS); -Datum geometry_left(PG_FUNCTION_ARGS); -Datum geometry_right(PG_FUNCTION_ARGS); -Datum geometry_overright(PG_FUNCTION_ARGS); -Datum geometry_contained(PG_FUNCTION_ARGS); -Datum geometry_contain(PG_FUNCTION_ARGS); -Datum geometry_overlap(PG_FUNCTION_ARGS); -Datum geometry_same(PG_FUNCTION_ARGS); -Datum box3d_overlap(PG_FUNCTION_ARGS); -Datum box3d_overleft(PG_FUNCTION_ARGS); -Datum box3d_right(PG_FUNCTION_ARGS); -Datum box3d_contain(PG_FUNCTION_ARGS); -Datum geometry_union(PG_FUNCTION_ARGS); -Datum geometry_inter(PG_FUNCTION_ARGS); -Datum geometry_size(PG_FUNCTION_ARGS); -Datum length3d(PG_FUNCTION_ARGS); -Datum length2d(PG_FUNCTION_ARGS); -Datum area2d(PG_FUNCTION_ARGS); -Datum perimeter3d(PG_FUNCTION_ARGS); -Datum perimeter2d(PG_FUNCTION_ARGS); -Datum truly_inside(PG_FUNCTION_ARGS); - -Datum geometry_lt(PG_FUNCTION_ARGS); -Datum geometry_le(PG_FUNCTION_ARGS); -Datum geometry_eq(PG_FUNCTION_ARGS); -Datum geometry_gt(PG_FUNCTION_ARGS); -Datum geometry_ge(PG_FUNCTION_ARGS); -Datum geometry_cmp(PG_FUNCTION_ARGS); - -Datum npoints(PG_FUNCTION_ARGS); -Datum nrings(PG_FUNCTION_ARGS); -Datum mem_size(PG_FUNCTION_ARGS); -Datum summary(PG_FUNCTION_ARGS); -Datum translate(PG_FUNCTION_ARGS); - -Datum asbinary_specify(PG_FUNCTION_ARGS); -Datum asbinary_simple(PG_FUNCTION_ARGS); - -Datum force_2d(PG_FUNCTION_ARGS); -Datum force_3d(PG_FUNCTION_ARGS); -Datum force_collection(PG_FUNCTION_ARGS); - -Datum combine_bbox(PG_FUNCTION_ARGS); - -Datum dimension(PG_FUNCTION_ARGS); -Datum geometrytype(PG_FUNCTION_ARGS); -Datum envelope(PG_FUNCTION_ARGS); - -Datum x_point(PG_FUNCTION_ARGS); -Datum y_point(PG_FUNCTION_ARGS); -Datum z_point(PG_FUNCTION_ARGS); - -Datum numpoints_linestring(PG_FUNCTION_ARGS); -Datum pointn_linestring(PG_FUNCTION_ARGS); - -Datum exteriorring_polygon(PG_FUNCTION_ARGS); -Datum numinteriorrings_polygon(PG_FUNCTION_ARGS); -Datum interiorringn_polygon(PG_FUNCTION_ARGS); - -Datum numgeometries_collection(PG_FUNCTION_ARGS); -Datum geometryn_collection(PG_FUNCTION_ARGS); - -Datum ellipsoid_out(PG_FUNCTION_ARGS); -Datum ellipsoid_in(PG_FUNCTION_ARGS); -Datum length_ellipsoid(PG_FUNCTION_ARGS); -Datum length3d_ellipsoid(PG_FUNCTION_ARGS); -Datum distance_ellipsoid(PG_FUNCTION_ARGS); -Datum distance_sphere(PG_FUNCTION_ARGS); - -Datum point_inside_circle(PG_FUNCTION_ARGS); -Datum distance(PG_FUNCTION_ARGS); - -Datum expand_bbox(PG_FUNCTION_ARGS); -Datum expand_geometry(PG_FUNCTION_ARGS); -Datum srid_geom(PG_FUNCTION_ARGS); -Datum geometry_from_text(PG_FUNCTION_ARGS); - -Datum startpoint(PG_FUNCTION_ARGS); - -Datum endpoint(PG_FUNCTION_ARGS); -Datum isclosed(PG_FUNCTION_ARGS); - -Datum centroid(PG_FUNCTION_ARGS); - -Datum postgis_gist_sel(PG_FUNCTION_ARGS); - -Datum WKB_in(PG_FUNCTION_ARGS); -Datum WKB_out(PG_FUNCTION_ARGS); - -Datum WKB_recv(PG_FUNCTION_ARGS); - -Datum CHIP_in(PG_FUNCTION_ARGS); -Datum CHIP_out(PG_FUNCTION_ARGS); -Datum CHIP_to_geom(PG_FUNCTION_ARGS); -Datum srid_chip(PG_FUNCTION_ARGS); -Datum setsrid_chip(PG_FUNCTION_ARGS); -Datum width_chip(PG_FUNCTION_ARGS); -Datum height_chip(PG_FUNCTION_ARGS); -Datum datatype_chip(PG_FUNCTION_ARGS); -Datum compression_chip(PG_FUNCTION_ARGS); -Datum setfactor_chip(PG_FUNCTION_ARGS); -Datum factor_chip(PG_FUNCTION_ARGS); - - -Datum segmentize(PG_FUNCTION_ARGS); - -Datum box3d_xmin(PG_FUNCTION_ARGS); -Datum box3d_ymin(PG_FUNCTION_ARGS); -Datum box3d_zmin(PG_FUNCTION_ARGS); - -Datum box3d_xmax(PG_FUNCTION_ARGS); -Datum box3d_ymax(PG_FUNCTION_ARGS); -Datum box3d_zmax(PG_FUNCTION_ARGS); -Datum box3dtobox(PG_FUNCTION_ARGS); - - - -Datum transform_geom(PG_FUNCTION_ARGS); - -Datum max_distance(PG_FUNCTION_ARGS); -Datum geom_accum(PG_FUNCTION_ARGS); -Datum collect_garray(PG_FUNCTION_ARGS); -Datum collector(PG_FUNCTION_ARGS); - -Datum WKBtoBYTEA(PG_FUNCTION_ARGS); - -Datum histogram2d_in(PG_FUNCTION_ARGS); -Datum histogram2d_out(PG_FUNCTION_ARGS); -Datum create_histogram2d(PG_FUNCTION_ARGS); - -Datum build_histogram2d(PG_FUNCTION_ARGS); - -Datum geometry2box(PG_FUNCTION_ARGS); - -Datum explode_histogram2d(PG_FUNCTION_ARGS); -Datum estimate_histogram2d(PG_FUNCTION_ARGS); -#if USE_VERSION >= 80 -Datum geometry_analyze(PG_FUNCTION_ARGS); -#endif - -Datum postgisgistcostestimate(PG_FUNCTION_ARGS); - -Datum geometryfromWKB(PG_FUNCTION_ARGS); -Datum geometryfromWKB_SRID(PG_FUNCTION_ARGS); - -Datum PointfromWKB_SRID(PG_FUNCTION_ARGS); -Datum LinefromWKB_SRID(PG_FUNCTION_ARGS); -Datum PolyfromWKB_SRID(PG_FUNCTION_ARGS); -Datum MPointfromWKB_SRID(PG_FUNCTION_ARGS); -Datum MLinefromWKB_SRID(PG_FUNCTION_ARGS); -Datum MPolyfromWKB_SRID(PG_FUNCTION_ARGS); -Datum GCfromWKB_SRID(PG_FUNCTION_ARGS); - - -Datum geometry_from_text_poly(PG_FUNCTION_ARGS); -Datum geometry_from_text_mpoly(PG_FUNCTION_ARGS); -Datum geometry_from_text_point(PG_FUNCTION_ARGS); -Datum geometry_from_text_mpoint(PG_FUNCTION_ARGS); -Datum geometry_from_text_line(PG_FUNCTION_ARGS); -Datum geometry_from_text_mline(PG_FUNCTION_ARGS); -Datum geometry_from_text_gc(PG_FUNCTION_ARGS); -Datum isempty(PG_FUNCTION_ARGS); -Datum simplify(PG_FUNCTION_ARGS); -Datum line_interpolate_point(PG_FUNCTION_ARGS); - -Datum fluffType(PG_FUNCTION_ARGS); -Datum postgis_uses_stats(PG_FUNCTION_ARGS); -Datum postgis_lib_version(PG_FUNCTION_ARGS); -Datum postgis_geos_version(PG_FUNCTION_ARGS); -Datum postgis_proj_version(PG_FUNCTION_ARGS); - -/*-------------------------------------------------------------------- - * Useful floating point utilities and constants. - * from postgres geo_decls.c - * EPSILON modified to be more "double" friendly - *-------------------------------------------------------------------*/ - - - -// from contrib/cube/cube.c - -#if ! defined(__MINGW32__) -#define max(a,b) ((a) > (b) ? (a) : (b)) -#define min(a,b) ((a) <= (b) ? (a) : (b)) -#endif -#define abs(a) ((a) < (0) ? (-a) : (a)) - - diff --git a/hwgeom/postgis.sql.in b/hwgeom/postgis.sql.in deleted file mode 100644 index c6fb4310c..000000000 --- a/hwgeom/postgis.sql.in +++ /dev/null @@ -1,2801 +0,0 @@ --- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --- --- $Id$ --- --- PostGIS - Spatial Types for PostgreSQL --- http://postgis.refractions.net --- Copyright 2001-2003 Refractions Research Inc. --- --- This is free software; you can redistribute and/or modify it under --- the terms of the GNU General Public Licence. See the COPYING file. --- --- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -#if USE_VERSION > 71 -#define CREATEFUNCTION CREATE OR REPLACE FUNCTION -#else -#define CREATEFUNCTION CREATE FUNCTION -#endif - -BEGIN TRANSACTION; - --- You might have to define the PL/PgSQL language usually done with the --- changelang script. - --- Here's some hokey code to test to see if PL/PgSQL is installed --- if it is, you get a message "PL/PgSQL is installed" --- otherwise it will give a big error message. - -(select 'PL/PgSQL is installed.' as message from pg_language where lanname='plpgsql') union (select 'You must install PL/PgSQL before running this SQL file,\nor you will get an error. To install PL/PgSQL run:\n\tcreatelang plpgsql '::text as message) order by message limit 1; - - -------------------------------------------------------------------- --- HISTOGRAM2D TYPE -------------------------------------------------------------------- - -#if USE_VERSION < 73 -# define HISTOGRAM_IN_REP opaque -# define HISTOGRAM_OUT_REP opaque -#else -# define HISTOGRAM_IN_REP histogram2d -# define HISTOGRAM_OUT_REP cstring -#endif - -CREATEFUNCTION histogram2d_in(HISTOGRAM_OUT_REP) - RETURNS HISTOGRAM_IN_REP - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION histogram2d_out(HISTOGRAM_IN_REP) - RETURNS HISTOGRAM_OUT_REP - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATE TYPE histogram2d ( - alignment = double, - internallength = variable, - input = histogram2d_in, - output = histogram2d_out, - storage = main -); - -------------------------------------------------------------------- --- BOX3D TYPE -------------------------------------------------------------------- - -#if USE_VERSION < 73 -# define BOX3D_IN_REP opaque -# define BOX3D_OUT_REP opaque -#else -# define BOX3D_IN_REP box3d -# define BOX3D_OUT_REP cstring -#endif - -CREATEFUNCTION box3d_in(BOX3D_OUT_REP) - RETURNS BOX3D_IN_REP - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION box3d_out(BOX3D_IN_REP) - RETURNS BOX3D_OUT_REP - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATE TYPE box3d ( - alignment = double, - internallength = 48, - input = box3d_in, - output = box3d_out -); - -------------------------------------------------------------------- --- SPHEROID TYPE -------------------------------------------------------------------- - -#if USE_VERSION < 73 -# define SPHEROID_IN_REP opaque -# define SPHEROID_OUT_REP opaque -#else -# define SPHEROID_IN_REP spheroid -# define SPHEROID_OUT_REP cstring -#endif - -CREATEFUNCTION spheroid_in(SPHEROID_OUT_REP) - RETURNS SPHEROID_IN_REP - AS '@MODULE_FILENAME@','ellipsoid_in' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION spheroid_out(SPHEROID_IN_REP) - RETURNS SPHEROID_OUT_REP - AS '@MODULE_FILENAME@','ellipsoid_out' - LANGUAGE 'C' WITH (isstrict); - -CREATE TYPE spheroid ( - alignment = double, - internallength = 65, - input = spheroid_in, - output = spheroid_out -); - -------------------------------------------------------------------- --- WKB TYPE -------------------------------------------------------------------- - -#if USE_VERSION < 73 -# define WKB_IN_REP opaque -# define WKB_OUT_REP opaque -#else -# define WKB_IN_REP wkb -# define WKB_OUT_REP cstring -#endif - -CREATEFUNCTION wkb_in(WKB_OUT_REP) - RETURNS WKB_IN_REP - AS '@MODULE_FILENAME@','WKB_in' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION wkb_out(WKB_IN_REP) - RETURNS WKB_OUT_REP - AS '@MODULE_FILENAME@','WKB_out' - LANGUAGE 'C' WITH (isstrict); - -#if USE_VERSION > 73 -CREATEFUNCTION wkb_recv(internal) - RETURNS wkb - AS '@MODULE_FILENAME@','WKB_recv' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION wkb_send(wkb) - RETURNS bytea - AS '@MODULE_FILENAME@','WKBtoBYTEA' - LANGUAGE 'C' WITH (iscachable,isstrict); -#endif - -CREATE TYPE wkb ( - internallength = variable, - input = wkb_in, - output = wkb_out, -#if USE_VERSION > 73 - send = wkb_send, - receive = wkb_recv, -#endif - storage = extended -); - -------------------------------------------------------------------- --- CHIP TYPE -------------------------------------------------------------------- - -#if USE_VERSION < 73 -# define CHIP_IN_REP opaque -# define CHIP_OUT_REP opaque -#else -# define CHIP_IN_REP chip -# define CHIP_OUT_REP cstring -#endif - -CREATEFUNCTION chip_in(CHIP_OUT_REP) - RETURNS CHIP_IN_REP - AS '@MODULE_FILENAME@','CHIP_in' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION chip_out(CHIP_IN_REP) - RETURNS CHIP_OUT_REP - AS '@MODULE_FILENAME@','CHIP_out' - LANGUAGE 'C' WITH (isstrict); - -CREATE TYPE chip ( - alignment = double, - internallength = variable, - input = chip_in, - output = chip_out, - storage = extended -); - -------------------------------------------------------------------- --- GEOMETRY TYPE -------------------------------------------------------------------- - -#if USE_VERSION < 73 -# define GEOMETRY_IN_REP opaque -# define GEOMETRY_OUT_REP opaque -#else -# define GEOMETRY_IN_REP geometry -# define GEOMETRY_OUT_REP cstring -#endif - -CREATEFUNCTION geometry_in(GEOMETRY_OUT_REP) - RETURNS GEOMETRY_IN_REP - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION geometry_out(GEOMETRY_IN_REP) - RETURNS GEOMETRY_OUT_REP - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -#if USE_VERSION >= 80 -CREATEFUNCTION geometry_analyze(internal) - RETURNS bool - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); -#endif - -CREATE TYPE geometry ( - alignment = double, - internallength = variable, - input = geometry_in, - output = geometry_out, -#if USE_VERSION >= 80 - analyze = geometry_analyze, -#endif - storage = main -); - - -------------------------------------------------------------------- --- Workaround for old user defined variable length datatype --- default value bug. Should not be necessary > 7.2 -------------------------------------------------------------------- -#if USE_VERSION <= 72 -UPDATE pg_type SET typdefault = NULL WHERE typname = 'wkb'; -UPDATE pg_type SET typdefault = NULL WHERE typname = 'geometry'; -UPDATE pg_type SET typdefault = NULL WHERE typname = 'histogram2d'; -#endif - - - -------------------------------------------------------------------- --- GiST Selectivity Function -------------------------------------------------------------------- -#if USE_VERSION == 71 -CREATEFUNCTION postgis_gist_sel(oid, oid, int2, opaque, int4) -#elif USE_VERSION == 72 -CREATEFUNCTION postgis_gist_sel(opaque, oid, opaque, int4) -#else -CREATEFUNCTION postgis_gist_sel (internal, oid, internal, int4) -#endif - RETURNS float8 - AS '@MODULE_FILENAME@' - LANGUAGE 'C'; - -------------------------------------------------------------------- --- SPATIAL_REF_SYS -------------------------------------------------------------------- -CREATE TABLE spatial_ref_sys ( - srid integer not null primary key, - auth_name varchar(256), - auth_srid integer, - srtext varchar(2048), - proj4text varchar(2048) -); - -------------------------------------------------------------------- --- GEOMETRY_COLUMNS -------------------------------------------------------------------- -CREATE TABLE geometry_columns ( - f_table_catalog varchar(256) not null, - f_table_schema varchar(256) not null, - f_table_name varchar(256) not null, - f_geometry_column varchar(256) not null, - coord_dimension integer not null, - srid integer not null, - type varchar(30) not null, -#if USE_VERSION < 80 - attrelid oid, - varattnum int, - stats histogram2d, -#endif - CONSTRAINT geometry_columns_pk primary key ( - f_table_catalog, - f_table_schema, - f_table_name, - f_geometry_column ) ); - ------------------------------------------------------------------------ --- POSTGIS_VERSION() ------------------------------------------------------------------------ - -CREATEFUNCTION postgis_version() RETURNS text -AS 'SELECT \'@POSTGIS_VERSION@\'::text AS version' -LANGUAGE 'sql'; - -CREATEFUNCTION postgis_lib_version() RETURNS text - AS '@MODULE_FILENAME@' - LANGUAGE 'C'; - -CREATEFUNCTION postgis_geos_version() RETURNS text - AS '@MODULE_FILENAME@' - LANGUAGE 'C'; - -CREATEFUNCTION postgis_proj_version() RETURNS text - AS '@MODULE_FILENAME@' - LANGUAGE 'C'; - -CREATEFUNCTION postgis_scripts_installed() RETURNS text -AS 'SELECT \'@POSTGIS_SCRIPTS_VERSION@\'::text AS version' -LANGUAGE 'sql'; - -CREATEFUNCTION postgis_scripts_released() RETURNS text - AS '@MODULE_FILENAME@' - LANGUAGE 'C'; - -CREATEFUNCTION postgis_uses_stats() RETURNS bool - AS '@MODULE_FILENAME@' - LANGUAGE 'C'; - -CREATEFUNCTION postgis_full_version() RETURNS text -AS ' -DECLARE - libver text; - projver text; - geosver text; - usestats bool; - dbproc text; - relproc text; - fullver text; -BEGIN - SELECT postgis_lib_version() INTO libver; - SELECT postgis_proj_version() INTO projver; - SELECT postgis_geos_version() INTO geosver; - SELECT postgis_uses_stats() INTO usestats; - SELECT postgis_scripts_installed() INTO dbproc; - SELECT postgis_scripts_released() INTO relproc; - - fullver = \'POSTGIS="\' || libver || \'"\'; - - IF geosver IS NOT NULL THEN - fullver = fullver || \' GEOS="\' || geosver || \'"\'; - END IF; - - IF projver IS NOT NULL THEN - fullver = fullver || \' PROJ="\' || projver || \'"\'; - END IF; - - IF usestats THEN - fullver = fullver || \' USE_STATS\'; - END IF; - - fullver = fullver || \' DBPROC="\' || dbproc || \'"\'; - fullver = fullver || \' RELPROC="\' || relproc || \'"\'; - - IF dbproc != relproc THEN - fullver = fullver || \' (needs proc upgrade)\'; - END IF; - - RETURN fullver; -END -' LANGUAGE 'plpgsql'; - ------------------------------------------------------------------------ --- FIND_SRID( , , ) ------------------------------------------------------------------------ -CREATEFUNCTION find_srid(varchar,varchar,varchar) RETURNS int4 AS -'DECLARE - schem text; - tabl text; - sr int4; -BEGIN - IF $1 IS NULL THEN - RAISE EXCEPTION ''find_srid() - schema is NULL!''; - END IF; - IF $2 IS NULL THEN - RAISE EXCEPTION ''find_srid() - table name is NULL!''; - END IF; - IF $3 IS NULL THEN - RAISE EXCEPTION ''find_srid() - column name is NULL!''; - END IF; - schem = $1; - tabl = $2; --- if the table contains a . and the schema is empty --- split the table into a schema and a table --- otherwise drop through to default behavior - IF ( schem = '''' and tabl LIKE ''%.%'' ) THEN - schem = substr(tabl,1,strpos(tabl,''.'')-1); - tabl = substr(tabl,length(schem)+2); - ELSE - schem = schem || ''%''; - END IF; - - select SRID into sr from geometry_columns where f_table_schema like schem and f_table_name = tabl and f_geometry_column = $3; - IF NOT FOUND THEN - RAISE EXCEPTION ''find_srid() - couldnt find the corresponding SRID - is the geometry registered in the GEOMETRY_COLUMNS table? Is there an uppercase/lowercase missmatch?''; - END IF; - return sr; -END; -' -LANGUAGE 'plpgsql' WITH (iscachable); - ------------------------------------------------------------------------ --- GET_PROJ4_FROM_SRID( ) ------------------------------------------------------------------------ -CREATEFUNCTION get_proj4_from_srid(integer) RETURNS text AS -'SELECT proj4text::text FROM spatial_ref_sys WHERE srid= $1' -LANGUAGE 'sql' WITH (iscachable,isstrict); - - ------------------------------------------------------------------------ --- RENAME_GEOMETRY_TABLE_CONSTRAINTS() ------------------------------------------------------------------------ --- This function renames geometrytype and srid constraints --- applied to spatial tables by old AddGeometryColumn to --- new meaningful name 'enforce_geotype_' --- and 'enforce_srid_' --- Needs to be called only when upgrading from postgis < 0.8.3 ------------------------------------------------------------------------ -CREATEFUNCTION rename_geometry_table_constraints() RETURNS text -AS -' -UPDATE pg_constraint - SET conname = textcat(''enforce_geotype_'', a.attname) - FROM pg_attribute a - WHERE - a.attrelid = conrelid - AND a.attnum = conkey[1] - AND consrc LIKE ''((geometrytype(%) = %''; - -UPDATE pg_constraint - SET conname = textcat(''enforce_srid_'', a.attname) - FROM pg_attribute a - WHERE - a.attrelid = conrelid - AND a.attnum = conkey[1] - AND consrc LIKE ''(srid(% = %)''; - -SELECT ''spatial table constraints renamed''::text; - -' LANGUAGE 'SQL'; - ------------------------------------------------------------------------ --- FIX_GEOMETRY_COLUMNS() ------------------------------------------------------------------------ --- This function will: --- --- o try to fix the schema of records with an invalid one --- (for PG>=73) --- --- o link records to system tables through attrelid and varattnum --- (for PG<80) --- --- o delete all records for which no linking was possible --- (for PG<80) --- --- ------------------------------------------------------------------------ -CREATEFUNCTION fix_geometry_columns() RETURNS text -AS -' -DECLARE - result text; - linked integer; - deleted integer; -#if USE_VERSION >= 73 - foundschema integer; -#endif -BEGIN - -#if USE_VERSION >= 73 - -- Since 7.3 schema support has been added. - -- Previous postgis versions used to put the database name in - -- the schema column. This needs to be fixed, so we try to - -- set the correct schema for each geometry_colums record - -- looking at table, column, type and srid. - UPDATE geometry_columns SET f_table_schema = n.nspname - FROM pg_namespace n, pg_class c, pg_attribute a, - pg_constraint sridcheck, pg_constraint typecheck - WHERE ( f_table_schema is NULL - OR f_table_schema = '''' - OR f_table_schema NOT IN ( - SELECT nspname::varchar - FROM pg_namespace nn, pg_class cc, pg_attribute aa - WHERE cc.relnamespace = nn.oid - AND cc.relname = f_table_name::name - AND aa.attrelid = cc.oid - AND aa.attname = f_geometry_column::name)) - AND f_table_name::name = c.relname - AND c.oid = a.attrelid - AND c.relnamespace = n.oid - AND f_geometry_column::name = a.attname - AND sridcheck.conrelid = c.oid - --AND sridcheck.conname = ''$1'' - AND sridcheck.consrc LIKE ''(srid(% = %)'' - AND typecheck.conrelid = c.oid - --AND typecheck.conname = ''$2'' - AND typecheck.consrc LIKE - ''((geometrytype(%) = ''''%''''::text) OR (% IS NULL))'' - AND sridcheck.consrc ~ textcat('' = '', srid::text) - AND typecheck.consrc ~ textcat('' = '''''', type::text) - AND NOT EXISTS ( - SELECT oid FROM geometry_columns gc - WHERE c.relname::varchar = gc.f_table_name -#if USE_VERSION >= 73 - AND n.nspname::varchar = gc.f_table_schema -#endif - AND a.attname::varchar = gc.f_geometry_column - ); - - GET DIAGNOSTICS foundschema = ROW_COUNT; -#endif - -#if USE_VERSION >= 80 - -- no linkage to system table needed - return ''fixed:''||foundschema::text; -#endif - - -- fix linking to system tables - UPDATE geometry_columns SET - attrelid = NULL, - varattnum = NULL, - stats = NULL; - - UPDATE geometry_columns SET - attrelid = c.oid, - varattnum = a.attnum -#if USE_VERSION >= 73 - FROM pg_class c, pg_attribute a, pg_namespace n - WHERE n.nspname = f_table_schema::name - AND c.relname = f_table_name::name - AND c.relnamespace = n.oid -#else // USE_VERSION < 73 - FROM pg_class c, pg_attribute a - WHERE c.relname = f_table_name::name -#endif - AND a.attname = f_geometry_column::name - AND a.attrelid = c.oid; - - GET DIAGNOSTICS linked = ROW_COUNT; - - -- remove stale records - DELETE FROM geometry_columns WHERE attrelid IS NULL; - - GET DIAGNOSTICS deleted = ROW_COUNT; - - result = -#if USE_VERSION >= 73 - ''fixed:'' || foundschema::text || -#endif - '' linked:'' || linked::text || - '' deleted:'' || deleted::text; - - return result; - -END; -' -LANGUAGE 'plpgsql' ; - ------------------------------------------------------------------------ --- PROBE_GEOMETRY_COLUMNS() ------------------------------------------------------------------------ --- Fill the geometry_columns table with values probed from the system --- catalogues. 3d flag can not be probed, it defaults to 2 --- --- Note that bogus records already in geometry_columns are not --- overridden (a check for schema.table.column is performed), so --- to have a fresh probe backup your geometry_column, delete from --- it and probe. ------------------------------------------------------------------------ -CREATEFUNCTION probe_geometry_columns() RETURNS text AS -' -DECLARE - inserted integer; - oldcount integer; - probed integer; - stale integer; -BEGIN - - SELECT count(*) INTO oldcount FROM geometry_columns; - - SELECT count(*) INTO probed - FROM pg_class c, pg_attribute a, pg_type t, -#if USE_VERSION >= 73 - pg_namespace n, -#endif - pg_constraint sridcheck, pg_constraint typecheck - WHERE t.typname = ''geometry'' - AND a.atttypid = t.oid - AND a.attrelid = c.oid -#if USE_VERSION >= 73 - AND c.relnamespace = n.oid - AND sridcheck.connamespace = n.oid - AND typecheck.connamespace = n.oid -#endif - AND sridcheck.conrelid = c.oid - --AND sridcheck.conname = ''$1'' - AND sridcheck.consrc LIKE ''(srid(% = %)'' - AND typecheck.conrelid = c.oid - --AND typecheck.conname = ''$2''; - AND typecheck.consrc LIKE - ''((geometrytype(%) = ''''%''''::text) OR (% IS NULL))'' - ; - - INSERT INTO geometry_columns SELECT - ''''::varchar as f_table_catalogue, -#if USE_VERSION >= 73 - n.nspname::varchar as f_table_schema, -#else - ''''::varchar as f_table_schema, -#endif - c.relname::varchar as f_table_name, - a.attname::varchar as f_geometry_column, - 2 as coord_dimension, - trim(both '' =)'' from substr(sridcheck.consrc, - strpos(sridcheck.consrc, ''='')))::integer as srid, - trim(both '' =)'''''' from substr(typecheck.consrc, - strpos(typecheck.consrc, ''=''), - strpos(typecheck.consrc, ''::'')- - strpos(typecheck.consrc, ''='') - ))::varchar as type, -#if USE_VERSION < 80 - a.attrelid, - a.attnum as varattnum, - null::histogram2d as stats -#endif - FROM pg_class c, pg_attribute a, pg_type t, -#if USE_VERSION >= 73 - pg_namespace n, -#endif - pg_constraint sridcheck, pg_constraint typecheck - WHERE t.typname = ''geometry'' - AND a.atttypid = t.oid - AND a.attrelid = c.oid -#if USE_VERSION >= 73 - AND c.relnamespace = n.oid - AND sridcheck.connamespace = n.oid - AND typecheck.connamespace = n.oid -#endif - AND sridcheck.conrelid = c.oid - --AND sridcheck.conname = ''$1'' - AND sridcheck.consrc LIKE ''(srid(% = %)'' - AND typecheck.conrelid = c.oid - --AND typecheck.conname = ''$2'' - AND typecheck.consrc LIKE - ''((geometrytype(%) = ''''%''''::text) OR (% IS NULL))'' - - AND NOT EXISTS ( - SELECT oid FROM geometry_columns gc - WHERE c.relname::varchar = gc.f_table_name -#if USE_VERSION >= 73 - AND n.nspname::varchar = gc.f_table_schema -#endif - AND a.attname::varchar = gc.f_geometry_column - ); - - GET DIAGNOSTICS inserted = ROW_COUNT; - - IF oldcount > probed THEN - stale = oldcount-probed; - ELSE - stale = 0; - END IF; - - RETURN ''probed:''||probed|| - '' inserted:''||inserted|| - '' conflicts:''||probed-inserted|| - '' stale:''||stale; -END - -' LANGUAGE 'plpgsql'; - ------------------------------------------------------------------------ --- FIND_EXTENT( ,
, ) ------------------------------------------------------------------------ -CREATEFUNCTION find_extent(text,text,text) RETURNS box3d AS -' -DECLARE - schemaname alias for $1; - tablename alias for $2; - columnname alias for $3; - okay boolean; - myrec RECORD; - -BEGIN - FOR myrec IN EXECUTE ''SELECT extent("''||columnname||''") FROM "''||schemaname||''"."''||tablename||''"'' LOOP - return myrec.extent; - END LOOP; -END; -' -LANGUAGE 'plpgsql' WITH (isstrict); - ------------------------------------------------------------------------ --- FIND_EXTENT(
, ) ------------------------------------------------------------------------ -CREATEFUNCTION find_extent(text,text) RETURNS box3d AS -' -DECLARE - tablename alias for $1; - columnname alias for $2; - okay boolean; - myrec RECORD; - -BEGIN - FOR myrec IN EXECUTE ''SELECT extent("''||columnname||''") FROM "''||tablename||''"'' LOOP - return myrec.extent; - END LOOP; -END; -' -LANGUAGE 'plpgsql' WITH (isstrict); - - ------------------------------------------------------------------------ --- TRANSFORM ( , ) ------------------------------------------------------------------------ --- --- Test: --- --- trans=# select * from spatial_ref_sys ; --- --- srid | auth_name | auth_srid | srtext | proj4text --- ------+---------------+-----------+--------+-------------------------------------------------------------------------- --- 1 | latlong WGS84 | 1 | | +proj=longlat +datum=WGS84 --- 2 | BC albers | 2 | | proj=aea ellps=GRS80 lon_0=-126 lat_0=45 lat_1=50 lat_2=58.5 x_0=1000000 --- --- select transform( 'SRID=1;POINT(-120.8 50.3)', 2); --- -> 'SRID=2;POINT(1370033.37046971 600755.810968684)' --- ------------------------------------------------------------------------ -CREATEFUNCTION transform_geometry(geometry,text,text,int) - RETURNS geometry - AS '@MODULE_FILENAME@','transform_geom' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION transform(geometry,integer) RETURNS geometry AS -'BEGIN - RETURN transform_geometry( $1 , get_proj4_from_srid(SRID( $1 ) ), get_proj4_from_srid( $2 ), $2 ); - END;' -LANGUAGE 'plpgsql' WITH (iscachable,isstrict); - - - ------------------------------------------------------------------------ --- COMMON FUNCTIONS ------------------------------------------------------------------------ - -CREATEFUNCTION srid(chip) - RETURNS int4 - AS '@MODULE_FILENAME@','srid_chip' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION height(chip) - RETURNS int4 - AS '@MODULE_FILENAME@','height_chip' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION factor(chip) - RETURNS FLOAT4 - AS '@MODULE_FILENAME@','factor_chip' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION width(chip) - RETURNS int4 - AS '@MODULE_FILENAME@','width_chip' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION datatype(chip) - RETURNS int4 - AS '@MODULE_FILENAME@','datatype_chip' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION compression(chip) - RETURNS int4 - AS '@MODULE_FILENAME@','compression_chip' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION setSRID(chip,int4) - RETURNS chip - AS '@MODULE_FILENAME@','setsrid_chip' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION setfactor(chip,float4) - RETURNS chip - AS '@MODULE_FILENAME@','setfactor_chip' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION geometry(CHIP) - RETURNS geometry - AS '@MODULE_FILENAME@','CHIP_to_geom' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION box3d(geometry) - RETURNS box3d - AS '@MODULE_FILENAME@','get_bbox_of_geometry' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION box(geometry) - RETURNS BOX - AS '@MODULE_FILENAME@','geometry2box' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION geometry(box3d) - RETURNS geometry - AS '@MODULE_FILENAME@','get_geometry_of_bbox' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION geometry(text) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_text' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION expand(box3d,float8) - RETURNS box3d - AS '@MODULE_FILENAME@','expand_bbox' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION expand(geometry,float8) - RETURNS geometry - AS '@MODULE_FILENAME@','expand_geometry' - LANGUAGE 'C' WITH (iscachable,isstrict); - --- --- Functions for converting to WKB --- - -CREATEFUNCTION asbinary(geometry) - RETURNS wkb - AS '@MODULE_FILENAME@','asbinary_simple' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION asbinary(geometry,TEXT) - RETURNS wkb - AS '@MODULE_FILENAME@','asbinary_specify' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION bytea(wkb) - RETURNS bytea - AS '@MODULE_FILENAME@','WKBtoBYTEA' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION geometry(wkb) - RETURNS GEOMETRY - AS '@MODULE_FILENAME@','geometryfromWKB_SRID' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION GeomFromWKB(wkb) - RETURNS GEOMETRY - AS '@MODULE_FILENAME@','geometryfromWKB_SRID' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION GeomFromWKB(wkb,int) - RETURNS GEOMETRY - AS '@MODULE_FILENAME@','geometryfromWKB_SRID' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION PointFromWKB(wkb,int) - RETURNS GEOMETRY - AS '@MODULE_FILENAME@','PointfromWKB_SRID' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION PointFromWKB(wkb) - RETURNS GEOMETRY - AS '@MODULE_FILENAME@','PointfromWKB_SRID' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION LineFromWKB(wkb,int) - RETURNS GEOMETRY - AS '@MODULE_FILENAME@','LinefromWKB_SRID' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION LineFromWKB(wkb) - RETURNS GEOMETRY - AS '@MODULE_FILENAME@','LinefromWKB_SRID' - LANGUAGE 'C' WITH (iscachable,isstrict); - - -CREATEFUNCTION LinestringFromWKB(wkb,int) - RETURNS GEOMETRY - AS '@MODULE_FILENAME@','LinefromWKB_SRID' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION LinestringFromWKB(wkb) - RETURNS GEOMETRY - AS '@MODULE_FILENAME@','LinefromWKB_SRID' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION PolyFromWKB(wkb,int) - RETURNS GEOMETRY - AS '@MODULE_FILENAME@','PolyfromWKB_SRID' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION PolyFromWKB(wkb) - RETURNS GEOMETRY - AS '@MODULE_FILENAME@','PolyfromWKB_SRID' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION PolygonFromWKB(wkb,int) - RETURNS GEOMETRY - AS '@MODULE_FILENAME@','PolyfromWKB_SRID' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION PolygonFromWKB(wkb) - RETURNS GEOMETRY - AS '@MODULE_FILENAME@','PolyfromWKB_SRID' - LANGUAGE 'C' WITH (iscachable,isstrict); - - -CREATEFUNCTION MPointFromWKB(wkb,int) - RETURNS GEOMETRY - AS '@MODULE_FILENAME@','MPointfromWKB_SRID' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION MPointFromWKB(wkb) - RETURNS GEOMETRY - AS '@MODULE_FILENAME@','MPointfromWKB_SRID' - LANGUAGE 'C' WITH (iscachable,isstrict); - - -CREATEFUNCTION MultiPointFromWKB(wkb,int) - RETURNS GEOMETRY - AS '@MODULE_FILENAME@','MPointfromWKB_SRID' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION MultiPointFromWKB(wkb) - RETURNS GEOMETRY - AS '@MODULE_FILENAME@','MPointfromWKB_SRID' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION MultiLineFromWKB(wkb,int) - RETURNS GEOMETRY - AS '@MODULE_FILENAME@','MLinefromWKB_SRID' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION MultiLineFromWKB(wkb) - RETURNS GEOMETRY - AS '@MODULE_FILENAME@','MLinefromWKB_SRID' - LANGUAGE 'C' WITH (iscachable,isstrict); - - -CREATEFUNCTION MLineFromWKB(wkb,int) - RETURNS GEOMETRY - AS '@MODULE_FILENAME@','MLinefromWKB_SRID' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION MLineFromWKB(wkb) - RETURNS GEOMETRY - AS '@MODULE_FILENAME@','MLinefromWKB_SRID' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION MPolyFromWKB(wkb,int) - RETURNS GEOMETRY - AS '@MODULE_FILENAME@','MPolyfromWKB_SRID' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION MPolyFromWKB(wkb) - RETURNS GEOMETRY - AS '@MODULE_FILENAME@','MPolyfromWKB_SRID' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION MultiPolyFromWKB(wkb,int) - RETURNS GEOMETRY - AS '@MODULE_FILENAME@','MPolyfromWKB_SRID' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION MultiPolyFromWKB(wkb) - RETURNS GEOMETRY - AS '@MODULE_FILENAME@','MPolyfromWKB_SRID' - LANGUAGE 'C' WITH (iscachable,isstrict); - - - -CREATEFUNCTION GeomCollFromWKB(wkb,int) - RETURNS GEOMETRY - AS '@MODULE_FILENAME@','GCfromWKB_SRID' - LANGUAGE 'C' WITH (iscachable,isstrict); - -CREATEFUNCTION GeomCollFromWKB(wkb) - RETURNS GEOMETRY - AS '@MODULE_FILENAME@','GCfromWKB_SRID' - LANGUAGE 'C' WITH (iscachable,isstrict); - - --- CREATEFUNCTION index_thing(geometry) --- RETURNS BOOL --- AS '@MODULE_FILENAME@' --- LANGUAGE 'C' WITH (isstrict); - --- --- Debugging functions --- - -CREATEFUNCTION npoints(geometry) - RETURNS int4 - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION nrings(geometry) - RETURNS int4 - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict) ; - -CREATEFUNCTION mem_size(geometry) - RETURNS int4 - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - - -CREATEFUNCTION summary(geometry) - RETURNS text - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION translate(geometry,float8,float8,float8) - RETURNS geometry - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict) ; - -CREATEFUNCTION dimension(geometry) - RETURNS int4 - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict) ; - -CREATEFUNCTION geometrytype(geometry) - RETURNS text - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION envelope(geometry) - RETURNS geometry - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION x(geometry) - RETURNS float8 - AS '@MODULE_FILENAME@','x_point' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION y(geometry) - RETURNS float8 - AS '@MODULE_FILENAME@','y_point' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION z(geometry) - RETURNS float8 - AS '@MODULE_FILENAME@','z_point' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION numpoints(geometry) - RETURNS integer - AS '@MODULE_FILENAME@','numpoints_linestring' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION pointn(geometry,integer) - RETURNS geometry - AS '@MODULE_FILENAME@','pointn_linestring' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION exteriorring(geometry) - RETURNS geometry - AS '@MODULE_FILENAME@','exteriorring_polygon' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION numinteriorrings(geometry) - RETURNS integer - AS '@MODULE_FILENAME@','numinteriorrings_polygon' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION interiorringn(geometry,integer) - RETURNS geometry - AS '@MODULE_FILENAME@','interiorringn_polygon' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION numgeometries(geometry) - RETURNS integer - AS '@MODULE_FILENAME@','numgeometries_collection' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION geometryn(geometry,integer) - RETURNS geometry - AS '@MODULE_FILENAME@','geometryn_collection' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION max_distance(geometry,geometry) - RETURNS float8 - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION optimistic_overlap(geometry,geometry,FLOAT8) - RETURNS BOOL - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION segmentize(geometry,FLOAT8) - RETURNS geometry - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION distance(geometry,geometry) - RETURNS float8 - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION astext(geometry) - RETURNS TEXT - AS '@MODULE_FILENAME@','astext_geometry' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION srid(geometry) - RETURNS int4 - AS '@MODULE_FILENAME@','srid_geom' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION geometryfromtext(geometry,int4) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text' - LANGUAGE 'C' WITH (isstrict,iscachable); - - -CREATEFUNCTION geometryfromtext(geometry) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION geomfromtext(geometry,int4) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION geomfromtext(geometry) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION polyfromtext(geometry,int4) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text_poly' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION polygonfromtext(geometry,int4) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text_poly' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION polygonfromtext(geometry) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text_poly' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION mpolyfromtext(geometry,int4) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text_mpoly' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION linefromtext(geometry,int4) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text_line' - LANGUAGE 'C' WITH (isstrict,iscachable); - - -CREATEFUNCTION mlinefromtext(geometry,int4) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text_mline' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION multilinestringfromtext(geometry,int4) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text_mline' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION multilinestringfromtext(geometry) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text_mline' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION pointfromtext(geometry,int4) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text_point' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION mpointfromtext(geometry,int4) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text_mpoint' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION multipointfromtext(geometry,int4) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text_mpoint' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION multipointfromtext(geometry) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text_mpoint' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION geomcollfromtext(geometry,int4) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text_gc' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION setSRID(geometry,int4) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION polyfromtext(geometry) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text_poly' - LANGUAGE 'C' WITH (isstrict,iscachable); - - -CREATEFUNCTION mpolyfromtext(geometry) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text_mpoly' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION multipolygonfromtext(geometry) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text_mpoly' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION multipolygonfromtext(geometry,int) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text_mpoly' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION linefromtext(geometry) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text_line' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION linestringfromtext(geometry) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text_line' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION linestringfromtext(geometry,int) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text_line' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION mlinefromtext(geometry) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text_mline' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION pointfromtext(geometry) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text_point' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION mpointfromtext(geometry) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text_mpoint' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION geomcollfromtext(geometry) - RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text_gc' - LANGUAGE 'C' WITH (isstrict,iscachable); - - -CREATEFUNCTION isempty(geometry) - RETURNS boolean - AS '@MODULE_FILENAME@','isempty' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION issimple(geometry) - RETURNS boolean - AS '@MODULE_FILENAME@','issimple' - LANGUAGE 'C' WITH (isstrict,iscachable); - - -CREATEFUNCTION equals(geometry,geometry) - RETURNS boolean - AS '@MODULE_FILENAME@','geomequals' - LANGUAGE 'C' WITH (isstrict,iscachable); - - --- --- Special spheroid functions --- - -CREATEFUNCTION length_spheroid(geometry,spheroid) - RETURNS FLOAT8 - AS '@MODULE_FILENAME@','length_ellipsoid' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION length3d_spheroid(geometry,spheroid) - RETURNS FLOAT8 - AS '@MODULE_FILENAME@','length3d_ellipsoid' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION distance_spheroid(geometry,geometry,spheroid) - RETURNS FLOAT8 - AS '@MODULE_FILENAME@','distance_ellipsoid' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION distance_sphere(geometry,geometry) - RETURNS FLOAT8 - AS '@MODULE_FILENAME@', 'distance_sphere' - LANGUAGE 'C' WITH (isstrict); - --- --- Generic operations --- - -CREATEFUNCTION multi(geometry) - RETURNS geometry - AS '@MODULE_FILENAME@','fluffType' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION length3d(geometry) - RETURNS FLOAT8 - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION length(geometry) - RETURNS FLOAT8 - AS '@MODULE_FILENAME@','length2d' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION area2d(geometry) - RETURNS FLOAT8 - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION area(geometry) - RETURNS FLOAT8 - AS '@MODULE_FILENAME@','area2d' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION perimeter3d(geometry) - RETURNS FLOAT8 - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION perimeter(geometry) - RETURNS FLOAT8 - AS '@MODULE_FILENAME@','perimeter2d' - LANGUAGE 'C' WITH (isstrict); - ----CREATEFUNCTION truly_inside(geometry,geometry) ---- RETURNS bool ---- AS '@MODULE_FILENAME@' ---- LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION point_inside_circle(geometry,float8,float8,float8) - RETURNS bool - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION startpoint(geometry) - RETURNS geometry - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION endpoint(geometry) - RETURNS geometry - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION isclosed(geometry) - RETURNS boolean - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION centroid(geometry) - RETURNS geometry - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION isring(geometry) - RETURNS boolean - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION pointonsurface(geometry) - RETURNS geometry - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - - --- --- BBox operations --- - -CREATEFUNCTION xmin(box3d) - RETURNS FLOAT8 - AS '@MODULE_FILENAME@','box3d_xmin' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION ymin(box3d) - RETURNS FLOAT8 - AS '@MODULE_FILENAME@','box3d_ymin' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION zmin(box3d) - RETURNS FLOAT8 - AS '@MODULE_FILENAME@','box3d_zmin' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION xmax(box3d) - RETURNS FLOAT8 - AS '@MODULE_FILENAME@','box3d_xmax' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION ymax(box3d) - RETURNS FLOAT8 - AS '@MODULE_FILENAME@','box3d_ymax' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION zmax(box3d) - RETURNS FLOAT8 - AS '@MODULE_FILENAME@','box3d_zmax' - LANGUAGE 'C' WITH (isstrict,iscachable); - -CREATEFUNCTION box3dtobox(box3d) - RETURNS BOX - AS '@MODULE_FILENAME@','box3dtobox' - LANGUAGE 'C' WITH (isstrict,iscachable); - --- --- Aggregate functions --- - -CREATEFUNCTION geom_accum (geometry[],geometry) - RETURNS geometry[] - AS '@MODULE_FILENAME@' - LANGUAGE 'C'; - -CREATEFUNCTION combine_bbox(box3d,geometry) - RETURNS box3d - AS '@MODULE_FILENAME@' - LANGUAGE 'C'; - -CREATE AGGREGATE extent( - sfunc = combine_bbox, - basetype = geometry, - stype = box3d - ); - -CREATEFUNCTION collector(geometry,geometry) - RETURNS geometry - AS '@MODULE_FILENAME@' - LANGUAGE 'C'; - -CREATE AGGREGATE memcollect( - sfunc = collector, - basetype = geometry, - stype = geometry - ); - -CREATEFUNCTION collect_garray (geometry[]) - RETURNS geometry - AS '@MODULE_FILENAME@' - LANGUAGE 'C'; - -CREATE AGGREGATE collect ( - sfunc = geom_accum, - basetype = geometry, - stype = geometry[], - finalfunc = collect_garray - ); - - --- --- Operator definitions --- - -CREATEFUNCTION geometry_overleft(geometry, geometry) - RETURNS bool - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION geometry_overright(geometry, geometry) - RETURNS bool - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION geometry_left(geometry, geometry) - RETURNS bool - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION geometry_right(geometry, geometry) - RETURNS bool - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION geometry_contain(geometry, geometry) - RETURNS bool - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION geometry_contained(geometry, geometry) - RETURNS bool - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION geometry_overlap(geometry, geometry) - RETURNS bool - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION geometry_same(geometry, geometry) - RETURNS bool - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - --- --- Sorting functions --- - -CREATEFUNCTION geometry_lt(geometry, geometry) - RETURNS bool - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION geometry_le(geometry, geometry) - RETURNS bool - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION geometry_gt(geometry, geometry) - RETURNS bool - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION geometry_ge(geometry, geometry) - RETURNS bool - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION geometry_eq(geometry, geometry) - RETURNS bool - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION geometry_cmp(geometry, geometry) - RETURNS integer - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - --- --- Two dimensional to three dimensional forces --- - -CREATEFUNCTION force_2d(geometry) - RETURNS geometry - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION force_3d(geometry) - RETURNS geometry - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - --- --- Force collection --- - -CREATEFUNCTION force_collection(geometry) - RETURNS geometry - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - --- --- Operator definitions --- - -CREATE OPERATOR << ( - LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_left, - COMMUTATOR = '>>', - RESTRICT = positionsel, JOIN = positionjoinsel -); - -CREATE OPERATOR &< ( - LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_overleft, - COMMUTATOR = '&>', - RESTRICT = positionsel, JOIN = positionjoinsel -); - -CREATE OPERATOR && ( - LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_overlap, - COMMUTATOR = '&&', - RESTRICT = postgis_gist_sel, JOIN = positionjoinsel -); - -CREATE OPERATOR &> ( - LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_overright, - COMMUTATOR = '&<', - RESTRICT = positionsel, JOIN = positionjoinsel -); - -CREATE OPERATOR >> ( - LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_right, - COMMUTATOR = '<<', - RESTRICT = positionsel, JOIN = positionjoinsel -); - -CREATE OPERATOR ~= ( - LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_same, - COMMUTATOR = '~=', - RESTRICT = eqsel, JOIN = eqjoinsel -); - -CREATE OPERATOR @ ( - LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_contained, - COMMUTATOR = '~', - RESTRICT = contsel, JOIN = contjoinsel -); - -CREATE OPERATOR ~ ( - LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_contain, - COMMUTATOR = '@', - RESTRICT = contsel, JOIN = contjoinsel -); - --- --- Sorting operators for Btree --- - -CREATE OPERATOR < ( - LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_lt, - COMMUTATOR = '>', NEGATOR = '>=', - RESTRICT = contsel, JOIN = contjoinsel -); - -CREATE OPERATOR <= ( - LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_le, - COMMUTATOR = '>=', NEGATOR = '>', - RESTRICT = contsel, JOIN = contjoinsel -); - -CREATE OPERATOR = ( - LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_eq, - COMMUTATOR = '=', -- we might implement a faster negator here - RESTRICT = contsel, JOIN = contjoinsel -); - -CREATE OPERATOR >= ( - LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_ge, - COMMUTATOR = '<=', NEGATOR = '<', - RESTRICT = contsel, JOIN = contjoinsel -); -CREATE OPERATOR > ( - LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_gt, - COMMUTATOR = '<', NEGATOR = '<=', - RESTRICT = contsel, JOIN = contjoinsel -); - --- --- GEOS Functions --- - - -CREATEFUNCTION intersection(geometry,geometry) - RETURNS geometry - AS '@MODULE_FILENAME@','intersection' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION buffer(geometry,float8) - RETURNS geometry - AS '@MODULE_FILENAME@','buffer' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION convexhull(geometry) - RETURNS geometry - AS '@MODULE_FILENAME@','convexhull' - LANGUAGE 'C' WITH (isstrict); - - -CREATEFUNCTION difference(geometry,geometry) - RETURNS geometry - AS '@MODULE_FILENAME@','difference' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION boundary(geometry) - RETURNS geometry - AS '@MODULE_FILENAME@','boundary' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION symdifference(geometry,geometry) - RETURNS geometry - AS '@MODULE_FILENAME@','symdifference' - LANGUAGE 'C' WITH (isstrict); - - -CREATEFUNCTION symmetricdifference(geometry,geometry) - RETURNS geometry - AS '@MODULE_FILENAME@','symdifference' - LANGUAGE 'C' WITH (isstrict); - - -CREATEFUNCTION GeomUnion(geometry,geometry) - RETURNS geometry - AS '@MODULE_FILENAME@','geomunion' - LANGUAGE 'C' WITH (isstrict); - -CREATE AGGREGATE MemGeomUnion ( - basetype = geometry, - sfunc = geomunion, - stype = geometry - ); - -CREATEFUNCTION unite_garray (geometry[]) - RETURNS geometry - AS '@MODULE_FILENAME@' - LANGUAGE 'C'; - -CREATE AGGREGATE GeomUnion ( - sfunc = geom_accum, - basetype = geometry, - stype = geometry[], - finalfunc = unite_garray - ); - - -CREATEFUNCTION relate(geometry,geometry) - RETURNS text - AS '@MODULE_FILENAME@','relate_full' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION relate(geometry,geometry,text) - RETURNS boolean - AS '@MODULE_FILENAME@','relate_pattern' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION disjoint(geometry,geometry) - RETURNS boolean - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION touches(geometry,geometry) - RETURNS boolean - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION intersects(geometry,geometry) - RETURNS boolean - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION crosses(geometry,geometry) - RETURNS boolean - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION within(geometry,geometry) - RETURNS boolean - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION contains(geometry,geometry) - RETURNS boolean - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION overlaps(geometry,geometry) - RETURNS boolean - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION isvalid(geometry) - RETURNS boolean - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION geosnoop(geometry) - RETURNS geometry - AS '@MODULE_FILENAME@', 'GEOSnoop' - LANGUAGE 'C' WITH (isstrict); - - --- --- Algorithms --- - -CREATEFUNCTION simplify(geometry, float8) - RETURNS geometry - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -CREATEFUNCTION line_interpolate_point(geometry, float8) - RETURNS geometry - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); - -------------------------------------------------------------------- --- GiST support functions -------------------------------------------------------------------- - -#if USE_VERSION < 73 -#define OPAQUE_TYPE opaque -#else -#define OPAQUE_TYPE internal -#endif - -CREATEFUNCTION ggeometry_consistent(OPAQUE_TYPE,geometry,int4) - RETURNS bool - AS '@MODULE_FILENAME@' - LANGUAGE 'C'; - -CREATEFUNCTION ggeometry_compress(OPAQUE_TYPE) - RETURNS OPAQUE_TYPE - AS '@MODULE_FILENAME@' - LANGUAGE 'C'; - -CREATEFUNCTION rtree_decompress(OPAQUE_TYPE) - RETURNS OPAQUE_TYPE - AS '@MODULE_FILENAME@' - LANGUAGE 'C'; - -#if USE_VERSION == 71 -CREATEFUNCTION ggeometry_penalty(OPAQUE_TYPE,OPAQUE_TYPE,OPAQUE_TYPE) -#else -CREATEFUNCTION gbox_penalty(OPAQUE_TYPE,OPAQUE_TYPE,OPAQUE_TYPE) -#endif - RETURNS OPAQUE_TYPE - AS '@MODULE_FILENAME@' - LANGUAGE 'C'; - -#if USE_VERSION == 71 -CREATEFUNCTION ggeometry_picksplit(OPAQUE_TYPE, OPAQUE_TYPE) -#else -CREATEFUNCTION gbox_picksplit(OPAQUE_TYPE, OPAQUE_TYPE) -#endif - RETURNS OPAQUE_TYPE - AS '@MODULE_FILENAME@' - LANGUAGE 'C'; - -#if USE_VERSION == 71 -CREATEFUNCTION ggeometry_union(bytea, OPAQUE_TYPE) -#else -CREATEFUNCTION gbox_union(bytea, OPAQUE_TYPE) -#endif - RETURNS OPAQUE_TYPE - AS '@MODULE_FILENAME@' - LANGUAGE 'C'; - -#if USE_VERSION == 71 -CREATEFUNCTION ggeometry_same(OPAQUE_TYPE, OPAQUE_TYPE, OPAQUE_TYPE) -#else -CREATEFUNCTION gbox_same(box, box, OPAQUE_TYPE) -#endif - RETURNS OPAQUE_TYPE - AS '@MODULE_FILENAME@' - LANGUAGE 'C'; - -------------------------------------------------------------------- --- R-Tree support functions -------------------------------------------------------------------- - -CREATEFUNCTION geometry_union(geometry,geometry) - RETURNS geometry - AS '@MODULE_FILENAME@' - LANGUAGE 'C'; - -CREATEFUNCTION geometry_inter(geometry,geometry) - RETURNS geometry - AS '@MODULE_FILENAME@' - LANGUAGE 'C'; - -CREATEFUNCTION geometry_size(geometry,opaque) - RETURNS float4 - AS '@MODULE_FILENAME@' - LANGUAGE 'C'; - - -#if USE_VERSION == 71 - --- --- Create opclass index binding entries. --- - -INSERT INTO pg_opclass (opcname, opcdeftype) - SELECT 'gist_geometry_ops', oid - FROM pg_type - WHERE typname = 'geometry'; - -SELECT o.oid AS opoid, o.oprname - INTO TABLE rt_ops_tmp - FROM pg_operator o, pg_type t - WHERE o.oprleft = t.oid AND t.typname = 'geometry'; - --- box_left -INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) - SELECT am.oid, opcl.oid, c.opoid, 1 - FROM pg_am am, pg_opclass opcl, rt_ops_tmp c - WHERE amname = 'gist' AND opcname = 'gist_geometry_ops' - AND c.oprname = '<<'; - --- box_overleft -INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) - SELECT am.oid, opcl.oid, c.opoid, 2 - FROM pg_am am, pg_opclass opcl, rt_ops_tmp c - WHERE amname = 'gist' AND opcname = 'gist_geometry_ops' - AND c.oprname = '&<'; - --- box_overlap -INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) - SELECT am.oid, opcl.oid, c.opoid, 3 - FROM pg_am am, pg_opclass opcl, rt_ops_tmp c - WHERE amname = 'gist' AND opcname = 'gist_geometry_ops' - AND c.oprname = '&&'; - --- box_overright -INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) - SELECT am.oid, opcl.oid, c.opoid, 4 - FROM pg_am am, pg_opclass opcl, rt_ops_tmp c - WHERE amname = 'gist' AND opcname = 'gist_geometry_ops' - AND c.oprname = '&>'; - --- box_right -INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) - SELECT am.oid, opcl.oid, c.opoid, 5 - FROM pg_am am, pg_opclass opcl, rt_ops_tmp c - WHERE amname = 'gist' AND opcname = 'gist_geometry_ops' - AND c.oprname = '>>'; - --- box_same -INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) - SELECT am.oid, opcl.oid, c.opoid, 6 - FROM pg_am am, pg_opclass opcl, rt_ops_tmp c - WHERE amname = 'gist' AND opcname = 'gist_geometry_ops' - AND c.oprname = '~='; - --- box_contains -INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) - SELECT am.oid, opcl.oid, c.opoid, 7 - FROM pg_am am, pg_opclass opcl, rt_ops_tmp c - WHERE amname = 'gist' AND opcname = 'gist_geometry_ops' - AND c.oprname = '~'; - --- box_contained -INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) - SELECT am.oid, opcl.oid, c.opoid, 8 - FROM pg_am am, pg_opclass opcl, rt_ops_tmp c - WHERE amname = 'gist' AND opcname = 'gist_geometry_ops' - AND c.oprname = '@'; - -DROP TABLE rt_ops_tmp; - --- --- Add the entries to amproc for the support methods. --- Note the amprocnum numbers associated with each are specific! --- - -INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum) - SELECT am.oid, opcl.oid, pro.oid, 1 - FROM pg_am am, pg_opclass opcl, pg_proc pro - WHERE amname = 'gist' AND opcname = 'gist_geometry_ops' - AND proname = 'ggeometry_consistent'; - -INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum) - SELECT am.oid, opcl.oid, pro.oid, 2 - FROM pg_am am, pg_opclass opcl, pg_proc pro - WHERE amname = 'gist' AND opcname = 'gist_geometry_ops' - AND proname = 'ggeometry_union'; - -INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum) - SELECT am.oid, opcl.oid, pro.oid, 3 - FROM pg_am am, pg_opclass opcl, pg_proc pro - WHERE amname = 'gist' AND opcname = 'gist_geometry_ops' - AND proname = 'ggeometry_compress'; - -INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum) - SELECT am.oid, opcl.oid, pro.oid, 4 - FROM pg_am am, pg_opclass opcl, pg_proc pro - WHERE amname = 'gist' AND opcname = 'gist_geometry_ops' - AND proname = 'rtree_decompress'; - -INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum) - SELECT am.oid, opcl.oid, pro.oid, 5 - FROM pg_am am, pg_opclass opcl, pg_proc pro - WHERE amname = 'gist' AND opcname = 'gist_geometry_ops' - AND proname = 'ggeometry_penalty'; - -INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum) - SELECT am.oid, opcl.oid, pro.oid, 6 - FROM pg_am am, pg_opclass opcl, pg_proc pro - WHERE amname = 'gist' AND opcname = 'gist_geometry_ops' - AND proname = 'ggeometry_picksplit'; - -INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum) - SELECT am.oid, opcl.oid, pro.oid, 7 - FROM pg_am am, pg_opclass opcl, pg_proc pro - WHERE amname = 'gist' AND opcname = 'gist_geometry_ops' - AND proname = 'ggeometry_same'; - -#elsif USE_VERSION == 72 - --- --- Create opclass index binding entries. --- - -INSERT INTO pg_opclass (opcamid, opcname, opcintype, opcdefault, opckeytype) - VALUES ( - (SELECT oid FROM pg_am WHERE amname = 'gist'), - 'gist_geometry_ops', - (SELECT oid FROM pg_type WHERE typname = 'geometry'), - true, - (SELECT oid FROM pg_type WHERE typname = 'box')); - --- drop table rt_ops_tmp; - -SELECT o.oid AS opoid, o.oprname - INTO TABLE rt_ops_tmp - FROM pg_operator o, pg_type t - WHERE o.oprleft = t.oid - AND t.typname = 'geometry'; - --- poly_left -INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr) - SELECT opcl.oid, 1, true, c.opoid - FROM pg_opclass opcl, rt_ops_tmp c - WHERE - opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist') - and opcname = 'gist_geometry_ops' - and c.oprname = '<<'; - --- poly_overleft -INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr) - SELECT opcl.oid, 2, true, c.opoid - FROM pg_opclass opcl, rt_ops_tmp c - WHERE - opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist') - and opcname = 'gist_geometry_ops' - and c.oprname = '&<'; - --- poly_overlap -INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr) - SELECT opcl.oid, 3, true, c.opoid - FROM pg_opclass opcl, rt_ops_tmp c - WHERE - opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist') - and opcname = 'gist_geometry_ops' - and c.oprname = '&&'; - --- poly_overright -INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr) - SELECT opcl.oid, 4, true, c.opoid - FROM pg_opclass opcl, rt_ops_tmp c - WHERE - opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist') - and opcname = 'gist_geometry_ops' - and c.oprname = '&>'; - --- poly_right -INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr) - SELECT opcl.oid, 5, true, c.opoid - FROM pg_opclass opcl, rt_ops_tmp c - WHERE - opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist') - and opcname = 'gist_geometry_ops' - and c.oprname = '>>'; - --- poly_same -INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr) - SELECT opcl.oid, 6, true, c.opoid - FROM pg_opclass opcl, rt_ops_tmp c - WHERE - opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist') - and opcname = 'gist_geometry_ops' - and c.oprname = '~='; - --- poly_contains -INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr) - SELECT opcl.oid, 7, true, c.opoid - FROM pg_opclass opcl, rt_ops_tmp c - WHERE - opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist') - and opcname = 'gist_geometry_ops' - and c.oprname = '~'; - --- poly_contained -INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr) - SELECT opcl.oid, 8, true, c.opoid - FROM pg_opclass opcl, rt_ops_tmp c - WHERE - opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist') - and opcname = 'gist_geometry_ops' - and c.oprname = '@'; - -DROP TABLE rt_ops_tmp; - --- add the entries to amproc for the support methods --- note the amprocnum numbers associated with each are specific! -INSERT INTO pg_amproc (amopclaid, amprocnum, amproc) - SELECT opcl.oid, 1, pro.oid - FROM pg_opclass opcl, pg_proc pro - WHERE - opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist') - and opcname = 'gist_geometry_ops' - and proname = 'ggeometry_consistent'; - -INSERT INTO pg_amproc (amopclaid, amprocnum, amproc) - SELECT opcl.oid, 2, pro.oid - FROM pg_opclass opcl, pg_proc pro - WHERE - opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist') - and opcname = 'gist_geometry_ops' - and proname = 'gbox_union'; - -INSERT INTO pg_amproc (amopclaid, amprocnum, amproc) - SELECT opcl.oid, 3, pro.oid - FROM pg_opclass opcl, pg_proc pro - WHERE - opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist') - and opcname = 'gist_geometry_ops' - and proname = 'ggeometry_compress'; - -INSERT INTO pg_amproc (amopclaid, amprocnum, amproc) - SELECT opcl.oid, 4, pro.oid - FROM pg_opclass opcl, pg_proc pro - WHERE - opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist') - and opcname = 'gist_geometry_ops' - and proname = 'rtree_decompress'; - -INSERT INTO pg_amproc (amopclaid, amprocnum, amproc) - SELECT opcl.oid, 5, pro.oid - FROM pg_opclass opcl, pg_proc pro - WHERE - opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist') - and opcname = 'gist_geometry_ops' - and proname = 'gbox_penalty'; - -INSERT INTO pg_amproc (amopclaid, amprocnum, amproc) - SELECT opcl.oid, 6, pro.oid - FROM pg_opclass opcl, pg_proc pro - WHERE - opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist') - and opcname = 'gist_geometry_ops' - and proname = 'gbox_picksplit'; - -INSERT INTO pg_amproc (amopclaid, amprocnum, amproc) - SELECT opcl.oid, 7, pro.oid - FROM pg_opclass opcl, pg_proc pro - WHERE - opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist') - and opcname = 'gist_geometry_ops' - and proname = 'gbox_same'; - -#else // USE_VERSION >= 73 - --- --- Create opclass index bindings --- - -CREATE OPERATOR CLASS gist_geometry_ops - DEFAULT FOR TYPE geometry USING gist AS - OPERATOR 1 << RECHECK, - OPERATOR 2 &< RECHECK, - OPERATOR 3 && RECHECK, - OPERATOR 4 &> RECHECK, - OPERATOR 5 >> RECHECK, - OPERATOR 6 ~= RECHECK, - OPERATOR 7 ~ RECHECK, - OPERATOR 8 @ RECHECK, - FUNCTION 1 ggeometry_consistent (internal, geometry, int4), - FUNCTION 2 gbox_union (bytea, internal), - FUNCTION 3 ggeometry_compress (internal), - FUNCTION 4 rtree_decompress (internal), - FUNCTION 5 gbox_penalty (internal, internal, internal), - FUNCTION 6 gbox_picksplit (internal, internal), - FUNCTION 7 gbox_same (box, box, internal); - -UPDATE pg_opclass - SET opckeytype = (select oid from pg_type where typname = 'box') - WHERE opcname = 'gist_geometry_ops'; - -#if USE_VERSION >= 74 - -CREATE OPERATOR CLASS btree_geometry_ops - DEFAULT FOR TYPE geometry USING btree AS - OPERATOR 1 < , - OPERATOR 2 <= , - OPERATOR 3 = , - OPERATOR 4 >= , - OPERATOR 5 > , - FUNCTION 1 geometry_cmp (geometry, geometry); - -#endif // USE_VERSION >= 74 - - -#endif // USE_VERSION >= 73 - - ------------------------------------------------------------------------ --- 7.3+ explicit casting definitions ------------------------------------------------------------------------ -#if USE_VERSION >= 73 ---CREATE CAST ( chip AS geometry ) WITH FUNCTION geometry(chip) AS IMPLICIT; -CREATE CAST ( geometry AS box3d ) WITH FUNCTION box3d(geometry) AS IMPLICIT; -CREATE CAST ( geometry AS box ) WITH FUNCTION box(geometry) AS IMPLICIT; -CREATE CAST ( box3d AS geometry ) WITH FUNCTION geometry(box3d) AS IMPLICIT; -CREATE CAST ( text AS geometry) WITH FUNCTION geometry(text) AS IMPLICIT; -CREATE CAST ( wkb AS bytea ) WITH FUNCTION bytea(wkb) AS IMPLICIT; -CREATE CAST ( box3d AS box ) WITH FUNCTION box3dtobox(box3d); -CREATE CAST ( geometry AS text ) WITH FUNCTION astext(geometry); -#endif - ------------------------------------------------------------------------ --- ADDGEOMETRYCOLUMN --- , ,
, , , , ------------------------------------------------------------------------ --- --- Type can be one of geometry, GEOMETRYCOLLECTION, POINT, MULTIPOINT, POLYGON, --- MULTIPOLYGON, LINESTRING, or MULTILINESTRING. --- --- Types (except geometry) are checked for consistency using a CHECK constraint --- uses SQL ALTER TABLE command to add the geometry column to the table. --- Addes a row to geometry_columns. --- Addes a constraint on the table that all the geometries MUST have the same --- SRID. Checks the coord_dimension to make sure its between 0 and 3. --- Should also check the precision grid (future expansion). --- Calls fix_geometry_columns() at the end. --- ------------------------------------------------------------------------ -CREATEFUNCTION AddGeometryColumn(varchar,varchar,varchar,varchar,integer,varchar,integer) - RETURNS text - AS -' -DECLARE - catalog_name alias for $1; - schema_name alias for $2; - table_name alias for $3; - column_name alias for $4; - new_srid alias for $5; - new_type alias for $6; - new_dim alias for $7; -#if USE_VERSION >= 73 - rec RECORD; - schema_ok bool; - real_schema name; -#endif - fixgeomres text; - -BEGIN - - IF ( not ( (new_type =''GEOMETRY'') or - (new_type =''GEOMETRYCOLLECTION'') or - (new_type =''POINT'') or - (new_type =''MULTIPOINT'') or - (new_type =''POLYGON'') or - (new_type =''MULTIPOLYGON'') or - (new_type =''LINESTRING'') or - (new_type =''MULTILINESTRING'')) ) - THEN - RAISE EXCEPTION ''Invalid type name - valid ones are: - GEOMETRY, GEOMETRYCOLLECTION, POINT, - MULTIPOINT, POLYGON, MULTIPOLYGON, - LINESTRING, or MULTILINESTRING ''; - return ''fail''; - END IF; - - IF ( (new_dim >3) or (new_dim <0) ) THEN - RAISE EXCEPTION ''invalid dimension''; - return ''fail''; - END IF; - -#if USE_VERSION >= 73 - IF ( schema_name != '''' ) THEN - schema_ok = ''f''; - FOR rec IN SELECT nspname FROM pg_namespace WHERE text(nspname) = schema_name LOOP - schema_ok := ''t''; - END LOOP; - - if ( schema_ok <> ''t'' ) THEN - RAISE NOTICE ''Invalid schema name - using current_schema()''; - SELECT current_schema() into real_schema; - ELSE - real_schema = schema_name; - END IF; - - ELSE - SELECT current_schema() into real_schema; - END IF; -#endif - - - -- Add geometry column - - EXECUTE ''ALTER TABLE '' || -#if USE_VERSION >= 73 - quote_ident(real_schema) || ''.'' || quote_ident(table_name) -#else - quote_ident(table_name) -#endif - || '' ADD COLUMN '' || quote_ident(column_name) || - '' geometry ''; - - - -- Delete stale record in geometry_column (if any) - - EXECUTE ''DELETE FROM geometry_columns WHERE - f_table_catalog = '' || quote_literal('''') || - '' AND f_table_schema = '' || -#if USE_VERSION >= 73 - quote_literal(real_schema) || -#else - quote_literal('''') || -#endif - '' AND f_table_name = '' || quote_literal(table_name) || - '' AND f_geometry_column = '' || quote_literal(column_name); - - - -- Add record in geometry_column - - EXECUTE ''INSERT INTO geometry_columns VALUES ('' || - quote_literal('''') || '','' || -#if USE_VERSION >= 73 - quote_literal(real_schema) || '','' || -#else - quote_literal('''') || '','' || -#endif - quote_literal(table_name) || '','' || - quote_literal(column_name) || '','' || - new_dim || '','' || new_srid || '','' || - quote_literal(new_type) || '')''; - - -- Add table checks - - EXECUTE ''ALTER TABLE '' || -#if USE_VERSION >= 73 - quote_ident(real_schema) || ''.'' || quote_ident(table_name) -#else - quote_ident(table_name) -#endif - || '' ADD CONSTRAINT "enforce_srid_'' || - column_name || ''" CHECK (SRID('' || quote_ident(column_name) || - '') = '' || new_srid || '')'' ; - - IF (not(new_type = ''GEOMETRY'')) THEN - EXECUTE ''ALTER TABLE '' || -#if USE_VERSION >= 73 - quote_ident(real_schema) || ''.'' || quote_ident(table_name) -#else - quote_ident(table_name) -#endif - || '' ADD CONSTRAINT "enforce_geotype_'' || - column_name || ''" CHECK (geometrytype('' || - quote_ident(column_name) || '')='' || - quote_literal(new_type) || '' OR ('' || - quote_ident(column_name) || '') is null)''; - END IF; - - SELECT fix_geometry_columns() INTO fixgeomres; - - return -#if USE_VERSION >= 73 - real_schema || ''.'' || -#endif - table_name || ''.'' || column_name || - '' SRID:'' || new_srid || - '' TYPE:'' || new_type || ''\n '' || - ''geometry_column '' || fixgeomres; -END; -' LANGUAGE 'plpgsql' WITH (isstrict); - ----------------------------------------------------------------------------- --- ADDGEOMETRYCOLUMN ( ,
, , , , ) ----------------------------------------------------------------------------- --- --- This is a wrapper to the real AddGeometryColumn, for use --- when catalogue is undefined --- ----------------------------------------------------------------------------- -CREATEFUNCTION AddGeometryColumn(varchar,varchar,varchar,integer,varchar,integer) RETURNS text AS ' -DECLARE - ret text; -BEGIN - SELECT AddGeometryColumn('''',$1,$2,$3,$4,$5,$6) into ret; - RETURN ret; -END; -' LANGUAGE 'plpgsql' WITH (isstrict); - ----------------------------------------------------------------------------- --- ADDGEOMETRYCOLUMN (
, , , , ) ----------------------------------------------------------------------------- --- --- This is a wrapper to the real AddGeometryColumn, for use --- when catalogue and schema are undefined --- ----------------------------------------------------------------------------- -CREATEFUNCTION AddGeometryColumn(varchar,varchar,integer,varchar,integer) RETURNS text AS ' -DECLARE - ret text; -BEGIN - SELECT AddGeometryColumn('''','''',$1,$2,$3,$4,$5) into ret; - RETURN ret; -END; -' LANGUAGE 'plpgsql' WITH (isstrict); - ------------------------------------------------------------------------ --- DROPGEOMETRYCOLUMN --- , ,
, ------------------------------------------------------------------------ --- --- Removes geometry column reference from geometry_columns table. --- Drops the column with pgsql >= 73. --- Make some silly enforcements on it for pgsql < 73 --- ------------------------------------------------------------------------ -CREATEFUNCTION DropGeometryColumn(varchar, varchar,varchar,varchar) - RETURNS text - AS -' -DECLARE - catalog_name alias for $1; - schema_name alias for $2; - table_name alias for $3; - column_name alias for $4; - myrec RECORD; - okay boolean; - real_schema name; - -BEGIN - - -#if USE_VERSION >= 73 - -- Find, check or fix schema_name - IF ( schema_name != '''' ) THEN - okay = ''f''; - - FOR myrec IN SELECT nspname FROM pg_namespace WHERE text(nspname) = schema_name LOOP - okay := ''t''; - END LOOP; - - IF ( okay <> ''t'' ) THEN - RAISE NOTICE ''Invalid schema name - using current_schema()''; - SELECT current_schema() into real_schema; - ELSE - real_schema = schema_name; - END IF; - ELSE - SELECT current_schema() into real_schema; - END IF; -#else - real_schema = schema_name; -#endif // USE_VERSION >= 73 - - -- Find out if the column is in the geometry_columns table - okay = ''f''; - FOR myrec IN SELECT * from geometry_columns where f_table_schema = text(real_schema) and f_table_name = table_name and f_geometry_column = column_name LOOP - okay := ''t''; - END LOOP; - IF (okay <> ''t'') THEN - RAISE EXCEPTION ''column not found in geometry_columns table''; - RETURN ''f''; - END IF; - - -- Remove ref from geometry_columns table - EXECUTE ''delete from geometry_columns where f_table_schema = '' || - quote_literal(real_schema) || '' and f_table_name = '' || - quote_literal(table_name) || '' and f_geometry_column = '' || - quote_literal(column_name); - -#if USE_VERSION < 73 - -- Remove not-null constraint to table column - EXECUTE ''update pg_attribute set attnotnull = false from pg_class where pg_attribute.attrelid = pg_class.oid and pg_class.relname = '' || quote_literal(table_name) ||'' and pg_attribute.attname = '' || quote_literal(column_name); - -- update the given table/column so that it it all NULLS - EXECUTE ''update "''||table_name||''" set "''||column_name||''"= NULL''; - -- add = NULL constraint to given table/column - EXECUTE ''ALTER TABLE "''||table_name||''" ADD CHECK ("''||column_name||''" IS NULL)''; -#else - -- Remove table column - EXECUTE ''ALTER TABLE '' || quote_ident(real_schema) || ''.'' || - quote_ident(table_name) || '' DROP COLUMN '' || - quote_ident(column_name); -#endif - - - RETURN real_schema || ''.'' || table_name || ''.'' || column_name ||'' effectively removed.''; - -END; -' -LANGUAGE 'plpgsql' WITH (isstrict); - ------------------------------------------------------------------------ --- DROPGEOMETRYCOLUMN --- ,
, ------------------------------------------------------------------------ --- --- This is a wrapper to the real DropGeometryColumn, for use --- when catalogue is undefined --- ------------------------------------------------------------------------ -CREATEFUNCTION DropGeometryColumn(varchar,varchar,varchar) - RETURNS text - AS -' -DECLARE - ret text; -BEGIN - SELECT DropGeometryColumn('''',$1,$2,$3) into ret; - RETURN ret; -END; -' LANGUAGE 'plpgsql' WITH (isstrict); - ------------------------------------------------------------------------ --- DROPGEOMETRYCOLUMN ---
, ------------------------------------------------------------------------ --- --- This is a wrapper to the real DropGeometryColumn, for use --- when catalogue and schema is undefined. --- ------------------------------------------------------------------------ -CREATEFUNCTION DropGeometryColumn(varchar,varchar) - RETURNS text - AS -' -DECLARE - ret text; -BEGIN - SELECT DropGeometryColumn('''','''',$1,$2) into ret; - RETURN ret; -END; -' LANGUAGE 'plpgsql' WITH (isstrict); - ------------------------------------------------------------------------ --- DROPGEOMETRYTABLE --- , ,
------------------------------------------------------------------------ --- --- Drop a table and all its references in geometry_columns --- ------------------------------------------------------------------------ -CREATEFUNCTION DropGeometryTable(varchar, varchar,varchar) - RETURNS text - AS -' -DECLARE - catalog_name alias for $1; - schema_name alias for $2; - table_name alias for $3; - real_schema name; - -BEGIN - -#if USE_VERSION >= 73 - IF ( schema_name = '''' ) THEN - SELECT current_schema() into real_schema; - ELSE - real_schema = schema_name; - END IF; -#endif // USE_VERSION >= 73 - - -- Remove refs from geometry_columns table - EXECUTE ''DELETE FROM geometry_columns WHERE '' || -#if USE_VERSION >= 73 - ''f_table_schema = '' || quote_literal(real_schema) || - '' AND '' || -#endif - '' f_table_name = '' || quote_literal(table_name); - - -- Remove table - EXECUTE ''DROP TABLE '' -#if USE_VERSION >= 73 - || quote_ident(real_schema) || ''.'' || -#endif - quote_ident(table_name); - - RETURN -#if USE_VERSION >= 73 - real_schema || ''.'' || -#endif - table_name ||'' dropped.''; - -END; -' -LANGUAGE 'plpgsql' WITH (isstrict); - ------------------------------------------------------------------------ --- DROPGEOMETRYTABLE --- ,
------------------------------------------------------------------------ --- --- Drop a table and all its references in geometry_columns --- ------------------------------------------------------------------------ -CREATEFUNCTION DropGeometryTable(varchar,varchar) RETURNS text AS -'SELECT DropGeometryTable('''',$1,$2)' -LANGUAGE 'sql' WITH (isstrict); - ------------------------------------------------------------------------ --- DROPGEOMETRYTABLE ---
------------------------------------------------------------------------ --- --- Drop a table and all its references in geometry_columns --- For PG>=73 use current_schema() --- ------------------------------------------------------------------------ -CREATEFUNCTION DropGeometryTable(varchar) RETURNS text AS -'SELECT DropGeometryTable('''','''',$1)' -LANGUAGE 'sql' WITH (isstrict); - ------------------------------------------------------------------------ --- UPDATE_GEOMETRY_STATS() ------------------------------------------------------------------------ --- --- Only meaningful for PG<80. --- Gather statisticts about geometry columns for use --- with cost estimator. --- --- It is defined also for PG>=80 for back-compatibility --- ------------------------------------------------------------------------ -#if USE_VERSION >= 80 -CREATEFUNCTION update_geometry_stats() RETURNS text -AS ' SELECT ''update_geometry_stats() has been obsoleted. Statistics are automatically built running the ANALYZE command''::text' LANGUAGE 'sql'; -#else // USE_VERSION < 80 -CREATEFUNCTION update_geometry_stats() -RETURNS text -AS -' -DECLARE - result text; - stated integer; - fixres text; -BEGIN - - SELECT fix_geometry_columns() INTO fixres; - - UPDATE geometry_columns SET -#if USE_VERSION >= 73 - stats = (build_histogram2d(create_histogram2d( - find_extent(f_table_schema, f_table_name, f_geometry_column), 40), f_table_schema, f_table_name, f_geometry_column)) - FROM pg_class c, pg_attribute a, pg_namespace n - WHERE n.nspname = f_table_schema::name - AND c.relname = f_table_name::name - AND c.relnamespace = n.oid -#else // USE_VERSION < 73 - stats = (build_histogram2d(create_histogram2d( - find_extent(f_table_name, f_geometry_column), - 40), f_table_name, f_geometry_column)) - FROM pg_class c, pg_attribute a - WHERE c.relname = f_table_name::name -#endif - AND a.attname = f_geometry_column::name - AND a.attrelid = c.oid - AND geometry_columns.attrelid is not null; - - GET DIAGNOSTICS stated = ROW_COUNT; - - result = fixres || '' stats:'' || stated::text; - - return result; -END; -' -LANGUAGE 'plpgsql' ; -#endif // USE_VERSION < 80 - ------------------------------------------------------------------------ --- UPDATE_GEOMETRY_STATS(
, ) ------------------------------------------------------------------------ --- --- Only meaningful for PG<80. --- Gather statisticts about a geometry column for use --- with cost estimator. --- --- It is defined also for PG>=80 for back-compatibility --- ------------------------------------------------------------------------ -#if USE_VERSION >= 80 -CREATEFUNCTION update_geometry_stats(varchar,varchar) RETURNS text -AS 'SELECT update_geometry_stats();' LANGUAGE 'sql' ; -#else -CREATEFUNCTION update_geometry_stats(varchar,varchar) RETURNS text -AS -' -DECLARE - tablename aliAS for $1; - columnname aliAS for $2; - stated integer; - result text; - fixres text; -BEGIN - - SELECT fix_geometry_columns() INTO fixres; - - EXECUTE ''UPDATE geometry_columns SET -#if USE_VERSION >= 73 - stats = (build_histogram2d(create_histogram2d( - find_extent(f_table_schema, - f_table_name, - f_geometry_column), 40), - f_table_schema, f_table_name, - f_geometry_column)) - FROM pg_class c, pg_attribute a, pg_namespace n - WHERE n.nspname = f_table_schema::name - AND c.relname = f_table_name::name - AND a.attname = f_geometry_column::name - AND c.relnamespace = n.oid - AND a.attrelid = c.oid -#else // USE_VERSION < 73 - stats = (build_histogram2d(create_histogram2d( - find_extent(f_table_name, f_geometry_column), - 40), f_table_name, f_geometry_column)) - FROM pg_class c, pg_attribute a - WHERE c.relname = f_table_name::name - AND a.attname = f_geometry_column::name - AND a.attrelid = c.oid -#endif - AND f_table_name = '' || quote_literal(tablename) || '' - AND f_geometry_column = '' || quote_literal(columnname) - || '' AND geometry_columns.attrelid is not null''; - - GET DIAGNOSTICS stated = ROW_COUNT; - - result = fixres || '' stats:'' || stated::text; - - return result; -END; -' -LANGUAGE 'plpgsql' ; - -#endif // USE_VERSION < 80 - ------------------------------------------------------------------------ --- CREATE_HISTOGRAM2D( , ) ------------------------------------------------------------------------ --- --- Returns a histgram with 0s in all the boxes. --- ------------------------------------------------------------------------ -CREATEFUNCTION create_histogram2d(box3d,int) - RETURNS histogram2d - AS '@MODULE_FILENAME@','create_histogram2d' - LANGUAGE 'C' with (isstrict); - ------------------------------------------------------------------------ --- BUILD_HISTOGRAM2D( , , ) ------------------------------------------------------------------------ -CREATEFUNCTION build_histogram2d (histogram2d,text,text) - RETURNS histogram2d - AS '@MODULE_FILENAME@','build_histogram2d' - LANGUAGE 'C' with (isstrict); - -#if USE_VERSION >= 73 ------------------------------------------------------------------------ --- BUILD_HISTOGRAM2D(,,,) ------------------------------------------------------------------------ --- This is a wrapper to the omonimous schema unaware function, --- thanks to Carl Anderson for the idea. ------------------------------------------------------------------------ -CREATEFUNCTION build_histogram2d (histogram2d,text,text,text) -RETURNS histogram2d -AS ' -BEGIN - EXECUTE ''SET local search_path = ''||$2||'',public''; - RETURN public.build_histogram2d($1,$3,$4); -END -' LANGUAGE 'plpgsql' with (isstrict); -#endif // USE_VERSION >= 73 - ------------------------------------------------------------------------ --- EXPLODE_HISTOGRAM2D( , ) ------------------------------------------------------------------------ -CREATEFUNCTION explode_histogram2d (HISTOGRAM2D,text) - RETURNS histogram2d - AS '@MODULE_FILENAME@','explode_histogram2d' - LANGUAGE 'C' with (isstrict); - ------------------------------------------------------------------------ --- ESTIMATE_HISTOGRAM2D( , ) ------------------------------------------------------------------------ -CREATEFUNCTION estimate_histogram2d(HISTOGRAM2D,box) - RETURNS float8 - AS '@MODULE_FILENAME@','estimate_histogram2d' - LANGUAGE 'C' with (isstrict); - - ------------------------------------------------------------------------ --- SVG OUTPUT ------------------------------------------------------------------------ -CREATEFUNCTION AsSvg(geometry,int4,int4) - RETURNS TEXT - AS '@MODULE_FILENAME@','assvg_geometry' - LANGUAGE 'C'; - -CREATEFUNCTION AsSvg(geometry,int4) - RETURNS TEXT - AS '@MODULE_FILENAME@','assvg_geometry' - LANGUAGE 'C'; - -CREATEFUNCTION AsSvg(geometry) - RETURNS TEXT - AS '@MODULE_FILENAME@','assvg_geometry' - LANGUAGE 'C'; - -END TRANSACTION; diff --git a/hwgeom/postgis_algo.c b/hwgeom/postgis_algo.c deleted file mode 100644 index f0994bc13..000000000 --- a/hwgeom/postgis_algo.c +++ /dev/null @@ -1,512 +0,0 @@ -/********************************************************************** - * $Id$ - * - * PostGIS - Spatial Types for PostgreSQL - * http://postgis.refractions.net - * Copyright 2001-2003 Refractions Research Inc. - * - * This is free software; you can redistribute and/or modify it under - * the terms of the GNU General Public Licence. See the COPYING file. - * - ********************************************************************** - * $Log$ - * Revision 1.1 2004/09/20 07:50:06 strk - * prepared to contain old internal representation code - * - * Revision 1.3 2004/04/27 13:50:59 strk - * Fixed bug in simplify() that was using the square of the given tolerance. - * - * Revision 1.2 2004/01/21 19:04:03 strk - * Added line_interpolate_point function by jsunday@rochgrp.com - * - * Revision 1.1 2003/10/27 10:21:15 strk - * Initial import. - * - **********************************************************************/ - -#include "postgres.h" -#include "postgis.h" - - -/*********************************************************************** - * Simple Douglas-Peucker line simplification. - * No checks are done to avoid introduction of self-intersections. - * No topology relations are considered. - * - * --strk@keybit.net; - ***********************************************************************/ - -#define SAMEPOINT(a,b) ((a)->x==(b)->x&&(a)->y==(b)->y&&(a)->z==(b)->z) -#define VERBOSE 0 - -#if VERBOSE > 0 -#undef REPORT_POINTS_REDUCTION -#undef REPORT_RINGS_REDUCTION -#define REPORT_RINGS_ADJUSTMENTS -#endif - -#undef CHECK_RING_IS_CLOSE - - -/* - * Search farthest point from segment p1-p2 - * returns distance in an int pointer - */ -void DP_findsplit(POINT3D *pts, int npts, int p1, int p2, - int *split, double *dist) -{ - int k; - POINT3D *pa, *pb, *pk; - double tmp; - -#if VERBOSE > 4 -elog(NOTICE, "DP_findsplit called"); -#endif - - *dist = -1; - *split = p1; - - if (p1 + 1 < p2) - { - - pa = &(pts[p1]); - pb = &(pts[p2]); - -#if VERBOSE > 4 -elog(NOTICE, "DP_findsplit: P%d(%f,%f) to P%d(%f,%f)", - p1, pa->x, pa->y, p2, pb->x, pb->y); -#endif - - for (k=p1+1; k 4 -elog(NOTICE, "DP_findsplit: P%d(%f,%f)", k, pk->x, pk->y); -#endif - - /* distance computation */ - tmp = distance_pt_seg(pk, pa, pb); - - if (tmp > *dist) - { - *dist = tmp; /* record the maximum */ - *split = k; -#if VERBOSE > 4 -elog(NOTICE, "DP_findsplit: P%d is farthest (%g)", k, *dist); -#endif - } - } - - } /* length---should be redone if can == 0 */ - - else - { -#if VERBOSE > 3 -elog(NOTICE, "DP_findsplit: segment too short, no split/no dist"); -#endif - } - -} - - -void -DP_simplify(POINT3D *inpts, int inptsn, POINT3D **outpts, int *outptsn, double epsilon) -{ - int stack[inptsn]; /* recursion stack */ - int sp=-1; /* recursion stack pointer */ - int p1, split; - double dist; - POINT3D *outpoints; - int numoutpoints=0; - - p1 = 0; - stack[++sp] = inptsn-1; - -#if VERBOSE > 4 - elog(NOTICE, "DP_simplify called"); -#endif - - outpoints = (POINT3D *)palloc( sizeof(POINT3D) * inptsn); - memcpy(outpoints, inpts, sizeof(POINT3D)); - numoutpoints++; - -#if VERBOSE > 3 -elog(NOTICE, "DP_simplify: added P0 to simplified point array (size 1)"); -#endif - - - do - { - - DP_findsplit(inpts, inptsn, p1, stack[sp], &split, &dist); -#if VERBOSE > 3 - elog(NOTICE, "DP_simplify: farthest point from P%d-P%d is P%d (dist. %g)", p1, stack[sp], split, dist); -#endif - - if (dist > epsilon) { - stack[++sp] = split; - } else { - /* - outpoints = repalloc( outpoints, sizeof(POINT3D) * numoutpoints+1 ); - if ( outpoints == NULL ) elog(NOTICE, "Out of virtual memory"); - */ - memcpy(outpoints+numoutpoints, &(inpts[stack[sp]]), - sizeof(POINT3D)); - numoutpoints++; -#if VERBOSE > 3 -elog(NOTICE, "DP_simplify: added P%d to simplified point array (size: %d)", - stack[sp], numoutpoints); -#endif - p1 = stack[sp--]; - } -#if VERBOSE > 5 -elog(NOTICE, "stack pointer = %d", sp); -#endif - } - while (! (sp<0) ); - - /* - * If we have reduced the number of points realloc - * outpoints array to free up some memory. - * Might be turned on and of with a SAVE_MEMORY define ... - */ - if ( numoutpoints < inptsn ) - { - outpoints = (POINT3D *)repalloc(outpoints, sizeof(POINT3D)*numoutpoints); - if ( outpoints == NULL ) { - elog(ERROR, "Out of virtual memory"); - } - } - - *outpts = outpoints; - *outptsn = numoutpoints; -} - -char * -simplify_line3d(LINE3D *iline, double dist) -{ - POINT3D *ipts; - POINT3D *opts; - int iptsn, optsn, olinesize; - LINE3D *oline; - - ipts = iline->points; - iptsn = iline->npoints; - - DP_simplify(ipts, iptsn, &opts, &optsn, dist); - - oline = make_line(optsn, opts, &olinesize); - - return (char *)oline; -} - -char * -simplify_polygon3d(POLYGON3D *ipoly, double dist) -{ - POINT3D *ipts; - POINT3D *opts; - int iptsn, optsn, size; - int nrings; - int pts_per_ring[ipoly->nrings]; - POLYGON3D *opoly; - int ri; - POINT3D *allpts = NULL; - int allptsn = 0; - int pt_off = 0; /* point offset for each ring */ - - nrings = 0; - -#ifdef REPORT_RINGS_REDUCTION -elog(NOTICE, "simplify_polygon3d: simplifying polygon with %d rings", - ipoly->nrings); -#endif - - /* Points start here */ - ipts = (POINT3D *) ((char *)&(ipoly->npoints[ipoly->nrings] )); - - pt_off=0; - for (ri=0; rinrings; pt_off += ipoly->npoints[ri++]) - { - iptsn = ipoly->npoints[ri]; - -#ifdef CHECK_RING_IS_CLOSE - if ( ! SAMEPOINT(ipts+pt_off, ipts+pt_off+iptsn-1) ) - elog(NOTICE, "First point != Last point"); -#endif - - DP_simplify(ipts+pt_off, iptsn, &opts, &optsn, dist); - if ( optsn < 2 ) - { - /* There as to be an error in DP_simplify */ - elog(NOTICE, "DP_simplify returned a <2 pts array"); - pfree(opts); - continue; - } - -#ifdef CHECK_RING_IS_CLOSE - if ( ! SAMEPOINT(opts, opts+optsn-1) ) - elog(NOTICE, "First point != Last point"); -#endif - - - if ( optsn < 4 ) - { - pfree(opts); -#ifdef REPORT_RINGS_ADJUSTMENTS - elog(NOTICE, "simplify_polygon3d: ring%d skipped ( <4 pts )", ri); -#endif - if ( ri ) continue; - else break; - } - - -#ifdef REPORT_POINTS_REDUCTION -elog(NOTICE, "simplify_polygon3d: ring%d simplified from %d to %d points", ri, iptsn, optsn); -#endif - - - /* - * Add ring to simplified ring array - * (TODO: dinamic allocation of pts_per_ring) - */ - pts_per_ring[nrings++] = optsn; - if ( ! allptsn ) { - allptsn = optsn; - allpts = palloc(sizeof(POINT3D)*allptsn); - memcpy(allpts, opts, sizeof(POINT3D)*optsn); - } else { - allptsn += optsn; - allpts = repalloc(allpts, sizeof(POINT3D)*allptsn); - memcpy(allpts+(allptsn-optsn), opts, sizeof(POINT3D)*optsn); - } - pfree(opts); - - if ( ! allpts ) { - elog(NOTICE, "Error allocating memory for all ring points"); - return NULL; - } - - } - -#ifdef REPORT_RINGS_REDUCTION -elog(NOTICE, "simplify_polygon3d: simplified polygon with %d rings", nrings); -#endif - - if ( nrings ) - { - opoly = make_polygon(nrings, pts_per_ring, allpts, allptsn, &size); - pfree(allpts); - return (char *)opoly; - } - else - { - return NULL; - } - -} - -char * -simplify_point3d(POINT3D *ipoint, double dist) -{ - return (char *)ipoint; -} - -PG_FUNCTION_INFO_V1(simplify); -Datum simplify(PG_FUNCTION_ARGS) -{ - Datum datum; - BOX3D *bbox; - GEOMETRY *orig_geom; - GEOMETRY *simp_geom = NULL; - char *orig_obj; /* pointer to each object in orig_geom */ - char *simp_obj; /* pointer to each simplified object */ - int simp_obj_size; /* size of simplified object */ - int32 *offsets; - int i; - double dist; - - if ( PG_ARGISNULL(0) ) PG_RETURN_NULL(); - datum = PG_GETARG_DATUM(0); - orig_geom = (GEOMETRY *)PG_DETOAST_DATUM(datum); - - if ( PG_ARGISNULL(1) ) PG_RETURN_NULL(); - dist = PG_GETARG_FLOAT8(1); - - /* - * Three or more points on a straight line will still collapse! - */ - // if ( dist == 0 ) PG_RETURN_POINTER(orig_geom); - - offsets = (int32 *) ( ((char *) &(orig_geom->objType[0] )) + - sizeof(int32) * orig_geom->nobjs ); - - - /* - * Simplify each subobject indipendently. - * No topology relations kept. - */ - for(i=0;inobjs; i++) - { - orig_obj = (char *) orig_geom+offsets[i]; - - if ( orig_geom->objType[i] == LINETYPE ) - { - simp_obj = simplify_line3d((LINE3D *)orig_obj, dist); - } - else if ( orig_geom->objType[i] == POLYGONTYPE ) - { - simp_obj = simplify_polygon3d((POLYGON3D *)orig_obj, dist); - } - else if ( orig_geom->objType[i] == POINTTYPE ) - { - simp_obj = simplify_point3d((POINT3D *)orig_obj, dist); - } - else - { - elog(NOTICE, "Unknown geometry type"); - PG_RETURN_NULL(); - } - - /* Simplified object degenerated to empty set */ - if ( ! simp_obj ) continue; - - /* Get size of simplified object */ - simp_obj_size = size_subobject(simp_obj, orig_geom->objType[i]); - - /* Create one-object geometry (will add objects later) */ - if ( simp_geom == NULL ) - { - simp_geom = make_oneobj_geometry( - simp_obj_size, simp_obj, orig_geom->objType[i], - orig_geom->is3d, orig_geom->SRID, orig_geom->scale, - orig_geom->offsetX, orig_geom->offsetY); - } - - /* Add object to already initialized geometry */ - else - { - simp_geom = add_to_geometry( - simp_geom, simp_obj_size, simp_obj, - orig_geom->objType[i] ); - } - - /* Error in simplified geometry construction */ - if ( ! simp_geom ) - { - elog(ERROR, "geometry construction failed at iteration %d", i); - PG_RETURN_NULL(); - } - - } - - if ( simp_geom == NULL ) PG_RETURN_NULL(); - - /* Calculate the bounding box */ - bbox = bbox_of_geometry(simp_geom); - memcpy(&(simp_geom->bvol), bbox, sizeof(BOX3D)); - pfree(bbox); - - - simp_geom->type = orig_geom->type; - PG_RETURN_POINTER(simp_geom); -} -/*********************************************************************** - * --strk@keybit.net; - ***********************************************************************/ - -/*********************************************************************** - * Interpolate a point along a line, useful for Geocoding applications - * SELECT line_interpolate_point( 'LINESTRING( 0 0, 2 2'::geometry, .5 ) - * returns POINT( 1 1 ) - * - * -- jsunday@rochgrp.com; - ***********************************************************************/ -PG_FUNCTION_INFO_V1(line_interpolate_point); -Datum line_interpolate_point(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - double distance = PG_GETARG_FLOAT8(1); - - int32 *offsets1; - LINE3D *line; - POINT3D point; - int nsegs, i; - double length, slength, tlength; - - if( distance < 0 || distance > 1 ) { - elog(ERROR,"line_interpolate_point: 2nd arg isnt within [0,1]"); - PG_RETURN_NULL(); - } - - if( geom->type != LINETYPE ) { - elog(ERROR,"line_interpolate_point: 1st arg isnt a line"); - PG_RETURN_NULL(); - } - - offsets1 = (int32 *) ( ((char *) &(geom->objType[0] )) + - sizeof(int32) * geom->nobjs ); - line = (LINE3D*) ( (char *)geom + offsets1[0] ); - - /* If distance is one of the two extremes, return the point on that - * end rather than doing any expensive computations - */ - if( distance == 0.0 ) { - PG_RETURN_POINTER( - make_oneobj_geometry(sizeof(POINT3D), - /*(char*)&(line->points[0]), POINTTYPE, */ - (char*)&(line->points[0]), POINTTYPE, - geom->is3d, geom->SRID, geom->scale, geom->offsetX, geom->offsetY - ) - ); - } - - if( distance == 1.0 ) { - PG_RETURN_POINTER( - make_oneobj_geometry(sizeof(POINT3D), - (char*)&(line->points[line->npoints-1]), POINTTYPE, - geom->is3d, geom->SRID, geom->scale, geom->offsetX, geom->offsetY - ) - ); - } - - /* Interpolate a point on the line */ - nsegs = line->npoints - 1; - length = line_length2d( line ); - tlength = 0; - for( i = 0; i < nsegs; i++ ) { - POINT3D *p1, *p2; - p1 = &(line->points[i]); - p2 = &(line->points[i+1]); - /* Find the relative length of this segment */ - slength = distance_pt_pt( p1, p2 )/length; - /* If our target distance is before the total length we've seen - * so far. create a new point some distance down the current - * segment. - */ - if( distance < tlength + slength ) { - double dseg = (distance - tlength) / slength; - point.x = (p1->x) + ((p2->x - p1->x) * dseg); - point.y = (p1->y) + ((p2->y - p1->y) * dseg); - point.z = 0; - PG_RETURN_POINTER( - make_oneobj_geometry(sizeof(POINT3D), - (char*)&point, POINTTYPE, - geom->is3d, geom->SRID, geom->scale, geom->offsetX, geom->offsetY - ) - ); - } - tlength += slength; - } - /* Return the last point on the line. This shouldn't happen, but - * could if there's some floating point rounding errors. */ - PG_RETURN_POINTER( - make_oneobj_geometry(sizeof(POINT3D), - (char*)&(line->points[line->npoints-1]), POINTTYPE, - geom->is3d, geom->SRID, geom->scale, geom->offsetX, geom->offsetY - ) - ); -} -/*********************************************************************** - * --jsunday@rochgrp.com; - ***********************************************************************/ diff --git a/hwgeom/postgis_chip.c b/hwgeom/postgis_chip.c deleted file mode 100644 index 4602edb5b..000000000 --- a/hwgeom/postgis_chip.c +++ /dev/null @@ -1,277 +0,0 @@ - -/********************************************************************** - * $Id$ - * - * PostGIS - Spatial Types for PostgreSQL - * http://postgis.refractions.net - * Copyright 2001-2003 Refractions Research Inc. - * - * This is free software; you can redistribute and/or modify it under - * the terms of the GNU General Public Licence. See the COPYING file. - * - ********************************************************************** - * $Log$ - * Revision 1.1 2004/09/20 07:50:06 strk - * prepared to contain old internal representation code - * - * Revision 1.7 2004/04/28 22:26:02 pramsey - * Fixed spelling mistake in header text. - * - * Revision 1.6 2003/07/01 18:30:55 pramsey - * Added CVS revision headers. - * - * - **********************************************************************/ - -#include "postgres.h" - - -#include -#include -#include -#include -#include - -#include "access/gist.h" -#include "access/itup.h" -#include "access/rtree.h" - - -#include "fmgr.h" - - -#include "postgis.h" -#include "utils/elog.h" - - - -// input is a string with hex chars in it. Convert to binary and put in the result -PG_FUNCTION_INFO_V1(CHIP_in); -Datum CHIP_in(PG_FUNCTION_ARGS) -{ - char *str = PG_GETARG_CSTRING(0); - CHIP *result; - int size; - int t; - int input_str_len; - int datum_size; - -//printf("chip_in called\n"); - - input_str_len = strlen(str); - - if ( ( ( (int)(input_str_len/2.0) ) *2.0) != input_str_len) - { - elog(ERROR,"CHIP_in parser - should be even number of characters!"); - PG_RETURN_NULL(); - } - - if (strspn(str,"0123456789ABCDEF") != strlen(str) ) - { - elog(ERROR,"CHIP_in parser - input contains bad characters. Should only have '0123456789ABCDEF'!"); - PG_RETURN_NULL(); - } - size = (input_str_len/2) ; - result = (CHIP *) palloc(size); - - - for (t=0;tsize = size; - if (result->size < sizeof(CHIP) ) - { - elog(ERROR,"CHIP_in parser - bad data (too small to be a CHIP)!"); - PG_RETURN_NULL(); - } - - - if (result->endian_hint != 1) - { - //need to do an endian flip - flip_endian_int32( (char *) &result->endian_hint); - - flip_endian_double((char *) &result->bvol.LLB.x); - flip_endian_double((char *) &result->bvol.LLB.y); - flip_endian_double((char *) &result->bvol.LLB.z); - - flip_endian_double((char *) &result->bvol.URT.x); - flip_endian_double((char *) &result->bvol.URT.y); - flip_endian_double((char *) &result->bvol.URT.z); - - flip_endian_int32( (char *) & result->SRID); - //dont know what to do with future[8] ... - - flip_endian_int32( (char *) & result->height); - flip_endian_int32( (char *) & result->width); - flip_endian_int32( (char *) & result->compression); - flip_endian_int32( (char *) & result->factor); - flip_endian_int32( (char *) & result->datatype); - - } - if (result->endian_hint != 1 ) - { - elog(ERROR,"CHIP_in parser - bad data (endian flag != 1)!"); - PG_RETURN_NULL(); - } - datum_size = 4; - - if ( (result->datatype == 6) || (result->datatype == 7) || (result->datatype == 106) || (result->datatype == 107) ) - { - datum_size = 2; - } - if ( (result->datatype == 8) || (result->datatype == 108) ) - { - datum_size=1; - } - - if (result->compression ==0) //only true for non-compressed data - { - if (result->size != (sizeof(CHIP) + datum_size * result->width*result->height) ) - { - elog(ERROR,"CHIP_in parser - bad data (actual size != computed size)!"); - PG_RETURN_NULL(); - } - } - - PG_RETURN_POINTER(result); -} - - -//given a CHIP structure, convert it to Hex and put it in a string -PG_FUNCTION_INFO_V1(CHIP_out); -Datum CHIP_out(PG_FUNCTION_ARGS) -{ - CHIP *chip = (CHIP *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - char *result; - int size_result; - int t; - -//printf("chip_out called\n"); - - size_result = (chip->size ) *2 +1; //+1 for null char - result = palloc (size_result); - result[size_result-1] = 0; //null terminate - - for (t=0; t< (chip->size); t++) - { - deparse_hex( ((unsigned char *) chip)[t], &result[t*2]); - } - PG_RETURN_CSTRING(result); -} - - - -PG_FUNCTION_INFO_V1(CHIP_to_geom); -Datum CHIP_to_geom(PG_FUNCTION_ARGS) -{ - CHIP *chip = (CHIP *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *result; - - POLYGON3D *poly; - POINT3D pts[5]; //5 points around box - int pts_per_ring[1]; - int poly_size; - - //use LLB's z value (we're going to set is3d to false) - - set_point( &pts[0], chip->bvol.LLB.x , chip->bvol.LLB.y , chip->bvol.LLB.z ); - set_point( &pts[1], chip->bvol.URT.x , chip->bvol.LLB.y , chip->bvol.LLB.z ); - set_point( &pts[2], chip->bvol.URT.x , chip->bvol.URT.y , chip->bvol.LLB.z ); - set_point( &pts[3], chip->bvol.LLB.x , chip->bvol.URT.y , chip->bvol.LLB.z ); - set_point( &pts[4], chip->bvol.LLB.x , chip->bvol.LLB.y , chip->bvol.LLB.z ); - - pts_per_ring[0] = 5; //ring has 5 points - - //make a polygon - poly = make_polygon(1, pts_per_ring, pts, 5, &poly_size); - - result = make_oneobj_geometry(poly_size, (char *)poly, POLYGONTYPE, FALSE,chip->SRID, 1.0, 0.0, 0.0); - - PG_RETURN_POINTER(result); - -} - -PG_FUNCTION_INFO_V1(srid_chip); -Datum srid_chip(PG_FUNCTION_ARGS) -{ - CHIP *c = (CHIP *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - - PG_RETURN_INT32(c->SRID); -} - -PG_FUNCTION_INFO_V1(factor_chip); -Datum factor_chip(PG_FUNCTION_ARGS) -{ - CHIP *c = (CHIP *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - - PG_RETURN_FLOAT4(c->factor); -} - - -PG_FUNCTION_INFO_V1(datatype_chip); -Datum datatype_chip(PG_FUNCTION_ARGS) -{ - CHIP *c = (CHIP *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - - PG_RETURN_INT32(c->datatype); -} - -PG_FUNCTION_INFO_V1(compression_chip); -Datum compression_chip(PG_FUNCTION_ARGS) -{ - CHIP *c = (CHIP *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - - PG_RETURN_INT32(c->compression); -} - - -PG_FUNCTION_INFO_V1(height_chip); -Datum height_chip(PG_FUNCTION_ARGS) -{ - CHIP *c = (CHIP *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - - PG_RETURN_INT32(c->height); -} - -PG_FUNCTION_INFO_V1(width_chip); -Datum width_chip(PG_FUNCTION_ARGS) -{ - CHIP *c = (CHIP *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - - PG_RETURN_INT32(c->width); -} - - - -PG_FUNCTION_INFO_V1(setsrid_chip); -Datum setsrid_chip(PG_FUNCTION_ARGS) -{ - CHIP *c = (CHIP *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - int32 new_srid = PG_GETARG_INT32(1); - CHIP *result; - - result = (CHIP *) palloc(c->size); - - memcpy(result,c,c->size); - result->SRID = new_srid; - - PG_RETURN_POINTER(result); -} - -PG_FUNCTION_INFO_V1(setfactor_chip); -Datum setfactor_chip(PG_FUNCTION_ARGS) -{ - CHIP *c = (CHIP *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - float factor = PG_GETARG_FLOAT4(1); - CHIP *result; - - result = (CHIP *) palloc(c->size); - - memcpy(result,c,c->size); - result->factor = factor; - - PG_RETURN_POINTER(result); -} diff --git a/hwgeom/postgis_debug.c b/hwgeom/postgis_debug.c deleted file mode 100644 index 2521a1075..000000000 --- a/hwgeom/postgis_debug.c +++ /dev/null @@ -1,337 +0,0 @@ - -/********************************************************************** - * $Id$ - * - * PostGIS - Spatial Types for PostgreSQL - * http://postgis.refractions.net - * Copyright 2001-2003 Refractions Research Inc. - * - * This is free software; you can redistribute and/or modify it under - * the terms of the GNU General Public Licence. See the COPYING file. - * - ********************************************************************** - * $Log$ - * Revision 1.1 2004/09/20 07:50:06 strk - * prepared to contain old internal representation code - * - * Revision 1.16 2004/08/20 10:23:19 strk - * removed leak from mem_size() - * - * Revision 1.15 2004/04/28 22:26:02 pramsey - * Fixed spelling mistake in header text. - * - * Revision 1.14 2004/01/13 20:30:19 strk - * Added useless PG_RETURN_NULL() call to make compiler happy - * - * Revision 1.13 2003/11/19 18:01:31 strk - * CR removed - * - * Revision 1.12 2003/09/16 20:27:12 dblasby - * added ability to delete geometries. - * - * Revision 1.11 2003/08/08 18:19:20 dblasby - * Conformance changes. - * Removed junk from postgis_debug.c and added the first run of the long - * transaction locking support. (this will change - dont use it) - * conformance tests were corrected - * some dos cr/lf removed - * empty geometries i.e. GEOMETRYCOLLECT(EMPTY) added (with indexing support) - * pointN(,1) now returns the first point (used to return 2nd) - * - * Revision 1.10 2003/07/25 17:08:37 pramsey - * Moved Cygwin endian define out of source files into postgis.h common - * header file. - * - * Revision 1.9 2003/07/01 18:30:55 pramsey - * Added CVS revision headers. - * - * - **********************************************************************/ - -#include "postgres.h" - - -#include -#include -#include -#include -#include - -#include "access/gist.h" -#include "access/itup.h" -#include "access/rtree.h" - - -#include "fmgr.h" - - -#include "postgis.h" -#include "utils/elog.h" - -#include "executor/spi.h" -#include "commands/trigger.h" - - -#define SHOW_DIGS_DOUBLE 15 -#define MAX_DIGS_DOUBLE (SHOW_DIGS_DOUBLE + 6 + 1 + 3 +1) - - -// #define DEBUG_GIST -//#define DEBUG_GIST2 - - - - - -//find the size of geometry -PG_FUNCTION_INFO_V1(mem_size); -Datum mem_size(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - int32 size = geom->size; - PG_FREE_IF_COPY(geom,0); - PG_RETURN_INT32(size); -} - - - -//get summary info on a GEOMETRY -PG_FUNCTION_INFO_V1(summary); -Datum summary(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - int32 *offsets1; - char *o1; - int32 type1,j,i; - POLYGON3D *poly; - LINE3D *line; - char *result; - int size; - char tmp[100]; - text *mytext; - - - size = 1; - result = palloc(1); - result[0] = 0; //null terminate it - - - offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ; - - //now have to do a scan of each object - - for (j=0; j< geom1->nobjs; j++) //for each object in geom1 - { - o1 = (char *) geom1 +offsets1[j] ; - type1= geom1->objType[j]; - - if (type1 == POINTTYPE) //point - { - size += 30; - result = repalloc(result,size); - sprintf(tmp,"Object %i is a POINT()\n",j); - strcat(result,tmp); - } - - if (type1 == LINETYPE) //line - { - line = (LINE3D *) o1; - - size += 57; - result = repalloc(result,size); - sprintf(tmp,"Object %i is a LINESTRING() with %i points\n",j,line->npoints); - strcat(result,tmp); - } - - if (type1 == POLYGONTYPE) //POLYGON - { - poly = (POLYGON3D *) o1; - - size += 57*(poly->nrings +1); - result = repalloc(result,size); - sprintf(tmp,"Object %i is a POLYGON() with %i rings\n",j,poly->nrings); - strcat(result,tmp); - for (i=0; inrings;i++) - { - sprintf(tmp," + ring %i has %i points\n",i,poly->npoints[i]); - strcat(result,tmp); - } - } - } - - // create a text obj to return - mytext = (text *) palloc(VARHDRSZ + strlen(result) ); - VARATT_SIZEP(mytext) = VARHDRSZ + strlen(result) ; - memcpy(VARDATA(mytext) , result, strlen(result) ); - pfree(result); - PG_RETURN_POINTER(mytext); -} - - - - - -extern Datum lockcheck(PG_FUNCTION_ARGS); - -PG_FUNCTION_INFO_V1(lockcheck); - -Datum lockcheck (PG_FUNCTION_ARGS) -{ - TriggerData *trigdata = (TriggerData *) fcinfo->context; - char *colname ; - int id; - HeapTuple rettuple; - TupleDesc tupdesc; - int SPIcode; - char *relname; - bool isnull; - char query[1024]; - int pk_type_oid; - char *pk_id = NULL; - - - elog(NOTICE,"in lockcheck()"); - - /* Make sure trigdata is pointing at what I expect */ - if (!CALLED_AS_TRIGGER(fcinfo)) - elog(ERROR, "lockcheck: not fired by trigger manager"); - - rettuple = trigdata->tg_newtuple; - tupdesc = trigdata->tg_relation->rd_att; - - /* Connect to SPI manager */ - SPIcode = SPI_connect(); - - if (SPIcode != SPI_OK_CONNECT) - { - elog(ERROR,"lockcheck: couldnt open a connection to SPI"); - PG_RETURN_NULL() ; - } - - relname = SPI_getrelname(trigdata->tg_relation); - - colname = trigdata->tg_trigger->tgargs[0]; - - - - - elog(NOTICE,"trigger was executed on the relation: '%s', with attribute named '%s', with locktable named '%s'", relname,colname,"authorization_table"); - - //get the value - - pk_type_oid =SPI_gettypeid ( tupdesc , SPI_fnumber(tupdesc,colname)); - elog(NOTICE,"primary key type # = %i", pk_type_oid ) ; - - if (pk_type_oid == 23) //int4 - { - int id = (int) DatumGetInt32( SPI_getbinval(rettuple, tupdesc, SPI_fnumber(tupdesc,colname), &isnull) ); - if (isnull) - { - elog(ERROR,"lockcheck - column (%s) of table (%s) is null!",colname,relname); - } - pk_id = palloc(100); - sprintf(pk_id,"%i",id); - } - else if (pk_type_oid == 25) // text - { - Datum id = ( SPI_getbinval(rettuple, tupdesc, SPI_fnumber(tupdesc,colname), &isnull) ); - if (isnull) - { - elog(ERROR,"lockcheck - column (%s) of table (%s) is null!",colname,relname); - } - pk_id = DatumGetCString(DirectFunctionCall1(textout,id)); - - } - else if (pk_type_oid == 1043) // varchar - { - Datum id = ( SPI_getbinval(rettuple, tupdesc, SPI_fnumber(tupdesc,colname), &isnull) ); - if (isnull) - { - elog(ERROR,"lockcheck - column (%s) of table (%s) is null!",colname,relname); - } - pk_id = DatumGetCString(DirectFunctionCall1(varcharout,id)); - } - else - { - elog(ERROR,"id column (%s) of table (%s) has to be either int4, text, or varchar. Its - %s (oid %i)",colname,relname,SPI_gettype ( tupdesc , SPI_fnumber(tupdesc,colname) ) ,pk_type_oid ); - } - - - id = (int) DatumGetInt32( SPI_getbinval(rettuple, tupdesc, SPI_fnumber(tupdesc,colname), &isnull) ); - - sprintf(query,"SELECT authid FROM %s WHERE expires >= now() AND tname = '%s' and fid = '%s'::text", "authorization_table",relname,pk_id); - elog(NOTICE,"about to execute :%s", query); - - SPIcode = SPI_exec(query,0); - if (SPIcode !=SPI_OK_SELECT ) - elog(ERROR,"couldnt execute to test for lock :%s",query); - - - if (SPI_processed >0) - { - // there is a lock - check to see if I have rights to it! - - TupleDesc tupdesc = SPI_tuptable->tupdesc; - SPITupleTable *tuptable = SPI_tuptable; - HeapTuple tuple = tuptable->vals[0]; - char *lockcode = SPI_getvalue(tuple, tupdesc, 1); - - elog(NOTICE,"there is a lock on this row!"); - - // check to see if temp_lock_have_table table exists (it might not exist if they own no locks - sprintf(query,"SELECT * FROM pg_class WHERE relname = 'temp_lock_have_table'"); - SPIcode = SPI_exec(query,0); - if (SPIcode !=SPI_OK_SELECT ) - elog(ERROR,"couldnt execute to test for lockkey temp table :%s",query); - if (SPI_processed ==0) - { - elog(NOTICE,"I do not own any locks (no lock table) - I cannot modify the row"); - //PG_RETURN_NULL(); - SPI_finish(); - //return NULL; - elog(ERROR,"attemted to modify a locked row that I do not have authorization for!"); - } - - - sprintf(query,"SELECT * FROM temp_lock_have_table WHERE xideq(transid , getTransactionID() ) AND lockcode ='%s'",lockcode); - elog(NOTICE,"about to execute :%s", query); - - SPIcode = SPI_exec(query,0); - if (SPIcode !=SPI_OK_SELECT ) - elog(ERROR,"couldnt execute to test for lock aquire:%s",query); - - if (SPI_processed >0) - { - elog(NOTICE,"I own the lock - I can modify the row"); - SPI_finish(); - return PointerGetDatum(rettuple); - } - - elog(NOTICE,"I do not own the lock - I cannot modify the row"); - //PG_RETURN_NULL(); - SPI_finish(); - //return NULL; - elog(ERROR,"attemted to modify a locked row that I do not have authorization for!"); - PG_RETURN_NULL(); - } - else - { - elog(NOTICE,"there is NOT a lock on this row!"); - SPI_finish(); - return PointerGetDatum(rettuple); - } - -} - - -extern Datum getTransactionID(PG_FUNCTION_ARGS); - -PG_FUNCTION_INFO_V1(getTransactionID); - -Datum getTransactionID(PG_FUNCTION_ARGS) -{ - TransactionId xid = GetCurrentTransactionId(); - PG_RETURN_DATUM( TransactionIdGetDatum(xid) ); -} - - diff --git a/hwgeom/postgis_estimate.c b/hwgeom/postgis_estimate.c deleted file mode 100644 index 995067cbb..000000000 --- a/hwgeom/postgis_estimate.c +++ /dev/null @@ -1,1950 +0,0 @@ - -/********************************************************************** - * $Id$ - * - * PostGIS - Spatial Types for PostgreSQL - * http://postgis.refractions.net - * Copyright 2001-2003 Refractions Research Inc. - * - * This is free software; you can redistribute and/or modify it under - * the terms of the GNU General Public Licence. See the COPYING file. - * - ********************************************************************** - * $Log$ - * Revision 1.1 2004/09/20 07:50:06 strk - * prepared to contain old internal representation code - * - * Revision 1.31 2004/08/19 06:15:58 strk - * USE_VERSION gets 80 where it got 75 - * - * Revision 1.30 2004/08/16 11:03:25 mcayland - * Added DLLIMPORT reference to "default_statistics_target" if we are compiling under Win32. This should make it unnecessary to apply Romi's patch to the PostgreSQL source tree when compiling PostgreSQL ready for PostGIS. - * - * Revision 1.29 2004/06/22 16:52:17 strk - * Standard deviation factor used in histogram extent computation made - * a compile-time define. - * - * Revision 1.28 2004/06/14 07:48:10 strk - * Histogram extent redefinition after hard deviant removal fixed to be - * "at most" the standard deviation based computed. - * - * Revision 1.27 2004/06/11 11:38:57 strk - * Infinite geometries handling. - * Histogram extent re-computation after 'hard deviant' features removal. - * - * Revision 1.26 2004/06/10 18:54:12 strk - * histogram grid size refined to use near-square cells. - * - * Revision 1.25 2004/06/10 15:44:43 strk - * Added standard deviation based histogram extent refinement - * - * Revision 1.24 2004/06/10 13:42:17 strk - * Separated the estimator code in an estimate_selectivity() function. - * Handled complete contaiment and complete miss of histogram by searc box. - * - * Revision 1.23 2004/06/09 09:35:49 strk - * Removed partial pgsql List API copy - * - * Revision 1.22 2004/06/08 17:49:14 strk - * Fixed to build cleanly agains pg75 - * - * Revision 1.21 2004/04/28 22:26:02 pramsey - * Fixed spelling mistake in header text. - * - * Revision 1.20 2004/03/15 17:07:05 strk - * Added calls to vacuum_delay_point() to give backend a chance of - * interrupting geometry stats computation. - * Set default DEBUG_GEOMETRY_STATS to 0. - * - * Revision 1.19 2004/03/09 00:21:02 strk - * Removed useless code blocks in histogram builder - * - * Revision 1.18 2004/03/09 00:09:56 strk - * estimator applies a gain of AOI/cell_area on each cell it intersects (reverted to previous behaviour) - * - * Revision 1.17 2004/03/04 13:50:45 strk - * postgis_gist_sel(): added warnings if search_box goes outside of histogram grid - * - * Revision 1.16 2004/03/04 09:44:57 strk - * The selectivity estimator does add the full value of each cell it overlaps, - * regardless of the actual overlapping area. Final gain is not applied - * (formerly 1 / minimun between average feature cells occupation and - * search_box cells occupation) - * - * Revision 1.15 2004/03/03 21:59:48 strk - * added check to keep selectivity value in the range of validity (suggested by m.cave) - * - * Revision 1.14 2004/03/01 16:02:41 strk - * histogram's boxesPerSide computed as a function of the column's statistic target - * - * Revision 1.13 2004/02/29 21:53:42 strk - * bug fix in postgis_gist_sel (for PG75): SysCache is not released if not acquired - * - * Revision 1.12 2004/02/26 16:42:59 strk - * Fixed bugs reported by Mark Cave-Ayland . - * Re-introduced previously removed estimate value incrementation by - * the fractional part of each of the cells' value computed as the fraction - * of overlapping area. - * - * Revision 1.11 2004/02/25 12:00:32 strk - * Added handling for point features in histogram creation (add 1 instead of AOI/cell_area when AOI is 0). - * Fixed a wrong cast of BOX3D to BOX (called the convertion func). - * Added some comments and an implementation on how to change evaluation - * based on the average feature and search box cells occupation. - * - * Revision 1.10 2004/02/25 00:46:26 strk - * initial version of && selectivity estimation for PG75 - * - * Revision 1.9 2004/02/23 21:59:16 strk - * geometry analyzer builds the histogram - * - * Revision 1.8 2004/02/23 12:18:55 strk - * added skeleton functions for pg75 stats integration - * - * Revision 1.7 2003/11/11 10:14:57 strk - * Added support for PG74 - * - * Revision 1.6 2003/07/25 17:08:37 pramsey - * Moved Cygwin endian define out of source files into postgis.h common - * header file. - * - * Revision 1.5 2003/07/01 18:30:55 pramsey - * Added CVS revision headers. - * - * - **********************************************************************/ - - // If you're modifiying this file you should read the postgis mail list as it has - // detailed descriptions of whats happening here and why. - -#include "postgres.h" - -#include -#include -#include -#include -#include - -#include "access/gist.h" -#include "access/itup.h" -#include "access/rtree.h" - -#include "fmgr.h" - -#include "postgis.h" -#include "utils/elog.h" - -#define SHOW_DIGS_DOUBLE 15 -#define MAX_DIGS_DOUBLE (SHOW_DIGS_DOUBLE + 6 + 1 + 3 +1) - -//-------------------------------------------------------------------------- - -#include "access/heapam.h" -#include "catalog/catname.h" -#include "catalog/pg_operator.h" -#include "catalog/pg_proc.h" -#include "catalog/pg_statistic.h" -#include "catalog/pg_type.h" -#include "mb/pg_wchar.h" -#include "nodes/makefuncs.h" -#include "optimizer/clauses.h" -#include "optimizer/cost.h" -#include "optimizer/pathnode.h" -#include "optimizer/plancat.h" -#include "optimizer/prep.h" -#include "parser/parse_func.h" -#include "parser/parse_oper.h" -#include "parser/parsetree.h" -#include "utils/builtins.h" -#include "utils/date.h" -#include "utils/int8.h" -#include "utils/lsyscache.h" -#include "utils/selfuncs.h" -#include "utils/syscache.h" - - - -#include "executor/spi.h" - -#if USE_VERSION >= 80 - -#include "commands/vacuum.h" - -/* - * Assign a number to the postgis statistics kind - * - * tgl suggested: - * - * 1-100: reserved for assignment by the core Postgres project - * 100-199: reserved for assignment by PostGIS - * 200-9999: reserved for other globally-known stats kinds - * 10000-32767: reserved for private site-local use - * - */ -#define STATISTIC_KIND_GEOMETRY 100 - -#define DEBUG_GEOMETRY_STATS 1 - -/* - * Define this if you want to use standard deviation based - * histogram extent computation. If you do, you can also - * tweak the deviation factor used in computation with - * SDFACTOR. - */ -#define USE_STANDARD_DEVIATION 1 -#define SDFACTOR 2 - -/* - * Default geometry selectivity factor - */ -#define DEFAULT_GEOMETRY_SEL 0.000005 - -typedef struct GEOM_STATS_T -{ - // cols * rows = total boxes in grid - float4 cols; - float4 rows; - - // average bounding box area of not-null features - float4 avgFeatureArea; - - // average number of histogram cells - // covered by the sample not-null features - float4 avgFeatureCells; - - // BOX of area - float4 xmin,ymin, xmax, ymax; - // variable length # of floats for histogram - float4 value[1]; -} GEOM_STATS; - -#endif - - -// For Win32 we must declare default_statistics_target as DLLIMPORT *after* -// including all the relevant header files otherwise we get a link error. -#if defined(__CYGWIN__) || defined(__MINGW32__) -extern DLLIMPORT int default_statistics_target; -#endif - - -//estimate_histogram2d(histogram2d, box) -// returns a % estimate of the # of features that will be returned by that box query -// -//For each grid cell that intersects the query box -// Calculate area of intersection (AOI) -// IF AOI < avgFeatureArea THEN set AOI = avgFeatureArea -// SUM AOI/area-of-cell*value-of-cell -// -// change : instead of avgFeatureArea, use avgFeatureArea or 10% of a grid cell (whichever is smaller) - -PG_FUNCTION_INFO_V1(estimate_histogram2d); -Datum estimate_histogram2d(PG_FUNCTION_ARGS) -{ - HISTOGRAM2D *histo = (HISTOGRAM2D *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - BOX *box = (BOX *) PG_GETARG_POINTER(1); - double box_area; - int x_idx_min, x_idx_max, y_idx_min, y_idx_max; - double intersect_x, intersect_y, AOI; - int x,y; - double xmin,ymin,xmax,ymax; - int32 result_sum; - double cell_area; - int total,t; - double avg_feature_size; - - - - result_sum = 0; - xmin = histo->xmin; - ymin = histo->ymin; - xmax = histo->xmax; - ymax = histo->ymax; - - cell_area = ( (xmax-xmin)*(ymax-ymin)/(histo->boxesPerSide*histo->boxesPerSide) ); - - avg_feature_size = histo->avgFeatureArea; - if ( avg_feature_size > cell_area*0.1) - { - avg_feature_size = cell_area*0.1; - } - - -//elog(NOTICE,"start estimate_histogram2d: "); -//elog(NOTICE,"box is : (%.15g,%.15g to %.15g,%.15g)",box->low.x,box->low.y, box->high.x, box->high.y); - - box_area = (box->high.x-box->low.x)*(box->high.y-box->low.y); - - if (box_area<0) - box_area =0; // for precision! - - //check to see which boxes this intersects - x_idx_min = (box->low.x-xmin)/(xmax-xmin)*histo->boxesPerSide; - if (x_idx_min <0) - x_idx_min = 0; - if (x_idx_min >= histo->boxesPerSide) - x_idx_min = histo->boxesPerSide-1; - y_idx_min = (box->low.y-ymin)/(ymax-ymin)*histo->boxesPerSide; - if (y_idx_min <0) - y_idx_min = 0; - if (y_idx_min >= histo->boxesPerSide) - y_idx_min = histo->boxesPerSide-1; - - x_idx_max = (box->high.x-xmin)/(xmax-xmin)*histo->boxesPerSide; - if (x_idx_max <0) - x_idx_max = 0; - if (x_idx_max >= histo->boxesPerSide) - x_idx_max = histo->boxesPerSide-1; - y_idx_max = (box->high.y-ymin)/(ymax-ymin)*histo->boxesPerSide ; - if (y_idx_max <0) - y_idx_max = 0; - if (y_idx_max >= histo->boxesPerSide) - y_idx_max = histo->boxesPerSide-1; - - //the {x,y}_idx_{min,max} define the grid squares that the box intersects - - -//elog(NOTICE," search is in x: %i to %i y: %i to %i",x_idx_min, x_idx_max, y_idx_min,y_idx_max); - for (y= y_idx_min; y<=y_idx_max;y++) - { - for (x=x_idx_min;x<= x_idx_max;x++) - { - intersect_x = min(box->high.x, xmin+ (x+1) * (xmax-xmin)/histo->boxesPerSide ) - - max(box->low.x, xmin+ x*(xmax-xmin)/histo->boxesPerSide ) ; - intersect_y = min(box->high.y, ymin+ (y+1) * (ymax-ymin)/histo->boxesPerSide ) - - max(box->low.y, ymin+ y*(ymax-ymin)/histo->boxesPerSide ) ; - - // for a point, intersect_x=0, intersect_y=0, box_area =0 -//elog(NOTICE,"x=%i,y=%i, intersect_x= %.15g, intersect_y = %.15g",x,y,intersect_x,intersect_y); - if ( (intersect_x>=0) && (intersect_y>=0) ) - { - AOI = intersect_x*intersect_y; - if (AOI< avg_feature_size) - AOI = avg_feature_size; - result_sum += AOI/cell_area* histo->value[x+y*histo->boxesPerSide]; - } - } - } - total = 0; - for(t=0;tboxesPerSide*histo->boxesPerSide;t++) - { - total+=histo->value[t]; - } - - if ( (histo->avgFeatureArea <=0) && (box_area <=0) ) - PG_RETURN_FLOAT8(1.0/((double)(total))); - else - PG_RETURN_FLOAT8(result_sum/((double)total)); - -} - -//explode_histogram2d(histogram2d, tablename::text) -// executes CREATE TABLE tablename (the_geom geometry, id int, hits int, percent float) -// then populates it -// DOES NOT UPDATE GEOMETRY_COLUMNS -PG_FUNCTION_INFO_V1(explode_histogram2d); -Datum explode_histogram2d(PG_FUNCTION_ARGS) -{ - HISTOGRAM2D *histo = (HISTOGRAM2D *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - char *tablename; - char sql[1000]; - char geom[1000]; - int t; - int total; - double cellx,celly; - int x,y; - int SPIcode; - - - cellx = (histo->xmax-histo->xmin)/histo->boxesPerSide; - celly = (histo->ymax-histo->ymin)/histo->boxesPerSide; - - tablename = DatumGetCString(DirectFunctionCall1(textout, - PointerGetDatum(PG_GETARG_DATUM(1)))); - - total = 0; - for(t=0;tboxesPerSide*histo->boxesPerSide;t++) - { - total+=histo->value[t]; - } - if (total==0) - total=1; - - SPIcode = SPI_connect(); - if (SPIcode != SPI_OK_CONNECT) - { - elog(ERROR,"build_histogram2d: couldnt open a connection to SPI"); - PG_RETURN_NULL() ; - - } - - sprintf(sql,"CREATE TABLE %s (the_geom geometry, id int, hits int, percent float)",tablename); - - SPIcode = SPI_exec(sql, 2147483640 ); // max signed int32 - - if (SPIcode != SPI_OK_UTILITY ) - { - elog(ERROR,"explode_histogram2d: couldnt create table"); - PG_RETURN_NULL() ; - } - t=0; - for(y=0;yboxesPerSide;y++) - { - for(x=0;xboxesPerSide;x++) - { - - sprintf(geom,"POLYGON((%.15g %.15g, %.15g %.15g, %.15g %.15g, %.15g %.15g, %.15g %.15g ))", - histo->xmin + x*cellx, histo->ymin+y*celly, - histo->xmin + (x)*cellx, histo->ymin+ (y+1)*celly, - histo->xmin + (x+1)*cellx, histo->ymin+ (y+1)*celly, - histo->xmin + (x+1)*cellx, histo->ymin+y*celly, - histo->xmin + x*cellx, histo->ymin+y*celly - ); - sprintf(sql,"INSERT INTO %s VALUES('%s'::geometry,%i,%i,%.15g)",tablename,geom,t,histo->value[t],histo->value[t]/((double)total)*100.0); -//elog(NOTICE,"SQL:%s",sql); - t++; - SPIcode = SPI_exec(sql, 2147483640 ); // max signed int32 - if (SPIcode != SPI_OK_INSERT ) - { - elog(ERROR,"explode_histogram2d: couldnt insert into"); - PG_RETURN_NULL() ; - } - } - } - - SPIcode =SPI_finish(); - if (SPIcode != SPI_OK_FINISH ) - { - elog(ERROR,"build_histogram2d: couldnt disconnect from SPI"); - PG_RETURN_NULL() ; - } - - PG_RETURN_POINTER(histo) ; -} - - -//build_histogram2d (HISTOGRAM2D, tablename, columnname) -// executes the SPI 'SELECT box3d(columnname) FROM tablename' -// and sticks all the results in the histogram -PG_FUNCTION_INFO_V1(build_histogram2d); -Datum build_histogram2d(PG_FUNCTION_ARGS) -{ - HISTOGRAM2D *histo = (HISTOGRAM2D *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - - char *tablename, *columnname; - HISTOGRAM2D *result; - int SPIcode; - char sql[1000]; - SPITupleTable *tuptable; - TupleDesc tupdesc ; - int ntuples,t; - Datum datum; - bool isnull; - HeapTuple tuple ; - BOX *box; - double box_area, area_intersect, cell_area; - int x_idx_min, x_idx_max; - int y_idx_min, y_idx_max; - double xmin,ymin, xmax,ymax; - double intersect_x, intersect_y; - int x,y; - int total; - double sum_area; - int sum_area_numb; - - double sum_area_new = 0; - int sum_area_numb_new =0; - int bump=0; - - int tuplimit = 500000; // No. of tuples returned on each cursor fetch - bool moredata; - void *SPIplan; - void *SPIportal; - - - xmin = histo->xmin; - ymin = histo->ymin; - xmax = histo->xmax; - ymax = histo->ymax; - - - result = (HISTOGRAM2D *) malloc(histo->size); - memcpy(result,histo,histo->size); - - - total = 0; - for(t=0;tboxesPerSide*histo->boxesPerSide;t++) - { - total+=histo->value[t]; - } - - - - sum_area = histo->avgFeatureArea * total; - sum_area_numb = total; - - - - tablename = DatumGetCString(DirectFunctionCall1(textout, - PointerGetDatum(PG_GETARG_DATUM(1)))); - - columnname = DatumGetCString(DirectFunctionCall1(textout, - PointerGetDatum(PG_GETARG_DATUM(2)))); - - //elog(NOTICE,"Start build_histogram2d with %i items already existing", sum_area_numb); - //elog(NOTICE,"table=\"%s\", column = \"%s\"", tablename, columnname); - - - SPIcode = SPI_connect(); - - if (SPIcode != SPI_OK_CONNECT) - { - elog(ERROR,"build_histogram2d: couldnt open a connection to SPI"); - PG_RETURN_NULL() ; - - } - - - sprintf(sql,"SELECT box(\"%s\") FROM \"%s\"",columnname,tablename); - //elog(NOTICE,"executing %s",sql); - - SPIplan = SPI_prepare(sql, 0, NULL); - if (SPIplan == NULL) - { - elog(ERROR,"build_histogram2d: couldnt create query plan via SPI"); - PG_RETURN_NULL() ; - } - - SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, NULL); - if (SPIportal == NULL) - { - elog(ERROR,"build_histogram2d: couldn't create cursor via SPI"); - PG_RETURN_NULL() ; - } - - - moredata = TRUE; - while (moredata==TRUE) { - - //elog(NOTICE,"about to fetch..."); - SPI_cursor_fetch(SPIportal, TRUE, tuplimit); - - ntuples = SPI_processed; - //elog(NOTICE,"processing %d records", ntuples); - - if (ntuples > 0) { - - tuptable = SPI_tuptable; - tupdesc = SPI_tuptable->tupdesc; - - cell_area = ( (xmax-xmin)*(ymax-ymin)/(histo->boxesPerSide*histo->boxesPerSide) ); - - for (t=0;tvals[t]; - datum = SPI_getbinval(tuple, tupdesc, 1, &isnull); - if (!(isnull)) - { - box = (BOX *)DatumGetPointer(datum); - box_area = (box->high.x-box->low.x)*(box->high.y-box->low.y); - - sum_area_new += box_area; - sum_area_numb_new ++; - - if (box_area > cell_area ) - box_area = cell_area; - if (box_area<0) - box_area =0; // for precision! - - //check to see which boxes this intersects - x_idx_min = (box->low.x-xmin)/(xmax-xmin)*histo->boxesPerSide; - if (x_idx_min <0) - x_idx_min = 0; - if (x_idx_min >= histo->boxesPerSide) - x_idx_min = histo->boxesPerSide-1; - y_idx_min = (box->low.y-ymin)/(ymax-ymin)*histo->boxesPerSide; - if (y_idx_min <0) - y_idx_min = 0; - if (y_idx_min >= histo->boxesPerSide) - y_idx_min = histo->boxesPerSide-1; - - x_idx_max = (box->high.x-xmin)/(xmax-xmin)*histo->boxesPerSide; - if (x_idx_max <0) - x_idx_max = 0; - if (x_idx_max >= histo->boxesPerSide) - x_idx_max = histo->boxesPerSide-1; - y_idx_max = (box->high.y-ymin)/(ymax-ymin)*histo->boxesPerSide ; - if (y_idx_max <0) - y_idx_max = 0; - if (y_idx_max >= histo->boxesPerSide) - y_idx_max = histo->boxesPerSide-1; - - //the {x,y}_idx_{min,max} define the grid squares that the box intersects - // if the area of the intersect between the box and the grid square > 5% of - - //elog(NOTICE,"box is : (%.15g,%.15g to %.15g,%.15g)",box->low.x,box->low.y, box->high.x, box->high.y); - //elog(NOTICE," search is in x: %i to %i y: %i to %i",x_idx_min, x_idx_max, y_idx_min,y_idx_max); - for (y= y_idx_min; y<=y_idx_max;y++) - { - for (x=x_idx_min;x<= x_idx_max;x++) - { - intersect_x = min(box->high.x, xmin+ (x+1) * (xmax-xmin)/histo->boxesPerSide ) - - max(box->low.x, xmin+ x*(xmax-xmin)/histo->boxesPerSide ) ; - intersect_y = min(box->high.y, ymin+ (y+1) * (ymax-ymin)/histo->boxesPerSide ) - - max(box->low.y, ymin+ y*(ymax-ymin)/histo->boxesPerSide ) ; - - // for a point, intersect_x=0, intersect_y=0, box_area =0 - //elog(NOTICE,"x=%i,y=%i, intersect_x= %.15g, intersect_y = %.15g",x,y,intersect_x,intersect_y); - if ( (intersect_x>=0) && (intersect_y>=0) ) - { - area_intersect = intersect_x*intersect_y; - if (area_intersect >= box_area*0.05) - { - //elog(NOTICE,"bump"); - bump++; - result->value[x+y*histo->boxesPerSide]++; - } - } - } - } // End of y - - } // End isnull - - } // End of for loop - - // Free all the results after each fetch, otherwise all tuples stay - // in memory until the end of the table... - SPI_freetuptable(tuptable); - - } else { - moredata = FALSE; - } // End of if ntuples > 0 - - } // End of while loop - - - // Close the cursor - SPI_cursor_close(SPIportal); - - SPIcode =SPI_finish(); - if (SPIcode != SPI_OK_FINISH ) - { - elog(ERROR,"build_histogram2d: couldnt disconnect from SPI"); - PG_RETURN_NULL() ; - } - - //elog(NOTICE,"finishing up build_histogram2d "); - - //pfree(tablename); - //pfree(columnname); - - total = 0; - for(t=0;tboxesPerSide*histo->boxesPerSide;t++) - { - total+=result->value[t]; - } - //elog(NOTICE ,"histogram finishes with %i items in it - acutally added %i rows and %i bumps\n",total,sum_area_numb_new,bump); - //elog(NOTICE,"done build_histogram2d "); - - - //re-calculate statistics on avg bbox size - if (sum_area_numb_new >0) - result->avgFeatureArea = (sum_area_new+sum_area)/((double)(sum_area_numb_new+sum_area_numb)); - - PG_RETURN_POINTER(result) ; -} - - - - - -#if USE_VERSION < 80 -/* - * get_restriction_var - * Examine the args of a restriction clause to see if it's of the - * form (var op something) or (something op var). If so, extract - * and return the var and the other argument. - * - * Inputs: - * args: clause argument list - * varRelid: see specs for restriction selectivity functions - * - * Outputs: (these are set only if TRUE is returned) - * *var: gets Var node - * *other: gets other clause argument - * *varonleft: set TRUE if var is on the left, FALSE if on the right - * - * Returns TRUE if a Var is identified, otherwise FALSE. - */ -static bool -get_restriction_var(List *args, - int varRelid, - Var **var, - Node **other, - bool *varonleft) -{ - Node *left, - *right; - - if (length(args) != 2) - return false; - - left = (Node *) lfirst(args); - right = (Node *) lsecond(args); - - /* Ignore any binary-compatible relabeling */ - - if (IsA(left, RelabelType)) - left = (Node *)((RelabelType *) left)->arg; - if (IsA(right, RelabelType)) - right = (Node *)((RelabelType *) right)->arg; - - /* Look for the var */ - - if (IsA(left, Var) && - (varRelid == 0 || varRelid == ((Var *) left)->varno)) - { - *var = (Var *) left; - *other = right; - *varonleft = true; - } - else if (IsA(right, Var) && - (varRelid == 0 || varRelid == ((Var *) right)->varno)) - { - *var = (Var *) right; - *other = left; - *varonleft = false; - } - else - { - /* Duh, it's too complicated for me... */ - return false; - } - - return true; -} - -//restriction in the GiST && operator -PG_FUNCTION_INFO_V1(postgis_gist_sel); -Datum postgis_gist_sel(PG_FUNCTION_ARGS) -{ - Query *root = (Query *) PG_GETARG_POINTER(0); - // Oid operator = PG_GETARG_OID(1); - List *args = (List *) PG_GETARG_POINTER(2); - int varRelid = PG_GETARG_INT32(3); - GEOMETRY *in; - BOX *search_box; - char sql[1000]; - - SPITupleTable *tuptable; - TupleDesc tupdesc ; - HeapTuple tuple ; - - Datum datum; - bool isnull; - - - Var *var; - Node *other; - bool varonleft; - Oid relid; - int SPIcode; - - double myest; - -#ifndef USE_STATS - PG_RETURN_FLOAT8(0.000005); -#endif - - //PG_RETURN_FLOAT8(0.000005); - - //elog(NOTICE,"postgis_gist_sel was called"); - - if (!get_restriction_var(args, varRelid, - &var, &other, &varonleft)) - { - //elog(NOTICE,"get_restriction_var FAILED -returning early"); - PG_RETURN_FLOAT8(0.000005); - } - - relid = getrelid(var->varno, root->rtable); - if (relid == InvalidOid) - { - //elog(NOTICE,"getrelid FAILED (invalid oid) -returning early"); - PG_RETURN_FLOAT8(0.000005); - } - - //elog(NOTICE,"operator's oid = %i (this should be GEOMETRY && GEOMETRY)",operator); - //elog(NOTICE,"relations' oid = %i (this should be the relation that the && is working on) ",relid); - //elog(NOTICE,"varatt oid = %i (basically relations column #) ",var->varattno); - - - if (IsA(other, Const) &&((Const *) other)->constisnull) - { - //elog(NOTICE,"other operand of && is NULL - returning early"); - PG_RETURN_FLOAT8(0.000005); - } - - if (IsA(other, Const)) - { - //elog(NOTICE,"The other side of the && is a constant with type (oid) = %i and length %i. This should be GEOMETRY with length -1 (variable length)",((Const*)other)->consttype,((Const*)other)->constlen); - - } - else - { - //elog(NOTICE,"the other side of && isnt a constant - returning early"); - PG_RETURN_FLOAT8(0.000005); - } - - //get the BOX thats being searched in - in = (GEOMETRY*)PG_DETOAST_DATUM( ((Const*)other)->constvalue ); - search_box = convert_box3d_to_box(&in->bvol); - - //elog(NOTICE,"requested search box is : (%.15g %.15g, %.15g %.15g)",search_box->low.x,search_box->low.y,search_box->high.x,search_box->high.y); - - - SPIcode = SPI_connect(); - if (SPIcode != SPI_OK_CONNECT) - { - elog(NOTICE,"postgis_gist_sel: couldnt open a connection to SPI:%i",SPIcode); - PG_RETURN_FLOAT8(0.000005) ; - } - - sprintf(sql,"SELECT stats FROM GEOMETRY_COLUMNS WHERE attrelid=%u AND varattnum=%i",relid,var->varattno); - //elog(NOTICE,"sql:%s",sql); - SPIcode = SPI_exec(sql, 1 ); - if (SPIcode != SPI_OK_SELECT ) - { - SPI_finish(); - elog(NOTICE,"postgis_gist_sel: couldnt execute sql via SPI"); - PG_RETURN_FLOAT8(0.000005) ; - } - - if (SPI_processed !=1) - { - SPI_finish(); - //elog(NOTICE,"postgis_gist_sel: geometry_columns didnt return a unique value"); - PG_RETURN_FLOAT8(0.000005) ; - } - - tuptable = SPI_tuptable; - tupdesc = SPI_tuptable->tupdesc; - tuple = tuptable->vals[0]; - datum = SPI_getbinval(tuple, tupdesc, 1, &isnull); - if (isnull) - { - SPI_finish(); - //elog(NOTICE,"postgis_gist_sel: geometry_columns returned a null histogram"); - PG_RETURN_FLOAT8(0.000005) ; - } -//elog(NOTICE,"postgis_gist_sel: checking against estimate_histogram2d"); - // now we have the histogram, and our search box - use the estimate_histogram2d(histo,box) to get the result! - myest = - DatumGetFloat8( DirectFunctionCall2( estimate_histogram2d, datum, PointerGetDatum(search_box) ) ); - - if ( (myest<0) || (myest!=myest) ) // <0? or NaN? - { - //elog(NOTICE,"postgis_gist_sel: got something crazy back from estimate_histogram2d"); - PG_RETURN_FLOAT8(0.000005) ; - } - - - - - SPIcode =SPI_finish(); - if (SPIcode != SPI_OK_FINISH ) - { - //elog(NOTICE,"postgis_gist_sel: couldnt disconnect from SPI"); - PG_RETURN_FLOAT8(0.000005) ; - } -//elog(NOTICE,"postgis_gist_sel: finished, returning with %lf",myest); - PG_RETURN_FLOAT8(myest); -} - -static void -genericcostestimate2(Query *root, RelOptInfo *rel, - IndexOptInfo *index, List *indexQuals, - Cost *indexStartupCost, - Cost *indexTotalCost, - Selectivity *indexSelectivity, - double *indexCorrelation) -{ - double numIndexTuples; - double numIndexPages; - List *selectivityQuals = indexQuals; -#if USE_VERSION >= 74 - QualCost index_qual_cost; -#endif - - -//elog(NOTICE,"in genericcostestimate"); - - - /* - * If the index is partial, AND the index predicate with the - * explicitly given indexquals to produce a more accurate idea of the - * index restriction. This may produce redundant clauses, which we - * hope that cnfify and clauselist_selectivity will deal with - * intelligently. - * - * Note that index->indpred and indexQuals are both in implicit-AND form - * to start with, which we have to make explicit to hand to - * canonicalize_qual, and then we get back implicit-AND form again. - */ - if (index->indpred != NIL) - { - Expr *andedQuals; - - andedQuals = make_ands_explicit(nconc(listCopy(index->indpred), - indexQuals)); - selectivityQuals = canonicalize_qual(andedQuals, true); - } - - - - /* Estimate the fraction of main-table tuples that will be visited */ - *indexSelectivity = clauselist_selectivity(root, selectivityQuals, -#if USE_VERSION < 74 - lfirsti(rel->relids)); -#else - rel->relid, JOIN_INNER); -#endif - - /* - * Estimate the number of tuples that will be visited. We do it in - * this rather peculiar-looking way in order to get the right answer - * for partial indexes. We can bound the number of tuples by the - * index size, in any case. - */ - numIndexTuples = *indexSelectivity * rel->tuples; - - //elog(NOTICE,"relation has %li pages",rel->pages); - //elog(NOTICE,"indexselectivity is %lf, ntuples = %lf, numindexTuples = %lf, index->tuples = %lf",*indexSelectivity, rel->tuples, numIndexTuples,index->tuples); - - - if (numIndexTuples > index->tuples) - numIndexTuples = index->tuples; - - /* - * Always estimate at least one tuple is touched, even when - * indexSelectivity estimate is tiny. - */ - if (numIndexTuples < 1.0) - numIndexTuples = 1.0; - - /* - * Estimate the number of index pages that will be retrieved. - * - * For all currently-supported index types, the first page of the index - * is a metadata page, and we should figure on fetching that plus a - * pro-rated fraction of the remaining pages. - */ - - - //elog(NOTICE,"index->pages = %li ",index->pages); - - if (index->pages > 1 && index->tuples > 0) - { - numIndexPages = (numIndexTuples / index->tuples) * (index->pages - 1); - numIndexPages += 1; /* count the metapage too */ - numIndexPages = ceil(numIndexPages); - } - else - numIndexPages = 1.0; - - -//elog(NOTICE,"numIndexPages = %lf ",numIndexPages); - /* - * Compute the index access cost. - * - * Our generic assumption is that the index pages will be read - * sequentially, so they have cost 1.0 each, not random_page_cost. - * Also, we charge for evaluation of the indexquals at each index - * tuple. All the costs are assumed to be paid incrementally during - * the scan. - */ - -#if USE_VERSION < 74 - *indexStartupCost = 0; - *indexTotalCost = numIndexPages + - (cpu_index_tuple_cost + cost_qual_eval(indexQuals)) * - numIndexTuples; -#else - cost_qual_eval(&index_qual_cost, indexQuals); - *indexStartupCost = index_qual_cost.startup; - *indexTotalCost = numIndexPages + - (cpu_index_tuple_cost + index_qual_cost.per_tuple) * - numIndexTuples; -#endif - - - //elog(NOTICE,"cpu_index_tuple_cost = %lf, cost_qual_eval(indexQuals)) = %lf", - // cpu_index_tuple_cost,cost_qual_eval(indexQuals)); - - //elog(NOTICE,"indexTotalCost = %lf ",*indexTotalCost); - - /* - * Generic assumption about index correlation: there isn't any. - */ - *indexCorrelation = 0.97; - //elog(NOTICE,"indexcorrelation = %lf ",*indexCorrelation); -} - - -PG_FUNCTION_INFO_V1(postgisgistcostestimate); -Datum -postgisgistcostestimate(PG_FUNCTION_ARGS) -{ - Query *root = (Query *) PG_GETARG_POINTER(0); - RelOptInfo *rel = (RelOptInfo *) PG_GETARG_POINTER(1); - IndexOptInfo *index = (IndexOptInfo *) PG_GETARG_POINTER(2); - List *indexQuals = (List *) PG_GETARG_POINTER(3); - Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(4); - Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(5); - Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(6); - double *indexCorrelation = (double *) PG_GETARG_POINTER(7); - -//elog(NOTICE,"postgisgistcostestimate was called"); - - genericcostestimate2(root, rel, index, indexQuals, - indexStartupCost, indexTotalCost, - indexSelectivity, indexCorrelation); -//elog(NOTICE,"postgisgistcostestimate is going to return void"); - - PG_RETURN_VOID(); -} - -#else // USE_VERSION >= 80 - -/* - * This function returns an estimate of the selectivity - * of a search_box looking at data in the GEOM_STATS - * structure. - * - * TODO: handle box dimension collapses - */ -static float8 -estimate_selectivity(BOX *box, GEOM_STATS *geomstats) -{ - int x, y; - int x_idx_min, x_idx_max, y_idx_min, y_idx_max; - double intersect_x, intersect_y, AOI; - double cell_area, box_area; - double geow, geoh; // width and height of histogram - int histocols, historows; // histogram grid size - double value; - float overlapping_cells; - float avg_feat_cells; - double gain; - float8 selectivity; - - - /* - * Search box completely miss histogram extent - */ - if ( box->high.x < geomstats->xmin || - box->low.x > geomstats->xmax || - box->high.y < geomstats->ymin || - box->low.y > geomstats->ymax ) - { -#if DEBUG_GEOMETRY_STATS - elog(NOTICE, " search_box does not overlaps histogram, returning 0"); -#endif - return 0.0; - } - - /* - * Search box completely contains histogram extent - */ - if ( box->high.x >= geomstats->xmax && - box->low.x <= geomstats->xmin && - box->high.y >= geomstats->ymax && - box->low.y <= geomstats->ymin ) - { -#if DEBUG_GEOMETRY_STATS - elog(NOTICE, " search_box contains histogram, returning 1"); -#endif - return 1.0; - } - - geow = geomstats->xmax-geomstats->xmin; - geoh = geomstats->ymax-geomstats->ymin; - - histocols = geomstats->cols; - historows = geomstats->rows; - - cell_area = (geow*geoh) / (histocols*historows); - box_area = (box->high.x-box->low.x)*(box->high.y-box->low.y); - value = 0; - - /* Find first overlapping column */ - x_idx_min = (box->low.x-geomstats->xmin) / geow * histocols; - if (x_idx_min < 0) { -#if DEBUG_GEOMETRY_STATS - elog(NOTICE, " search_box overlaps %d columns on the left of histogram grid", -x_idx_min); -#endif - // should increment the value somehow - x_idx_min = 0; - } - if (x_idx_min >= histocols) - { -#if DEBUG_GEOMETRY_STATS - elog(NOTICE, " search_box overlaps %d columns on the right of histogram grid", x_idx_min-histocols+1); -#endif - // should increment the value somehow - x_idx_min = histocols-1; - } - - /* Find first overlapping row */ - y_idx_min = (box->low.y-geomstats->ymin) / geoh * historows; - if (y_idx_min <0) - { -#if DEBUG_GEOMETRY_STATS - elog(NOTICE, " search_box overlaps %d columns on the bottom of histogram grid", -y_idx_min); -#endif - // should increment the value somehow - y_idx_min = 0; - } - if (y_idx_min >= historows) - { -#if DEBUG_GEOMETRY_STATS - elog(NOTICE, " search_box overlaps %d columns on the top of histogram grid", y_idx_min-historows+1); -#endif - // should increment the value somehow - y_idx_min = historows-1; - } - - /* Find last overlapping column */ - x_idx_max = (box->high.x-geomstats->xmin) / geow * histocols; - if (x_idx_max <0) - { - // should increment the value somehow - x_idx_max = 0; - } - if (x_idx_max >= histocols ) - { - // should increment the value somehow - x_idx_max = histocols-1; - } - - /* Find last overlapping row */ - y_idx_max = (box->high.y-geomstats->ymin) / geoh * historows; - if (y_idx_max <0) - { - // should increment the value somehow - y_idx_max = 0; - } - if (y_idx_max >= historows) - { - // should increment the value somehow - y_idx_max = historows-1; - } - - /* - * the {x,y}_idx_{min,max} - * define the grid squares that the box intersects - */ - for (y=y_idx_min; y<=y_idx_max; y++) - { - for (x=x_idx_min; x<=x_idx_max; x++) - { - double val; - double gain; - - val = geomstats->value[x+y*histocols]; - - /* - * Of the cell value we get - * only the overlap fraction. - */ - - intersect_x = min(box->high.x, geomstats->xmin + (x+1) * geow / histocols) - max(box->low.x, geomstats->xmin + x * geow / histocols ); - intersect_y = min(box->high.y, geomstats->ymin + (y+1) * geoh / historows) - max(box->low.y, geomstats->ymin+ y * geoh / historows) ; - - AOI = intersect_x*intersect_y; - gain = AOI/cell_area; - -#if DEBUG_GEOMETRY_STATS > 1 - elog(NOTICE, " [%d,%d] cell val %.15f", - x, y, val); - elog(NOTICE, " [%d,%d] AOI %.15f", - x, y, AOI); - elog(NOTICE, " [%d,%d] gain %.15f", - x, y, gain); -#endif - - val *= gain; - -#if DEBUG_GEOMETRY_STATS > 1 - elog(NOTICE, " [%d,%d] adding %.15f to value", - x, y, val); -#endif - value += val; - } - } - - - /* - * If the search_box is a point, it will - * overlap a single cell and thus get - * it's value, which is the fraction of - * samples (we can presume of row set also) - * which bumped to that cell. - * - * If the table features are points, each - * of them will overlap a single histogram cell. - * Our search_box value would then be correctly - * computed as the sum of the bumped cells values. - * - * If both our search_box AND the sample features - * overlap more then a single histogram cell we - * need to consider the fact that our sum computation - * will have many duplicated included. E.g. each - * single sample feature would have contributed to - * raise the search_box value by as many times as - * many cells in the histogram are commonly overlapped - * by both searc_box and feature. We should then - * divide our value by the number of cells in the virtual - * 'intersection' between average feature cell occupation - * and occupation of the search_box. This is as - * fuzzy as you understand it :) - * - * Consistency check: whenever the number of cells is - * one of whichever part (search_box_occupation, - * avg_feature_occupation) the 'intersection' must be 1. - * If sounds that our 'intersaction' is actually the - * minimun number between search_box_occupation and - * avg_feat_occupation. - * - */ - overlapping_cells = (x_idx_max-x_idx_min+1) * - (y_idx_max-y_idx_min+1); - avg_feat_cells = geomstats->avgFeatureCells; - -#if DEBUG_GEOMETRY_STATS -elog(NOTICE, " search_box overlaps %f cells", overlapping_cells); -elog(NOTICE, " avg feat overlaps %f cells", avg_feat_cells); -#endif - - gain = 1/min(overlapping_cells, avg_feat_cells); - selectivity = value*gain; - -#if DEBUG_GEOMETRY_STATS - elog(NOTICE, " SUM(ov_histo_cells)=%f", value); - elog(NOTICE, " gain=%f", gain); - elog(NOTICE, " selectivity=%f", selectivity); -#endif - - /* prevent rounding overflows */ - if (selectivity > 1.0) selectivity = 1.0; - else if (selectivity < 0) selectivity = 0.0; - - return selectivity; -} - -/* - * This function should return an estimation of the number of - * rows returned by a query involving an overlap check - * ( it's the restrict function for the && operator ) - * - * It can make use (if available) of the statistics collected - * by the geometry analyzer function. - * - * Note that the good work is done by estimate_selectivity() above. - * This function just tries to find the search_box, loads the statistics - * and invoke the work-horse. - * - * This is the one used for PG version >= 7.5 - * - */ -PG_FUNCTION_INFO_V1(postgis_gist_sel); -Datum postgis_gist_sel(PG_FUNCTION_ARGS) -{ - Query *root = (Query *) PG_GETARG_POINTER(0); - //Oid operator = PG_GETARG_OID(1); - List *args = (List *) PG_GETARG_POINTER(2); - int varRelid = PG_GETARG_INT32(3); - Oid relid; - HeapTuple stats_tuple; - GEOM_STATS *geomstats; - int geomstats_nvalues=0; - Node *other; - Var *self; - GEOMETRY *in; - BOX *search_box; - float8 selectivity=0; - -#if DEBUG_GEOMETRY_STATS - elog(NOTICE, "postgis_gist_sel called"); -#endif - - /* Fail if not a binary opclause (probably shouldn't happen) */ - if (list_length(args) != 2) - { -#if DEBUG_GEOMETRY_STATS - elog(NOTICE, "postgis_gist_sel: not a binary opclause"); -#endif - PG_RETURN_FLOAT8(DEFAULT_GEOMETRY_SEL); - } - - - /* - * Find the constant part - */ - other = (Node *) linitial(args); - if ( ! IsA(other, Const) ) - { - self = (Var *)other; - other = (Node *) lsecond(args); - } - else - { - self = (Var *) lsecond(args); - } - - if ( ! IsA(other, Const) ) - { -#if DEBUG_GEOMETRY_STATS - elog(NOTICE, " no constant arguments - returning default selectivity"); -#endif - PG_RETURN_FLOAT8(DEFAULT_GEOMETRY_SEL); - } - - /* - * We are working on two constants.. - * TODO: check if expression is true, - * returned set would be either - * the whole or none. - */ - if ( ! IsA(self, Var) ) - { -#if DEBUG_GEOMETRY_STATS - elog(NOTICE, " no variable argument ? - returning default selectivity"); -#endif - PG_RETURN_FLOAT8(DEFAULT_GEOMETRY_SEL); - } - - /* - * Convert the constant to a BOX - */ - - in = (GEOMETRY*)PG_DETOAST_DATUM( ((Const*)other)->constvalue ); - search_box = convert_box3d_to_box(&in->bvol); -#if DEBUG_GEOMETRY_STATS > 1 - elog(NOTICE," requested search box is : %.15g %.15g, %.15g %.15g",search_box->low.x,search_box->low.y,search_box->high.x,search_box->high.y); -#endif - - /* - * Get pg_statistic row - */ - - relid = getrelid(varRelid, root->rtable); - - stats_tuple = SearchSysCache(STATRELATT, ObjectIdGetDatum(relid), Int16GetDatum(self->varattno), 0, 0); - if ( ! stats_tuple ) - { -#if DEBUG_GEOMETRY_STATS - elog(NOTICE, " No statistics, returning default estimate"); -#endif - PG_RETURN_FLOAT8(DEFAULT_GEOMETRY_SEL); - } - - - if ( ! get_attstatsslot(stats_tuple, 0, 0, - STATISTIC_KIND_GEOMETRY, InvalidOid, NULL, NULL, - (float4 **)&geomstats, &geomstats_nvalues) ) - { -#if DEBUG_GEOMETRY_STATS - elog(NOTICE, " STATISTIC_KIND_GEOMETRY stats not found - returning default geometry selectivity"); -#endif - ReleaseSysCache(stats_tuple); - PG_RETURN_FLOAT8(DEFAULT_GEOMETRY_SEL); - - } - -#if DEBUG_GEOMETRY_STATS > 1 - elog(NOTICE, " %d read from stats", geomstats_nvalues); -#endif - -#if DEBUG_GEOMETRY_STATS > 1 - elog(NOTICE, " histo: xmin,ymin: %f,%f", - geomstats->xmin, geomstats->ymin); - elog(NOTICE, " histo: xmax,ymax: %f,%f", - geomstats->xmax, geomstats->ymax); - elog(NOTICE, " histo: cols: %f", geomstats->rows); - elog(NOTICE, " histo: rows: %f", geomstats->cols); - elog(NOTICE, " histo: avgFeatureArea: %f", geomstats->avgFeatureArea); - elog(NOTICE, " histo: avgFeatureCells: %f", geomstats->avgFeatureCells); -#endif - - /* - * Do the estimation - */ - selectivity = estimate_selectivity(search_box, geomstats); - - -#if DEBUG_GEOMETRY_STATS - elog(NOTICE, " returning computed value: %f", selectivity); -#endif - - free_attstatsslot(0, NULL, 0, (float *)geomstats, geomstats_nvalues); - ReleaseSysCache(stats_tuple); - PG_RETURN_FLOAT8(selectivity); - -} - -/* - * This function is called by the analyze function iff - * the geometry_analyze() function give it its pointer - * (this is always the case so far). - * The geometry_analyze() function is also responsible - * of deciding the number of "sample" rows we will receive - * here. It is able to give use other 'custom' data, but we - * won't use them so far. - * - * Our job is to build some statistics on the sample data - * for use by operator estimators. - * - * Currently we only need statistics to estimate the number of rows - * overlapping a given extent (estimation function bound - * to the && operator). - * - */ -static void -compute_geometry_stats(VacAttrStats *stats, AnalyzeAttrFetchFunc fetchfunc, - int samplerows, double totalrows) -{ - MemoryContext old_context; - int i; - int geom_stats_size; - BOX **sampleboxes; - GEOM_STATS *geomstats; - bool isnull; - int null_cnt=0, notnull_cnt=0, examinedsamples=0; - BOX3D *sample_extent=NULL; - double total_width=0; - double total_boxes_area=0; - int total_boxes_cells=0; - double cell_area; - double cell_width; - double cell_height; -#if USE_STANDARD_DEVIATION - /* for standard deviation */ - double avgLOWx, avgLOWy, avgHIGx, avgHIGy; - double sumLOWx=0, sumLOWy=0, sumHIGx=0, sumHIGy=0; - double sdLOWx=0, sdLOWy=0, sdHIGx=0, sdHIGy=0; - BOX *newhistobox=NULL; -#endif - double geow, geoh; // width and height of histogram - int histocells; - int cols, rows; // histogram grid size - BOX histobox; - - /* - * This is where geometry_analyze - * should put its' custom parameters. - */ - //void *mystats = stats->extra_data; - - /* - * We'll build an histogram having from 40 to 400 boxesPerSide - * Total number of cells is determined by attribute stat - * target. It can go from 1600 to 160000 (stat target: 10,1000) - */ - histocells = 160*stats->attr->attstattarget; - - -#if DEBUG_GEOMETRY_STATS - elog(NOTICE, "compute_geometry_stats called"); - elog(NOTICE, " samplerows: %d", samplerows); - elog(NOTICE, " histogram cells: %d", histocells); -#endif - - /* - * We might need less space, but don't think - * its worth saving... - */ - sampleboxes = palloc(sizeof(BOX *)*samplerows); - - /* - * First scan: - * o find extent of the sample rows - * o count null-infinite/not-null values - * o compute total_width - * o compute total features's box area (for avgFeatureArea) - * o sum features box coordinates (for standard deviation) - */ - for (i=0; ibvol.LLB.x) || - ! finite(geom->bvol.LLB.y) || - ! finite(geom->bvol.URT.x) || - ! finite(geom->bvol.URT.y) ) - { -#if DEBUG_GEOMETRY_STATS - elog(NOTICE, " skipped infinite geometry %d", i); -#endif - continue; - } - - /* - * Cache bounding box - */ - box = convert_box3d_to_box(&(geom->bvol)); - sampleboxes[notnull_cnt] = box; - - /* - * Add to sample extent union - */ - sample_extent = union_box3d(&(geom->bvol), sample_extent); - - // TODO: ask if we need geom or bvol size for stawidth - total_width += geom->size; - total_boxes_area += (box->high.x-box->low.x)*(box->high.y-box->low.y); - -#if USE_STANDARD_DEVIATION - /* - * Add bvol coordinates to sum for standard deviation - * computation. - */ - sumLOWx += box->low.x; - sumLOWy += box->low.y; - sumHIGx += box->high.x; - sumHIGy += box->high.y; -#endif - - notnull_cnt++; - - /* give backend a chance of interrupting us */ - vacuum_delay_point(); - - } - - if ( ! notnull_cnt ) { - elog(NOTICE, " no notnull values, invalid stats"); - stats->stats_valid = false; - return; - } - -#if USE_STANDARD_DEVIATION - -#if DEBUG_GEOMETRY_STATS - elog(NOTICE, " sample_extent: xmin,ymin: %f,%f", - sample_extent->LLB.x, sample_extent->LLB.y); - elog(NOTICE, " sample_extent: xmax,ymax: %f,%f", - sample_extent->URT.x, sample_extent->URT.y); -#endif - - /* - * Second scan: - * o compute standard deviation - */ - avgLOWx = sumLOWx/notnull_cnt; - avgLOWy = sumLOWy/notnull_cnt; - avgHIGx = sumHIGx/notnull_cnt; - avgHIGy = sumHIGy/notnull_cnt; - for (i=0; ilow.x - avgLOWx) * (box->low.x - avgLOWx); - sdLOWy += (box->low.y - avgLOWy) * (box->low.y - avgLOWy); - sdHIGx += (box->high.x - avgHIGx) * (box->high.x - avgHIGx); - sdHIGy += (box->high.y - avgHIGy) * (box->high.y - avgHIGy); - } - sdLOWx = sqrt(sdLOWx/(notnull_cnt-1)); - sdLOWy = sqrt(sdLOWy/(notnull_cnt-1)); - sdHIGx = sqrt(sdHIGx/(notnull_cnt-1)); - sdHIGy = sqrt(sdHIGy/(notnull_cnt-1)); - -#if DEBUG_GEOMETRY_STATS - elog(NOTICE, " standard deviations:"); - elog(NOTICE, " LOWx - avg:%f sd:%f", avgLOWx, sdLOWx); - elog(NOTICE, " LOWy - avg:%f sd:%f", avgLOWy, sdLOWy); - elog(NOTICE, " HIGx - avg:%f sd:%f", avgHIGx, sdHIGx); - elog(NOTICE, " HIGy - avg:%f sd:%f", avgHIGy, sdHIGy); -#endif - - histobox.low.x = max((avgLOWx - SDFACTOR * sdLOWx), - sample_extent->LLB.x); - histobox.low.y = max((avgLOWy - SDFACTOR * sdLOWy), - sample_extent->LLB.y); - histobox.high.x = min((avgHIGx + SDFACTOR * sdHIGx), - sample_extent->URT.x); - histobox.high.y = min((avgHIGy + SDFACTOR * sdHIGy), - sample_extent->URT.y); - -#if DEBUG_GEOMETRY_STATS - elog(NOTICE, " sd_extent: xmin,ymin: %f,%f", - histobox.low.x, histobox.low.y); - elog(NOTICE, " sd_extent: xmax,ymax: %f,%f", - histobox.high.x, histobox.high.y); -#endif - - /* - * Third scan: - * o skip hard deviants - * o compute new histogram box - */ - for (i=0; ilow.x > histobox.high.x || - box->high.x < histobox.low.x || - box->low.y > histobox.high.y || - box->high.y < histobox.low.y ) - { -#if DEBUG_GEOMETRY_STATS > 1 - elog(NOTICE, " feat %d is an hard deviant, skipped", i); -#endif - sampleboxes[i] = NULL; - continue; - } - if ( ! newhistobox ) { - newhistobox = palloc(sizeof(BOX)); - memcpy(newhistobox, box, sizeof(BOX)); - } else { - if ( box->low.x < newhistobox->low.x ) - newhistobox->low.x = box->low.x; - if ( box->low.y < newhistobox->low.y ) - newhistobox->low.y = box->low.y; - if ( box->high.x > newhistobox->high.x ) - newhistobox->high.x = box->high.x; - if ( box->high.y > newhistobox->high.y ) - newhistobox->high.y = box->high.y; - } - } - - /* - * Set histogram extent as the intersection between - * standard deviation based histogram extent - * and computed sample extent after removal of - * hard deviants (there might be no hard deviants). - */ - if ( histobox.low.x < newhistobox->low.x ) - histobox.low.x = newhistobox->low.x; - if ( histobox.low.y < newhistobox->low.y ) - histobox.low.y = newhistobox->low.y; - if ( histobox.high.x > newhistobox->high.x ) - histobox.high.x = newhistobox->high.x; - if ( histobox.high.y > newhistobox->high.y ) - histobox.high.y = newhistobox->high.y; - - -#else // ! USE_STANDARD_DEVIATION - - /* - * Set histogram extent box - */ - histobox.low.x = sample_extent->LLB.x; - histobox.low.y = sample_extent->LLB.y; - histobox.high.x = sample_extent->URT.x; - histobox.high.y = sample_extent->URT.y; -#endif // USE_STANDARD_DEVIATION - - -#if DEBUG_GEOMETRY_STATS - elog(NOTICE, " histogram_extent: xmin,ymin: %f,%f", - histobox.low.x, histobox.low.y); - elog(NOTICE, " histogram_extent: xmax,ymax: %f,%f", - histobox.high.x, histobox.high.y); -#endif - - - geow = histobox.high.x - histobox.low.x; - geoh = histobox.high.y - histobox.low.y; - - /* - * Compute histogram cols and rows based on aspect ratio - * of histogram extent - */ - if ( ! geow && ! geoh ) { - cols = 1; - rows = 1; - histocells = 1; - } else if ( ! geow ) { - cols = 1; - rows = histocells; - } else if ( ! geoh ) { - cols = histocells; - rows = 1; - } else { - if ( geowanl_context); - geom_stats_size=sizeof(GEOM_STATS)+(histocells-1)*sizeof(float4); - geomstats = palloc(geom_stats_size); - MemoryContextSwitchTo(old_context); - - geomstats->avgFeatureArea = total_boxes_area/notnull_cnt; - geomstats->xmin = histobox.low.x; - geomstats->ymin = histobox.low.y; - geomstats->xmax = histobox.high.x; - geomstats->ymax = histobox.high.y; - geomstats->cols = cols; - geomstats->rows = rows; - - // Initialize all values to 0 - for (i=0;ivalue[i] = 0; - - cell_width = geow/cols; - cell_height = geoh/rows; - cell_area = cell_width*cell_height; - -#if DEBUG_GEOMETRY_STATS > 2 - elog(NOTICE, "cell_width: %f", cell_width); - elog(NOTICE, "cell_height: %f", cell_height); -#endif - - - /* - * Fourth scan: - * o fill histogram values with the number of - * features' bbox overlaps: a feature's bvol - * can fully overlap (1) or partially overlap - * (fraction of 1) an histogram cell. - * - * o compute total cells occupation - * - */ - for (i=0; i 2 - elog(NOTICE, " feat %d box is %f %f, %f %f", - i, box->high.x, box->high.y, - box->low.x, box->low.y); -#endif - - /* Find first overlapping column */ - x_idx_min = (box->low.x-geomstats->xmin) / geow * cols; - if (x_idx_min <0) x_idx_min = 0; - if (x_idx_min >= cols) x_idx_min = cols-1; - - /* Find first overlapping row */ - y_idx_min = (box->low.y-geomstats->ymin) / geoh * rows; - if (y_idx_min <0) y_idx_min = 0; - if (y_idx_min >= rows) y_idx_min = rows-1; - - /* Find last overlapping column */ - x_idx_max = (box->high.x-geomstats->xmin) / geow * cols; - if (x_idx_max <0) x_idx_max = 0; - if (x_idx_max >= cols ) x_idx_max = cols-1; - - /* Find last overlapping row */ - y_idx_max = (box->high.y-geomstats->ymin) / geoh * rows; - if (y_idx_max <0) y_idx_max = 0; - if (y_idx_max >= rows) y_idx_max = rows-1; -#if DEBUG_GEOMETRY_STATS > 2 - elog(NOTICE, " feat %d overlaps columns %d-%d, rows %d-%d", - i, x_idx_min, x_idx_max, y_idx_min, y_idx_max); -#endif - - /* - * the {x,y}_idx_{min,max} - * define the grid squares that the box intersects - */ - for (y=y_idx_min; y<=y_idx_max; y++) - { - for (x=x_idx_min; x<=x_idx_max; x++) - { - geomstats->value[x+y*cols] += 1; - numcells++; - } - } - - // before adding to the total cells - // we could decide if we really - // want this feature to count - total_boxes_cells += numcells; - - examinedsamples++; - } -#if DEBUG_GEOMETRY_STATS - elog(NOTICE, " examined_samples: %d/%d", examinedsamples, samplerows); -#endif - - if ( ! examinedsamples ) { - elog(NOTICE, " no examined values, invalid stats"); - stats->stats_valid = false; -#if DEBUG_GEOMETRY_STATS - elog(NOTICE, " no stats have been gathered"); -#endif - return; - } - - // what about null features (TODO) ? - geomstats->avgFeatureCells = (float4)total_boxes_cells/examinedsamples; - -#if DEBUG_GEOMETRY_STATS - elog(NOTICE, " histo: total_boxes_cells: %d", total_boxes_cells); - elog(NOTICE, " histo: avgFeatureArea: %f", geomstats->avgFeatureArea); - elog(NOTICE, " histo: avgFeatureCells: %f", geomstats->avgFeatureCells); -#endif - - - /* - * Normalize histogram - * - * We divide each histogram cell value - * by the number of samples examined. - * - */ - for (i=0; ivalue[i] /= examinedsamples; - -#if DEBUG_GEOMETRY_STATS > 1 - { - int x, y; - for (x=0; xvalue[x+y*cols]); - } - } - } -#endif - - /* - * Write the statistics data - */ - stats->stakind[0] = STATISTIC_KIND_GEOMETRY; - stats->staop[0] = InvalidOid; - stats->stanumbers[0] = (float4 *)geomstats; - stats->numnumbers[0] = geom_stats_size/sizeof(float4); - - stats->stanullfrac = null_cnt/samplerows; - stats->stawidth = total_width/notnull_cnt; - stats->stadistinct = -1.0; - -#if DEBUG_GEOMETRY_STATS - elog(NOTICE, " out: slot 0: kind %d (STATISTIC_KIND_GEOMETRY)", - stats->stakind[0]); - elog(NOTICE, " out: slot 0: op %d (InvalidOid)", stats->staop[0]); - elog(NOTICE, " out: slot 0: numnumbers %d", stats->numnumbers[0]); - elog(NOTICE, " out: null fraction: %d/%d", null_cnt, samplerows); - elog(NOTICE, " out: average width: %d bytes", stats->stawidth); - elog(NOTICE, " out: distinct values: all (no check done)"); -#endif - - stats->stats_valid = true; -} - -/* - * This function will be called when the ANALYZE command is run - * on a column of the "geometry" type. - * - * It will need to return a stats builder function reference - * and a "minimum" sample rows to feed it. - * If we want analisys to be completely skipped we can return - * FALSE and leave output vals untouched. - * - * What we know from this call is: - * - * o The pg_attribute row referring to the specific column. - * Could be used to get reltuples from pg_class (which - * might quite inexact though...) and use them to set an - * appropriate minimum number of sample rows to feed to - * the stats builder. The stats builder will also receive - * a more accurate "estimation" of the number or rows. - * - * o The pg_type row for the specific column. - * Could be used to set stat builder / sample rows - * based on domain type (when postgis will be implemented - * that way). - * - * Being this experimental we'll stick to a static stat_builder/sample_rows - * value for now. - * - */ -PG_FUNCTION_INFO_V1(geometry_analyze); -Datum geometry_analyze(PG_FUNCTION_ARGS) -{ - VacAttrStats *stats = (VacAttrStats *)PG_GETARG_POINTER(0); - Form_pg_attribute attr = stats->attr; - -#if DEBUG_GEOMETRY_STATS - elog(NOTICE, "geometry_analyze called"); -#endif - - /* If the attstattarget column is negative, use the default value */ - /* NB: it is okay to scribble on stats->attr since it's a copy */ - if (attr->attstattarget < 0) - attr->attstattarget = default_statistics_target; - -#if DEBUG_GEOMETRY_STATS - elog(NOTICE, " attribute stat target: %d", attr->attstattarget); -#endif - - /* - * There might be a reason not to analyze this column - * (can we detect the absence of an index?) - */ - //elog(NOTICE, "compute_geometry_stats not implemented yet"); - //PG_RETURN_BOOL(false); - - /* Setup the minimum rows and the algorithm function */ - stats->minrows = 300 * stats->attr->attstattarget; - stats->compute_stats = compute_geometry_stats; - -#if DEBUG_GEOMETRY_STATS - elog(NOTICE, " minrows: %d", stats->minrows); -#endif - - /* Indicate we are done successfully */ - PG_RETURN_BOOL(true); -} - - - -#endif - - diff --git a/hwgeom/postgis_fn.c b/hwgeom/postgis_fn.c deleted file mode 100644 index a449ffbce..000000000 --- a/hwgeom/postgis_fn.c +++ /dev/null @@ -1,3218 +0,0 @@ - -/********************************************************************** - * $Id$ - * - * PostGIS - Spatial Types for PostgreSQL - * http://postgis.refractions.net - * Copyright 2001-2003 Refractions Research Inc. - * - * This is free software; you can redistribute and/or modify it under - * the terms of the GNU General Public Licence. See the COPYING file. - * - ********************************************************************** - * $Log$ - * Revision 1.1 2004/09/20 07:50:06 strk - * prepared to contain old internal representation code - * - * Revision 1.40 2004/08/26 16:55:09 strk - * max_distance() raises an 'unimplemented yet' error. - * - * Revision 1.39 2004/07/28 16:10:59 strk - * Changed all version functions to return text. - * Renamed postgis_scripts_version() to postgis_scripts_installed() - * Added postgis_scripts_released(). - * Added postgis_full_version(). - * - * Revision 1.38 2004/07/28 13:37:43 strk - * Added postgis_uses_stats and postgis_scripts_version. - * Experimented with PIP short-circuit in within/contains functions. - * Documented new version functions. - * - * Revision 1.37 2004/07/22 16:20:10 strk - * Added postgis_lib_version() and postgis_geos_version() - * - * Revision 1.36 2004/06/03 16:44:56 strk - * Added expand_geometry - expand(geometry, int8) - * - * Revision 1.35 2004/04/28 22:26:02 pramsey - * Fixed spelling mistake in header text. - * - * Revision 1.34 2004/03/26 00:54:09 dblasby - * added full support for fluffType() - * postgis09=# select fluffType('POINT(0 0)'); - * flufftype - * ------------------------- - * SRID=-1;MULTIPOINT(0 0) - * - * Revision 1.33 2004/03/25 00:43:41 dblasby - * added function fluffType() that takes POINT LINESTRING or POLYGON - * type and converts it to a multi*. - * Needs to be integrated into a proper Postgresql function and given an - * SQL CREATE FUNCTION - * - * Revision 1.32 2004/02/12 10:34:49 strk - * changed USE_GEOS check from ifdef / ifndef to if / if ! - * - * Revision 1.31 2003/11/11 10:58:43 strk - * Fixed a typo in envelope() - * - * Revision 1.30 2003/10/29 15:53:10 strk - * geoscentroid() removed. both geos and pgis versions are called 'centroid'. - * only one version will be compiled based on USE_GEOS flag. - * - * Revision 1.29 2003/10/28 16:57:35 strk - * Added collect_garray() function. - * - * Revision 1.28 2003/10/28 15:16:17 strk - * unite_sfunc() from postgis_geos.c renamed to geom_accum() and moved in postgis_fn.c - * - * Revision 1.27 2003/10/17 16:12:23 dblasby - * Made Envelope() CW instead of CCW. - * - * Revision 1.26 2003/10/17 16:07:05 dblasby - * made isEmpty() return true/false - * - * Revision 1.25 2003/09/16 20:27:12 dblasby - * added ability to delete geometries. - * - * Revision 1.24 2003/08/08 18:19:20 dblasby - * Conformance changes. - * Removed junk from postgis_debug.c and added the first run of the long - * transaction locking support. (this will change - dont use it) - * conformance tests were corrected - * some dos cr/lf removed - * empty geometries i.e. GEOMETRYCOLLECT(EMPTY) added (with indexing support) - * pointN(,1) now returns the first point (used to return 2nd) - * - * Revision 1.23 2003/07/25 17:08:37 pramsey - * Moved Cygwin endian define out of source files into postgis.h common - * header file. - * - * Revision 1.22 2003/07/01 18:30:55 pramsey - * Added CVS revision headers. - * - * - **********************************************************************/ - -#include "postgres.h" - - -#include -#include -#include -#include -#include - -#include "access/gist.h" -#include "access/itup.h" -#include "access/rtree.h" - -#include "fmgr.h" - -#include "postgis.h" -#include "utils/elog.h" -#include "utils/array.h" - -#define NfunctionFirstPoint 1 - -// if you use #define NfunctionFirstPoint 0, you get 0-based indexing (this is what programmers want):: -// pointN(, 0) is the 1st point, and pointN(, 1) is the second point. - -// if you use #define NfunctionFirstPoint 1, you get 1-based indexing (which seems to be what the spec wants):: -// pointN(, 1) is the 1st point, and pointN(, 2) is the second point. - - -#define SHOW_DIGS_DOUBLE 15 -#define MAX_DIGS_DOUBLE (SHOW_DIGS_DOUBLE + 6 + 1 + 3 +1) - - -// #define DEBUG_GIST -//#define DEBUG_GIST2 - - - - -/************************************************************************** - * GENERAL PURPOSE GEOMETRY FUNCTIONS - **************************************************************************/ - - -double line_length2d(LINE3D *line) -{ - int i; - POINT3D *frm,*to; - double dist = 0.0; - - if (line->npoints <2) - return 0.0; //must have >1 point to make sense - - frm = &line->points[0]; - - for (i=1; inpoints;i++) - { - to = &line->points[i]; - - dist += sqrt( ( (frm->x - to->x)*(frm->x - to->x) ) + - ( (frm->y - to->y)*(frm->y - to->y) ) ); - - frm = to; - } - return dist; -} - -double line_length3d(LINE3D *line) -{ - int i; - POINT3D *frm,*to; - double dist = 0.0; - - if (line->npoints <2) - return 0.0; //must have >1 point to make sense - - frm = &line->points[0]; - - for (i=1; inpoints;i++) - { - to = &line->points[i]; - - dist += sqrt( ( (frm->x - to->x)*(frm->x - to->x) ) + - ((frm->y - to->y)*(frm->y - to->y) ) + - ((frm->z - to->z)*(frm->z - to->z) ) ); - - frm = to; - } - return dist; -} - - -//find the "length of a geometry" -// length3d(point) = 0 -// length3d(line) = length of line -// length3d(polygon) = 0 -- could make sense to return sum(ring perimeter) -// uses euclidian 3d length - -PG_FUNCTION_INFO_V1(length3d); -Datum length3d(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - int32 *offsets1; - char *o1; - int32 type1,j; - LINE3D *line; - double dist = 0.0; - - offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ; - - - //now have to do a scan of each object - - for (j=0; j< geom1->nobjs; j++) //for each object in geom1 - { - o1 = (char *) geom1 +offsets1[j] ; - type1= geom1->objType[j]; - if (type1 == LINETYPE) //LINESTRING - { - line = (LINE3D *) o1; - dist += line_length3d(line); - } - } - PG_RETURN_FLOAT8(dist); -} - -//find the "length of a geometry" -// length3d(point) = 0 -// length3d(line) = length of line -// length3d(polygon) = 0 -- could make sense to return sum(ring perimeter) -// uses euclidian 2d length - -PG_FUNCTION_INFO_V1(length2d); -Datum length2d(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - int32 *offsets1; - char *o1; - int32 type1,j; - LINE3D *line; - double dist = 0.0; - - offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ; - - - //now have to do a scan of each object - - for (j=0; j< geom1->nobjs; j++) //for each object in geom1 - { - o1 = (char *) geom1 +offsets1[j] ; - type1= geom1->objType[j]; - if (type1 == LINETYPE) //LINESTRING - { - line = (LINE3D *) o1; - dist += line_length2d(line); - } - } - PG_RETURN_FLOAT8(dist); -} - - -//find the 2d area of the outer ring - sum (area 2d of inner rings) -// Could use a more numerically stable calculator... -double polygon_area2d_old(POLYGON3D *poly1) -{ - double poly_area=0.0, ringarea=0.0; - int i,j,ring,pt_offset; - POINT3D *pts1; - - - pts1 = (POINT3D *) ( (char *)&(poly1->npoints[poly1->nrings] ) ); - pts1 = (POINT3D *) MAXALIGN(pts1); - -//elog(NOTICE,"in polygon_area2d_old"); - - pt_offset = 0; //index to first point in ring - for (ring = 0; ring < poly1->nrings; ring++) - { - ringarea = 0.0; - - for (i=0;i<(poly1->npoints[ring]-1);i++) - { - // j = (i+1) % (poly1->npoints[ring]); - j = i+1; - ringarea += pts1[pt_offset+ i].x * pts1[pt_offset+j].y - pts1[pt_offset+ i].y * pts1[pt_offset+j].x; - } - - ringarea /= 2.0; -//elog(NOTICE," ring 1 has area %lf",ringarea); - ringarea = fabs(ringarea ); - if (ring != 0) //outer - ringarea = -1.0*ringarea ; // its a hole - - poly_area += ringarea; - - pt_offset += poly1->npoints[ring]; - } - - return poly_area; -} - - - -//calculate the area of all the subobj in a polygon -// area(point) = 0 -// area (line) = 0 -// area(polygon) = find its 2d area -PG_FUNCTION_INFO_V1(area2d); -Datum area2d(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - int32 *offsets1; - char *o1; - int32 type1,j; - POLYGON3D *poly; - double area = 0.0; - - offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ; - - //now have to do a scan of each object - - for (j=0; j< geom1->nobjs; j++) //for each object in geom1 - { - o1 = (char *) geom1 +offsets1[j] ; - type1= geom1->objType[j]; - if (type1 == POLYGONTYPE) //POLYGON - { - poly = (POLYGON3D *) o1; - area += polygon_area2d_old(poly); - } - } - PG_RETURN_FLOAT8(area); -} - -double polygon_perimeter3d(POLYGON3D *poly1) -{ - double poly_perimeter=0.0, ring_perimeter=0.0; - int i,ring,pt_offset; - POINT3D *pts1; - POINT3D *to,*frm; - - - pts1 = (POINT3D *) ( (char *)&(poly1->npoints[poly1->nrings] ) ); - pts1 = (POINT3D *) MAXALIGN(pts1); - - - - pt_offset = 0; //index to first point in ring - for (ring = 0; ring < poly1->nrings; ring++) - { - ring_perimeter = 0.0; - - - frm = &pts1[pt_offset]; - - for (i=1; inpoints[ring];i++) - { - to = &pts1[pt_offset+ i]; - - ring_perimeter += sqrt( ( (frm->x - to->x)*(frm->x - to->x) ) + - ((frm->y - to->y)*(frm->y - to->y) ) + - ((frm->z - to->z)*(frm->z - to->z) ) ); - - frm = to; - } - - poly_perimeter += ring_perimeter; - - pt_offset += poly1->npoints[ring]; - } - - return poly_perimeter; - -} - -double polygon_perimeter2d(POLYGON3D *poly1) -{ - double poly_perimeter=0.0, ring_perimeter=0.0; - int i,ring,pt_offset; - POINT3D *pts1; - POINT3D *to,*frm; - - - pts1 = (POINT3D *) ( (char *)&(poly1->npoints[poly1->nrings] ) ); - pts1 = (POINT3D *) MAXALIGN(pts1); - - - pt_offset = 0; //index to first point in ring - for (ring = 0; ring < poly1->nrings; ring++) - { - ring_perimeter = 0.0; - - - frm = &pts1[pt_offset]; - - for (i=1; inpoints[ring];i++) - { - to = &pts1[pt_offset+ i]; - - ring_perimeter += sqrt( ( (frm->x - to->x)*(frm->x - to->x) ) + - ((frm->y - to->y)*(frm->y - to->y) ) ); - - frm = to; - } - - poly_perimeter += ring_perimeter; - - pt_offset += poly1->npoints[ring]; - } - - return poly_perimeter; - -} - - - -//calculate the perimeter of polys (sum of length of all rings) -PG_FUNCTION_INFO_V1(perimeter3d); -Datum perimeter3d(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - int32 *offsets1; - char *o1; - int32 type1,j; - POLYGON3D *poly; - double area = 0.0; - - offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ; - - //now have to do a scan of each object - - for (j=0; j< geom1->nobjs; j++) //for each object in geom1 - { - o1 = (char *) geom1 +offsets1[j] ; - type1= geom1->objType[j]; - if (type1 == POLYGONTYPE) //POLYGON - { - poly = (POLYGON3D *) o1; - area += polygon_perimeter3d(poly); - } - } - PG_RETURN_FLOAT8(area); -} - -//calculate the perimeter of polys (sum of length of all rings) -PG_FUNCTION_INFO_V1(perimeter2d); -Datum perimeter2d(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - int32 *offsets1; - char *o1; - int32 type1,j; - POLYGON3D *poly; - double area = 0.0; - - offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ; - - //now have to do a scan of each object - - for (j=0; j< geom1->nobjs; j++) //for each object in geom1 - { - o1 = (char *) geom1 +offsets1[j] ; - type1= geom1->objType[j]; - if (type1 == POLYGONTYPE) //POLYGON - { - poly = (POLYGON3D *) o1; - area += polygon_perimeter2d(poly); - } - } - PG_RETURN_FLOAT8(area); -} - - -// cn_PnPoly(): crossing number test for a point in a polygon -// input: P = a point, -// V[] = vertex points of a polygon V[n+1] with V[n]=V[0] -// returns: 0 = outside, 1 = inside -// -// Our polygons have first and last point the same, -// -int PIP( POINT3D *P, POINT3D *V, int n ) -{ - int cn = 0; // the crossing number counter - int i; - - double vt; - - // loop through all edges of the polygon - - for (i=0; i< (n-1) ; i++) - { // edge from V[i] to V[i+1] - - if (((V[i].y <= P->y) && (V[i+1].y > P->y)) // an upward crossing - || ((V[i].y > P->y) && (V[i+1].y <= P->y))) // a downward crossing - { - - vt = (double)(P->y - V[i].y) / (V[i+1].y - V[i].y); - if (P->x < V[i].x + vt * (V[i+1].x - V[i].x)) // P.x x >= box->LLB.x) && (point->x <= box->URT.x) && - (point->y >= box->LLB.y) && (point->y <= box->URT.y) - ); -} - - -// see if a linestring is inside a box - check to see if each its line -// segments are inside the box -// NOTE: all this is happening in 2d - third dimention is ignored -// -//use a modified CohenSutherland line clipping algoritm -// -//Step one - compute outcodes for Pi and Pi+1 -// -// -// | | -// 1001 | 1000 | 1010 -// | | -// ----------+-----------+------------ -// | (inside) | -// 0001 | | 0010 -// | 0000 | -// ----------+-----------+------------ -// | | -// 0101 | 0100 | 0110 -// | | -// -// If Pi or Pi+1 have code 0000 then this line seg is inside the box (trivial accept) -// if Pi && Pi+1 != 0 then seg is NOT in the box (trivial reject) -// -// Otherwise the line seg might traverse through the box. -// => see if the seg intersects any of the walls of the box. -// - -int compute_outcode( POINT3D *p, BOX3D *box) -{ - int Code=0; - -//printf("compute outcode:\n"); -//print_box(box); -//printf("point = [%g,%g]\n",p->x,p->y); - if (p->y > box->URT.y ) - Code = 8; - else - { - if (p->y LLB.y ) - { - Code = 4; - } - } - if (p->x > box->URT.x ) - { - return (Code+2); - } - if (p->x LLB.x ) - { - return (Code+1); - } - - return (Code); -} - - -bool lineseg_inside_box( POINT3D *P1, POINT3D *P2, BOX3D *box) -{ - int outcode_p1, outcode_p2; - double Ax,Ay, Bx,By, Cx,Cy, Dx,Dy; - double r,s; - - outcode_p1 = compute_outcode(P1, box); - if (outcode_p1 ==0) - return TRUE; - - outcode_p2 = compute_outcode(P2, box); - if (outcode_p2 ==0) - return TRUE; - if ((outcode_p1 & outcode_p2) != 0) - return FALSE; - - - if ((outcode_p1 + outcode_p2) == 12) - return TRUE; //vertically slices box - - if ((outcode_p1 + outcode_p2) == 3) - return TRUE; //horizontally slices box - - -//printf("have to do boundry calcs\n"); - - // know that its a diagonal line - - //this is the tough case - it may or maynot intersect the box - //see if it intersects the horizonal and vertical box lines - - // from comp.graphics.algo's faq: - /* - (Ay-Cy)(Dx-Cx)-(Ax-Cx)(Dy-Cy) - r = ------------------------------------ - (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx) - - (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay) - s = ----------------------------------- - (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx) - - */ - // if 0<= r&s <=1 then intersection exists - - Ax = P1->x; Ay = P1->y; - Bx = P2->x; By = P2->y; - - //top hor part of box - Cx = box->LLB.x; Cy= box->URT.y; - Dx = box->URT.x; Dy= box->URT.y; - - r= ((Ay-Cy)*(Dx-Cx)-(Ax-Cx)*(Dy-Cy) )/ - ((Bx-Ax)*(Dy-Cy)-(By-Ay)*(Dx-Cx) ) ; - - s= ((Ay-Cy)*(Bx-Ax)-(Ax-Cx)*(By-Ay))/ - ((Bx-Ax)*(Dy-Cy)-(By-Ay)*(Dx-Cx) ) ; - - if ( (r>=0) && (r<=1) && (s>=0) && (s<=1) ) - return TRUE; - - //bottom hor part of box - Cx = box->LLB.x; Cy= box->LLB.y; - Dx = box->URT.x; Dy= box->LLB.y; - - r= ((Ay-Cy)*(Dx-Cx)-(Ax-Cx)*(Dy-Cy) )/ - ((Bx-Ax)*(Dy-Cy)-(By-Ay)*(Dx-Cx) ) ; - - s= ((Ay-Cy)*(Bx-Ax)-(Ax-Cx)*(By-Ay))/ - ((Bx-Ax)*(Dy-Cy)-(By-Ay)*(Dx-Cx) ) ; - if ( (r>=0) && (r<=1) && (s>=0) && (s<=1) ) - return TRUE; - - //left ver part of box - Cx = box->LLB.x; Cy= box->LLB.y; - Dx = box->LLB.x; Dy= box->URT.y; - - r= ((Ay-Cy)*(Dx-Cx)-(Ax-Cx)*(Dy-Cy) )/ - ((Bx-Ax)*(Dy-Cy)-(By-Ay)*(Dx-Cx) ) ; - - s= ((Ay-Cy)*(Bx-Ax)-(Ax-Cx)*(By-Ay))/ - ((Bx-Ax)*(Dy-Cy)-(By-Ay)*(Dx-Cx) ) ; - - if ( (r>=0) && (r<=1) && (s>=0) && (s<=1) ) - return TRUE; - - //right ver part of box - Cx = box->URT.x; Cy= box->LLB.y; - Dx = box->URT.x; Dy= box->URT.y; - - r= ((Ay-Cy)*(Dx-Cx)-(Ax-Cx)*(Dy-Cy) )/ - ((Bx-Ax)*(Dy-Cy)-(By-Ay)*(Dx-Cx) ) ; - - s= ((Ay-Cy)*(Bx-Ax)-(Ax-Cx)*(By-Ay))/ - ((Bx-Ax)*(Dy-Cy)-(By-Ay)*(Dx-Cx) ) ; - if ( (r>=0) && (r<=1) && (s>=0) && (s<=1) ) - return TRUE; - - //otherwise we did not intersect the box - return FALSE; - -} - - -//give the work to an easier process -bool linestring_inside_box(POINT3D *pts, int npoints, BOX3D *box) -{ - POINT3D *frm,*to; - int i; - - if (npoints <2) - return FALSE; //must have >1 point to make sense - - frm = &pts[0]; - - for (i=1; i< npoints;i++) - { - to = &pts[i]; - - if (lineseg_inside_box( frm, to, box)) - return TRUE; - - frm = to; - } - return FALSE; -} - - -//this ones the most complex -// 1. treat the outer ring as a line and see if its inside -// + if it is, then poly is inside box -// 2. The polygon could be completely contained inside the box -// + line detector (step 1) would have found this -// 3. The polygon could be completely surrounding the box -// + point-in-polygon of one of the box corners -// + COMPLEXITY: box could be totally inside a single hole -// +test all holes like step 1. Any that pass arent "bad" holes -// + each of the bad holes do a point-in-polygon if true =-> totally in hole - -bool polygon_truely_inside(POLYGON3D *poly, BOX3D *box) -{ - bool outer_ring_inside,outer_ring_surrounds; - POINT3D *pts1; - POINT3D test_point; - int32 ring; - int point_offset; - - pts1 = (POINT3D *) ( (char *)&(poly->npoints[poly->nrings] ) ); - pts1 = (POINT3D *) MAXALIGN(pts1); - - - //step 1 (and 2) - outer_ring_inside = linestring_inside_box(pts1, poly->npoints[0], box); - - if (outer_ring_inside) - return TRUE; - - test_point.x = box->LLB.x; - test_point.y = box->LLB.y; - //.z unimportant - - outer_ring_surrounds = PIP(&test_point, pts1,poly->npoints[0] ); - - if (!(outer_ring_surrounds)) - return FALSE; // disjoing - - //printf("polygon - have to check holes\n"); - - //step 3 - - point_offset = poly->npoints[0]; - for (ring =1; ring< poly->nrings; ring ++) - { - if (!( linestring_inside_box(&pts1[point_offset], poly->npoints[ring], box) )) - { - //doesnt intersect the box - // so if one of the corners of the box is inside the hole, it totally - // surrounds the box - - if (PIP(&test_point, &pts1[point_offset],poly->npoints[ring] ) ) - return FALSE; - } - point_offset += poly->npoints[ring]; - } - - return TRUE; -} - - - - - -//This is more complicated because all the points in the line can be outside the box, -// but one of the edges can cross into the box. -// We send the work off to another function because its generically usefull for -// polygons too -bool line_truely_inside( LINE3D *line, BOX3D *box) -{ - return linestring_inside_box(&line->points[0], line->npoints, box); -} - -// is point inside polygon surface ? -//bool point_within_polygon(POINT3D *point, POLYGON3D *poly) -//{ -// POINT3D *ring; -// int ringpoints; -// int ri; // ring index -// -// // if point is outside the shell return false. -// ring = (POINT3D *) ( (char *)&(poly->npoints[poly->nrings] ) ); -// ringpoints = poly->npoints[0]; -// if ( !PIP(point, ring, ringpoints) ) return FALSE; -// -// // if point is inside any hole return false. -// //ring += ringpoints*sizeof(POINT3D); -// //for (ri=1; rinrings; ri++) -// //{ -// // ringpoints = poly->npoints[ri]; -// // if ( PIP(point, ring, ringpoints) ) return FALSE; -// // ring += ringpoints*sizeof(POINT3D); -// //} -// -// // return true -// return TRUE; -//} - -//is anything in geom1 really inside the the bvol (2d only) defined in geom2? -// send each object to its proper handler -PG_FUNCTION_INFO_V1(truly_inside); -Datum truly_inside(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - BOX3D *the_bbox; - int32 *offsets1; - char *o1; - int32 type1,j; - POLYGON3D *poly; - LINE3D *line; - POINT3D *point; - - if (geom1->SRID != geom2->SRID) - { - elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n"); - PG_RETURN_NULL(); - } - - the_bbox = &geom2->bvol; - - offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ; - - //now have to do a scan of each object - - for (j=0; j< geom1->nobjs; j++) //for each object in geom1 - { - o1 = (char *) geom1 +offsets1[j] ; - type1= geom1->objType[j]; - - if (type1 == POINTTYPE) //point - { - point = (POINT3D *) o1; - if ( point_truely_inside(point, the_bbox)) - PG_RETURN_BOOL(TRUE); - } - - if (type1 == LINETYPE) //line - { - line = (LINE3D *) o1; - if ( line_truely_inside(line, the_bbox)) - PG_RETURN_BOOL(TRUE); - } - - if (type1 == POLYGONTYPE) //POLYGON - { - poly = (POLYGON3D *) o1; - - if ( polygon_truely_inside(poly, the_bbox)) - PG_RETURN_BOOL(TRUE); - } - } - PG_RETURN_BOOL(FALSE); -} - - - -//number of points in an object -PG_FUNCTION_INFO_V1(npoints); -Datum npoints(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - int32 *offsets1; - char *o1; - int32 type1,j,i; - POLYGON3D *poly; - LINE3D *line; - int32 numb_points = 0; - - offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ; - - //now have to do a scan of each object - - for (j=0; j< geom1->nobjs; j++) //for each object in geom1 - { - o1 = (char *) geom1 +offsets1[j] ; - type1= geom1->objType[j]; - - if (type1 == POINTTYPE) //point - { - numb_points ++; - } - - if (type1 == LINETYPE) //line - { - line = (LINE3D *) o1; - numb_points += line->npoints; - } - - if (type1 == POLYGONTYPE) //POLYGON - { - poly = (POLYGON3D *) o1; - for (i=0; inrings;i++) - { - numb_points += poly->npoints[i]; - } - } - } - - PG_RETURN_INT32(numb_points); -} - -//number of rings in an object -PG_FUNCTION_INFO_V1(nrings); -Datum nrings(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - int32 *offsets1; - char *o1; - int32 type1,j; - POLYGON3D *poly; - int32 numb_rings = 0; - - offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ; - - //now have to do a scan of each object - - for (j=0; j< geom1->nobjs; j++) //for each object in geom1 - { - o1 = (char *) geom1 +offsets1[j] ; - type1= geom1->objType[j]; - - if (type1 == POLYGONTYPE) //POLYGON - { - poly = (POLYGON3D *) o1; - numb_rings += poly->nrings; - } - } - - PG_RETURN_INT32(numb_rings); -} - - - -void translate_points(POINT3D *pt, int npoints,double x_off, double y_off, double z_off) -{ - int i; - -//printf("translating %i points by [%g,%g,%g]\n",npoints,x_off,y_off,z_off); - if (npoints <1) - return; //nothing to do - - for (i=0;isize); - memcpy(geom1, geom, geom->size); //Will handle SRID and grid - - - offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ; - - //now have to do a scan of each object - - for (j=0; j< geom1->nobjs; j++) //for each object in geom1 - { - o1 = (char *) geom1 +offsets1[j] ; - type= geom1->objType[j]; - - if (type == POINTTYPE) //point - { - point = (POINT3D *) o1; - translate_points(point, 1,x_off,y_off,z_off); - } - - if (type == LINETYPE) //line - { - line = (LINE3D *) o1; - translate_points(&(line->points[0]), line->npoints,x_off,y_off,z_off); - } - - if (type == POLYGONTYPE) //POLYGON - { - poly = (POLYGON3D *) o1; - //find where the points are and where to put them - numb_points =0; - for (i=0; inrings;i++) - { - numb_points += poly->npoints[i]; - } - pts = (POINT3D *) ( (char *)&(poly->npoints[poly->nrings] ) ); - pts = (POINT3D *) MAXALIGN(pts); - translate_points(pts, numb_points,x_off,y_off,z_off); - - - } - } - //translate the bounding box as well - geom1->bvol.LLB.x += x_off; - geom1->bvol.LLB.y += y_off; - geom1->bvol.LLB.z += z_off; - geom1->bvol.URT.x += x_off; - geom1->bvol.URT.y += y_off; - geom1->bvol.URT.z += z_off; - - PG_RETURN_POINTER(geom1); -} - - - - -// set the is3d flag so the system think the geometry is 2d or 3d - -PG_FUNCTION_INFO_V1(force_2d); -Datum force_2d(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *result; - - result = (GEOMETRY *) palloc(geom->size); - memcpy(result,geom, geom->size); - - result->is3d = FALSE; - PG_RETURN_POINTER(result); -} - - -PG_FUNCTION_INFO_V1(force_3d); -Datum force_3d(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *result; - - result = (GEOMETRY *) palloc(geom->size); - memcpy(result,geom, geom->size); - - result->is3d = TRUE; - PG_RETURN_POINTER(result); - -} - - -//NULL safe bbox union -// combine_bbox(BOX3D, geometry) => union BOX3D and geometry->bvol -// For finding the extent of a set of rows using the extent() aggregate - -PG_FUNCTION_INFO_V1(combine_bbox); -Datum combine_bbox(PG_FUNCTION_ARGS) -{ - Pointer box3d_ptr = PG_GETARG_POINTER(0); - Pointer geom_ptr = PG_GETARG_POINTER(1); - BOX3D *a,*b; - GEOMETRY *geom; - BOX3D *box; - - if ( (box3d_ptr == NULL) && (geom_ptr == NULL) ) - { - PG_RETURN_NULL(); // combine_bbox(null,null) => null - } - - if (box3d_ptr == NULL) - { - geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - box = (BOX3D *) palloc(sizeof(BOX3D)); - memcpy(box, &(geom->bvol), sizeof(BOX3D) ); - - PG_RETURN_POINTER(box); // combine_bbox(null, geometry) => geometry->bvol - } - - if (geom_ptr == NULL) - { - box = (BOX3D *) palloc(sizeof(BOX3D)); - memcpy(box, (char *) PG_GETARG_DATUM(0) , sizeof(BOX3D) ); - - - PG_RETURN_POINTER( box ); // combine_bbox(BOX3D, null) => BOX3D - } - - //combine_bbox(BOX3D, geometry) => union(BOX3D, geometry->bvol) - - box = (BOX3D *) palloc(sizeof(BOX3D)); - - a = (BOX3D *) PG_GETARG_DATUM(0) ; - b= &(( (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)) )->bvol); - - box->LLB.x = b->LLB.x; - box->LLB.y = b->LLB.y; - box->LLB.z = b->LLB.z; - - box->URT.x = b->URT.x; - box->URT.y = b->URT.y; - box->URT.z = b->URT.z; - - if (a->LLB.x < b->LLB.x) - box->LLB.x = a->LLB.x; - if (a->LLB.y < b->LLB.y) - box->LLB.y = a->LLB.y; - if (a->LLB.z < b->LLB.z) - box->LLB.z = a->LLB.z; - - if (a->URT.x > b->URT.x) - box->URT.x = a->URT.x; - if (a->URT.y > b->URT.y) - box->URT.y = a->URT.y; - if (a->URT.z > b->URT.z) - box->URT.z = a->URT.z; - - PG_RETURN_POINTER( box ); -} - - -//returns 0 for points, 1 for lines, 2 for polygons. -//returns max dimension for a collection. -PG_FUNCTION_INFO_V1(dimension); -Datum dimension(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - int t; - int result,dim,type; - - - if ((geom->type == COLLECTIONTYPE) && (geom->nobjs ==0)) - PG_RETURN_INT32(-1); - - if (geom->type == POINTTYPE) - PG_RETURN_INT32(0); - - if (geom->type == LINETYPE) - PG_RETURN_INT32(1); - - if (geom->type == POLYGONTYPE) - PG_RETURN_INT32(2); - - - if (geom->type == MULTIPOINTTYPE) - PG_RETURN_INT32(0); - - if (geom->type == MULTILINETYPE) - PG_RETURN_INT32(1); - - if (geom->type == MULTIPOLYGONTYPE) - PG_RETURN_INT32(2); - - result = -1; - dim =0; - //its a collection -look for the largest one - for (t=0;tnobjs;t++) - { - type= geom->objType[t]; - - if (type == POINTTYPE) - dim=0; - - if (type == LINETYPE) - dim=1; - - if (type == POLYGONTYPE) - dim=2; - - if (dim>result) - result = dim; - - } - PG_RETURN_INT32(result); -} - -//returns a string representation of this geometry's type -PG_FUNCTION_INFO_V1(geometrytype); -Datum geometrytype(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - char *text_ob = palloc(20+4); - char *result = text_ob+4; - int32 size; - - - memset(result,0,20); - - if (geom->type == POINTTYPE) - strcpy(result,"POINT"); - if (geom->type == MULTIPOINTTYPE) - strcpy(result,"MULTIPOINT"); - - if (geom->type == LINETYPE) - strcpy(result,"LINESTRING"); - if (geom->type == MULTILINETYPE) - strcpy(result,"MULTILINESTRING"); - - if (geom->type == POLYGONTYPE) - strcpy(result,"POLYGON"); - if (geom->type == MULTIPOLYGONTYPE) - strcpy(result,"MULTIPOLYGON"); - - if (geom->type == COLLECTIONTYPE) - strcpy(result,"GEOMETRYCOLLECTION"); - - if (strlen(result) == 0) - strcpy(result,"UNKNOWN"); - - size = strlen(result) +4 ; - - memcpy(text_ob, &size,4); // size of string - - - PG_RETURN_POINTER(text_ob); - -} - - -//makes a polygon of a features bvol - 1st point = LL 3rd=UR -// 2d only -// -// create new geometry of type polygon, 1 ring, 5 points - -PG_FUNCTION_INFO_V1(envelope); -Datum envelope(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *result; - POLYGON3D *poly; - POINT3D pts[5]; //5 points around box - int pts_per_ring[1]; - int poly_size; - - //use LLB's z value (we're going to set is3d to false) - - //0,1,2,3,4 --> CCW order, 4,3,2,1,0 --> CW order - set_point( &pts[4], geom->bvol.LLB.x , geom->bvol.LLB.y , geom->bvol.LLB.z ); - set_point( &pts[3], geom->bvol.URT.x , geom->bvol.LLB.y , geom->bvol.LLB.z ); - set_point( &pts[2], geom->bvol.URT.x , geom->bvol.URT.y , geom->bvol.LLB.z ); - set_point( &pts[1], geom->bvol.LLB.x , geom->bvol.URT.y , geom->bvol.LLB.z ); - set_point( &pts[0], geom->bvol.LLB.x , geom->bvol.LLB.y , geom->bvol.LLB.z ); - - pts_per_ring[0] = 5; //ring has 5 points - - //make a polygon - poly = make_polygon(1, pts_per_ring, pts, 5, &poly_size); - - result = make_oneobj_geometry(poly_size, (char *)poly, POLYGONTYPE, FALSE,geom->SRID, geom->scale, geom->offsetX, geom->offsetY); - - PG_RETURN_POINTER(result); - -} - -//X(GEOMETRY) -- find the first POINT(..) in GEOMETRY, returns its X value. -//Return NULL if there is no POINT(..) in GEOMETRY -PG_FUNCTION_INFO_V1(x_point); -Datum x_point(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - char *o; - int type1,j; - int32 *offsets1; - - - offsets1 = (int32 *) ( ((char *) &(geom->objType[0] ))+ sizeof(int32) * geom->nobjs ) ; - - //now have to do a scan of each object - - for (j=0; j< geom->nobjs; j++) //for each object in geom1 - { - o = (char *) geom +offsets1[j] ; - type1= geom->objType[j]; - - if (type1 == POINTTYPE) //point - { - PG_RETURN_FLOAT8( ((POINT3D *)o)->x) ; - } - - } - PG_RETURN_NULL(); -} - -//Y(GEOMETRY) -- find the first POINT(..) in GEOMETRY, returns its Y value. -//Return NULL if there is no POINT(..) in GEOMETRY -PG_FUNCTION_INFO_V1(y_point); -Datum y_point(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - char *o; - int type1,j; - int32 *offsets1; - - - offsets1 = (int32 *) ( ((char *) &(geom->objType[0] ))+ sizeof(int32) * geom->nobjs ) ; - - //now have to do a scan of each object - - for (j=0; j< geom->nobjs; j++) //for each object in geom1 - { - o = (char *) geom +offsets1[j] ; - type1= geom->objType[j]; - - if (type1 == POINTTYPE) //point - { - PG_RETURN_FLOAT8( ((POINT3D *)o)->y) ; - } - - } - PG_RETURN_NULL(); -} - -//Z(GEOMETRY) -- find the first POINT(..) in GEOMETRY, returns its Z value. -//Return NULL if there is no POINT(..) in GEOMETRY -PG_FUNCTION_INFO_V1(z_point); -Datum z_point(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - char *o; - int type1,j; - int32 *offsets1; - - - offsets1 = (int32 *) ( ((char *) &(geom->objType[0] ))+ sizeof(int32) * geom->nobjs ) ; - - //now have to do a scan of each object - - for (j=0; j< geom->nobjs; j++) //for each object in geom1 - { - o = (char *) geom +offsets1[j] ; - type1= geom->objType[j]; - - if (type1 == POINTTYPE) //point - { - PG_RETURN_FLOAT8( ((POINT3D *)o)->z) ; - } - - } - PG_RETURN_NULL(); -} - -//numpoints(GEOMETRY) -- find the first linestring in GEOMETRY, return -//the number of points in it. Return NULL if there is no LINESTRING(..) -//in GEOMETRY -PG_FUNCTION_INFO_V1(numpoints_linestring); -Datum numpoints_linestring(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - char *o; - int type1,j; - int32 *offsets1; - - offsets1 = (int32 *) ( ((char *) &(geom->objType[0] ))+ sizeof(int32) * geom->nobjs ) ; - - for (j=0; j< geom->nobjs; j++) //for each object in geom1 - { - o = (char *) geom +offsets1[j] ; - type1= geom->objType[j]; - - if (type1 == LINETYPE) //linestring - { - PG_RETURN_INT32( ((LINE3D *)o)->npoints) ; - } - - } - PG_RETURN_NULL(); -} - -//pointn(GEOMETRY,INTEGER) -- find the first linestring in GEOMETRY, -//return the point at index INTEGER (0 is 1st point). Return NULL if -//there is no LINESTRING(..) in GEOMETRY or INTEGER is out of bounds. -// keeps is3d flag - -PG_FUNCTION_INFO_V1(pointn_linestring); -Datum pointn_linestring(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - int32 wanted_index =PG_GETARG_INT32(1); - char *o; - int type1,j; - int32 *offsets1; - LINE3D *line; - - - wanted_index -= NfunctionFirstPoint; - - offsets1 = (int32 *) ( ((char *) &(geom->objType[0] ))+ sizeof(int32) * geom->nobjs ) ; - - for (j=0; j< geom->nobjs; j++) //for each object in geom1 - { - o = (char *) geom +offsets1[j] ; - type1= geom->objType[j]; - - if (type1 == LINETYPE) //linestring - { - line = (LINE3D *)o; - if ( (wanted_index<0) || (wanted_index> (line->npoints-1) ) ) - PG_RETURN_NULL(); //index out of range - //get the point, make a new geometry - PG_RETURN_POINTER( - make_oneobj_geometry(sizeof(POINT3D), - (char *)&line->points[wanted_index], - POINTTYPE, geom->is3d, geom->SRID, geom->scale, geom->offsetX, geom->offsetY) - ); - } - - } - PG_RETURN_NULL(); -} - -// exteriorRing(GEOMETRY) -- find the first polygon in GEOMETRY, return -//its exterior ring (as a linestring). Return NULL if there is no -//POLYGON(..) in GEOMETRY. - -PG_FUNCTION_INFO_V1(exteriorring_polygon); -Datum exteriorring_polygon(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - - char *o; - int type1,j; - int32 *offsets1; - LINE3D *line; - POLYGON3D *poly; - POINT3D *pts; - int size_line; - - - offsets1 = (int32 *) ( ((char *) &(geom->objType[0] ))+ sizeof(int32) * geom->nobjs ) ; - - for (j=0; j< geom->nobjs; j++) //for each object in geom1 - { - o = (char *) geom +offsets1[j] ; - type1= geom->objType[j]; - - if (type1 == POLYGONTYPE) //polygon object - { - poly = (POLYGON3D *)o; - pts = (POINT3D *) ( (char *)&(poly->npoints[poly->nrings] ) ); - pts = (POINT3D *) MAXALIGN(pts); - - line = make_line(poly->npoints[0], pts, &size_line); - - //get the ring, make a new geometry - PG_RETURN_POINTER( - make_oneobj_geometry(size_line, - (char *) line, - LINETYPE, geom->is3d,geom->SRID, geom->scale, geom->offsetX, geom->offsetY) - ); - } - - } - PG_RETURN_NULL(); -} - -//NumInteriorRings(GEOMETRY) -- find the first polygon in GEOMETRY, -//return the number of interior rings. Return NULL if there is no -//POLYGON(..) in GEOMETRY. - -PG_FUNCTION_INFO_V1(numinteriorrings_polygon); -Datum numinteriorrings_polygon(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - - char *o; - int type1,j; - int32 *offsets1; - POLYGON3D *poly; - - - - offsets1 = (int32 *) ( ((char *) &(geom->objType[0] ))+ sizeof(int32) * geom->nobjs ) ; - - for (j=0; j< geom->nobjs; j++) //for each object in geom1 - { - o = (char *) geom +offsets1[j] ; - type1= geom->objType[j]; - - if (type1 == POLYGONTYPE) //polygon object - { - poly = (POLYGON3D *)o; - PG_RETURN_INT32( poly->nrings -1 ) ; - } - } - PG_RETURN_NULL(); -} - -// InteriorRingN(GEOMETRY,INTEGER) -- find the first polygon in GEOMETRY, -//return the interior ring at index INTEGER (as a linestring). Return -//NULL if there is no POLYGON(..) in GEOMETRY or INTEGER is out of bounds. -// 1st ring = exerior ring - -PG_FUNCTION_INFO_V1(interiorringn_polygon); -Datum interiorringn_polygon(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - int32 wanted_index =PG_GETARG_INT32(1); - char *o; - int type1,j,t,point_offset; - int32 *offsets1; - POLYGON3D *poly; - LINE3D *line; - POINT3D *pts; - int size_line; - - - wanted_index -= NfunctionFirstPoint; - - offsets1 = (int32 *) ( ((char *) &(geom->objType[0] ))+ sizeof(int32) * geom->nobjs ) ; - - for (j=0; j< geom->nobjs; j++) //for each object in geom1 - { - o = (char *) geom +offsets1[j] ; - type1= geom->objType[j]; - - if (type1 == POLYGONTYPE) //polygon object - { - poly = (POLYGON3D *)o; - - if ( (wanted_index<0) || (wanted_index> (poly->nrings-2) ) ) - PG_RETURN_NULL(); //index out of range - - - pts = (POINT3D *) ( (char *)&(poly->npoints[poly->nrings] ) ); - pts = (POINT3D *) MAXALIGN(pts); - - //find the 1st point in wanted ring - point_offset=0; - for (t=0; t< (wanted_index+1); t++) - { - point_offset += poly->npoints[t]; - } - - line = make_line(poly->npoints[wanted_index+1], &pts[point_offset], &size_line); - - //get the ring, make a new geometry - PG_RETURN_POINTER( - make_oneobj_geometry(size_line, - (char *) line, - LINETYPE, geom->is3d, geom->SRID, geom->scale, geom->offsetX, geom->offsetY) - ); - } - } - PG_RETURN_NULL(); -} - - -// numgeometries(GEOMETRY) -- if GEOMETRY is a GEOMETRYCOLLECTION, return -//the number of geometries in it, otherwise return NULL. -// if GEOMETRY is a MULTI* type, return the number of sub-types in it. - -PG_FUNCTION_INFO_V1(numgeometries_collection); -Datum numgeometries_collection(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - - if ( (geom->type == COLLECTIONTYPE) || - (geom->type == MULTIPOINTTYPE) || - (geom->type == MULTILINETYPE) || - (geom->type == MULTIPOLYGONTYPE) - ) - PG_RETURN_INT32( geom->nobjs ) ; - else - PG_RETURN_NULL(); -} - - -//geometryN(GEOMETRY, INTEGER) -- if GEOMETRY is a GEOMETRYCOLLECTION, -//return the sub-geometry at index INTEGER (0=first geometry), otherwise -//return NULL. NOTE: MULTIPOINT, MULTILINESTRING,MULTIPOLYGON are -//converted to sets of POINT,LINESTRING, and POLYGON so the index may -//change. -// if GEOMETRY is a MULTI* type, return the Nth sub-geometry - - -PG_FUNCTION_INFO_V1(geometryn_collection); -Datum geometryn_collection(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - int32 wanted_index =PG_GETARG_INT32(1); - int type; - int32 *offsets1; - char *o; - - wanted_index -= NfunctionFirstPoint; - - offsets1 = (int32 *) ( ((char *) &(geom->objType[0] ))+ sizeof(int32) * geom->nobjs ) ; - - if (!(( (geom->type == COLLECTIONTYPE) || - (geom->type == MULTIPOINTTYPE) || - (geom->type == MULTILINETYPE) || - (geom->type == MULTIPOLYGONTYPE) - ))) - PG_RETURN_NULL(); - - - if ( (wanted_index <0) || (wanted_index > (geom->nobjs-1) ) ) - PG_RETURN_NULL(); //bad index - - type = geom->objType[wanted_index]; - o = (char *) geom +offsets1[wanted_index] ; - - if (type == POINTTYPE) - { - PG_RETURN_POINTER( - make_oneobj_geometry(sizeof(POINT3D), - o, - POINTTYPE, geom->is3d, geom->SRID, geom->scale, geom->offsetX, geom->offsetY) - ); - } - if (type == LINETYPE) - { - PG_RETURN_POINTER( - make_oneobj_geometry( size_subobject (o, LINETYPE), - o, - LINETYPE, geom->is3d, geom->SRID, geom->scale, geom->offsetX, geom->offsetY) - ); - } - if (type == POLYGONTYPE) - { - PG_RETURN_POINTER( - make_oneobj_geometry( size_subobject (o, POLYGONTYPE), - o, - POLYGONTYPE, geom->is3d, geom->SRID, geom->scale, geom->offsetX, geom->offsetY) - ); - } - - PG_RETURN_NULL(); -} - - -//force the geometry to be a geometrycollection type - -PG_FUNCTION_INFO_V1(force_collection); -Datum force_collection(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *result; - - result = (GEOMETRY *) palloc(geom->size); - memcpy(result,geom, geom->size); - - result->type = COLLECTIONTYPE; - - PG_RETURN_POINTER(result); -} - - - -// point_inside_circle(geometry, Px, Py, d) -// returns true if there is a point in geometry whose distance to (Px,Py) is < d - -PG_FUNCTION_INFO_V1(point_inside_circle); -Datum point_inside_circle(PG_FUNCTION_ARGS) -{ - - GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - char *o; - int type1,j; - int32 *offsets1; - POINT3D *pt; - double Px = PG_GETARG_FLOAT8(1); - double Py = PG_GETARG_FLOAT8(2); - double d = PG_GETARG_FLOAT8(3); - double dd = d*d; //d squared - - offsets1 = (int32 *) ( ((char *) &(geom->objType[0] ))+ sizeof(int32) * geom->nobjs ) ; - - //now have to do a scan of each object - - for (j=0; j< geom->nobjs; j++) //for each object in geom - { - o = (char *) geom +offsets1[j] ; - type1= geom->objType[j]; - - if (type1 == POINTTYPE) //point - { - //see if its within d of Px,Py - pt = (POINT3D *) o; - if ( ( (pt->x - Px)*(pt->x - Px) + (pt->y - Py)*(pt->y - Py) ) < dd) - { - PG_RETURN_BOOL(TRUE); - } - } - - } - PG_RETURN_BOOL(FALSE); -} - - -//distance from p to line A->B -double distance_pt_seg(POINT3D *p, POINT3D *A, POINT3D *B) -{ - double r,s; - - - //if start==end, then use pt distance - if ( ( A->x == B->x) && (A->y == B->y) ) - return distance_pt_pt(p,A); - - //otherwise, we use comp.graphics.algorithms Frequently Asked Questions method - - /*(1) AC dot AB - r = --------- - ||AB||^2 - r has the following meaning: - r=0 P = A - r=1 P = B - r<0 P is on the backward extension of AB - r>1 P is on the forward extension of AB - 0x-A->x) * (B->x-A->x) + (p->y-A->y) * (B->y-A->y) )/( (B->x-A->x)*(B->x-A->x) +(B->y-A->y)*(B->y-A->y) ); - - if (r<0) - return (distance_pt_pt(p,A)); - if (r>1) - return(distance_pt_pt(p,B)); - - - /*(2) - (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay) - s = ----------------------------- - L^2 - - Then the distance from C to P = |s|*L. - - */ - - s = ((A->y-p->y)*(B->x-A->x)- (A->x-p->x)*(B->y-A->y) )/ ((B->x-A->x)*(B->x-A->x) +(B->y-A->y)*(B->y-A->y) ); - - return abs(s) * sqrt(((B->x-A->x)*(B->x-A->x) +(B->y-A->y)*(B->y-A->y) )); -} - - - -// find the distance from AB to CD -double distance_seg_seg(POINT3D *A, POINT3D *B, POINT3D *C, POINT3D *D) -{ - - double s_top, s_bot,s; - double r_top, r_bot,r; - - -//printf("seg_seg [%g,%g]->[%g,%g] by [%g,%g]->[%g,%g] \n",A->x,A->y,B->x,B->y, C->x,C->y, D->x, D->y); - //A and B are the same point - - if ( ( A->x == B->x) && (A->y == B->y) ) - return distance_pt_seg(A,C,D); - - //U and V are the same point - - if ( ( C->x == D->x) && (C->y == D->y) ) - return distance_pt_seg(D,A,B); - - // AB and CD are line segments - /* from comp.graphics.algo - - Solving the above for r and s yields - (Ay-Cy)(Dx-Cx)-(Ax-Cx)(Dy-Cy) - r = ----------------------------- (eqn 1) - (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx) - - (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay) - s = ----------------------------- (eqn 2) - (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx) - Let P be the position vector of the intersection point, then - P=A+r(B-A) or - Px=Ax+r(Bx-Ax) - Py=Ay+r(By-Ay) - By examining the values of r & s, you can also determine some other limiting conditions: - If 0<=r<=1 & 0<=s<=1, intersection exists - r<0 or r>1 or s<0 or s>1 line segments do not intersect - If the denominator in eqn 1 is zero, AB & CD are parallel - If the numerator in eqn 1 is also zero, AB & CD are collinear. - - */ - r_top = (A->y-C->y)*(D->x-C->x) - (A->x-C->x)*(D->y-C->y) ; - r_bot = (B->x-A->x)*(D->y-C->y) - (B->y-A->y)*(D->x-C->x) ; - - s_top = (A->y-C->y)*(B->x-A->x) - (A->x-C->x)*(B->y-A->y); - s_bot = (B->x-A->x)*(D->y-C->y) - (B->y-A->y)*(D->x-C->x); - - if ( (r_bot==0) || (s_bot == 0) ) - { - return ( - min(distance_pt_seg(A,C,D), - min(distance_pt_seg(B,C,D), - min(distance_pt_seg(C,A,B), - distance_pt_seg(D,A,B) ) ) ) - ); - } - s = s_top/s_bot; - r= r_top/r_bot; - - if ((r<0) || (r>1) || (s<0) || (s>1) ) - { - //no intersection - return ( - min(distance_pt_seg(A,C,D), - min(distance_pt_seg(B,C,D), - min(distance_pt_seg(C,A,B), - distance_pt_seg(D,A,B) ) ) ) - ); - - } - else - return -0; //intersection exists - -} - - - -//trivial -double distance_pt_pt(POINT3D *p1, POINT3D *p2) -{ - //print_point_debug(p1); - //print_point_debug(p2); - return ( sqrt( (p2->x - p1->x) * (p2->x - p1->x) + (p2->y - p1->y) * (p2->y - p1->y) ) ); -} - - -//search all the segments of line to see which one is closest to p1 -double distance_pt_line(POINT3D *p1, LINE3D *l2) -{ - double result = 99999999999.9,dist_this; - bool result_okay = FALSE; //result is a valid min - int t; - POINT3D *start,*end; - - start = &(l2->points[0]); - - for (t =1;tnpoints;t++) - { - end = &(l2->points[t]); - - dist_this = distance_pt_seg(p1, start,end); - if (result_okay) - result= min(result,dist_this); - else - { - result_okay = TRUE; - result = dist_this; - } - - start =end; - } - - return result; -} - - - -// test each segment of l1 against each segment of l2. Return min -double distance_line_line(LINE3D *l1, LINE3D *l2) -{ - - double result = 99999999999.9,dist_this; - bool result_okay = FALSE; //result is a valid min - int t,u; - POINT3D *start,*end; - POINT3D *start2,*end2; - - - start = &(l1->points[0]); - - for (t =1;tnpoints;t++) //for each segment in L1 - { - end = &(l1->points[t]); - - start2 = &(l2->points[0]); - - for (u=1; u< l2->npoints; u++) //for each segment in L2 - { - end2 = &(l2->points[u]); - - dist_this = distance_seg_seg(start,end,start2,end2); -//printf("line_line; seg %i * seg %i, dist = %g\n",t,u,dist_this); - - if (result_okay) - result= min(result,dist_this); - else - { - result_okay = TRUE; - result = dist_this; - } - if (result <=0) - return 0; //intersection - - start2 = end2; - } - start = end; - } - - return result; -} - - -// 1. see if pt in outer boundary. if no, then treat the outer ring like a line -// 2. if in the boundary, test to see if its in a hole. if so, then return dist to hole -double distance_pt_poly(POINT3D *p1, POLYGON3D *poly2) -{ - POINT3D *pts; //pts array for polygon - double result; - LINE3D *line; - int junk,t; - int offset; - - - pts = (POINT3D *) ( (char *)&(poly2->npoints[poly2->nrings] ) ); - pts = (POINT3D *) MAXALIGN(pts); - - - if (PIP( p1, pts, poly2->npoints[0] ) ) - { - //inside the outer ring. scan though each of the inner rings looking to - // see if its inside. If not, distance =0. Otherwise, distance = - // pt to ring distance - - offset = poly2->npoints[0]; //where ring t starts; - for (t=1; tnrings;t++) //foreach inner ring - { - if ( PIP( p1, &pts[offset], poly2->npoints[t] ) ) - { - //inside a hole. Distance = pt -> ring - - line = make_line (poly2->npoints[t] , &pts[offset] , &junk); - result = distance_pt_line(p1, line); - pfree(line); - return result; - } - offset += poly2->npoints[t]; - } - - return 0; //its inside the polygon - } - else - { - //outside the outer ring. Distance = pt -> ring - - line = make_line (poly2->npoints[0] , pts, &junk); - result = distance_pt_line(p1, line); - pfree(line); - return result; - } - - -} - - -// brute force. Test l1 against each ring. If there's an intersection then return 0 (crosses boundary) -// otherwise, test to see if a point inside outer rings of polygon, but not in inner rings. -// if so, return 0 (line inside polygon) -// otherwise return min distance to a ring (could be outside polygon or inside a hole) -double distance_line_poly(LINE3D *l1, POLYGON3D *poly2) -{ - double min_dist=9999999.0,this_dist; - int t,junk; - LINE3D *line; - POINT3D *pts; //pts array for polygon - int offset; - - - - pts = (POINT3D *) ( (char *)&(poly2->npoints[poly2->nrings] ) ); - pts = (POINT3D *) MAXALIGN(pts); - - offset =0; - for (t=0;tnrings; t++) - { - line = make_line (poly2->npoints[t] , &pts[offset] , &junk); - this_dist = distance_line_line(l1, line); - pfree(line); - -//printf("line_poly; ring %i dist = %g\n",t,this_dist); - if (t==0) - min_dist = this_dist; - else - min_dist = min(min_dist,this_dist); - - if (min_dist <=0) - return 0; //intersection - - offset += poly2->npoints[t]; - } - - //no intersection, have to check if a point is inside the outer ring - - if (PIP( &l1->points[0], pts, poly2->npoints[0] ) ) - { - //its in the polygon. Have to check if its inside a hole - -//printf("line_poly; inside outer ring\n"); - offset =poly2->npoints[0] ; - for (t=1; tnrings;t++) //foreach inner ring - { - if ( PIP( &l1->points[0], &pts[offset], poly2->npoints[t] ) ) - { - //its inside a hole, then the actual distance is the min ring distance -//printf("line_poly; inside inner ring %i\n",t); - return min_dist; - } - offset += poly2->npoints[t]; - } - // not in hole, there for inside the polygon - return 0; - } - else - { - //not in the outside ring, so min distance to a ring is the actual min distance - return min_dist; - } - -} - -// true if point is in poly (and not in its holes) -bool point_in_poly(POINT3D *p, POLYGON3D *poly) -{ - int t; - POINT3D *pts1; - int offset; - - pts1 = (POINT3D *) ( (char *)&(poly->npoints[poly->nrings] ) ); - pts1 = (POINT3D *) MAXALIGN(pts1); - - if (PIP(p, pts1, poly->npoints[0])) - { - offset = poly->npoints[0]; - for (t=1;tnrings;t++) - { - if (PIP(p, &pts1[offset], poly->npoints[t]) ) - { - return FALSE; //inside a hole - } - offset += poly->npoints[t]; - } - return TRUE; //in outer ring, not in holes - } - else - return FALSE; //not in outer ring -} - -// brute force. -// test to see if any rings intersect. if yes, dist =0 -// test to see if one inside the other and if they are inside holes. -// find min distance ring-to-ring -double distance_poly_poly(POLYGON3D *poly1, POLYGON3D *poly2) -{ - //foreach ring in Poly1 - // foreach ring in Poly2 - // if intersect, return 0 - - // if poly1 inside poly2 return 0 - // if poly2 inside poly1 return 0 - - // otherwise return closest approach of rings - - int t,junk; - POINT3D *pts1,*pts2; - int32 offset1; - double min_dist= 99999999999.9, this_dist; - LINE3D *line; - - - pts1 = (POINT3D *) ( (char *)&(poly1->npoints[poly1->nrings] ) ); - pts1 = (POINT3D *) MAXALIGN(pts1); - pts2 = (POINT3D *) ( (char *)&(poly2->npoints[poly2->nrings] ) ); - pts2 = (POINT3D *) MAXALIGN(pts2); - - - //do this first as its a quick test - - //test if poly1 inside poly2 - if (point_in_poly(pts1, poly2) ) - return 0; - - //test if poly2 inside poly1 - if (point_in_poly(pts2, poly1) ) - return 0; - - - offset1 =0; - for (t=0; tnrings; t++) //for each ring in poly1 - { - line = make_line (poly1->npoints[t] , &pts1[offset1] , &junk); - this_dist = distance_line_poly(line, poly2); - pfree(line); -//printf("poly_poly; ring %i dist = %g\n",t,this_dist); - if (t==0) - min_dist = this_dist; - else - min_dist = min(min_dist,this_dist); - - if (min_dist <=0) - return 0; //intersection - - - offset1 += poly1->npoints[t]; - } - - //rings do not intersect - - return min_dist; -} - -//minimum distance between objects in geom1 and geom2. returns null if it doesnt exist (future null-safe version). -PG_FUNCTION_INFO_V1(distance); -Datum distance(PG_FUNCTION_ARGS) -{ - - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - int g1_i, g2_i; - double dist,this_dist = 0; - bool dist_set = FALSE; //true once dist makes sense. - int32 *offsets1,*offsets2; - int type1,type2; - char *o1,*o2; - - - if (geom1->SRID != geom2->SRID) - { - elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n"); - PG_RETURN_NULL(); - } - - dist = 99999999999999999999.9; //very far - - - offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ; - offsets2 = (int32 *) ( ((char *) &(geom2->objType[0] ))+ sizeof(int32) * geom2->nobjs ) ; - - - for (g1_i=0; g1_i < geom1->nobjs; g1_i++) - { - o1 = (char *) geom1 +offsets1[g1_i] ; - type1= geom1->objType[g1_i]; - for (g2_i=0; g2_i < geom2->nobjs; g2_i++) - { - o2 = (char *) geom2 +offsets2[g2_i] ; - type2= geom2->objType[g2_i]; - - if ( (type1 == POINTTYPE) && (type2 == POINTTYPE) ) - { - this_dist = distance_pt_pt( (POINT3D *)o1, (POINT3D *)o2 ); - } - if ( (type1 == POINTTYPE) && (type2 == LINETYPE) ) - { - this_dist = distance_pt_line( (POINT3D *)o1, (LINE3D *)o2 ); - } - if ( (type1 == POINTTYPE) && (type2 == POLYGONTYPE) ) - { - this_dist = distance_pt_poly( (POINT3D *)o1, (POLYGON3D *)o2 ); - } - if ( (type1 == LINETYPE) && (type2 == LINETYPE) ) - { - this_dist = distance_line_line( (LINE3D *)o1, (LINE3D *)o2 ); - } - if ( (type1 == LINETYPE) && (type2 == POLYGONTYPE) ) - { - this_dist = distance_line_poly( (LINE3D *)o1, (POLYGON3D *)o2 ); - } - if ( (type1 == POLYGONTYPE) && (type2 == POLYGONTYPE) ) - { - this_dist = distance_poly_poly( (POLYGON3D *)o1, (POLYGON3D *)o2 ); - } - //trival versions based on above dist(a,b) = dist(b,a) - - if ( (type1 == LINETYPE) && (type2 == POINTTYPE) ) - { - this_dist = distance_pt_line( (POINT3D *)o2, (LINE3D *)o1 ); - } - if ( (type1 == POLYGONTYPE) && (type2 == POINTTYPE) ) - { - this_dist = distance_pt_poly( (POINT3D *)o2, (POLYGON3D *)o1 ); - } - if ( (type1 == POLYGONTYPE) && (type2 == LINETYPE) ) - { - this_dist = distance_line_poly( (LINE3D *)o2, (POLYGON3D *)o1 ); - } - - if (dist_set) - { - dist = min(dist,this_dist); - } - else - { - dist = this_dist; //first one through - dist_set = TRUE; - } - - if (dist <= 0.0) - PG_RETURN_FLOAT8( (double) 0.0); // no need to look for things closer - } - } - if (dist <0) - dist = 0; //computational error, may get -0.00000000001 - PG_RETURN_FLOAT8(dist); -} - - -//expand_bbox(bbox3d, d) -// returns a new bbox which is exanded d unit in all directions -PG_FUNCTION_INFO_V1(expand_bbox); -Datum expand_bbox(PG_FUNCTION_ARGS) -{ - BOX3D *bbox = (BOX3D *) PG_GETARG_POINTER(0); - double d = PG_GETARG_FLOAT8(1); - BOX3D *result = (BOX3D *) palloc(sizeof(BOX3D)); - - - result->LLB.x = bbox->LLB.x - d; - result->LLB.y = bbox->LLB.y - d; - result->LLB.z = bbox->LLB.z - d; - - - result->URT.x = bbox->URT.x + d; - result->URT.y = bbox->URT.y + d; - result->URT.z = bbox->URT.z + d; - - - PG_RETURN_POINTER(result); -} - -// makes a polygon of the expanded features bvol - 1st point = LL 3rd=UR -// 2d only -// create new geometry of type polygon, 1 ring, 5 points -PG_FUNCTION_INFO_V1(expand_geometry); -Datum expand_geometry(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - double d = PG_GETARG_FLOAT8(1); - GEOMETRY *result; - POLYGON3D *poly; - POINT3D pts[5]; //5 points around box - int pts_per_ring[1]; - int poly_size; - - //use LLB's z value (we're going to set is3d to false) - - //0,1,2,3,4 --> CCW order, 4,3,2,1,0 --> CW order - set_point( &pts[4], geom->bvol.LLB.x - d, geom->bvol.LLB.y - d, - geom->bvol.LLB.z - d ); - set_point( &pts[3], geom->bvol.URT.x + d, geom->bvol.LLB.y - d, - geom->bvol.LLB.z - d ); - set_point( &pts[2], geom->bvol.URT.x + d, geom->bvol.URT.y + d, - geom->bvol.LLB.z - d); - set_point( &pts[1], geom->bvol.LLB.x - d, geom->bvol.URT.y + d, - geom->bvol.LLB.z - d); - memcpy(&pts[0], &pts[4], sizeof(POINT3D)); - - pts_per_ring[0] = 5; //ring has 5 points - - //make a polygon - poly = make_polygon(1, pts_per_ring, pts, 5, &poly_size); - - result = make_oneobj_geometry(poly_size, (char *)poly, POLYGONTYPE, FALSE,geom->SRID, geom->scale, geom->offsetX, geom->offsetY); - - PG_RETURN_POINTER(result); - -} - -//startpoint(geometry) :- if geometry is a linestring, return the first -//point. Otherwise, return NULL. - -PG_FUNCTION_INFO_V1(startpoint); -Datum startpoint(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - POINT3D *pt; - LINE3D *line; - int32 *offsets1; - - if ( (geom1->type != LINETYPE) && (geom1->type != MULTILINETYPE) ) - PG_RETURN_NULL(); - - offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ; - - - line = (LINE3D *) ( (char *) geom1 +offsets1[0]); - - pt = &line->points[0]; - - PG_RETURN_POINTER( - make_oneobj_geometry(sizeof(POINT3D), - (char *) pt, - POINTTYPE, geom1->is3d, geom1->SRID, geom1->scale, geom1->offsetX, geom1->offsetY) - ); -} - -//endpoint(geometry) :- if geometry is a linestring, return the last -//point. Otherwise, return NULL. - -PG_FUNCTION_INFO_V1(endpoint); -Datum endpoint(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - POINT3D *pt; - LINE3D *line; - int32 *offsets1; - - - - if ( (geom1->type != LINETYPE) && (geom1->type != MULTILINETYPE) ) - PG_RETURN_NULL(); - - offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ; - - - line = (LINE3D *) ( (char *) geom1 +offsets1[0]); - - - pt = &line->points[line->npoints-1]; - - PG_RETURN_POINTER( - make_oneobj_geometry(sizeof(POINT3D), - (char *) pt, - POINTTYPE, geom1->is3d, geom1->SRID, geom1->scale, geom1->offsetX, geom1->offsetY) - ); -} - - - -//isclosed(geometry) :- if geometry is a linestring then returns -//startpoint == endpoint. If its not a linestring then return NULL. If -//its a multilinestring, return true only if all the sub-linestrings have -//startpoint=endpoint. -//calculations always done in 3d (even if you do a force2d) - - -PG_FUNCTION_INFO_V1(isclosed); -Datum isclosed(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - POINT3D *pt1,*pt2; - LINE3D *line; - int32 *offsets1; - int t; - - if (!((geom1->type == LINETYPE) || (geom1->type == MULTILINETYPE) )) - PG_RETURN_NULL(); - - offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ; - - - for (t=0; t< geom1->nobjs; t++) - { - line = (LINE3D *) ( (char *) geom1 +offsets1[t]); - pt1 = &line->points[0]; - pt2 = &line->points[line->npoints-1]; - - if ( (pt1->x != pt2->x) || (pt1->y != pt2->y) || (pt1->z != pt2->z) ) - PG_RETURN_BOOL(FALSE); - } - PG_RETURN_BOOL(TRUE); -} - -#if ! USE_GEOS -PG_FUNCTION_INFO_V1(centroid); -Datum centroid(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - int32 *offsets1; - POINT3D *pts,*cent; - POLYGON3D *poly; - int t,v; - int num_points,num_points_tot; - double tot_x,tot_y,tot_z; - GEOMETRY *result; - - - - offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ; - - if (!((geom1->type == POLYGONTYPE) || (geom1->type == MULTIPOLYGONTYPE) )) - PG_RETURN_NULL(); - - //find the centroid - num_points_tot = 0; - tot_x = 0; tot_y =0; tot_z=0; - - for (t=0;tnobjs;t++) - { - poly = (POLYGON3D *) ( (char *) geom1 +offsets1[t]); - pts = (POINT3D *) ( (char *)&(poly->npoints[poly->nrings] ) ); - pts = (POINT3D *) MAXALIGN(pts); - num_points =poly->npoints[0]; - - // just do the outer ring - // for (u=0;unrings;u++) - // { - // num_points += poly->npoints[u]; - // } - - num_points_tot += num_points-1; //last point = 1st point - for (v=0;vis3d, geom1->SRID, geom1->scale, geom1->offsetX, geom1->offsetY) - ); - pfree(cent); - PG_RETURN_POINTER(result); - -} -#endif // ! defined USE_GEOS - -// max_distance(geom,geom) (both geoms must be linestrings) -//find max distance between l1 and l2 -// method: for each point in l1, find distance to l2. -// return max distance -// -// note: max_distance(l1,l2) != max_distance(l2,l1) -// returns double - -PG_FUNCTION_INFO_V1(max_distance); -Datum max_distance(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - LINE3D *l1,*l2; - - int32 *offsets1,*offsets2; - - int t; - POINT3D *pt; - - double result,dist; - - elog(ERROR, "This function is unimplemented yet"); - PG_RETURN_NULL(); - - if (geom1->SRID != geom2->SRID) - { - elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n"); - PG_RETURN_NULL(); - } - - // only works with lines - if ( (geom1->type != LINETYPE) || (geom2->type != LINETYPE) ) - PG_RETURN_NULL(); - - offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ; - offsets2 = (int32 *) ( ((char *) &(geom2->objType[0] ))+ sizeof(int32) * geom2->nobjs ) ; - - l1 = (LINE3D *) ( (char *) geom1 +offsets1[0] ); - l2 = (LINE3D *) ( (char *) geom2 +offsets2[0] ) ; - - result = -9999; // all distances should be positive - - for(t=0;tnpoints;t++) //for each point in l1 - { - pt = &l1->points[t]; - dist = distance_pt_line(pt, l2); - - if (dist > result) - { - result = dist; - } - } - - if (result <0.0) - result = 0; - - PG_RETURN_FLOAT8(result); -} - -// optimistic_overlap(Polygon P1, Multipolygon MP2, double dist) -// returns true if P1 overlaps MP2 -// method: bbox check - is separation < dist? no - return false (quick) -// yes - return distance(P1,MP2) < dist - -PG_FUNCTION_INFO_V1(optimistic_overlap); -Datum optimistic_overlap(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - double dist = PG_GETARG_FLOAT8(2); - BOX3D g1_bvol; - double calc_dist; - - if (geom1->SRID != geom2->SRID) - { - elog(ERROR,"optimistic_overlap:Operation on two GEOMETRIES with different SRIDs\n"); - PG_RETURN_NULL(); - } - - if (geom1->type != POLYGONTYPE) - { - elog(ERROR,"optimistic_overlap: first arg isnt a polygon\n"); - PG_RETURN_NULL(); - } - - if ( (geom2->type != POLYGONTYPE) && (geom2->type != MULTIPOLYGONTYPE) ) - { - elog(ERROR,"optimistic_overlap: 2nd arg isnt a [multi-]polygon\n"); - PG_RETURN_NULL(); - } - - //bbox check - - memcpy(&g1_bvol, &geom1->bvol, sizeof(BOX3D) ); - - g1_bvol.LLB.x = g1_bvol.LLB.x - dist; - g1_bvol.LLB.y = g1_bvol.LLB.y - dist; - - g1_bvol.URT.x = g1_bvol.URT.x + dist; - g1_bvol.URT.y = g1_bvol.URT.y + dist; - - //xmin = LLB.x, xmax = URT.x - - - if ( (g1_bvol.LLB.x > geom2->bvol.URT.x) || - (g1_bvol.URT.x < geom2->bvol.LLB.x) || - (g1_bvol.LLB.y > geom2->bvol.URT.y) || - (g1_bvol.URT.y < geom2->bvol.LLB.y) - ) - { - PG_RETURN_BOOL(FALSE); //bbox not overlap - } - - //compute distances - //should be a fast calc if they actually do intersect - calc_dist = DatumGetFloat8 (DirectFunctionCall2(distance, PointerGetDatum( geom1 ), PointerGetDatum( geom2 ))); - - PG_RETURN_BOOL(calc_dist < dist); -} - -//returns a list of points for a single polygon -// foreach segment -// (1st and last points will be unaltered, but -// there will be more points inbetween if segment length is -POINT3D *segmentize_ring(POINT3D *points, double dist, int num_points_in, int *num_points_out) -{ - double seg_distance; - int max_points, offset_new,offset_old; - POINT3D *result,*r; - bool keep_going; - POINT3D *last_point, *next_point; - - - //initial storage - max_points = 1000; - offset_new=0; //start at beginning of points list - result = (POINT3D *) palloc (sizeof(POINT3D) * max_points); - - memcpy(result, points, sizeof(POINT3D) ); //1st point - offset_new++; - - last_point = points; - offset_old = 1; - - keep_going = 1; - while(keep_going) - { - next_point = &points[offset_old]; - - //distance last->next > dist - seg_distance = sqrt( - (next_point->x-last_point->x)*(next_point->x-last_point->x) + - (next_point->y-last_point->y)*(next_point->y-last_point->y) ); - if (offset_new >= max_points) - { - //need to add new points to result - r = result; - result = (POINT3D *) palloc (sizeof(POINT3D) * max_points *2);//double size - memcpy(result,r, sizeof(POINT3D)*max_points); - max_points *=2; - pfree(r); - } - - if (seg_distance > dist) - { - //add a point at the distance location - // and set last_point to this loc - - result[offset_new].x = last_point->x + (next_point->x-last_point->x)/seg_distance * dist; - result[offset_new].y = last_point->y + (next_point->y-last_point->y)/seg_distance * dist; - last_point = &result[offset_new]; - offset_new ++; - } - else - { - //everything fine, just add the next_point and pop forward - result[offset_new].x = next_point->x; - result[offset_new].y = next_point->y; - offset_new++; - offset_old++; - last_point = next_point; - } - keep_going = (offset_old < num_points_in); - } - *num_points_out = offset_new; - return result; -} - -// select segmentize('POLYGON((0 0, 0 10, 5 5, 0 0))',1); - -//segmentize(GEOMETRY P1, double maxlen) -//given a [multi-]polygon, return a new polygon with each segment at most a given length -PG_FUNCTION_INFO_V1(segmentize); -Datum segmentize(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *result = NULL, *result2; - double maxdist = PG_GETARG_FLOAT8(1); - int32 *offsets1,*p_npoints_ring; - int g1_i,r; - POLYGON3D *p,*poly; - POINT3D *polypts; - int num_polypts; - POINT3D *all_polypts; - int all_num_polypts,all_num_polypts_max; - POINT3D *p_points,*rr; - int new_size; - bool first_one; - int poly_size; - BOX3D *bbox; - - first_one = 1; - - - if ( (geom1->type != POLYGONTYPE) && (geom1->type != MULTIPOLYGONTYPE) ) - { - elog(ERROR,"segmentize: 1st arg isnt a [multi-]polygon\n"); - PG_RETURN_NULL(); - } - - - - offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ; - - for (g1_i=0; g1_i < geom1->nobjs; g1_i++) - { - - all_num_polypts = 0; - all_num_polypts_max = 1000; - all_polypts = (POINT3D *) palloc (sizeof(POINT3D) * all_num_polypts_max ); - - p = (POLYGON3D*)((char *) geom1 +offsets1[g1_i]) ; // the polygon - - p_npoints_ring = (int32 *) palloc(sizeof(int32) * p->nrings); - - p_points = (POINT3D *) ( (char *)&(p->npoints[p->nrings] ) ); - p_points = (POINT3D *) MAXALIGN(p_points); - - for (r=0;rnrings;r++) //foreach ring in the polygon - { - polypts = segmentize_ring(p_points, maxdist, p->npoints[r], &num_polypts); - if ( (all_num_polypts + num_polypts) < all_num_polypts_max ) - { - //just add - memcpy( &all_polypts[all_num_polypts], polypts, sizeof(POINT3D) *num_polypts ); - all_num_polypts += num_polypts; - } - else - { - //need more space - new_size = all_num_polypts_max + num_polypts + 1000; - rr = (POINT3D*) palloc(sizeof(POINT3D) * new_size); - memcpy(rr,all_polypts, sizeof(POINT3D) *all_num_polypts); - memcpy(&rr[all_num_polypts], polypts , sizeof(POINT3D) *num_polypts); - pfree(all_polypts); - all_polypts = rr; - all_num_polypts += num_polypts; - } - //set points in ring value - pfree(polypts); - p_npoints_ring[r] = num_polypts; - } //for each ring - - poly = make_polygon(p->nrings, p_npoints_ring, all_polypts, all_num_polypts, &poly_size); - - if (first_one) - { - first_one = 0; - result = make_oneobj_geometry(poly_size, (char *)poly, POLYGONTYPE, FALSE,geom1->SRID, geom1->scale, geom1->offsetX, geom1->offsetY); - pfree(poly); - pfree(all_polypts); - } - else - { - result2 = add_to_geometry(result,poly_size, (char *) poly, POLYGONTYPE); - bbox = bbox_of_geometry( result2 ); // make bounding box - memcpy( &result2->bvol, bbox, sizeof(BOX3D) ); // copy bounding box - pfree(bbox); // free bounding box - pfree(result); - result = result2; - pfree(poly); - pfree(all_polypts); - } - - } // foreach polygon - PG_RETURN_POINTER(result); -} - -/* - * This is a geometry array constructor - * for use as aggregates sfunc. - * Will have * as input an array of Geometry pointers and a Geometry. - * Will DETOAST given geometry and put a pointer to it - * in the given array. DETOASTED value is first copied - * to a safe memory context to avoid premature deletion. - */ -PG_FUNCTION_INFO_V1(geom_accum); -Datum geom_accum(PG_FUNCTION_ARGS) -{ - ArrayType *array; - int nelems, nbytes; - Datum datum; - GEOMETRY *geom; - ArrayType *result; - Pointer **pointers; - MemoryContext oldcontext; - - datum = PG_GETARG_DATUM(0); - if ( (Pointer *)datum == NULL ) { - array = NULL; - nelems = 0; - //elog(NOTICE, "geom_accum: NULL array, nelems=%d", nelems); - } else { - array = (ArrayType *) PG_DETOAST_DATUM_COPY(datum); - nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array)); - } - - datum = PG_GETARG_DATUM(1); - // Do nothing, return state array - if ( (Pointer *)datum == NULL ) - { - //elog(NOTICE, "geom_accum: NULL geom, nelems=%d", nelems); - PG_RETURN_ARRAYTYPE_P(array); - } - - /* - * Switch to * flinfo->fcinfo->fn_mcxt - * memory context to be sure both detoasted - * geometry AND array of pointers to it - * last till the call to unite_finalfunc. - */ - oldcontext = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt); - - /* Make a DETOASTED copy of input geometry */ - geom = (GEOMETRY *)PG_DETOAST_DATUM_COPY(datum); - - //elog(NOTICE, "geom_accum: adding %p (nelems=%d)", geom, nelems); - - /* - * Might use a more optimized version instead of repalloc'ing - * at every iteration. This is not the bottleneck anyway. - * --strk(TODO); - */ - ++nelems; - nbytes = ARR_OVERHEAD(1) + sizeof(Pointer *) * nelems; - if ( ! array ) { - result = (ArrayType *) palloc(nbytes); - result->size = nbytes; - result->ndim = 1; - *((int *) ARR_DIMS(result)) = nelems; - } else { - result = (ArrayType *) repalloc(array, nbytes); - result->size = nbytes; - result->ndim = 1; - *((int *) ARR_DIMS(result)) = nelems; - } - - pointers = (Pointer **)ARR_DATA_PTR(result); - pointers[nelems-1] = (Pointer *)geom; - - /* Go back to previous memory context */ - MemoryContextSwitchTo(oldcontext); - - - PG_RETURN_ARRAYTYPE_P(result); - -} - -/* - * collect_garray ( GEOMETRY[] ) returns a geometry which contains - * all the sub_objects from all of the geometries in given array. - * - * returned geometry is the simplest possible, based on the types - * of the collected objects - * ie. if all are of either X or multiX, then a multiX is returned - * bboxonly types are treated as null geometries (no sub_objects) - */ -PG_FUNCTION_INFO_V1( collect_garray ); -Datum collect_garray ( PG_FUNCTION_ARGS ) -{ - Datum datum; - ArrayType *array; - int nelems, srid=-1, is3d=0; - GEOMETRY **geoms; - GEOMETRY *result=NULL, *geom, *tmp; - int i, o; - BOX3D *bbox; - - /* Get input datum */ - datum = PG_GETARG_DATUM(0); - - /* Return null on null input */ - if ( (Pointer *)datum == NULL ) PG_RETURN_NULL(); - - /* Get actual ArrayType */ - array = (ArrayType *) PG_DETOAST_DATUM(datum); - - /* Get number of geometries in array */ - nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array)); - - /* Return null on 0-elements input array */ - if ( nelems == 0 ) PG_RETURN_NULL(); - - /* Get pointer to GEOMETRY pointers array */ - geoms = (GEOMETRY **)ARR_DATA_PTR(array); - - /* Return the only present element of a 1-element array */ - if ( nelems == 1 ) PG_RETURN_POINTER(geoms[0]); - - /* Iterate over all geometries in array */ - for (i=0; iSRID; - - /* Get first geometry's is3d flag as base is3d */ - is3d = geom->is3d; - - result = (GEOMETRY *)palloc(geom->size); - if ( ! result ) { - elog(ERROR, "collect_garray: out of virtual memory"); - PG_RETURN_NULL(); - } - memcpy(result, geom, geom->size); - - /* - * I belive memory associated with geometries - * in array can be safely removed. Comment - * this out if you get memory faults! - * TODO: inspect this (as long as passed - * array is the result of geom_accum this - * is true because geom_accum will DETOAST_COPY - * while for direct user call I do not know) - */ - pfree(geom); - - continue; - } - - /* Skip geometry if it contains no sub-objects */ - if ( ! geom->nobjs ) - { - if ( geom->is3d ) is3d = 1; // should I care ? - pfree(geom); // se note above - continue; - } - - /* - * If we are here this means we are in front of a - * good (non empty) geometry beside the first - */ - - /* Fist let's check for SRID compatibility */ - if ( geom->SRID != srid ) - { - elog(ERROR, "Operation on GEOMETRIES with different SRIDs"); - PG_RETURN_NULL(); - } - - /* - * Set result is3d flag to true if at least one - * of geometries in set has is set to true - */ - if ( geom->is3d ) is3d = 1; - - /* Get to sub-objects offset */ - offsets = (int32 *)(((char *)&(geom->objType[0])) + - sizeof(int32) * geom->nobjs ) ; - - /* Iterate over geometry sub-objects */ - for (o=0; onobjs; o++) - { - int size, type; - char *obj; - - /* Get object pointer */ - obj = (char *) geom+offsets[o]; - - /* Get object type */ - type = geom->objType[o]; - - /* Get object size (fast way) */ - if( o == geom->nobjs-1 ) { - size = geom->size - offsets[o]; - } else { - size = offsets[o+1] - offsets[o]; - } - - /* - * Add sub-object to base geometry, - * replace base geometry with new one. - */ - tmp = add_to_geometry(result, size, obj, type); - pfree( result ); - result = tmp; - } - pfree(geom); // se note above - } - - /* Check we got something in our result */ - if ( result == NULL ) PG_RETURN_NULL(); - - /* - * We should now have a big fat geometry composed of all - * sub-objects from all geometries in array - */ - - /* Set is3d flag */ - result->is3d = is3d; - - /* Construct bounding volume */ - bbox = bbox_of_geometry( result ); // make - memcpy( &result->bvol, bbox, sizeof(BOX3D) ); // copy - pfree( bbox ); // release - - PG_RETURN_POINTER( result ); -} - -// collector( geom, geom ) returns a geometry which contains -// all the sub_objects from both of the argument geometries - -// returned geometry is the simplest possible, based on the types -// of the colelct objects -// ie. if all are of either X or multiX, then a multiX is returned -// bboxonly types are treated as null geometries (no sub_objects) -PG_FUNCTION_INFO_V1( collector ); -Datum collector( PG_FUNCTION_ARGS ) -{ - Pointer geom1_ptr = PG_GETARG_POINTER(0); - Pointer geom2_ptr = PG_GETARG_POINTER(1); - GEOMETRY *geom1, *geom2, *temp, *result; - BOX3D *bbox; - int32 i, size, *offsets2; - - // return null if both geoms are null - if ( (geom1_ptr == NULL) && (geom2_ptr == NULL) ) - { - PG_RETURN_NULL(); - } - - // return a copy of the second geom if only first geom is null - if (geom1_ptr == NULL) - { - geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - result = (GEOMETRY *)palloc( geom2->size ); - memcpy( result, geom2, geom2->size ); - PG_RETURN_POINTER(result); - } - - // return a copy of the first geom if only second geom is null - if (geom2_ptr == NULL) - { - geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - result = (GEOMETRY *)palloc( geom1->size ); - memcpy( result, geom1, geom1->size ); - PG_RETURN_POINTER(result); - } - - geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - if ( geom1->SRID != geom2->SRID ) - { - elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n"); - PG_RETURN_NULL(); - } - - if (geom1->nobjs ==0) - { - geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - result = (GEOMETRY *)palloc( geom2->size ); - memcpy( result, geom2, geom2->size ); - PG_RETURN_POINTER(result); - } - if (geom2->nobjs ==0) - { - geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - result = (GEOMETRY *)palloc( geom1->size ); - memcpy( result, geom1, geom1->size ); - PG_RETURN_POINTER(result); - } - - result = (GEOMETRY *)palloc( geom1->size ); - memcpy( result, geom1, geom1->size ); - - offsets2 = (int32 *)( ((char *)&(geom2->objType[0])) + sizeof( int32 ) * geom2->nobjs ) ; - - for (i=0; inobjs; i++) - { - if( i == geom2->nobjs-1 ) - { - size = geom2->size - offsets2[i]; - } - else - { - size = offsets2[i+1] - offsets2[i]; - } - temp = add_to_geometry( result, size, ((char *) geom2 + offsets2[i]), geom2->objType[i] ); - pfree( result ); - result = temp; - } - - result->is3d = geom1->is3d || geom2->is3d; - bbox = bbox_of_geometry( result ); // make bounding box - memcpy( &result->bvol, bbox, sizeof(BOX3D) ); // copy bounding box - pfree( bbox ); // free bounding box - - PG_RETURN_POINTER( result ); -} - -PG_FUNCTION_INFO_V1(box3d_xmin); -Datum box3d_xmin(PG_FUNCTION_ARGS) -{ - BOX3D *box1 = (BOX3D *) PG_GETARG_POINTER(0); - - PG_RETURN_FLOAT8(box1->LLB.x); -} - -PG_FUNCTION_INFO_V1(box3d_ymin); -Datum box3d_ymin(PG_FUNCTION_ARGS) -{ - BOX3D *box1 = (BOX3D *) PG_GETARG_POINTER(0); - - PG_RETURN_FLOAT8(box1->LLB.y); -} - -PG_FUNCTION_INFO_V1(box3d_zmin); -Datum box3d_zmin(PG_FUNCTION_ARGS) -{ - BOX3D *box1 = (BOX3D *) PG_GETARG_POINTER(0); - - PG_RETURN_FLOAT8(box1->LLB.z); -} - -PG_FUNCTION_INFO_V1(box3d_xmax); -Datum box3d_xmax(PG_FUNCTION_ARGS) -{ - BOX3D *box1 = (BOX3D *) PG_GETARG_POINTER(0); - - PG_RETURN_FLOAT8(box1->URT.x); -} - -PG_FUNCTION_INFO_V1(box3d_ymax); -Datum box3d_ymax(PG_FUNCTION_ARGS) -{ - BOX3D *box1 = (BOX3D *) PG_GETARG_POINTER(0); - - PG_RETURN_FLOAT8(box1->URT.y); -} - -PG_FUNCTION_INFO_V1(box3d_zmax); -Datum box3d_zmax(PG_FUNCTION_ARGS) -{ - BOX3D *box1 = (BOX3D *) PG_GETARG_POINTER(0); - - PG_RETURN_FLOAT8(box1->URT.z); -} - -PG_FUNCTION_INFO_V1(box3dtobox); -Datum box3dtobox(PG_FUNCTION_ARGS) -{ - BOX3D *box1 = (BOX3D *) PG_GETARG_POINTER(0); - BOX *out; - out = convert_box3d_to_box(box1); - PG_RETURN_POINTER(out); -} - - -PG_FUNCTION_INFO_V1(isempty); -Datum isempty(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1= (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - - - if (geom1->nobjs ==0) - PG_RETURN_BOOL(TRUE); - PG_RETURN_BOOL(FALSE); -} - - -// converts multi* types with 1 element to the single-element version. -// ie. MULTIPOINT(0 0) --> POINT(0 0) -void compressType(GEOMETRY *g) -{ - if (g->nobjs ==1) - { - if (g->type == MULTIPOINTTYPE) - { - g->type = POINTTYPE; - return; - } - if (g->type == MULTILINETYPE) - { - g->type = LINETYPE; - return; - } - if (g->type == MULTIPOLYGONTYPE) - { - g->type = POLYGONTYPE; - return; - } - - } -} - - -// converts single-type (point,linestring,polygon) -// to multi* types with 1 element -// ie. POINT(0 0) --> MULTIPOINT(0 0) -// -//postgis09=# select fluffType('POINT(0 0)'); -// flufftype -//------------------------- -// SRID=-1;MULTIPOINT(0 0) -//(1 row) -// -//postgis09=# select fluffType('LINESTRING(0 0, 1 1)'); -// flufftype -//------------------------------------ -// SRID=-1;MULTILINESTRING((0 0,1 1)) -//(1 row) - -PG_FUNCTION_INFO_V1(fluffType); -Datum fluffType(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1= (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *g; - - g = (GEOMETRY*) palloc( *((int *) geom1) ); - memcpy(g,geom1, *((int *) geom1)); - - if (g->type == POINTTYPE) - { - g->type = MULTIPOINTTYPE; - } - if (g->type == LINETYPE) - { - g->type = MULTILINETYPE; - } - if (g->type == POLYGONTYPE) - { - g->type = MULTIPOLYGONTYPE; - } - - PG_FREE_IF_COPY(geom1,0); - PG_RETURN_POINTER(g); -} - -PG_FUNCTION_INFO_V1(postgis_lib_version); -Datum postgis_lib_version(PG_FUNCTION_ARGS) -{ - char *ver = POSTGIS_LIB_VERSION; - text *result; - result = (text *) palloc(VARHDRSZ + strlen(ver)); - VARATT_SIZEP(result) = VARHDRSZ + strlen(ver) ; - memcpy(VARDATA(result), ver, strlen(ver)); - PG_RETURN_POINTER(result); -} - -PG_FUNCTION_INFO_V1(postgis_scripts_released); -Datum postgis_scripts_released(PG_FUNCTION_ARGS) -{ - char *ver = POSTGIS_SCRIPTS_VERSION; - text *result; - result = (text *) palloc(VARHDRSZ + strlen(ver)); - VARATT_SIZEP(result) = VARHDRSZ + strlen(ver) ; - memcpy(VARDATA(result), ver, strlen(ver)); - PG_RETURN_POINTER(result); -} - -PG_FUNCTION_INFO_V1(postgis_uses_stats); -Datum postgis_uses_stats(PG_FUNCTION_ARGS) -{ -#ifdef USE_STATS - PG_RETURN_BOOL(TRUE); -#else - PG_RETURN_BOOL(FALSE); -#endif -} diff --git a/hwgeom/postgis_geos.c b/hwgeom/postgis_geos.c deleted file mode 100644 index 1713368f6..000000000 --- a/hwgeom/postgis_geos.c +++ /dev/null @@ -1,2142 +0,0 @@ -/********************************************************************** - * $Id$ - * - * PostGIS - Spatial Types for PostgreSQL - * http://postgis.refractions.net - * Copyright 2001-2003 Refractions Research Inc. - * - * This is free software; you can redistribute and/or modify it under - * the terms of the GNU General Public Licence. See the COPYING file. - * - ********************************************************************** - * $Log$ - * Revision 1.1 2004/09/20 07:50:06 strk - * prepared to contain old internal representation code - * - * Revision 1.39 2004/08/23 15:37:16 strk - * Changed SCRIPTS_VERSION to 0.0.1 - * - * Revision 1.38 2004/07/28 16:10:59 strk - * Changed all version functions to return text. - * Renamed postgis_scripts_version() to postgis_scripts_installed() - * Added postgis_scripts_released(). - * Added postgis_full_version(). - * - * Revision 1.37 2004/07/28 13:37:43 strk - * Added postgis_uses_stats and postgis_scripts_version. - * Experimented with PIP short-circuit in within/contains functions. - * Documented new version functions. - * - * Revision 1.36 2004/07/27 17:51:50 strk - * short-circuit test for 'contains' - * - * Revision 1.35 2004/07/27 17:49:59 strk - * Added short-circuit test for the within function. - * - * Revision 1.34 2004/07/22 16:58:08 strk - * Updated to reflect geos version string split. - * - * Revision 1.33 2004/07/22 16:20:10 strk - * Added postgis_lib_version() and postgis_geos_version() - * - * Revision 1.32 2004/07/01 17:02:05 strk - * Updated to support latest GEOS (actually removed all geos-version related - * switches). - * Fixed an access to unallocated memory. - * - * Revision 1.31 2004/06/16 19:59:36 strk - * Changed GEOS_VERSION to POSTGIS_GEOS_VERSION to avoid future clashes - * - * Revision 1.30 2004/06/16 19:37:54 strk - * Added cleanup needed for GEOS > 1.0 - * - * Revision 1.29 2004/06/16 18:47:59 strk - * Added code to detect geos version. - * Added appropriate includes in geos connectors. - * - * Revision 1.28 2004/04/28 22:26:02 pramsey - * Fixed spelling mistake in header text. - * - * Revision 1.27 2004/02/12 10:34:49 strk - * changed USE_GEOS check from ifdef / ifndef to if / if ! - * - * Revision 1.26 2003/12/12 12:03:29 strk - * More debugging output, some code cleanup. - * - * Revision 1.25 2003/12/12 10:28:50 strk - * added GEOSnoop OUTPUT debugging info - * - * Revision 1.24 2003/12/12 10:08:24 strk - * Added GEOSnoop function and some optional debugging output for - * geos<->postgis converter (define DEBUG_CONVERTER at top postgis_geos.c) - * - * Revision 1.23 2003/11/05 18:25:08 strk - * moved #ifdef USE_GEOS below prototypes, added NULL implementation of unite_garray - * - * Revision 1.22 2003/11/05 18:02:41 strk - * renamed unite_finalfunc to unite_garray - * - * Revision 1.21 2003/11/04 19:06:08 strk - * added missing first geom pfree in unite_finalfunc - * - * Revision 1.20 2003/10/29 15:53:10 strk - * geoscentroid() removed. both geos and pgis versions are called 'centroid'. - * only one version will be compiled based on USE_GEOS flag. - * - * Revision 1.19 2003/10/29 13:59:40 strk - * Added geoscentroid function. - * - * Revision 1.18 2003/10/28 15:16:17 strk - * unite_sfunc() from postgis_geos.c renamed to geom_accum() and moved in postgis_fn.c - * - * Revision 1.17 2003/10/28 10:59:55 strk - * handled NULL state array in unite_finalfunc, cleaned up some spurios code - * - * Revision 1.16 2003/10/27 23:44:54 strk - * unite_sfunc made always copy input array in long lived memory context. - * It should now work with safer memory. - * - * Revision 1.15 2003/10/27 20:13:05 strk - * Made GeomUnion release memory soon, Added fastunion support functions - * - * Revision 1.14 2003/10/24 21:52:35 strk - * Modified strcmp-based if-else with switch-case in GEOS2POSTGIS() - * using new GEOSGeometryTypeId() interface. - * - * Revision 1.13 2003/10/24 08:28:49 strk - * Fixed memory leak in GEOSGetCoordinates(), made sure that GEOS2POSTGIS - * free type string even in case of collapsed geoms. Made sure that geomunion - * release memory in case of exception thrown by GEOSUnion. Sooner release - * of palloced memory in PolyFromGeometry (pts_per_ring). - * - * Revision 1.12 2003/10/16 20:16:18 dblasby - * Added NOTICE_HANDLER function. For some reason this didnt get properly - * committed last time. - * - * Revision 1.11 2003/10/14 23:19:19 dblasby - * GEOS2POSTGIS - added protection to pfree(NULL) for multi* geoms - * - * Revision 1.10 2003/10/03 16:45:37 dblasby - * added pointonsurface() as a sub. Some memory management fixes/tests. - * removed a few NOTICEs. - * - * Revision 1.9 2003/09/16 20:27:12 dblasby - * added ability to delete geometries. - * - * Revision 1.8 2003/08/08 18:19:20 dblasby - * Conformance changes. - * Removed junk from postgis_debug.c and added the first run of the long - * transaction locking support. (this will change - dont use it) - * conformance tests were corrected - * some dos cr/lf removed - * empty geometries i.e. GEOMETRYCOLLECT(EMPTY) added (with indexing support) - * pointN(,1) now returns the first point (used to return 2nd) - * - * Revision 1.7 2003/08/06 19:31:18 dblasby - * Added the WKB parser. Added all the functions like - * PolyFromWKB(,[]). - * - * Added all the functions like PolyFromText(,[]) - * - * Minor problem in GEOS library fixed. - * - * Revision 1.6 2003/08/05 18:27:21 dblasby - * Added null implementations of new GEOS-returning-geometry functions (ie. - * buffer). - * - * Revision 1.5 2003/08/01 23:58:08 dblasby - * added the functionality to convert GEOS->PostGIS geometries. Added those geos - * functions to postgis. - * - * Revision 1.4 2003/07/01 18:30:55 pramsey - * Added CVS revision headers. - * - * - **********************************************************************/ - - -//-------------------------------------------------------------------------- -// -//#define DEBUG - -#include "postgres.h" - - -#include -#include -#include -#include -#include - -#include "fmgr.h" - -#include "postgis.h" -#include "utils/elog.h" -#include "utils/array.h" - -#include "access/gist.h" -#include "access/itup.h" -#include "access/rtree.h" - -#include "utils/builtins.h" - -//#include "postgis_geos_version.h" - - /* - * Define this to have have many notices printed - * during postgis->geos and geos->postgis conversions - */ -#undef DEBUG_CONVERTER -#undef DEBUG_POSTGIS2GEOS -#undef DEBUG_GEOS2POSTGIS - - -typedef struct Geometry Geometry; - - -extern const char * createGEOSPoint(POINT3D *pt); -extern void initGEOS(int maxalign); -extern char *GEOSrelate(Geometry *g1, Geometry*g2); -extern char GEOSrelatePattern(Geometry *g1, Geometry*g2,char *pat); -extern char GEOSrelateDisjoint(Geometry *g1, Geometry*g2); -extern char GEOSrelateTouches(Geometry *g1, Geometry*g2); -extern char GEOSrelateIntersects(Geometry *g1, Geometry*g2); -extern char GEOSrelateCrosses(Geometry *g1, Geometry*g2); -extern char GEOSrelateWithin(Geometry *g1, Geometry*g2); -extern char GEOSrelateContains(Geometry *g1, Geometry*g2); -extern char GEOSrelateOverlaps(Geometry *g1, Geometry*g2); - -extern char *GEOSasText(Geometry *g1); -extern char GEOSisEmpty(Geometry *g1); -extern char *GEOSGeometryType(Geometry *g1); -extern int GEOSGeometryTypeId(Geometry *g1); -extern char *GEOSversion(); -extern char *GEOSjtsport(); - - -extern void GEOSdeleteChar(char *a); -extern void GEOSdeleteGeometry(Geometry *a); - -extern Geometry *PostGIS2GEOS_point(POINT3D *point,int SRID, bool is3d); -extern Geometry *PostGIS2GEOS_linestring(LINE3D *line,int SRID, bool is3d); -extern Geometry *PostGIS2GEOS_polygon(POLYGON3D *polygon,int SRID, bool is3d); -extern Geometry *PostGIS2GEOS_multipolygon(POLYGON3D **polygons,int npolys, int SRID, bool is3d); -extern Geometry *PostGIS2GEOS_multilinestring(LINE3D **lines,int nlines, int SRID, bool is3d); -extern Geometry *PostGIS2GEOS_multipoint(POINT3D **points,int npoints, int SRID, bool is3d); -extern Geometry *PostGIS2GEOS_box3d(BOX3D *box, int SRID); -extern Geometry *PostGIS2GEOS_collection(Geometry **geoms, int ngeoms,int SRID, bool is3d); - -extern char GEOSisvalid(Geometry *g1); - - - -extern char *throw_exception(Geometry *g); -extern Geometry *GEOSIntersection(Geometry *g1, Geometry *g2); - - -extern POINT3D *GEOSGetCoordinate(Geometry *g1); -extern POINT3D *GEOSGetCoordinates(Geometry *g1); -extern int GEOSGetNumCoordinate(Geometry *g1); -extern Geometry *GEOSGetGeometryN(Geometry *g1, int n); -extern Geometry *GEOSGetExteriorRing(Geometry *g1); -extern Geometry *GEOSGetInteriorRingN(Geometry *g1,int n); -extern int GEOSGetNumInteriorRings(Geometry *g1); -extern int GEOSGetSRID(Geometry *g1); -extern int GEOSGetNumGeometries(Geometry *g1); - -extern Geometry *GEOSBuffer(Geometry *g1,double width); -extern Geometry *GEOSConvexHull(Geometry *g1); -extern Geometry *GEOSDifference(Geometry *g1,Geometry *g2); -extern Geometry *GEOSBoundary(Geometry *g1); -extern Geometry *GEOSSymDifference(Geometry *g1,Geometry *g2); -extern Geometry *GEOSUnion(Geometry *g1,Geometry *g2); -extern char GEOSequals(Geometry *g1, Geometry*g2); - -extern char GEOSisSimple(Geometry *g1); -extern char GEOSisRing(Geometry *g1); - -extern Geometry *GEOSpointonSurface(Geometry *g1); -extern Geometry *GEOSGetCentroid(Geometry *g); - - -Datum relate_full(PG_FUNCTION_ARGS); -Datum relate_pattern(PG_FUNCTION_ARGS); -Datum disjoint(PG_FUNCTION_ARGS); -Datum touches(PG_FUNCTION_ARGS); -Datum intersects(PG_FUNCTION_ARGS); -Datum crosses(PG_FUNCTION_ARGS); -Datum within(PG_FUNCTION_ARGS); -Datum contains(PG_FUNCTION_ARGS); -Datum overlaps(PG_FUNCTION_ARGS); -Datum isvalid(PG_FUNCTION_ARGS); - - -Datum buffer(PG_FUNCTION_ARGS); -Datum intersection(PG_FUNCTION_ARGS); -Datum convexhull(PG_FUNCTION_ARGS); -Datum difference(PG_FUNCTION_ARGS); -Datum boundary(PG_FUNCTION_ARGS); -Datum symdifference(PG_FUNCTION_ARGS); -Datum geomunion(PG_FUNCTION_ARGS); -Datum unite_garray(PG_FUNCTION_ARGS); - - -Datum issimple(PG_FUNCTION_ARGS); -Datum isring(PG_FUNCTION_ARGS); -Datum geomequals(PG_FUNCTION_ARGS); -Datum pointonsurface(PG_FUNCTION_ARGS); - -Datum GEOSnoop(PG_FUNCTION_ARGS); - - -Geometry *POSTGIS2GEOS(GEOMETRY *g); -void errorIfGeometryCollection(GEOMETRY *g1, GEOMETRY *g2); -GEOMETRY *GEOS2POSTGIS(Geometry *g, char want3d ); - -POLYGON3D *PolyFromGeometry(Geometry *g, int *size); -LINE3D *LineFromGeometry(Geometry *g, int *size); -void NOTICE_MESSAGE(char *msg); - -#if USE_GEOS - -//----------------------------------------------- -// return a GEOS Geometry from a POSTGIS GEOMETRY -//---------------------------------------------- - - - -void NOTICE_MESSAGE(char *msg) -{ - elog(NOTICE,msg); -} - - -/* - * Resize an ArrayType of 1 dimension to contain num (Pointer *) elements - * array will be repalloc'ed - */ -static ArrayType * -resize_ptrArrayType(ArrayType *a, int num) -{ - int nelems = ArrayGetNItems(ARR_NDIM(a), ARR_DIMS(a)); - int nbytes = ARR_OVERHEAD(1) + sizeof(Pointer *) * num; - - if (num == nelems) return a; - - a = (ArrayType *) repalloc(a, nbytes); - - a->size = nbytes; - a->ndim = 1; - - *((int *) ARR_DIMS(a)) = num; - return a; -} - - -/* - * This is the final function for union/fastunite/geomunion - * aggregate (still discussing the name). Will have - * as input an array of Geometry pointers. - * Will iteratively call GEOSUnion on the GEOS-converted - * versions of them and return PGIS-converted version back. - * Changing combination order *might* speed up performance. - * - * Geometries in the array are pfree'd as soon as possible. - * - */ -PG_FUNCTION_INFO_V1(unite_garray); -Datum unite_garray(PG_FUNCTION_ARGS) -{ - Datum datum; - ArrayType *array; - int is3d = 0; - int nelems, i; - GEOMETRY **geoms, *result, *pgis_geom; - Geometry *g1, *g2, *geos_result; -#ifdef DEBUG - static int call=1; -#endif - -#ifdef DEBUG - call++; -#endif - - datum = PG_GETARG_DATUM(0); - - /* Null array, null geometry (should be empty?) */ - if ( (Pointer *)datum == NULL ) PG_RETURN_NULL(); - - array = (ArrayType *) PG_DETOAST_DATUM(datum); - - nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array)); - -#ifdef DEBUG - elog(NOTICE, "unite_garray: number of elements: %d", nelems); -#endif - - if ( nelems == 0 ) PG_RETURN_NULL(); - - geoms = (GEOMETRY **)ARR_DATA_PTR(array); - - /* One-element union is the element itself */ - if ( nelems == 1 ) PG_RETURN_POINTER(geoms[0]); - - /* Ok, we really need geos now ;) */ - initGEOS(MAXIMUM_ALIGNOF); - - if ( geoms[0]->is3d ) is3d = 1; - geos_result = POSTGIS2GEOS(geoms[0]); - pfree(geoms[0]); - for (i=1; iis3d || geom2->is3d; - - Geometry *g1,*g2,*g3; - GEOMETRY *result; - - initGEOS(MAXIMUM_ALIGNOF); -//elog(NOTICE,"in geomunion"); - - g1 = POSTGIS2GEOS(geom1); - g2 = POSTGIS2GEOS(geom2); - -//elog(NOTICE,"g1=%s",GEOSasText(g1)); -//elog(NOTICE,"g2=%s",GEOSasText(g2)); - g3 = GEOSUnion(g1,g2); - -//elog(NOTICE,"g3=%s",GEOSasText(g3)); - - PG_FREE_IF_COPY(geom1, 0); - PG_FREE_IF_COPY(geom2, 1); - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g2); - - if (g3 == NULL) - { - elog(ERROR,"GEOS union() threw an error!"); - PG_RETURN_NULL(); //never get here - } - -//elog(NOTICE,"result: %s", GEOSasText(g3) ) ; - - result = GEOS2POSTGIS(g3, is3d); - - GEOSdeleteGeometry(g3); - - if (result == NULL) - { - elog(ERROR,"GEOS union() threw an error (result postgis geometry formation)!"); - PG_RETURN_NULL(); //never get here - } - - compressType(result); // convert multi* to single item if appropriate - PG_RETURN_POINTER(result); -} - - -// select symdifference('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))','POLYGON((5 5, 15 5, 15 7, 5 7, 5 5))'); -PG_FUNCTION_INFO_V1(symdifference); -Datum symdifference(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - Geometry *g1,*g2,*g3; - GEOMETRY *result; - - initGEOS(MAXIMUM_ALIGNOF); - - g1 = POSTGIS2GEOS(geom1 ); - g2 = POSTGIS2GEOS(geom2 ); - g3 = GEOSSymDifference(g1,g2); - - if (g3 == NULL) - { - elog(ERROR,"GEOS symdifference() threw an error!"); - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g2); - PG_RETURN_NULL(); //never get here - } - -// elog(NOTICE,"result: %s", GEOSasText(g3) ) ; - - result = GEOS2POSTGIS(g3, geom1->is3d || geom2->is3d); - if (result == NULL) - { - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g2); - GEOSdeleteGeometry(g3); - elog(ERROR,"GEOS symdifference() threw an error (result postgis geometry formation)!"); - PG_RETURN_NULL(); //never get here - } - - - - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g2); - GEOSdeleteGeometry(g3); - - compressType(result); // convert multi* to single item if appropriate - - PG_RETURN_POINTER(result); -} - - -PG_FUNCTION_INFO_V1(boundary); -Datum boundary(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - - Geometry *g1,*g3; - GEOMETRY *result; - initGEOS(MAXIMUM_ALIGNOF); - - g1 = POSTGIS2GEOS(geom1 ); - g3 = GEOSBoundary(g1); - - if (g3 == NULL) - { - elog(ERROR,"GEOS bounary() threw an error!"); - GEOSdeleteGeometry(g1); - PG_RETURN_NULL(); //never get here - } - -// elog(NOTICE,"result: %s", GEOSasText(g3) ) ; - - result = GEOS2POSTGIS(g3, geom1->is3d); - if (result == NULL) - { - GEOSdeleteGeometry(g1); - - GEOSdeleteGeometry(g3); - elog(ERROR,"GEOS bounary() threw an error (result postgis geometry formation)!"); - PG_RETURN_NULL(); //never get here - } - - - - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g3); - - compressType(result); // convert multi* to single item if appropriate - - PG_RETURN_POINTER(result); -} - -PG_FUNCTION_INFO_V1(convexhull); -Datum convexhull(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - Geometry *g1,*g3; - GEOMETRY *result; - - initGEOS(MAXIMUM_ALIGNOF); - - g1 = POSTGIS2GEOS(geom1 ); - g3 = GEOSConvexHull(g1); - - - if (g3 == NULL) - { - elog(ERROR,"GEOS convexhull() threw an error!"); - GEOSdeleteGeometry(g1); - PG_RETURN_NULL(); //never get here - } - - -// elog(NOTICE,"result: %s", GEOSasText(g3) ) ; - - result = GEOS2POSTGIS(g3, geom1->is3d); - if (result == NULL) - { - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g3); - elog(ERROR,"GEOS convexhull() threw an error (result postgis geometry formation)!"); - PG_RETURN_NULL(); //never get here - } - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g3); - - - compressType(result); // convert multi* to single item if appropriate - - PG_RETURN_POINTER(result); - -} - -PG_FUNCTION_INFO_V1(buffer); -Datum buffer(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - double size = PG_GETARG_FLOAT8(1); - Geometry *g1,*g3; - GEOMETRY *result; - - initGEOS(MAXIMUM_ALIGNOF); - - g1 = POSTGIS2GEOS(geom1 ); - g3 = GEOSBuffer(g1,size); - - - if (g3 == NULL) - { - elog(ERROR,"GEOS buffer() threw an error!"); - GEOSdeleteGeometry(g1); - PG_RETURN_NULL(); //never get here - } - - -// elog(NOTICE,"result: %s", GEOSasText(g3) ) ; - - result = GEOS2POSTGIS(g3, geom1->is3d); - if (result == NULL) - { - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g3); - elog(ERROR,"GEOS buffer() threw an error (result postgis geometry formation)!"); - PG_RETURN_NULL(); //never get here - } - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g3); - - - compressType(result); // convert multi* to single item if appropriate - PG_RETURN_POINTER(result); - -} - - -//select intersection('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))','POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))'); -//select intersection('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))','POLYGON((5 5, 15 5, 15 7, 5 7, 5 5))'); -//select intersection('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))','POLYGON((25 5, 35 5, 35 7, 25 7, 25 5))'); -//select intersection('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))','POINT(5 5)'); -//select intersection('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))','LINESTRING(5 5, 10 10)'); -//select intersection('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))','MULTIPOINT(5 5, 7 7, 9 9, 10 10, 11 11)'); -//select intersection('POLYGON(( 0 0, 10 0, 10 10, 0 10, 0 0))','POLYGON((5 5, 15 5, 15 7, 5 7, 5 5 ),(6 6,6.5 6, 6.5 6.5,6 6.5,6 6))'); - - -////select intersection('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))','MULTIPOINT(5 5, 7 7, 9 9, 10 10, 11 11)'); -// select intersection('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))','MULTILINESTRING((5 5, 10 10),(1 1, 2 2) )'); -//select intersection('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))','MULTILINESTRING((5 5, 10 10),(1 1, 2 2) )'); -//select intersection('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))','MULTIPOLYGON(((5 5, 15 5, 15 7, 5 7, 5 5)),((1 1,1 2,2 2,1 2, 1 1)))'); -PG_FUNCTION_INFO_V1(intersection); -Datum intersection(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - Geometry *g1,*g2,*g3; - GEOMETRY *result; - - initGEOS(MAXIMUM_ALIGNOF); - -//elog(NOTICE,"intersection() START"); - - g1 = POSTGIS2GEOS(geom1 ); - g2 = POSTGIS2GEOS(geom2 ); - -//elog(NOTICE," constructed geometrys - calling geos"); - -//elog(NOTICE,"g1 = %s",GEOSasText(g1)); -//elog(NOTICE,"g2 = %s",GEOSasText(g2)); - - -//if (g1==NULL) -// elog(NOTICE,"g1 is null"); -//if (g2==NULL) -// elog(NOTICE,"g2 is null"); -//elog(NOTICE,"g2 is valid = %i",GEOSisvalid(g2)); -//elog(NOTICE,"g1 is valid = %i",GEOSisvalid(g1)); - - - g3 = GEOSIntersection(g1,g2); - -//elog(NOTICE," intersection finished"); - - if (g3 == NULL) - { - elog(ERROR,"GEOS Intersection() threw an error!"); - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g2); - PG_RETURN_NULL(); //never get here - } - - - - -// elog(NOTICE,"result: %s", GEOSasText(g3) ) ; - - result = GEOS2POSTGIS(g3, geom1->is3d || geom2->is3d); - if (result == NULL) - { - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g2); - GEOSdeleteGeometry(g3); - elog(ERROR,"GEOS Intersection() threw an error (result postgis geometry formation)!"); - PG_RETURN_NULL(); //never get here - } - - - - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g2); - GEOSdeleteGeometry(g3); - - compressType(result); // convert multi* to single item if appropriate - - PG_RETURN_POINTER(result); -} - -//select difference('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))','POLYGON((5 5, 15 5, 15 7, 5 7, 5 5))'); -PG_FUNCTION_INFO_V1(difference); -Datum difference(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - Geometry *g1,*g2,*g3; - GEOMETRY *result; - - initGEOS(MAXIMUM_ALIGNOF); - - g1 = POSTGIS2GEOS(geom1 ); - g2 = POSTGIS2GEOS(geom2 ); - g3 = GEOSDifference(g1,g2); - - if (g3 == NULL) - { - elog(ERROR,"GEOS difference() threw an error!"); - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g2); - PG_RETURN_NULL(); //never get here - } - - - - -// elog(NOTICE,"result: %s", GEOSasText(g3) ) ; - - result = GEOS2POSTGIS(g3, geom1->is3d || geom2->is3d); - if (result == NULL) - { - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g2); - GEOSdeleteGeometry(g3); - elog(ERROR,"GEOS difference() threw an error (result postgis geometry formation)!"); - PG_RETURN_NULL(); //never get here - } - - - - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g2); - GEOSdeleteGeometry(g3); - - - compressType(result); // convert multi* to single item if appropriate - - PG_RETURN_POINTER(result); -} - - -//select pointonsurface('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))'); -PG_FUNCTION_INFO_V1(pointonsurface); -Datum pointonsurface(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - - Geometry *g1,*g3; - GEOMETRY *result; - - initGEOS(MAXIMUM_ALIGNOF); - - g1 = POSTGIS2GEOS(geom1 ); - g3 = GEOSpointonSurface(g1); - - if (g3 == NULL) - { - elog(ERROR,"GEOS pointonsurface() threw an error!"); - GEOSdeleteGeometry(g1); - PG_RETURN_NULL(); //never get here - } - - - - -// elog(NOTICE,"result: %s", GEOSasText(g3) ) ; - - result = GEOS2POSTGIS(g3, geom1->is3d); - if (result == NULL) - { - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g3); - elog(ERROR,"GEOS pointonsurface() threw an error (result postgis geometry formation)!"); - PG_RETURN_NULL(); //never get here - } - - - - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g3); - - compressType(result); // convert multi* to single item if appropriate - - PG_RETURN_POINTER(result); -} - -PG_FUNCTION_INFO_V1(centroid); -Datum centroid(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom, *result; - Geometry *geosgeom, *geosresult; - - geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - - initGEOS(MAXIMUM_ALIGNOF); - - geosgeom = POSTGIS2GEOS(geom); - - geosresult = GEOSGetCentroid(geosgeom); - if ( geosresult == NULL ) - { - GEOSdeleteGeometry(geosgeom); - elog(ERROR,"GEOS getCentroid() threw an error!"); - PG_RETURN_NULL(); - } - - result = GEOS2POSTGIS(geosresult, geom->is3d); - if (result == NULL) - { - GEOSdeleteGeometry(geosgeom); - GEOSdeleteGeometry(geosresult); - elog(ERROR,"Error in GEOS-PGIS conversion"); - PG_RETURN_NULL(); - } - GEOSdeleteGeometry(geosgeom); - GEOSdeleteGeometry(geosresult); - - PG_RETURN_POINTER(result); -} - - - -//---------------------------------------------- - - - -void errorIfGeometryCollection(GEOMETRY *g1, GEOMETRY *g2) -{ - if ( (g1->type == COLLECTIONTYPE) || (g2->type == COLLECTIONTYPE) ) - elog(ERROR,"Relate Operation called with a GEOMETRYCOLLECTION type. This is unsupported"); -} - -PG_FUNCTION_INFO_V1(isvalid); -Datum isvalid(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - bool result; - Geometry *g1; - - initGEOS(MAXIMUM_ALIGNOF); - - g1 = POSTGIS2GEOS(geom1 ); - - result = GEOSisvalid(g1); - GEOSdeleteGeometry(g1); - if (result == 2) - { - elog(ERROR,"GEOS isvalid() threw an error!"); - PG_RETURN_NULL(); //never get here - } - - - PG_RETURN_BOOL(result); -} - - -// overlaps(GEOMETRY g1,GEOMETRY g2) -// returns if GEOS::g1->overlaps(g2) returns true -// throws an error (elog(ERROR,...)) if GEOS throws an error -PG_FUNCTION_INFO_V1(overlaps); -Datum overlaps(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - - Geometry *g1,*g2; - bool result; - - errorIfGeometryCollection(geom1,geom2); - initGEOS(MAXIMUM_ALIGNOF); - - g1 = POSTGIS2GEOS(geom1 ); - g2 = POSTGIS2GEOS(geom2 ); - - - - result = GEOSrelateOverlaps(g1,g2); - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g2); - if (result == 2) - { - elog(ERROR,"GEOS overlaps() threw an error!"); - PG_RETURN_NULL(); //never get here - } - - PG_RETURN_BOOL(result); -} - - - -PG_FUNCTION_INFO_V1(contains); -Datum contains(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - Geometry *g1,*g2; - bool result; - //POINT3D *testpoint; - //POLYGON3D *poly; - - errorIfGeometryCollection(geom1,geom2); - - /* - * short-circuit 1: if geom2 bounding box is not completely inside - * geom1 bounding box we can prematurely return FALSE - */ - if ( geom2->bvol.LLB.x < geom1->bvol.LLB.x ) PG_RETURN_BOOL(FALSE); - if ( geom2->bvol.URT.x > geom1->bvol.URT.x ) PG_RETURN_BOOL(FALSE); - if ( geom2->bvol.LLB.y < geom1->bvol.LLB.y ) PG_RETURN_BOOL(FALSE); - if ( geom2->bvol.URT.y > geom1->bvol.URT.y ) PG_RETURN_BOOL(FALSE); - - /* - * short-circuit 2: if geom1 is a polygon and any corner of - * geom2 bounding box is not 'within' geom1 we can prematurely - * return FALSE - */ - //if ( geom1->type == POLYGONTYPE ) - //{ - // poly = (POLYGON3D *)geom1->objData; - // testpoint.x = geom2->bvol.LLB.x; - // testpoint.y = geom2->bvol.LLB.y; - // if ( !point_within_polygon(&testpoint, poly) ) - // PG_RETURN_BOOL(FALSE); - // testpoint.x = geom2->bvol.LLB.x; - // testpoint.y = geom2->bvol.URT.y; - // if ( !point_within_polygon(&testpoint, poly) ) - // PG_RETURN_BOOL(FALSE); - // testpoint.x = geom2->bvol.URT.x; - // testpoint.y = geom2->bvol.URT.y; - // if ( !point_within_polygon(&testpoint, poly) ) - // PG_RETURN_BOOL(FALSE); - // testpoint.x = geom2->bvol.URT.x; - // testpoint.y = geom2->bvol.LLB.y; - // if ( !point_within_polygon(&testpoint, poly) ) - // PG_RETURN_BOOL(FALSE); - //} - - initGEOS(MAXIMUM_ALIGNOF); - - g1 = POSTGIS2GEOS(geom1 ); - g2 = POSTGIS2GEOS(geom2 ); - - - - result = GEOSrelateContains(g1,g2); - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g2); - - if (result == 2) - { - elog(ERROR,"GEOS contains() threw an error!"); - PG_RETURN_NULL(); //never get here - } - - - - PG_RETURN_BOOL(result); -} - - -PG_FUNCTION_INFO_V1(within); -Datum within(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - Geometry *g1,*g2; - bool result; - //POINT3D testpoint; - //POLYGON3D *poly; - - errorIfGeometryCollection(geom1,geom2); - - - /* - * short-circuit 1: if geom1 bounding box is not completely inside - * geom2 bounding box we can prematurely return FALSE - */ - if ( geom1->bvol.LLB.x < geom2->bvol.LLB.x ) PG_RETURN_BOOL(FALSE); - if ( geom1->bvol.URT.x > geom2->bvol.URT.x ) PG_RETURN_BOOL(FALSE); - if ( geom1->bvol.LLB.y < geom2->bvol.LLB.y ) PG_RETURN_BOOL(FALSE); - if ( geom1->bvol.URT.y > geom2->bvol.URT.y ) PG_RETURN_BOOL(FALSE); - -#if 1 - /* - * short-circuit 2: if geom2 is a polygon and any corner of - * geom1 bounding box is not 'within' geom2 we can prematurely - * return FALSE - */ - //if ( geom2->type == POLYGONTYPE ) - //{ - // poly = (POLYGON3D *)geom2->objData; - // testpoint.x = geom1->bvol.LLB.x; - // testpoint.y = geom1->bvol.LLB.y; - // if ( !point_within_polygon(&testpoint, poly) ) - // PG_RETURN_BOOL(FALSE); - // testpoint.x = geom1->bvol.LLB.x; - // testpoint.y = geom1->bvol.URT.y; - // if ( !point_within_polygon(&testpoint, poly) ) - // PG_RETURN_BOOL(FALSE); - // testpoint.x = geom1->bvol.URT.x; - // testpoint.y = geom1->bvol.URT.y; - // if ( !point_within_polygon(&testpoint, poly) ) - // PG_RETURN_BOOL(FALSE); - // testpoint.x = geom1->bvol.URT.x; - // testpoint.y = geom1->bvol.LLB.y; - // if ( !point_within_polygon(&testpoint, poly) ) - // PG_RETURN_BOOL(FALSE); - //} -#endif - - initGEOS(MAXIMUM_ALIGNOF); - g1 = POSTGIS2GEOS(geom1 ); - g2 = POSTGIS2GEOS(geom2 ); - - result = GEOSrelateWithin(g1,g2); - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g2); - - if (result == 2) - { - elog(ERROR,"GEOS within() threw an error!"); - PG_RETURN_NULL(); //never get here - } - - - - PG_RETURN_BOOL(result); -} - - - -PG_FUNCTION_INFO_V1(crosses); -Datum crosses(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - - Geometry *g1,*g2; - bool result; - - errorIfGeometryCollection(geom1,geom2); - initGEOS(MAXIMUM_ALIGNOF); - - g1 = POSTGIS2GEOS(geom1 ); - g2 = POSTGIS2GEOS(geom2 ); - - - - result = GEOSrelateCrosses(g1,g2); - - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g2); - - if (result == 2) - { - elog(ERROR,"GEOS crosses() threw an error!"); - PG_RETURN_NULL(); //never get here - } - - - - PG_RETURN_BOOL(result); -} - - - -PG_FUNCTION_INFO_V1(intersects); -Datum intersects(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - Geometry *g1,*g2; - bool result; - - - - - errorIfGeometryCollection(geom1,geom2); - initGEOS(MAXIMUM_ALIGNOF); - - g1 = POSTGIS2GEOS(geom1 ); - g2 = POSTGIS2GEOS(geom2 ); - - - - result = GEOSrelateIntersects(g1,g2); - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g2); - if (result == 2) - { - elog(ERROR,"GEOS intersects() threw an error!"); - PG_RETURN_NULL(); //never get here - } - - - - PG_RETURN_BOOL(result); -} - - -PG_FUNCTION_INFO_V1(touches); -Datum touches(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - - Geometry *g1,*g2; - bool result; - - errorIfGeometryCollection(geom1,geom2); - initGEOS(MAXIMUM_ALIGNOF); - - g1 = POSTGIS2GEOS(geom1 ); - g2 = POSTGIS2GEOS(geom2 ); - - - - result = GEOSrelateTouches(g1,g2); - - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g2); - - if (result == 2) - { - elog(ERROR,"GEOS touches() threw an error!"); - PG_RETURN_NULL(); //never get here - } - - - - PG_RETURN_BOOL(result); -} - - -PG_FUNCTION_INFO_V1(disjoint); -Datum disjoint(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - - Geometry *g1,*g2; - bool result; - - errorIfGeometryCollection(geom1,geom2); - initGEOS(MAXIMUM_ALIGNOF); - - g1 = POSTGIS2GEOS(geom1 ); - g2 = POSTGIS2GEOS(geom2 ); - - - result = GEOSrelateDisjoint(g1,g2); - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g2); - - if (result == 2) - { - elog(ERROR,"GEOS disjoin() threw an error!"); - PG_RETURN_NULL(); //never get here - } - - PG_RETURN_BOOL(result); -} - - -PG_FUNCTION_INFO_V1(relate_pattern); -Datum relate_pattern(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - char *patt; - bool result; - - Geometry *g1,*g2; - - - errorIfGeometryCollection(geom1,geom2); - initGEOS(MAXIMUM_ALIGNOF); - - g1 = POSTGIS2GEOS(geom1 ); - g2 = POSTGIS2GEOS(geom2 ); - - - patt = DatumGetCString(DirectFunctionCall1(textout, - PointerGetDatum(PG_GETARG_DATUM(2)))); - - result = GEOSrelatePattern(g1,g2,patt); - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g2); - pfree(patt); - - if (result == 2) - { - elog(ERROR,"GEOS relate_pattern() threw an error!"); - PG_RETURN_NULL(); //never get here - } - - PG_RETURN_BOOL(result); - - -} - - - -PG_FUNCTION_INFO_V1(relate_full); -Datum relate_full(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - Geometry *g1,*g2; - char *relate_str; - int len; - char *result; - -//elog(NOTICE,"in relate_full()"); - - errorIfGeometryCollection(geom1,geom2); - - - initGEOS(MAXIMUM_ALIGNOF); - -//elog(NOTICE,"GEOS init()"); - - g1 = POSTGIS2GEOS(geom1 ); - g2 = POSTGIS2GEOS(geom2 ); - -//elog(NOTICE,"constructed geometries "); - - - - - -if ((g1==NULL) || (g2 == NULL)) - elog(NOTICE,"g1 or g2 are null"); - -//elog(NOTICE,GEOSasText(g1)); -//elog(NOTICE,GEOSasText(g2)); - -//elog(NOTICE,"valid g1 = %i", GEOSisvalid(g1)); -//elog(NOTICE,"valid g2 = %i",GEOSisvalid(g2)); - -//elog(NOTICE,"about to relate()"); - - - relate_str = GEOSrelate(g1, g2); - -//elog(NOTICE,"finished relate()"); - - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g2); - - - - if (relate_str == NULL) - { - //free(relate_str); - elog(ERROR,"GEOS relate() threw an error!"); - PG_RETURN_NULL(); //never get here - } - - - len = strlen(relate_str) + 4; - - result= palloc(len); - *((int *) result) = len; - - memcpy(result +4, relate_str, len-4); - - free(relate_str); - - - PG_RETURN_POINTER(result); -} - -//============================== - -PG_FUNCTION_INFO_V1(geomequals); -Datum geomequals(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - - Geometry *g1,*g2; - bool result; - - errorIfGeometryCollection(geom1,geom2); - initGEOS(MAXIMUM_ALIGNOF); - - g1 = POSTGIS2GEOS(geom1 ); - g2 = POSTGIS2GEOS(geom2 ); - - - result = GEOSequals(g1,g2); - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g2); - - if (result == 2) - { - elog(ERROR,"GEOS equals() threw an error!"); - PG_RETURN_NULL(); //never get here - } - - PG_RETURN_BOOL(result); -} - -PG_FUNCTION_INFO_V1(issimple); -Datum issimple(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - - Geometry *g1; - int result; - - if (geom->nobjs == 0) - PG_RETURN_BOOL(true); - - initGEOS(MAXIMUM_ALIGNOF); - - //elog(NOTICE,"GEOS init()"); - - g1 = POSTGIS2GEOS(geom ); - - result = GEOSisSimple(g1); - GEOSdeleteGeometry(g1); - - - if (result == 2) - { - elog(ERROR,"GEOS issimple() threw an error!"); - PG_RETURN_NULL(); //never get here - } - - PG_RETURN_BOOL(result); -} - -PG_FUNCTION_INFO_V1(isring); -Datum isring(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - - Geometry *g1; - int result; - - if (geom->type != LINETYPE) - { - elog(ERROR,"isring() should only be called on a LINE"); - } - - if (geom->nobjs == 0) - PG_RETURN_BOOL(false); - - initGEOS(MAXIMUM_ALIGNOF); - - //elog(NOTICE,"GEOS init()"); - - g1 = POSTGIS2GEOS(geom ); - - result = GEOSisRing(g1); - GEOSdeleteGeometry(g1); - - - if (result == 2) - { - elog(ERROR,"GEOS isring() threw an error!"); - PG_RETURN_NULL(); //never get here - } - - PG_RETURN_BOOL(result); -} - - - -//=================================================== - -POLYGON3D *PolyFromGeometry(Geometry *g, int *size) -{ - - int ninteriorrings; - POINT3D *pts; - int *pts_per_ring; - int t; - POLYGON3D *poly; - int npoints; - - ninteriorrings = GEOSGetNumInteriorRings(g); - - npoints = GEOSGetNumCoordinate(g); - pts = GEOSGetCoordinates(g); - if (npoints <3) - { - GEOSdeleteChar( (char*) pts); - return NULL; - } - - pts_per_ring = palloc(sizeof(int) * (ninteriorrings+1)); - pts_per_ring[0] = GEOSGetNumCoordinate(GEOSGetExteriorRing(g)); - - for (t=0;tpoints[t].x,line->points[t].y,line->points[t].z); -//} - GEOSdeleteChar( (char*) pts); - return line; -} - - - - -GEOMETRY * -GEOS2POSTGIS(Geometry *g,char want3d) -{ - int type = GEOSGeometryTypeId(g) ; - GEOMETRY *result = NULL; - POINT3D *pts; - LINE3D *line; - BOX3D *bbox ; - GEOMETRY *geom, *g2, *r; - POLYGON3D *poly; - GEOMETRY *g_new,*g_old; - int ngeoms,t,size; - - switch (type) - { - /* From slower to faster.. compensation rule :) */ - - case COLLECTIONTYPE: -#ifdef DEBUG_GEOS2POSTGIS - elog(NOTICE, "GEOS2POSTGIS: It's a COLLECTION"); -#endif - //this is more difficult because GEOS allows GCs of GCs - ngeoms = GEOSGetNumGeometries(g); - if (ngeoms ==0) - { - result = makeNullGeometry(GEOSGetSRID(g)); - return result; - } - if (ngeoms == 1) - { - return GEOS2POSTGIS(GEOSGetGeometryN(g,0), - want3d); // short cut! - } - geom = GEOS2POSTGIS(GEOSGetGeometryN(g,0) , want3d); - for (t=1;ttype = MULTIPOLYGONTYPE; - return result; - } - for (t=0;tbvol, bbox, sizeof(BOX3D) ); - // free bounding box - pfree( bbox ); - return result; - - case MULTILINETYPE: -#ifdef DEBUG_GEOS2POSTGIS - elog(NOTICE, "GEOS2POSTGIS: It's a MULTILINE"); -#endif - ngeoms = GEOSGetNumGeometries(g); - if (ngeoms ==0) - { - result = makeNullGeometry(GEOSGetSRID(g)); - result->type = MULTILINETYPE; - return result; - } - - line = LineFromGeometry(GEOSGetGeometryN(g,0), &size); - result = make_oneobj_geometry(size, (char *)line, - MULTILINETYPE, want3d, - GEOSGetSRID(g),1.0, 0.0, 0.0); -#ifdef DEBUG_GEOS2POSTGIS - elog(NOTICE,"GEOS2POSTGIS: t0: %s",geometry_to_text(result)); - elog(NOTICE," size = %i", result->size); -#endif - - for (t=1;tsize); -#endif - pfree(g_old); - } - bbox = bbox_of_geometry( result ); // make bounding box - memcpy( &result->bvol, bbox, sizeof(BOX3D) ); // copy bounding box - pfree( bbox ); // free bounding box -#ifdef DEBUG_GEOS2POSTGIS - elog(NOTICE,"GEOS2POSTGIS: end: %s",geometry_to_text(result)); - elog(NOTICE," size = %i", result->size); -#endif - - return result; - - case MULTIPOINTTYPE: -#ifdef DEBUG_GEOS2POSTGIS - elog(NOTICE, "GEOS2POSTGIS: It's a MULTIPOINT"); -#endif - g_new = NULL; - ngeoms = GEOSGetNumGeometries(g); - if (ngeoms ==0) - { - result = makeNullGeometry(GEOSGetSRID(g)); - result->type = MULTIPOINTTYPE; - return result; - } - pts = GEOSGetCoordinates(g); - g_old = make_oneobj_geometry(sizeof(POINT3D), - (char *) pts, MULTIPOINTTYPE, want3d, - GEOSGetSRID(g),1.0, 0.0, 0.0); - for (t=1;tbvol, bbox, sizeof(BOX3D) ); - // free bounding box - pfree( bbox ); - return g_new; - - case POLYGONTYPE: -#ifdef DEBUG_GEOS2POSTGIS - elog(NOTICE, "GEOS2POSTGIS: It's a POLYGON"); -#endif - poly = PolyFromGeometry(g,&size); - if (poly == NULL) return NULL; - result = make_oneobj_geometry(size, - (char *) poly, POLYGONTYPE, want3d, - GEOSGetSRID(g),1.0, 0.0, 0.0); - return result; - - case LINETYPE: -#ifdef DEBUG_GEOS2POSTGIS - elog(NOTICE, "GEOS2POSTGIS: It's a LINE"); -#endif - line = LineFromGeometry(g,&size); - if (line == NULL) return NULL; - result = make_oneobj_geometry(size, - (char *) line, LINETYPE, want3d, - GEOSGetSRID(g),1.0, 0.0, 0.0); - return result; - - case POINTTYPE: -#ifdef DEBUG_GEOS2POSTGIS - elog(NOTICE, "GEOS2POSTGIS: It's a POINT"); -#endif - pts = GEOSGetCoordinate(g); - result = make_oneobj_geometry(sizeof(POINT3D), - (char *) pts, POINTTYPE, want3d, - GEOSGetSRID(g), 1.0, 0.0, 0.0); - GEOSdeleteChar( (char*) pts); - return result; - - default: -#ifdef DEBUG_GEOS2POSTGIS - elog(NOTICE, "GEOS2POSTGIS: It's UNKNOWN!"); -#endif - return NULL; - - } -} - - - -//BBOXONLYTYPE -> returns as a 2d polygon -Geometry * -POSTGIS2GEOS(GEOMETRY *g) -{ - POINT3D *pt; - LINE3D *line; - POLYGON3D *poly; - POLYGON3D **polys; - LINE3D **lines; - POINT3D **points; - Geometry **geoms; - Geometry *geos; - char *obj; - int obj_type; - int t; - Geometry *result; - - int32 *offsets1 = (int32 *) ( ((char *) &(g->objType[0] ))+ sizeof(int32) * g->nobjs ) ; - - switch(g->type) - { - case POINTTYPE: -#ifdef DEBUG_POSTGIS2GEOS - elog(NOTICE, "POSTGIS2GEOS: it's a POINT"); -#endif - pt = (POINT3D*) ((char *) g +offsets1[0]) ; - result = PostGIS2GEOS_point(pt,g->SRID,g->is3d); - if (result == NULL) - { - elog(ERROR,"Couldnt convert the postgis geometry to GEOS!"); - } - return result; - break; - - case LINETYPE: -#ifdef DEBUG_POSTGIS2GEOS - elog(NOTICE, "POSTGIS2GEOS: it's a LINE"); -#endif - line = (LINE3D*) ((char *) g +offsets1[0]) ; - result = PostGIS2GEOS_linestring(line,g->SRID,g->is3d); - if (result == NULL) - { - elog(ERROR,"Couldnt convert the postgis geometry to GEOS!"); - } - return result; - break; - - case POLYGONTYPE: -#ifdef DEBUG_POSTGIS2GEOS - elog(NOTICE, "POSTGIS2GEOS: it's a POLYGON"); -#endif - poly = (POLYGON3D*) ((char *) g +offsets1[0]) ; - result = PostGIS2GEOS_polygon(poly,g->SRID,g->is3d); - if (result == NULL) - { - elog(ERROR,"Couldnt convert the postgis geometry to GEOS!"); - } - return result; - break; - - case MULTIPOLYGONTYPE: -#ifdef DEBUG_POSTGIS2GEOS - elog(NOTICE, "POSTGIS2GEOS: it's a MULTIPOLYGON"); -#endif - //make an array of POLYGON3Ds - polys = NULL; - if (g->nobjs >0) - polys = (POLYGON3D**) palloc(sizeof (POLYGON3D*) * g->nobjs); - for (t=0;tnobjs;t++) - { - polys[t] = (POLYGON3D*) ((char *) g +offsets1[t]) ; - } - geos= PostGIS2GEOS_multipolygon(polys, g->nobjs, g->SRID,g->is3d); - if (polys != NULL) pfree(polys); - if (geos == NULL) - { - elog(ERROR,"Couldnt convert the postgis geometry to GEOS!"); - } - return geos; - break; - - case MULTILINETYPE: -#ifdef DEBUG_POSTGIS2GEOS - elog(NOTICE, "POSTGIS2GEOS: it's a MULTILINE"); -#endif - //make an array of LINES3D - lines = NULL; - if (g->nobjs >0) - lines = (LINE3D**) palloc(sizeof (LINE3D*) * g->nobjs); - for (t=0;tnobjs;t++) - { -#ifdef DEBUG_POSTGIS2GEOS - elog(NOTICE, "Line %d has offset %d", t, offsets1[t]); -#endif - lines[t] = (LINE3D*) ((char *)g+offsets1[t]) ; - } - geos= PostGIS2GEOS_multilinestring(lines, g->nobjs, g->SRID,g->is3d); - if (lines != NULL) pfree(lines); - if (geos == NULL) - { - elog(ERROR,"Couldnt convert the postgis geometry to GEOS!"); - } - return geos; - break; - - case MULTIPOINTTYPE: -#ifdef DEBUG_POSTGIS2GEOS - elog(NOTICE, "POSTGIS2GEOS: it's a MULTIPOINT"); -#endif - //make an array of POINT3Ds - points = NULL; - if (g->nobjs >0) - points = (POINT3D**) palloc(sizeof (POINT3D*) * g->nobjs); - for (t=0;tnobjs;t++) - { - points[t] = (POINT3D*) ((char *) g +offsets1[t]) ; - } - geos= PostGIS2GEOS_multipoint(points, g->nobjs,g->SRID,g->is3d); - if (points != NULL) pfree(points); - if (geos == NULL) - { - elog(ERROR,"Couldnt convert the postgis geometry to GEOS!"); - } - return geos; - break; - - case BBOXONLYTYPE: -#ifdef DEBUG_POSTGIS2GEOS - elog(NOTICE, "POSTGIS2GEOS: it's a BBOXONLY"); -#endif - result = PostGIS2GEOS_box3d(&g->bvol, g->SRID); - if (result == NULL) - { - elog(ERROR,"Couldnt convert the postgis geometry to GEOS!"); - } - return result; - break; - - case COLLECTIONTYPE: -#ifdef DEBUG_POSTGIS2GEOS - elog(NOTICE, "POSTGIS2GEOS: it's a COLLECTION"); -#endif - //make an array of GEOS Geometries - geoms = NULL; - if (g->nobjs >0) - geoms = (Geometry**) palloc(sizeof (Geometry*) * g->nobjs); - for (t=0;tnobjs;t++) - { - obj = ((char *) g +offsets1[t]); - obj_type = g->objType[t]; - switch (obj_type) - { - case POINTTYPE: - pt = (POINT3D*) obj ; - geoms[t] = PostGIS2GEOS_point(pt,g->SRID,g->is3d); - if (geoms[t] == NULL) - { - pfree(geoms); - elog(ERROR,"Couldnt convert the postgis geometry to GEOS!"); - return NULL; - } - break; - case LINETYPE: - line = (LINE3D*) obj ; - geoms[t] = PostGIS2GEOS_linestring(line,g->SRID,g->is3d); - if (geoms[t] == NULL) - { - pfree(geoms); - elog(ERROR,"Couldnt convert the postgis geometry to GEOS!"); - return NULL; - } - break; - case POLYGONTYPE: - poly = (POLYGON3D*) obj ; - geoms[t] = PostGIS2GEOS_polygon(poly,g->SRID,g->is3d); - if (geoms[t] == NULL) - { - pfree(geoms); - elog(ERROR,"Couldnt convert the postgis geometry to GEOS!"); - return NULL; - } - break; - } - } -#ifdef DEBUG_POSTGIS2GEOS - elog(NOTICE, "POSTGIS2GEOS: COLLECTION has %d objs, srid %d and is %s 3d", g->nobjs, g->SRID, g->is3d ? "" : "not"); -#endif - geos = PostGIS2GEOS_collection(geoms,g->nobjs,g->SRID,g->is3d); - if (geoms != NULL) pfree(geoms); - if (geos == NULL) - { - elog(ERROR,"Couldnt convert the postgis geometry to GEOS!"); - } - return geos; - break; - - } - return NULL; -} - -PG_FUNCTION_INFO_V1(GEOSnoop); -Datum GEOSnoop(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom; - Geometry *geosgeom; - GEOMETRY *result; - - initGEOS(MAXIMUM_ALIGNOF); - - geom = (GEOMETRY *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); -#ifdef DEBUG_CONVERTER - elog(NOTICE, "GEOSnoop: IN: %s", geometry_to_text(geom)); -#endif - - geosgeom = POSTGIS2GEOS(geom); - if ( (Pointer *)geom != (Pointer *)PG_GETARG_DATUM(0) ) pfree(geom); - - result = GEOS2POSTGIS(geosgeom, geom->is3d); - GEOSdeleteGeometry(geosgeom); - -#ifdef DEBUG_CONVERTER - elog(NOTICE, "GEOSnoop: OUT: %s", geometry_to_text(result)); -#endif - - PG_RETURN_POINTER(result); -} - -PG_FUNCTION_INFO_V1(postgis_geos_version); -Datum postgis_geos_version(PG_FUNCTION_ARGS) -{ - char *ver = GEOSversion(); - text *result; - result = (text *) palloc(VARHDRSZ + strlen(ver)); - VARATT_SIZEP(result) = VARHDRSZ + strlen(ver) ; - memcpy(VARDATA(result), ver, strlen(ver)); - free(ver); - PG_RETURN_POINTER(result); -} - -//---------------------------------------------------------------------------- -// NULL implementation here -// --------------------------------------------------------------------------- -#else // ndef USE_GEOS - - -#include "postgres.h" - - -#include -#include -#include -#include -#include - -#include "fmgr.h" - - -Datum relate_full(PG_FUNCTION_ARGS); -Datum relate_pattern(PG_FUNCTION_ARGS); -Datum disjoint(PG_FUNCTION_ARGS); -Datum touches(PG_FUNCTION_ARGS); -Datum intersects(PG_FUNCTION_ARGS); -Datum crosses(PG_FUNCTION_ARGS); -Datum within(PG_FUNCTION_ARGS); -Datum contains(PG_FUNCTION_ARGS); -Datum overlaps(PG_FUNCTION_ARGS); -Datum isvalid(PG_FUNCTION_ARGS); - - -Datum buffer(PG_FUNCTION_ARGS); -Datum intersection(PG_FUNCTION_ARGS); -Datum convexhull(PG_FUNCTION_ARGS); -Datum difference(PG_FUNCTION_ARGS); -Datum boundary(PG_FUNCTION_ARGS); -Datum symdifference(PG_FUNCTION_ARGS); -Datum geomunion(PG_FUNCTION_ARGS); - -PG_FUNCTION_INFO_V1(intersection); -Datum intersection(PG_FUNCTION_ARGS) -{ - elog(ERROR,"intersection:: operation not implemented - compile PostGIS with GEOS support"); - PG_RETURN_NULL(); // never get here -} -PG_FUNCTION_INFO_V1(convexhull); -Datum convexhull(PG_FUNCTION_ARGS) -{ - elog(ERROR,"convexhull:: operation not implemented - compile PostGIS with GEOS support"); - PG_RETURN_NULL(); // never get here -} -PG_FUNCTION_INFO_V1(difference); -Datum difference(PG_FUNCTION_ARGS) -{ - elog(ERROR,"difference:: operation not implemented - compile PostGIS with GEOS support"); - PG_RETURN_NULL(); // never get here -} -PG_FUNCTION_INFO_V1(boundary); -Datum boundary(PG_FUNCTION_ARGS) -{ - elog(ERROR,"boundary:: operation not implemented - compile PostGIS with GEOS support"); - PG_RETURN_NULL(); // never get here -} -PG_FUNCTION_INFO_V1(symdifference); -Datum symdifference(PG_FUNCTION_ARGS) -{ - elog(ERROR,"symdifference:: operation not implemented - compile PostGIS with GEOS support"); - PG_RETURN_NULL(); // never get here -} -PG_FUNCTION_INFO_V1(geomunion); -Datum geomunion(PG_FUNCTION_ARGS) -{ - elog(ERROR,"geomunion:: operation not implemented - compile PostGIS with GEOS support"); - PG_RETURN_NULL(); // never get here -} - -PG_FUNCTION_INFO_V1(buffer); -Datum buffer(PG_FUNCTION_ARGS) -{ - elog(ERROR,"buffer:: operation not implemented - compile PostGIS with GEOS support"); - PG_RETURN_NULL(); // never get here -} - - - -PG_FUNCTION_INFO_V1(relate_full); -Datum relate_full(PG_FUNCTION_ARGS) -{ - elog(ERROR,"relate_full:: operation not implemented - compile PostGIS with GEOS support"); - PG_RETURN_NULL(); // never get here -} -PG_FUNCTION_INFO_V1(relate_pattern); -Datum relate_pattern(PG_FUNCTION_ARGS) -{ - elog(ERROR,"relate_pattern:: operation not implemented - compile PostGIS with GEOS support"); - PG_RETURN_NULL(); // never get here -} -PG_FUNCTION_INFO_V1(disjoint); -Datum disjoint(PG_FUNCTION_ARGS) -{ - elog(ERROR,"disjoint:: operation not implemented - compile PostGIS with GEOS support"); - PG_RETURN_NULL(); // never get here -} -PG_FUNCTION_INFO_V1(intersects); -Datum intersects(PG_FUNCTION_ARGS) -{ - elog(ERROR,"intersects:: operation not implemented - compile PostGIS with GEOS support"); - PG_RETURN_NULL(); // never get here -} -PG_FUNCTION_INFO_V1(touches); -Datum touches(PG_FUNCTION_ARGS) -{ - elog(ERROR,"touches:: operation not implemented - compile PostGIS with GEOS support"); - PG_RETURN_NULL(); // never get here -} -PG_FUNCTION_INFO_V1(crosses); -Datum crosses(PG_FUNCTION_ARGS) -{ - elog(ERROR,"crosses:: operation not implemented - compile PostGIS with GEOS support"); - PG_RETURN_NULL(); // never get here -} -PG_FUNCTION_INFO_V1(within); -Datum within(PG_FUNCTION_ARGS) -{ - elog(ERROR,"within:: operation not implemented - compile PostGIS with GEOS support"); - PG_RETURN_NULL(); // never get here -} -PG_FUNCTION_INFO_V1(contains); -Datum contains(PG_FUNCTION_ARGS) -{ - elog(ERROR,"contains:: operation not implemented - compile PostGIS with GEOS support"); - PG_RETURN_NULL(); // never get here -} -PG_FUNCTION_INFO_V1(overlaps); -Datum overlaps(PG_FUNCTION_ARGS) -{ - elog(ERROR,"overlaps:: operation not implemented - compile PostGIS with GEOS support"); - PG_RETURN_NULL(); // never get here -} -PG_FUNCTION_INFO_V1(isvalid); -Datum isvalid(PG_FUNCTION_ARGS) -{ - elog(ERROR,"isvalid:: operation not implemented - compile PostGIS with GEOS support"); - PG_RETURN_NULL(); // never get here -} - -PG_FUNCTION_INFO_V1(issimple); -Datum issimple(PG_FUNCTION_ARGS) -{ - elog(ERROR,"issimple:: operation not implemented - compile PostGIS with GEOS support"); - PG_RETURN_NULL(); // never get here -} -PG_FUNCTION_INFO_V1(geomequals); -Datum geomequals(PG_FUNCTION_ARGS) -{ - elog(ERROR,"geomequals:: operation not implemented - compile PostGIS with GEOS support"); - PG_RETURN_NULL(); // never get here -} -PG_FUNCTION_INFO_V1(isring); -Datum isring(PG_FUNCTION_ARGS) -{ - elog(ERROR,"isring:: operation not implemented - compile PostGIS with GEOS support"); - PG_RETURN_NULL(); // never get here -} - -PG_FUNCTION_INFO_V1(pointonsurface); -Datum pointonsurface(PG_FUNCTION_ARGS) -{ - elog(ERROR,"pointonsurface:: operation not implemented - compile PostGIS with GEOS support"); - PG_RETURN_NULL(); // never get here -} - -PG_FUNCTION_INFO_V1(unite_garray); -Datum unite_garray(PG_FUNCTION_ARGS) -{ - elog(ERROR,"unite_garray:: operation not implemented - compile PostGIS with GEOS support"); - PG_RETURN_NULL(); // never get here -} - -PG_FUNCTION_INFO_V1(GEOSnoop); -Datum GEOSnoop(PG_FUNCTION_ARGS) -{ - elog(ERROR,"GEOSnoop:: operation not implemented - compile PostGIS with GEOS support"); - PG_RETURN_NULL(); -} - -PG_FUNCTION_INFO_V1(postgis_geos_version); -Datum postgis_geos_version(PG_FUNCTION_ARGS) -{ - //elog(ERROR,"GEOSversion:: operation not implemented - compile PostGIS with GEOS support"); - PG_RETURN_NULL(); -} - -#endif - diff --git a/hwgeom/postgis_geos_wrapper.cpp b/hwgeom/postgis_geos_wrapper.cpp deleted file mode 100644 index 49e35584e..000000000 --- a/hwgeom/postgis_geos_wrapper.cpp +++ /dev/null @@ -1,1551 +0,0 @@ -// g++ postgis_GEOSwrapper.cpp -c -I/usr/local/include -I/usr/local/include/geos -I/usr/local/src/postgresql-7.2.3//src/include - -/* -* $Log$ -* Revision 1.1 2004/09/20 07:50:06 strk -* prepared to contain old internal representation code -* -* Revision 1.27 2004/07/22 16:58:08 strk -* Updated to reflect geos version string split. -* -* Revision 1.26 2004/07/22 16:20:10 strk -* Added postgis_lib_version() and postgis_geos_version() -* -* Revision 1.25 2004/07/17 09:52:48 strk -* GEOS multi-version support switches implemented with GEOS_LAST_INTERFACE -* -* Revision 1.24 2004/07/08 19:33:51 strk -* Updated to respect CoordinateSequence GEOS interface switch. -* -* Revision 1.23 2004/07/02 13:33:23 strk -* Changed GEOS header inclusion mechanism to be more polite -* -* Revision 1.22 2004/07/01 17:02:26 strk -* Updated to support latest GEOS API. -* -* Revision 1.21 2004/06/16 19:59:36 strk -* Changed GEOS_VERSION to POSTGIS_GEOS_VERSION to avoid future clashes -* -* Revision 1.20 2004/06/16 19:37:54 strk -* Added cleanup needed for GEOS > 1.0 -* -* Revision 1.19 2004/06/16 18:47:59 strk -* Added code to detect geos version. -* Added appropriate includes in geos connectors. -* -* Revision 1.18 2004/04/27 07:44:26 strk -* Removed use of geometryFactory->toGeometry(), indicated by Martin Davis -* as being intended for internal use only. Created a linear ring instead -* (the function converts a box3d to a geos geometry). -* -* Revision 1.17 2003/12/12 13:34:20 strk -* added missing 'const' in prototypes -* -* Revision 1.16 2003/12/12 12:03:30 strk -* More debugging output, some code cleanup. -* -* Revision 1.15 2003/11/12 16:36:04 strk -* delete all caught exceptions after use -* -* Revision 1.14 2003/10/29 13:58:28 strk -* Added GEOSGetCentroid() function -* -* Revision 1.13 2003/10/24 21:33:21 strk -* Added GEOSGeometryTypeId(Geometry *) wrapper function. -* Added GEOSGetCoordinates_Polygon(Polygon *) as an experimental optimized -* version of GEOSGetCoordinates(Geometry *); More to add ... -* -* Revision 1.12 2003/10/24 14:29:53 strk -* GEOSGetCoordinates() reverted to getCoordinates() call so to be compatible -* to all type of geometries (not only LineStrings) -* -* Revision 1.11 2003/10/24 08:28:50 strk -* Fixed memory leak in GEOSGetCoordinates(), made sure that GEOS2POSTGIS -* free type string even in case of collapsed geoms. Made sure that geomunion -* release memory in case of exception thrown by GEOSUnion. Sooner release -* of palloced memory in PolyFromGeometry (pts_per_ring). -* -* Revision 1.10 2003/10/20 19:50:49 strk -* Removed some memory leaks in PostGIS2* converters. -* -*/ - - -#include - -#include -#include -#include - -#include "postgis_geos_version.h" -#include "geos/geom.h" -#include "geos/util.h" - -using namespace geos; - -//WARNING THIS *MUST* BE SET CORRECTLY. -int MAXIMUM_ALIGNOF = -999999; // to be set during initialization - this will be either 4 (intel) or 8 (sparc) - -//for getting things to align properly double are on 8byte align on solaris machines, and 4bytes on intel - -#define TYPEALIGN(ALIGNVAL,LEN) (((long)(LEN) + (ALIGNVAL-1)) & ~(ALIGNVAL-1)) -#define MAXALIGN(LEN) TYPEALIGN(MAXIMUM_ALIGNOF, (LEN)) - -typedef int int32; - -typedef struct -{ - double x,y,z; //for lat/long x=long, y=lat -} POINT3D; - -typedef struct -{ - POINT3D LLB,URT; /* corner POINT3Ds on long diagonal */ -} BOX3D; - -typedef struct -{ - int32 npoints; // how many points in the line - int32 junk; // double-word alignment - POINT3D points[1]; // array of actual points -} LINE3D; - - -typedef struct -{ - int32 nrings; // how many rings in this polygon - int32 npoints[1]; //how many points in each ring - /* could be 4 byes of filler here to make sure points[] is - double-word aligned*/ - POINT3D points[1]; // array of actual points -} POLYGON3D; - - -#define POINTTYPE 1 -#define LINETYPE 2 -#define POLYGONTYPE 3 -#define MULTIPOINTTYPE 4 -#define MULTILINETYPE 5 -#define MULTIPOLYGONTYPE 6 -#define COLLECTIONTYPE 7 - -//########################################################### - -extern "C" char *GEOSrelate(Geometry *g1, Geometry*g2); -extern "C" void initGEOS(int maxalign); - - -extern "C" void GEOSdeleteChar(char *a); -extern "C" void GEOSdeleteGeometry(Geometry *a); -extern "C" char GEOSrelatePattern(Geometry *g1, Geometry*g2,char *pat); -extern "C" char GEOSrelateDisjoint(Geometry *g1, Geometry*g2); -extern "C" char GEOSrelateTouches(Geometry *g1, Geometry*g2); -extern "C" char GEOSrelateIntersects(Geometry *g1, Geometry*g2); -extern "C" char GEOSrelateCrosses(Geometry *g1, Geometry*g2); -extern "C" char GEOSrelateWithin(Geometry *g1, Geometry*g2); -extern "C" char GEOSrelateContains(Geometry *g1, Geometry*g2); -extern "C" char GEOSrelateOverlaps(Geometry *g1, Geometry*g2); -extern "C" char *GEOSversion(); -extern "C" char *GEOSjtsport(); - -extern "C" Geometry *PostGIS2GEOS_point(POINT3D *point,int SRID, bool is3d); -extern "C" Geometry *PostGIS2GEOS_linestring(const LINE3D *line,int SRID, bool is3d); -extern "C" Geometry *PostGIS2GEOS_polygon(POLYGON3D *polygon,int SRID, bool is3d); -extern "C" Geometry *PostGIS2GEOS_multipolygon(POLYGON3D **polygons,int npolys, int SRID, bool is3d); -extern "C" Geometry *PostGIS2GEOS_multilinestring(const LINE3D **lines,int nlines, int SRID, bool is3d); -extern "C" Geometry *PostGIS2GEOS_multipoint(POINT3D **points,int npoints, int SRID, bool is3d); - -extern "C" Geometry *PostGIS2GEOS_box3d(BOX3D *box, int SRID); -extern "C" Geometry *PostGIS2GEOS_collection(Geometry **geoms, int ngeoms,int SRID, bool is3d); - -extern "C" char GEOSisvalid(Geometry *g1); - - -extern "C" char *GEOSasText(Geometry *g1); -extern "C" char GEOSisEmpty(Geometry *g1); -extern "C" char *GEOSGeometryType(Geometry *g1); -extern "C" int GEOSGeometryTypeId(Geometry *g1); - - -extern "C" char *throw_exception(Geometry *g); - -extern "C" Geometry *GEOSIntersection(Geometry *g1,Geometry *g1); -extern "C" Geometry *GEOSBuffer(Geometry *g1,double width); -extern "C" Geometry *GEOSConvexHull(Geometry *g1); -extern "C" Geometry *GEOSDifference(Geometry *g1,Geometry *g2); -extern "C" Geometry *GEOSBoundary(Geometry *g1); -extern "C" Geometry *GEOSSymDifference(Geometry *g1,Geometry *g2); -extern "C" Geometry *GEOSUnion(Geometry *g1,Geometry *g2); - - -extern "C" POINT3D *GEOSGetCoordinate(Geometry *g1); -extern "C" POINT3D *GEOSGetCoordinates_Polygon(Polygon *g1); -extern "C" POINT3D *GEOSGetCoordinates(Geometry *g1); -extern "C" int GEOSGetNumCoordinate(Geometry *g1); -extern "C" const Geometry *GEOSGetGeometryN(Geometry *g1, int n); -extern "C" const Geometry *GEOSGetExteriorRing(Geometry *g1); -extern "C" const Geometry *GEOSGetInteriorRingN(Geometry *g1, int n); -extern "C" int GEOSGetNumInteriorRings(Geometry *g1); -extern "C" int GEOSGetSRID(Geometry *g1); -extern "C" int GEOSGetNumGeometries(Geometry *g1); - -extern "C" char GEOSisSimple(Geometry *g1); -extern "C" char GEOSequals(Geometry *g1, Geometry*g2); - -extern "C" char GEOSisRing(Geometry *g1); - -extern "C" Geometry *GEOSpointonSurface(Geometry *g1); - -extern "C" Geometry *GEOSGetCentroid(Geometry *g1); - -extern "C" void NOTICE_MESSAGE(char *msg); - - - -//########################################################### -#if GEOS_LAST_INTERFACE < 2 -# define CoordinateSequence CoordinateList -# define DefaultCoordinateSequence BasicCoordinateList -#endif - -GeometryFactory *geomFactory = NULL; - - -void initGEOS (int maxalign) -{ - if (geomFactory == NULL) - { - geomFactory = new GeometryFactory( new PrecisionModel(), -1); // NOTE: SRID will have to be changed after geometry creation - MAXIMUM_ALIGNOF = maxalign; - } -} - -// ------------------------------------------------------------------------------ -// geometry constuctors - return NULL if there was an error -//------------------------------------------------------------------------------- - - - - //note: you lose the 3d from this! -Geometry *PostGIS2GEOS_box3d(BOX3D *box, int SRID) -{ - DefaultCoordinateSequence *cl = new DefaultCoordinateSequence(5); - try { - Geometry *g; - Coordinate c; - c.x = box->LLB.x; c.y = box->LLB.y; - cl->setAt(c, 0); - c.x = box->LLB.x; c.y = box->URT.y; - cl->setAt(c, 1); - c.x = box->URT.x; c.y = box->URT.y; - cl->setAt(c, 2); - c.x = box->URT.x; c.y = box->LLB.y; - cl->setAt(c, 3); - c.x = box->LLB.x; c.y = box->LLB.y; - cl->setAt(c, 4); - - g = geomFactory->createLinearRing(cl); -#if GEOS_LAST_INTERFACE < 2 - delete cl; -#endif - if (g==NULL) return NULL; - g->setSRID(SRID); - return g; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete cl; - return NULL; - } - catch (...) - { - delete cl; - return NULL; - } -} - -Geometry *PostGIS2GEOS_collection(Geometry **geoms, int ngeoms,int SRID, bool is3d) -{ - try - { - Geometry *g; - int t; - vector *subGeos=new vector; - - for (t =0; t< ngeoms; t++) - { - subGeos->push_back(geoms[t]); - } - g = geomFactory->buildGeometry(subGeos); -#if GEOS_LAST_INTERFACE < 2 - delete subGeos; -#endif - if (g==NULL) - return NULL; - g->setSRID(SRID); - return g; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return NULL; - } - - catch (...) - { - return NULL; - } -} - -Geometry *PostGIS2GEOS_point(POINT3D *point,int SRID, bool is3d) -{ - try - { - Coordinate *c; - - if (is3d) - c = new Coordinate(point->x, point->y); - else - c = new Coordinate(point->x, point->y, point->z); - Geometry *g = geomFactory->createPoint(*c); - delete c; - if (g==NULL) - return NULL; - g->setSRID(SRID); - return g; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return NULL; - } - - catch (...) - { - return NULL; - } -} - - -/* - * This function must return an all-new allocated object - */ -Geometry * -PostGIS2GEOS_linestring(const LINE3D *line,int SRID, bool is3d) -{ - try{ - int t; - Coordinate c; - - //build coordinatelist & pre-allocate space - DefaultCoordinateSequence *coords = new DefaultCoordinateSequence(line->npoints); - if (is3d) - { - for (t=0;tnpoints;t++) - { - c.x = line->points[t].x; - c.y = line->points[t].y; - c.z = line->points[t].z; - coords->setAt( c ,t); - } - } - else //make 2d points - { - for (t=0;tnpoints;t++) - { - c.x = line->points[t].x; - c.y = line->points[t].y; - c.z = DoubleNotANumber; - coords->setAt( c ,t); - } - } - Geometry *g = geomFactory->createLineString(coords); -#if GEOS_LAST_INTERFACE < 2 - delete coords; -#endif - if (g==NULL) return NULL; - g->setSRID(SRID); - return g; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return NULL; - } - - catch (...) - { - return NULL; - } -} - -//polygons is an array of pointers to polygons -Geometry *PostGIS2GEOS_multipolygon(POLYGON3D **polygons,int npolys, int SRID, bool is3d) -{ - try - { - int t; - vector *subPolys=NULL; - Geometry *g; - - subPolys=new vector; - - for (t =0; t< npolys; t++) - { - subPolys->push_back(PostGIS2GEOS_polygon(polygons[t], SRID,is3d )); - } - g = geomFactory->createMultiPolygon(subPolys); -#if GEOS_LAST_INTERFACE < 2 - delete subPolys; -#endif - - if (g== NULL) - return NULL; - g->setSRID(SRID); - return g; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return NULL; - } - - catch (...) - { - return NULL; - } -} - -//lines is an array of pointers to line3d -Geometry * -PostGIS2GEOS_multilinestring(const LINE3D **lines, int nlines, int SRID, bool is3d) -{ - try - { - int t; - vector *subLines = new vector; - Geometry *g; - - for (t =0; t< nlines; t++) - { - subLines->push_back(PostGIS2GEOS_linestring(lines[t], - SRID,is3d )); - } - g = geomFactory->createMultiLineString(subLines); -#if GEOS_LAST_INTERFACE < 2 - delete subLines; -#endif - if (g==NULL) return NULL; - g->setSRID(SRID); - return g; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return NULL; - } - catch (...) - { - return NULL; - } -} - -Geometry *PostGIS2GEOS_multipoint(POINT3D **points,int npoints, int SRID, bool is3d) -{ - try - { - int t; - vector *subPoints =new vector; - Geometry *g; - - for (t =0; t< npoints; t++) - { - subPoints->push_back(PostGIS2GEOS_point(points[t], SRID,is3d )); - } - g = geomFactory->createMultiPoint(subPoints); -#if GEOS_LAST_INTERFACE < 2 - delete subPoints; -#endif - if (g==NULL) - return NULL; - g->setSRID(SRID); - return g; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return NULL; - } - - catch (...) - { - return NULL; - } - -} - - -Geometry *PostGIS2GEOS_polygon(POLYGON3D *polygon,int SRID, bool is3d) -{ - try - { - POINT3D *pts; - Coordinate c; - int ring,t; - Geometry *g; - LinearRing *outerRing; - LinearRing *innerRing; - DefaultCoordinateSequence *cl; - int pointOffset =0; // first point that we're looking at. a POLYGON3D has all its points smooshed together - vector *innerRings=new vector; - - - pts = (POINT3D *) ( (char *)&(polygon->npoints[polygon->nrings] ) ); - pts = (POINT3D *) MAXALIGN(pts); - - // make outerRing - cl = new DefaultCoordinateSequence(polygon->npoints[0]); - if (is3d) - { - for(t=0;tnpoints[0];t++) - { - c.x = pts[t].x; - c.y = pts[t].y; - c.z = pts[t].z; - cl->setAt( c ,t); - } - } - else - { - for(t=0;tnpoints[0];t++) - { - c.x = pts[t].x; - c.y = pts[t].y; - c.z = DoubleNotANumber; - cl->setAt( c ,t); - } - } - outerRing = (LinearRing*) geomFactory->createLinearRing(cl); -#if GEOS_LAST_INTERFACE < 2 - delete cl; -#endif - if (outerRing == NULL) - return NULL; - outerRing->setSRID(SRID); - pointOffset = polygon->npoints[0]; - - for(ring =1; ring< polygon->nrings; ring++) - { - cl = new DefaultCoordinateSequence(polygon->npoints[ring]); - if (is3d) - { - for(t=0;tnpoints[ring];t++) - { - c.x = pts[t+pointOffset].x; - c.y = pts[t+pointOffset].y; - c.z = pts[t+pointOffset].z; - cl->setAt( c ,t); - } - } - else - { - for(t=0;tnpoints[ring];t++) - { - c.x = pts[t+pointOffset].x; - c.y = pts[t+pointOffset].y; - c.z = DoubleNotANumber; - cl->setAt( c ,t); - } - } - innerRing = (LinearRing *) geomFactory->createLinearRing(cl); -#if GEOS_LAST_INTERFACE < 2 - delete cl; -#endif - if (innerRing == NULL) - { - delete outerRing; - return NULL; - } - innerRing->setSRID(SRID); - innerRings->push_back(innerRing); - pointOffset += polygon->npoints[ring]; - } - - g = geomFactory->createPolygon(outerRing, innerRings); - if (g==NULL) - return NULL; - g->setSRID(SRID); - return g; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return NULL; - } - - catch (...) - { - return NULL; - } -} - -//----------------------------------------------------------- -// relate()-related functions -// return 0 = false, 1 = true, 2 = error occured -//----------------------------------------------------------- - -char GEOSrelateDisjoint(Geometry *g1, Geometry*g2) -{ - try { - bool result; - result = g1->disjoint(g2); - return result; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return 2; - } - catch (...) - { - return 2; - } -} - -char GEOSrelateTouches(Geometry *g1, Geometry*g2) -{ - try { - bool result; - result = g1->touches(g2); - return result; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return 2; - } - - catch (...) - { - return 2; - } -} - -char GEOSrelateIntersects(Geometry *g1, Geometry*g2) -{ - try { - bool result; - result = g1->intersects(g2); - return result; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return 2; - } - - catch (...) - { - return 2; - } -} - -char GEOSrelateCrosses(Geometry *g1, Geometry*g2) -{ - try { - bool result; - result = g1->crosses(g2); - return result; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return 2; - } - - catch (...) - { - return 2; - } -} - -char GEOSrelateWithin(Geometry *g1, Geometry*g2) -{ - try { - bool result; - result = g1->within(g2); - return result; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return 2; - } - - catch (...) - { - return 2; - } -} - -// call g1->contains(g2) -// returns 0 = false -// 1 = true -// 2 = error was trapped -char GEOSrelateContains(Geometry *g1, Geometry*g2) -{ - try { - bool result; - result = g1->contains(g2); - return result; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return 2; - } - - catch (...) - { - return 2; - } -} - -char GEOSrelateOverlaps(Geometry *g1, Geometry*g2) -{ - try { - bool result; - result = g1->overlaps(g2); - return result; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return 2; - } - - catch (...) - { - return 2; - } -} - - -//------------------------------------------------------------------- -// low-level relate functions -//------------------------------------------------------------------ - -char GEOSrelatePattern(Geometry *g1, Geometry*g2,char *pat) -{ - try { - bool result; - string s = pat; - result = g1->relate(g2,pat); - return result; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return 2; - } - - catch (...) - { - return 2; - } -} - -char *GEOSrelate(Geometry *g1, Geometry*g2) -{ - - try { - - IntersectionMatrix *im = g1->relate(g2); - - string s; - char *result; - if (im == NULL) - return NULL; - - s= im->toString(); - result = (char*) malloc( s.length() + 1); - strcpy(result, s.c_str() ); - - return result; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return NULL; - } - - catch (...) - { - return NULL; - } -} - - - -//----------------------------------------------------------------- -// isValid -//----------------------------------------------------------------- - - -char GEOSisvalid(Geometry *g1) -{ - try { - bool result; - result =g1->isValid(); - return result; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return 2; - } - - catch (...) - { - return 2; - } - -} - - -//----------------------------------------------------------------- -// general purpose -//----------------------------------------------------------------- - -char GEOSequals(Geometry *g1, Geometry*g2) -{ - try { - bool result; - result = g1->equals(g2); - return result; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return 2; - } - - catch (...) - { - return 2; - } -} - - - -char *GEOSasText(Geometry *g1) -{ - try - { - string s = g1->toString(); - - - char *result; - result = (char*) malloc( s.length() + 1); - strcpy(result, s.c_str() ); - return result; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return NULL; - } - - catch (...) - { - return NULL; - } -} - -char GEOSisEmpty(Geometry *g1) -{ - try - { - return g1->isEmpty(); - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return 2; - } - - catch (...) - { - return 2; - } -} - -char GEOSisSimple(Geometry *g1) -{ - try - { - return g1->isSimple(); - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return 2; - } - - catch (...) - { - return 2; - } -} - -char GEOSisRing(Geometry *g1) -{ - try - { - return (( (LinearRing*)g1)->isRing()); - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return 2; - } - - catch (...) - { - return 2; - } -} - - - -//free the result of this -char *GEOSGeometryType(Geometry *g1) -{ - try - { - string s = g1->getGeometryType(); - - - char *result; - result = (char*) malloc( s.length() + 1); - strcpy(result, s.c_str() ); - return result; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return NULL; - } - - catch (...) - { - return NULL; - } -} - -// Return postgis geometry type index -int GEOSGeometryTypeId(Geometry *g1) -{ - try - { - GeometryTypeId id = g1->getGeometryTypeId(); - switch (id) - { - case GEOS_POINT: - return POINTTYPE; - case GEOS_LINESTRING: - return LINETYPE; - case GEOS_POLYGON: - return POLYGONTYPE; - case GEOS_MULTIPOINT: - return MULTIPOINTTYPE; - case GEOS_MULTILINESTRING: - return MULTILINETYPE; - case GEOS_MULTIPOLYGON: - return MULTIPOLYGONTYPE; - case GEOS_GEOMETRYCOLLECTION: - return COLLECTIONTYPE; - default: - return 0; - } - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return -1; - } - - catch (...) - { - return -1; - } -} - - - - -//------------------------------------------------------------------- -// GEOS functions that return geometries -//------------------------------------------------------------------- - -Geometry *GEOSIntersection(Geometry *g1,Geometry *g2) -{ - try - { - Geometry *g3 = g1->intersection(g2); - return g3; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return NULL; - } - - catch (...) - { - return NULL; - } -} - -Geometry *GEOSBuffer(Geometry *g1,double width) -{ - try - { - Geometry *g3 = g1->buffer(width); - return g3; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return NULL; - } - - catch (...) - { - return NULL; - } -} - -Geometry *GEOSConvexHull(Geometry *g1) -{ - try - { - Geometry *g3 = g1->convexHull(); - return g3; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return NULL; - } - - catch (...) - { - return NULL; - } -} - -Geometry *GEOSDifference(Geometry *g1,Geometry *g2) -{ - try - { - Geometry *g3 = g1->difference(g2); - return g3; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return NULL; - } - - catch (...) - { - return NULL; - } -} - -Geometry *GEOSBoundary(Geometry *g1) -{ - try - { - Geometry *g3 = g1->getBoundary(); - return g3; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return NULL; - } - - catch (...) - { - return NULL; - } -} - -Geometry *GEOSSymDifference(Geometry *g1,Geometry *g2) -{ - try - { - Geometry *g3 = g1->symDifference(g2); - return g3; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return NULL; - } - - catch (...) - { - return NULL; - } -} - -Geometry *GEOSUnion(Geometry *g1,Geometry *g2) -{ - try - { - Geometry *g3 = g1->Union(g2); - return g3; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return NULL; - } - catch (...) - { - return NULL; - } -} - - -Geometry *GEOSpointonSurface(Geometry *g1) -{ - try - { - Geometry *g3 = g1->getInteriorPoint(); - return g3; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return NULL; - } - - catch (...) - { - return NULL; - } -} - - - - - -//------------------------------------------------------------------- -// memory management functions -//------------------------------------------------------------------ - - -//BUG:: this leaks memory, but delete kills the PrecisionModel for ALL the geometries -void GEOSdeleteGeometry(Geometry *a) -{ - try{ - delete a; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - //return NULL; - } - - catch(...) - { - // do nothing! - } -} - -void GEOSdeleteChar(char *a) -{ - try{ - free(a); - } - catch (GEOSException *ge) // ??? - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - //return NULL; - } - - catch(...) - { - // do nothing! - } -} - - -//------------------------------------------------------------------- -//GEOS => POSTGIS conversions -//------------------------------------------------------------------- - - -// free the result when done! -// g1 must be a point -POINT3D *GEOSGetCoordinate(Geometry *g1) -{ - try{ - POINT3D *result = (POINT3D*) malloc (sizeof(POINT3D)); - const Coordinate *c =g1->getCoordinate(); - - result->x = c->x; - result->y = c->y; - result->z = c->z; - return result; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return NULL; - } - - catch(...) - { - return NULL; - } - -} - - -//must free the result when done -// result is an array length g1->getNumCoordinates() -POINT3D *GEOSGetCoordinates(Geometry *g1) -{ - if ( g1->getGeometryTypeId() == GEOS_POLYGON ) - { - return GEOSGetCoordinates_Polygon((Polygon *)g1); - } - - try { - int numPoints = g1->getNumPoints(); - POINT3D *result = (POINT3D*) malloc (sizeof(POINT3D) * numPoints ); - int t; - CoordinateSequence *cl = g1->getCoordinates(); - Coordinate c; - - for (t=0;tgetAt(t); - - result[t].x = c.x; - result[t].y = c.y; - result[t].z = c.z; - } - - delete cl; - return result; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return NULL; - } - - catch(...) - { - return NULL; - } - -} - -// A somewhat optimized version for polygon types. -POINT3D *GEOSGetCoordinates_Polygon(Polygon *g1) -{ - try { - int t, r, outidx=0; - const CoordinateSequence *cl; - Coordinate c; - const LineString *lr; - int npts, nrings; - POINT3D *result; - - npts = g1->getNumPoints(); - result = (POINT3D*) malloc (sizeof(POINT3D) * npts); - - // Exterior ring - lr = g1->getExteriorRing(); - cl = lr->getCoordinatesRO(); - npts = lr->getNumPoints(); - for (t=0; tgetAt(t); - - result[outidx].x = c.x; - result[outidx].y = c.y; - result[outidx].z = c.z; - outidx++; - } - - // Interior rings - nrings = g1->getNumInteriorRing(); - for (r=0; rgetInteriorRingN(r); - cl = lr->getCoordinatesRO(); - npts = lr->getNumPoints(); - for (t=0; tgetAt(t); - result[outidx].x = c.x; - result[outidx].y = c.y; - result[outidx].z = c.z; - outidx++; - } - } - - return result; - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return NULL; - } - - catch(...) - { - return NULL; - } - -} - - - - -int GEOSGetNumCoordinate(Geometry *g1) -{ - try{ - return g1->getNumPoints(); - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return 0; - } - - catch(...) - { - return 0; - } -} - -int GEOSGetNumInteriorRings(Geometry *g1) -{ - try{ - Polygon *p = (Polygon *) g1; - return p->getNumInteriorRing(); - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return 0; - } - - catch(...) - { - return 0; - } -} - - -//only call on GCs (or multi*) -int GEOSGetNumGeometries(Geometry *g1) -{ - try{ - GeometryCollection *gc = (GeometryCollection *) g1; - return gc->getNumGeometries(); - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return 0; - } - - catch(...) - { - return 0; - } -} - - -//call only on GEOMETRYCOLLECTION or MULTI* -const Geometry *GEOSGetGeometryN(Geometry *g1, int n) -{ - try{ - const GeometryCollection *gc = (GeometryCollection *) g1; - return gc->getGeometryN(n); - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return NULL; - } - - catch(...) - { - return NULL; - } -} - - -//call only on polygon -const Geometry *GEOSGetExteriorRing(Geometry *g1) -{ - try{ - Polygon *p = (Polygon *) g1; - return p->getExteriorRing(); - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return 0; - } - - catch(...) - { - return 0; - } -} - -//call only on polygon -const Geometry *GEOSGetInteriorRingN(Geometry *g1,int n) -{ - try{ - Polygon *p = (Polygon *) g1; - return p->getInteriorRingN(n); - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return NULL; - } - - catch(...) - { - return NULL; - } -} - -Geometry *GEOSGetCentroid(Geometry *g) -{ - try{ - return g->getCentroid(); - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return NULL; - } - - catch(...) - { - return NULL; - } -} - - -int GEOSGetSRID(Geometry *g1) -{ - try{ - return g1->getSRID(); - } - catch (GEOSException *ge) - { - NOTICE_MESSAGE((char *)ge->toString().c_str()); - delete ge; - return 0; - } - - catch(...) - { - return 0; - } -} - -char * -GEOSversion() -{ -#if GEOS_LAST_INTERFACE < 2 - /* - * GEOS upgrade needs postgis re-build, so this static - * assignment is not going to be a problem - */ - char *res = strdup("1.0.0"); -#else - string version = geosversion(); - char *res = strdup(version.c_str()); -#endif - return res; -} - -char * -GEOSjtsport() -{ -#if GEOS_LAST_INTERFACE < 2 - /* - * GEOS upgrade needs postgis re-build, so this static - * assignment is not going to be a problem - */ - char *res = strdup("1.3"); -#else - string version = jtsport(); - char *res = strdup(version.c_str()); -#endif - return res; -} - - diff --git a/hwgeom/postgis_gist_71.c b/hwgeom/postgis_gist_71.c deleted file mode 100644 index b2391b23f..000000000 --- a/hwgeom/postgis_gist_71.c +++ /dev/null @@ -1,599 +0,0 @@ - -/********************************************************************** - * $Id$ - * - * PostGIS - Spatial Types for PostgreSQL - * http://postgis.refractions.net - * Copyright 2001-2003 Refractions Research Inc. - * - * This is free software; you can redistribute and/or modify it under - * the terms of the GNU General Public Licence. See the COPYING file. - * - ********************************************************************** - * $Log$ - * Revision 1.1 2004/09/20 07:50:06 strk - * prepared to contain old internal representation code - * - * Revision 1.4 2004/04/28 22:26:02 pramsey - * Fixed spelling mistake in header text. - * - * Revision 1.3 2003/08/08 18:19:20 dblasby - * Conformance changes. - * Removed junk from postgis_debug.c and added the first run of the long - * transaction locking support. (this will change - dont use it) - * conformance tests were corrected - * some dos cr/lf removed - * empty geometries i.e. GEOMETRYCOLLECT(EMPTY) added (with indexing support) - * pointN(,1) now returns the first point (used to return 2nd) - * - * Revision 1.2 2003/07/01 18:30:55 pramsey - * Added CVS revision headers. - * - * - **********************************************************************/ - -#include "postgres.h" - -#include -#include -#include -#include -#include - -#include "access/gist.h" -#include "access/itup.h" -#include "access/rtree.h" - -#include "fmgr.h" - -#include "postgis.h" -#include "utils/elog.h" - -//Norman Vine found this problem for compiling under cygwin -// it defines BYTE_ORDER and LITTLE_ENDIAN - -#ifdef __CYGWIN__ -#include // FOR ENDIAN DEFINES -#endif - -#define SHOW_DIGS_DOUBLE 15 -#define MAX_DIGS_DOUBLE (SHOW_DIGS_DOUBLE + 6 + 1 + 3 +1) - -// #define DEBUG_GIST - - -//for GIST index -typedef char* (*BINARY_UNION)(char*, char*, int*); -typedef float (*SIZE_BOX)(char*); -typedef Datum (*RDF)(PG_FUNCTION_ARGS); - -GISTENTRY *ggeometry_compress(PG_FUNCTION_ARGS); -GEOMETRYKEY *ggeometry_union(PG_FUNCTION_ARGS); -GIST_SPLITVEC * ggeometry_picksplit(PG_FUNCTION_ARGS); -bool ggeometry_consistent(PG_FUNCTION_ARGS); -float * ggeometry_penalty(PG_FUNCTION_ARGS); -bool * ggeometry_same(PG_FUNCTION_ARGS); - -char * ggeometry_binary_union(char *r1, char *r2, int *sizep); -float size_geometrykey( char *pk ); - -Datum ggeometry_inter(PG_FUNCTION_ARGS); - -/* -** Common rtree-function (for all ops) -*/ -char * rtree_union(bytea *entryvec, int *sizep, BINARY_UNION bu); -float * rtree_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result, BINARY_UNION bu, SIZE_BOX sb); -GIST_SPLITVEC * rtree_picksplit(bytea *entryvec, GIST_SPLITVEC *v, int keylen, BINARY_UNION bu, RDF interop, SIZE_BOX sb); -bool rtree_internal_consistent(BOX *key, BOX *query, StrategyNumber strategy); - - -GISTENTRY *rtree_decompress(PG_FUNCTION_ARGS); - - -//restriction in the GiST && operator - -Datum postgis_gist_sel(PG_FUNCTION_ARGS) -{ - PG_RETURN_FLOAT8(0.000005); -} - - -BOX *convert_box3d_to_box(BOX3D *in) -{ - BOX *out = palloc (sizeof (BOX) ); - - out->high.x = in->URT.x; - out->high.y = in->URT.y; - - out->low.x = in->LLB.x; - out->low.y = in->LLB.y; - - return out; -} - -PG_FUNCTION_INFO_V1(ggeometry_compress); -GISTENTRY *ggeometry_compress(PG_FUNCTION_ARGS) -{ - GISTENTRY *entry=(GISTENTRY*)PG_GETARG_POINTER(0); - GISTENTRY *retval; - - if ( entry->leafkey) { - retval = palloc(sizeof(GISTENTRY)); - if ( entry->pred ) { - - GEOMETRY *in; - GEOMETRYKEY *r; - BOX *thebox; - -#ifdef DEBUG_GIST2 - printf("GIST: ggeometry_compress called on geometry\n"); -#endif - - in = (GEOMETRY*)PG_DETOAST_DATUM(PointerGetDatum(entry->pred)); - - if (in->nobjs ==0) // this is the EMPTY geometry - { - //elog(NOTICE,"found an empty geometry"); - // dont bother adding this to the index - PG_RETURN_POINTER(entry); - } - - r = (GEOMETRYKEY*)palloc( sizeof(GEOMETRYKEY) ); - r->size = sizeof(GEOMETRYKEY); - r->SRID = in->SRID; - thebox = convert_box3d_to_box(&in->bvol); - memcpy( (void*)&(r->key), (void*)thebox, sizeof(BOX) ); - if ( (char*)in != entry->pred ) - { - pfree( in ); - pfree(thebox); - } - - gistentryinit(*retval, (char*)r, entry->rel, entry->page, - entry->offset, sizeof(GEOMETRYKEY),FALSE); - - } else { - gistentryinit(*retval, NULL, entry->rel, entry->page, - entry->offset, 0,FALSE); - } - } else { - retval = entry; - } - return( retval ); -} - -PG_FUNCTION_INFO_V1(ggeometry_consistent); -bool ggeometry_consistent(PG_FUNCTION_ARGS) -{ - GISTENTRY *entry = (GISTENTRY*) PG_GETARG_POINTER(0); - GEOMETRY *query = (GEOMETRY*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); - BOX *thebox; - /* - ** if entry is not leaf, use gbox_internal_consistent, - ** else use gbox_leaf_consistent - */ - -#ifdef DEBUG_GIST2 - printf("GIST: ggeometry_consistent called\n"); -#endif - - if ( ! (entry->pred && query) ) - return FALSE; - - thebox = convert_box3d_to_box( &(query->bvol) ); - - if( ((GEOMETRYKEY *)(entry->pred))->SRID != query->SRID) - { - elog(ERROR,"Operation on two GEOMETRIES with different SRIDs (ggeometry_consistent)\n"); - PG_RETURN_BOOL(FALSE); - } - - PG_RETURN_BOOL(rtree_internal_consistent((BOX*)&( ((GEOMETRYKEY *)(entry->pred))->key ), - thebox, strategy)); -} - - -PG_FUNCTION_INFO_V1(ggeometry_union); -GEOMETRYKEY *ggeometry_union(PG_FUNCTION_ARGS) -{ - GEOMETRYKEY *result; - -#ifdef DEBUG_GIST2 - printf("GIST: ggeometry_union called\n"); -#endif - - result = (GEOMETRYKEY*) - rtree_union( - (bytea*) PG_GETARG_POINTER(0), - (int*) PG_GETARG_POINTER(1), - ggeometry_binary_union - ); - - return result; -} - - -PG_FUNCTION_INFO_V1(ggeometry_penalty); -float *ggeometry_penalty(PG_FUNCTION_ARGS) -{ -#ifdef DEBUG_GIST2 - printf("GIST: ggeometry_penalty called\n"); -#endif - - return rtree_penalty( - (GISTENTRY*) PG_GETARG_POINTER(0), - (GISTENTRY*) PG_GETARG_POINTER(1), - (float*) PG_GETARG_POINTER(2), - ggeometry_binary_union, - size_geometrykey - ); -} - -PG_FUNCTION_INFO_V1(ggeometry_picksplit); -GIST_SPLITVEC *ggeometry_picksplit(PG_FUNCTION_ARGS) -{ -#ifdef DEBUG_GIST2 - printf("GIST: ggeometry_picksplit called\n"); -#endif - - - return rtree_picksplit( - (bytea*)PG_GETARG_POINTER(0), - (GIST_SPLITVEC*)PG_GETARG_POINTER(1), - sizeof(GEOMETRYKEY), - ggeometry_binary_union, - ggeometry_inter, - size_geometrykey - ); -} - -PG_FUNCTION_INFO_V1(ggeometry_same); -bool *ggeometry_same(PG_FUNCTION_ARGS) -{ - - GEOMETRYKEY *b1 = (GEOMETRYKEY*) PG_GETARG_POINTER(0); - GEOMETRYKEY *b2 = (GEOMETRYKEY*) PG_GETARG_POINTER(1); - - bool *result = (bool*) PG_GETARG_POINTER(2); - -#ifdef DEBUG_GIST2 - printf("GIST: ggeometry_same called\n"); -#endif - - - if ( b1 && b2 ) - *result = DatumGetBool( DirectFunctionCall2( box_same, - PointerGetDatum(&(b1->key)), - PointerGetDatum(&(b2->key))) ); - else - *result = ( b1==NULL && b2==NULL ) ? TRUE : FALSE; - return(result); -} - -PG_FUNCTION_INFO_V1(ggeometry_inter); -Datum ggeometry_inter(PG_FUNCTION_ARGS) { - GEOMETRYKEY *b1 = (GEOMETRYKEY*) PG_GETARG_POINTER(0); - GEOMETRYKEY*b2 = (GEOMETRYKEY*) PG_GETARG_POINTER(1); - char *interd; - -#ifdef DEBUG_GIST2 - printf("GIST: ggeometry_inter called\n"); -#endif - - - interd = DatumGetPointer(DirectFunctionCall2( - rt_box_inter, - PointerGetDatum( &(b1->key) ), - PointerGetDatum( &(b2->key) )) ); - - if (interd) { - GEOMETRYKEY *tmp = (GEOMETRYKEY*)palloc( sizeof(GEOMETRYKEY) ); - tmp->size = sizeof(GEOMETRYKEY); - - memcpy( (void*)&(tmp->key), (void*)interd, sizeof(BOX) ); - tmp->SRID = b1->SRID; - pfree( interd ); - PG_RETURN_POINTER( tmp ); - } else - PG_RETURN_POINTER( NULL ); -} - -char *ggeometry_binary_union(char *r1, char *r2, int *sizep) -{ - GEOMETRYKEY *retval; - -#ifdef DEBUG_GIST2 - printf("GIST: ggeometry_binary_union called\n"); -#endif - - if ( ! (r1 && r2) ) { - if ( r1 ) { - retval = (GEOMETRYKEY*)palloc( sizeof(GEOMETRYKEY) ); - memcpy( (void*)retval, (void*)r1, sizeof(GEOMETRYKEY) ); - *sizep = sizeof(GEOMETRYKEY); - } else if ( r2 ) { - retval = (GEOMETRYKEY*)palloc( sizeof(GEOMETRYKEY) ); - memcpy( (void*)retval, (void*)r2, sizeof(GEOMETRYKEY) ); - *sizep = sizeof(GEOMETRYKEY); - } else { - *sizep = 0; - retval = NULL; - } - } else { - BOX *key = (BOX*)DatumGetPointer( DirectFunctionCall2( - rt_box_union, - PointerGetDatum( &(((GEOMETRYKEY*)r1)->key) ), - PointerGetDatum( &(((GEOMETRYKEY*)r2)->key) )) ); - retval = (GEOMETRYKEY*)palloc( sizeof(GEOMETRYKEY) ); - retval->SRID = ((GEOMETRYKEY *) r1)->SRID; - memcpy( (void*)&(retval->key), (void*)key, sizeof(BOX) ); - pfree( key ); - *sizep = retval->size = sizeof(GEOMETRYKEY); - } - return (char*)retval; -} - - -float size_geometrykey( char *pk ) { - -#ifdef DEBUG_GIST2 - printf("GIST: size_geometrykey called\n"); -#endif - - if ( pk ) { - float size; - DirectFunctionCall2( rt_box_size, - PointerGetDatum( &(((GEOMETRYKEY*)pk)->key) ), - PointerGetDatum( &size ) ); - return size; - } else - return 0.0; -} - -char *rtree_union(bytea *entryvec, int *sizep, BINARY_UNION bu) -{ - int numranges, i; - char *out, *tmp; - -#ifdef DEBUG_GIST2 - printf("GIST: rtree_union called\n"); -#endif - - numranges = (VARSIZE(entryvec) - VARHDRSZ)/sizeof(GISTENTRY); - tmp = (char *)(((GISTENTRY *)(VARDATA(entryvec)))[0]).pred; - out = NULL; - - for (i = 1; i < numranges; i++) { - out = (*bu)(tmp, (char *) - (((GISTENTRY *)(VARDATA(entryvec)))[i]).pred, - sizep); - if (i > 1 && tmp) pfree(tmp); - tmp = out; - } - - return(out); -} - -float *rtree_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result, BINARY_UNION bu, SIZE_BOX sb) -{ - char * ud; - float tmp1; - int sizep; - -#ifdef DEBUG_GIST2 - printf("GIST: rtree_penalty called\n"); -#endif - - - - ud = (*bu)( origentry->pred, newentry->pred, &sizep ); - tmp1 = (*sb)( ud ); - if (ud) pfree(ud); - - *result = tmp1 - (*sb)( origentry->pred ); - return(result); -} - -/* -** The GiST PickSplit method -** We use Guttman's poly time split algorithm -*/ -GIST_SPLITVEC *rtree_picksplit(bytea *entryvec, GIST_SPLITVEC *v, int keylen, BINARY_UNION bu, RDF interop, SIZE_BOX sb) -{ - OffsetNumber i, j; - char *datum_alpha, *datum_beta; - char *datum_l, *datum_r; - char *union_d, *union_dl, *union_dr; - char *inter_d; - bool firsttime; - float size_alpha, size_beta, size_union, size_inter; - float size_waste, waste; - float size_l, size_r; - int nbytes; - int sizep; - OffsetNumber seed_1 = 0, seed_2 = 0; - OffsetNumber *left, *right; - OffsetNumber maxoff; - -#ifdef DEBUG_GIST2 - printf("GIST: rtree_picsplit called\n"); -#endif - - maxoff = ((VARSIZE(entryvec) - VARHDRSZ)/sizeof(GISTENTRY)) - 2; - nbytes = (maxoff + 2) * sizeof(OffsetNumber); - v->spl_left = (OffsetNumber *) palloc(nbytes); - v->spl_right = (OffsetNumber *) palloc(nbytes); - - firsttime = true; - waste = 0.0; - - for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i)) { - datum_alpha = (char *)(((GISTENTRY *)(VARDATA(entryvec)))[i].pred); - for (j = OffsetNumberNext(i); j <= maxoff; j = OffsetNumberNext(j)) { - datum_beta = (char *)(((GISTENTRY *)(VARDATA(entryvec)))[j].pred); - - /* compute the wasted space by unioning these guys */ - /* size_waste = size_union - size_inter; */ - union_d = (*bu)( datum_alpha, datum_beta, &sizep ); - if ( union_d ) { - size_union = (*sb)(union_d); - pfree(union_d); - } else - size_union = 0.0; - - if ( datum_alpha && datum_beta ) { - inter_d = DatumGetPointer(DirectFunctionCall2( - interop, - PointerGetDatum( datum_alpha ), - PointerGetDatum( datum_beta )) ); - if ( inter_d ) { - size_inter = (*sb)(inter_d); - pfree(inter_d); - } else - size_inter = 0.0; - } else - size_inter = 0.0; - - size_waste = size_union - size_inter; - - /* - * are these a more promising split that what we've - * already seen? - */ - - if (size_waste > waste || firsttime) { - waste = size_waste; - seed_1 = i; - seed_2 = j; - firsttime = false; - } - } - } - - left = v->spl_left; - v->spl_nleft = 0; - right = v->spl_right; - v->spl_nright = 0; - - if ( ((GISTENTRY *)(VARDATA(entryvec)))[seed_1].pred ) { - datum_l = (char*) palloc( keylen ); - memcpy( (void*)datum_l, (void*)(((GISTENTRY *)(VARDATA(entryvec)))[seed_1].pred ), keylen ); - } else - datum_l = NULL; - size_l = (*sb)( datum_l ); - if ( ((GISTENTRY *)(VARDATA(entryvec)))[seed_2].pred ) { - datum_r = (char*) palloc( keylen ); - memcpy( (void*)datum_r, (void*)(((GISTENTRY *)(VARDATA(entryvec)))[seed_2].pred ), keylen ); - } else - datum_r = NULL; - size_r = (*sb)( datum_r ); - - /* - * Now split up the regions between the two seeds. An important - * property of this split algorithm is that the split vector v - * has the indices of items to be split in order in its left and - * right vectors. We exploit this property by doing a merge in - * the code that actually splits the page. - * - * For efficiency, we also place the new index tuple in this loop. - * This is handled at the very end, when we have placed all the - * existing tuples and i == maxoff + 1. - */ - - maxoff = OffsetNumberNext(maxoff); - for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) { - - /* - * If we've already decided where to place this item, just - * put it on the right list. Otherwise, we need to figure - * out which page needs the least enlargement in order to - * store the item. - */ - - if (i == seed_1) { - *left++ = i; - v->spl_nleft++; - continue; - } else if (i == seed_2) { - *right++ = i; - v->spl_nright++; - continue; - } - - /* okay, which page needs least enlargement? */ - datum_alpha = (char *)(((GISTENTRY *)(VARDATA(entryvec)))[i].pred); - union_dl = (*bu)( datum_l, datum_alpha, &sizep ); - union_dr = (*bu)( datum_r, datum_alpha, &sizep ); - size_alpha = (*sb)( union_dl ); - size_beta = (*sb)( union_dr ); - - /* pick which page to add it to */ - if (size_alpha - size_l < size_beta - size_r) { - pfree(datum_l); - pfree(union_dr); - datum_l = union_dl; - size_l = size_alpha; - *left++ = i; - v->spl_nleft++; - } else { - pfree(datum_r); - pfree(union_dl); - datum_r = union_dr; - size_r = size_alpha; - *right++ = i; - v->spl_nright++; - } - } - *left = *right = FirstOffsetNumber; /* sentinel value, see dosplit() */ - - v->spl_ldatum = datum_l; - v->spl_rdatum = datum_r; - - return( v ); -} - - -bool rtree_internal_consistent(BOX *key, - BOX *query, - StrategyNumber strategy) -{ - bool retval; - -#ifdef DEBUG_GIST2 - printf("GIST: rtree_internal_consist called\n"); -#endif - - switch(strategy) { - case RTLeftStrategyNumber: - case RTOverLeftStrategyNumber: - retval = DatumGetBool( DirectFunctionCall2( box_overleft, PointerGetDatum(key), PointerGetDatum(query) ) ); - break; - case RTOverlapStrategyNumber: - retval = DatumGetBool( DirectFunctionCall2( box_overlap, PointerGetDatum(key), PointerGetDatum(query) ) ); - break; - case RTOverRightStrategyNumber: - case RTRightStrategyNumber: - retval = DatumGetBool( DirectFunctionCall2( box_right, PointerGetDatum(key), PointerGetDatum(query) ) ); - break; - case RTSameStrategyNumber: - case RTContainsStrategyNumber: - retval = DatumGetBool( DirectFunctionCall2( box_contain, PointerGetDatum(key), PointerGetDatum(query) ) ); - break; - case RTContainedByStrategyNumber: - retval = DatumGetBool( DirectFunctionCall2( box_overlap, PointerGetDatum(key), PointerGetDatum(query) ) ); - break; - default: - retval = FALSE; - } - return(retval); -} - -PG_FUNCTION_INFO_V1(rtree_decompress); -GISTENTRY *rtree_decompress(PG_FUNCTION_ARGS) -{ - return((GISTENTRY*)PG_GETARG_POINTER(0)); -} - - diff --git a/hwgeom/postgis_gist_72.c b/hwgeom/postgis_gist_72.c deleted file mode 100644 index 1d68bd193..000000000 --- a/hwgeom/postgis_gist_72.c +++ /dev/null @@ -1,738 +0,0 @@ - -/********************************************************************** - * $Id$ - * - * PostGIS - Spatial Types for PostgreSQL - * http://postgis.refractions.net - * Copyright 2001-2003 Refractions Research Inc. - * - * This is free software; you can redistribute and/or modify it under - * the terms of the GNU General Public Licence. See the COPYING file. - * - ********************************************************************** - * $Log$ - * Revision 1.1 2004/09/20 07:50:06 strk - * prepared to contain old internal representation code - * - * Revision 1.19 2004/08/19 06:15:58 strk - * USE_VERSION gets 80 where it got 75 - * - * Revision 1.18 2004/06/09 10:19:06 strk - * Moved changes needed for PG75 inside postgis_gist_72.c using #if switches. - * - * Revision 1.17 2004/06/03 08:19:20 strk - * yet another Infinite check used: finite() - which checks for NaN,-Inf,+Inf - * - * Revision 1.16 2004/06/03 08:13:11 strk - * Simplified INFINITY checks by use of isinf() - * - * Revision 1.15 2004/06/03 07:58:11 strk - * Infinite coordinate geoms omitted from index - * - * Revision 1.14 2004/06/02 23:54:09 strk - * Made equality checks the default in picksplit to catch also NaN results (INF geoms) - * - * Revision 1.13 2004/06/02 23:29:08 strk - * reverted Inf handling modification (conceptually bogus) - * - * Revision 1.12 2004/06/02 22:43:54 strk - * handled special case of Inf boxes as GiST keys in picksplit - * - * Revision 1.11 2004/04/28 22:26:02 pramsey - * Fixed spelling mistake in header text. - * - * Revision 1.10 2004/04/08 17:05:20 dblasby - * Somehow the memory leak changes I made got removed - I've re-added them. - * - * Revision 1.9 2004/04/08 17:00:27 dblasby - * Changed ggeometry_consistent to be aware of NULL queries. Ie. - * select * from
where the_geom && null::geometry; - * - * This tends to happen when you're joining two tables using && and the table - * has NULLs in it. - * - * Revision 1.8 2004/03/05 18:16:47 strk - * Applied Mark Cave-Ayland patch - * - * Revision 1.7 2004/02/25 13:17:31 strk - * RTContainedBy and RTOverlap strategries implemented locally with a pgbox_overlap function - * - * Revision 1.6 2003/08/08 18:19:20 dblasby - * Conformance changes. - * Removed junk from postgis_debug.c and added the first run of the long - * transaction locking support. (this will change - dont use it) - * conformance tests were corrected - * some dos cr/lf removed - * empty geometries i.e. GEOMETRYCOLLECT(EMPTY) added (with indexing support) - * pointN(,1) now returns the first point (used to return 2nd) - * - * Revision 1.5 2003/07/01 18:30:55 pramsey - * Added CVS revision headers. - * - * - ********************************************************************** - * - * GiST indexing functions for pgsql >= 7.2 - * - **********************************************************************/ - -#include "postgres.h" - -#include -#include -#include -#include -#include - -#include "access/gist.h" -#include "access/itup.h" -#include "access/rtree.h" - -#include "fmgr.h" - -#include "postgis.h" -#include "utils/elog.h" - -#define SHOW_DIGS_DOUBLE 15 -#define MAX_DIGS_DOUBLE (SHOW_DIGS_DOUBLE + 6 + 1 + 3 +1) - -#define DEBUG_GIST - -//for GIST index -typedef char* (*BINARY_UNION)(char*, char*, int*); -typedef float (*SIZE_BOX)(char*); -typedef Datum (*RDF)(PG_FUNCTION_ARGS); - - -BOX *convert_box3d_to_box(BOX3D *in); -Datum ggeometry_compress(PG_FUNCTION_ARGS); -Datum ggeometry_consistent(PG_FUNCTION_ARGS); -static bool rtree_internal_consistent(BOX *key, BOX *query,StrategyNumber strategy); -static bool rtree_leaf_consistent(BOX *key, BOX *query,StrategyNumber strategy); -Datum rtree_decompress(PG_FUNCTION_ARGS); -Datum gbox_union(PG_FUNCTION_ARGS); -Datum gbox_picksplit(PG_FUNCTION_ARGS); -Datum gbox_penalty(PG_FUNCTION_ARGS); -Datum gbox_same(PG_FUNCTION_ARGS); -static float size_box(Datum box); -extern void convert_box3d_to_box_p(BOX3D *in,BOX *out); - - -int debug = 0; - -//puts result in pre-allocated "out" -void convert_box3d_to_box_p(BOX3D *in,BOX *out) -{ - - out->high.x = in->URT.x; - out->high.y = in->URT.y; - - out->low.x = in->LLB.x; - out->low.y = in->LLB.y; -} - - -BOX *convert_box3d_to_box(BOX3D *in) -{ - BOX *out = palloc (sizeof (BOX) ); - - out->high.x = in->URT.x; - out->high.y = in->URT.y; - - out->low.x = in->LLB.x; - out->low.y = in->LLB.y; - - return out; -} - -PG_FUNCTION_INFO_V1(ggeometry_compress); -Datum ggeometry_compress(PG_FUNCTION_ARGS) -{ - GISTENTRY *entry=(GISTENTRY*)PG_GETARG_POINTER(0); - GISTENTRY *retval; - -#ifdef DEBUG_GIST - elog(NOTICE,"GIST: ggeometry_compress called on geometry\n"); - fflush( stdout ); -#endif - - if ( entry->leafkey) - { - retval = palloc(sizeof(GISTENTRY)); - if ( DatumGetPointer(entry->key) != NULL ) - { - - GEOMETRY *in; - BOX *r; - - - in = (GEOMETRY*)PG_DETOAST_DATUM( entry->key ); - - if (in->nobjs ==0) // this is the EMPTY geometry - { - //elog(NOTICE,"found an empty geometry"); - // dont bother adding this to the index - PG_RETURN_POINTER(entry); - } - - if ( ! finite(in->bvol.URT.x) || - ! finite(in->bvol.URT.y) || - ! finite(in->bvol.LLB.x) || - ! finite(in->bvol.LLB.y) ) - { - //elog(NOTICE, "found infinite geometry"); - PG_RETURN_POINTER(entry); - } - - r = convert_box3d_to_box(&in->bvol); - if ( in != (GEOMETRY*)DatumGetPointer(entry->key) ) - { - pfree( in ); - } - - gistentryinit(*retval, PointerGetDatum(r), - entry->rel, entry->page, - entry->offset, sizeof(BOX), - FALSE); - - } - else - { - gistentryinit(*retval, (Datum) 0, entry->rel, - entry->page, entry->offset, 0,FALSE); - } - } - else - { - retval = entry; - } - PG_RETURN_POINTER(retval); -} - -PG_FUNCTION_INFO_V1(ggeometry_consistent); -Datum ggeometry_consistent(PG_FUNCTION_ARGS) -{ - GISTENTRY *entry = (GISTENTRY*) PG_GETARG_POINTER(0); - GEOMETRY *query ; - StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); - BOX thebox; - bool result; - -elog(NOTICE, "**** ggeometry_consistent call"); - - /* - ** if entry is not leaf, use rtree_internal_consistent, - ** else use rtree_leaf_consistent - */ - - if ( ( (Pointer *) PG_GETARG_DATUM(1) ) == NULL) - { - //elog(NOTICE,"ggeometry_consistent:: got null query!"); - PG_RETURN_BOOL(false); // null query - this is screwy! - } - - query = (GEOMETRY*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - - -#ifdef DEBUG_GIST - elog(NOTICE,"GIST: ggeometry_consistent called\n"); - fflush( stdout ); -#endif - - if ( ! (DatumGetPointer(entry->key) != NULL && query) ) - PG_RETURN_BOOL(FALSE); - - convert_box3d_to_box_p( &(query->bvol) , &thebox); - - if (GIST_LEAF(entry)) - result = rtree_leaf_consistent((BOX *) DatumGetPointer(entry->key), &thebox, strategy ); - else - result = rtree_internal_consistent((BOX *) DatumGetPointer(entry->key), &thebox, strategy ); - - PG_FREE_IF_COPY(query, 1); - PG_RETURN_BOOL(result); -} - - -static bool -rtree_internal_consistent(BOX *key, - BOX *query, - StrategyNumber strategy) -{ - bool retval; - -#ifdef DEBUG_GIST - elog(NOTICE,"GIST: rtree_internal_consist called\n"); - fflush( stdout ); -#endif - - switch(strategy) { - case RTLeftStrategyNumber: - case RTOverLeftStrategyNumber: - retval = DatumGetBool( DirectFunctionCall2( box_overleft, PointerGetDatum(key), PointerGetDatum(query) ) ); - break; - case RTOverlapStrategyNumber: - retval = DatumGetBool( DirectFunctionCall2( box_overlap, PointerGetDatum(key), PointerGetDatum(query) ) ); - break; - case RTOverRightStrategyNumber: - case RTRightStrategyNumber: - retval = DatumGetBool( DirectFunctionCall2( box_overright, PointerGetDatum(key), PointerGetDatum(query) ) ); - break; - case RTSameStrategyNumber: - case RTContainsStrategyNumber: - retval = DatumGetBool( DirectFunctionCall2( box_contain, PointerGetDatum(key), PointerGetDatum(query) ) ); - break; - case RTContainedByStrategyNumber: - retval = DatumGetBool( DirectFunctionCall2( box_overlap, PointerGetDatum(key), PointerGetDatum(query) ) ); - break; - default: - retval = FALSE; - } - return(retval); -} - - -static bool -rtree_leaf_consistent(BOX *key, - BOX *query, - StrategyNumber strategy) -{ - bool retval; - -#ifdef DEBUG_GIST - elog(NOTICE,"GIST: rtree_leaf_consist called\n"); - fflush( stdout ); -#endif - - switch (strategy) - { - case RTLeftStrategyNumber: - retval = DatumGetBool(DirectFunctionCall2(box_left, PointerGetDatum(key), PointerGetDatum(query))); - break; - case RTOverLeftStrategyNumber: - retval = DatumGetBool(DirectFunctionCall2(box_overleft, PointerGetDatum(key), PointerGetDatum(query))); - break; - case RTOverlapStrategyNumber: - retval = DatumGetBool(DirectFunctionCall2(box_overlap, PointerGetDatum(key), PointerGetDatum(query))); - break; - case RTOverRightStrategyNumber: - retval = DatumGetBool(DirectFunctionCall2(box_overright, PointerGetDatum(key), PointerGetDatum(query))); - break; - case RTRightStrategyNumber: - retval = DatumGetBool(DirectFunctionCall2(box_right, PointerGetDatum(key), PointerGetDatum(query))); - break; - case RTSameStrategyNumber: - retval = DatumGetBool(DirectFunctionCall2(box_same, PointerGetDatum(key), PointerGetDatum(query))); - break; - case RTContainsStrategyNumber: - retval = DatumGetBool(DirectFunctionCall2(box_contain, PointerGetDatum(key), PointerGetDatum(query))); - break; - case RTContainedByStrategyNumber: - retval = DatumGetBool(DirectFunctionCall2(box_contained, PointerGetDatum(key), PointerGetDatum(query))); - break; - default: - retval = FALSE; - } - return (retval); -} - - -PG_FUNCTION_INFO_V1(rtree_decompress); -Datum rtree_decompress(PG_FUNCTION_ARGS) -{ - elog(NOTICE, "rtree_decompress called"); - PG_RETURN_POINTER(PG_GETARG_POINTER(0)); -} - -/* -** The GiST Union method for boxes -** returns the minimal bounding box that encloses all the entries in entryvec -*/ -PG_FUNCTION_INFO_V1(gbox_union); -Datum gbox_union(PG_FUNCTION_ARGS) -{ -#if USE_VERSION < 80 - bytea *entryvec = (bytea *) PG_GETARG_POINTER(0); -#else - GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0); -#endif - int *sizep = (int *) PG_GETARG_POINTER(1); - int numranges, - i; - BOX *cur, - *pageunion; - -#ifdef DEBUG_GIST - elog(NOTICE,"GIST: gbox_union called\n"); - fflush( stdout ); -#endif - -#if USE_VERSION < 80 - numranges = (VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY); - cur = DatumGetBoxP(((GISTENTRY *) VARDATA(entryvec))[0].key); -#else - numranges = entryvec->n; - cur = DatumGetBoxP(entryvec->vector[0].key); -#endif - pageunion = (BOX *) palloc(sizeof(BOX)); - memcpy((void *) pageunion, (void *) cur, sizeof(BOX)); - - for (i = 1; i < numranges; i++) - { -#if USE_VERSION < 80 - cur = DatumGetBoxP(((GISTENTRY *) VARDATA(entryvec))[i].key); -#else - cur = DatumGetBoxP(entryvec->vector[i].key); -#endif - if (pageunion->high.x < cur->high.x) - pageunion->high.x = cur->high.x; - if (pageunion->low.x > cur->low.x) - pageunion->low.x = cur->low.x; - if (pageunion->high.y < cur->high.y) - pageunion->high.y = cur->high.y; - if (pageunion->low.y > cur->low.y) - pageunion->low.y = cur->low.y; - } - *sizep = sizeof(BOX); - - PG_RETURN_POINTER(pageunion); -} - -/* -** The GiST Penalty method for boxes -** As in the R-tree paper, we use change in area as our penalty metric -*/ -PG_FUNCTION_INFO_V1(gbox_penalty); -Datum gbox_penalty(PG_FUNCTION_ARGS) -{ - GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0); - GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1); - float *result = (float *) PG_GETARG_POINTER(2); - Datum ud; - float tmp1; - -#ifdef DEBUG_GIST - elog(NOTICE,"GIST: gbox_penalty called\n"); - fflush( stdout ); -#endif - - ud = DirectFunctionCall2(rt_box_union, origentry->key, newentry->key); - tmp1 = size_box(ud); - if (DatumGetPointer(ud) != NULL) - pfree(DatumGetPointer(ud)); - - *result = tmp1 - size_box(origentry->key); - PG_RETURN_POINTER(result); -} - -typedef struct { - BOX *key; - int pos; -} KBsort; - -static int -compare_KB(const void* a, const void* b) { - BOX *abox = ((KBsort*)a)->key; - BOX *bbox = ((KBsort*)b)->key; - float sa = (abox->high.x - abox->low.x) * (abox->high.y - abox->low.y); - float sb = (bbox->high.x - bbox->low.x) * (bbox->high.y - bbox->low.y); - - if ( sa==sb ) return 0; - return ( sa>sb ) ? 1 : -1; -} - -/* -** The GiST PickSplit method -** New linear algorithm, see 'New Linear Node Splitting Algorithm for R-tree', -** C.H.Ang and T.C.Tan -*/ -PG_FUNCTION_INFO_V1(gbox_picksplit); -Datum -gbox_picksplit(PG_FUNCTION_ARGS) -{ -#if USE_VERSION < 80 - bytea *entryvec = (bytea *) PG_GETARG_POINTER(0); -#else - GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0); -#endif - GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1); - OffsetNumber i; - OffsetNumber *listL, - *listR, - *listB, - *listT; - BOX *unionL, - *unionR, - *unionB, - *unionT; - int posL, - posR, - posB, - posT; - BOX pageunion; - BOX *cur; - char direction = ' '; - bool allisequal = true; - OffsetNumber maxoff; - int nbytes; - -#ifdef DEBUG_GIST - elog(NOTICE,"GIST: gbox_picksplit called\n"); - fflush( stdout ); -#endif - - posL = posR = posB = posT = 0; -#if USE_VERSION < 80 - maxoff = ((VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY)) - 1; - cur = DatumGetBoxP(((GISTENTRY *) VARDATA(entryvec))[FirstOffsetNumber].key); -#else - maxoff = entryvec->n - 1; - cur = DatumGetBoxP(entryvec->vector[FirstOffsetNumber].key); -#endif - - memcpy((void *) &pageunion, (void *) cur, sizeof(BOX)); - - /* find MBR */ - for (i = OffsetNumberNext(FirstOffsetNumber); i <= maxoff; i = OffsetNumberNext(i)) - { -#if USE_VERSION < 80 - cur = DatumGetBoxP(((GISTENTRY *) VARDATA(entryvec))[i].key); -#else - cur = DatumGetBoxP(entryvec->vector[i].key); -#endif - if ( allisequal == true && ( - pageunion.high.x != cur->high.x || - pageunion.high.y != cur->high.y || - pageunion.low.x != cur->low.x || - pageunion.low.y != cur->low.y - ) ) - allisequal = false; - - if (pageunion.high.x < cur->high.x) - pageunion.high.x = cur->high.x; - if (pageunion.low.x > cur->low.x) - pageunion.low.x = cur->low.x; - if (pageunion.high.y < cur->high.y) - pageunion.high.y = cur->high.y; - if (pageunion.low.y > cur->low.y) - pageunion.low.y = cur->low.y; - } - - nbytes = (maxoff + 2) * sizeof(OffsetNumber); - listL = (OffsetNumber *) palloc(nbytes); - listR = (OffsetNumber *) palloc(nbytes); - unionL = (BOX *) palloc(sizeof(BOX)); - unionR = (BOX *) palloc(sizeof(BOX)); - if (allisequal) - { -#if USE_VERSION < 80 - cur = DatumGetBoxP(((GISTENTRY *) VARDATA(entryvec))[OffsetNumberNext(FirstOffsetNumber)].key); -#else - cur = DatumGetBoxP(entryvec->vector[OffsetNumberNext(FirstOffsetNumber)].key); -#endif - if (memcmp((void *) cur, (void *) &pageunion, sizeof(BOX)) == 0) - { - v->spl_left = listL; - v->spl_right = listR; - v->spl_nleft = v->spl_nright = 0; - memcpy((void *) unionL, (void *) &pageunion, sizeof(BOX)); - memcpy((void *) unionR, (void *) &pageunion, sizeof(BOX)); - - for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) - { - if (i <= (maxoff - FirstOffsetNumber + 1) / 2) - { - v->spl_left[v->spl_nleft] = i; - v->spl_nleft++; - } - else - { - v->spl_right[v->spl_nright] = i; - v->spl_nright++; - } - } - v->spl_ldatum = BoxPGetDatum(unionL); - v->spl_rdatum = BoxPGetDatum(unionR); - - PG_RETURN_POINTER(v); - } - } - - listB = (OffsetNumber *) palloc(nbytes); - listT = (OffsetNumber *) palloc(nbytes); - unionB = (BOX *) palloc(sizeof(BOX)); - unionT = (BOX *) palloc(sizeof(BOX)); - -#define ADDLIST( list, unionD, pos, num ) do { \ - if ( pos ) { \ - if ( unionD->high.x < cur->high.x ) unionD->high.x = cur->high.x; \ - if ( unionD->low.x > cur->low.x ) unionD->low.x = cur->low.x; \ - if ( unionD->high.y < cur->high.y ) unionD->high.y = cur->high.y; \ - if ( unionD->low.y > cur->low.y ) unionD->low.y = cur->low.y; \ - } else { \ - memcpy( (void*)unionD, (void*) cur, sizeof( BOX ) ); \ - } \ - list[pos] = num; \ - (pos)++; \ -} while(0) - - for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) - { -#if USE_VERSION < 80 - cur = DatumGetBoxP(((GISTENTRY *) VARDATA(entryvec))[i].key); -#else - cur = DatumGetBoxP(entryvec->vector[i].key); -#endif - if (cur->low.x - pageunion.low.x < pageunion.high.x - cur->high.x) - ADDLIST(listL, unionL, posL,i); - else - ADDLIST(listR, unionR, posR,i); - - if (cur->low.y - pageunion.low.y < pageunion.high.y - cur->high.y) - ADDLIST(listB, unionB, posB,i); - else - ADDLIST(listT, unionT, posT,i); - } - - /* bad disposition, sort by ascending and resplit */ - if ( (posR==0 || posL==0) && (posT==0 || posB==0) ) { - KBsort *arr = (KBsort*)palloc( sizeof(KBsort) * maxoff ); - posL = posR = posB = posT = 0; - for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) { -#if USE_VERSION < 80 - arr[i-1].key = DatumGetBoxP(((GISTENTRY *) VARDATA(entryvec))[i].key); -#else - arr[i-1].key = DatumGetBoxP(entryvec->vector[i].key); -#endif - arr[i-1].pos = i; - } - qsort( arr, maxoff, sizeof(KBsort), compare_KB ); - for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) { - cur = arr[i-1].key; - if (cur->low.x - pageunion.low.x < pageunion.high.x - cur->high.x) - ADDLIST(listL, unionL, posL,arr[i-1].pos); - else if ( cur->low.x - pageunion.low.x > pageunion.high.x - cur->high.x ) - ADDLIST(listR, unionR, posR,arr[i-1].pos); - else - { - if ( posL>posR ) - ADDLIST(listR, unionR, posR,arr[i-1].pos); - else - ADDLIST(listL, unionL, posL,arr[i-1].pos); - } - - if (cur->low.y - pageunion.low.y < pageunion.high.y - cur->high.y) - ADDLIST(listB, unionB, posB,arr[i-1].pos); - else if ( cur->low.y - pageunion.low.y > pageunion.high.y - cur->high.y ) - ADDLIST(listT, unionT, posT,arr[i-1].pos); - else - { - if ( posB>posT ) - ADDLIST(listT, unionT, posT,arr[i-1].pos); - else - ADDLIST(listB, unionB, posB,arr[i-1].pos); - } - } - pfree(arr); - } - - /* which split more optimal? */ - if (Max(posL, posR) < Max(posB, posT)) - direction = 'x'; - else if (Max(posL, posR) > Max(posB, posT)) - direction = 'y'; - else - { - Datum interLR = DirectFunctionCall2(rt_box_inter, - BoxPGetDatum(unionL), - BoxPGetDatum(unionR)); - Datum interBT = DirectFunctionCall2(rt_box_inter, - BoxPGetDatum(unionB), - BoxPGetDatum(unionT)); - float sizeLR, - sizeBT; - - sizeLR = size_box(interLR); - sizeBT = size_box(interBT); - - if (sizeLR < sizeBT) - direction = 'x'; - else - direction = 'y'; - } - - if (direction == 'x') - { - pfree(unionB); - pfree(listB); - pfree(unionT); - pfree(listT); - - v->spl_left = listL; - v->spl_right = listR; - v->spl_nleft = posL; - v->spl_nright = posR; - v->spl_ldatum = BoxPGetDatum(unionL); - v->spl_rdatum = BoxPGetDatum(unionR); - } - else - { - pfree(unionR); - pfree(listR); - pfree(unionL); - pfree(listL); - - v->spl_left = listB; - v->spl_right = listT; - v->spl_nleft = posB; - v->spl_nright = posT; - v->spl_ldatum = BoxPGetDatum(unionB); - v->spl_rdatum = BoxPGetDatum(unionT); - } - - PG_RETURN_POINTER(v); -} - -/* -** Equality method -*/ -PG_FUNCTION_INFO_V1(gbox_same); -Datum gbox_same(PG_FUNCTION_ARGS) -{ - BOX *b1 = (BOX *) PG_GETARG_POINTER(0); - BOX *b2 = (BOX *) PG_GETARG_POINTER(1); - bool *result = (bool *) PG_GETARG_POINTER(2); - -#ifdef DEBUG_GIST - elog(NOTICE,"GIST: gbox_same called\n"); - fflush( stdout ); -#endif - - if (b1 && b2) - *result = DatumGetBool(DirectFunctionCall2(box_same, PointerGetDatum(b1), PointerGetDatum(b2))); - else - *result = (b1 == NULL && b2 == NULL) ? TRUE : FALSE; - PG_RETURN_POINTER(result); -} - -static float -size_box(Datum box) -{ - -#ifdef DEBUG_GIST - elog(NOTICE,"GIST: size_box called\n"); - fflush( stdout ); -#endif - - if (DatumGetPointer(box) != NULL) - { - float size; - - DirectFunctionCall2(rt_box_size, - box, PointerGetDatum(&size)); - return size; - } - else - return 0.0; -} diff --git a/hwgeom/postgis_inout.c b/hwgeom/postgis_inout.c deleted file mode 100644 index d12ccdfa5..000000000 --- a/hwgeom/postgis_inout.c +++ /dev/null @@ -1,4906 +0,0 @@ - -/********************************************************************** - * $Id$ - * - * PostGIS - Spatial Types for PostgreSQL - * http://postgis.refractions.net - * Copyright 2001-2003 Refractions Research Inc. - * - * This is free software; you can redistribute and/or modify it under - * the terms of the GNU General Public Licence. See the COPYING file. - * - ********************************************************************** - * $Log$ - * Revision 1.1 2004/09/20 07:50:06 strk - * prepared to contain old internal representation code - * - * Revision 1.45 2004/08/11 17:07:26 strk - * Fixed a bug in non-finite Z check - * - * Revision 1.44 2004/06/09 09:08:53 strk - * changed index/rindex to strchr/strrchr - * - * Revision 1.43 2004/06/08 15:18:12 strk - * Deleted prototype for isspace() in postgis.h - * and included in postgis_inout.c, - * which is the only module calling isspace(). - * This was needed to compile postgis against PG75(CVS). - * - * Revision 1.42 2004/06/03 09:45:57 strk - * infinite geoms handled in WKB parser - * - * Revision 1.41 2004/06/03 08:19:20 strk - * yet another Infinite check used: finite() - which checks for NaN,-Inf,+Inf - * - * Revision 1.40 2004/06/03 08:13:11 strk - * Simplified INFINITY checks by use of isinf() - * - * Revision 1.39 2004/06/03 07:57:29 strk - * wkt parser throws an error on Infinite coordinates - * - * Revision 1.38 2004/04/28 22:26:02 pramsey - * Fixed spelling mistake in header text. - * - * Revision 1.37 2004/04/27 23:47:39 dblasby - * minor 3d geometrycollection bug fix - * - * Revision 1.36 2004/01/13 22:14:25 pramsey - * Changed getint and getdouble used by WKB so that it plays nice with - * memory alignment (solaris issue). - * - * Revision 1.35 2003/12/12 18:00:15 strk - * reverted make_line patch, patched size_subobject instead - the reported bug was caused to their inconsistency - * - * Revision 1.34 2003/12/12 14:39:04 strk - * Fixed a bug in make_line allocating less memory then required - * - * Revision 1.33 2003/12/12 12:03:30 strk - * More debugging output, some code cleanup. - * - * Revision 1.32 2003/12/09 11:58:42 strk - * Final touch to wkb binary input function - * - * Revision 1.31 2003/12/09 11:13:41 strk - * WKB_recv: set StringInfo cursor to the end of StringInfo buf as required by postgres backend - * - * Revision 1.30 2003/12/08 17:57:36 strk - * Binary WKB input function built only when USE_VERSION > 73. Making some modifications based on reported failures - * - * Revision 1.29 2003/11/28 11:06:49 strk - * Added WKB_recv function for binary WKB input - * - * Revision 1.28 2003/10/06 18:09:08 dblasby - * Fixed typo in add_to_geometry(). With very poorly aligned sub-objects, it - * wouldnt allocate enough memory. Fixed it so its pesimistic and will allocate - * enough memory. - * - * Revision 1.27 2003/08/22 17:40:11 dblasby - * fixed geometry_in('SRID={no ;}'). - * - * Revision 1.26 2003/08/21 16:22:09 dblasby - * added patch from strk@freek.keybit.net for PG_NARGS() not being in 7.2 - * - * Revision 1.25 2003/08/08 18:19:20 dblasby - * Conformance changes. - * Removed junk from postgis_debug.c and added the first run of the long - * transaction locking support. (this will change - dont use it) - * conformance tests were corrected - * some dos cr/lf removed - * empty geometries i.e. GEOMETRYCOLLECT(EMPTY) added (with indexing support) - * pointN(,1) now returns the first point (used to return 2nd) - * - * Revision 1.24 2003/08/06 19:31:18 dblasby - * Added the WKB parser. Added all the functions like - * PolyFromWKB(,[]). - * - * Added all the functions like PolyFromText(,[]) - * - * Minor problem in GEOS library fixed. - * - * Revision 1.23 2003/07/25 17:08:37 pramsey - * Moved Cygwin endian define out of source files into postgis.h common - * header file. - * - * Revision 1.22 2003/07/08 18:35:54 dblasby - * changed asbinary_specify() so that it is more aware of TEXT being - * un-terminated. - * - * this is a modified patch from David Garnier . - * - * Revision 1.21 2003/07/01 18:30:55 pramsey - * Added CVS revision headers. - * - * - **********************************************************************/ - -#include "postgres.h" - - -#include -#include -#include -#include -#include -#include - -#include "access/gist.h" -#include "access/itup.h" -#include "access/rtree.h" - - -#include "fmgr.h" - - -#include "postgis.h" -#if USE_VERSION > 73 -# include "lib/stringinfo.h" // for WKB binary input -#endif -#include "utils/elog.h" - - -#define SHOW_DIGS_DOUBLE 16 -#define MAX_DIGS_DOUBLE (SHOW_DIGS_DOUBLE + 6 + 1 + 3 +1) - - -// #define DEBUG_GIST -//#define DEBUG_GIST2 - - -#define WKB3DOFFSET 0x80000000 - - -void swap_char(char *a,char *b) -{ - char c; - - c = *a; - *a=*b; - *b=c; -} - - -void flip_endian_double(char *d) -{ - swap_char(d+7, d); - swap_char(d+6, d+1); - swap_char(d+5, d+2); - swap_char(d+4, d+3); -} - -void flip_endian_int32(char *i) -{ - swap_char (i+3,i); - swap_char (i+2,i+1); -} - - - -//takes a point and sticks it at the end of a string -void print_point(char *result, POINT3D *pt,bool is3d) -{ - char temp[MAX_DIGS_DOUBLE*3 +6]; - - - if ( (pt == NULL) || (result == NULL) ) - return; - - if (is3d) - sprintf(temp, "%.15g %.15g %.15g", pt->x,pt->y,pt->z); - else - sprintf(temp, "%.15g %.15g", pt->x,pt->y); - - strcat(result,temp); - -} - -//result MUST BE null terminated (or result[0] = 0) -void print_many_points(char *result, POINT3D *pt ,int npoints, bool is3d) -{ - int u; - - result += strlen(result); - if (is3d) - { - for (u=0;u 2 (2nd list is not included) -int numb_points_in_list(char *str) -{ - bool keep_going; - int points_found = 1; //no "," if only one point (and last point) - // # points = 1 + numb of "," - - if ( (str == NULL) || (str[0] == 0) ) - { - return 0; //either null string or empty string - } - - //look ahead for the "(" - - str = strchr(str,'(') ; - - if ( (str == NULL) || (str[1] == 0) ) // str[0] = '('; - { - return 0; //either didnt find "(" or its at the end of the string - } - - keep_going = TRUE; - while (keep_going) - { - str=strpbrk(str,",)"); // look for a "," or ")" - keep_going = (str != NULL); - if (keep_going) // found a , or ) - { - if (str[0] == ')') - { - //finished - return points_found; - } - else //str[0] = "," - { - points_found++; - str++; //move 1 char forward - } - } - } - return points_found; // technically it should return an error. -} - -//Actually parse the points in a list -// "(1 2 3, 4 5 6),(7 8, 9 10, 11 12 13)" => -// points[0] = {1,2,3} and points[1] = {4,5,6} -// (2nd list is not parsed) -// -// parse at most max_points (points should already have enough space) -// if any of the points are 3d, is3d is set to true, otherwise its untouched. -// 2d points have z=0.0 -// -// returns true if everything parses okay, otherwise false - -bool parse_points_in_list(char *str, POINT3D *points, int32 max_points, bool *is3d) -{ - bool keep_going; - int numb_found= 0; - int num_entities; - - if ( (str == NULL) || (str[0] == 0) || (max_points <0) || (points == NULL) ) - { - return FALSE; //either null string or empty string or other problem - } - - if (max_points == 0) - return TRUE; //ask for nothing, get nothing - - //look ahead for the "(" - - str = strchr(str,'(') ; - - if ( (str == NULL) || (str[1] == 0) ) // str[0] = '('; - { - return FALSE; //either didnt find "(" or its at the end of the string - } - str++; //move forward one char - - keep_going = TRUE; - while (keep_going) - { - //attempt to get the point - num_entities = sscanf(str,"%le %le %le", - &(points[numb_found].x), - &(points[numb_found].y), - &(points[numb_found].z)); - - if (num_entities !=3) - { - if (num_entities !=2 ) - { - elog(ERROR, "geom3d: parse_points_in_list() on invalid point"); - return FALSE; //error - } - else - { - points[numb_found].z = 0.0; //2d (only found x,y - set z =0.0) - } - } - else - { - *is3d = TRUE; //found 3 entites (x,y,z) - } - - if ( ! finite(points[numb_found].x) || - ! finite(points[numb_found].y) ) - { - elog(ERROR, "infinite coordinate in geom"); - return FALSE; - } - numb_found++; - - str=strpbrk(str,",)"); // look for a "," or ")" - if (str != NULL) - str++; - keep_going = ( (str != NULL) && (str[0] != ')' ) && (numb_found < max_points) ); - } - return TRUE; -} - - -//Actually parse the points in a list -// "(1 2 3, 4 5 6),(7 8, 9 10, 11 12 13)" => -// points[0] = {1,2,3} and points[1] = {4,5,6} -// (2nd list is not parsed) -// -// parse at most max_points (points should already have enough space) -// if any of the points are 3d, is3d is set to true, otherwise its untouched. -// 2d points have z=0.0 -// -// returns true if everything parses okay, otherwise false -// -// THIS IS EXACTLY the same as parse_points_in_list(), but returns FALSE if -// the number of points parsed is != max_points - -bool parse_points_in_list_exact(char *str, POINT3D *points, int32 max_points, bool *is3d) -{ - bool keep_going; - int numb_found= 0; - - char *end_of_double; - - if ( (str == NULL) || (str[0] == 0) || (max_points <0) || (points == NULL) ) - { - return FALSE; //either null string or empty string or other problem - } - - if (max_points == 0) - return TRUE; //ask for nothing, get nothing - - //look ahead for the "(" - - str = strchr(str,'(') ; - - if ( (str == NULL) || (str[1] == 0) ) // str[0] = '('; - { - return FALSE; //either didnt find "(" or its at the end of the string - } - str++; //move forward one char - - keep_going = TRUE; - while (keep_going) - { - //attempt to get the point - - //scanf is slow, so we use strtod() - - - points[numb_found].x = strtod(str,&end_of_double); - if (end_of_double == str) - { - return FALSE; //error occured (nothing parsed) - } - str = end_of_double; - if ( ! finite(points[numb_found].x) ) - { - elog(ERROR, "infinite coordinate in geom"); - return FALSE; - } - points[numb_found].y = strtod(str,&end_of_double); - if (end_of_double == str) - { - return FALSE; //error occured (nothing parsed) - } - if ( ! finite(points[numb_found].y) ) - { - elog(ERROR, "infinite coordinate in geom"); - return FALSE; - } - str = end_of_double; - points[numb_found].z = strtod(str,&end_of_double); //will be zero if error occured - if (!(end_of_double == str)) - { - if ( ! finite(points[numb_found].z) ) - { - elog(ERROR, "infinite coordinate in geom"); - return FALSE; - } - *is3d = TRUE; //found 3 entites (x,y,z) - } - else - { - points[numb_found].z = 0.0; - } - str = end_of_double; - numb_found++; - - - - str=strpbrk(str,",)"); // look for a "," or ")" - if (str != NULL) - str++; - keep_going = ( (str != NULL) && (str[0] != ')' ) && (numb_found < max_points) ); - } - return (numb_found == max_points); -} - - - - -// Find the number of sub lists in a list -// ( (..),(..),(..) ) -> 3 -// ( ( (..),(..) ), ( (..) )) -> 2 -// ( ) -> 0 -// scan through the list, for every "(", depth (nesting) increases by 1 -// for every ")", depth (nesting) decreases by 1 -// if find a "(" at depth 1, then there is a sub list -// -// example: -// "(((..),(..)),((..)))" -//depth 12333223332112333210 -// + + increase here - -int find_outer_list_length(char *str) -{ - int current_depth = 0; - int numb_lists = 0; - - - while ( (str != NULL) && (str[0] != 0) ) - { - str=strpbrk(str,"()"); //look for "(" or ")" - if (str != NULL) - { - if (str[0] == '(') - { - current_depth++; - if (current_depth == 2) - numb_lists ++; - } - if (str[0] == ')') - { - current_depth--; - if (current_depth == 0) - return numb_lists ; - } - str++; - } - } - return numb_lists ; // probably should give an error -} - - -// Find out how many points are in each sublist, put the result in the array npoints[] -// (for at most max_list sublists) -// -// ( (L1),(L2),(L3) ) --> npoints[0] = points in L1, -// npoints[1] = points in L2, -// npoints[2] = points in L3 -// -// We find these by, again, scanning through str looking for "(" and ")" -// to determine the current depth. We dont actually parse the points. - -bool points_per_sublist( char *str, int32 *npoints, int32 max_lists) -{ - //scan through, noting depth and ","s - - int current_depth = 0; - int current_list =-1 ; - - - while ( (str != NULL) && (str[0] != 0) ) - { - str=strpbrk(str,"(),"); //find "(" or ")" or "," - if (str != NULL) - { - if (str[0] == '(') - { - current_depth++; - if (current_depth == 2) - { - current_list ++; - if (current_list >=max_lists) - return TRUE; // too many sub lists found - npoints[current_list] = 1; - } - // might want to return an error if depth>2 - } - if (str[0] == ')') - { - current_depth--; - if (current_depth == 0) - return TRUE ; - } - if (str[0] == ',') - { - if (current_depth==2) - { - npoints[current_list] ++; - } - } - - str++; - } - } - return TRUE ; // probably should give an error -} - - - - -//simple scan-forward to find the next "(" at the same level -// ( (), (),(), ),(... -// + return this location -char *scan_to_same_level(char *str) -{ - - //scan forward in string looking for at "(" at the same level - // as the one its already pointing at - - int current_depth = 0; - bool first_one=TRUE; - - - while ( (str != NULL) && (str[0] != 0) ) - { - str=strpbrk(str,"()"); - if (str != NULL) - { - if (str[0] == '(') - { - if (!(first_one)) - { - if (current_depth == 0) - return str; - } - else - first_one = FALSE; //ignore the first opening "(" - current_depth++; - } - if (str[0] == ')') - { - current_depth--; - } - - str++; - } - } - return str ; // probably should give an error -} - - -/* - * BOX3D_in - takes a string rep of BOX3D and returns internal rep - * - * example: - * "BOX3D(x1 y1 z1,x2 y2 z2)" - * or "BOX3D(x1 y1,x2 y2)" z1 and z2 = 0.0 - * - * - */ - -BOX3D *parse_box3d(char *str) -{ - - BOX3D *bbox = (BOX3D *) palloc(sizeof(BOX3D)); - bool junk_bool; - bool okay; - int npoints; - - - //verify that there are exactly two points - - //strip leading spaces - while (isspace((unsigned char) *str)) - str++; -//printf( "box3d_in gets '%s'\n",str); - - if (strstr(str,"BOX3D") != str ) - { - elog(ERROR,"BOX3D parser - doesnt start with BOX3D"); - pfree(bbox); - return NULL; - } - - if ((npoints = numb_points_in_list(str)) != 2) - { -//printf("npoints in this bbox is %i, should be 2\n",npoints); - elog(ERROR,"BOX3D parser - number of points should be exactly 2"); - pfree(bbox); - return NULL; - } - - //want to parse two points, and dont care if they are 2d or 3d - okay = parse_points_in_list(str, &(bbox->LLB), 2, &junk_bool); - if (okay == 0) - { - elog(ERROR,"box3d: couldnt parse: '%s'\n",str); - pfree(bbox); - return NULL; - } - - - //validate corners so LLB is mins of x,y,z and URT is maxs x,y,z - if ( bbox->LLB.x > bbox->URT.x) - { - swap ( &bbox->LLB.x , &bbox->URT.x ) ; - } - if ( bbox->LLB.y > bbox->URT.y) - { - swap ( &bbox->LLB.y , &bbox->URT.y ); - } - if ( bbox->LLB.z > bbox->URT.z) - { - swap ( &bbox->LLB.z , &bbox->URT.z ) ; - } - - return bbox; -} - -PG_FUNCTION_INFO_V1(box3d_in); -Datum box3d_in(PG_FUNCTION_ARGS) -{ - char *str = PG_GETARG_CSTRING(0); - BOX3D *bbox ; - - bbox = parse_box3d(str); - if (bbox != NULL) - PG_RETURN_POINTER(bbox); - else - PG_RETURN_NULL(); -} - -/* - * Takes an internal rep of a BOX3D and returns a string rep. - * - * example: - * "BOX3D(LLB.x LLB.y LLB.z, URT.x URT.y URT.z)" - */ -PG_FUNCTION_INFO_V1(box3d_out); -Datum box3d_out(PG_FUNCTION_ARGS) -{ - BOX3D *bbox = (BOX3D *) PG_GETARG_POINTER(0); - int size; - char *result; - - if (bbox == NULL) - { - result = palloc(5); - strcat(result,"NULL"); - PG_RETURN_CSTRING(result); - } - - size = MAX_DIGS_DOUBLE*6+5+2+4+5+1; - result = (char *) palloc(size); //double digits+ "BOX3D"+ "()" + commas +null - sprintf(result, "BOX3D(%.15g %.15g %.15g,%.15g %.15g %.15g)", - bbox->LLB.x,bbox->LLB.y,bbox->LLB.z, - bbox->URT.x,bbox->URT.y,bbox->URT.z); - - PG_RETURN_CSTRING(result); -} - -/*************************************************************** - * these functions return the number of sub-objects inside a - * sub-portion of a string. - * - * LINESTRING(), POLYGON(), POINT() allways have 1 sub object - * - * MULTIPOLYGON() MULTILINESTRING() MULTIPOINT() will have a variable number of sub-parts - * ex MULTIPOINT(1 1 1, 2 2 2,3 3 3,4 4 4) -->4 because there are 4 points in it - * - * GEOMETRYCOLLECTION() - need to look at each sub-object in the collection - ***************************************************************/ - -//number of object inside a point -int objects_inside_point(char *str) -{ - return 1; //trivial points always have 1 point in them -} - - -//number of object inside a line -int objects_inside_line(char *str) -{ - return 1; //trivial lines always have 1 line in them -} - -//number of object inside a polygon -int objects_inside_polygon(char *str) -{ - return 1; //trivial polygon always have 1 polygon in them -} - - -//bit more complicated - need to find out how many points are in this entity -int objects_inside_multipoint(char *str) -{ - return numb_points_in_list(str); -} - -//bit more complicated - need to find out how many lines are in this entity -int objects_inside_multiline(char *str) -{ - return find_outer_list_length(str); -} - - -//bit more complicated - need to find out how many polygons are in this entity -int objects_inside_multipolygon(char *str) -{ - return find_outer_list_length(str); -} - - - -//This one is more complicated, we have to look at each of the sub-object inside -// the collection. -// result = sum of ( number of objects in each of the collection's sub-objects ) -// -// EX: 'GEOMETRYCOLLECTION( POINT(1 2 3), -// POINT (4 5 6) ), -// LINESTRING(3 4 5,1 2 3,5 6 0), -// MULTILINESTRING((3 4 5,1 2 3,5 6 0)), -// MULTIPOINT(1 2 3), -// MULTILINESTRING((3 4 5,1 2 3,5 6 0),(1 2 0,4 5 0,6 7 0,99 99 0)), -// MULTIPOLYGON (( (3 4 5,1 2 3,5 6),(1 2, 4 5, 6 7) ), ( (11 11, 22 22, 33 33),(44 44, 55 55, 66 66) ) )' -// -// # object = # of objs in POINT (1) + # of objs in POINT (1) + # of objs in LINESTRING (1) -// + # of objs in MULTILINESTRING (1) + # of objs in MULTIPOINT (1) -// + # of objs in MULTILINESTRING (1) + # of objs in MULTIPOLYGON (2) - -int objects_inside_collection(char *str) -{ - int tally = 0; - int sub_size = 0; - - //skip past the "geometrycollection" at begining of string - str += 18; - if (strstr(str, "GEOMETRYCOLLECTION") != NULL) - return -1; // collection inside collection; bad boy! - - //we scan to the first letter, then pass it to objects inside - // to find out how many sub-objects there are. Then move to - // the next object - - - while ( str != NULL) - { - //scan for a letter (all objs start with M, P, or L - str = strpbrk(str,"MPL"); //search for MULTI*, POLY*, POIN* - if (str != NULL) - { - //object found - sub_size = objects_inside(str); //how many in this object - if (sub_size == -1) - return -1;//relay error - - tally += sub_size; // running total - - //need to move to next item - // by scanning past any letters - str = strchr(str,'('); //need to move to the next sub-object - } - } - return tally; -} - - -// Find the # of sub-objects inside the geometry -// Just pass it off to the other functions -int objects_inside(char *str) -{ - - char *parenth; - char *loc; - - - parenth = strchr(str,'('); - if (parenth == NULL) - return -1; //invalid string - - // look only at the begining of the string - // the order of these "if" are important! - - if ( ((loc = strstr(str, "GEOMETRYCOLLECTION")) != NULL) && (loc < parenth) ) - return objects_inside_collection(str); - - // do multi before base types (MULTIPOINT has the string "POINT" in it) - - if (((loc = strstr(str,"MULTIPOINT")) != NULL) && (loc < parenth) ) - return objects_inside_multipoint(str); - if (((loc = strstr(str,"MULTILINESTRING") )!= NULL) && (loc < parenth) ) - return objects_inside_multiline(str); - if (((loc = strstr(str,"MULTIPOLYGON")) != NULL) && (loc < parenth) ) - return objects_inside_multipolygon(str); - - //base types - if (((loc = strstr(str,"POINT")) != NULL) && (loc < parenth) ) - return objects_inside_point(str); - if (((loc = strstr(str,"LINESTRING")) != NULL) && (loc < parenth) ) - return objects_inside_line(str); - if (((loc = strstr(str,"POLYGON")) != NULL) && (loc < parenth) ) - return objects_inside_polygon(str); - - return -1; //invalid - -} - - -/**************************************************************************** - * These functions actually parse the objects in the strings - * They all have arguments: - * obj_size[] -- size (in bytes) of each the sub-objects - * objs[][] -- list of pointers to the actual objects - * obj_types -- type of the sub-obj (see postgis.h) - * nobjs -- max number of sub-obj - * str -- actual string to parse from (start at begining) - * offset -- which sub-object # are we dealing with - * is3d -- are any of the points in the object 3d? - * - * basically, each of the functions will: - * + parse str to find the information required - * + allocate a new obj(s) and place it/them in objs to hold this info - * + set the obj_size for this/these sub-object - * + set the obj_type for this/these sub-object - * + increase offset so the next objects will go in the correct place - * + set is3d if there are any 3d points in the sub-object - * + return FALSE if an error occured - ****************************************************************************/ - - -//parse a point - make a new POINT3D object -bool parse_objects_inside_point(int32 *obj_size,char **objs, int32 *obj_types, int32 nobjs, char *str, int *offset, bool* is3d) -{ - bool result; - - if (*offset >= nobjs) - return FALSE; //too many objs found - - objs[*offset] = palloc (sizeof(POINT3D) ); - memset(objs[*offset], 0, sizeof(POINT3D) ); // zero memory - obj_types[*offset] = POINTTYPE; - obj_size[*offset] = sizeof(POINT3D); - - str = strchr(str,'('); - if (str == NULL) - return FALSE; // parse error - -//printf("about to parse the point\n"); - - result = parse_points_in_list_exact(str, (POINT3D*) objs[*offset] , 1, is3d); -//printf(" +point parsed\n"); - - *offset = *offset + 1; - return (result); // pass along any parse error -} - - -//parse a multipoint object - offset may increase by >1 -// multiple sub object may be created -bool parse_objects_inside_multipoint(int32 *obj_size,char **objs, int32 *obj_types, int32 nobjs, char *str, int *offset, bool* is3d) -{ - bool result; - int npoints; - int t; - POINT3D *pts; - - // first find out how many points are in the multi-point - npoints = objects_inside_multipoint(str); - - if (npoints <0) - return FALSE; // error in parsing (should have been caught before) - - if (npoints ==0) - return TRUE; //no points, no nothing - - if (*offset >= nobjs) - return FALSE; //too many objs found dont do anything, relay error - - - str = strchr(str,'('); - if (str == NULL) - return FALSE; - - //allocate all the new objects - pts = palloc( sizeof(POINT3D) * npoints); - for (t=0;t make it two on top of each other - - - if (*offset >= nobjs) - return FALSE; //too many objs found - - //how many points are in this linestring? - num_points = numb_points_in_list(str); - - if (num_points == 0) - return FALSE; - - - if (num_points == 1) //not really a line - { - num_points = 2; - add_point = TRUE; - } - - - - // -1 because object already has 1 point in it - objs[*offset] = palloc (sizeof(LINE3D) + sizeof(POINT3D)*(num_points-1) ); - memset(objs[*offset], 0, sizeof(LINE3D) + sizeof(POINT3D)*(num_points-1) ); // zero memory - - obj_types[*offset] = LINETYPE; - obj_size[*offset] = sizeof(LINE3D) + sizeof(POINT3D)*(num_points-1) ; - - str = strchr(str,'('); - if (str == NULL) - return FALSE; - - ( (LINE3D *) objs[*offset] )->npoints = num_points; - - if (add_point) - { - result = parse_points_in_list_exact(str, &(( (LINE3D*) objs[*offset]) ->points[0]) , num_points-1, is3d); - } - else - { - result = parse_points_in_list_exact(str, &(( (LINE3D*) objs[*offset]) ->points[0]) , num_points, is3d); - } - - if (add_point) - { - memcpy( &(( (LINE3D*) objs[*offset]) ->points[1]) , &(( (LINE3D*) objs[*offset]) ->points[0]) , sizeof(POINT3D) ); - } - - *offset = *offset + 1; - return (result); -} - - - -//parse a multi-line. For each sub-linestring, call the parse_objects_inside_line() function -// 'MULTILINESTRING((3 4 5,1 2 3,5 6 0),(1 2 0,4 5 0,6 7 0,99 99 0))' -// first scan to the second "(" - this is the begining of the first linestring. -// scan it, then move to the second linestring -bool parse_objects_inside_multiline(int32 *obj_size,char **objs, int32 *obj_types, int32 nobjs, char *str, int *offset, bool* is3d) -{ - bool result; - int num_lines; - int t; - - - //how many lines are there? - num_lines = objects_inside_multiline(str); - - - if (num_lines <0) - return FALSE; - - if (num_lines ==0) - return TRUE; //can be nothing - - - if (*offset >= nobjs) - return FALSE; //too many objs found - - str= strchr(str,'('); //first one - if (str != NULL) - str++; - str= strchr(str,'('); //2nd one - - if (str == NULL) - return FALSE; // couldnt find it - - for (t=0;t= nobjs) - return FALSE; //too many objs found - - //find out how many rings there are - num_rings = find_outer_list_length(str); - - if (num_rings <1) - return FALSE; // must have at least one ring - - //allocate space for how many points in each ring - npoints = palloc( sizeof(int32) * num_rings); - - //find out how many points are in each sub-list (ring) - result = points_per_sublist(str,npoints, num_rings); - - //how many points are inside this polygon in total? - sum_points =0; - for(t=0; t< num_rings ; t++) - { - sum_points += npoints[t]; - if (npoints[t] <3) - { - elog(ERROR,"polygon has ring with <3 points."); - pfree(npoints); - return FALSE; - } - } - - //now we can allocate the structure - - - // -1 because the POLYGON3D already has space for 1 ring with 1 point - // 4 is for possible double-word alignment - size = sizeof(POLYGON3D) + sizeof(int32)*(num_rings-1) +4+ sizeof(POINT3D)*(sum_points-1) ; - objs[*offset] = palloc (size); - memset(objs[*offset], 0, size ); // zero memory - - polygon = (POLYGON3D *) objs[*offset]; - obj_types[*offset] = POLYGONTYPE; - obj_size[*offset] = size; - - str = strchr(str,'('); - if (str == NULL) - { - pfree(npoints); - return FALSE; - } - str++; - - polygon->nrings = num_rings; - - pts = (POINT3D *) &(polygon->npoints[num_rings]); //pts[] is just past the end of npoints[] - - // make sure its double-word aligned - - pts = (POINT3D *) MAXALIGN(pts); - - -//printf("POLYGON is at %p, size is %i, pts is at %p (%i)\n",objs[*offset],size, pts, ((void *) pts) - ((void *)objs[*offset]) ); -//printf("npoints[0] is at %p, num_rings=%i\n", &(((POLYGON3D *) objs[*offset])->npoints[0] ), num_rings ); - - points_offset = 0; - for(t=0;tnpoints[t] = npoints[t]; // set # pts in this ring - - //use exact because it will screw up otherwise -//printf("about to parse the actual points in ring #%i with %i points:\n",t,npoints[t]); - result = parse_points_in_list_exact(str, - &pts[points_offset], - npoints[t], is3d); -//printf(" +done parsing points\n"); - -//printf("1st points in ring is: [%g,%g,%g]\n", pts[points_offset].x ,pts[points_offset].y ,pts[points_offset].z ); - - if (!(result)) - { - pfree(npoints); - return FALSE; //relay error - } - - //first and last point are the same - if (! (FPeq(pts[points_offset].x , pts[points_offset + npoints[t]-1].x ) - &&FPeq(pts[points_offset].y , pts[points_offset + npoints[t]-1].y ) - &&FPeq(pts[points_offset].z , pts[points_offset + npoints[t]-1].z ) ) ) - { - elog(ERROR,"polygon has ring where first point != last point"); - pfree(npoints); - return FALSE; //invalid poly - } - - - points_offset += npoints[t]; //where to stick points in the next ring - - str = strchr(str,'('); // where is the next ring - if (str == NULL) - { - pfree(npoints); - return FALSE; //relay parse error - } - str++; - } - - pfree(npoints); - *offset = *offset + 1; - return (result); -} - - -// MULTIPOLYGON (( (3 4 5,1 2 3,5 6),(1 2, 4 5, 6 7) ), ( (11 11, 22 22, 33 33),(44 44, 55 55, 66 66) ) )' -// pass off work to parse_objects_inside_polygon() - -bool parse_objects_inside_multipolygon(int32 *obj_size,char **objs, int32 *obj_types, int32 nobjs, char *str, int *offset, bool* is3d) -{ - bool result; - int num_polys; - int t; - - num_polys = objects_inside_multipolygon(str); //how many polygons are inside me? - -//printf("parse_objects_inside_multipolygon('%s')\n",str); - - if (num_polys <0) - return FALSE; - - if (num_polys ==0) - return TRUE; //ask for nothing, get nothing - - if (*offset >= nobjs) - return FALSE; //too many objs found - - str= strchr(str,'('); //first one (begining of list of polys) - if (str != NULL) - { - str++; - str= strchr(str,'('); //2nd one (beginning of 1st poly) - } - if (str == NULL) - return FALSE; //relay error - - for (t=0;tLLB.x = pt->x; - the_box->LLB.y = pt->y; - the_box->LLB.z = pt->z; - - the_box->URT.x = pt->x; - the_box->URT.y = pt->y; - the_box->URT.z = pt->z; - - return the_box; -} - -// box encloses all the points in all the rings -BOX3D *bbox_of_polygon(POLYGON3D *polygon) -{ - BOX3D *the_box ; - int numb_points =0,i; - POINT3D *pts,*pt; - - for (i=0; inrings; i++) - { - numb_points += polygon->npoints[i]; - } - - if (numb_points <1) - return NULL; - - pts = (POINT3D *) ( (char *)&(polygon->npoints[polygon->nrings] ) ); - pts = (POINT3D *) MAXALIGN(pts); - - the_box = bbox_of_point(&pts[0]); - - for (i=1; ix < the_box->LLB.x) - the_box->LLB.x = pt->x; - - if (pt->y < the_box->LLB.y) - the_box->LLB.y = pt->y; - - if (pt->z < the_box->LLB.z) - the_box->LLB.z = pt->z; - - if (pt->x > the_box->URT.x) - the_box->URT.x = pt->x; - - if (pt->y > the_box->URT.y) - the_box->URT.y = pt->y; - - if (pt->z > the_box->URT.z) - the_box->URT.z = pt->z; - - } - return the_box; -} - -//box encloses points in line -BOX3D *bbox_of_line(LINE3D *line) -{ - BOX3D *the_box; - POINT3D *pt; - int i; - - if (line->npoints <1) - { - return NULL; - } - the_box = bbox_of_point(&line->points[0]); - - for (i=1;i< line->npoints; i++) - { - pt = &line->points[i]; - if (pt->x < the_box->LLB.x) - the_box->LLB.x = pt->x; - - if (pt->y < the_box->LLB.y) - the_box->LLB.y = pt->y; - - if (pt->z < the_box->LLB.z) - the_box->LLB.z = pt->z; - - if (pt->x > the_box->URT.x) - the_box->URT.x = pt->x; - - if (pt->y > the_box->URT.y) - the_box->URT.y = pt->y; - - if (pt->z > the_box->URT.z) - the_box->URT.z = pt->z; - } - return the_box; -} - -//merge box a and b (expand b) -//if b is null, new one is returned -// otherwise b is returned -BOX3D *union_box3d(BOX3D *a, BOX3D *b) -{ - if (a==NULL) - return NULL; - if (b==NULL) - { - b=(BOX3D*) palloc(sizeof(BOX3D)); - memcpy(b,a,sizeof(BOX3D) ); - return b; - } - - - if (a->LLB.x < b->LLB.x) - b->LLB.x = a->LLB.x; - if (a->LLB.y < b->LLB.y) - b->LLB.y = a->LLB.y; - if (a->LLB.z < b->LLB.z) - b->LLB.z = a->LLB.z; - - if (a->URT.x > b->URT.x) - b->URT.x = a->URT.x; - if (a->URT.y > b->URT.y) - b->URT.y = a->URT.y; - if (a->URT.z > b->URT.z) - b->URT.z = a->URT.z; - return b; -} - -BOX3D *bbox_of_geometry(GEOMETRY *geom) -{ - int i; - int32 *offsets; - char *obj; - BOX3D *result=NULL; - BOX3D *a_box; - -//printf("bbox_of_geometry(%p)\n", geom); - - if (geom->nobjs <1) - return NULL; //bbox of 0 objs is 0 - - //where are the objects living? - offsets = (int32 *) ( ((char *) &(geom->objType[0] ))+ sizeof(int32) * geom->nobjs ) ; - - - //for each sub-object - for(i=0; inobjs;i++) - { - obj = (char *) geom +offsets[i] ; - - - if (geom->objType[i] == POINTTYPE) - { -//printf("box of a point\n"); - a_box = bbox_of_point( (POINT3D *) obj); - result= union_box3d(a_box ,result); - - if (a_box != NULL) - pfree (a_box); - } - if (geom->objType[i] == LINETYPE) - { -//printf("box of a line, # points = %i\n",((LINE3D *) obj)->npoints ); - a_box = bbox_of_line( (LINE3D *) obj); - result = union_box3d(a_box ,result); - if (a_box != NULL) - pfree (a_box); - } - if (geom->objType[i] == POLYGONTYPE) - { -//printf("box of a polygon\n"); - a_box = bbox_of_polygon( (POLYGON3D *) obj); - result =union_box3d(a_box ,result); - if (a_box != NULL) - pfree (a_box); - } - } - return result; -} - - -//given wkt and SRID, return a geometry -//actually we cheat, postgres will convert the string to a geometry for us... -PG_FUNCTION_INFO_V1(geometry_from_text); -Datum geometry_from_text(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - int32 SRID; - - GEOMETRY *result; - - if ( ! PG_ARGISNULL(1) ) - SRID = PG_GETARG_INT32(1); - else - SRID = -1; - - - result = (GEOMETRY *) palloc(geom1->size); - memcpy(result,geom1, geom1->size); - - if (result != NULL) - { - result->SRID = SRID; - } - else - { - PG_RETURN_NULL(); - } - PG_RETURN_POINTER(result); -} - - - -// Parse a geometry object -// -// 1. Find information on how many sub-object there are -// 2. create a group of sub-object and populate them -// 3. make a large structure & populate with all the above info. -// -// -PG_FUNCTION_INFO_V1(geometry_in); -Datum geometry_in(PG_FUNCTION_ARGS) -{ - char *str = PG_GETARG_CSTRING(0); - GEOMETRY *geometry; - BOX3D *the_bbox; - int32 nobjs; - char **objs; - int32 *obj_types; - int32 *obj_size; - int entire_size; - bool is3d = FALSE; - bool okay; - int next_loc; - int32 *offsets; - int t; - int obj_parse_offset; - int nitems; - int32 SRID; - double scale,offx,offy; - BOX3D *mybox; - -//printf("str=%s\n",str); - - - - //trim white - while (isspace((unsigned char) *str)) - str++; - - //test to see if it starts with a SRID= - - SRID = -1; - scale = offx = offy = 0; - - if (strstr(str,"SRID=")) - { - //its spatially located - nitems = sscanf(str,"SRID=%i;",&SRID); - if (nitems !=1 ) - { - //error - elog(ERROR,"couldnt parse objects in GEOMETRY (SRID related)"); - PG_RETURN_NULL() ; - } - //delete first part of string - str = strchr(str,';'); - if (str != NULL) - str++; - else - { - elog(ERROR,"couldnt parse objects in GEOMETRY (SRID related - no ';')"); - PG_RETURN_NULL() ; - } - } - - - if (strstr(str,"EMPTY")) - { - GEOMETRY *result=makeNullGeometry( SRID); - if (strstr(str,"MULTIPOLYGON")) - result->type = MULTIPOLYGONTYPE; - if (strstr(str,"MULTILINESTRING")) - result->type = MULTILINETYPE; - if (strstr(str,"MULTIPOINT")) - result->type = MULTIPOINTTYPE; - PG_RETURN_POINTER( result ); - } - - if (strstr(str,"BOX3D") != NULL ) // bbox only - { - - - mybox = parse_box3d(str); - - if (mybox == NULL) - PG_RETURN_NULL() ; - - geometry = (GEOMETRY *) palloc(sizeof(GEOMETRY)); - geometry->size = sizeof(GEOMETRY); - geometry->type = BBOXONLYTYPE; - geometry->nobjs = -1; - geometry->SRID = SRID; - geometry->scale = 1.0; - geometry->offsetX = 0.0; - geometry->offsetY = 0.0; - memcpy(&(geometry->bvol),mybox, sizeof(BOX3D) ); - - pfree(mybox); - PG_RETURN_POINTER(geometry); - } - - - if ((str==NULL) || (strlen(str) == 0) ) - { - elog(ERROR,"couldnt parse objects in GEOMETRY (null string)\n"); - PG_RETURN_NULL() ; - } - - // handle the 2 variants of MULTIPOINT - 'MULTIPOINT(0 0, 1 1)'::geometry and 'MULTIPOINT( (0 0), (1 1))'::geometry; - - // we cheat - if its the 2nd variant, we replace the internal parethesis with spaces! - if (strstr(str,"MULTIPOINT") != NULL ) - { - //its a multipoint - replace any internal parenthesis with spaces - char *first_paren; - char *last_paren; - char *current_paren; - - first_paren= strchr (str,'('); - last_paren = strrchr(str,')'); - - if ( (first_paren == NULL) || (last_paren == NULL) || (first_paren >last_paren) ) - { - elog(ERROR,"couldnt parse objects in GEOMETRY (parenthesis related)\n"); - PG_RETURN_NULL() ; - } - //now we can just got through the string - for (current_paren = (first_paren+1); current_paren <(last_paren);current_paren++) - { - if ( (current_paren[0] ==')') || (current_paren[0]=='(') ) - { - current_paren[0] = ' '; - } - } - - } - - -//elog (NOTICE,"in:%s\n", str); - -//printf("geometry_in got string ''\n"); - - nobjs= objects_inside(str); //how many sub-objects - if (nobjs <=0) //dont allow zero-object items - { - elog(ERROR,"couldnt parse objects in GEOMETRY\n"); - PG_RETURN_NULL() ; - } - -//printf("geometry_in determins that there are %i sub-objects\n",nobjs); - - //allocate enough space for info structures - - - objs = palloc(sizeof( char *) * nobjs); - memset(objs, 0, sizeof( char *) * nobjs); - - obj_types = palloc(sizeof(int32) * nobjs); - memset(obj_types, 0, sizeof(int32) * nobjs); - - obj_size = palloc(sizeof(int32) * nobjs); - memset(obj_size, 0, sizeof(int32) * nobjs); - - obj_parse_offset = 0; //start populating obj list at beginning - - -//printf(" +about to parse the objects\n"); - - - okay = parse_objects(obj_size,objs,obj_types,nobjs,str,&obj_parse_offset , &is3d); - -//printf(" +finished parsing object\n"); - - if (!(okay) || (obj_parse_offset != nobjs ) ) - { - //free - for (t =0; tsize = entire_size; - - //set collection type. Need to differentiate between - // geometrycollection and (say) multipoint - - if ( strstr(str, "GEOMETRYCOLLECTION") != NULL ) - geometry->type = COLLECTIONTYPE; - else - { - if ( strstr(str, "MULTI") != NULL ) - { - if (obj_types[0] == POINTTYPE) - geometry->type = MULTIPOINTTYPE; - if (obj_types[0] == LINETYPE) - geometry->type = MULTILINETYPE; - if (obj_types[0] == POLYGONTYPE) - geometry->type = MULTIPOLYGONTYPE; - } - else - { - geometry->type = obj_types[0]; //single object - } - } - - geometry->is3d = is3d; //any 3d points found anywhere? - geometry->nobjs = nobjs; // sub-objects - - - //copy in type and length info - - //where to put objects. next_loc will point to (bytes forward) &objData[0] - next_loc = ( (char *) &(geometry->objType[0] ) - (char *) geometry); - next_loc += sizeof(int32) * 2* nobjs; - - next_loc = MAXALIGN(next_loc); - - - - //where is the offsets array - offsets = (int32 *) ( ((char *) &(geometry->objType[0] ))+ sizeof(int32) * nobjs ) ; - - -//printf("structure is at %p, offsets is at %p, next_loc = %i\n",geometry, offsets, next_loc); - - for (t=0; tobjType[t] = obj_types[t]; //set its type - - offsets[t] = next_loc; //where is it -//printf("copy %i bytes from %p to %p\n", obj_size[t] , objs[t],(char *) geometry + next_loc); - memcpy( (char *) geometry + next_loc, objs[t], obj_size[t] ); //put sub-object into object - pfree(objs[t]); // free the original object (its redundant) - - next_loc += obj_size[t]; //where does the next object go? - - next_loc = MAXALIGN(next_loc); - - - } - - //free temporary structures - pfree(objs); pfree(obj_types); pfree(obj_size); - - - //calculate its bounding volume - the_bbox = bbox_of_geometry(geometry); - - if (the_bbox != NULL) - { - memcpy( &geometry->bvol, the_bbox, sizeof(BOX3D) ); - pfree(the_bbox); - } - - -//printf("returning from geometry_in, nobjs = %i\n", nobjs); - - - geometry->SRID = SRID; - geometry->scale = scale; - geometry->offsetX = offx; - geometry->offsetY = offy; - PG_RETURN_POINTER(geometry); -} - -PG_FUNCTION_INFO_V1(srid_geom); -Datum srid_geom(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - - PG_RETURN_INT32(geom1->SRID); -} - - -//Take internal rep of geometry, output string in the form of -// 'SRID=%i;' ie. 'SRID=5;POINT(1 1)' -PG_FUNCTION_INFO_V1(geometry_out); -Datum geometry_out(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - char *wkt; - char *result; - int len; - - wkt = geometry_to_text(geom1); - - len = strlen(wkt) + 6+ 25 + 1; - result = palloc(len);//extra space for SRID - memset(result, 0, len); //zero everything out - - sprintf(result,"SRID=%i;%s",geom1->SRID,wkt); - - pfree(wkt); - - PG_RETURN_CSTRING(result); - -} - -//Take internal rep of geometry, output string -PG_FUNCTION_INFO_V1(astext_geometry); -Datum astext_geometry(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - char *wkt; - char *result; - int len; - - wkt = geometry_to_text(geom1); - - //changed so it isnt null terminated (not needed with text) - len = strlen(wkt) + 4; - - result= palloc(len); - *((int *) result) = len; - - memcpy(result +4, wkt, len-4); - - pfree(wkt); - - PG_RETURN_CSTRING(result); -} - - -//Take internal rep of geometry, output string - - -//takes a GEOMETRY and returns a WKT representation -char *geometry_to_text(GEOMETRY *geometry) -{ - char *result; - int t,u; - int32 *offsets; - char *obj; - POINT3D *pts; - POLYGON3D *polygon; - LINE3D *line; - POINT3D *point; - - int pt_off,size; - bool briefmode= TRUE; // ie. dont print out "POINT3D(..)", just print out the ".." part - bool is3d; - bool first_sub_obj = TRUE; - bool multi_obj = FALSE; - int mem_size,npts; - - - if (geometry->nobjs == 0) - { - //empty geometry - result = (char*) palloc(30); - - sprintf(result,"GEOMETRYCOLLECTION(EMPTY)"); - - if (geometry->type == MULTILINETYPE) - sprintf(result,"MULTILINESTRING(EMPTY)"); - if (geometry->type == MULTIPOINTTYPE) - sprintf(result,"MULTIPOINT(EMPTY)"); - if (geometry->type == MULTIPOLYGONTYPE) - sprintf(result,"MULTIPOLYGON(EMPTY)"); - return result; - } - - -//printf("in geom_out(%p)\n",geometry); - - size = 30; //just enough to put in object type - result = (char *) palloc(30); mem_size= 30; //try to limit number of repalloc()s - - if (geometry->type == BBOXONLYTYPE) - { - mem_size = MAX_DIGS_DOUBLE*6+5+2+4+5+1; - pfree(result); - result = (char *) palloc(mem_size); //double digits+ "BOX3D"+ "()" + commas +null - sprintf(result, "BOX3D(%.15g %.15g %.15g,%.15g %.15g %.15g)", - geometry->bvol.LLB.x,geometry->bvol.LLB.y,geometry->bvol.LLB.z, - geometry->bvol.URT.x,geometry->bvol.URT.y,geometry->bvol.URT.z); - return result; - } - - - if (geometry->type == POINTTYPE) - { - multi_obj = FALSE; - sprintf(result, "POINT(" ); - } - else if (geometry->type == LINETYPE) - { - multi_obj = FALSE; - sprintf(result, "LINESTRING" ); - } - else if (geometry->type == POLYGONTYPE) - { - multi_obj = FALSE; - sprintf(result, "POLYGON" ); - } - else if (geometry->type == MULTIPOINTTYPE) - { - //multiple sub-object need to be put into one object - multi_obj = TRUE; - sprintf(result, "MULTIPOINT(" ); - } - else if (geometry->type == MULTILINETYPE) - { - //multiple sub-object need to be put into one object - multi_obj = TRUE; - sprintf(result, "MULTILINESTRING(" ); - } - else if (geometry->type == MULTIPOLYGONTYPE) - { - //multiple sub-object need to be put into one object - multi_obj = TRUE; - sprintf(result, "MULTIPOLYGON(" ); - } - else if (geometry->type == COLLECTIONTYPE) - { - sprintf(result, "GEOMETRYCOLLECTION(" ); - briefmode = FALSE; - multi_obj = FALSE; - } - - //where are the objects? - offsets = (int32 *) ( ((char *) &(geometry->objType[0] ))+ sizeof(int32) * geometry->nobjs ) ; - - is3d = geometry->is3d; - - - for(t=0;tnobjs; t++) //for each object - { - obj = (char *) geometry +offsets[t] ; - - if (geometry->objType[t] == 1) //POINT - { - point = (POINT3D *) obj; - if (briefmode) //dont need to put in "POINT(" - { - size +=MAX_DIGS_DOUBLE*3 + 2 +3 ; - result = repalloc(result, size ); //make memory bigger - if (!(first_sub_obj)) - { - strcat(result,","); - } - else - { - first_sub_obj = FALSE; - } - print_point(result, point,is3d); //render point - if (t == (geometry->nobjs-1)) - strcat(result,")"); // need to close object? - } - else - { - size +=MAX_DIGS_DOUBLE*3 + 2 +3 +7 ; - result = repalloc(result, size ); - strcat(result, "POINT("); - print_point(result, point,is3d); - strcat(result, ")"); - if (t != (geometry->nobjs -1) ) - strcat(result,","); - } - - } - if (geometry->objType[t] == 2) //LINESTRING - { - line = (LINE3D *) obj; - if (briefmode) - { - size +=(MAX_DIGS_DOUBLE*3+5)*line->npoints +3; - result = repalloc(result, size ); -#ifdef DEBUG_TOTEXT -elog(NOTICE, "Added space for %d points, result size: %d", line->npoints, size); -elog(NOTICE, "Strlen result(%x): %d", result, strlen(result)); -#endif - - if (!(first_sub_obj)) - { - strcat(result,","); - } - else - { - first_sub_obj = FALSE; - } - - strcat(result,"("); - print_many_points(result, &line->points[0],line->npoints , is3d); - strcat(result,")"); - if ((t == (geometry->nobjs-1)) && multi_obj ) //close object? - strcat(result,")"); -#ifdef DEBUG_TOTEXT -elog(NOTICE, "RESULT: %s", result); -#endif - } - else - { - size +=(MAX_DIGS_DOUBLE*3+5)*line->npoints +12+3; - result = repalloc(result, size ); - strcat(result, "LINESTRING("); - - //optimized for speed - - print_many_points(result, &line->points[0],line->npoints , is3d); - strcat(result,")"); - if (t != (geometry->nobjs -1) ) - strcat(result,","); - - } - } - if (geometry->objType[t] == 3) //POLYGON - { - polygon = (POLYGON3D *) obj; - if (!(briefmode)) - { - size += 7 + polygon->nrings *3+9; - result = repalloc(result, size ); - strcat(result,"POLYGON"); - } - else - { - size += 7 + polygon->nrings *3; - result = repalloc(result, size ); - } - - //need to separate objects? - if (!(first_sub_obj)) - { - strcat(result,","); - } - else - { - first_sub_obj = FALSE; - } - - - strcat(result,"("); //begin poly - - pt_off = 0; //where is the first point in this ring? - - //where are the points - pts = (POINT3D *) ( (char *)&(polygon->npoints[polygon->nrings] ) ); - pts = (POINT3D *) MAXALIGN(pts); - - - npts = 0; - for (u=0; u< polygon->nrings ; u++) - npts += polygon->npoints[u]; - - size += (MAX_DIGS_DOUBLE*3+3) * npts + 5* polygon->nrings; - result = repalloc(result, size ); - - for (u=0; u< polygon->nrings ; u++) //for each ring - { -//printf("making ring #%i in obj, %i\n",u,t); - if (u!=0) - strcat(result,","); //separate rings - - strcat(result,"("); //begin ring - print_many_points(result, &pts[pt_off] ,polygon->npoints[u], is3d); - - pt_off = pt_off + polygon->npoints[u]; //where is first point of next ring? - strcat(result,")"); //end ring - } - strcat(result,")"); //end poly - if ((t == (geometry->nobjs-1)) && multi_obj ) - strcat(result,")"); - if ((!(briefmode)) && (t != (geometry->nobjs -1) )) - strcat(result,","); - } - if (!(briefmode)) - { - first_sub_obj = TRUE; - } - - } - - if (!(briefmode)) - strcat(result,")"); - return(result); -} - - -/***************************************************** - * conversion routines - *****************************************************/ - - - - - -//get bvol inside a geometry -PG_FUNCTION_INFO_V1(get_bbox_of_geometry); -Datum get_bbox_of_geometry(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - - BOX3D *result; - - if (geom->nobjs == 0) - PG_RETURN_NULL(); - - //make a copy of it - - result = palloc ( sizeof(BOX3D) ); - memcpy(result,&geom->bvol, sizeof(BOX3D) ); - - - PG_RETURN_POINTER(result); -} - - -//make a fake geomery with just it a bvol -PG_FUNCTION_INFO_V1(get_geometry_of_bbox); -Datum get_geometry_of_bbox(PG_FUNCTION_ARGS) -{ - BOX3D *bbox = (BOX3D *) PG_GETARG_POINTER(0); - GEOMETRY *geom ; - - //make a copy of it - - geom = palloc ( sizeof(GEOMETRY) ); - geom->size = sizeof(GEOMETRY); - geom->type = BBOXONLYTYPE; - geom->nobjs = -1; - geom->SRID = -1; - geom->scale = 1.0; - geom->offsetX = 0.0; - geom->offsetY = 0.0; - memcpy(&(geom->bvol),bbox, sizeof(BOX3D) ); - - - PG_RETURN_POINTER(geom); -} - - - - -//***************************************************************** -//WKB does not do any padding or alignment! - -// in general these function take -// 1. geometry item or list -// 2. if the endian-ness should be changed (flipbytes) -// 3. byte_order - 0=big endian (XDR) 1= little endian (NDR) -// 4. use the 3d extention wkb (use3d) -// -// NOTE: -// A. mem - if null, function pallocs memory for result -// - otherwise, use mem to dump the wkb into -// b. for lists, the # of sub-objects is also specified -// -// and return -// 1. size of the wkb structure ("int *size") -// 2. the actual wkb structure -//***************************************************************** - -//convert a POINT3D into wkb -char *wkb_point(POINT3D *pt,int32 *size, bool flipbytes, char byte_order, bool use3d) -{ - char *result ; - uint32 type ; - char *c_type = (char *) &type; - - if (use3d) - { - *size = 29; - type = ((unsigned int) WKB3DOFFSET + ((unsigned int)1)); - } - else - { - *size = 21; - type = 1; - } - - result = palloc (*size); - - if (flipbytes) - flip_endian_int32( (char *) &type); - - result[0] = byte_order; - result[1] = c_type[0]; - result[2] = c_type[1]; - result[3] = c_type[2]; - result[4] = c_type[3]; - - if (use3d) - memcpy(&result[5], pt, 24 ); //copy in point data - else - memcpy(&result[5], pt, 16 ); //copy in point data - - if (flipbytes) - { - flip_endian_double((char *) &result[5]); // x - flip_endian_double((char *) &result[5+8]); // y - if (use3d) - flip_endian_double((char *) &result[5+16]); // z - } - - return result; -} - -//pt is a pointer to list of POINT3Ds -char *wkb_multipoint(POINT3D *pt,int32 numb_points,int32 *size, bool flipbytes, char byte_order,bool use3d) -{ - char *result; - uint32 type ; // 3D/2D multipoint, following frank's spec - uint32 npoints = numb_points; - char *c_type = (char *) &type; - char *c_npoints = (char *) &npoints; - int t; - int32 junk; - const int sub_size_3d = 29; - const int sub_size_2d = 21; - - - - - if (use3d) - { - *size = 9 + sub_size_3d*numb_points; - type = WKB3DOFFSET + 4; - } - else - { - *size = 9 + sub_size_2d*numb_points; - type = 4; - } - - - result = palloc (*size); - npoints = numb_points; - - if (flipbytes) - { - flip_endian_int32((char *) &type); - flip_endian_int32((char *) &npoints); - } - - - result[0] = byte_order; - result[1] = c_type[0]; - result[2] = c_type[1]; - result[3] = c_type[2]; - result[4] = c_type[3]; - - result[5] = c_npoints[0]; - result[6] = c_npoints[1]; - result[7] = c_npoints[2]; - result[8] = c_npoints[3]; - - for (t=0; tnpoints; - int numb_points = line->npoints; - char *c_npoints = (char *) &npoints; - - - if (use3d) - { - *size = 9 + 24*numb_points; - type = WKB3DOFFSET + 2; - } - else - { - *size = 9 + 16*numb_points; - type = 2; - } - - - - if (flipbytes) - { - flip_endian_int32((char *) &type); - flip_endian_int32((char *) &npoints); - } - - if (mem == NULL) - result = palloc (*size); - else - result = mem; - - result[0] = byte_order; - result[1] = c_type[0]; //type - result[2] = c_type[1]; - result[3] = c_type[2]; - result[4] = c_type[3]; - - result[5] = c_npoints[0]; //npoints - result[6] = c_npoints[1]; - result[7] = c_npoints[2]; - result[8] = c_npoints[3]; - - if (use3d) - { - memcpy(&result[9],&line->points, line->npoints*24); // copy all the pt data in one chuck - if (flipbytes) - { - for (t=0;tnpoints; t++) - { - flip_endian_double((char *) &result[9 + t*24]); // x - flip_endian_double((char *) &result[9+8 + t*24]); // y - flip_endian_double((char *) &result[9+16+ t*24]); // z - } - } - } - else - { - for (t=0; tpoints)[t]), 16); //need to copy each pt individually - if (flipbytes) - { - flip_endian_double((char *) &result[9 + t*16]); // x - flip_endian_double((char *) &result[9+8 + t*16]); // y - } - } - } - return result; -} - -// expects an array of pointers to lines -// calls wkb_line() to do most of the work -char *wkb_multiline(LINE3D **lines,int32 *size, int numb_lines, bool flipbytes, char byte_order,bool use3d) -{ - int total_points = 0; - int total_size=0; - int size_part = 0; - - int t; - char *result,*new_spot; - - - uint32 type ; - char *c_type = (char *) &type; - - uint32 nlines = numb_lines; - char *c_nlines = (char *) &nlines; - - if (use3d) - { - type = WKB3DOFFSET + 5; - } - else - { - type = 5; - } - - if (flipbytes) - { - flip_endian_int32((char *) &type); - flip_endian_int32((char *) &nlines); - } - - //how many points in the entire multiline() - for (t=0;tnpoints; - } - - - if (use3d) - { - total_size = 9+ 9*numb_lines + 24*total_points; - } - else - { - total_size = 9 + 9*numb_lines + 16*total_points; - } - - *size = total_size; - - result = palloc (total_size); - - - - result[0] = byte_order; - result[1] = c_type[0]; //type - result[2] = c_type[1]; - result[3] = c_type[2]; - result[4] = c_type[3]; - - result[5] = c_nlines[0]; //num linestrings - result[6] = c_nlines[1]; - result[7] = c_nlines[2]; - result[8] = c_nlines[3]; - - - - new_spot = result + 9;//where to put the next linestring - - for (t=0;tnpoints[poly->nrings] ) ); - pts = (POINT3D *) MAXALIGN(pts); - - - - numRings = poly->nrings; - - //total points in all the rings - for (t=0; t< poly->nrings; t++) - { - total_points += poly->npoints[t]; - } - - if (use3d) - { - *size = 9 + 4*poly->nrings + 24*total_points; - type = WKB3DOFFSET + 3; - } - else - { - *size = 9 + 4*poly->nrings + 16*total_points; - type = 3; - } - - if (mem == NULL) - result = palloc (*size); - else - result = mem; - - - if (flipbytes) - { - flip_endian_int32((char *) &type); - flip_endian_int32((char *) &numRings); - } - - - - result[0] = byte_order; - result[1] = c_type[0]; //type - result[2] = c_type[1]; - result[3] = c_type[2]; - result[4] = c_type[3]; - - result[5] = c_numRings[0]; //npoints - result[6] = c_numRings[1]; - result[7] = c_numRings[2]; - result[8] = c_numRings[3]; - - - if (use3d) - { - offset = 9; //where the actual linearring structure is going - point_offset = 0; - for (t=0;tnrings; t++) //for each ring - { - npoints = poly->npoints[t]; - if (flipbytes) - flip_endian_int32((char *) &npoints); - result[offset] = c_npoints[0]; //num points in this ring - result[offset+1] = c_npoints[1]; - result[offset+2] = c_npoints[2]; - result[offset+3] = c_npoints[3]; - - memcpy(&result[offset+4], &pts[point_offset], 24*poly->npoints[t]); - if (flipbytes) - { - for (u=0;unpoints[t];u++) //for each point - { - flip_endian_double((char *) &result[offset+4+u*24] ); - flip_endian_double((char *) &result[offset+4+u*24+8] ); - flip_endian_double((char *) &result[offset+4+u*24]+16); - } - } - point_offset += poly->npoints[t]; // reset offsets - offset += 4 + poly->npoints[t]* 24; - } - } - else - { - offset = 9; // where the 1st linearring goes - point_offset = 0; - for (t=0;tnrings; t++) - { - npoints = poly->npoints[t]; - if (flipbytes) - flip_endian_int32((char *) &npoints); - result[offset] = c_npoints[0]; - result[offset+1] = c_npoints[1]; - result[offset+2] = c_npoints[2]; - result[offset+3] = c_npoints[3]; - - for (u=0;unpoints[t];u++) - { - memcpy(&result[offset+4 + u*16], &pts[point_offset+u], 16); - if (flipbytes) - { - flip_endian_double((char *) &result[offset+4+u*16] ); - flip_endian_double((char *) &result[offset+4+u*16+8] ); - } - } - - point_offset += poly->npoints[t]; - offset += 4 + poly->npoints[t]* 16; - } - - } - return result; -} - - -//expects a list of pointer to polygon3d -char *wkb_multipolygon(POLYGON3D **polys,int numb_polys,int32 *size, bool flipbytes, char byte_order,bool use3d) -{ - - int t,u; - int total_points = 0; - int total_size=0; - int size_part = 0; - int total_rings = 0; - char *result,*new_spot; - uint32 type; - - char *c_type = (char *) &type; - - uint32 npolys = numb_polys; - char *c_npolys = (char *) &npolys; - - if (use3d) - { - type = WKB3DOFFSET + 6; - } - else - { - type = 6; - } - - - if (flipbytes) - { - flip_endian_int32( (char *) &type); - flip_endian_int32((char *) &npolys); - } - - - - - //find total # rings and total points - for (t=0;tnrings; - for (u=0;unrings; u++) - { - total_points += polys[t]->npoints[u]; - } - } - - - if (use3d) - { - total_size =9 + 9*numb_polys + 24*total_points + 4*total_rings; - } - else - { - total_size = 9 + 9*numb_polys + 16*total_points + 4*total_rings; - } - - *size = total_size; - - result = palloc (total_size); - - result[0] = byte_order; - result[1] = c_type[0]; //type - result[2] = c_type[1]; - result[3] = c_type[2]; - result[4] = c_type[3]; - - result[5] = c_npolys[0]; //number of polygons - result[6] = c_npolys[1]; - result[7] = c_npolys[2]; - result[8] = c_npolys[3]; - - - - new_spot = result+9; //where 1st polygon goes - - for (t=0;ttype == COLLECTIONTYPE) - { - sub_result= to_wkb_collection(geom, flip_endian, &size); - size += 4; //size info - result = palloc (size ); - memcpy(result+4, sub_result, size-4); - memcpy(result, &size, 4); - pfree(sub_result); - return result; - } - else - { - sub_result= to_wkb_sub(geom, flip_endian, &size); - size += 4; //size info - result = palloc (size ); - memcpy(result+4, sub_result, size-4); - memcpy(result, &size, 4); - pfree(sub_result); - return result; - } - -} - -//make a wkb chunk out of a geometrycollection -char *to_wkb_collection(GEOMETRY *geom, bool flip_endian, int32 *end_size) -{ - char *result, **sub_result; - int sub_size; - int *sizes; - int t; - int32 *offsets1; - - int32 type; - int total_size =0; - int offset; - char byte_order; - int coll_type=7; - char *c_type = (char *)&coll_type; - int nobj = geom->nobjs; - char *c_nobj = (char *) &nobj; - -//printf("making a wkb of a collections\n"); - - - //determing byte order and if numbers need endian change - if (BYTE_ORDER == BIG_ENDIAN) - { - if (flip_endian) - { - byte_order = 1; - } - else - { - byte_order = 0; - } - } - else - { - if (flip_endian) - { - byte_order = 0; - } - else - { - byte_order = 1; - } - } - - //for sub part of the geometry structure - offsets1 = (int32 *) ( ((char *) &(geom->objType[0] ))+ sizeof(int32) * geom->nobjs ) ; - - - // we make a list of smaller wkb chunks in sub_result[] - // and that wkb chunk's size in sizes[] - - sub_result = NULL; - if (geom->nobjs >0) - sub_result = palloc( sizeof(char *) * geom->nobjs); - sizes = NULL; - if (geom->nobjs >0) - sizes = palloc( sizeof(int) * geom->nobjs); - - - for (t=0; tnobjs; t++) //for each part of the collections, do the work in another function - { - type = geom->objType[t]; - - if (type == POINTTYPE) - { - sub_result[t] = ( wkb_point((POINT3D *) ((char *) geom +offsets1[t] ) , - &sub_size, flip_endian, byte_order, geom->is3d)); - sizes[t] = sub_size; - total_size += sub_size; - } - - if (type == LINETYPE) - { - - sub_result[t] = ( wkb_line((LINE3D *) ((char *) geom +offsets1[t] ) , - &sub_size, flip_endian, byte_order, geom->is3d, NULL)); - sizes[t] = sub_size; - total_size += sub_size; - } - if (type == POLYGONTYPE) - { - - sub_result[t] = ( wkb_polygon((POLYGON3D *) ((char *) geom +offsets1[t] ) , - &sub_size, flip_endian, byte_order, geom->is3d, NULL)); - sizes[t] = sub_size; - total_size += sub_size; - } - } - - result = palloc( total_size +9); // need geometrycollection header - - if (geom->is3d) - coll_type += WKB3DOFFSET; - - if (flip_endian) - { - flip_endian_int32((char *) &coll_type); - flip_endian_int32((char *) &nobj); - } - - //could use a memcpy, but... - - - - result[0] = byte_order; - result[1] = c_type[0]; //type - result[2] = c_type[1]; - result[3] = c_type[2]; - result[4] = c_type[3]; - - result[5] = c_nobj[0]; //number of part to collection - result[6] = c_nobj[1]; - result[7] = c_nobj[2]; - result[8] = c_nobj[3]; - - - offset =9; //start after the geometrycollection header - - - for (t=0;tnobjs; t++) - { - memcpy(result+ offset, sub_result[t], sizes[t]); - pfree(sub_result[t]); - offset += sizes[t]; - } - - //free temp structures - if (sub_result != NULL) - pfree( sub_result); - if (sizes != NULL) - pfree( sizes); - - //total size of the wkb - *end_size = total_size+9; - - - - //decode_wkb(result, &junk); - return result; -} - - -//convert geometry to WKB, flipping endian if appropriate -// -// This handles POINT, LINESTRING, POLYGON, MULTIPOINT,MULTILINESTRING, MULTIPOLYGON -// -// GEOMETRYCOLLECTION is not handled by this function see to_wkb_collection() -// -// flip_endian - request an endian swap (relative to current machine) -// wkb_size - return size of wkb - -char *to_wkb_sub(GEOMETRY *geom, bool flip_endian, int32 *wkb_size) -{ - - char byte_order; - char *result = NULL; - int t; - - - int32 *offsets1; - LINE3D **linelist; - POLYGON3D **polylist; - - - //determine WKB byte order flag - if (BYTE_ORDER == BIG_ENDIAN) //server is running on a big endian machine - { - if (flip_endian) - { - byte_order = 1; //as per WKB specification - } - else - { - byte_order = 0; - } - } - else - { - if (flip_endian) - { - byte_order = 0; - } - else - { - byte_order = 1; - } - } - - // for searching in the geom struct - offsets1 = (int32 *) ( ((char *) &(geom->objType[0] ))+ sizeof(int32) * geom->nobjs ) ; - - - // for each of the possible geometry types, we pass it off to a worker function - - if (geom->type == POINTTYPE) - { - - result = ( wkb_point((POINT3D *) ((char *) geom +offsets1[0] ) , - wkb_size, flip_endian, byte_order, geom->is3d)); - } - - if (geom->type == MULTIPOINTTYPE) - { - - result = ( wkb_multipoint((POINT3D *) ((char *) geom +offsets1[0] ) , - geom->nobjs, wkb_size, flip_endian, byte_order, geom->is3d)); - } - - if (geom->type == LINETYPE) - { - - result = ( wkb_line((LINE3D *) ((char *) geom +offsets1[0] ) , - wkb_size, flip_endian, byte_order, geom->is3d, NULL)); - } - - - if (geom->type == MULTILINETYPE) - { - //make a list of lines - linelist = NULL; - if (geom->nobjs >0) - linelist = palloc( sizeof(LINE3D *) * geom->nobjs); - for (t=0;tnobjs; t++) - { - linelist[t] = (LINE3D *) ((char *) geom +offsets1[t] ) ; - } - result = ( wkb_multiline( linelist, - wkb_size, geom->nobjs, flip_endian, byte_order, geom->is3d)); - } - - if (geom->type == POLYGONTYPE) - { - - result = ( wkb_polygon((POLYGON3D *) ((char *) geom +offsets1[0] ) , - wkb_size, flip_endian, byte_order, geom->is3d, NULL)); - } - - - if (geom->type == MULTIPOLYGONTYPE) - { - //make a list of polygons - polylist = NULL; - if (geom->nobjs >0) - polylist = palloc( sizeof(POLYGON3D *) * geom->nobjs); - for (t=0;tnobjs; t++) - { - polylist[t] = (POLYGON3D *) ((char *) geom +offsets1[t] ) ; - } - result = ( wkb_multipolygon( polylist,geom->nobjs, - wkb_size, flip_endian, byte_order, geom->is3d)); - } - - //decode_wkb(result, &junk); - - return (result); -} - - -//convert binary geometry into OGIS well know binary format with NDR (little endian) formating -// see http://www.opengis.org/techno/specs/99-049.rtf page 3-24 for specification -// -// 3d geometries are encode as in OGR by adding WKB3DOFFSET to the type. Points are then 24bytes (X,Y,Z) -// instead of 16 bytes (X,Y) -// -//dont do any flipping of endian asbinary_simple(GEOMETRY) -PG_FUNCTION_INFO_V1(asbinary_simple); -Datum asbinary_simple(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - - PG_RETURN_POINTER(to_wkb(geom, FALSE)); -} - - -//convert binary geometry into OGIS well know binary format with NDR (little endian) formating -// see http://www.opengis.org/techno/specs/99-049.rtf page 3-24 for specification -// -// 3d geometries are encode as in OGR by adding WKB3DOFFSET to the type. Points are then 24bytes (X,Y,Z) -// instead of 16 bytes (X,Y) -// -//flip if required asbinary_specify(GEOMETRY,'xdr') or asbinary_specify(GEOMETRY,'ndr') -PG_FUNCTION_INFO_V1(asbinary_specify); -Datum asbinary_specify(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - text *type = PG_GETARG_TEXT_P(1); - - - if (VARSIZE(type) < 7) // 4 (size header) + 3 (text length) - { - elog(ERROR,"asbinary(geometry, ) - type should be 'XDR' or 'NDR'. type length is %i",VARSIZE(type) -4); - PG_RETURN_NULL(); - } - - if ( ( strncmp(VARDATA(type) ,"xdr",3) == 0 ) || (strncmp(VARDATA(type) ,"XDR",3) == 0) ) - { -//printf("requested XDR\n"); - if (BYTE_ORDER == BIG_ENDIAN) - PG_RETURN_POINTER(to_wkb(geom, FALSE)); - else - PG_RETURN_POINTER(to_wkb(geom, TRUE)); - } - else - { -//printf("requested NDR\n"); - if (BYTE_ORDER == LITTLE_ENDIAN) - PG_RETURN_POINTER(to_wkb(geom, FALSE)); - else - PG_RETURN_POINTER(to_wkb(geom, TRUE)); - } -} - -//takes a text argument and parses it to make a geometry -PG_FUNCTION_INFO_V1(geometry_text); -Datum geometry_text(PG_FUNCTION_ARGS) -{ - char *input = (char *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - char *cstring; - void *result; - - if (*((int *) input) == 4) - { - //empty string - PG_RETURN_NULL(); - } - cstring = palloc(*((int *) input)); // length+4 - - memcpy(cstring, &input[4], ( *((int *) input))-4); - cstring[( *((int *) input))-4] = 0; // nullterminate - - result = DatumGetPointer( DirectFunctionCall1(geometry_in,PointerGetDatum(cstring))) ; - - PG_RETURN_POINTER (result); -//NOTE: this could cause problem since input isnt null terminated - usually this will not -// cause a problem because the parse will not go further than the end of the string. -// FIXED. -} - - - -//make a geometry with one obj in it (of size new_obj_size) -// type should be POINTTYPE, LINETYPE or POLYGONTYPE -// if you want to change the object's type to something else (ie GEOMETRYCOLLECTION), do -// that after with geom->type = GEOMETRYCOLLECTION -// this does calculate the bvol -// -// sets the SRID and grid info to the given values -// -// do not call this with type = GEOMETRYCOLLECTION - -GEOMETRY *make_oneobj_geometry(int sub_obj_size, char *sub_obj, int type, bool is3d,int SRID, double scale, double offx, double offy) -{ - int size = sizeof(GEOMETRY) + 4 + sub_obj_size ; - GEOMETRY *result = palloc(size); - char *sub_obj_loc; - BOX3D *bbox; - - result->size = size; - result->nobjs = 1; - result->type = type; - result->is3d = is3d; - - - result->SRID = SRID; - result->scale = scale; - result->offsetX = offx; - result->offsetY = offy; - - result->objType[0] = type; - if (type == MULTIPOINTTYPE) - result->objType[0] = POINTTYPE; - if (type == MULTILINETYPE) - result->objType[0] = LINETYPE; - if (type == MULTIPOLYGONTYPE) - result->objType[0] = POLYGONTYPE; - - if (type == COLLECTIONTYPE) - { - pfree(result); - return(NULL); //error - } - - sub_obj_loc = (char *) &result->objType[2]; - sub_obj_loc = (char *) MAXALIGN(sub_obj_loc); - - result->objType[1] = sub_obj_loc - (char *) result; //result->objType[1] is where objOffset is - - //copy in the subobject - memcpy(sub_obj_loc , sub_obj, sub_obj_size); - - bbox = bbox_of_geometry(result); - memcpy(&result->bvol,bbox, sizeof(BOX3D) ); //make bounding box - - return result; -} - - -//find the size of the subobject and return it -int size_subobject (char *sub_obj, int type) -{ - if (type == POINTTYPE) - { - return (sizeof(POINT3D)); - } - if (type == LINETYPE) - { - /* size of first point is included in struct LINE3D */ - return(sizeof(LINE3D) + sizeof(POINT3D) * ( ((LINE3D *)sub_obj)->npoints - 1 )); - } - if (type==POLYGONTYPE) - { - POLYGON3D *poly = (POLYGON3D *) sub_obj; - int t,points=0; - - for (t=0;tnrings;t++) - { - points += poly->npoints[t]; - } - if ( ( (long) ( &poly->npoints[poly->nrings] )) == (MAXALIGN(&poly->npoints[poly->nrings] ) ) ) - return (sizeof(POLYGON3D) + 4*(poly->nrings-1) + sizeof(POINT3D)*(points-1) ); //no extra align - else - return (sizeof(POLYGON3D) + 4*(poly->nrings-1) + sizeof(POINT3D)*(points-1) +4 ); - } - - return (-1);//unknown sub-object type -} - - -//produce a new geometry, which is the old geometry with another object stuck in it -// This will try to make the geometry's type is correct (move POINTTYPE to MULTIPOINTTYPE or -// change to GEOMETRYCOLLECTION) -// -// this does NOT calculate the bvol - you should set it with "bbox_of_geometry" -// -// type is the type of the subobject -// do not call this as with type = GEOMETRYCOLLECTION -// -// doesnt change the is3d flag -// doesnt change the SRID or other attributes - -GEOMETRY *add_to_geometry(GEOMETRY *geom,int sub_obj_size, char *sub_obj, int type) -{ - int size,t; - int size_obj,next_offset; - GEOMETRY *result; - int32 *old_offsets, *new_offsets; - - //all the offsets could cause re-alignment problems, so need to deal with each one - size = geom->size +4*(geom->nobjs +1) /*byte align*/ - +sub_obj_size + 4 /*ObjType[]*/ +4 /*new offset*/; - - result = (GEOMETRY *) palloc(size); - result->size = size; - result->is3d = geom->is3d; - result->SRID = geom->SRID; - result->offsetX = geom->offsetX; - result->offsetY = geom->offsetY; - result->scale = geom->scale; - - //accidently sent in a single-entity type but gave it a multi-entity type - // re-type it as single-entity - if (type == MULTIPOINTTYPE) - type = POINTTYPE; - if (type == MULTILINETYPE) - type = LINETYPE; - if (type == MULTIPOLYGONTYPE) - type = POLYGONTYPE; - - - // change to the simplest possible type that supports the type being added - if (geom->type == POINTTYPE || geom->type == MULTIPOINTTYPE) - { - if (type == POINTTYPE) - result->type = MULTIPOINTTYPE; - else - result->type = COLLECTIONTYPE; - } - if (geom->type == LINETYPE || geom->type == MULTILINETYPE) - { - if (type == LINETYPE) - result->type = MULTILINETYPE; - else - result->type = COLLECTIONTYPE; - } - if (geom->type == POLYGONTYPE || geom->type == MULTIPOLYGONTYPE) - { - if (type == POLYGONTYPE) - result->type = MULTIPOLYGONTYPE; - else - result->type = COLLECTIONTYPE; - } - if (geom->type == COLLECTIONTYPE) - result->type = COLLECTIONTYPE; - - // now result geometry's type and sub-object's type is okay - // we have to setup the geometry - - result->nobjs = geom->nobjs+1; - - for (t=0; t< geom->nobjs; t++) - { - result->objType[t] = geom->objType[t]; - } - -//printf("about to copy geomes\n"); -//printf("result is at %p and is %i bytes long\n",result,result->size); -//printf("geom is at %p and is %i bytes long\n",geom,geom->size); - - old_offsets =& geom->objType[geom->nobjs] ; - new_offsets =& result->objType[result->nobjs] ; - next_offset = ( (char *) &new_offsets[result->nobjs] ) - ( (char *) result) ; - next_offset = MAXALIGN(next_offset); - - //have to re-set the offsets and copy in the sub-object data - for (t=0; t< geom->nobjs; t++) - { - //where is this going to go? - new_offsets[t] = next_offset; - - size_obj = size_subobject ((char *) (((char *) geom) + old_offsets[t] ), geom->objType[t]); - - next_offset += size_obj; - next_offset = MAXALIGN(next_offset); // make sure its aligned properly - - -//printf("coping %i bytes from %p to %p\n", size_obj,( (char *) geom) + old_offsets[t],((char *) result) + new_offsets[t] ); - memcpy( ((char *) result) + new_offsets[t] , ( (char *) geom) + old_offsets[t], size_obj); -//printf("copying done\n"); - - } - -//printf("copying in new object\n"); - - //now, put in the new data - result->objType[ result->nobjs -1 ] = type; - new_offsets[ result->nobjs -1 ] = next_offset; - memcpy( ((char *) result) + new_offsets[result->nobjs-1] ,sub_obj , sub_obj_size); - -//printf("returning\n"); - - return result; -} - - - -//make a polygon obj -// size is return in arg "size" -POLYGON3D *make_polygon(int nrings, int *pts_per_ring, POINT3D *pts, int npoints, int *size) -{ - POLYGON3D *result; - int t; - POINT3D *inside_poly_pts; - - - *size = sizeof(POLYGON3D) + 4 /*align*/ - + 4*(nrings-1)/*npoints struct*/ - + sizeof(POINT3D) *(npoints-1) /*points struct*/ ; - - result= (POLYGON3D *) palloc (*size); - result->nrings = nrings; - - - for (t=0;tnpoints[t] = pts_per_ring[t]; - } - - inside_poly_pts = (POINT3D *) ( (char *)&(result->npoints[result->nrings] ) ); - inside_poly_pts = (POINT3D *) MAXALIGN(inside_poly_pts); - - memcpy(inside_poly_pts, pts, npoints *sizeof(POINT3D) ); - - return result; -} - -void set_point( POINT3D *pt,double x, double y, double z) -{ - pt->x = x; - pt->y = y; - pt->z = z; -} - -//make a line3d object -// return size of structure in 'size' -LINE3D *make_line(int npoints, POINT3D *pts, int *size) -{ - LINE3D *result; - - *size = sizeof(LINE3D) + (npoints-1)*sizeof(POINT3D); - - result= (LINE3D *) palloc (*size); - - result->npoints = npoints; - memcpy( result->points, pts, npoints*sizeof(POINT3D) ); - - return result; -} - -//given one byte, populate result with two byte representing -// the hex number -// ie deparse_hex( 255, mystr) -// -> mystr[0] = 'F' and mystr[1] = 'F' -// no error checking done -void deparse_hex(unsigned char str, unsigned char *result) -{ - int input_high; - int input_low; - - input_high = (str>>4); - input_low = (str & 0x0F); - - switch (input_high) - { - case 0: - result[0] = '0'; - break; - case 1: - result[0] = '1'; - break; - case 2: - result[0] = '2'; - break; - case 3: - result[0] = '3'; - break; - case 4: - result[0] = '4'; - break; - case 5: - result[0] = '5'; - break; - case 6: - result[0] = '6'; - break; - case 7: - result[0] = '7'; - break; - case 8: - result[0] = '8'; - break; - case 9: - result[0] = '9'; - break; - case 10: - result[0] = 'A'; - break; - case 11: - result[0] = 'B'; - break; - case 12: - result[0] = 'C'; - break; - case 13: - result[0] = 'D'; - break; - case 14: - result[0] = 'E'; - break; - case 15: - result[0] = 'F'; - break; - } - - switch (input_low) - { - case 0: - result[1] = '0'; - break; - case 1: - result[1] = '1'; - break; - case 2: - result[1] = '2'; - break; - case 3: - result[1] = '3'; - break; - case 4: - result[1] = '4'; - break; - case 5: - result[1] = '5'; - break; - case 6: - result[1] = '6'; - break; - case 7: - result[1] = '7'; - break; - case 8: - result[1] = '8'; - break; - case 9: - result[1] = '9'; - break; - case 10: - result[1] = 'A'; - break; - case 11: - result[1] = 'B'; - break; - case 12: - result[1] = 'C'; - break; - case 13: - result[1] = 'D'; - break; - case 14: - result[1] = 'E'; - break; - case 15: - result[1] = 'F'; - break; - } -} - - -//given a string with at least 2 chars in it, convert them to -// a byte value. No error checking done! -unsigned char parse_hex(char *str) -{ - //do this a little brute force to make it faster - - unsigned char result_high = 0; - unsigned char result_low = 0; - - switch (str[0]) - { - case '0' : - result_high = 0; - break; - case '1' : - result_high = 1; - break; - case '2' : - result_high = 2; - break; - case '3' : - result_high = 3; - break; - case '4' : - result_high = 4; - break; - case '5' : - result_high = 5; - break; - case '6' : - result_high = 6; - break; - case '7' : - result_high = 7; - break; - case '8' : - result_high = 8; - break; - case '9' : - result_high = 9; - break; - case 'A' : - result_high = 10; - break; - case 'B' : - result_high = 11; - break; - case 'C' : - result_high = 12; - break; - case 'D' : - result_high = 13; - break; - case 'E' : - result_high = 14; - break; - case 'F' : - result_high = 15; - break; - } - switch (str[1]) - { - case '0' : - result_low = 0; - break; - case '1' : - result_low = 1; - break; - case '2' : - result_low = 2; - break; - case '3' : - result_low = 3; - break; - case '4' : - result_low = 4; - break; - case '5' : - result_low = 5; - break; - case '6' : - result_low = 6; - break; - case '7' : - result_low = 7; - break; - case '8' : - result_low = 8; - break; - case '9' : - result_low = 9; - break; - case 'A' : - result_low = 10; - break; - case 'B' : - result_low = 11; - break; - case 'C' : - result_low = 12; - break; - case 'D' : - result_low = 13; - break; - case 'E' : - result_low = 14; - break; - case 'F' : - result_low = 15; - break; - } - return (unsigned char) ((result_high<<4) + result_low); -} - - -// input is a string with hex chars in it. Convert to binary and put in the result -PG_FUNCTION_INFO_V1(WKB_in); -Datum WKB_in(PG_FUNCTION_ARGS) -{ - char *str = PG_GETARG_CSTRING(0); - WellKnownBinary *result; - int size; - int t; - int input_str_len; - -//printf("wkb_in called\n"); - - input_str_len = strlen(str); - - if ( ( ( (int)(input_str_len/2.0) ) *2.0) != input_str_len) - { - elog(ERROR,"WKB_in parser - should be even number of characters!"); - PG_RETURN_NULL(); - } - - if (strspn(str,"0123456789ABCDEF") != strlen(str) ) - { - elog(ERROR,"WKB_in parser - input contains bad characters. Should only have '0123456789ABCDEF'!"); - PG_RETURN_NULL(); - } - size = (input_str_len/2) + 4; - result = (WellKnownBinary *) palloc(size); - result->size = size; - - for (t=0;tsize - 4) *2 +1; //+1 for null char - result = palloc (size_result); - result[size_result-1] = 0; //null terminate - - for (t=0; t< (WKB->size -4); t++) - { - deparse_hex( ((unsigned char *) WKB)[4 + t], &result[t*2]); - } - PG_RETURN_CSTRING(result); -} - - -#if USE_VERSION > 73 -/* - * This function must advance the StringInfo.cursor pointer - * and leave it at the end of StringInfo.buf. If it fails - * to do so the backend will raise an exception with message: - * ERROR: incorrect binary data format in bind parameter # - * - */ -PG_FUNCTION_INFO_V1(WKB_recv); -Datum WKB_recv(PG_FUNCTION_ARGS) -{ - StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); - bytea *result; - - //elog(NOTICE, "WKB_recv start"); - - /* Add VARLENA size info to make it a valid varlena object */ - result = (bytea *)palloc(buf->len+VARHDRSZ); - VARATT_SIZEP(result) = buf->len+VARHDRSZ; - memcpy(VARATT_DATA(result), buf->data, buf->len); - - /* Set cursor to the end of buffer (so the backend is happy) */ - buf->cursor = buf->len; - - //elog(NOTICE, "WKB_recv end (returning result)"); - PG_RETURN_POINTER(result); -} -#endif - -PG_FUNCTION_INFO_V1(WKBtoBYTEA); -Datum WKBtoBYTEA(PG_FUNCTION_ARGS) -{ - WellKnownBinary *WKB = (WellKnownBinary *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - bytea *result; - - result = (bytea*) palloc(WKB->size); - memcpy(result,WKB, WKB->size); - - PG_RETURN_POINTER(result); -} - -PG_FUNCTION_INFO_V1(geometry2box); -Datum geometry2box(PG_FUNCTION_ARGS) -{ - GEOMETRY *g = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - -//elog(NOTICE,"geometry2box - ymax is %.15g",g->bvol.URT.y); - - PG_RETURN_POINTER(convert_box3d_to_box(&g->bvol) ); - -} - -//create_histogram2d(BOX3D, boxesPerSide) -// returns a histgram with 0s in all the boxes. -PG_FUNCTION_INFO_V1(create_histogram2d); -Datum create_histogram2d(PG_FUNCTION_ARGS) -{ - BOX3D *bbox = (BOX3D *) PG_GETARG_POINTER(0); - int32 boxesPerSide= PG_GETARG_INT32(1); - HISTOGRAM2D *histo; - int size,t; - - - if ( (boxesPerSide <1) || (boxesPerSide >50) ) - { - elog(ERROR,"create_histogram2d - boxesPerSide is too small or big.\n"); - PG_RETURN_NULL() ; - } - - - size = sizeof(HISTOGRAM2D) + (boxesPerSide*boxesPerSide-1)*4 ; - - histo = (HISTOGRAM2D *) palloc (size); - histo->size = size; - - histo->xmin = bbox->LLB.x; - histo->ymin = bbox->LLB.y; - - - histo->xmax = bbox->URT.x; - histo->ymax = bbox->URT.y; - - histo->avgFeatureArea = 0; - - histo->boxesPerSide = boxesPerSide; - - for (t=0;tvalue[t] =0; - } - - //elog(NOTICE,"create_histogram2d returning"); - - PG_RETURN_POINTER(histo); - -} - - -//text form of HISTOGRAM2D is: -// 'HISTOGRAM2D(xmin,ymin,xmax,ymax,boxesPerSide;value[0],value[1],...') -// note the ";" in the middle (for easy parsing) -// I dont expect anyone to actually create one by hand -PG_FUNCTION_INFO_V1(histogram2d_in); -Datum histogram2d_in(PG_FUNCTION_ARGS) -{ - char *str = PG_GETARG_CSTRING(0); - HISTOGRAM2D *histo ; - int nitems; - double xmin,ymin,xmax,ymax; - int boxesPerSide; - double avgFeatureArea; - char *str2,*str3; - long datum; - - int t; - - while (isspace((unsigned char) *str)) - str++; - - if (strstr(str,"HISTOGRAM2D(") != str) - { - elog(ERROR,"histogram2d parser - doesnt start with 'HISTOGRAM2D(\n"); - PG_RETURN_NULL() ; - } - if (strstr(str,";") == NULL) - { - elog(ERROR,"histogram2d parser - doesnt have a ; in sring!\n"); - PG_RETURN_NULL() ; - } - - nitems = sscanf(str,"HISTOGRAM2D(%lf,%lf,%lf,%lf,%i,%lf;",&xmin,&ymin,&xmax,&ymax,&boxesPerSide,&avgFeatureArea); - - if (nitems != 6) - { - elog(ERROR,"histogram2d parser - couldnt parse initial portion of histogram!\n"); - PG_RETURN_NULL() ; - } - - if ( (boxesPerSide > 50) || (boxesPerSide <1) ) - { - elog(ERROR,"histogram2d parser - boxesPerSide is too big or too small\n"); - PG_RETURN_NULL() ; - } - - str2 = strstr(str,";"); - str2++; - - if (str2[0] ==0) - { - elog(ERROR,"histogram2d parser - no histogram values\n"); - PG_RETURN_NULL() ; - } - - histo = (HISTOGRAM2D *) palloc (sizeof(HISTOGRAM2D) + (boxesPerSide*boxesPerSide-1)*4 ); - histo->size = sizeof(HISTOGRAM2D) + (boxesPerSide*boxesPerSide-1)*4 ; - - for (t=0;tvalue[t] = (unsigned int) datum; - str2= str3+1; //move past the "," or ")" - } - histo->xmin = xmin; - histo->xmax = xmax; - histo->ymin = ymin; - histo->ymax = ymax; - histo->avgFeatureArea = avgFeatureArea; - histo->boxesPerSide = boxesPerSide; - - PG_RETURN_POINTER(histo); -} - - - -//text version -PG_FUNCTION_INFO_V1(histogram2d_out); -Datum histogram2d_out(PG_FUNCTION_ARGS) -{ - //char *result; - //result = palloc(200); - //sprintf(result,"HISTOGRAM2D(0,0,100,100,2;11,22,33,44)"); - //PG_RETURN_CSTRING(result); - - HISTOGRAM2D *histo = (HISTOGRAM2D *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - char *result; - int t; - char temp[100]; - int size; - - size = 26+6*MAX_DIGS_DOUBLE + histo->boxesPerSide*histo->boxesPerSide* (MAX_DIGS_DOUBLE+1); - result = palloc(size); - - sprintf(result,"HISTOGRAM2D(%.15g,%.15g,%.15g,%.15g,%i,%.15g;", - histo->xmin,histo->ymin,histo->xmax,histo->ymax,histo->boxesPerSide,histo->avgFeatureArea ); - - //elog(NOTICE,"so far: %s",result); - //elog(NOTICE,"buffsize=%i, size=%i",size,histo->size); - - for (t=0;tboxesPerSide*histo->boxesPerSide;t++) - { - if (t!=((histo->boxesPerSide*histo->boxesPerSide)-1)) - sprintf(temp,"%u,", histo->value[t]); - else - sprintf(temp,"%u", histo->value[t]); - strcat(result,temp); - } - - strcat(result,")"); - //elog(NOTICE,"about to return string (len=%i): -%s-",strlen(result),result); - - PG_RETURN_CSTRING(result); - -} - - - -int getint(char *c) -{ - int i; - memcpy( &i, c, 4); - return i; -//return *((int*)c); -} - -double getdouble(char *c) -{ - double d; - memcpy( &d, c, 8); - return d; -// return *((double*)c); -} - -//void flip_endian_double(char *dd); -//void flip_endian_int32(char *ii); - - -//select geometry(asbinary('POINT(1 2 3)','XDR')); -//select geometry(asbinary('POINT(1 2)','XDR')); -//select geometry(asbinary('POINT(1 2 3)','NDR')); -//select geometry(asbinary('POINT(1 2)','NDR')); - -//select geometry(asbinary('LINESTRING(1 2, 3 4)','XDR')); -//select geometry(asbinary('LINESTRING(1 2, 3 4)','NDR')); -//select geometry(asbinary('LINESTRING(1 2 5 , 3 4 6)','XDR')); -//select geometry(asbinary('LINESTRING(1 2 5 , 3 4 6)','NDR')); - - -//select geometry(asbinary('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))','XDR')); -//select geometry(asbinary('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))','NDR')); -//select geometry(asbinary('POLYGON((0 0 0, 10 0, 10 10, 0 10, 0 0))','XDR')); -//select geometry(asbinary('POLYGON((0 0 0, 10 0, 10 10, 0 10, 0 0))','NDR')); - -//select geometry(asbinary('POLYGON((5 5, 15 5, 15 7, 5 7, 5 5 ),(6 6,6.5 6, 6.5 6.5,6 6.5,6 6))','NDR')); -//select geometry(asbinary('POLYGON((5 5, 15 5, 15 7, 5 7, 5 5 ),(6 6,6.5 6, 6.5 6.5,6 6.5,6 6))','XDR')); -//select geometry(asbinary('POLYGON((5 5 0, 15 5, 15 7, 5 7, 5 5 ),(6 6,6.5 6, 6.5 6.5,6 6.5,6 6))','NDR')); -//select geometry(asbinary('POLYGON((5 5 0, 15 5, 15 7, 5 7, 5 5 ),(6 6,6.5 6, 6.5 6.5,6 6.5,6 6))','XDR')); - - -//select geometry(asbinary('MULTIPOINT(0 0, 10 0, 10 10, 0 10, 0 0)','NDR')); -//select geometry(asbinary('MULTIPOINT(0 0, 10 0, 10 10, 0 10, 0 0 0)','NDR')); -//select geometry(asbinary('MULTIPOINT(0 0, 10 0, 10 10, 0 10, 0 0)','XDR')); -//select geometry(asbinary('MULTIPOINT(0 0, 10 0, 10 10, 0 10, 0 0 0)','NDR')); - - -//select geometry(asbinary('MULTILINESTRING((5 5, 10 10),(1 1, 2 2) )','NDR')); -//select geometry(asbinary('MULTILINESTRING((5 5, 10 10),(1 1, 2 2 0) )','NDR')); -//select geometry(asbinary('MULTILINESTRING((5 5, 10 10),(1 1, 2 2) )','XDR')); -//select geometry(asbinary('MULTILINESTRING((5 5, 10 10),(1 1, 2 2 0) )','XDR')); - - -//select geometry(asbinary('MULTIPOLYGON(((5 5, 15 5, 15 7, 5 7, 5 5)),((1 1,1 2,2 2,1 2, 1 1)))','NDR')); -//select geometry(asbinary('MULTIPOLYGON(((5 5, 15 5, 15 7, 5 7, 5 5)),((1 1,1 2,2 2,1 2, 1 1 0)))','NDR')); -//select geometry(asbinary('MULTIPOLYGON(((5 5, 15 5, 15 7, 5 7, 5 5)),((1 1,1 2,2 2,1 2, 1 1)))','XDR')); -//select geometry(asbinary('MULTIPOLYGON(((5 5, 15 5, 15 7, 5 7, 5 5)),((1 1,1 2,2 2,1 2, 1 1 0)))','XDR')); - - -//select geometry(asbinary('GEOMETRYCOLLECTION(POINT(1 2),POINT(3 4))','NDR')); -//select geometry(asbinary('GEOMETRYCOLLECTION(POINT(1 2 3),LINESTRING(1 2, 3 4),POLYGON((0 0, 10 0, 10 10, 0 10, 0 0)))','NDR')); -// geometryfromWKB(, [] ) -PG_FUNCTION_INFO_V1(geometryfromWKB_SRID); -Datum geometryfromWKB_SRID(PG_FUNCTION_ARGS) -{ - char *wkb_input = (char *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - int SRID = PG_GETARG_INT32(1); - char *wkb = &wkb_input[4]; - int wkb_size = *((int *) wkb_input); - int bytes_read; - GEOMETRY *result; - - if ( ! PG_ARGISNULL(1) ) - SRID = PG_GETARG_INT32(1); - else - SRID = -1; - -//elog(NOTICE,"geometryfromWKB:: size = %i",wkb_size); - - result = WKBtoGeometry(wkb,wkb_size,&bytes_read); - - if (result == NULL) - { - PG_RETURN_NULL(); - } - else - { - result->SRID = SRID; - PG_RETURN_POINTER(result); - } -} - -PG_FUNCTION_INFO_V1(PointfromWKB_SRID); -Datum PointfromWKB_SRID(PG_FUNCTION_ARGS) -{ - int SRID; - GEOMETRY *geom; - - if ( ! PG_ARGISNULL(1) ) - SRID = PG_GETARG_INT32(1); - else - SRID = -1; - - - geom = (GEOMETRY *) DatumGetPointer( - DirectFunctionCall2(geometryfromWKB_SRID, - PG_GETARG_DATUM(0),Int32GetDatum(SRID) - )); - if (geom->type != POINTTYPE) - { - elog(ERROR,"PointfromWKB:: WKB isnt POINT"); - } - PG_RETURN_POINTER(geom); -} - -PG_FUNCTION_INFO_V1(LinefromWKB_SRID); -Datum LinefromWKB_SRID(PG_FUNCTION_ARGS) -{ - int SRID; - GEOMETRY *geom; - - if ( ! PG_ARGISNULL(1) ) - SRID = PG_GETARG_INT32(1); - else - SRID = -1; - - - geom = (GEOMETRY *) DatumGetPointer( - DirectFunctionCall2(geometryfromWKB_SRID, - PG_GETARG_DATUM(0),Int32GetDatum(SRID) - )); - if (geom->type != LINETYPE) - { - elog(ERROR,"LinefromWKB_SRID:: WKB isnt LINESTRING"); - } - PG_RETURN_POINTER(geom); -} - -PG_FUNCTION_INFO_V1(PolyfromWKB_SRID); -Datum PolyfromWKB_SRID(PG_FUNCTION_ARGS) -{ - int SRID; - GEOMETRY *geom; - - if ( ! PG_ARGISNULL(1) ) - SRID = PG_GETARG_INT32(1); - else - SRID = -1; - - - geom = (GEOMETRY *) DatumGetPointer( - DirectFunctionCall2(geometryfromWKB_SRID, - PG_GETARG_DATUM(0),Int32GetDatum(SRID) - )); - if (geom->type != POLYGONTYPE) - { - elog(ERROR,"PolyfromWKB_SRID:: WKB isnt POLYGON"); - } - PG_RETURN_POINTER(geom); -} - -PG_FUNCTION_INFO_V1(MPointfromWKB_SRID); -Datum MPointfromWKB_SRID(PG_FUNCTION_ARGS) -{ - int SRID; - GEOMETRY *geom; - - if ( ! PG_ARGISNULL(1) ) - SRID = PG_GETARG_INT32(1); - else - SRID = -1; - - - geom = (GEOMETRY *) DatumGetPointer( - DirectFunctionCall2(geometryfromWKB_SRID, - PG_GETARG_DATUM(0),Int32GetDatum(SRID) - )); - if (geom->type != MULTIPOINTTYPE) - { - elog(ERROR,"MPointfromWKB_SRID:: WKB isnt MULTIPOINT"); - } - PG_RETURN_POINTER(geom); -} - -PG_FUNCTION_INFO_V1(MLinefromWKB_SRID); -Datum MLinefromWKB_SRID(PG_FUNCTION_ARGS) -{ - int SRID; - GEOMETRY *geom; - - if ( ! PG_ARGISNULL(1) ) - SRID = PG_GETARG_INT32(1); - else - SRID = -1; - - - geom = (GEOMETRY *) DatumGetPointer( - DirectFunctionCall2(geometryfromWKB_SRID, - PG_GETARG_DATUM(0),Int32GetDatum(SRID) - )); - if (geom->type != MULTILINETYPE) - { - elog(ERROR,"MLinefromWKB_SRID:: WKB isnt MULTILINESTRING"); - } - PG_RETURN_POINTER(geom); -} - -PG_FUNCTION_INFO_V1(MPolyfromWKB_SRID); -Datum MPolyfromWKB_SRID(PG_FUNCTION_ARGS) -{ - int SRID; - GEOMETRY *geom; - - if ( ! PG_ARGISNULL(1) ) - SRID = PG_GETARG_INT32(1); - else - SRID = -1; - - - geom = (GEOMETRY *) DatumGetPointer( - DirectFunctionCall2(geometryfromWKB_SRID, - PG_GETARG_DATUM(0),Int32GetDatum(SRID) - )); - if (geom->type != MULTIPOLYGONTYPE) - { - elog(ERROR,"MPolyfromWKB_SRID:: WKB isnt MULTIPOLYGON"); - } - PG_RETURN_POINTER(geom); -} - -PG_FUNCTION_INFO_V1(GCfromWKB_SRID); -Datum GCfromWKB_SRID(PG_FUNCTION_ARGS) -{ - int SRID; - GEOMETRY *geom; - - if ( ! PG_ARGISNULL(1) ) - SRID = PG_GETARG_INT32(1); - else - SRID = -1; - - - geom = (GEOMETRY *) DatumGetPointer( - DirectFunctionCall2(geometryfromWKB_SRID, - PG_GETARG_DATUM(0),Int32GetDatum(SRID) - )); - if (geom->type != COLLECTIONTYPE) - { - elog(ERROR,"MPolyfromWKB_SRID:: WKB isnt GEOMETRYCOLLECTION"); - } - PG_RETURN_POINTER(geom); -} - - - - -//convert a WKB (that has length bytes) -// to a GEOMETRY. This function read bytes_read bytes during the operation -// This function will call itself "recursively" on GeometryCollections -GEOMETRY *WKBtoGeometry(char *WKB, int length, int *bytes_read) -{ - char myByteOrder; - char wkbByteOrder; - int wkbType; - char is3d; - -*bytes_read = 0; -if (length<5) - elog(ERROR,"WKB:: insufficient bytes in stream"); - - -if ( BYTE_ORDER == BIG_ENDIAN ) - myByteOrder=0; -else - myByteOrder=1; - -wkbByteOrder = *(WKB); - -if (!( (wkbByteOrder==0) || (wkbByteOrder==1) )) -{ - elog(ERROR,"WKB is not valid - endian code = %i", (int) wkbByteOrder); - return NULL; -} - -WKB ++; // skip to next byte -(*bytes_read)++; - -if (myByteOrder == wkbByteOrder) -{ - wkbType = getint(WKB); -} -else -{ - flip_endian_int32( WKB ); - wkbType = getint(WKB); -} -WKB += 4; -(*bytes_read) += 4; - -//elog(NOTICE,"my byte order is %i",myByteOrder); -//elog(NOTICE,"WKB byte order is %i",wkbByteOrder); -//elog(NOTICE,"WKB type is %i",wkbType); - -is3d = 0; - -switch (wkbType) -{ - case (0x80000000 +1): //point 3d - is3d = 1; - case 1: //point 2d - if ( (length-(*bytes_read)) < (16+is3d*8)) - elog(ERROR,"WKB:: insufficient bytes in stream"); - { - POINT3D pt; - if (myByteOrder == wkbByteOrder) - { - pt.x = getdouble(WKB); - WKB+=8; - (*bytes_read)+=8; - pt.y = getdouble(WKB); - WKB+=8; - (*bytes_read)+=8; - if (is3d) - { - pt.z = getdouble(WKB); - WKB+=8; - (*bytes_read)+=8; - } - else - { - pt.z=0; - } - } - else - { - flip_endian_double(WKB); - pt.x = getdouble(WKB); - WKB+=8; - (*bytes_read)+=8; - flip_endian_double(WKB); - pt.y = getdouble(WKB); - WKB+=8; - (*bytes_read)+=8; - if (is3d) - { - flip_endian_double(WKB); - pt.z = getdouble(WKB); - WKB+=8; - (*bytes_read)+=8; - } - else - { - pt.z =0; - } - } - if ( ! finite(pt.x) || ! finite(pt.y) || ! finite(pt.z) ) - { - elog(ERROR, "infinite coordinate in geom"); - return NULL; - } - return make_oneobj_geometry(sizeof(POINT3D), - (char *) &pt, - POINTTYPE, is3d, -1,1.0, 0.0, 0.0 - ); - } - - - break; - case (0x80000000 +2): //line 3d - is3d = 1; - case 2: //line 2d - if ( (length-(*bytes_read)) < (4)) - elog(ERROR,"WKB:: insufficient bytes in stream"); - { - int npoints,t; - POINT3D *pts; - int size; - LINE3D *line; - if (myByteOrder == wkbByteOrder) - { - npoints= getint(WKB); - WKB+=4; - (*bytes_read)+=4; - if ( (length-(*bytes_read)) < ((16+is3d*8))*npoints) - elog(ERROR,"WKB:: insufficient bytes in stream"); - - pts = palloc( npoints *sizeof(POINT3D)); - for (t=0;ttype = MULTIPOINTTYPE; - return result; - } - - mybytes_read = *bytes_read; - so_far = WKBtoGeometry(WKB, length - mybytes_read, &other_bytes_read); - (*bytes_read) = mybytes_read + other_bytes_read; - WKB += other_bytes_read; - so_far->type = MULTIPOINTTYPE; - - if (ngeoms ==1) - return so_far; - - for (t=1;ttype = MULTILINETYPE; - return result; - } - - mybytes_read = *bytes_read; - so_far = WKBtoGeometry(WKB, length - mybytes_read, &other_bytes_read); - (*bytes_read) = mybytes_read + other_bytes_read; - WKB += other_bytes_read; - so_far->type = MULTILINETYPE; - - if (ngeoms ==1) - return so_far; - - for (t=1;ttype = MULTIPOLYGONTYPE; - return result; - } - - mybytes_read = *bytes_read; - so_far = WKBtoGeometry(WKB, length - mybytes_read, &other_bytes_read); - (*bytes_read) = mybytes_read + other_bytes_read; - WKB += other_bytes_read; - so_far->type = MULTIPOLYGONTYPE; - - if (ngeoms ==1) - return so_far; - - for (t=1;ttype = COLLECTIONTYPE; - - if (ngeoms ==1) - return so_far; - - for (t=1;ttype != POLYGONTYPE) - { - elog(ERROR,"geometry_from_text_poly:: WKT isnt POLYGON"); - } - PG_RETURN_POINTER(geom); -} - -PG_FUNCTION_INFO_V1(geometry_from_text_line); -Datum geometry_from_text_line(PG_FUNCTION_ARGS) -{ - int SRID; - GEOMETRY *geom; - - if ( ! PG_ARGISNULL(1) ) - SRID = PG_GETARG_INT32(1); - else - SRID = -1; - - - geom = (GEOMETRY *) DatumGetPointer( - DirectFunctionCall2(geometry_from_text, - PG_GETARG_DATUM(0),Int32GetDatum(SRID) - )); - if (geom->type != LINETYPE) - { - elog(ERROR,"geometry_from_text_line:: WKT isnt LINESTRING"); - } - PG_RETURN_POINTER(geom); -} - - -PG_FUNCTION_INFO_V1(geometry_from_text_point); -Datum geometry_from_text_point(PG_FUNCTION_ARGS) -{ - int SRID; - GEOMETRY *geom; - - if ( ! PG_ARGISNULL(1) ) - SRID = PG_GETARG_INT32(1); - else - SRID = -1; - - - geom = (GEOMETRY *) DatumGetPointer( - DirectFunctionCall2(geometry_from_text, - PG_GETARG_DATUM(0),Int32GetDatum(SRID) - )); - if (geom->type != POINTTYPE) - { - elog(ERROR,"geometry_from_text_point:: WKT isnt POINT"); - } - PG_RETURN_POINTER(geom); -} - -PG_FUNCTION_INFO_V1(geometry_from_text_mpoint); -Datum geometry_from_text_mpoint(PG_FUNCTION_ARGS) -{ - int SRID; - GEOMETRY *geom; - - if ( ! PG_ARGISNULL(1) ) - SRID = PG_GETARG_INT32(1); - else - SRID = -1; - - - geom = (GEOMETRY *) DatumGetPointer( - DirectFunctionCall2(geometry_from_text, - PG_GETARG_DATUM(0),Int32GetDatum(SRID) - )); - if (geom->type != MULTIPOINTTYPE) - { - elog(ERROR,"geometry_from_text_mpoint:: WKT isnt MULTIPOINT"); - } - PG_RETURN_POINTER(geom); -} - -PG_FUNCTION_INFO_V1(geometry_from_text_mline); -Datum geometry_from_text_mline(PG_FUNCTION_ARGS) -{ - int SRID; - GEOMETRY *geom; - - if ( ! PG_ARGISNULL(1) ) - SRID = PG_GETARG_INT32(1); - else - SRID = -1; - - - geom = (GEOMETRY *) DatumGetPointer( - DirectFunctionCall2(geometry_from_text, - PG_GETARG_DATUM(0),Int32GetDatum(SRID) - )); - if (geom->type != MULTILINETYPE) - { - elog(ERROR,"geometry_from_text_mline:: WKT isnt MULTILINESTRING"); - } - PG_RETURN_POINTER(geom); -} - -PG_FUNCTION_INFO_V1(geometry_from_text_mpoly); -Datum geometry_from_text_mpoly(PG_FUNCTION_ARGS) -{ - int SRID; - GEOMETRY *geom; - - if ( ! PG_ARGISNULL(1) ) - SRID = PG_GETARG_INT32(1); - else - SRID = -1; - - - geom = (GEOMETRY *) DatumGetPointer( - DirectFunctionCall2(geometry_from_text, - PG_GETARG_DATUM(0),Int32GetDatum(SRID) - )); - if (geom->type != MULTIPOLYGONTYPE) - { - elog(ERROR,"geometry_from_text_mpoly:: WKT isnt MULTIPOLYGON"); - } - PG_RETURN_POINTER(geom); -} - -PG_FUNCTION_INFO_V1(geometry_from_text_gc); -Datum geometry_from_text_gc(PG_FUNCTION_ARGS) -{ - int SRID; - GEOMETRY *geom; - - if ( ! PG_ARGISNULL(1) ) - SRID = PG_GETARG_INT32(1); - else - SRID = -1; - - - geom = (GEOMETRY *) DatumGetPointer( - DirectFunctionCall2(geometry_from_text, - PG_GETARG_DATUM(0),Int32GetDatum(SRID) - )); - if (geom->type != COLLECTIONTYPE) - { - elog(ERROR,"geometry_from_text_gc:: WKT isnt GEOMETRYCOLLECTION"); - } - PG_RETURN_POINTER(geom); -} - - -//returns a GEOMETRYCOLLECTION(EMPTY) -// bbox of this object is BOX3D(0 0 0, 0 0 0) -// but should be treated as NULL -GEOMETRY *makeNullGeometry(int SRID) -{ - int size = sizeof(GEOMETRY); - GEOMETRY *result = palloc(size); - - - memset(result,0, size ); // init to 0s - - result->size = size; - result->nobjs = 0; - result->type = COLLECTIONTYPE; - result->is3d = false; - - - result->SRID = SRID; - result->scale = 1.0; - result->offsetX = 0; - result->offsetY = 0; - - memset(&result->bvol,0, sizeof(BOX3D) ); //make bbox :: BOX3D(0 0 0, 0 0 0) - - return result; -} - - diff --git a/hwgeom/postgis_ops.c b/hwgeom/postgis_ops.c deleted file mode 100644 index 188cad32a..000000000 --- a/hwgeom/postgis_ops.c +++ /dev/null @@ -1,1123 +0,0 @@ - -/********************************************************************** - * $Id$ - * - * PostGIS - Spatial Types for PostgreSQL - * http://postgis.refractions.net - * Copyright 2001-2003 Refractions Research Inc. - * - * This is free software; you can redistribute and/or modify it under - * the terms of the GNU General Public Licence. See the COPYING file. - * - ********************************************************************** - * $Log$ - * Revision 1.1 2004/09/20 07:50:06 strk - * prepared to contain old internal representation code - * - * Revision 1.13 2004/04/28 22:26:02 pramsey - * Fixed spelling mistake in header text. - * - * Revision 1.12 2003/11/20 15:34:02 strk - * expected in-transaction memory release for btree operators - * - * Revision 1.11 2003/11/19 15:26:57 strk - * Added geometry_le, geometry_ge, geometry_cmp functions, - * modified geometry_lt, geometry_gt, geometry_eq to be consistent. - * - * Revision 1.10 2003/07/25 17:08:37 pramsey - * Moved Cygwin endian define out of source files into postgis.h common - * header file. - * - * Revision 1.9 2003/07/01 18:30:55 pramsey - * Added CVS revision headers. - * - * - **********************************************************************/ - -#include "postgres.h" - -#include -#include -#include -#include -#include - -#include "access/gist.h" -#include "access/itup.h" -#include "access/rtree.h" - -#include "fmgr.h" - -#include "postgis.h" -#include "utils/elog.h" - -#define SHOW_DIGS_DOUBLE 15 -#define MAX_DIGS_DOUBLE (SHOW_DIGS_DOUBLE + 6 + 1 + 3 +1) - - -//given a bvol, make a "fake" geometry that contains it (for indexing) -GEOMETRY *make_bvol_geometry(BOX3D *box) -{ - return (GEOMETRY *) DatumGetPointer(DirectFunctionCall1(get_geometry_of_bbox,PointerGetDatum(box) ) ); -} - -// *********************************** -// GEOMETRY indexing (operator) fns -// NOTE: -// These work on the bbox of the geometry, not the -// individual components (except same) -// *********************************** - - -PG_FUNCTION_INFO_V1(box3d_same); -Datum box3d_same(PG_FUNCTION_ARGS) -{ - BOX3D *box1 = (BOX3D *) PG_GETARG_POINTER(0); - BOX3D *box2 = (BOX3D *) PG_GETARG_POINTER(1); - - bool result; - - result = ( FPeq(box1->LLB.x , box2->LLB.x) && - FPeq(box1->LLB.y , box2->LLB.y) && - FPeq(box1->URT.x , box2->URT.x) && - FPeq(box1->URT.y , box2->URT.y) - ); - PG_RETURN_BOOL(result); -} - - - - -PG_FUNCTION_INFO_V1(geometry_overleft); -Datum geometry_overleft(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - bool result; - -//printf("in geometry_overleft\n"); -//print_box(&geom1->bvol); -//print_box(&geom2->bvol); - - if (geom1->SRID != geom2->SRID) - { - elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n"); - PG_RETURN_NULL(); - } - - result = FPle(geom1->bvol.URT.x, geom2->bvol.URT.x); - - PG_RETURN_BOOL(result); -} - -PG_FUNCTION_INFO_V1(geometry_left); -Datum geometry_left(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - bool result; - -//printf("in geometry_left\n"); - - if (geom1->SRID != geom2->SRID) - { - elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n"); - PG_RETURN_NULL(); - } - - - result = FPlt(geom1->bvol.URT.x, geom2->bvol.LLB.x); - - - PG_RETURN_BOOL(result); -} - - -PG_FUNCTION_INFO_V1(geometry_right); -Datum geometry_right(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - bool result; -//printf("in geometry_right\n"); - - if (geom1->SRID != geom2->SRID) - { - elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n"); - PG_RETURN_NULL(); - } - - - result = FPgt(geom1->bvol.LLB.x, geom2->bvol.URT.x); - - PG_RETURN_BOOL(result); -} - -PG_FUNCTION_INFO_V1(geometry_overright); -Datum geometry_overright(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - bool result; -//printf("in geometry_overright\n"); - - if (geom1->SRID != geom2->SRID) - { - elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n"); - PG_RETURN_NULL(); - } - - - result = FPge(geom1->bvol.LLB.x, geom2->bvol.LLB.x); - - - - PG_RETURN_BOOL(result); -} - -PG_FUNCTION_INFO_V1(geometry_contained); -Datum geometry_contained(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - bool result; - - if (geom1->SRID != geom2->SRID) - { - elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n"); - PG_RETURN_NULL(); - } - - -//printf("in geometry_contained\n"); - - - result = FPle(geom1->bvol.URT.x, geom2->bvol.URT.x) && - FPge(geom1->bvol.LLB.x, geom2->bvol.LLB.x) && - FPle(geom1->bvol.URT.y, geom2->bvol.URT.y) && - FPge(geom1->bvol.LLB.y, geom2->bvol.LLB.y); - -//printf("returning geometry_contained\n"); - PG_RETURN_BOOL(result); -} - -PG_FUNCTION_INFO_V1(geometry_contain); -Datum geometry_contain(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - bool result; -//printf("in geometry_contain\n"); - - if (geom1->SRID != geom2->SRID) - { - elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n"); - PG_RETURN_NULL(); - } - - - result = FPge(geom1->bvol.URT.x, geom2->bvol.URT.x) && - FPle(geom1->bvol.LLB.x, geom2->bvol.LLB.x) && - FPge(geom1->bvol.URT.y, geom2->bvol.URT.y) && - FPle(geom1->bvol.LLB.y, geom2->bvol.LLB.y); - - - - PG_RETURN_BOOL(result); -} - -bool box3d_ov(BOX3D *box1, BOX3D *box2) -{ - bool result; - - result = - - /*overlap in x*/ - (( FPge(box1->URT.x, box2->URT.x) && - FPle(box1->LLB.x, box2->URT.x)) || - (FPge(box2->URT.x, box1->URT.x) && - FPle(box2->LLB.x, box1->URT.x))) - && - /*overlap in y*/ - ((FPge(box1->URT.y, box2->URT.y) && - FPle(box1->LLB.y, box2->URT.y)) || - (FPge(box2->URT.y, box1->URT.y) && - FPle(box2->LLB.y, box1->URT.y))); - -//printf("box3d_ov about to return %i\n",(int) result); - return result; -} - - -PG_FUNCTION_INFO_V1(geometry_overlap); -Datum geometry_overlap(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - -//printf("in geometry_overlap\n"); - - if (geom1->SRID != geom2->SRID) - { - elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n"); - PG_RETURN_NULL(); - } - - - PG_RETURN_BOOL(box3d_ov(&(geom1->bvol), &(geom2->bvol))); -} - - -bool is_same_point(POINT3D *p1, POINT3D *p2) -{ - return ( FPeq(p1->x, p2->x ) && FPeq(p1->y, p2->y ) &&FPeq(p1->z, p2->z ) ); -} - -bool is_same_line(LINE3D *l1, LINE3D *l2) -{ - int i; - //lines are directed, so all the points should be the same - - if (l1->npoints != l2->npoints) - return FALSE; //simple case, not the same # of points - - for (i=0;inpoints; i++) - { - if (!( is_same_point( &l1->points[i], &l2->points[i] ) ) ) - { - return FALSE; - } - } - return TRUE; -} - - -/*********************************************************** - * - * Comparision function for use in Binary Tree searches - * (ORDER BY, GROUP BY, DISTINCT) - * - ***********************************************************/ - - -PG_FUNCTION_INFO_V1(geometry_lt); -Datum geometry_lt(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - //elog(NOTICE, "geometry_lt called"); - - if (geom1->SRID != geom2->SRID) - { - elog(ERROR, - "Operation on two GEOMETRIES with different SRIDs\n"); - PG_RETURN_NULL(); - } - - if ( ! FPeq(geom1->bvol.LLB.x , geom2->bvol.LLB.x) ) { - if (geom1->bvol.LLB.x < geom2->bvol.LLB.x) - PG_RETURN_BOOL(TRUE); - } - - if ( ! FPeq(geom1->bvol.LLB.y , geom2->bvol.LLB.y) ) { - if (geom1->bvol.LLB.y < geom2->bvol.LLB.y) - PG_RETURN_BOOL(TRUE); - } - - if ( ! FPeq(geom1->bvol.LLB.z , geom2->bvol.LLB.z) ) { - if (geom1->bvol.LLB.z < geom2->bvol.LLB.z) - PG_RETURN_BOOL(TRUE); - } - - if ( ! FPeq(geom1->bvol.URT.x , geom2->bvol.URT.x) ) { - if (geom1->bvol.URT.x < geom2->bvol.URT.x) - PG_RETURN_BOOL(TRUE); - } - - if ( ! FPeq(geom1->bvol.URT.y , geom2->bvol.URT.y) ) { - if (geom1->bvol.URT.y < geom2->bvol.URT.y) - PG_RETURN_BOOL(TRUE); - } - - if ( ! FPeq(geom1->bvol.URT.z , geom2->bvol.URT.z) ) { - if (geom1->bvol.URT.z < geom2->bvol.URT.z) - PG_RETURN_BOOL(TRUE); - } - - PG_RETURN_BOOL(FALSE); -} - -PG_FUNCTION_INFO_V1(geometry_le); -Datum geometry_le(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - //elog(NOTICE, "geometry_le called"); - - if (geom1->SRID != geom2->SRID) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - elog(ERROR, - "Operation on two GEOMETRIES with different SRIDs\n"); - PG_RETURN_NULL(); - } - - if ( ! FPeq(geom1->bvol.LLB.x , geom2->bvol.LLB.x) ) { - if (geom1->bvol.LLB.x < geom2->bvol.LLB.x) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(TRUE); - } - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(FALSE); - } - - if ( ! FPeq(geom1->bvol.LLB.y , geom2->bvol.LLB.y) ) { - if (geom1->bvol.LLB.y < geom2->bvol.LLB.y) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(TRUE); - } - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(FALSE); - } - - if ( ! FPeq(geom1->bvol.LLB.z , geom2->bvol.LLB.z) ) { - if (geom1->bvol.LLB.z < geom2->bvol.LLB.z) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(TRUE); - } - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(FALSE); - } - - if ( ! FPeq(geom1->bvol.URT.x , geom2->bvol.URT.x) ) { - if (geom1->bvol.URT.x < geom2->bvol.URT.x) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(TRUE); - } - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(FALSE); - } - - if ( ! FPeq(geom1->bvol.URT.y , geom2->bvol.URT.y) ) { - if (geom1->bvol.URT.y < geom2->bvol.URT.y) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(TRUE); - } - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(FALSE); - } - - if ( ! FPeq(geom1->bvol.URT.z , geom2->bvol.URT.z) ) { - if (geom1->bvol.URT.z < geom2->bvol.URT.z) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(TRUE); - } - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(FALSE); - } - - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - - PG_RETURN_BOOL(TRUE); -} - -PG_FUNCTION_INFO_V1(geometry_eq); -Datum geometry_eq(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - //elog(NOTICE, "geometry_eq called"); - - if (geom1->SRID != geom2->SRID) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - elog(ERROR, - "Operation on two GEOMETRIES with different SRIDs\n"); - PG_RETURN_NULL(); - } - - if ( ! FPeq(geom1->bvol.LLB.x , geom2->bvol.LLB.x) ) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(FALSE); - } - - if ( ! FPeq(geom1->bvol.LLB.y , geom2->bvol.LLB.y) ) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(FALSE); - } - - if ( ! FPeq(geom1->bvol.LLB.z , geom2->bvol.LLB.z) ) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(FALSE); - } - - if ( ! FPeq(geom1->bvol.URT.x , geom2->bvol.URT.x) ) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(FALSE); - } - - if ( ! FPeq(geom1->bvol.URT.y , geom2->bvol.URT.y) ) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(FALSE); - } - - if ( ! FPeq(geom1->bvol.URT.z , geom2->bvol.URT.z) ) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(FALSE); - } - - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - - PG_RETURN_BOOL(TRUE); -} - -PG_FUNCTION_INFO_V1(geometry_ge); -Datum geometry_ge(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - //elog(NOTICE, "geometry_ge called"); - - if (geom1->SRID != geom2->SRID) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - elog(ERROR, - "Operation on two GEOMETRIES with different SRIDs\n"); - PG_RETURN_NULL(); - } - - if ( ! FPeq(geom1->bvol.LLB.x , geom2->bvol.LLB.x) ) { - if (geom1->bvol.LLB.x > geom2->bvol.LLB.x) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(TRUE); - } - PG_RETURN_BOOL(FALSE); - } - - if ( ! FPeq(geom1->bvol.LLB.y , geom2->bvol.LLB.y) ) { - if (geom1->bvol.LLB.y > geom2->bvol.LLB.y) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(TRUE); - } - PG_RETURN_BOOL(FALSE); - } - - if ( ! FPeq(geom1->bvol.LLB.z , geom2->bvol.LLB.z) ) { - if (geom1->bvol.LLB.z > geom2->bvol.LLB.z) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(TRUE); - } - PG_RETURN_BOOL(FALSE); - } - - if ( ! FPeq(geom1->bvol.URT.x , geom2->bvol.URT.x) ) { - if (geom1->bvol.URT.x > geom2->bvol.URT.x) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(TRUE); - } - PG_RETURN_BOOL(FALSE); - } - - if ( ! FPeq(geom1->bvol.URT.y , geom2->bvol.URT.y) ) { - if (geom1->bvol.URT.y > geom2->bvol.URT.y) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(TRUE); - } - PG_RETURN_BOOL(FALSE); - } - - if ( ! FPeq(geom1->bvol.URT.z , geom2->bvol.URT.z) ) { - if (geom1->bvol.URT.z > geom2->bvol.URT.z) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(TRUE); - } - PG_RETURN_BOOL(FALSE); - } - - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - - PG_RETURN_BOOL(TRUE); -} - -PG_FUNCTION_INFO_V1(geometry_gt); -Datum geometry_gt(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - //elog(NOTICE, "geometry_gt called"); - - if (geom1->SRID != geom2->SRID) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) - pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) - pfree(geom2); - elog(ERROR, - "Operation on two GEOMETRIES with different SRIDs\n"); - PG_RETURN_NULL(); - } - - if ( ! FPeq(geom1->bvol.LLB.x , geom2->bvol.LLB.x) ) { - if (geom1->bvol.LLB.x > geom2->bvol.LLB.x) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(TRUE); - } - } - - if ( ! FPeq(geom1->bvol.LLB.y , geom2->bvol.LLB.y) ) { - if (geom1->bvol.LLB.y > geom2->bvol.LLB.y) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(TRUE); - } - } - - if ( ! FPeq(geom1->bvol.LLB.z , geom2->bvol.LLB.z) ) { - if (geom1->bvol.LLB.z > geom2->bvol.LLB.z) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(TRUE); - } - } - - if ( ! FPeq(geom1->bvol.URT.x , geom2->bvol.URT.x) ) { - if (geom1->bvol.URT.x > geom2->bvol.URT.x) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(TRUE); - } - } - - if ( ! FPeq(geom1->bvol.URT.y , geom2->bvol.URT.y) ) { - if (geom1->bvol.URT.y > geom2->bvol.URT.y) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(TRUE); - } - } - - if ( ! FPeq(geom1->bvol.URT.z , geom2->bvol.URT.z) ) { - if (geom1->bvol.URT.z > geom2->bvol.URT.z) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_BOOL(TRUE); - } - } - - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - - PG_RETURN_BOOL(FALSE); -} - -PG_FUNCTION_INFO_V1(geometry_cmp); -Datum geometry_cmp(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - //elog(NOTICE, "geometry_cmp called"); - - if (geom1->SRID != geom2->SRID) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) - pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) - pfree(geom2); - elog(ERROR, - "Operation on two GEOMETRIES with different SRIDs\n"); - PG_RETURN_NULL(); - } - - if ( ! FPeq(geom1->bvol.LLB.x , geom2->bvol.LLB.x) ) { - if (geom1->bvol.LLB.x < geom2->bvol.LLB.x) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_INT32(-1); - } - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_INT32(1); - } - - if ( ! FPeq(geom1->bvol.LLB.y , geom2->bvol.LLB.y) ) { - if (geom1->bvol.LLB.y < geom2->bvol.LLB.y) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_INT32(-1); - } - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_INT32(1); - } - - if ( ! FPeq(geom1->bvol.LLB.z , geom2->bvol.LLB.z) ) { - if (geom1->bvol.LLB.z < geom2->bvol.LLB.z) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_INT32(-1); - } - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_INT32(1); - } - - if ( ! FPeq(geom1->bvol.URT.x , geom2->bvol.URT.x) ) { - if (geom1->bvol.URT.x < geom2->bvol.URT.x) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_INT32(-1); - } - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_INT32(1); - } - - if ( ! FPeq(geom1->bvol.URT.y , geom2->bvol.URT.y) ) { - if (geom1->bvol.URT.y < geom2->bvol.URT.y) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_INT32(-1); - } - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_INT32(1); - } - - if ( ! FPeq(geom1->bvol.URT.z , geom2->bvol.URT.z) ) { - if (geom1->bvol.URT.z < geom2->bvol.URT.z) - { - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_INT32(-1); - } - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - PG_RETURN_INT32(1); - } - - if ( (Pointer *)PG_GETARG_DATUM(0) != (Pointer *)geom1 ) pfree(geom1); - if ( (Pointer *)PG_GETARG_DATUM(1) != (Pointer *)geom2 ) pfree(geom2); - - PG_RETURN_INT32(0); -} - - -//order of points in a ring IS important -//order of rings is also important -bool is_same_polygon(POLYGON3D *poly1, POLYGON3D *poly2) -{ - int i; - int numb_points; - POINT3D *pts1, *pts2; - - - if (poly1->nrings != poly2->nrings) - return FALSE; - - numb_points = 0; - for (i=0; i< poly1->nrings; i++) - { - if (poly1->npoints[i] != poly2->npoints[i]) - return FALSE; - numb_points += poly1->npoints[i]; - } - - pts1 = (POINT3D *) ( (char *)&(poly1->npoints[poly1->nrings] ) ); - pts1 = (POINT3D *) MAXALIGN(pts1); - - - pts2 = (POINT3D *) ( (char *)&(poly2->npoints[poly2->nrings] ) ); - pts2 = (POINT3D *) MAXALIGN(pts2); - - for (i=0; i< numb_points; i++) - { - if (!( is_same_point( &pts1[i], &pts2[i] ) ) ) - { - return FALSE; - } - - } - return TRUE; -} - - - -//FIXED: -// geom1 same as geom2 -// iff -// + have same type -// + have same # objects -// + have same bvol -// + each object in geom1 has a corresponding object in geom2 (see above) -PG_FUNCTION_INFO_V1(geometry_same); -Datum geometry_same(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - bool result; - int i,j; - bool *already_hit; - int32 type1,type2; - int32 *offsets1,*offsets2; - char *o1,*o2; - - if (geom1->SRID != geom2->SRID) - { - elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n"); - PG_RETURN_NULL(); - } - - -//printf("in geometry_same\n"); - - //This was removed because this doesnt actually refer to the geometry, but how it is represented - // to the user - //easy tests - //if (geom1->type != geom2-> type) - // PG_RETURN_BOOL(FALSE); - - - - if (geom1->nobjs != geom2->nobjs) - PG_RETURN_BOOL(FALSE); - - result = DatumGetBool(DirectFunctionCall2(box3d_same, - PointerGetDatum(&geom1->bvol), - PointerGetDatum(&geom2->bvol) ) ); - - if (result == FALSE) - PG_RETURN_BOOL(FALSE); - - if (geom1->nobjs<1) - return FALSE; // no objects (probably a BOXONLYTYPE) and bvols dont match - -// printf(" +have to do it the hard way"); - - already_hit = (bool *) palloc (geom2->nobjs * sizeof(bool) ); - memset(already_hit, 0, geom2->nobjs * sizeof(bool) ); //all false - - - offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ; - offsets2 = (int32 *) ( ((char *) &(geom2->objType[0] ))+ sizeof(int32) * geom2->nobjs ) ; - - - //now have to do a scan of each object - - for (j=0; j< geom1->nobjs; j++) //for each object in geom1 - { - o1 = (char *) geom1 +offsets1[j] ; - type1= geom1->objType[j]; - - for(i=0;inobjs; i++) //for each object in geom2 - { - o2 = (char *) geom2 +offsets2[i] ; - type2= geom2->objType[j]; - - if ( (type1 == type2) && (!(already_hit[i])) ) - { - //see if they match - if (type1 == POINTTYPE) - { - if (is_same_point((POINT3D *) o1,(POINT3D *) o2)) - { - already_hit[i] = TRUE; - break; - } - } - if (type1 == LINETYPE) - { - if (is_same_line((LINE3D *) o1,(LINE3D *) o2)) - { - already_hit[i] = TRUE; - break; - } - - } - if (type2 == POLYGONTYPE) - { - if (is_same_polygon((POLYGON3D *) o1,(POLYGON3D *) o2)) - { - already_hit[i] = TRUE; - break; - } - } - } - } - if (i == geom1->nobjs) - PG_RETURN_BOOL(FALSE); // couldnt find match - } - PG_RETURN_BOOL(TRUE); -} - -/******************************************************* - *Box3d routines - *******************************************************/ - - - -/* box_overlap - does box1 overlap box2? - */ -PG_FUNCTION_INFO_V1(box3d_overlap); -Datum box3d_overlap(PG_FUNCTION_ARGS) -{ - BOX3D *box1 = (BOX3D *) PG_GETARG_POINTER(0); - BOX3D *box2 = (BOX3D *) PG_GETARG_POINTER(1); - - PG_RETURN_BOOL(box3d_ov(box1, box2)); -} - -/* box_overleft - is the right edge of box1 to the left of - * the right edge of box2? - * - * This is "less than or equal" for the end of a time range, - * when time ranges are stored as rectangles. - */ -PG_FUNCTION_INFO_V1(box3d_overleft); -Datum box3d_overleft(PG_FUNCTION_ARGS) -{ - BOX3D *box1 = (BOX3D *) PG_GETARG_POINTER(0); - BOX3D *box2 = (BOX3D *) PG_GETARG_POINTER(1); - - bool result; - - result = FPle(box1->URT.x, box2->URT.x); - -//printf("box3d_overleft about to return %i\n",(int) result); - - PG_RETURN_BOOL(result); -} - -/* box_right - is box1 strictly right of box2? - */ -PG_FUNCTION_INFO_V1(box3d_right); -Datum box3d_right(PG_FUNCTION_ARGS) -{ - BOX3D *box1 = (BOX3D *) PG_GETARG_POINTER(0); - BOX3D *box2 = (BOX3D *) PG_GETARG_POINTER(1); - - bool result; - - result = FPgt(box1->LLB.x, box2->URT.x); -//printf("box3d_rightabout to return %i\n",(int) result); - - PG_RETURN_BOOL(result); -} - -/* box_contain - does box1 contain box2? - */ -PG_FUNCTION_INFO_V1(box3d_contain); -Datum box3d_contain(PG_FUNCTION_ARGS) -{ - BOX3D *box1 = (BOX3D *) PG_GETARG_POINTER(0); - BOX3D *box2 = (BOX3D *) PG_GETARG_POINTER(1); - - bool result; - - result = FPge(box1->URT.x, box2->URT.x) && - FPle(box1->LLB.x, box2->LLB.x) && - FPge(box1->URT.y, box2->URT.y) && - FPle(box1->LLB.y, box2->LLB.y); - //printf("box3d_contain about to return %i\n",(int) result); - - - PG_RETURN_BOOL(result); -} - - -/****************************************************** - * RTREE index requires these 3 functions - ******************************************************/ - -PG_FUNCTION_INFO_V1(geometry_union); -Datum geometry_union(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - GEOMETRY *result = (GEOMETRY *) palloc(sizeof(GEOMETRY) ); - BOX3D *n; - - if (geom1->SRID != geom2->SRID) - { - elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n"); - PG_RETURN_NULL(); - } - - - result->size = sizeof(GEOMETRY); - result->type = BBOXONLYTYPE; - result->nobjs = -1; - result->SRID = geom1->SRID; - result->scale = geom1->scale; - result->offsetX = geom1->offsetX; - result->offsetY = geom1->offsetY; - - - n = &result->bvol; - - //cheat - just change the bbox - - n->URT.x = max(geom1->bvol.URT.x, geom2->bvol.URT.x); - n->URT.y = max(geom1->bvol.URT.y, geom2->bvol.URT.y); - n->LLB.x = min(geom1->bvol.LLB.x, geom2->bvol.LLB.x); - n->LLB.y = min(geom1->bvol.LLB.y, geom2->bvol.LLB.y); - - - n->URT.z = max(geom1->bvol.URT.z, geom2->bvol.URT.z); - n->LLB.z = min(geom1->bvol.LLB.z, geom2->bvol.LLB.z); - - PG_FREE_IF_COPY(geom1, 0); - PG_FREE_IF_COPY(geom2, 1); - - PG_RETURN_POINTER(result); -} - -PG_FUNCTION_INFO_V1(geometry_inter); -Datum geometry_inter(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - GEOMETRY *result = (GEOMETRY *) palloc(sizeof(GEOMETRY) ); - - if (geom1->SRID != geom2->SRID) - { - elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n"); - PG_RETURN_NULL(); - } - - result->size = sizeof(GEOMETRY); - result->type = BBOXONLYTYPE; - result->nobjs = -1; - result->SRID = geom1->SRID; - result->scale = geom1->scale; - result->offsetX = geom1->offsetX; - result->offsetY = geom1->offsetY; - - result->bvol.URT.x = min(geom1->bvol.URT.x, geom2->bvol.URT.x); - result->bvol.URT.y = min(geom1->bvol.URT.y, geom2->bvol.URT.y); - result->bvol.URT.z = min(geom1->bvol.URT.z, geom2->bvol.URT.z); - - result->bvol.LLB.x = max(geom1->bvol.LLB.x, geom2->bvol.LLB.x); - result->bvol.LLB.y = max(geom1->bvol.LLB.y, geom2->bvol.LLB.y); - result->bvol.LLB.z = max(geom1->bvol.LLB.z, geom2->bvol.LLB.z); - - if (result->bvol.URT.x < result->bvol.LLB.x || result->bvol.URT.y < result->bvol.LLB.y) - { - pfree(result); - /* Indicate "no intersection" by returning NULL pointer */ - result = NULL; - } - PG_FREE_IF_COPY(geom1, 0); - PG_FREE_IF_COPY(geom2, 1); - - PG_RETURN_POINTER(result); -} - -PG_FUNCTION_INFO_V1(geometry_size); -Datum geometry_size(PG_FUNCTION_ARGS) -{ - Pointer aptr = PG_GETARG_POINTER(0); - - float *size = (float *) PG_GETARG_POINTER(1); - GEOMETRY *a; - float xdim,ydim; - - if (aptr == NULL) - { - *size = 0.0; - //printf(" + aprt==null return in 0.0\n"); - PG_RETURN_VOID(); - } - - a = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - - if (a->bvol.URT.x <= a->bvol.LLB.x || - a->bvol.URT.y <= a->bvol.LLB.y) - *size = 0.0; - else - { - xdim = (a->bvol.URT.x - a->bvol.LLB.x); - ydim = (a->bvol.URT.y - a->bvol.LLB.y); - - *size = (float) (xdim * ydim); - } - - //printf(" + about to return (and free) with %e\n",*size); - - /* Avoid leaking memory when handed toasted input. */ - PG_FREE_IF_COPY(a, 0); - - PG_RETURN_VOID(); -} diff --git a/hwgeom/postgis_proj.c b/hwgeom/postgis_proj.c deleted file mode 100644 index 9d09440da..000000000 --- a/hwgeom/postgis_proj.c +++ /dev/null @@ -1,646 +0,0 @@ - -/********************************************************************** - * $Id$ - * - * PostGIS - Spatial Types for PostgreSQL - * http://postgis.refractions.net - * Copyright 2001-2003 Refractions Research Inc. - * - * This is free software; you can redistribute and/or modify it under - * the terms of the GNU General Public Licence. See the COPYING file. - * - ********************************************************************** - * $Log$ - * Revision 1.1 2004/09/20 07:50:06 strk - * prepared to contain old internal representation code - * - * Revision 1.14 2004/09/16 15:50:59 mleslie - * Added the distance_sphere function to calculate the distance between two points - * on an earth-sized sphere using an algorithm implemented by Bruno Wolff III. - * Added the postgresql loader function. - * - * Revision 1.13 2004/04/28 22:26:02 pramsey - * Fixed spelling mistake in header text. - * - * Revision 1.12 2004/02/06 00:42:25 dblasby - * moved forward declarations from postgis.h to postgis_proj.c - * - * Revision 1.11 2004/02/05 20:31:48 dblasby - * Optimized the curvature method (doesnt have to calculate e2) - * - * Revision 1.10 2004/02/05 20:21:14 dblasby - * Added 'curvature method' for cases where the original algorithm breaks down. - * - * Revision 1.9 2004/02/04 02:53:20 dblasby - * applied patricia tozer's patch (distance function was taking acos of something - * just slightly outside [-1,1]). - * - * Revision 1.8 2003/12/04 18:58:35 dblasby - * changed david skae to skea - * - * Revision 1.7 2003/07/01 18:30:55 pramsey - * Added CVS revision headers. - * - * - **********************************************************************/ - -#include "postgres.h" - - -#include -#include -#include -#include -#include - -#include "access/gist.h" -#include "access/itup.h" -#include "access/rtree.h" - - -#include "fmgr.h" - - -#include "postgis.h" -#include "utils/elog.h" - -#define SHOW_DIGS_DOUBLE 15 -#define MAX_DIGS_DOUBLE (SHOW_DIGS_DOUBLE + 6 + 1 + 3 +1) - - -// distance from -126 49 to -126 49.011096139863 in 'SPHEROID["GRS_1980",6378137,298.257222101]' is 1234.000 - - -double distance_sphere_method(double lat1, double long1,double lat2,double long2, SPHEROID *sphere); -double distance_ellipse_calculation(double lat1, double long1, - double lat2, double long2, - SPHEROID *sphere); - -//use the WKT definition of an ellipsoid -// ie. SPHEROID["name",A,rf] or SPHEROID("name",A,rf) -// SPHEROID["GRS_1980",6378137,298.257222101] -// wkt says you can use "(" or "[" - -PG_FUNCTION_INFO_V1(ellipsoid_in); -Datum ellipsoid_in(PG_FUNCTION_ARGS) -{ - char *str = PG_GETARG_CSTRING(0); - SPHEROID *sphere = (SPHEROID *) palloc(sizeof(SPHEROID)); - int nitems; - double rf; - - - memset(sphere,0, sizeof(SPHEROID)); - - if (strstr(str,"SPHEROID") != str ) - { - elog(ERROR,"SPHEROID parser - doesnt start with SPHEROID"); - pfree(sphere); - PG_RETURN_NULL(); - } - - nitems = sscanf(str,"SPHEROID[\"%19[^\"]\",%lf,%lf]",sphere->name,&sphere->a,&rf); - - if ( nitems==0) - nitems = sscanf(str,"SPHEROID(\"%19[^\"]\",%lf,%lf)",sphere->name,&sphere->a,&rf); - - if (nitems != 3) - { - elog(ERROR,"SPHEROID parser - couldnt parse the spheroid"); - pfree(sphere); - PG_RETURN_NULL(); - } - - sphere->f = 1.0/rf; - sphere->b = sphere->a - (1.0/rf)*sphere->a; - sphere->e_sq = ((sphere->a*sphere->a) - (sphere->b*sphere->b) )/ (sphere->a*sphere->a); - sphere->e = sqrt(sphere->e_sq); - - PG_RETURN_POINTER(sphere); - -} - - - -PG_FUNCTION_INFO_V1(ellipsoid_out); -Datum ellipsoid_out(PG_FUNCTION_ARGS) -{ - SPHEROID *sphere = (SPHEROID *) PG_GETARG_POINTER(0); - char *result; - - result = palloc(MAX_DIGS_DOUBLE + MAX_DIGS_DOUBLE + 20 + 9 + 2); - - sprintf(result,"SPHEROID(\"%s\",%.15g,%.15g)", sphere->name,sphere->a, 1.0/sphere->f); - - PG_RETURN_CSTRING(result); -} - -//support function for distance calc - //code is taken from David Skea - //Geographic Data BC, Province of British Columbia, Canada. - // Thanks to GDBC and David Skea for allowing this to be - // put in PostGIS. -double deltaLongitude(double azimuth, double sigma, double tsm,SPHEROID *sphere) -{ - // compute the expansion C - double das,C; - double ctsm,DL; - - das = cos(azimuth)*cos(azimuth); - C = sphere->f/16.0 * das * (4.0 + sphere->f * (4.0 - 3.0 * das)); - // compute the difference in longitude - - ctsm = cos(tsm); - DL = ctsm + C * cos(sigma) * (-1.0 + 2.0 * ctsm*ctsm); - DL = sigma + C * sin(sigma) * DL; - return (1.0 - C) * sphere->f * sin(azimuth) * DL; -} - - -//support function for distance calc - //code is taken from David Skea - //Geographic Data BC, Province of British Columbia, Canada. - // Thanks to GDBC and David Skea for allowing this to be - // put in PostGIS. -double mu2(double azimuth,SPHEROID *sphere) -{ - double e2; - - e2 = sqrt(sphere->a*sphere->a-sphere->b*sphere->b)/sphere->b; - return cos(azimuth)*cos(azimuth) * e2*e2; -} - - -//support function for distance calc - //code is taken from David Skea - //Geographic Data BC, Province of British Columbia, Canada. - // Thanks to GDBC and David Skea for allowing this to be - // put in PostGIS. -double bigA(double u2) -{ - return 1.0 + u2/256.0 * (64.0 + u2 * (-12.0 + 5.0 * u2)); -} - - -//support function for distance calc - //code is taken from David Skea - //Geographic Data BC, Province of British Columbia, Canada. - // Thanks to GDBC and David Skea for allowing this to be - // put in PostGIS. -double bigB(double u2) -{ - return u2/512.0 * (128.0 + u2 * (-64.0 + 37.0 * u2)); -} - - - -double distance_ellipse(double lat1, double long1, - double lat2, double long2, - SPHEROID *sphere) -{ - double result; - - if ( (lat1==lat2) && (long1 == long2) ) - { - return 0.0; // same point, therefore zero distance - } - - result = distance_ellipse_calculation(lat1,long1,lat2,long2,sphere); -// result2 = distance_sphere_method(lat1, long1,lat2,long2, sphere); - -//elog(NOTICE,"delta = %lf, skae says: %.15lf,2 circle says: %.15lf",(result2-result),result,result2); -//elog(NOTICE,"2 circle says: %.15lf",result2); - - if (result != result) // NaN check (x==x for all x except NaN by IEEE definition) - { - result = distance_sphere_method(lat1, long1,lat2,long2, sphere); - } - - return result; -} - -//given 2 lat/longs and ellipse, find the distance -// note original r = 1st, s=2nd location -double distance_ellipse_calculation(double lat1, double long1, - double lat2, double long2, - SPHEROID *sphere) -{ - //code is taken from David Skea - //Geographic Data BC, Province of British Columbia, Canada. - // Thanks to GDBC and David Skea for allowing this to be - // put in PostGIS. - - double L1,L2,sinU1,sinU2,cosU1,cosU2; - double dl,dl1,dl2,dl3,cosdl1,sindl1; - double cosSigma,sigma,azimuthEQ,tsm; - double u2,A,B; - double dsigma; - - double TEMP; - - int iterations; - - - L1 = atan((1.0 - sphere->f ) * tan( lat1) ); - L2 = atan((1.0 - sphere->f ) * tan( lat2) ); - sinU1 = sin(L1); - sinU2 = sin(L2); - cosU1 = cos(L1); - cosU2 = cos(L2); - - dl = long2- long1; - dl1 = dl; - cosdl1 = cos(dl); - sindl1 = sin(dl); - iterations = 0; - do { - cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosdl1; - sigma = acos(cosSigma); - azimuthEQ = asin((cosU1 * cosU2 * sindl1)/sin(sigma)); - - // patch from patrica tozer to handle minor mathematical stability problem - TEMP = cosSigma - (2.0 * sinU1 * sinU2)/(cos(azimuthEQ)*cos(azimuthEQ)); - if(TEMP > 1) - { - TEMP = 1; - } - else if(TEMP < -1) - { - TEMP = -1; - } - tsm = acos(TEMP); - - - //tsm = acos(cosSigma - (2.0 * sinU1 * sinU2)/(cos(azimuthEQ)*cos(azimuthEQ))); - dl2 = deltaLongitude(azimuthEQ, sigma, tsm,sphere); - dl3 = dl1 - (dl + dl2); - dl1 = dl + dl2; - cosdl1 = cos(dl1); - sindl1 = sin(dl1); - iterations++; - } while ( (iterations<999) && (fabs(dl3) > 1.0e-032)); - - // compute expansions A and B - u2 = mu2(azimuthEQ,sphere); - A = bigA(u2); - B = bigB(u2); - - // compute length of geodesic - dsigma = B * sin(sigma) * (cos(tsm) + (B*cosSigma*(-1.0 + 2.0 * (cos(tsm)*cos(tsm))))/4.0); - return sphere->b * (A * (sigma - dsigma)); -} - - -double length2d_ellipse_linestring(LINE3D *line, SPHEROID *sphere) -{ - - int i; - POINT3D *frm,*to; - double dist = 0.0; - - if (line->npoints <2) - return 0.0; //must have >1 point to make sense - - frm = &line->points[0]; - - for (i=1; inpoints;i++) - { - to = &line->points[i]; - - dist += distance_ellipse(frm->y*M_PI/180.0 , frm->x*M_PI/180.0, - to->y*M_PI/180.0 , to->x*M_PI/180.0, - sphere); - - frm = to; - } - return dist; -} - -double length3d_ellipse_linestring(LINE3D *line, SPHEROID *sphere) -{ - int i; - POINT3D *frm,*to; - double dist = 0.0; - double dist_ellipse; - - if (line->npoints <2) - return 0.0; //must have >1 point to make sense - - frm = &line->points[0]; - - for (i=1; inpoints;i++) - { - to = &line->points[i]; - - dist_ellipse = distance_ellipse(frm->y*M_PI/180.0 , frm->x*M_PI/180.0, - to->y*M_PI/180.0 , to->x*M_PI/180.0, - sphere); - - dist += sqrt(dist_ellipse*dist_ellipse + (frm->z*frm->z) ); - - frm = to; - } - return dist; - - -} - - -// length_ellipsoid(GEOMETRY, SPHEROID) -// find the "length of a geometry" -// length2d(point) = 0 -// length2d(line) = length of line -// length2d(polygon) = 0 -// uses ellipsoidal math to find the distance -//// x's are longitude, and y's are latitude - both in decimal degrees - -PG_FUNCTION_INFO_V1(length_ellipsoid); -Datum length_ellipsoid(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - SPHEROID *sphere = (SPHEROID *) PG_GETARG_POINTER(1); - - int32 *offsets1; - char *o1; - int32 type1,j; - LINE3D *line; - double dist = 0.0; - - offsets1 = (int32 *) ( ((char *) &(geom->objType[0] ))+ sizeof(int32) * geom->nobjs ) ; - - - //now have to do a scan of each object - - for (j=0; j< geom->nobjs; j++) //for each object in geom1 - { - o1 = (char *) geom +offsets1[j] ; - type1= geom->objType[j]; - if (type1 == LINETYPE) //LINESTRING - { - line = (LINE3D *) o1; - dist += length2d_ellipse_linestring(line,sphere); - } - } - PG_RETURN_FLOAT8(dist); - - - -} - -// length3d_ellipsoid(GEOMETRY, SPHEROID) -// find the "length of a geometry" -// length3d(point) = 0 -// length3d(line) = length of line -// length3d(polygon) = 0 -// uses ellipsoidal math to find the distance on the XY plane, then -// uses simple Pythagoras theorm to find the 3d distance on each segment -// x's are longitude, and y's are latitude - both in decimal degrees - -PG_FUNCTION_INFO_V1(length3d_ellipsoid); -Datum length3d_ellipsoid(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - SPHEROID *sphere = (SPHEROID *) PG_GETARG_POINTER(1); - - int32 *offsets1; - char *o1; - int32 type1,j; - LINE3D *line; - double dist = 0.0; - - offsets1 = (int32 *) ( ((char *) &(geom->objType[0] ))+ sizeof(int32) * geom->nobjs ) ; - - - //now have to do a scan of each object - - for (j=0; j< geom->nobjs; j++) //for each object in geom1 - { - o1 = (char *) geom +offsets1[j] ; - type1= geom->objType[j]; - if (type1 == LINETYPE) //LINESTRING - { - line = (LINE3D *) o1; - dist += length3d_ellipse_linestring(line,sphere); - } - } - PG_RETURN_FLOAT8(dist); -} - -/* - * This algorithm was taken from the geo_distance function of the - * earthdistance package contributed by Bruno Wolff III. - * It was altered to accept GEOMETRY objects and return results in - * meters. - */ -PG_FUNCTION_INFO_V1(distance_sphere); -Datum distance_sphere(PG_FUNCTION_ARGS) -{ - const double EARTH_RADIUS = 6370986.884258304; - const double TWO_PI = 2.0 * M_PI; - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - POINT3D *pt1, *pt2; - int32 *offsets1; - int32 *offsets2; - char *o; - - double long1, lat1, long2, lat2; - double longdiff; - double sino; - - if (geom1->SRID != geom2->SRID) - { - elog(ERROR, "optimistic_overlap:Operation on two GEOMETRIES with differenc SRIDs\n"); - PG_RETURN_NULL(); - } - - if (geom1->type != POINTTYPE) - { - elog(ERROR, "optimistic_overlap: first arg isnt a point\n"); - PG_RETURN_NULL(); - } - - if (geom2->type != POINTTYPE) - { - elog(ERROR, "optimistic_overlap: second arg isnt a point\n"); - PG_RETURN_NULL(); - } - - offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ); - offsets2 = (int32 *) ( ((char *) &(geom2->objType[0] ))+ sizeof(int32) * geom2->nobjs ); - o = (char *) geom1 + offsets1[0]; - pt1 = (POINT3D *) o; - - o = (char *) geom2 + offsets2[0]; - pt2 = (POINT3D *) o; - - /* - * Start geo_distance code. Longitude is degrees west of - * Greenwich, and thus is negative from what normal things - * will supply the function. - */ - long1 = -1 * (pt1->x / 360.0) * TWO_PI; - lat1 = (pt1->y / 360.0) * TWO_PI; - - long2 = -1 * (pt2->x / 360.0) * TWO_PI; - lat2 = (pt2->y / 360.0) * TWO_PI; - - /* compute difference in longitudes - want < 180 degrees */ - longdiff = fabs(long1 - long2); - if (longdiff > M_PI) - longdiff = TWO_PI - longdiff; - - sino = sqrt(sin(fabs(lat1 - lat2) / 2.) * sin(fabs(lat1 - lat2) / 2.) + - cos(lat1) * cos(lat2) * sin(longdiff / 2.) * sin(longdiff / 2.)); - if (sino > 1.) - sino = 1.; - PG_RETURN_FLOAT8(2. * EARTH_RADIUS * asin(sino)); - -/* PG_RETURN_FLOAT8(distance_sphere_method(pt1->y*M_PI/180.0 , - pt1->x*M_PI/180.0 , - pt2->y*M_PI/180.0 , - pt2->x*M_PI/180.0 , - sphere)); -*/ - -} - - -//distance (geometry,geometry, sphere) -// -geometrys MUST be points -PG_FUNCTION_INFO_V1(distance_ellipsoid); -Datum distance_ellipsoid(PG_FUNCTION_ARGS) -{ - SPHEROID *sphere = (SPHEROID *) PG_GETARG_POINTER(2); - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - POINT3D *pt1,*pt2; - int32 *offsets1; - int32 *offsets2; - char *o; - - - if (geom1->SRID != geom2->SRID) - { - elog(ERROR,"optimistic_overlap:Operation on two GEOMETRIES with different SRIDs\n"); - PG_RETURN_NULL(); - } - - if (geom1->type != POINTTYPE) - { - elog(ERROR,"optimistic_overlap: first arg isnt a point\n"); - PG_RETURN_NULL(); - } - if (geom2->type != POINTTYPE) - { - elog(ERROR,"optimistic_overlap: second arg isnt a point\n"); - PG_RETURN_NULL(); - } - - offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ; - offsets2 = (int32 *) ( ((char *) &(geom2->objType[0] ))+ sizeof(int32) * geom2->nobjs ) ; - o = (char *) geom1 +offsets1[0] ; - pt1 = (POINT3D *) o; - - o = (char *) geom2 +offsets2[0] ; - pt2 = (POINT3D *) o; - - PG_RETURN_FLOAT8(distance_ellipse(pt1->y*M_PI/180.0 ,pt1->x*M_PI/180.0 , - pt2->y*M_PI/180.0 ,pt2->x*M_PI/180.0 , sphere) ); - -//double distance_ellipse(double lat1, double long1, -// double lat2, double long2, -// SPHEROID *sphere) - - -} - - -/* - * For some lat/long points, the above method doesnt calculate the distance very well. - * Typically this is for two lat/long points that are very very close together (<10cm). - * This gets worse closer to the equator. - * - * This method works very well for very close together points, not so well if they're - * far away (>1km). - * - * METHOD: - * We create two circles (with Radius R and Radius S) and use these to calculate the distance. - * - * The first (R) is basically a (north-south) line of longitude. - * Its radius is approximated by looking at the ellipse. Near the equator R = 'a' (earth's major axis) - * near the pole R = 'b' (earth's minor axis). - * - * The second (S) is basically a (east-west) line of lattitude. - * Its radius runs from 'a' (major axis) at the equator, and near 0 at the poles. - * - * - * North pole - * * - * * - * *\--S-- - * * R + - * * \ + - * * A\ + - * * ------ \ Equator/centre of earth - * * - * * - * * - * * - * * - * * - * South pole - * (side view of earth) - * - * Angle A is lat1 - * R is the distance from the centre of the earth to the lat1/long1 point on the surface - * of the Earth. - * S is the circle-of-lattitude. Its calculated from the right triangle defined by - * the angle (90-A), and the hypothenus R. - * - * - * - * Once R and S have been calculated, the actual distance between the two points can be - * calculated. - * - * We dissolve the vector from lat1,long1 to lat2,long2 into its X and Y components (called DeltaX,DeltaY). - * The actual distance that these angle-based measurements represent is taken from the two - * circles we just calculated; R (for deltaY) and S (for deltaX). - * - * (if deltaX is 1 degrees, then that distance represents 1/360 of a circle of radius S.) - * - * - * Parts taken from PROJ4 - geodetic_to_geocentric() (for calculating Rn) - * - * remember that lat1/long1/lat2/long2 are comming in a *RADIANS* not degrees. - * - * By Patricia Tozer and Dave Blasby - * - * This is also called the "curvature method". - */ - -double distance_sphere_method(double lat1, double long1,double lat2,double long2, SPHEROID *sphere) -{ - double R,S,X,Y,deltaX,deltaY; - - double distance = 0.0; - double sin_lat = sin(lat1); - double sin2_lat = sin_lat * sin_lat; - - double Geocent_a = sphere->a; - double Geocent_e2 = sphere->e_sq; - - R = Geocent_a / (sqrt(1.0e0 - Geocent_e2 * sin2_lat)); - S = R * sin(M_PI/2.0-lat1) ; // 90 - lat1, but in radians - - deltaX = long2 - long1; //in rads - deltaY = lat2 - lat1; // in rads - - X = deltaX/(2.0*M_PI) * 2 * M_PI * S; // think: a % of 2*pi*S - Y = deltaY /(2.0*M_PI) * 2 * M_PI * R; - - distance = sqrt((X * X + Y * Y)); - - return distance; -} diff --git a/hwgeom/postgis_svg.c b/hwgeom/postgis_svg.c deleted file mode 100644 index cb14bfcb5..000000000 --- a/hwgeom/postgis_svg.c +++ /dev/null @@ -1,352 +0,0 @@ -/********************************************************************** - * $Id$ - * - * PostGIS - Spatial Types for PostgreSQL - * http://postgis.refractions.net - * Copyright 2001-2003 Refractions Research Inc. - * - * This is free software; you can redistribute and/or modify it under - * the terms of hte GNU General Public Licence. See the COPYING file. - * - ********************************************************************** - * - * SVG output routines. - * Originally written by: Klaus Förster - * Patches from: Olivier Courtin - * - ********************************************************************** - * $Log$ - * Revision 1.1 2004/09/20 07:50:06 strk - * prepared to contain old internal representation code - * - * Revision 1.4 2004/09/13 14:26:27 strk - * indentation fix - * - * Revision 1.3 2004/09/10 16:16:31 pramsey - * Added Log tag to header. - * - * - **********************************************************************/ - - -#include "postgres.h" -#include "postgis.h" - -Datum assvg_geometry(PG_FUNCTION_ARGS); -char *geometry_to_svg(GEOMETRY *geometry, int svgrel, int precision); -void print_svg_coords(char *result, POINT3D *pt, int precision); -void print_svg_circle(char *result, POINT3D *pt, int precision); -void print_svg_path_abs(char *result, POINT3D *pt, int npoints, int precision); -void print_svg_path_rel(char *result, POINT3D *pt, int npoints, int precision); - -#define SHOW_DIGS_DOUBLE 15 -#define MAX_DIGS_DOUBLE (SHOW_DIGS_DOUBLE + 6 + 1 + 3 +1) - -/** - * SVG features - */ -PG_FUNCTION_INFO_V1(assvg_geometry); -Datum assvg_geometry(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1; - char *wkt; - char *result; - int len; - int32 svgrel=0; - int32 precision=15; - - if ( PG_ARGISNULL(0) ) PG_RETURN_NULL(); - - geom1 = (GEOMETRY *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - - // check for relative path notation - if ( PG_NARGS() > 1 && ! PG_ARGISNULL(1) ) - svgrel = PG_GETARG_INT32(1); - - if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) ) - precision = PG_GETARG_INT32(2); - - wkt = geometry_to_svg(geom1, svgrel, precision); - - len = strlen(wkt) + 5; - - result= palloc(len); - *((int *) result) = len; - - memcpy(result +4, wkt, len-4); - - pfree(wkt); - - PG_RETURN_CSTRING(result); -} - - -//takes a GEOMETRY and returns a SVG representation -char *geometry_to_svg(GEOMETRY *geometry, int svgrel, int precision) -{ - char *result; - int t,u; - int32 *offsets; - char *obj; - POINT3D *pts; - POLYGON3D *polygon; - LINE3D *line; - POINT3D *point; - - int pt_off,size; - bool first_sub_obj = TRUE; - int npts; - - //elog(NOTICE, "precision is %d", precision); - size = 30; //just enough to put in object type - - // TODO BBox, from where is it called?... - if (geometry->type == BBOXONLYTYPE) - { - if (svgrel == 1) - { - // 5 double digits+ "Mhvhz"+ spaces +null - size = MAX_DIGS_DOUBLE*5+5+6+1; - result = (char *) palloc(size); - - sprintf(result, "M %.*g %.*g h%.*g v%.*g h%.*g z", - precision, - geometry->bvol.LLB.x, - precision, - geometry->bvol.URT.y*-1, - precision, - (geometry->bvol.URT.x - - geometry->bvol.LLB.x), - precision, - (geometry->bvol.URT.y - - geometry->bvol.LLB.y), - precision, - (geometry->bvol.URT.x - - geometry->bvol.LLB.x)*-1); - } - else - { - size = MAX_DIGS_DOUBLE*4+3+1; - result = (char *) palloc(size); - // 4 double digits + 3 spaces +null - - sprintf(result, "%.*g %.*g %.*g %.*g", - precision, - geometry->bvol.LLB.x, - precision, - geometry->bvol.URT.y*-1, - precision, - (geometry->bvol.URT.x - -geometry->bvol.LLB.x), - precision, - (geometry->bvol.URT.y - -geometry->bvol.LLB.y) - ); - } - return result; - } - - if (geometry->type == COLLECTIONTYPE) - { - result = (char *)palloc(64); - sprintf(result, "GEOMETRYCOLLECTION not yet supported"); - return result; - } - - //where are the objects? - offsets = (int32 *) ( ((char *) &(geometry->objType[0] )) - + sizeof(int32) * geometry->nobjs ) ; - - result = palloc(size); - result[0] = '\0'; - for(t=0;tnobjs; t++) //for each object - { - obj = (char *) geometry +offsets[t] ; - - if (geometry->objType[t] == 1) //POINT - { - point = (POINT3D *) obj; - size +=MAX_DIGS_DOUBLE*3 + 2 +10 ; - //make memory bigger - result = repalloc(result, size ); - - if (!(first_sub_obj)) - { - // next circle ... - strcat(result,","); - } - else - { - first_sub_obj = FALSE; - } - if (svgrel == 1) - { - //render circle - print_svg_coords(result, point, precision); - } - else - { - //render circle - print_svg_circle(result, point, precision); - } - - } - if (geometry->objType[t] == 2) //LINESTRING - { - line = (LINE3D *) obj; - - size +=(MAX_DIGS_DOUBLE*3+5)*line->npoints +12+3; - result = repalloc(result, size ); - - // start path with moveto - strcat(result, "M "); - - if (svgrel == 1) - print_svg_path_rel( - result, - &line->points[0], - line->npoints, - precision - ); - else - print_svg_path_abs( - result, - &line->points[0], - line->npoints, - precision - ); - - strcat(result," "); - } - if (geometry->objType[t] == 3) //POLYGON - { - polygon = (POLYGON3D *) obj; - pt_off = 0; //where is the first point in this ring? - - //where are the points - pts = (POINT3D *) - ((char *)&(polygon->npoints[polygon->nrings])); - pts = (POINT3D *) MAXALIGN(pts); - - npts = 0; - for (u=0; u< polygon->nrings ; u++) - npts += polygon->npoints[u]; - - size += (MAX_DIGS_DOUBLE*3+3) - * npts + 5* polygon->nrings; - result = repalloc(result, size ); - - for (u=0; u< polygon->nrings ; u++) //for each ring - { - strcat(result,"M "); //begin ring - if (svgrel == 1) - print_svg_path_rel(result, - &pts[pt_off] , - polygon->npoints[u], - precision); - else - print_svg_path_abs(result, - &pts[pt_off], - polygon->npoints[u], - precision); - - //where is first point of next ring? - pt_off = pt_off + polygon->npoints[u]; - strcat(result," "); //end ring - } - } - } - return(result); -} - - -void print_svg_coords(char *result, POINT3D *pt, int precision) -{ - char temp[MAX_DIGS_DOUBLE*3 +12]; - - if ( (pt == NULL) || (result == NULL) ) - return; - - sprintf(temp, "x=\"%.*g\" y=\"%.*g\"", - precision, pt->x, - precision, pt->y*-1); - strcat(result,temp); -} - - -void print_svg_circle(char *result, POINT3D *pt, int precision) -{ - char temp[MAX_DIGS_DOUBLE*3 +12]; - - if ( (pt == NULL) || (result == NULL) ) - return; - - sprintf(temp, "cx=\"%.*g\" cy=\"%.*g\"", - precision, pt->x, - precision, pt->y*-1); - strcat(result,temp); -} - - -void print_svg_path_abs(char *result, POINT3D *pt ,int npoints, int -precision){ - int u; - - result += strlen(result); - for (u=0;u -#include -#include -#include -#include - -#include "access/gist.h" -#include "access/itup.h" -#include "access/rtree.h" - - -#include "fmgr.h" - - -#include "postgis.h" -#include "utils/elog.h" - - - -#define SHOW_DIGS_DOUBLE 15 -#define MAX_DIGS_DOUBLE (SHOW_DIGS_DOUBLE + 6 + 1 + 3 +1) - - -// if USE_PROJECTION undefined, we get a do-nothing transform() function -#ifdef USE_PROJ - -#include "projects.h" - - -PJ *make_project(char *str1); -void to_rad(POINT3D *pts, int num_points); -void to_dec(POINT3D *pts, int num_points); - -int pj_transform_nodatum( PJ *srcdefn, PJ *dstdefn, long point_count, int point_offset, - double *x, double *y, double *z ); - -//this is *exactly* the same as PROJ.4's pj_transform(), but it doesnt do the -// datum shift. -int pj_transform_nodatum( PJ *srcdefn, PJ *dstdefn, long point_count, int point_offset, - double *x, double *y, double *z ) - -{ - long i; - //int need_datum_shift; - - pj_errno = 0; - - if( point_offset == 0 ) - point_offset = 1; - - if( !srcdefn->is_latlong ) - { - for( i = 0; i < point_count; i++ ) - { - XY projected_loc; - LP geodetic_loc; - - projected_loc.u = x[point_offset*i]; - projected_loc.v = y[point_offset*i]; - - geodetic_loc = pj_inv( projected_loc, srcdefn ); - if( pj_errno != 0 ) - return pj_errno; - - x[point_offset*i] = geodetic_loc.u; - y[point_offset*i] = geodetic_loc.v; - } - } - - if( !dstdefn->is_latlong ) - { - for( i = 0; i < point_count; i++ ) - { - XY projected_loc; - LP geodetic_loc; - - geodetic_loc.u = x[point_offset*i]; - geodetic_loc.v = y[point_offset*i]; - - projected_loc = pj_fwd( geodetic_loc, dstdefn ); - if( pj_errno != 0 ) - return pj_errno; - - x[point_offset*i] = projected_loc.u; - y[point_offset*i] = projected_loc.v; - } - } - - return 0; -} - - - -// convert decimal degress to radians -void to_rad(POINT3D *pts, int num_points) -{ - int t; - for(t=0;tvl_len +1-4); - memcpy(input_proj4,input_proj4_text->vl_dat, input_proj4_text->vl_len-4); - input_proj4[input_proj4_text->vl_len-4] = 0; //null terminate - - - output_proj4 = (char *) palloc(output_proj4_text->vl_len +1-4); - memcpy(output_proj4,output_proj4_text->vl_dat, output_proj4_text->vl_len-4); - output_proj4[output_proj4_text->vl_len-4] = 0; //null terminate - - if (geom->SRID == -1) - { - pfree(input_proj4); pfree(output_proj4); - elog(ERROR,"tranform: source SRID = -1"); - PG_RETURN_NULL(); // no srid, cannot convert - } - - if (result_srid == -1) - { - pfree(input_proj4); pfree(output_proj4); - elog(ERROR,"tranform: destination SRID = -1"); - PG_RETURN_NULL(); // no srid, cannot convert - } - - //make input and output projection objects - input_pj = make_project(input_proj4); - if ( (input_pj == NULL) || pj_errno) - { - pfree(input_proj4); pfree(output_proj4); - elog(ERROR,"tranform: couldnt parse proj4 input string"); - PG_RETURN_NULL(); - } - - output_pj = make_project(output_proj4); - if ((output_pj == NULL)|| pj_errno) - { - pfree(input_proj4); pfree(output_proj4); - pj_free(input_pj); - elog(ERROR,"tranform: couldnt parse proj4 output string"); - - PG_RETURN_NULL(); - } - //great, now we have a geometry, and input/output PJ* structs. Excellent. - - //copy the geometry structure - we're only going to change the points, not the structures - result = (GEOMETRY *) palloc (geom->size); - memcpy(result,geom, geom->size); - - gtype = result->type; - - // allow transformations of the BOX3D type - the loop below won't be entered since for a BOX3D - // type result->nobjs will be -1 so we check for it here - if (gtype == BBOXONLYTYPE) - { - bbox = &(result->bvol); - pt = (POINT3D *)bbox; - - if (input_pj->is_latlong) - to_rad(pt,2); - - tmpPts = palloc(sizeof(POINT3D)*2); - memcpy(tmpPts, pt, sizeof(POINT3D)*2); - - pj_transform(input_pj,output_pj, 2,3, &pt->x,&pt->y, &pt->z); - - if (pj_errno) - { - if (pj_errno == -38) //2nd chance - { - //couldnt do nadshift - do it without the datum - memcpy(pt,tmpPts, sizeof(POINT3D)*2); - pj_transform_nodatum(input_pj,output_pj, 2 ,3, &pt->x,&pt->y, &pt->z); - } - - if (pj_errno) - { - pfree(input_proj4); pfree(output_proj4); - pj_free(input_pj); pj_free(output_pj); - elog(ERROR,"transform: couldnt project bbox point: %i (%s)",pj_errno,pj_strerrno(pj_errno)); - PG_RETURN_NULL(); - } - - } - pfree(tmpPts); - if (output_pj->is_latlong) - to_dec(pt,2); - - }else{ - - //handle each sub-geometry - offsets1 = (int32 *) ( ((char *) &(result->objType[0] ))+ sizeof(int32) * result->nobjs ) ; - for (j=0; j< result->nobjs; j++) //for each object in geom1 - { - o1 = (char *) result +offsets1[j] ; - type1= result->objType[j]; - - if (type1 == POINTTYPE) //point - { - pt = (POINT3D *) o1; - if (input_pj->is_latlong) - to_rad(pt,1); - - tmpPts = palloc(sizeof(POINT3D) ); - memcpy(tmpPts,pt, sizeof(POINT3D)); - - pj_transform(input_pj,output_pj, 1,3, &pt->x,&pt->y, &pt->z); - if (pj_errno) - { - if (pj_errno == -38) //2nd chance - { - //couldnt do nadshift - do it without the datum - memcpy(pt,tmpPts, sizeof(POINT3D)); - pj_transform_nodatum(input_pj,output_pj, 1,3, &pt->x,&pt->y, &pt->z); - } - - if (pj_errno) - { - pfree(input_proj4); pfree(output_proj4); - pj_free(input_pj); pj_free(output_pj); - elog(ERROR,"transform: couldnt project point: %i (%s)",pj_errno,pj_strerrno(pj_errno)); - PG_RETURN_NULL(); - } - - } - pfree(tmpPts); - if (output_pj->is_latlong) - to_dec(pt,1); - } - if (type1 == LINETYPE) //line - { - line = (LINE3D *) o1; - if (input_pj->is_latlong) - to_rad(&line->points[0],line->npoints); - - tmpPts = palloc(sizeof(POINT3D)*line->npoints ); - memcpy(tmpPts,&line->points[0], sizeof(POINT3D)*line->npoints); - - pj_transform(input_pj,output_pj, line->npoints ,3, - &line->points[0].x,&line->points[0].y, &line->points[0].z); - if (pj_errno) - { - if (pj_errno == -38) //2nd chance - { - //couldnt do nadshift - do it without the datum - memcpy(&line->points[0],tmpPts, sizeof(POINT3D)*line->npoints); - pj_transform_nodatum(input_pj,output_pj, line->npoints ,3, - &line->points[0].x,&line->points[0].y, &line->points[0].z); - } - - if (pj_errno) - { - - pfree(input_proj4); pfree(output_proj4); - pj_free(input_pj); pj_free(output_pj); - elog(ERROR,"transform: couldnt project line"); - PG_RETURN_NULL(); - } - } - pfree(tmpPts); - if (output_pj->is_latlong) - to_dec(&line->points[0],line->npoints); - } - if (type1 == POLYGONTYPE) //POLYGON - { - poly = (POLYGON3D *) o1; - poly_points = 0; - - for (i=0; inrings;i++) - { - poly_points += poly->npoints[i]; - } - poly_pts = (POINT3D *) ( (char *)&(poly->npoints[poly->nrings] ) ); - poly_pts = (POINT3D *) MAXALIGN(poly_pts); - - if (input_pj->is_latlong) - to_rad(poly_pts , poly_points); - - tmpPts = palloc(sizeof(POINT3D)* poly_points ); - memcpy(tmpPts,&poly_pts[0].x, sizeof(POINT3D)* poly_points); - - - - pj_transform(input_pj,output_pj, poly_points,3, - &poly_pts[0].x,&poly_pts[0].y, &poly_pts[0].z); - if (pj_errno) - { - if (pj_errno == -38) //2nd chance - { - //couldnt do nadshift - do it without the datum - memcpy(&poly_pts[0].x,tmpPts, sizeof(POINT3D)*poly_points); - pj_transform_nodatum(input_pj,output_pj, poly_points,3, - &poly_pts[0].x,&poly_pts[0].y, &poly_pts[0].z); - } - - if (pj_errno) - { - - pfree(input_proj4); pfree(output_proj4); - pj_free(input_pj); pj_free(output_pj); - elog(ERROR,"transform: couldnt project polygon"); - PG_RETURN_NULL(); - } - } - pfree(tmpPts); - if (output_pj->is_latlong) - to_dec(poly_pts , poly_points); - } - } - - } - - // clean up - pj_free(input_pj); - pj_free(output_pj); - pfree(input_proj4); pfree(output_proj4); - - // Generate the bounding box if necessary - if (gtype != BBOXONLYTYPE) - { - bbox = bbox_of_geometry(result); - memcpy(&result->bvol,bbox, sizeof(BOX3D) ); //make bounding box - } - - result->SRID = result_srid; - - PG_RETURN_POINTER(result); // new geometry -} - -PG_FUNCTION_INFO_V1(postgis_proj_version); -Datum postgis_proj_version(PG_FUNCTION_ARGS) -{ - //const char *ver = pj_get_release(); - const char *ver = pj_release; - text *result; - result = (text *) palloc(VARHDRSZ + strlen(ver)); - VARATT_SIZEP(result) = VARHDRSZ + strlen(ver) ; - memcpy(VARDATA(result), ver, strlen(ver)); - PG_RETURN_POINTER(result); -} - - -#else // ! defined USE_PROJ - - // return the original geometry -PG_FUNCTION_INFO_V1(transform_geom); -Datum transform_geom(PG_FUNCTION_ARGS) -{ - - elog(ERROR,"PostGIS transform() called, but support not compiled in. Modify your makefile to add proj support, remake and re-install"); - - //GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - //GEOMETRY *result; - - //result = (GEOMETRY *) palloc (geom1->size); - //memcpy(result,geom1, geom1->size); - ///elog(NOTICE,"PostGIS transform - //PG_RETURN_POINTER(result); - PG_RETURN_NULL(); -} - -PG_FUNCTION_INFO_V1(postgis_proj_version); -Datum postgis_proj_version(PG_FUNCTION_ARGS) -{ - PG_RETURN_NULL(); -} -#endif