+++ /dev/null
-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 <havard.tveite@nlh.no>
-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
-
+++ /dev/null
-
-/**********************************************************************
- * $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 <ctype.h> 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(<geom>)
- * 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 <sys/types.h> 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(<linestring>,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(<WKB>,[<SRID>]).
- *
- * Added all the functions like PolyFromText(<WKT>,[<SRID>])
- *
- * 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 <sys/types.h>
-#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 <sys/param.h> // 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;
- * <there is almost certainly some type of padding here>
- * 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:
- // <header><data>
- // 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))
-
-
+++ /dev/null
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
---
--- $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 <dbname>'::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( <schema>, <table>, <geom col> )
------------------------------------------------------------------------
-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( <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_<geomcolname>'
--- and 'enforce_srid_<geomcolname>'
--- 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( <schema name>, <table name>, <column name> )
------------------------------------------------------------------------
-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( <table name>, <column name> )
------------------------------------------------------------------------
-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 ( <geometry>, <srid> )
------------------------------------------------------------------------
---
--- 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
--- <catalogue>, <schema>, <table>, <column>, <srid>, <type>, <dim>
------------------------------------------------------------------------
---
--- 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 ( <schema>, <table>, <column>, <srid>, <type>, <dim> )
-----------------------------------------------------------------------------
---
--- 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 ( <table>, <column>, <srid>, <type>, <dim> )
-----------------------------------------------------------------------------
---
--- 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
--- <catalogue>, <schema>, <table>, <column>
------------------------------------------------------------------------
---
--- 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
--- <schema>, <table>, <column>
------------------------------------------------------------------------
---
--- 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
--- <table>, <column>
------------------------------------------------------------------------
---
--- 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
--- <catalogue>, <schema>, <table>
------------------------------------------------------------------------
---
--- 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
--- <schema>, <table>
------------------------------------------------------------------------
---
--- 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
--- <table>
------------------------------------------------------------------------
---
--- 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( <table>, <column> )
------------------------------------------------------------------------
---
--- 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( <box>, <size> )
------------------------------------------------------------------------
---
--- 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( <histogram2d>, <tablename>, <columnname> )
------------------------------------------------------------------------
-CREATEFUNCTION build_histogram2d (histogram2d,text,text)
- RETURNS histogram2d
- AS '@MODULE_FILENAME@','build_histogram2d'
- LANGUAGE 'C' with (isstrict);
-
-#if USE_VERSION >= 73
------------------------------------------------------------------------
--- BUILD_HISTOGRAM2D(<histogram2d>,<schema>,<tablename>,<columnname>)
------------------------------------------------------------------------
--- 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( <histogram2d>, <tablename> )
------------------------------------------------------------------------
-CREATEFUNCTION explode_histogram2d (HISTOGRAM2D,text)
- RETURNS histogram2d
- AS '@MODULE_FILENAME@','explode_histogram2d'
- LANGUAGE 'C' with (isstrict);
-
------------------------------------------------------------------------
--- ESTIMATE_HISTOGRAM2D( <histogram2d>, <box> )
------------------------------------------------------------------------
-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;
+++ /dev/null
-/**********************************************************************
- * $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<p2; k++)
- {
- pk = &(pts[k]);
-
-#if VERBOSE > 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; ri<ipoly->nrings; 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;i<orig_geom->nobjs; 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;
- ***********************************************************************/
+++ /dev/null
-
-/**********************************************************************
- * $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 <math.h>
-#include <float.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-
-#include "access/gist.h"
-#include "access/itup.h"
-#include "access/rtree.h"
-
-
-#include "fmgr.h"
-
-
-#include "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;t<size;t++)
- {
- ((unsigned char *)result)[t] = parse_hex( &str[t*2]) ;
- }
-// if endian is wrong, flip it otherwise do nothing
- result->size = 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);
-}
+++ /dev/null
-
-/**********************************************************************
- * $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(<linestring>,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 <math.h>
-#include <float.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-
-#include "access/gist.h"
-#include "access/itup.h"
-#include "access/rtree.h"
-
-
-#include "fmgr.h"
-
-
-#include "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; i<poly->nrings;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) );
-}
-
-
+++ /dev/null
-
-/**********************************************************************
- * $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 <m.cave-ayland@webbased.co.uk>.
- * 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 <math.h>
-#include <float.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-
-#include "access/gist.h"
-#include "access/itup.h"
-#include "access/rtree.h"
-
-#include "fmgr.h"
-
-#include "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;t<histo->boxesPerSide*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;t<histo->boxesPerSide*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;y<histo->boxesPerSide;y++)
- {
- for(x=0;x<histo->boxesPerSide;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;t<histo->boxesPerSide*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;t<ntuples;t++)
- {
- tuple = tuptable->vals[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;t<histo->boxesPerSide*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; i<samplerows; i++)
- {
- Datum datum;
- GEOMETRY *geom;
- BOX *box;
-
- datum = fetchfunc(stats, i, &isnull);
-
- /*
- * Skip nulls
- */
- if ( isnull ) {
- null_cnt++;
- continue;
- }
-
- geom = (GEOMETRY *) PG_DETOAST_DATUM(datum);
-
- /*
- * Skip infinite geoms
- */
- if ( ! finite(geom->bvol.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; i<notnull_cnt; i++)
- {
- BOX *box;
- box = (BOX *)sampleboxes[i];
-
- sdLOWx += (box->low.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; i<notnull_cnt; i++)
- {
- BOX *box;
- box = (BOX *)sampleboxes[i];
-
- if ( box->low.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 ( geow<geoh) {
- cols = ceil(sqrt((double)histocells*(geow/geoh)));
- rows = ceil((double)histocells/cols);
- } else {
- rows = ceil(sqrt((double)histocells*(geoh/geow)));
- cols = ceil((double)histocells/rows);
- }
- histocells = cols*rows;
- }
-#if DEBUG_GEOMETRY_STATS
- elog(NOTICE, " computed histogram grid size (CxR): %dx%d (%d cells)", cols, rows, histocells);
-#endif
-
-
- /*
- * Create the histogram (GEOM_STATS)
- */
- old_context = MemoryContextSwitchTo(stats->anl_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;i<histocells; i++) geomstats->value[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<notnull_cnt; i++)
- {
- BOX *box;
- int x_idx_min, x_idx_max, x;
- int y_idx_min, y_idx_max, y;
- int numcells=0;
-
- box = (BOX *)sampleboxes[i];
- if ( ! box ) continue; // hard deviant..
-
- /* give backend a chance of interrupting us */
- vacuum_delay_point();
-
-#if DEBUG_GEOMETRY_STATS > 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; i<histocells; i++)
- geomstats->value[i] /= examinedsamples;
-
-#if DEBUG_GEOMETRY_STATS > 1
- {
- int x, y;
- for (x=0; x<cols; x++)
- {
- for (y=0; y<rows; y++)
- {
- elog(NOTICE, " histo[%d,%d] = %.15f", x, y, geomstats->value[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
-
-
+++ /dev/null
-
-/**********************************************************************
- * $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(<geom>)
- * 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(<linestring>,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 <math.h>
-#include <float.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-
-#include "access/gist.h"
-#include "access/itup.h"
-#include "access/rtree.h"
-
-#include "fmgr.h"
-
-#include "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(<linestring>, 0) is the 1st point, and pointN(<linestring>, 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(<linestring>, 1) is the 1st point, and pointN(<linestring>, 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; i<line->npoints;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; i<line->npoints;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; i<poly1->npoints[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; i<poly1->npoints[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 <intersect
- ++cn; // a valid crossing of y=P.y right of P.x
- }
- }
- return (cn&1); // 0 if even (out), and 1 if odd (in)
-
-}
-
-
-
-
-
-//this one is easy - is the point inside a box?
-bool point_truely_inside(POINT3D *point, BOX3D *box)
-{
- return (
- (point->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 <box->LLB.y )
- {
- Code = 4;
- }
- }
- if (p->x > box->URT.x )
- {
- return (Code+2);
- }
- if (p->x <box->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; ri<poly->nrings; 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; i<poly->nrings;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;i<npoints;i++)
- {
-//printf("before: [%g,%g,%g]\n", pt[i].x, pt[i].y,pt[i].z);
-
- pt[i].x += x_off;
- pt[i].y += y_off;
- pt[i].z += z_off;
-
-//printf("after: [%g,%g,%g]\n", pt[i].x, pt[i].y,pt[i].z);
- }
-}
-
-
-
-//translate geometry
-PG_FUNCTION_INFO_V1(translate);
-Datum translate(PG_FUNCTION_ARGS)
-{
- GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
- GEOMETRY *geom1;
- double x_off = PG_GETARG_FLOAT8(1);
- double y_off = PG_GETARG_FLOAT8(2);
- double z_off = PG_GETARG_FLOAT8(3);
- int32 *offsets1;
- char *o1;
- int32 type,j,i;
- POLYGON3D *poly;
- POINT3D *point,*pts;
- LINE3D *line;
- int numb_points;
-
-
-
-
- //make a copy of geom so we can return a new version
-
- geom1 = (GEOMETRY *) palloc (geom->size);
- 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; i<poly->nrings;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;t<geom->nobjs;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
- 0<r<1 P is interior to AB
- */
-
- r = ( (p->x-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;t<l2->npoints;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;t<l1->npoints;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; t<poly2->nrings;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;t<poly2->nrings; 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; t<poly2->nrings;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;t<poly->nrings;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; t<poly1->nrings; 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;t<geom1->nobjs;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;u<poly->nrings;u++)
- // {
- // num_points += poly->npoints[u];
- // }
-
- num_points_tot += num_points-1; //last point = 1st point
- for (v=0;v<num_points-1;v++)
- {
- tot_x += pts[v].x;
- tot_y += pts[v].y;
- tot_z += pts[v].z;
- }
- }
- cent = palloc(sizeof(POINT3D));
- set_point(cent, tot_x/num_points_tot, tot_y/num_points_tot,tot_z/num_points_tot);
- result = (
- make_oneobj_geometry(sizeof(POINT3D),
- (char *) cent,
- POINTTYPE, geom1->is3d, 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;t<l1->npoints;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;r<p->nrings;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; i<nelems; i++)
- {
- int32 *offsets;
-
- geom = geoms[i];
-
- /* Skip NULL array elements (are them possible?) */
- if ( geom == NULL ) continue;
-
- /* Use first NOT-NULL GEOMETRY as the base */
- if ( ! result )
- {
- /* Remember first geometry's SRID for later checks */
- srid = geom->SRID;
-
- /* 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; o<geom->nobjs; 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; i<geom2->nobjs; 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
-}
+++ /dev/null
-/**********************************************************************
- * $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(<linestring>,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(<WKB>,[<SRID>]).
- *
- * Added all the functions like PolyFromText(<WKT>,[<SRID>])
- *
- * 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 <math.h>
-#include <float.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-
-#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; i<nelems; i++)
- {
- pgis_geom = geoms[i];
-
- g1 = POSTGIS2GEOS(pgis_geom);
- /*
- * If we free this memory now we'll have
- * more space for the growing result geometry.
- * We don't need it anyway.
- */
- pfree(pgis_geom);
-
-#ifdef DEBUG
- elog(NOTICE, "unite_garray(%d): adding geom %d to union",
- call, i);
-#endif
-
- g2 = GEOSUnion(g1,geos_result);
- if ( g2 == NULL )
- {
- GEOSdeleteGeometry(g1);
- GEOSdeleteGeometry(geos_result);
- elog(ERROR,"GEOS union() threw an error!");
- }
- GEOSdeleteGeometry(g1);
- GEOSdeleteGeometry(geos_result);
- geos_result = g2;
- }
-
- result = GEOS2POSTGIS(geos_result, is3d);
- GEOSdeleteGeometry(geos_result);
- if ( result == NULL )
- {
- elog(ERROR, "GEOS2POSTGIS returned an error");
- PG_RETURN_NULL(); //never get here
- }
-
- compressType(result);
-
- PG_RETURN_POINTER(result);
-
-}
-
-
-//select geomunion('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(geomunion);
-Datum geomunion(PG_FUNCTION_ARGS)
-{
- GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
- GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
- int is3d = geom1->is3d || 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;t<ninteriorrings;t++)
- {
-
- pts_per_ring[t+1] = GEOSGetNumCoordinate(GEOSGetInteriorRingN(g,t));
- }
-
-
-
- poly = make_polygon( ninteriorrings+1, pts_per_ring,
- pts, GEOSGetNumCoordinate(g), size);
-
-
-
- GEOSdeleteChar( (char*) pts);
- pfree(pts_per_ring);
- return poly;
-}
-
-
-
-LINE3D *LineFromGeometry(Geometry *g,int *size)
-{
-// int t;
- POINT3D *pts = GEOSGetCoordinates(g);
-
- LINE3D *line;
- int npoints = GEOSGetNumCoordinate(g);
-
-
- if (npoints <2)
- {
- GEOSdeleteChar( (char*) pts);
- return NULL;
- }
-
- line = make_line(npoints, pts, size);
-//elog(NOTICE,"line::");
-//for (t=0;t<npoints;t++)
-//{
-// elog(NOTICE,"point (in): %g,%g,%g", pts[t].x,pts[t].y,pts[t].z);
-// elog(NOTICE,"point (line): %g,%g,%g",line->points[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;t<ngeoms;t++)
- {
- g2 = GEOS2POSTGIS(GEOSGetGeometryN(g,t),
- want3d);
- r = geom;
-#if 1
- geom = (GEOMETRY *) DatumGetPointer(
- DirectFunctionCall2(collector,
- PointerGetDatum(r),
- PointerGetDatum(g2)));
-#else
- geom = collector_raw(r, g2);
-#endif
- pfree(r);
- pfree(g2);
- }
- return geom;
-
- case MULTIPOLYGONTYPE:
- ngeoms = GEOSGetNumGeometries(g);
-#ifdef DEBUG_GEOS2POSTGIS
- elog(NOTICE, "GEOS2POSTGIS: It's a MULTIPOLYGON");
-#endif // DEBUG_GEOS2POSTGIS
- if (ngeoms ==0)
- {
- result = makeNullGeometry(GEOSGetSRID(g));
- result->type = MULTIPOLYGONTYPE;
- return result;
- }
- for (t=0;t<ngeoms;t++)
- {
- poly = PolyFromGeometry(GEOSGetGeometryN(g,t) ,&size);
- if (t==0)
- {
- result = make_oneobj_geometry(size,
- (char *) poly,
- MULTIPOLYGONTYPE, want3d, GEOSGetSRID(g),1.0, 0.0, 0.0
- );
- }
- else
- {
- g_old = result;
- result = add_to_geometry(g_old,size, (char*) poly, POLYGONTYPE);
- pfree(g_old);
- }
- pfree(poly);
- }
- // make bounding box
- bbox = bbox_of_geometry( result );
- // copy bounding box
- memcpy( &result->bvol, 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;t<ngeoms;t++)
- {
- line = LineFromGeometry(GEOSGetGeometryN(g,t),
- &size);
- g_old = result;
- result = add_to_geometry(g_old,size,
- (char*) line, LINETYPE);
-#ifdef DEBUG_GEOS2POSTGIS
- elog(NOTICE,"GEOS2POSTGIS: t%d: %s", t, geometry_to_text(result));
- elog(NOTICE," size = %i", result->size);
-#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;t<ngeoms;t++)
- {
- g_new = add_to_geometry(g_old, sizeof(POINT3D),
- (char*)&pts[t], POINTTYPE);
- pfree(g_old);
- g_old =g_new;
- }
- GEOSdeleteChar( (char*) pts);
- // make bounding box
- bbox = bbox_of_geometry( g_new );
- // copy bounding box
- memcpy( &g_new->bvol, 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;t<g->nobjs;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;t<g->nobjs;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;t<g->nobjs;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;t<g->nobjs;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 <math.h>
-#include <float.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-
-#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
-
+++ /dev/null
-// 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 <stdio.h>
-
-#include <string>
-#include <iostream>
-#include <fstream>
-
-#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<Geometry *> *subGeos=new vector<Geometry *>;
-
- 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;t<line->npoints;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;t<line->npoints;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<Geometry *> *subPolys=NULL;
- Geometry *g;
-
- subPolys=new vector<Geometry *>;
-
- 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<Geometry *> *subLines = new vector<Geometry *>;
- 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<Geometry *> *subPoints =new vector<Geometry *>;
- 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<Geometry *> *innerRings=new vector<Geometry *>;
-
-
- pts = (POINT3D *) ( (char *)&(polygon->npoints[polygon->nrings] ) );
- pts = (POINT3D *) MAXALIGN(pts);
-
- // make outerRing
- cl = new DefaultCoordinateSequence(polygon->npoints[0]);
- if (is3d)
- {
- for(t=0;t<polygon->npoints[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;t<polygon->npoints[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;t<polygon->npoints[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;t<polygon->npoints[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;t<numPoints;t++)
- {
- c =cl->getAt(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; t<npts; t++)
- {
- c = cl->getAt(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; r<nrings; r++)
- {
- lr = g1->getInteriorRingN(r);
- cl = lr->getCoordinatesRO();
- npts = lr->getNumPoints();
- for (t=0; t<npts; t++)
- {
- c = cl->getAt(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;
-}
-
-
+++ /dev/null
-
-/**********************************************************************
- * $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(<linestring>,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 <math.h>
-#include <float.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-
-#include "access/gist.h"
-#include "access/itup.h"
-#include "access/rtree.h"
-
-#include "fmgr.h"
-
-#include "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 <sys/param.h> // 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));
-}
-
-
+++ /dev/null
-
-/**********************************************************************
- * $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 <table> 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(<linestring>,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 <math.h>
-#include <float.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-
-#include "access/gist.h"
-#include "access/itup.h"
-#include "access/rtree.h"
-
-#include "fmgr.h"
-
-#include "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;
-}
+++ /dev/null
-
-/**********************************************************************
- * $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 <ctype.h> 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=<int>{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(<linestring>,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(<WKB>,[<SRID>]).
- *
- * Added all the functions like PolyFromText(<WKT>,[<SRID>])
- *
- * 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 <david.garnier@etudier-online.com>.
- *
- * Revision 1.21 2003/07/01 18:30:55 pramsey
- * Added CVS revision headers.
- *
- *
- **********************************************************************/
-
-#include "postgres.h"
-
-
-#include <math.h>
-#include <float.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-#include <ctype.h>
-
-#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<npoints;u++)
- {
- if (u != 0)
- {
- result[0] = ',';
- result++;
- }
- result+= sprintf(result,"%.15g %.15g %.15g", pt[u].x,pt[u].y,pt[u].z);
- }
- }
- else
- {
- for (u=0;u<npoints;u++)
- {
- if (u != 0)
- {
- result[0] = ',';
- result++;
- }
-
- result += sprintf(result, "%.15g %.15g",
- pt[u].x, pt[u].y);
- }
- }
-}
-
-
-//swap two doubles
-void swap(double *d1, double *d2)
-{
- double t;
-
- t = *d1;
- *d1 = *d2;
- *d2 = t;
-}
-
-
-//returns how many points are in the first list in str
-//
-// 1. scan ahead looking for "("
-// 2. find "," until hit a ")"
-// 3. return number of points found
-//
-// NOTE: doesnt actually parse the points, so if the
-// str contains an invalid geometry, this could give
-// back the wrong answer.
-//
-// "(1 2 3, 4 5 6),(7 8, 9 10, 11 12 13)" => 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<npoints; t++)
- {
- objs[*offset + t] = palloc( sizeof(POINT3D) );
- memset(objs[*offset+t], 0, sizeof(POINT3D) ); // zero memory
-
- obj_types[*offset+t] = POINTTYPE;
- obj_size[*offset+t] = sizeof(POINT3D);
- }
-
- //actually do the parsing into a temporary list
- result = parse_points_in_list_exact(str, pts , npoints, is3d);
-
-
- if (!(result))
- {
- pfree(pts);
- return FALSE; //relay error
- }
-
- for(t=0;t<npoints;t++)
- {
- memcpy(objs[*offset+t], &pts[t], sizeof(POINT3D) );
- }
-
- pfree(pts);
- *offset = *offset + npoints;
- return (result);
-}
-
-
-//parse a linestring
-bool parse_objects_inside_line(int32 *obj_size,char **objs, int32 *obj_types, int32 nobjs, char *str, int *offset, bool* is3d)
-{
- bool result;
- int num_points;
- bool add_point = FALSE; // only 1 point --> 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<num_lines; t++)
- {
- //pass along the work - it will update offset for us
- result = parse_objects_inside_line(obj_size,objs, obj_types,nobjs, str,offset,is3d);
- if (!(result))
- return FALSE;//relay error
- if (str != NULL)
- str++; // go past the first '(' in the linestring
- else
- return FALSE; //parse error
- str = strchr(str,'('); // go to the beginning of the next linestring
- }
-
- return (TRUE); //everything okay
-}
-
-//parse a polygon
-// POLYGON ( (3 4 5,1 2 3,5 6),(1 2, 4 5, 6 7) )'
-
-
-bool parse_objects_inside_polygon(int32 *obj_size,char **objs, int32 *obj_types, int32 nobjs, char *str, int *offset, bool* is3d)
-{
- bool result;
- int num_rings;
- int32 *npoints;
- int32 sum_points,points_offset;
- int t;
- int size;
- POINT3D *pts;
- POLYGON3D *polygon;
-
-
-
- if (*offset >= 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;t<num_rings;t++) //for each ring
- {
- //set num points in this obj
- polygon->npoints[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;t<num_polys; t++)
- {
- if (str == NULL)
- return FALSE; //relay error
-//printf("parse_inside_multipolygon: parsing a polygon #%i\n",t);
- result = parse_objects_inside_polygon(obj_size,objs, obj_types,nobjs, str,offset,is3d);
- if (!(result))
- return FALSE; //relay error
-
- //scan ahead to next "(" start of next polygon
- str = scan_to_same_level(str);
- }
- return (TRUE);
-}
-
-
-// relay work to the above functions
-bool parse_objects(int32 *obj_size,char **objs,int32 *obj_types,int32 nobjs,char *str, int *offset, bool *is3d)
-{
- char *parenth;
- char *loc;
-
-
-//printf("parse_objects: parsing object offset=%i\n",*offset);
-
- if (str == NULL)
- return FALSE;
-
- parenth = strchr(str,'(');
- if (parenth == NULL)
- return FALSE; //invalid string
-
-
- if ( ((loc = strstr(str, "GEOMETRYCOLLECTION")) != NULL) && (loc < parenth) )
- return parse_objects_inside_collection(obj_size,objs, obj_types, nobjs, str, offset, is3d);
-
-
- if (((loc = strstr(str,"MULTIPOINT")) != NULL) && (loc < parenth) )
- return parse_objects_inside_multipoint(obj_size,objs, obj_types, nobjs, str, offset, is3d);
-
-
- if (((loc = strstr(str,"MULTILINESTRING") )!= NULL) && (loc < parenth) )
- return parse_objects_inside_multiline(obj_size,objs, obj_types, nobjs, str, offset, is3d);
-
-
- if (((loc = strstr(str,"MULTIPOLYGON")) != NULL) && (loc < parenth) )
- return parse_objects_inside_multipolygon(obj_size,objs, obj_types, nobjs, str, offset, is3d);
-
- if (((loc = strstr(str,"POINT")) != NULL) && (loc < parenth) )
- return parse_objects_inside_point(obj_size,objs, obj_types, nobjs, str, offset, is3d);
-
-
- if (((loc = strstr(str,"LINESTRING")) != NULL) && (loc < parenth) )
- return parse_objects_inside_line(obj_size,objs, obj_types, nobjs, str, offset, is3d);
-
- if (((loc = strstr(str,"POLYGON")) != NULL) && (loc < parenth) )
- return parse_objects_inside_polygon(obj_size,objs, obj_types, nobjs, str, offset, is3d);
-
-
- return FALSE; //invalid
-
-}
-
-
-
-//look for each of the object inside a collection, and send the work to parse it along
-bool parse_objects_inside_collection(int32 *obj_size,char **objs, int32 *obj_types, int32 nobjs, char *str, int *offset, bool* is3d)
-{
- bool result = FALSE;
-
- str += 18; //scan past "geometrycollection"
- if (strstr(str, "GEOMETRYCOLLECTION") != NULL)
- return FALSE; // collection inside collection; bad boy!
-
- while ( str != NULL)
- {
- //scan for a letter
- str = strpbrk(str,"MPL"); //search for MULTI*, POLY*, POIN*
- if (str != NULL)
- {
- //object found
- result = parse_objects(obj_size,objs,obj_types,nobjs,str, offset, is3d);
-
- if (result == FALSE)
- return FALSE;//relay error
-
- //prepare to move to next item
- // by scanning past any letters
- str = strchr(str,'(');
- }
- }
- return result;
-}
-
-/**************************************************************
- * Find the bounding box3d of a sub-object
- **************************************************************/
-
-//simple box encloses a point
-BOX3D *bbox_of_point(POINT3D *pt)
-{
- BOX3D *the_box = (BOX3D *) palloc (sizeof(BOX3D));
-
- the_box->LLB.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; i<polygon->nrings; 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; i<numb_points;i++)
- {
- pt = &pts[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;
-}
-
-//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; i<geom->nobjs;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; t<nobjs; t++)
- {
- if (objs[t] != NULL)
- pfree (objs[t]);
- }
- pfree(objs); pfree(obj_types); pfree(obj_size);
- elog(ERROR,"couldnt parse object in GEOMETRY\n");
- PG_RETURN_NULL();
- }
-
- entire_size = sizeof(GEOMETRY);
-
- for (t =0; t<nobjs; t++)
- {
- //do they all have an obj_type?
- if ( (obj_types[t] == 0) || (objs[t] == NULL) )
- {
- okay = FALSE;
- }
- entire_size += obj_size[t]; //total space of the objects
-
- //size seem reasonable?
- if (obj_size[t] <1)
- {
- okay = FALSE;
- }
-
- }
- if (!(okay) )
- {
- for (t =0; t<nobjs; t++)
- {
- if (objs[t] != NULL)
- pfree (objs[t]);
- }
- pfree(objs); pfree(obj_types); pfree(obj_size);
- elog(ERROR,"couldnt parse object in GEOMETRY\n");
- PG_RETURN_NULL();
- }
-
- //size = object size + space for object type & offset array and possible double-word boundary stuff
- entire_size = entire_size + sizeof(int32) *nobjs*2 + nobjs*4;
- geometry = (GEOMETRY *) palloc (entire_size);
-
- geometry->size = 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; t<nobjs; t++) //for each object
- {
- geometry->objType[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;<wkt>' 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;t<geometry->nobjs; 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; t<numb_points;t++) //for each point
- {
- if (use3d)
- memcpy(&result[9+ t*sub_size_3d],
- wkb_point(&pt[t],&junk, flipbytes, byte_order,use3d)
- , sub_size_3d);
- else
- memcpy(&result[9+ t*sub_size_2d],
- wkb_point(&pt[t],&junk, flipbytes, byte_order,use3d)
- , sub_size_2d);
- }
-
- return result;
-
-}
-
-
-//if mem != null, it must have enough space for the wkb
-char *wkb_line(LINE3D *line,int32 *size, bool flipbytes, char byte_order,bool use3d, char *mem)
-{
- char *result;
- uint32 type ;
-
- char *c_type = (char *) &type;
- int t;
-
- uint32 npoints = line->npoints;
- 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;t<line->npoints; 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; t<numb_points;t++)
- {
- memcpy(&result[9+16*t],&((&line->points)[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;t<numb_lines; t++)
- {
- total_points += lines[t]->npoints;
- }
-
-
- 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;t<numb_lines;t++) //for each linestring
- {
- wkb_line( lines[t], &size_part, flipbytes, byte_order, use3d, new_spot);
- new_spot += size_part; //move to next slot
- }
- return result;
-}
-
-
-//mem should be zero or hold enough space
-char *wkb_polygon(POLYGON3D *poly,int32 *size, bool flipbytes, char byte_order,bool use3d, char *mem)
-{
- int t, u,total_points =0;
- uint32 type ;
- char *c_type = (char *) &type;
- uint32 numRings,npoints;
- char *c_numRings = (char *) &numRings;
- char *c_npoints = (char *) &npoints;
- int offset;
- POINT3D *pts;
- int point_offset;
- char *result;
-
-
- //where the polygon's points are (double aligned)
-
- pts = (POINT3D *) ( (char *)&(poly->npoints[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;t<poly->nrings; 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;u<poly->npoints[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;t<poly->nrings; 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;u<poly->npoints[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;t<numb_polys; t++)
- {
- total_rings += polys[t]->nrings;
- for (u=0;u<polys[t]->nrings; 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;t<numb_polys;t++) //for each polygon
- {
- wkb_polygon( polys[t], &size_part, flipbytes, byte_order, use3d, new_spot);
- new_spot += size_part; //more to next slot
- }
- return result;
-
-}
-
-
-//passes work off to the correct function
-// then makes a simple postgres type - the first 4 bytes is an int32 with the size of the structure
-// and the rest is the wkb info.
-//
-// 3d-ness is determined by looking at the is3d flag in the GEOMETRY structure
-
-char *to_wkb(GEOMETRY *geom, bool flip_endian)
-{
- char *result, *sub_result;
- int size;
-
- if (geom->type == 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; t<geom->nobjs; 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;t<geom->nobjs; 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;t<geom->nobjs; 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;t<geom->nobjs; 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>) - 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;t<poly->nrings;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;t<nrings;t++)
- {
- result->npoints[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;t<input_str_len/2;t++)
- {
- ((unsigned char *)result)[t+4] = parse_hex( &str[t*2]) ;
- }
- PG_RETURN_POINTER(result);
-}
-
-
-//given a WKB structure, convert it to Hex and put it in a string
-PG_FUNCTION_INFO_V1(WKB_out);
-Datum WKB_out(PG_FUNCTION_ARGS)
-{
- WellKnownBinary *WKB = (WellKnownBinary *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
- char *result;
- int size_result;
- int t;
-
-//printf("wkb_out called\n");
-
- size_result = (WKB->size - 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;t<boxesPerSide*boxesPerSide; t++)
- {
- histo->value[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;t<boxesPerSide*boxesPerSide;t++)
- {
- datum = strtol(str2,&str3,10); // str2=start of int, str3=end of int, base 10
- // str3 points to "," or ")"
- if (str3[0] ==0)
- {
- elog(ERROR,"histogram2d parser - histogram values prematurely ended!\n");
- PG_RETURN_NULL() ;
- }
- histo->value[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;t<histo->boxesPerSide*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(<WKB>, [<SRID>] )
-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;t<npoints;t++)
- {
- pts[t].x = getdouble(WKB);
- WKB+=8;
- (*bytes_read)+=8;
- pts[t].y = getdouble(WKB);
- WKB+=8;
- (*bytes_read)+=8;
- if (is3d)
- {
- pts[t].z = getdouble(WKB);
- WKB+=8;
- (*bytes_read)+=8;
- }
- else
- {
- pts[t].z =0;
- }
- if ( ! finite(pts[t].x) || ! finite(pts[t].y) || ! finite(pts[t].z) )
- {
- elog(ERROR, "infinite coordinate in geom");
- return NULL;
- }
- }
- //make_line(int npoints, POINT3D *pts, int *size)
- line = make_line(npoints, pts,&size);
- return make_oneobj_geometry(size,
- (char *) line,
- LINETYPE, is3d, -1,1.0, 0.0, 0.0
- );
- }
- else
- {
- flip_endian_int32(WKB);
- 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;t<npoints;t++)
- {
- flip_endian_double(WKB);
- pts[t].x = getdouble(WKB);
- WKB+=8;
- (*bytes_read)+=8;
- flip_endian_double(WKB);
- pts[t].y = getdouble(WKB);
- WKB+=8;
- (*bytes_read)+=8;
- if (is3d)
- {
- flip_endian_double(WKB);
- pts[t].z = getdouble(WKB);
- WKB+=8;
- (*bytes_read)+=8;
- }
- else
- {
- pts[t].z =0;
- }
- if ( ! finite(pts[t].x) || ! finite(pts[t].y) || ! finite(pts[t].z) )
- {
- elog(ERROR, "infinite coordinate in geom");
- return NULL;
- }
- }
- //make_line(int npoints, POINT3D *pts, int *size)
- line = make_line(npoints, pts,&size);
- return make_oneobj_geometry(size, (char *) line, LINETYPE, is3d, -1,1.0, 0.0, 0.0);
- }
- }
- break;
- case (0x80000000 +3): //polygon 3d
- is3d =1;
- case 3: //polygon
- if ( (length-(*bytes_read)) < (4))
- elog(ERROR,"WKB:: insufficient bytes in stream");
- {
- int nrings;
- POINT3D** list_list_points;
- int32 *points_per_ring;
- int t;
- int total_points =0;
- POLYGON3D *poly;
- int size;
- POINT3D *pts;
- int point_offset;
-
- if (myByteOrder == wkbByteOrder)
- {
- nrings= getint(WKB);
- WKB+=4;
- (*bytes_read)+=4;
- list_list_points = palloc( sizeof(POINT3D*) * nrings);
- points_per_ring = palloc( sizeof(int32*) * nrings);
- for (t=0;t<nrings;t++)
- {
- int bytes, numbPoints;
-
- list_list_points[t] =
- wkb_linearring(WKB, is3d, 0, &numbPoints, &bytes,length-(*bytes_read));
- points_per_ring[t] = numbPoints;
- total_points += numbPoints;
- WKB += bytes;
- (*bytes_read)+=bytes;
- }
-
- }
- else
- {
- flip_endian_int32(WKB);
- nrings= getint(WKB);
- WKB+=4;
- (*bytes_read)+=4;
- list_list_points = palloc( sizeof(POINT3D*) * nrings);
- points_per_ring = palloc( sizeof(int32*) * nrings);
- for (t=0;t<nrings;t++)
- {
- int bytes, numbPoints;
-
- list_list_points[t] =
- wkb_linearring(WKB, is3d, 1, &numbPoints, &bytes,length-(*bytes_read));
- points_per_ring[t] = numbPoints;
- total_points += numbPoints;
- WKB += bytes;
- (*bytes_read)+=bytes;
- }
- }
- //compact point arrays
- pts = palloc ( sizeof(POINT3D) * total_points);
- point_offset = 0;
- for (t=0;t<nrings;t++)
- {
- memcpy( &pts[point_offset],list_list_points[t], sizeof(POINT3D)*points_per_ring[t]);
- point_offset += points_per_ring[t];
- }
- poly = make_polygon( nrings, points_per_ring, pts, total_points, &size);
- return make_oneobj_geometry(size,
- (char *) poly,
- POLYGONTYPE, is3d, -1,1.0, 0.0, 0.0
- );
- }
-
- break;
- case (0x80000000 +4): //multipoint 3d
- case 4: //multipoint
- {
- int ngeoms,t;
- GEOMETRY *so_far,*so_far2;
- GEOMETRY *one_obj;
-
- int mybytes_read;
- int other_bytes_read;
-
- if (myByteOrder != wkbByteOrder)
- {
- flip_endian_int32(WKB);
- }
- ngeoms= getint(WKB);
- WKB+=4;
- (*bytes_read)+=4;
- if (ngeoms ==0)
- {
- GEOMETRY *result= makeNullGeometry(-1);
- result->type = 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;t<ngeoms;t++) // already done the first
- {
- mybytes_read = *bytes_read;
- one_obj = WKBtoGeometry(WKB, length - mybytes_read, &other_bytes_read);
- (*bytes_read) = mybytes_read + other_bytes_read;
- WKB += other_bytes_read;
- so_far2 =
- (GEOMETRY *) DatumGetPointer(
- DirectFunctionCall2(collector,
- PointerGetDatum(so_far),PointerGetDatum(one_obj)
- )
- );
- pfree(one_obj);
- pfree(so_far);
- so_far = so_far2;
- }
- return so_far;
- }
- case (0x80000000 +5): //multiline 3d
- case 5: //multiline
- {
- int ngeoms,t;
- GEOMETRY *so_far,*so_far2;
- GEOMETRY *one_obj;
-
- int mybytes_read;
- int other_bytes_read;
-
- if (myByteOrder != wkbByteOrder)
- {
- flip_endian_int32(WKB);
- }
- ngeoms= getint(WKB);
- WKB+=4;
- (*bytes_read)+=4;
- if (ngeoms ==0)
- {
- GEOMETRY *result= makeNullGeometry(-1);
- result->type = 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;t<ngeoms;t++) // already done the first
- {
- mybytes_read = *bytes_read;
- one_obj = WKBtoGeometry(WKB, length - mybytes_read, &other_bytes_read);
- (*bytes_read) = mybytes_read + other_bytes_read;
- WKB += other_bytes_read;
- so_far2 =
- (GEOMETRY *) DatumGetPointer(
- DirectFunctionCall2(collector,
- PointerGetDatum(so_far),PointerGetDatum(one_obj)
- )
- );
- pfree(one_obj);
- pfree(so_far);
- so_far = so_far2;
- }
- return so_far;
- }
- case (0x80000000 +6): //multipolygon 3d
- case 6: //multipolygon
- {
- int ngeoms,t;
- GEOMETRY *so_far,*so_far2;
- GEOMETRY *one_obj;
-
- int mybytes_read;
- int other_bytes_read;
-
- if (myByteOrder != wkbByteOrder)
- {
- flip_endian_int32(WKB);
- }
- ngeoms= getint(WKB);
- WKB+=4;
- (*bytes_read)+=4;
- if (ngeoms ==0)
- {
- GEOMETRY *result= makeNullGeometry(-1);
- result->type = 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;t<ngeoms;t++) // already done the first
- {
- mybytes_read = *bytes_read;
- one_obj = WKBtoGeometry(WKB, length - mybytes_read, &other_bytes_read);
- (*bytes_read) = mybytes_read + other_bytes_read;
- WKB += other_bytes_read;
- so_far2 =
- (GEOMETRY *) DatumGetPointer(
- DirectFunctionCall2(collector,
- PointerGetDatum(so_far),PointerGetDatum(one_obj)
- )
- );
- pfree(one_obj);
- pfree(so_far);
- so_far = so_far2;
- }
- return so_far;
- }
- case (0x80000000 +7): //geometry collection 3d
- case 7: //geometry collection
- {
- int ngeoms,t;
- GEOMETRY *so_far,*so_far2;
- GEOMETRY *one_obj;
-
- int mybytes_read;
- int other_bytes_read;
-
- if (myByteOrder != wkbByteOrder)
- {
- flip_endian_int32(WKB);
- }
- ngeoms= getint(WKB);
- WKB+=4;
- (*bytes_read)+=4;
- if (ngeoms ==0)
- {
- GEOMETRY *result= makeNullGeometry(-1);
- 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 = COLLECTIONTYPE;
-
- if (ngeoms ==1)
- return so_far;
-
- for (t=1;t<ngeoms;t++) // already done the first
- {
- mybytes_read = *bytes_read;
- one_obj = WKBtoGeometry(WKB, length - mybytes_read, &other_bytes_read);
- (*bytes_read) = mybytes_read + other_bytes_read;
- WKB += other_bytes_read;
- so_far2 =
- (GEOMETRY *) DatumGetPointer(
- DirectFunctionCall2(collector,
- PointerGetDatum(so_far),PointerGetDatum(one_obj)
- )
- );
- pfree(one_obj);
- pfree(so_far);
- so_far = so_far2;
- }
- return so_far;
- }
- default:
- elog(ERROR,"unknown WKB type: %i",wkbType);
- return NULL;
-}
-return NULL;
-}
-
-// take some wkt (and if its 3d or needs endianflip) and return as list of points
-// also return the number of points and its size in bytes
-//
-POINT3D *wkb_linearring(char *WKB,char is3d, char flip_endian, int *numbPoints, int *bytes,int bytes_in_stream)
-{
- int t;
-
- if (bytes_in_stream < 4)
- elog(ERROR,"WKB:: insufficient bytes in stream");
-
- if (flip_endian)
- {
- POINT3D *pts;
- int npoints;
-
- flip_endian_int32(WKB);
- npoints= getint(WKB);
- WKB+=4;
- if ( (bytes_in_stream-4) < ((16+is3d*8))*npoints)
- elog(ERROR,"WKB:: insufficient bytes in stream");
- pts = palloc( npoints *sizeof(POINT3D));
- for (t=0;t<npoints;t++)
- {
- flip_endian_double(WKB);
- pts[t].x = getdouble(WKB);
- WKB+=8;
- flip_endian_double(WKB);
- pts[t].y = getdouble(WKB);
- WKB+=8;
- if (is3d)
- {
- flip_endian_double(WKB);
- pts[t].z = getdouble(WKB);
- WKB+=8;
- }
- else
- {
- pts[t].z =0;
- }
- if ( ! finite(pts[t].x) || ! finite(pts[t].y) || ! finite(pts[t].z) )
- {
- elog(ERROR, "infinite coordinate in geom");
- return NULL;
- }
- }
- *numbPoints = npoints;
- if (is3d)
- {
- *bytes = 4+8*3*npoints;
- }
- else
- {
- *bytes = 4+8*2*npoints;
- }
- return pts;
- }
- else
- {
- POINT3D *pts;
- int npoints;
-
- npoints= getint(WKB);
- WKB+=4;
- if ( (bytes_in_stream-4) < ((16+is3d*8))*npoints)
- elog(ERROR,"WKB:: insufficient bytes in stream");
- pts = palloc( npoints *sizeof(POINT3D));
- for (t=0;t<npoints;t++)
- {
- pts[t].x = getdouble(WKB);
- WKB+=8;
- pts[t].y = getdouble(WKB);
- WKB+=8;
- if (is3d)
- {
- pts[t].z = getdouble(WKB);
- WKB+=8;
- }
- else
- {
- pts[t].z =0;
- }
- }
- *numbPoints = npoints;
- if (is3d)
- {
- *bytes = 4+8*3*npoints;
- }
- else
- {
- *bytes = 4+8*2*npoints;
- }
- return pts;
- }
-}
-
-
-
-PG_FUNCTION_INFO_V1(geometry_from_text_poly);
-Datum geometry_from_text_poly(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 != 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;
-}
-
-
+++ /dev/null
-
-/**********************************************************************
- * $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 <math.h>
-#include <float.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-
-#include "access/gist.h"
-#include "access/itup.h"
-#include "access/rtree.h"
-
-#include "fmgr.h"
-
-#include "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;i<l2->npoints; 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;i<geom1->nobjs; 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();
-}
+++ /dev/null
-
-/**********************************************************************
- * $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 <math.h>
-#include <float.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-
-#include "access/gist.h"
-#include "access/itup.h"
-#include "access/rtree.h"
-
-
-#include "fmgr.h"
-
-
-#include "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; i<line->npoints;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; i<line->npoints;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;
-}
+++ /dev/null
-/**********************************************************************
- * $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 <klaus@svg.cc>
- * Patches from: Olivier Courtin <pnine@free.fr>
- *
- **********************************************************************
- * $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;t<geometry->nobjs; 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<npoints;u++)
- {
- if (u != 0)
- {
- result[0] = ' ';
- result++;
- }
- result+= sprintf(result,"%.*g %.*g",
- precision, pt[u].x,
- precision, pt[u].y*-1);
- }
-}
-
-
-void print_svg_path_rel(char *result, POINT3D *pt ,int npoints, int
-precision){
- int u;
-
- result += strlen(result);
- for (u=0;u<npoints;u++)
- {
- if (u == 0)
- {
- result+= sprintf(result,"%.*g %.*g l",
- precision, pt[u].x,
- precision, pt[u].y*-1);
- }
- else
- {
- result+= sprintf(result," %.*g %.*g",
- precision, (pt[u].x-pt[u-1].x),
- precision, (pt[u].y-pt[u-1].y)*-1);
- }
- }
-}
-
-
-/**********************************************************************
- * $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.
- *
- * Revision 1.2 2004/09/10 13:25:36 strk
- * fixed a memory fault
- *
- * Revision 1.1 2004/09/10 12:49:29 strk
- * Included SVG output function, modified to have precision expressed
- * in terms of significant digits.
- *
- **********************************************************************/
-
+++ /dev/null
-
-/**********************************************************************
- * $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.20 2004/08/10 21:09:59 strk
- * changed proj version extractor to support pre 4.4.8 releases
- *
- * Revision 1.19 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.18 2004/07/23 21:24:33 strk
- * Added postgis_proj_version()
- *
- * Revision 1.17 2004/07/22 16:20:10 strk
- * Added postgis_lib_version() and postgis_geos_version()
- *
- * Revision 1.16 2004/04/28 22:26:02 pramsey
- * Fixed spelling mistake in header text.
- *
- * Revision 1.15 2004/01/14 01:52:53 pramsey
- * Fix solaris alignment problem in transformations.
- *
- * Revision 1.14 2003/09/16 20:27:12 dblasby
- * added ability to delete geometries.
- *
- * Revision 1.13 2003/07/01 18:30:55 pramsey
- * Added CVS revision headers.
- *
- *
- **********************************************************************/
-
-#include "postgres.h"
-
-
-#include <math.h>
-#include <float.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-
-#include "access/gist.h"
-#include "access/itup.h"
-#include "access/rtree.h"
-
-
-#include "fmgr.h"
-
-
-#include "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;t<num_points;t++)
- {
- pts[t].x *= PI/180.0;
- pts[t].y *= PI/180.0;
- }
-}
-
-// convert radians to decimal degress
-void to_dec(POINT3D *pts, int num_points)
-{
- int t;
- for(t=0;t<num_points;t++)
- {
- pts[t].x *= 180.0/PI;
- pts[t].y *= 180.0/PI;
- }
-
-}
-
- //given a string, make a PJ object
-PJ *make_project(char *str1)
-{
- int t;
- char *params[1024]; //one for each parameter
- char *loc;
- char *str;
- PJ *result;
-
-
- if (str1 == NULL)
- return NULL;
-
- if (strlen(str1) ==0)
- return NULL;
-
- str = palloc(1+strlen(str1) );
- strcpy(str,str1);
-
- //first we split the string into a bunch of smaller strings, based on the " " separator
-
- params[0] = str; //1st param, we'll null terminate at the " " soon
-
- loc = str;
- t =1;
- while ((loc != NULL) && (*loc != 0) )
- {
- loc = strchr( loc,' ');
- if (loc != NULL)
- {
- *loc = 0; // null terminate
- params[t] = loc +1;
- loc++; // next char
- t++; //next param
- }
- }
-
- if (!(result= pj_init ( t , params)))
- {
- pfree(str);
- return NULL;
- }
- pfree(str);
- return result;
-}
-
-
-//tranform_geom( GEOMETRY, TEXT (input proj4), TEXT (output proj4), INT (output srid)
-// tmpPts - if there is a nadgrid error (-38), we re-try the transform on a copy of points. The transformed points
-// are in an indeterminate state after the -38 error is thrown.
-PG_FUNCTION_INFO_V1(transform_geom);
-Datum transform_geom(PG_FUNCTION_ARGS)
-{
- GEOMETRY *geom ;
- GEOMETRY *result;
- PJ *input_pj,*output_pj;
-
- char *o1;
- int32 *offsets1;
- int j,type1,gtype,i,poly_points;
-
- POLYGON3D *poly;
- LINE3D *line;
- POINT3D *pt,*poly_pts;
-
- char *input_proj4, *output_proj4;
-
- BOX3D *bbox;
- POINT3D *tmpPts;
-
-
-
- text *input_proj4_text;
- text *output_proj4_text;
- int32 result_srid ;
-
-
- geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
- input_proj4_text = (PG_GETARG_TEXT_P(1));
- output_proj4_text = (PG_GETARG_TEXT_P(2));
- result_srid = PG_GETARG_INT32(3);
-
-
- input_proj4 = (char *) palloc(input_proj4_text->vl_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; i<poly->nrings;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