]> granicus.if.org Git - postgis/commitdiff
First cut of new WKT output functions, need more unit tests.
authorPaul Ramsey <pramsey@cleverelephant.ca>
Mon, 22 Feb 2010 19:53:22 +0000 (19:53 +0000)
committerPaul Ramsey <pramsey@cleverelephant.ca>
Mon, 22 Feb 2010 19:53:22 +0000 (19:53 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@5302 b70326c6-7e19-0410-871a-916f4a2858ee

liblwgeom/Makefile.in
liblwgeom/cunit/Makefile.in
liblwgeom/cunit/cu_tester.c
liblwgeom/cunit/cu_tester.h
liblwgeom/cunit/cu_wkt.c [new file with mode: 0644]
liblwgeom/cunit/cu_wkt.h [new file with mode: 0644]
liblwgeom/libgeom.h
liblwgeom/liblwgeom.h
liblwgeom/lwout_wkt.c [new file with mode: 0644]
liblwgeom/stringbuffer.c
liblwgeom/stringbuffer.h

index bd441411828affc2e63e9b285629859831d2694e..904891063206f5749bb7222b9b68fd230d5ab031 100644 (file)
@@ -37,6 +37,7 @@ SA_OBJS = \
        lwcurvepoly.o \
        lwmcurve.o \
        lwmsurface.o \
+       lwout_wkt.o \
        lwutil.o \
        lwhomogenize.o \
        lwalgorithm.o \
index b9f6291ced3f3609b1fae01b080bb733de111a8c..751e29ef4c2539653b772d99d922f209e2615788 100644 (file)
@@ -18,6 +18,7 @@ CUNIT_CPPFLAGS=@CUNIT_CPPFLAGS@ -I..
 
 OBJS=  \
        cu_algorithm.o \
+       cu_wkt.o \
        cu_geodetic.o \
        cu_measures.o \
        cu_libgeom.o \
index ae210d244e0fc3d029307b7668e98f218a90e6a0..f157278804685140b7d3ccc03cddb7e90d6ed313 100644 (file)
@@ -85,6 +85,13 @@ int main()
                return CU_get_error();
        }
 
