From: David Blasby Date: Tue, 26 Jun 2001 18:33:40 +0000 (+0000) Subject: Added OGIS support functions and basic constructors. X-Git-Tag: pgis_0_5_0~25 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=571b9329bed75c5aa67daa2448e08a882d7db46c;p=postgis Added OGIS support functions and basic constructors. git-svn-id: http://svn.osgeo.org/postgis/trunk@7 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/Makefile b/Makefile index fe0a9e0fb..ec8a8c99e 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,8 @@ subdir = contrib/postgis # Root of the pgsql source tree -top_builddir = ../.. -#top_builddir = /data3/postgresql-7.1.2/src +#top_builddir = ../.. +top_builddir = /data3/postgresql-7.1.2/src include $(top_builddir)/src/Makefile.global @@ -36,11 +36,11 @@ all: all-lib $(NAME).sql # Shared library stuff include $(top_srcdir)/src/Makefile.shlib -$(NAME).sql: $(NAME).sql.in - sed -e 's:@MODULE_FILENAME@:$(libdir)/$(shlib):g' < $< > $@ - #$(NAME).sql: $(NAME).sql.in -# sed -e 's:@MODULE_FILENAME@:/data1/Refractions/Projects/PostGIS/work_dave/postgis/$(shlib):g' < $< > $@ +# sed -e 's:@MODULE_FILENAME@:$(libdir)/$(shlib):g' < $< > $@ + +$(NAME).sql: $(NAME).sql.in + sed -e 's:@MODULE_FILENAME@:/data1/Refractions/Projects/PostGIS/work_dave/postgis/$(shlib):g' < $< > $@ install: all installdirs install-lib $(INSTALL_DATA) $(srcdir)/README.$(NAME) $(docdir)/contrib diff --git a/postgis.h b/postgis.h index c54aee45a..46af4a641 100644 --- a/postgis.h +++ b/postgis.h @@ -189,6 +189,10 @@ typedef struct geomkey { int isspace(int c); +/* 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); void print_box(BOX3D *box); void print_box_oneline(BOX3D *box); @@ -241,7 +245,10 @@ 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); +char *print_geometry(GEOMETRY *geom); void swap_char(char *a, char*b); void flip_endian_double(char *dd); @@ -304,14 +311,32 @@ Datum numb_sub_objs(PG_FUNCTION_ARGS); Datum summary(PG_FUNCTION_ARGS); Datum translate(PG_FUNCTION_ARGS); -Datum wkb_XDR(PG_FUNCTION_ARGS); -Datum wkb_NDR(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 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); + //for GIST index diff --git a/postgis.sql.in b/postgis.sql.in index c2b0553a6..2031ee91b 100644 --- a/postgis.sql.in +++ b/postgis.sql.in @@ -5,12 +5,12 @@ BEGIN TRANSACTION; CREATE FUNCTION BOX3D_in(opaque) RETURNS BOX3D AS '@MODULE_FILENAME@' - LANGUAGE 'c'; + LANGUAGE 'c' with (isstrict); CREATE FUNCTION BOX3D_out(opaque) RETURNS opaque AS '@MODULE_FILENAME@' - LANGUAGE 'c'; + LANGUAGE 'c' with (isstrict); CREATE TYPE BOX3D ( alignment = double, @@ -31,12 +31,12 @@ CREATE TYPE WKB ( create function geometry_in(opaque) RETURNS GEOMETRY AS '@MODULE_FILENAME@' - LANGUAGE 'c'; + LANGUAGE 'c' with (isstrict); create function geometry_out(opaque) RETURNS opaque AS '@MODULE_FILENAME@' - LANGUAGE 'c'; + LANGUAGE 'c' with (isstrict); CREATE TYPE GEOMETRY ( alignment = double, @@ -50,24 +50,24 @@ CREATE TYPE GEOMETRY ( CREATE FUNCTION box3d(GEOMETRY) RETURNS BOX3D AS '@MODULE_FILENAME@','get_bbox_of_geometry' - LANGUAGE 'c' WITH (iscachable); + LANGUAGE 'c' WITH (iscachable,isstrict); CREATE FUNCTION geometry(BOX3D) RETURNS GEOMETRY AS '@MODULE_FILENAME@','get_geometry_of_bbox' - LANGUAGE 'c' WITH (iscachable); + LANGUAGE 'c' WITH (iscachable,isstrict); --------- functions for converting to wkb -CREATE FUNCTION wkb_NDR(GEOMETRY) +CREATE FUNCTION asbinary(GEOMETRY) RETURNS WKB - AS '@MODULE_FILENAME@','wkb_NDR' - LANGUAGE 'c' WITH (iscachable); + AS '@MODULE_FILENAME@','asbinary_simple' + LANGUAGE 'c' WITH (iscachable,isstrict); -CREATE FUNCTION wkb_XDR(GEOMETRY) +CREATE FUNCTION asbinary(GEOMETRY,TEXT) RETURNS WKB - AS '@MODULE_FILENAME@','wkb_XDR' - LANGUAGE 'c' WITH (iscachable); + AS '@MODULE_FILENAME@','asbinary_specify' + LANGUAGE 'c' WITH (iscachable,isstrict); ---- Debug (info) functions @@ -75,32 +75,98 @@ CREATE FUNCTION wkb_XDR(GEOMETRY) CREATE FUNCTION npoints(GEOMETRY) RETURNS INT4 AS '@MODULE_FILENAME@' - LANGUAGE 'c' ; + LANGUAGE 'c' with (isstrict); CREATE FUNCTION nrings(GEOMETRY) RETURNS INT4 AS '@MODULE_FILENAME@' - LANGUAGE 'c' ; + LANGUAGE 'c' with (isstrict) ; CREATE FUNCTION mem_size(GEOMETRY) RETURNS INT4 AS '@MODULE_FILENAME@' - LANGUAGE 'c' ; + LANGUAGE 'c' with (isstrict); CREATE FUNCTION numb_sub_objs(GEOMETRY) RETURNS INT4 AS '@MODULE_FILENAME@' - LANGUAGE 'c' ; + LANGUAGE 'c' with (isstrict); CREATE FUNCTION summary(GEOMETRY) RETURNS text AS '@MODULE_FILENAME@' - LANGUAGE 'c' ; + LANGUAGE 'c' with (isstrict); CREATE FUNCTION translate(GEOMETRY,float8,float8,float8) RETURNS GEOMETRY AS '@MODULE_FILENAME@' - LANGUAGE 'c' ; + LANGUAGE 'c' with (isstrict) ; + +CREATE FUNCTION dimension(GEOMETRY) + RETURNS INT4 + AS '@MODULE_FILENAME@' + LANGUAGE 'c' with (isstrict) ; + +CREATE FUNCTION geometrytype(GEOMETRY) + RETURNS text + AS '@MODULE_FILENAME@' + LANGUAGE 'c' with (isstrict); + +CREATE FUNCTION envelope(GEOMETRY) + RETURNS geometry + AS '@MODULE_FILENAME@' + LANGUAGE 'c' with (isstrict); + +CREATE FUNCTION x(GEOMETRY) + RETURNS float4 + AS '@MODULE_FILENAME@','x_point' + LANGUAGE 'c' with (isstrict); + +CREATE FUNCTION y(GEOMETRY) + RETURNS float4 + AS '@MODULE_FILENAME@','y_point' + LANGUAGE 'c' with (isstrict); + +CREATE FUNCTION z(GEOMETRY) + RETURNS float4 + AS '@MODULE_FILENAME@','z_point' + LANGUAGE 'c' with (isstrict); + +CREATE FUNCTION numpoints(GEOMETRY) + RETURNS integer + AS '@MODULE_FILENAME@','numpoints_linestring' + LANGUAGE 'c' with (isstrict); + +CREATE FUNCTION pointn(GEOMETRY,INTEGER) + RETURNS GEOMETRY + AS '@MODULE_FILENAME@','pointn_linestring' + LANGUAGE 'c' with (isstrict); + +CREATE FUNCTION exteriorring(GEOMETRY) + RETURNS GEOMETRY + AS '@MODULE_FILENAME@','exteriorring_polygon' + LANGUAGE 'c' with (isstrict); + +CREATE FUNCTION numinteriorrings(GEOMETRY) + RETURNS INTEGER + AS '@MODULE_FILENAME@','numinteriorrings_polygon' + LANGUAGE 'c' with (isstrict); + +CREATE FUNCTION interiorringn(GEOMETRY,INTEGER) + RETURNS GEOMETRY + AS '@MODULE_FILENAME@','interiorringn_polygon' + LANGUAGE 'c' with (isstrict); + + +CREATE FUNCTION numgeometries(GEOMETRY) + RETURNS INTEGER + AS '@MODULE_FILENAME@','numgeometries_collection' + LANGUAGE 'c' with (isstrict); + +CREATE FUNCTION geometryn(GEOMETRY,INTEGER) + RETURNS GEOMETRY + AS '@MODULE_FILENAME@','geometryn_collection' + LANGUAGE 'c' with (isstrict); ------- generic operations @@ -108,32 +174,32 @@ CREATE FUNCTION translate(GEOMETRY,float8,float8,float8) CREATE FUNCTION length3d(GEOMETRY) RETURNS FLOAT4 AS '@MODULE_FILENAME@' - LANGUAGE 'c'; + LANGUAGE 'c' with (isstrict); CREATE FUNCTION length2d(GEOMETRY) RETURNS FLOAT4 AS '@MODULE_FILENAME@' - LANGUAGE 'c'; + LANGUAGE 'c' with (isstrict); CREATE FUNCTION area2d(GEOMETRY) RETURNS FLOAT4 AS '@MODULE_FILENAME@' - LANGUAGE 'c'; + LANGUAGE 'c' with (isstrict); CREATE FUNCTION perimeter3d(GEOMETRY) RETURNS FLOAT4 AS '@MODULE_FILENAME@' - LANGUAGE 'c'; + LANGUAGE 'c' with (isstrict); CREATE FUNCTION perimeter2d(GEOMETRY) RETURNS FLOAT4 AS '@MODULE_FILENAME@' - LANGUAGE 'c'; + LANGUAGE 'c' with (isstrict); CREATE FUNCTION truly_inside(GEOMETRY,GEOMETRY) RETURNS bool AS '@MODULE_FILENAME@' - LANGUAGE 'c'; + LANGUAGE 'c' with (isstrict); ------- Aggregate @@ -153,47 +219,47 @@ CREATE AGGREGATE extent( ------- OPERATOR functions CREATE FUNCTION geometry_overleft(GEOMETRY, GEOMETRY) RETURNS bool - AS '@MODULE_FILENAME@' LANGUAGE 'c'; + AS '@MODULE_FILENAME@' LANGUAGE 'c' with (isstrict); CREATE FUNCTION geometry_overright(GEOMETRY, GEOMETRY) RETURNS bool - AS '@MODULE_FILENAME@' LANGUAGE 'c'; + AS '@MODULE_FILENAME@' LANGUAGE 'c' with (isstrict); CREATE FUNCTION geometry_left(GEOMETRY, GEOMETRY) RETURNS bool - AS '@MODULE_FILENAME@' LANGUAGE 'c'; + AS '@MODULE_FILENAME@' LANGUAGE 'c' with (isstrict); CREATE FUNCTION geometry_right(GEOMETRY, GEOMETRY) RETURNS bool - AS '@MODULE_FILENAME@' LANGUAGE 'c'; + AS '@MODULE_FILENAME@' LANGUAGE 'c' with (isstrict); CREATE FUNCTION geometry_contain(GEOMETRY, GEOMETRY) RETURNS bool - AS '@MODULE_FILENAME@' LANGUAGE 'c'; + AS '@MODULE_FILENAME@' LANGUAGE 'c' with (isstrict); CREATE FUNCTION geometry_contained(GEOMETRY, GEOMETRY) RETURNS bool - AS '@MODULE_FILENAME@' LANGUAGE 'c'; + AS '@MODULE_FILENAME@' LANGUAGE 'c' with (isstrict); CREATE FUNCTION geometry_overlap(GEOMETRY, GEOMETRY) RETURNS bool - AS '@MODULE_FILENAME@' LANGUAGE 'c'; + AS '@MODULE_FILENAME@' LANGUAGE 'c' with (isstrict); CREATE FUNCTION geometry_same(GEOMETRY, GEOMETRY) RETURNS bool - AS '@MODULE_FILENAME@' LANGUAGE 'c'; + AS '@MODULE_FILENAME@' LANGUAGE 'c' with (isstrict); --------- functions for doing sorting-like things (not very usefull) CREATE FUNCTION geometry_lt(GEOMETRY, GEOMETRY) RETURNS bool - AS '@MODULE_FILENAME@' LANGUAGE 'c'; + AS '@MODULE_FILENAME@' LANGUAGE 'c' with (isstrict); CREATE FUNCTION geometry_gt(GEOMETRY, GEOMETRY) RETURNS bool - AS '@MODULE_FILENAME@' LANGUAGE 'c'; + AS '@MODULE_FILENAME@' LANGUAGE 'c' with (isstrict); CREATE FUNCTION geometry_eq(GEOMETRY, GEOMETRY) RETURNS bool - AS '@MODULE_FILENAME@' LANGUAGE 'c'; + AS '@MODULE_FILENAME@' LANGUAGE 'c' with (isstrict); --------- functions for forcing geometry to be 2d or 3d CREATE FUNCTION force_2d(GEOMETRY) RETURNS GEOMETRY - AS '@MODULE_FILENAME@' LANGUAGE 'c'; + AS '@MODULE_FILENAME@' LANGUAGE 'c' with (isstrict); CREATE FUNCTION force_3d(GEOMETRY) RETURNS GEOMETRY - AS '@MODULE_FILENAME@' LANGUAGE 'c'; + AS '@MODULE_FILENAME@' LANGUAGE 'c' with (isstrict); diff --git a/postgis_debug.c b/postgis_debug.c index 420b3f10b..d5afd2276 100644 --- a/postgis_debug.c +++ b/postgis_debug.c @@ -714,3 +714,12 @@ void decode_wkb(char *wkb, int *size) } +char *print_geometry(GEOMETRY *geom) +{ + char *text; + + text = (char *) DatumGetPointer(DirectFunctionCall1(geometry_out,PointerGetDatum(geom) ) ) ; + + printf( "%s", text); + return text; +} diff --git a/postgis_fn.c b/postgis_fn.c index 5052bc1c0..312bd9fc6 100644 --- a/postgis_fn.c +++ b/postgis_fn.c @@ -970,5 +970,460 @@ Datum combine_bbox(PG_FUNCTION_ARGS) } +//return 2 for 2d geometries or 3 for 3d geometries +PG_FUNCTION_INFO_V1(dimension); +Datum dimension(PG_FUNCTION_ARGS) +{ + GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + + if (geom->is3d) + PG_RETURN_INT32(3); + else + PG_RETURN_INT32(2); +} + +//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) + + set_point( &pts[0], geom->bvol.LLB.x , geom->bvol.LLB.y , geom->bvol.LLB.z ); + set_point( &pts[1], 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[3], geom->bvol.LLB.x , geom->bvol.URT.y , geom->bvol.LLB.z ); + set_point( &pts[4], 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); + + 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_FLOAT4( ((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_FLOAT4( ((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_FLOAT4( ((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; + + + 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) + ); + } + + } + 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) + ); + } + + } + 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; + + + 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) + ); + } + } + PG_RETURN_NULL(); +} + + +// numgeometries(GEOMETRY) -- if GEOMETRY is a GEOMETRYCOLLECTION, return +//the number of geometries in it, otherwise return NULL. + +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) + 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. + + +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; + + + + offsets1 = (int32 *) ( ((char *) &(geom->objType[0] ))+ sizeof(int32) * geom->nobjs ) ; + + if (geom->type != COLLECTIONTYPE) + 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) + ); + } + if (type == LINETYPE) + { + PG_RETURN_POINTER( + make_oneobj_geometry( size_subobject (o, LINETYPE), + o, + LINETYPE, geom->is3d) + ); + } + if (type == POLYGONTYPE) + { + PG_RETURN_POINTER( + make_oneobj_geometry( size_subobject (o, POLYGONTYPE), + o, + POLYGONTYPE, geom->is3d) + ); + } + + PG_RETURN_NULL(); +} + + + + + + diff --git a/postgis_inout.c b/postgis_inout.c index ac814ff71..f9df0bc3d 100644 --- a/postgis_inout.c +++ b/postgis_inout.c @@ -1358,6 +1358,7 @@ BOX3D *bbox_of_geometry(GEOMETRY *geom) if (geom->objType[i] == POINTTYPE) { +//printf("box of a point\n"); a_box = bbox_of_point( (POINT3D *) obj); result= union_box3d(a_box ,result); @@ -1366,6 +1367,7 @@ BOX3D *bbox_of_geometry(GEOMETRY *geom) } 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) @@ -1373,6 +1375,7 @@ BOX3D *bbox_of_geometry(GEOMETRY *geom) } 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) @@ -2608,39 +2611,304 @@ char *to_wkb_sub(GEOMETRY *geom, bool flip_endian, int32 *wkb_size) } -//convert binary geometry into OGIS well know binary format with XDR (big endian) formating +//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 32768 to the type. Points are then 24bytes (X,Y,Z) // instead of 16 bytes (X,Y) - -PG_FUNCTION_INFO_V1(wkb_XDR); -Datum wkb_XDR(PG_FUNCTION_ARGS) +// +//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)); - if (BYTE_ORDER == BIG_ENDIAN) - PG_RETURN_POINTER(to_wkb(geom, FALSE)); - else - PG_RETURN_POINTER(to_wkb(geom, TRUE)); + 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 32768 to the type. Points are then 24bytes (X,Y,Z) // instead of 16 bytes (X,Y) - -PG_FUNCTION_INFO_V1(wkb_NDR); -Datum wkb_NDR(PG_FUNCTION_ARGS) +// +//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)); + GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + text *type = PG_GETARG_TEXT_P(1); - if (BYTE_ORDER == LITTLE_ENDIAN) - PG_RETURN_POINTER(to_wkb(geom, FALSE)); + if ( ( strcmp(VARDATA(type) ,"xdr") == 0 ) || (strcmp(VARDATA(type) ,"XDR") == 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 - PG_RETURN_POINTER(to_wkb(geom, TRUE)); + { +printf("requested NDR\n"); + if (BYTE_ORDER == LITTLE_ENDIAN) + PG_RETURN_POINTER(to_wkb(geom, FALSE)); + else + PG_RETURN_POINTER(to_wkb(geom, TRUE)); + } +} + + + + + +//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 +// +// do not call this with type = GEOMETRYCOLLECTION + +GEOMETRY *make_oneobj_geometry(int sub_obj_size, char *sub_obj, int type, bool is3d) +{ + 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->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) + { + return(sizeof(LINE3D) + sizeof(POINT3D) * ( ((LINE3D *)sub_obj)->npoints )); + } + if (type==POLYGONTYPE) + { + POLYGON3D *poly = (POLYGON3D *) sub_obj; + int t,points=0; + + for (t=0;tnrings;t++) + { + points += poly->npoints[t]; + } + if ( ( (long) ( &poly->npoints[poly->nrings] )) == (MAXALIGN(&poly->npoints[poly->nrings] ) ) ) + return (sizeof(POLYGON3D) + 4*(poly->nrings-1) + sizeof(POINT3D)*(points-1) ); //no extra align + else + return (sizeof(POLYGON3D) + 4*(poly->nrings-1) + sizeof(POINT3D)*(points-1) +4 ); + } + + return (-1);//unknown sub-object type +} + + +//produce a new geometry, which is the old geometry with another object stuck in it +// This will try to make the geometry's type is correct (move POINTTYPE to MULTIPOINTTYPE or +// change to GEOMETRYCOLLECTION) +// +// this does NOT calculate the bvol - you should set it with "bbox_of_geometry" +// +// type is the type of the subobject +// do not call this as with type = GEOMETRYCOLLECTION +// +// doesnt change the is3d flag + +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; + BOX3D *bbox; + + //all the offsets could cause re-alignment problems, so need to deal with each on + 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; + + //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; + + + //simple conversion + if (geom->type == POINTTYPE) + { + if (type == POINTTYPE) + result->type = MULTIPOINTTYPE; + else + result->type = COLLECTIONTYPE; + } + if (geom->type == LINETYPE) + { + if (type == LINETYPE) + result->type = MULTILINETYPE; + else + result->type = COLLECTIONTYPE; + } + if (geom->type == POLYGONTYPE) + { + 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("calculating bbox\n"); + + bbox = bbox_of_geometry(result); + memcpy(&result->bvol,bbox, sizeof(BOX3D) ); //make bounding box + +//printf("returning\n"); + + return result; +} + + + +//make a polygon obj +// size is return in arg "size" +POLYGON3D *make_polygon(int nrings, int *pts_per_ring, POINT3D *pts, int npoints, int *size) +{ + POLYGON3D *result; + int t; + POINT3D *inside_poly_pts; + + + *size = sizeof(POLYGON3D) + 4 /*align*/ + + 4*(nrings-1)/*npoints struct*/ + + sizeof(POINT3D) *(npoints-1) /*points struct*/ ; + + result= (POLYGON3D *) palloc (*size); + result->nrings = nrings; + + + for (t=0;tnpoints[t] = pts_per_ring[t]; + } + + inside_poly_pts = (POINT3D *) ( (char *)&(result->npoints[result->nrings] ) ); + inside_poly_pts = (POINT3D *) MAXALIGN(inside_poly_pts); + + memcpy(inside_poly_pts, pts, npoints *sizeof(POINT3D) ); + + return result; +} + +void set_point( POINT3D *pt,double x, double y, double z) +{ + pt->x = x; + pt->y = y; + pt->z = z; } + +//make a line3d object +// return size of structure in 'size' +LINE3D *make_line(int npoints, POINT3D *pts, int *size) +{ + LINE3D *result; + + *size = sizeof(LINE3D) + (npoints-1)*sizeof(POINT3D); + + result= (LINE3D *) palloc (*size); + + result->npoints = npoints; + memcpy( result->points, pts, npoints*sizeof(POINT3D) ); + + return result; +} \ No newline at end of file