From 16328b7229833f2dc58dcdef7f7961781b3832b5 Mon Sep 17 00:00:00 2001 From: David Blasby Date: Wed, 7 Apr 2004 23:12:31 +0000 Subject: [PATCH] Added a cstring(lwgeom) function that returns WKT! git-svn-id: http://svn.osgeo.org/postgis/trunk@501 b70326c6-7e19-0410-871a-916f4a2858ee --- lwgeom/Makefile | 2 +- lwgeom/lwgeom.sql.in | 6 + lwgeom/lwgeom_api.c | 1 + lwgeom/lwgeom_inout.c | 431 +++++++++++++++++++++++++++++++++++++++++- lwgeom/stringBuffer.c | 87 +++++++++ lwgeom/stringBuffer.h | 14 ++ 6 files changed, 539 insertions(+), 2 deletions(-) create mode 100644 lwgeom/stringBuffer.c create mode 100644 lwgeom/stringBuffer.h diff --git a/lwgeom/Makefile b/lwgeom/Makefile index 71a7980a1..b8f345bea 100644 --- a/lwgeom/Makefile +++ b/lwgeom/Makefile @@ -134,7 +134,7 @@ ifeq ($(USE_GEOS),1) GEOS_WRAPPER=postgis_geos_wrapper.o endif -OBJS=lwgeom_api.o lwgeom_functions_analytic.o lwgeom_geos.o lwgeom_inout.o lwgeom_estimate.o lwgeom_functions_basic.o lwgeom_gist.o lwgeom_transform.o +OBJS=lwgeom_api.o lwgeom_functions_analytic.o lwgeom_geos.o lwgeom_inout.o lwgeom_estimate.o lwgeom_functions_basic.o lwgeom_gist.o lwgeom_transform.o stringBuffer.o diff --git a/lwgeom/lwgeom.sql.in b/lwgeom/lwgeom.sql.in index 9748a1a61..97a8baf12 100644 --- a/lwgeom/lwgeom.sql.in +++ b/lwgeom/lwgeom.sql.in @@ -28,6 +28,12 @@ CREATE FUNCTION wkb(lwgeom) RETURNS wkb AS '/net/lion/raid/share/Refractions/Projects/PostGIS/work_dave2/postgis/lwgeom/liblwgeom.so.0.1','WKBFromLWGEOM' LANGUAGE 'C' WITH (isstrict,iscachable); + +CREATE FUNCTION cstring(lwgeom) + RETURNS CSTRING + AS '/net/lion/raid/share/Refractions/Projects/PostGIS/work_dave2/postgis/lwgeom/liblwgeom.so.0.1', + 'LWGEOM_asText' + LANGUAGE 'C' WITH (isstrict,iscachable); COMMIT; diff --git a/lwgeom/lwgeom_api.c b/lwgeom/lwgeom_api.c index 040506247..6a51ad3e7 100644 --- a/lwgeom/lwgeom_api.c +++ b/lwgeom/lwgeom_api.c @@ -1165,6 +1165,7 @@ LWGEOM_INSPECTED *lwgeom_inspect(char *serialized_form) result->serialized_form = serialized_form; result->type = serialized_form[0]; + result->SRID = -1; // assume type = lwgeom_getType(serialized_form[0]); diff --git a/lwgeom/lwgeom_inout.c b/lwgeom/lwgeom_inout.c index 5f943a3da..78bca3915 100644 --- a/lwgeom/lwgeom_inout.c +++ b/lwgeom/lwgeom_inout.c @@ -15,7 +15,7 @@ #include "lwgeom.h" - +#include "stringBuffer.h" #define DEBUG @@ -50,6 +50,15 @@ extern char *serialized_multi_to_wkb(char *serialized_form,char desiredWKBEndian extern unsigned char parse_hex(char *str); extern void deparse_hex(unsigned char str, unsigned char *result); +extern char *renderPOINTARRAY(POINTARRAY *array, int *slen,char *header); +extern char *renderLWLINE(LWLINE *line, bool wantHeader, int *slen); +extern char *renderLWPOINT(LWPOINT *pt, bool wantHeader, int *slen); +extern char *renderLWPOLY(LWPOLY *poly, bool wantHeader, int *slen); +extern char *renderMULTI(LWGEOM_INSPECTED *inspected, int *slen); +extern char *renderMULTIPOINT(LWGEOM_INSPECTED *inspected, int *slen); +extern char *renderMULTILINE(LWGEOM_INSPECTED *inspected, int *slen); +extern char *renderMULTIPOLY(LWGEOM_INSPECTED *inspected, int *slen); +extern char *renderGC(LWGEOM_INSPECTED *inspected, int *slen); // 3d or 4d. There is NOT a (x,y,m) point type!!! #define WKB3DOFFSET 0x80000000 @@ -62,6 +71,8 @@ Datum WKBFromLWGEOM(PG_FUNCTION_ARGS); Datum LWGEOM_in(PG_FUNCTION_ARGS); Datum LWGEOM_out(PG_FUNCTION_ARGS); +Datum LWGEOM_asText(PG_FUNCTION_ARGS); + // WKB structure -- exactly the same as TEXT typedef struct Well_known_bin { @@ -1101,3 +1112,421 @@ unsigned char parse_hex(char *str) return (unsigned char) ((result_high<<4) + result_low); } + +// takes a point list and makes a '(1 2,3 4)'-like string +// handles 2d, 3d, and 4d entities +// +// zero-length list looks like '()' +// +// final length of the string (excluding null-termination) +// is returned in 'slen' for easy manipulation (strlen(result) == *slen) +// +// '(1 2,3 4)' -- 2d example +// '(1 2 3,4 5 6)' -- 3d example +// '(1 2 3 4,5 6 7 8)' -- 4d example +// +// header is something you put at the beginning of the result +// ie renderPOINTARRAY(, , "LINESTRING") +// --> 'LINESTRING(1 2 3,4 5 6)' +// if you dont want a header, then send in null or an empty string +char *renderPOINTARRAY(POINTARRAY *array, int *slen, char *header) +{ + STRBUFF *buff ; + char aPointStr[400]; // big enough for a 4d point in all representations! + int t; + POINT2D pt2d; + POINT3D pt3d; + POINT4D pt4d; + char *result; + int len; + int head_length=0; + + if (header != NULL) + { + head_length = strlen(header); + // guess size a 10 chars/ordinate + buff = new_strBUFF(array->ndims * array->npoints * 10 + head_length); + catenate(buff, header, head_length); + } + else // no header + { + // guess size a 10 chars/ordinate + buff = new_strBUFF(array->ndims * array->npoints * 10); + } + + catenate(buff,"(",1); + + //optimize loop for speed + if (array->ndims == 4) + { + for (t=0;tnpoints;t++) + { + getPoint4d_p(array, t,(char *) &pt4d); + len = sprintf(aPointStr,"%.15g %.15g %.15g %.15g",pt4d.x,pt4d.y,pt4d.z,pt4d.m); + catenate(buff,aPointStr,len); + if (t!= (array->npoints-1)) // not the last one in the list + catenate(buff,",",1); + } + } + if (array->ndims == 3) + { + for (t=0;tnpoints;t++) + { + getPoint3d_p(array, t,(char *) &pt3d); + len = sprintf(aPointStr,"%.15g %.15g %.15g",pt3d.x,pt3d.y,pt3d.z); + catenate(buff,aPointStr,len); + if (t!= (array->npoints-1)) // not the last one in the list + catenate(buff,",",1); + } + } + if (array->ndims == 2) + { + for (t=0;tnpoints;t++) + { + getPoint2d_p(array, t,(char *) &pt2d); + len = sprintf(aPointStr,"%.15g %.15g",pt2d.x,pt2d.y); + catenate(buff,aPointStr,len); + if (t!= (array->npoints-1)) // not the last one in the list + catenate(buff,",",1); + } + } + + + catenate(buff,")",1); + *slen = buff->length; + result = to_CString(buff); + delete_StrBUFF(buff); + return result; +} + + +// makes a 'LINESTRING(1 2, 3 4)' (wantHeader = true) +// makes a '(1 2, 3 4)' (wantHeader = false) +// final length of the string (excluding null-termination) +// is returned in 'slen' for easy manipulation (strlen(result) == *slen) +char *renderLWLINE(LWLINE *line, bool wantHeader, int *slen) +{ + if (wantHeader) + { + return renderPOINTARRAY( line->points, slen, "LINESTRING"); + } + else + { + return renderPOINTARRAY( line->points, slen, NULL); + } +} + +// makes a 'POINT(1 2)' (wantHeader = true) +// makes a '(1 2)' (wantHeader = false) +// final length of the string (excluding null-termination) +// is returned in 'slen' for easy manipulation (strlen(result) == *slen) +char *renderLWPOINT(LWPOINT *pt, bool wantHeader, int *slen) +{ + if (wantHeader) + { + return renderPOINTARRAY( pt->point, slen, "POINT"); + } + else + { + return renderPOINTARRAY( pt->point, slen, NULL); + } +} + +// makes a 'POLYGON((),())' (wantHeader = true) +// makes a '((),())' (wantHeader = false) +// example:: +// 'POLYGON((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1))' (1 ring) +// 'POLYGON((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1),(2 2,2 3,3 3,3 2,2 2))' (2 rings) +// final length of the string (excluding null-termination) +// is returned in 'slen' for easy manipulation (strlen(result) == *slen) +char *renderLWPOLY(LWPOLY *poly, bool wantHeader, int *slen) +{ + STRBUFF *result_buff; + char *result; + int total_points =0; + int t; + + + + for (t=0;tnrings;t++) + { + total_points += poly->rings[t]->npoints; + } + // guess at size + result_buff = new_strBUFF(poly->ndims * total_points * 10 ); + + + if (wantHeader) + catenate(result_buff, "POLYGON(",8); + else + catenate(result_buff, "(",1); + + for (t=0;tnrings;t++) + { + char *aRingStr = renderPOINTARRAY( poly->rings[t], slen, NULL); + catenate(result_buff,aRingStr,*slen); + pfree(aRingStr); + if (t!= (poly->nrings-1) ) // not the last one + catenate(result_buff,",",1); + } + + catenate(result_buff, ")",1); + + *slen = result_buff->length; + result = to_CString(result_buff); + delete_StrBUFF(result_buff); + return result; +} + +// NOTE: (!! LOOK !!) +// 'MULTIPOINT(0 0,1 1,2 2)' --NOT--- 'MULTIPOINT((0 0),(1 1),(2 2))' +char *renderMULTIPOINT(LWGEOM_INSPECTED *inspected, int *slen) +{ + STRBUFF *buff ; + char aPointStr[400]; // big enough for a 4d point in all representations! + int t; + POINT2D pt2d; + POINT3D pt3d; + POINT4D pt4d; + char *result; + int len; + + + // guess size a 10 chars/ordinate + buff = new_strBUFF(4 * inspected->ngeometries * 10); + + + catenate(buff,"MULTIPOINT(",11); + + for (t=0;tngeometries;t++) + { + LWPOINT *pt = lwgeom_getpoint_inspected(inspected, t); + if (pt->ndims == 4) + { + getPoint4d_p(pt->point,0,(char *) &pt4d); + len = sprintf(aPointStr,"%.15g %.15g %.15g %.15g",pt4d.x,pt4d.y,pt4d.z,pt4d.m); + catenate(buff,aPointStr,len); + if (t!= (inspected->ngeometries-1)) // not the last one in the list + catenate(buff,",",1); + } + if (pt->ndims == 3) + { + getPoint3d_p(pt->point,0,(char *) &pt3d); + len = sprintf(aPointStr,"%.15g %.15g %.15g",pt3d.x,pt3d.y,pt3d.z); + catenate(buff,aPointStr,len); + if (t!= (inspected->ngeometries-1)) // not the last one in the list + catenate(buff,",",1); + } + if (pt->ndims == 2) + { + getPoint2d_p(pt->point,0,(char *) &pt2d); + len = sprintf(aPointStr,"%.15g %.15g",pt2d.x,pt2d.y); + catenate(buff,aPointStr,len); + if (t!= (inspected->ngeometries-1)) // not the last one in the list + catenate(buff,",",1); + } + pfree_point(pt); + } + + catenate(buff,")",1); + *slen = buff->length; + result = to_CString(buff); + delete_StrBUFF(buff); + return result; +} + +char *renderMULTILINE(LWGEOM_INSPECTED *inspected, int *slen) +{ + STRBUFF *buff ; + int t; + char *result; + int len; + + // guess size a 10 chars/ordinate and 10 points/line -- total guess + buff = new_strBUFF(4* inspected->ngeometries * 10 * 10); + + + catenate(buff,"MULTILINESTRING(",16); + + for (t=0;tngeometries;t++) + { + LWLINE *line = lwgeom_getline_inspected(inspected, t); + char *single_line = renderLWLINE(line,false, &len); + catenate(buff, single_line, len); + pfree(single_line); + pfree_line(line); + if (t != (inspected->ngeometries-1) ) + catenate(buff,",",1); + } + + catenate(buff,")",1); + *slen = buff->length; + result = to_CString(buff); + delete_StrBUFF(buff); + + return result; +} + +char *renderMULTIPOLY(LWGEOM_INSPECTED *inspected, int *slen) +{ + STRBUFF *buff ; + int t; + char *result; + int len; + + + + // guess size a 10 chars/ordinate and 20 points/polygon -- total guess + buff = new_strBUFF(4 * inspected->ngeometries * 10 * 20); + + + catenate(buff,"MULTIPOLYGON(",13); + + for (t=0;tngeometries;t++) + { + LWPOLY *poly = lwgeom_getpoly_inspected(inspected, t); + char *single_poly = renderLWPOLY(poly,false, &len); + catenate(buff, single_poly, len); + pfree(single_poly); + pfree_polygon(poly); + if (t != (inspected->ngeometries-1) ) + catenate(buff,",",1); + } + + catenate(buff,")",1); + *slen = buff->length; + result = to_CString(buff); + delete_StrBUFF(buff); + + return result; +} + + +char *renderGC(LWGEOM_INSPECTED *inspected, int *slen) +{ + STRBUFF *buff ; + int t; + char *result; + int len; + // guess size a 10 chars/ordinate and 20 points/object -- total guess + buff = new_strBUFF(4 * inspected->ngeometries * 10 * 20); + + + catenate(buff,"GEOMETRYCOLLECTION(",19); + + for (t=0;tngeometries;t++) + { + char *single_obj = lwgeom_getsubgeometry_inspected(inspected,t); + LWGEOM_INSPECTED *inspected_sub = lwgeom_inspect(single_obj); + char *single_obj_str = renderMULTI(inspected_sub, &len); + pfree_inspected(inspected_sub); + + catenate(buff, single_obj_str, len); + pfree(single_obj_str); + + if (t != (inspected->ngeometries-1) ) + catenate(buff,",",1); + } + + catenate(buff,")",1); + *slen = buff->length; + result = to_CString(buff); + delete_StrBUFF(buff); + + return result; +} + +// makes things like: +// 'MULTILINESTRING((1 2,3 4,5 6),(7 8,9 10))' +// 'MULTIPOLYGON(((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1)),((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1)' +// 'GEOMETRYCOLLECTION(LINESTRING(5 6 -55,7 8 -22),LINESTRING(1 2 -1,3 4 -2))' +// +// NOTE: (!! LOOK !!) +// 'MULTIPOINT(0 0,1 1,2 2)' --NOT--- 'MULTIPOINT((0 0),(1 1),(2 2))' +// +// handles MULTI* inside GCs +// +// final length of the string (excluding null-termination) +// is returned in 'slen' for easy manipulation (strlen(result) == *slen) +char *renderMULTI(LWGEOM_INSPECTED *inspected, int *slen) +{ + LWPOINT *pt; + LWLINE *line; + LWPOLY *poly; + char *result; + + + switch(lwgeom_getType(inspected->type)) + { + // shouldnt call this with a singular type, but we handle it here anyways + case POINTTYPE: + pt = lwgeom_getpoint_inspected(inspected,0); + result = renderLWPOINT(pt, true, slen); + pfree_point(pt); + return result; + break; //redundant + case LINETYPE: + line = lwgeom_getline_inspected(inspected,0); + result = renderLWLINE(line, true, slen); + pfree_line(line); + return result; + break; //redundant + case POLYGONTYPE: + poly = lwgeom_getpoly_inspected(inspected,0); + result = renderLWPOLY(poly, true, slen); + pfree_polygon(poly); + return result; + break; //redundant + case MULTIPOINTTYPE: + //this is the special case 'MULTIPOINT(0 0,1 1,2 2,3 3)' + return renderMULTIPOINT(inspected, slen); // special case!! + break; //redundant + case MULTILINETYPE: + return renderMULTILINE(inspected, slen); + break; //redundant + case MULTIPOLYGONTYPE: + return renderMULTIPOLY(inspected, slen); + break; //redundant + case COLLECTIONTYPE: + return renderGC(inspected, slen); // special case -- could recurse + break; //redundant + } + elog(ERROR,"renderMULTI:: couldnt determine geometry type"); + return NULL; +} + + + + +PG_FUNCTION_INFO_V1(LWGEOM_asText); +Datum LWGEOM_asText(PG_FUNCTION_ARGS) +{ + char *lwgeom = (char *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + char *wkt; + char *result; + int len,len_total; + int SRID; + LWGEOM_INSPECTED *inspected = lwgeom_inspect(lwgeom+4); + char SRIDtext[100]; + int len_SRIDtext; + + wkt = renderMULTI(inspected, &len); + elog(NOTICE," wkt = %s", wkt); + + SRID = inspected->SRID; + + len_SRIDtext = sprintf(SRIDtext,"SRID=%i;",SRID); + elog(NOTICE," srid = %i", SRID); + len_total = len + len_SRIDtext+ 1 ; // 1= null term + + result = palloc(len_total);//extra space for SRID + + memcpy(result, SRIDtext, len_SRIDtext); + memcpy(result+len_SRIDtext, wkt, len); + result[len_total-1] = 0;//ensure null-terminated + + pfree(wkt); + + PG_RETURN_CSTRING(result); + +} diff --git a/lwgeom/stringBuffer.c b/lwgeom/stringBuffer.c new file mode 100644 index 000000000..7017001e1 --- /dev/null +++ b/lwgeom/stringBuffer.c @@ -0,0 +1,87 @@ +#include "postgres.h" +#include +#include "stdio.h" +#include +#include +#include "stringBuffer.h" + +#define DEFAULT_STR_LENGTH_PADDING 10 +#define DEFAULT_PERCENT_SIZE_INCREASE 0.25 + +//NOTE: buffer->length does NOT include the null!!! + + + + +//constructor for the string buffer +STRBUFF * new_strBUFF(int size) { + STRBUFF * buffer; + buffer = (STRBUFF *)palloc(sizeof(STRBUFF)); + buffer->string = (char * )palloc(size); + buffer->size = size; + buffer->length = 0; + return buffer; +} + +//destructor +void delete_StrBUFF(STRBUFF* buffer) { + pfree(buffer->string); + pfree(buffer); +} + +//returns a CString contained in the buffer +char* to_CString(STRBUFF* buffer) { + char* resultStr; + if(buffer->length == 0) { + return NULL; + } + + resultStr = (char * )palloc(buffer->length+1); + memcpy(resultStr, buffer->string, buffer->length+1); + return resultStr; +} + +//add a string to the buffer- calls catenate +void add_str_simple(STRBUFF* buffer, char* str) { + if(str == NULL) { + return; + } + catenate(buffer, str, strlen(str)); +} + +//adds the new string to the existing string in the buffer +//allocates +void catenate(STRBUFF *buffer, char* str, int strLength) +{ + if (buffer->size <= (buffer->length+strLength) ) // not big enough to hold this + null termination + { + //need to re-allocate the buffer so its bigger + char *old_buffer = buffer->string; + int new_size = getSize(buffer->size, buffer->length, strLength); //new size (always big enough) + + buffer->string = palloc(new_size); + buffer->size = new_size; + memcpy(buffer->string, old_buffer, buffer->length+1); // copy old string (+1 = null term) + + // buff is exactly the same as it was, except it has a bigger string buffer + pfree(old_buffer); + } + + //add new info + memcpy(buffer->string + buffer->length, str, strLength); + buffer->length += strLength; + buffer->string[buffer->length] = 0;// force null-terminated +} + + +// get new buffer size +// new size = + +// 10 + //just a little constant +// 25% * //exponential growth +int getSize(int buffer_size, int buffer_length, int strLength) +{ + int needed_extra = strLength - (buffer_size-buffer_length); // extra space required in buffer + + return buffer_size + needed_extra + DEFAULT_STR_LENGTH_PADDING + buffer_size*DEFAULT_PERCENT_SIZE_INCREASE; +} + diff --git a/lwgeom/stringBuffer.h b/lwgeom/stringBuffer.h new file mode 100644 index 000000000..ce6dc737d --- /dev/null +++ b/lwgeom/stringBuffer.h @@ -0,0 +1,14 @@ + +typedef struct { + char * string; + int length;//length of string, EXCLUDING null termination + int size; //size of buffer -can be longer than +} STRBUFF; + + +extern STRBUFF * new_strBUFF(int size); +extern void delete_StrBUFF(STRBUFF* buff); +extern char* to_CString(STRBUFF * buffer); +extern void add_str_simple(STRBUFF* buffer, char* str); +extern void catenate(STRBUFF *buffer, char* str, int length); +extern int getSize(int buffer_size, int buffer_length, int strLength); -- 2.49.0