+       /* Add the wkt suite to the registry */
+       if (NULL == register_wkt_suite())
+       {
+               CU_cleanup_registry();
+               return CU_get_error();
+       }
+
        /* Add the libgeom suite to the registry */
        if (NULL == register_libgeom_suite())
        {
index d8fcc7bd8bb42dfc73689c9206d3605bc98939c8..7b42a9520845a240bb875c8162a3fc46dd6f018a 100644 (file)
@@ -6,6 +6,7 @@ CU_pSuite register_measures_suite(void);
 CU_pSuite register_geodetic_suite(void);
 CU_pSuite register_libgeom_suite(void);
 CU_pSuite register_cg_suite(void);
+CU_pSuite register_wkt_suite(void);
 CU_pSuite register_homogenize_suite(void);
 CU_pSuite register_out_gml_suite(void);
 CU_pSuite register_out_kml_suite(void);
@@ -16,6 +17,7 @@ int init_measures_suite(void);
 int init_geodetic_suite(void);
 int init_libgeom_suite(void);
 int init_cg_suite(void);
+int init_wkt_suite(void);
 int init_homogenize_suite(void);
 int init_out_gml_suite(void);
 int init_out_kml_suite(void);
@@ -26,6 +28,7 @@ int clean_measures_suite(void);
 int clean_geodetic_suite(void);
 int clean_libgeom_suite(void);
 int clean_cg_suite(void);
+int clean_wkt_suite(void);
 int clean_homogenize_suite(void);
 int clean_out_gml_suite(void);
 int clean_out_kml_suite(void);
diff --git a/liblwgeom/cunit/cu_wkt.c b/liblwgeom/cunit/cu_wkt.c
new file mode 100644 (file)
index 0000000..f2a4bc4
--- /dev/null
@@ -0,0 +1,118 @@
+/**********************************************************************
+ * $Id$
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ * http://postgis.refractions.net
+ * Copyright 2010 Olivier Courtin <olivier.courtin@oslandia.com>
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of the GNU General Public Licence. See the COPYING file.
+ *
+ **********************************************************************/
+
+#include "cu_wkt.h"
+
+/*
+** Called from test harness to register the tests in this file.
+*/
+CU_pSuite register_wkt_suite(void)
+{
+       CU_pSuite pSuite;
+       pSuite = CU_add_suite("WKT Suite", init_wkt_suite, clean_wkt_suite);
+       if (NULL == pSuite)
+       {
+               CU_cleanup_registry();
+               return NULL;
+       }
+
+       if (
+           (NULL == CU_add_test(pSuite, "test_wkt_point()", test_wkt_point)) ||
+           (NULL == CU_add_test(pSuite, "test_wkt_linestring()", test_wkt_linestring)) ||
+           (NULL == CU_add_test(pSuite, "test_wkt_polygon()", test_wkt_polygon)) ||
+           (NULL == CU_add_test(pSuite, "test_wkt_multipoint()", test_wkt_multipoint)) ||
+           (NULL == CU_add_test(pSuite, "test_wkt_multilinestring()", test_wkt_multilinestring)) ||
+           (NULL == CU_add_test(pSuite, "test_wkt_multipolygon()", test_wkt_multipolygon)) ||
+           (NULL == CU_add_test(pSuite, "test_wkt_collection()", test_wkt_collection)) 
+       )
+       {
+               CU_cleanup_registry();
+               return NULL;
+       }
+       return pSuite;
+}
+
+/*
+** The suite initialization function.
+** Create any re-used objects.
+*/
+int init_wkt_suite(void)
+{
+       return 0;
+}
+
+/*
+** The suite cleanup function.
+** Frees any global objects.
+*/
+int clean_wkt_suite(void)
+{
+       return 0;
+}
+
+void test_wkt_point(void)
+{
+       LWGEOM *g;
+       char *s;
+
+       g = lwgeom_from_ewkt("POINT(0 0 0 0)", PARSER_CHECK_NONE);
+       s = lwgeom_to_wkt(g, 14, WKT_ISO);
+       CU_ASSERT_STRING_EQUAL(s, "POINTZM(0 0 0 0)");
+       lwfree(s);
+
+       s = lwgeom_to_wkt(g, 14, WKT_EXTENDED);
+       CU_ASSERT_STRING_EQUAL(s, "POINT(0 0 0 0)");
+       lwfree(s);
+
+       s = lwgeom_to_wkt(g, 14, WKT_SFSQL);
+       CU_ASSERT_STRING_EQUAL(s, "POINT(0 0)");
+       lwfree(s);
+       lwgeom_free(g);
+
+       g = lwgeom_from_ewkt("POINTM(0 0 0)", PARSER_CHECK_NONE);
+       s = lwgeom_to_wkt(g, 14, WKT_ISO);
+       CU_ASSERT_STRING_EQUAL(s, "POINTM(0 0 0)");
+       lwfree(s);
+
+       s = lwgeom_to_wkt(g, 14, WKT_EXTENDED);
+       CU_ASSERT_STRING_EQUAL(s, "POINTM(0 0 0)");
+       lwfree(s);
+
+       s = lwgeom_to_wkt(g, 14, WKT_SFSQL);
+       CU_ASSERT_STRING_EQUAL(s, "POINT(0 0)");
+       lwfree(s);
+       lwgeom_free(g);
+
+}
+
+void test_wkt_linestring(void) 
+{
+
+}
+
+void test_wkt_polygon(void) 
+{
+
+}
+void test_wkt_multipoint(void) 
+{
+               
+}
+
+void test_wkt_multilinestring(void) 
+{
+       
+}
+
+void test_wkt_multipolygon(void) {}
+void test_wkt_collection(void) {}
+
diff --git a/liblwgeom/cunit/cu_wkt.h b/liblwgeom/cunit/cu_wkt.h
new file mode 100644 (file)
index 0000000..cfaaaa5
--- /dev/null
@@ -0,0 +1,31 @@
+/**********************************************************************
+ * $Id:$
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ * http://postgis.refractions.net
+ * Copyright 2010 Olivier Courtin <olivier.courtin@oslandia.com>
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of the GNU General Public Licence. See the COPYING file.
+ *
+ **********************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "CUnit/Basic.h"
+
+#include "libgeom.h"
+#include "cu_tester.h"
+
+/**********************************************************************/
+
+
+/* Test functions */
+void test_wkt_point(void);
+void test_wkt_linestring(void);
+void test_wkt_polygon(void);
+void test_wkt_multipoint(void);
+void test_wkt_multilinestring(void);
+void test_wkt_multipolygon(void);
+void test_wkt_collection(void);
\ No newline at end of file
index 4842254a0e96fa01c23122d4401ab37d2eb5ccbd..f78f029359850f2d839562b786c1d0e5c60f143e 100644 (file)
 #define LW_TRUE 1
 #define LW_FALSE 0
 
+/**
+* WKT Output Variant Types
+*/
+#define WKT_ISO 0x01
+#define WKT_SFSQL 0x02
+#define WKT_EXTENDED 0x04
+#define WKT_NOTYPE 0x08
+#define WKT_NOPARENS 0x10
+
 /**
 * Maximum allowed SRID value. 
 * Currently we are using 20 bits (1048575) of storage for SRID.
index 69bc0370ef382a6dbb1db3adc2b2a8b00d4f967f..4c457a2ef0eb457c20a4661d8bebb82bdd8a6606 100644 (file)
@@ -1423,6 +1423,12 @@ extern LWGEOM* lwpoly_remove_repeated_points(LWPOLY *in);
 extern uchar parse_hex(char *str);
 extern void deparse_hex(uchar str, char *result);
 
+/*
+** New parsing and unparsing functions.
+*/
+extern char *lwgeom_to_wkt(const LWGEOM *geom, int precision, uchar variant);
+
+
 /* Parser check flags */
 #define PARSER_CHECK_MINPOINTS  1
 #define PARSER_CHECK_ODD        2
diff --git a/liblwgeom/lwout_wkt.c b/liblwgeom/lwout_wkt.c
new file mode 100644 (file)
index 0000000..158a216
--- /dev/null
@@ -0,0 +1,542 @@
+/**********************************************************************
+ * $Id$
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ * Copyright 2009 Paul Ramsey <pramsey@cleverelephant.ca>
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of the GNU General Public Licence. See the COPYING file.
+ *
+ **********************************************************************/
+
+#include "libgeom.h"
+
+static void lwgeom_to_wkt_sb(const LWGEOM *geom, stringbuffer_t *sb, int precision, uchar variant);
+
+
+/**
+* ISO format uses both Z and M qualifiers.
+* Extended format only uses an M qualifier for 3DM variants, where it is not
+* clear what the third dimension represents.
+* SFSQL format never has more than two dimensions, so no qualifiers.
+*/
+static void dimension_qualifiers_to_wkt_sb(const LWGEOM *geom, stringbuffer_t *sb, uchar variant)
+{
+
+       /* Extended WKT: POINTM(0 0 0) */
+       if( (variant & WKT_EXTENDED) && TYPE_HASM(geom->type) && (!TYPE_HASZ(geom->type)) )
+       {
+               stringbuffer_append(sb, "M"); /* "M" */
+               return;
+       }
+               
+       /* ISO WKT: POINT ZM (0 0 0 0) */
+       if( (variant & WKT_ISO) && (TYPE_NDIMS(geom->type) > 2) )
+       {
+               if( TYPE_HASZ(geom->type) )
+                       stringbuffer_append(sb, "Z");
+               if( TYPE_HASM(geom->type) )
+                       stringbuffer_append(sb, "M");
+       }       
+}
+
+/**
+* Point array is a list of coordinates. Depending on output mode,
+* we may suppress some dimensions. ISO and Extended formats include
+* all dimensions. Standard OGC output only includes X/Y coordinates.
+*/
+static void ptarray_to_wkt_sb(const POINTARRAY *ptarray, stringbuffer_t *sb, int precision, uchar variant)
+{
+       /* OGC only includes X/Y */
+       int dimensions = 2;
+       int i, j;
+       
+       /* ISO and extended formats include all dimensions */
+       if( variant & ( WKT_ISO | WKT_EXTENDED ) )
+               dimensions = TYPE_NDIMS(ptarray->dims);
+
+       /* Opening paren? */
+       if( ! (variant & WKT_NOPARENS) )
+               stringbuffer_append(sb, "(");
+       
+       /* Digits and commas */
+       for(i = 0; i < ptarray->npoints; i++)
+       {
+               uchar *p = getPoint_internal(ptarray, i);
+               double d;
+
+               /* Commas before ever coord but the first */
+               if( i > 0 )
+                       stringbuffer_append(sb, ",");
+
+               for(j = 0; j < dimensions; j++)
+               {
+                       memcpy(&d, p + j * sizeof(double), sizeof(double));             
+                       /* Spaces before every ordinate but the first */
+                       if( j > 0 )
+                               stringbuffer_append(sb, " ");
+                       stringbuffer_vasbappend(sb, "%.*g", precision, d);
+               }
+       }
+       
+       /* Closing paren? */
+       if( ! (variant & WKT_NOPARENS) )
+               stringbuffer_append(sb, ")");
+}
+
+/**
+* A four-dimensional point will have different outputs depending on variant.
+*   ISO: POINT ZM (0 0 0 0)
+*   Extended: POINT(0 0 0 0)
+*   OGC: POINT(0 0)
+* A three-dimensional m-point will have different outputs too.
+*   ISO: POINT M (0 0 0)
+*   Extended: POINTM(0 0 0)
+*   OGC: POINT(0 0)
+*/
+static void lwpoint_to_wkt_sb(const LWPOINT *pt, stringbuffer_t *sb, int precision, uchar variant)
+{
+       if( ! (variant & WKT_NOTYPE) )
+       {
+               stringbuffer_append(sb, "POINT"); /* "POINT" */
+               dimension_qualifiers_to_wkt_sb((LWGEOM*)pt, sb, variant);
+       }
+
+       if( pt->point->npoints < 1 )
+       {
+               stringbuffer_append(sb, " EMPTY"); /* "EMPTY" */
+               return;
+       }       
+
+       ptarray_to_wkt_sb(pt->point, sb, precision, variant);
+}
+
+/**
+* LINESTRING(0 0 0, 1 1 1)
+*/
+static void lwline_to_wkt_sb(const LWLINE *line, stringbuffer_t *sb, int precision, uchar variant) 
+{
+       if( ! (variant & WKT_NOTYPE) )
+       {
+               stringbuffer_append(sb, "LINESTRING"); /* "LINESTRING" */
+               dimension_qualifiers_to_wkt_sb((LWGEOM*)line, sb, variant);
+       }
+       if( line->points->npoints < 1 )
+       {
+               stringbuffer_append(sb, " EMPTY"); /* "EMPTY" */
+               return;
+       }
+
+       ptarray_to_wkt_sb(line->points, sb, precision, variant);
+}
+
+/**
+* POLYGON(0 0 1, 1 0 1, 1 1 1, 0 1 1, 0 0 1)
+*/
+static void lwpoly_to_wkt_sb(const LWPOLY *poly, stringbuffer_t *sb, int precision, uchar variant) 
+{
+       int i = 0;
+       if( ! (variant & WKT_NOTYPE) )
+       {
+               stringbuffer_append(sb, "POLYGON"); /* "POLYGON" */
+               dimension_qualifiers_to_wkt_sb((LWGEOM*)poly, sb, variant);
+       }
+       if( poly->nrings < 1 )
+       {
+               stringbuffer_append(sb, " EMPTY"); /* "EMPTY" */
+               return;
+       }
+
+       stringbuffer_append(sb, "(");
+       for( i = 0; i < poly->nrings; i++ )
+       {
+               if( i > 0 )
+                       stringbuffer_append(sb, ",");
+               ptarray_to_wkt_sb(poly->rings[i], sb, precision, variant);
+       }
+       stringbuffer_append(sb, ")");
+}
+
+/**
+* CIRCULARSTRING
+*/
+static void lwcircstring_to_wkt_sb(const LWCIRCSTRING *circ, stringbuffer_t *sb, int precision, uchar variant) 
+{
+       if( ! (variant & WKT_NOTYPE) )
+       {
+               stringbuffer_append(sb, "CIRCULARSTRING"); /* "CIRCULARSTRING" */
+               dimension_qualifiers_to_wkt_sb((LWGEOM*)circ, sb, variant);
+       }
+       if( circ->points->npoints < 1 )
+       {
+               stringbuffer_append(sb, " EMPTY"); /* "EMPTY" */
+               return;
+       }
+       ptarray_to_wkt_sb(circ->points, sb, precision, variant);
+}
+
+
+/**
+* Multi-points do not wrap their sub-members in parens, unlike other multi-geometries.
+*   MULTPOINT(0 0, 1 1) instead of MULTIPOINT((0 0),(1 1))
+*/
+static void lwmpoint_to_wkt_sb(const LWMPOINT *mpoint, stringbuffer_t *sb, int precision, uchar variant) 
+{      
+       int i = 0;
+       if( ! (variant & WKT_NOTYPE) )
+       {
+               stringbuffer_append(sb, "MULTIPOINT"); /* "MULTIPOINT" */
+               dimension_qualifiers_to_wkt_sb((LWGEOM*)mpoint, sb, variant);
+       }
+       if( mpoint->ngeoms < 1 )
+       {
+               stringbuffer_append(sb, " EMPTY"); /* "EMPTY" */
+               return;
+       }
+       stringbuffer_append(sb, "(");
+       for( i = 0; i < mpoint->ngeoms; i++ )
+       {
+               if( i > 0 )
+                       stringbuffer_append(sb, ",");
+               /* We don't want type strings or parens on our subgeoms */
+               lwpoint_to_wkt_sb(mpoint->geoms[i], sb, precision, variant | WKT_NOPARENS | WKT_NOTYPE );
+       }
+       stringbuffer_append(sb, ")");
+}
+
+/**
+* MULTILINESTRING
+*/
+static void lwmline_to_wkt_sb(const LWMLINE *mline, stringbuffer_t *sb, int precision, uchar variant) 
+{
+       int i = 0;
+       
+       if( ! (variant & WKT_NOTYPE) )
+       {
+               stringbuffer_append(sb, "MULTILINESTRING"); /* "MULTILINESTRING" */
+               dimension_qualifiers_to_wkt_sb((LWGEOM*)mline, sb, variant);
+       }
+       if( mline->ngeoms < 1 )
+       {
+               stringbuffer_append(sb, " EMPTY"); /* "EMPTY" */
+               return;
+       }
+
+       stringbuffer_append(sb, "(");
+       for( i = 0; i < mline->ngeoms; i++ )
+       {
+               if( i > 0 )
+                       stringbuffer_append(sb, ",");
+               /* We don't want type strings on our subgeoms */
+               lwline_to_wkt_sb(mline->geoms[i], sb, precision, variant | WKT_NOTYPE );
+       }
+       stringbuffer_append(sb, ")");
+}
+
+/**
+* MULTIPOLYGON
+*/
+static void lwmpoly_to_wkt_sb(const LWMPOLY *mpoly, stringbuffer_t *sb, int precision, uchar variant) 
+{
+       int i = 0;
+       
+       if( ! (variant & WKT_NOTYPE) )
+       {
+               stringbuffer_append(sb, "MULTIPOLYGON"); /* "MULTIPOLYGON" */
+               dimension_qualifiers_to_wkt_sb((LWGEOM*)mpoly, sb, variant);
+       }
+       if( mpoly->ngeoms < 1 )
+       {
+               stringbuffer_append(sb, " EMPTY"); /* "EMPTY" */
+               return;
+       }
+
+       stringbuffer_append(sb, "(");
+       for( i = 0; i < mpoly->ngeoms; i++ )
+       {
+               if( i > 0 )
+                       stringbuffer_append(sb, ",");
+               /* We don't want type strings on our subgeoms */
+               lwpoly_to_wkt_sb(mpoly->geoms[i], sb, precision, variant | WKT_NOTYPE );
+       }
+       stringbuffer_append(sb, ")");
+}
+
+/** 
+* Compound curves provide type information for their curved sub-geometries
+* but not their linestring sub-geometries.
+*   COMPOUNDCURVE((0 0, 1 1), CURVESTRING(1 1, 2 2, 3 3))
+*/
+static void lwcompound_to_wkt_sb(const LWCOMPOUND *comp, stringbuffer_t *sb, int precision, uchar variant) 
+{
+       int i = 0;
+       
+       if( ! (variant & WKT_NOTYPE) )
+       {
+               stringbuffer_append(sb, "COMPOUNDCURVE"); /* "COMPOUNDCURVE" */
+               dimension_qualifiers_to_wkt_sb((LWGEOM*)comp, sb, variant);
+       }
+       if( comp->ngeoms < 1 )
+       {
+               stringbuffer_append(sb, " EMPTY"); /* "EMPTY" */
+               return;
+       }
+
+       stringbuffer_append(sb, "(");
+       for( i = 0; i < comp->ngeoms; i++ )
+       {
+               int type = TYPE_GETTYPE(comp->geoms[i]->type);
+               if( i > 0 )
+                       stringbuffer_append(sb, ",");
+               /* Linestring subgeoms don't get type identifiers */
+               if( type == LINETYPE )
+               {
+                       lwline_to_wkt_sb((LWLINE*)comp->geoms[i], sb, precision, variant | WKT_NOTYPE );
+               }
+               /* But circstring subgeoms *do* get type identifiers */
+               else if( type == CIRCSTRINGTYPE )
+               {
+                       lwcircstring_to_wkt_sb((LWCIRCSTRING*)comp->geoms[i], sb, precision, variant );
+               }
+               else
+               {
+                       lwerror("lwcompound_to_wkt_size: Unknown type recieved %d", type);
+               }
+       }
+       stringbuffer_append(sb, ")");   
+}
+
+/** 
+* Curve polygons provide type information for their curved rings
+* but not their linestring rings.
+*   CURVEPOLYGON((0 0, 1 1, 0 1, 0 0), CURVESTRING(0 0, 1 1, 0 1, 0.5 1, 0 0))
+*/
+static void lwcurvepoly_to_wkt_sb(const LWCURVEPOLY *cpoly, stringbuffer_t *sb, int precision, uchar variant) 
+{
+       int i = 0;
+       
+       if( ! (variant & WKT_NOTYPE) )
+       {
+               stringbuffer_append(sb, "CURVEPOLYGON"); /* "CURVEPOLYGON" */
+               dimension_qualifiers_to_wkt_sb((LWGEOM*)cpoly, sb, variant);
+       }
+       if( cpoly->nrings < 1 )
+       {
+               stringbuffer_append(sb, " EMPTY"); /* "EMPTY" */
+               return;
+       }
+       stringbuffer_append(sb, "(");
+       for( i = 0; i < cpoly->nrings; i++ )
+       {
+               int type = TYPE_GETTYPE(cpoly->rings[i]->type);
+               if( i > 0 )
+                       stringbuffer_append(sb, ",");
+               switch(type)
+               {
+                       case LINETYPE:
+                               /* Linestring subgeoms don't get type identifiers */
+                               lwline_to_wkt_sb((LWLINE*)cpoly->rings[i], sb, precision, variant | WKT_NOTYPE );
+                               break;
+                       case CIRCSTRINGTYPE:
+                               /* But circstring subgeoms *do* get type identifiers */
+                               lwcircstring_to_wkt_sb((LWCIRCSTRING*)cpoly->rings[i], sb, precision, variant );
+                               break;
+                       case COMPOUNDTYPE:
+                               /* And compoundcurve subgeoms *do* get type identifiers */
+                               lwcompound_to_wkt_sb((LWCOMPOUND*)cpoly->rings[i], sb, precision, variant );
+                               break;
+                       default:
+                               lwerror("lwcurvepoly_to_wkt_size: Unknown type recieved %d", type);
+               }
+       }
+       stringbuffer_append(sb, ")");
+}
+
+
+/** 
+* Multi-curves provide type information for their curved sub-geometries
+* but not their linear sub-geometries.
+*   MULTICURVE((0 0, 1 1), CURVESTRING(0 0, 1 1, 2 2))
+*/
+static void lwmcurve_to_wkt_sb(const LWMCURVE *mcurv, stringbuffer_t *sb, int precision, uchar variant) 
+{
+       int i = 0;
+
+       if( ! (variant & WKT_NOTYPE) )
+       {
+               stringbuffer_append(sb, "MULTICURVE"); /* "MULTICURVE" */
+               dimension_qualifiers_to_wkt_sb((LWGEOM*)mcurv, sb, variant);
+       }
+       if( mcurv->ngeoms < 1 )
+       {
+               stringbuffer_append(sb, " EMPTY"); /* "EMPTY" */
+               return;
+       }
+       stringbuffer_append(sb, "(");
+       for( i = 0; i < mcurv->ngeoms; i++ )
+       {
+               int type = TYPE_GETTYPE(mcurv->geoms[i]->type);
+               if( i > 0 )
+                       stringbuffer_append(sb, ",");
+               switch(type)
+               {
+                       case LINETYPE:
+                               /* Linestring subgeoms don't get type identifiers */
+                               lwline_to_wkt_sb((LWLINE*)mcurv->geoms[i], sb, precision, variant | WKT_NOTYPE );
+                               break;
+                       case CIRCSTRINGTYPE:
+                               /* But circstring subgeoms *do* get type identifiers */
+                               lwcircstring_to_wkt_sb((LWCIRCSTRING*)mcurv->geoms[i], sb, precision, variant );
+                               break;
+                       case COMPOUNDTYPE:
+                               /* And compoundcurve subgeoms *do* get type identifiers */
+                               lwcompound_to_wkt_sb((LWCOMPOUND*)mcurv->geoms[i], sb, precision, variant );
+                               break;
+                       default:
+                               lwerror("lwmcurve_to_wkt_size: Unknown type recieved %d", type);
+               }
+       }       
+       stringbuffer_append(sb, ")");
+}
+
+
+/** 
+* Multi-surfaces provide type information for their curved sub-geometries
+* but not their linear sub-geometries.
+*   MULTISURFACE(((0 0, 1 1, 1 0, 0 0)), CURVEPOLYGON(CURVESTRING(0 0, 1 1, 2 2, 0 1, 0 0)))
+*/
+static void lwmsurface_to_wkt_sb(const LWMSURFACE *msurf, stringbuffer_t *sb, int precision, uchar variant) 
+{
+       int i = 0;
+
+       if( ! (variant & WKT_NOTYPE) )
+       {
+               stringbuffer_append(sb, "MULTISURFACE"); /* "MULTISURFACE" */
+               dimension_qualifiers_to_wkt_sb((LWGEOM*)msurf, sb, variant);
+       }
+       if( msurf->ngeoms < 1 )
+       {
+               stringbuffer_append(sb, " EMPTY"); /* "EMPTY" */
+               return;
+       }
+       stringbuffer_append(sb, "(");
+       for( i = 0; i < msurf->ngeoms; i++ )
+       {
+               int type = TYPE_GETTYPE(msurf->geoms[i]->type);
+               if( i > 0 )
+                       stringbuffer_append(sb, ",");
+               switch(type)
+               {
+                       case POLYGONTYPE:
+                               /* Linestring subgeoms don't get type identifiers */
+                               lwpoly_to_wkt_sb((LWPOLY*)msurf->geoms[i], sb, precision, variant | WKT_NOTYPE );
+                               break;
+                       case CURVEPOLYTYPE:
+                               /* But circstring subgeoms *do* get type identifiers */
+                               lwcurvepoly_to_wkt_sb((LWCURVEPOLY*)msurf->geoms[i], sb, precision, variant );
+                               break;
+                       default:
+                               lwerror("lwmsurface_to_wkt_size: Unknown type recieved %d", type);
+               }
+       }       
+       stringbuffer_append(sb, ")");
+}
+
+/** 
+* Geometry collections provide type information for all their curved sub-geometries
+* but not their linear sub-geometries.
+*   GEOMETRYCOLLECTION(POLYGON((0 0, 1 1, 1 0, 0 0)), CURVEPOLYGON(CURVESTRING(0 0, 1 1, 2 2, 0 1, 0 0)))
+*/
+static void lwcollection_to_wkt_sb(const LWCOLLECTION *collection, stringbuffer_t *sb, int precision, uchar variant) 
+{
+       int i = 0;
+       
+       if( ! (variant & WKT_NOTYPE) )
+       {
+               stringbuffer_append(sb, "GEOMETRYCOLLECTION"); /* "GEOMETRYCOLLECTION" */
+               dimension_qualifiers_to_wkt_sb((LWGEOM*)collection, sb, variant);
+       }
+       if( collection->ngeoms < 1 )
+       {
+               stringbuffer_append(sb, " EMPTY"); /* "EMPTY" */
+               return;
+       }
+       stringbuffer_append(sb, "("); 
+       for( i = 0; i < collection->ngeoms; i++ )
+       {
+               if( i > 0 )
+                       stringbuffer_append(sb, ","); 
+               lwgeom_to_wkt_sb((LWGEOM*)collection->geoms[i], sb, precision, variant );
+       }
+       stringbuffer_append(sb, ")"); 
+}
+
+/**
+* Generic GEOMETRY
+*/
+static void lwgeom_to_wkt_sb(const LWGEOM *geom, stringbuffer_t *sb, int precision, uchar variant)
+{
+       switch(TYPE_GETTYPE(geom->type))
+       {
+               case POINTTYPE:
+                       lwpoint_to_wkt_sb((LWPOINT*)geom, sb, precision, variant);
+                       break;
+               case LINETYPE:
+                       lwline_to_wkt_sb((LWLINE*)geom, sb, precision, variant);
+                       break;
+               case POLYGONTYPE:
+                       lwpoly_to_wkt_sb((LWPOLY*)geom, sb, precision, variant);
+                       break;
+               case MULTIPOINTTYPE:
+                       lwmpoint_to_wkt_sb((LWMPOINT*)geom, sb, precision, variant);
+                       break;
+               case MULTILINETYPE:
+                       lwmline_to_wkt_sb((LWMLINE*)geom, sb, precision, variant);
+                       break;
+               case MULTIPOLYGONTYPE:
+                       lwmpoly_to_wkt_sb((LWMPOLY*)geom, sb, precision, variant);
+                       break;
+               case COLLECTIONTYPE:
+                       lwcollection_to_wkt_sb((LWCOLLECTION*)geom, sb, precision, variant);
+                       break;
+               case CIRCSTRINGTYPE:
+                       lwcircstring_to_wkt_sb((LWCIRCSTRING*)geom, sb, precision, variant);
+                       break;
+               case COMPOUNDTYPE:
+                       lwcompound_to_wkt_sb((LWCOMPOUND*)geom, sb, precision, variant);
+                       break;
+               case CURVEPOLYTYPE:
+                       lwcurvepoly_to_wkt_sb((LWCURVEPOLY*)geom, sb, precision, variant);
+                       break;
+               case MULTICURVETYPE:
+                       lwmcurve_to_wkt_sb((LWMCURVE*)geom, sb, precision, variant);
+                       break;
+               case MULTISURFACETYPE:
+                       lwmsurface_to_wkt_sb((LWMSURFACE*)geom, sb, precision, variant);
+                       break;
+               default:
+                       lwerror("lwgeom_to_wkt_sb: Type %d unsupported.", TYPE_GETTYPE(geom->type));
+       }
+}
+
+/**
+* Public WKT emitter function
+*/
+char *lwgeom_to_wkt(const LWGEOM *geom, int precision, uchar variant)
+{
+       stringbuffer_t *sb;
+       char *str = NULL;
+       if( geom == NULL )
+               return NULL;
+       sb = stringbuffer_create();
+       lwgeom_to_wkt_sb(geom, sb, precision, variant);
+       if( stringbuffer_getstring(sb) == NULL )
+       {
+               lwerror("Uh oh");
+               return NULL;
+       }
+       str = strdup(stringbuffer_getstring(sb));
+       stringbuffer_destroy(sb);
+       return str;
+}
+
index 25c3a9931a16a656083b9def7013b8c3679e5161..f0cd854782e941a5067bd48ef480aa6855657ecf 100644 (file)
@@ -30,7 +30,7 @@
  * Therefore the raw string routines will always assume +1 when given length.
  */
 
-#include "stringbuffer.h"
+#include "liblwgeom.h"
 
 /* * * * * * * * * * * * *
  * raw string routines.  *
@@ -40,7 +40,7 @@
 static char *allocate_string(int len)
 {
        char *s;
-       s = malloc(sizeof(char) * len + 1); /* add for null termination. */
+       s = lwalloc(sizeof(char) * len + 1); /* add for null termination. */
        s[len] = 0;
        return s;
 }
@@ -49,7 +49,7 @@ static char *allocate_string(int len)
 static char *extend_string(char *str, int cur_len, int ex_len)
 {
 
-       str = realloc(str, (cur_len * sizeof(char)) + (ex_len * sizeof(char)) + (1 * sizeof(char)));
+       str = lwrealloc(str, (cur_len * sizeof(char)) + (ex_len * sizeof(char)) + (1 * sizeof(char)));
        str[cur_len] = 0; /* make sure it's null terminated. */
 
        return str;
@@ -124,7 +124,7 @@ stringbuffer_t *stringbuffer_create(void)
 {
        stringbuffer_t *sb;
 
-       sb = malloc(sizeof(stringbuffer_t));
+       sb = lwalloc(sizeof(stringbuffer_t));
        sb->len = 0;
        sb->capacity = 0;
        sb->buf = allocate_string(0);
@@ -135,8 +135,8 @@ stringbuffer_t *stringbuffer_create(void)
 /* destroy the stringbuffer */
 void stringbuffer_destroy(stringbuffer_t *sb)
 {
-       free(sb->buf);
-       free(sb);
+       lwfree(sb->buf);
+       lwfree(sb);
 }
 
 /* clear a string. */
@@ -228,7 +228,7 @@ stringbuffer_t *stringbuffer_trim_whitespace(stringbuffer_t *sb)
                newbuf[new_len] = 0;
 
                /* free up old. */
-               free(sb->buf);
+               lwfree(sb->buf);
 
                /* set new. */
                sb->buf = newbuf;
@@ -409,7 +409,7 @@ void stringbuffer_align(stringbuffer_t *sb, int begin, int end)
 
                stringbuffer_append(aligned_string, word_string);
                stringbuffer_append(aligned_string, "\n");
-               free(word_string);
+               lwfree(word_string);
 
        }
 
@@ -430,13 +430,13 @@ void stringbuffer_avprintf_align(stringbuffer_t *sb, int start, int end, const c
 
        /* our first malloc is bogus. */
        len = 1;
-       str = malloc(sizeof(char) * len);
+       str = lwalloc(sizeof(char) * len);
        total = vsnprintf(str, len, fmt, ap);
 
        /* total is the real length needed. */
-       free(str);
+       lwfree(str);
        len = total + 1;
-       str = malloc(sizeof(char) * len);
+       str = lwalloc(sizeof(char) * len);
        vsnprintf(str, len, fmt, ap);
 
        /* now align if we want to align. */
@@ -457,7 +457,7 @@ void stringbuffer_avprintf_align(stringbuffer_t *sb, int start, int end, const c
                stringbuffer_append(sb, str);
        }
 
-       free(str);
+       lwfree(str);
 
        return;
 }
@@ -566,3 +566,23 @@ int stringbuffer_getlen(stringbuffer_t *sb)
 {
        return sb->len;
 }
+
+void stringbuffer_vasbappend(stringbuffer_t *sb, char *fmt, ... )
+{
+       va_list ap;
+       char *msg;
+
+       va_start(ap, fmt);
+
+       if (!lw_vasprintf (&msg, fmt, ap))
+       {
+               va_end (ap);
+               return;
+       }
+
+       /* Append to the stringbuffer */
+       stringbuffer_append(sb, msg);
+       lwfree(msg);
+
+       va_end(ap);
+}
\ No newline at end of file
index 15d64088f11dd99b1c3a24ddca5855408bf0c159..20959e00561447a227ff6a526cd5a1258c88ea5f 100644 (file)
@@ -66,3 +66,4 @@ extern void stringbuffer_avprintf(stringbuffer_t *sb, const char *fmt, va_list a
 extern int stringbuffer_marknewlines(stringbuffer_t *sb);
 extern const char *stringbuffer_getnextline(stringbuffer_t *sb, const char *cptr);
 extern int stringbuffer_getlen(stringbuffer_t *sb);
+extern void stringbuffer_vasbappend(stringbuffer_t *sb, char *fmt, ... );