--- postgis-svn/lwgeom/liblwgeom.h	2007-09-20 16:22:47.000000000 +0200
+++ postgis-patch/lwgeom/liblwgeom.h	2007-09-18 15:50:59.000000000 +0200
@@ -293,6 +293,26 @@
 	LWPOLY **geoms;
 } LWMPOLY; 
 
+/* TINTYPE */
+typedef struct
+{
+        uchar type;
+        BOX2DFLOAT4 *bbox;
+        uint32 SRID;
+        int  ngeoms;
+        LWPOLY **geoms;
+} LWTIN;
+
+/* POLYHEDRALSURFACETYPE */
+typedef struct
+{
+        uchar type;
+        BOX2DFLOAT4 *bbox;
+        uint32 SRID;
+        int  ngeoms;
+        LWPOLY **geoms;
+} LWPOLYHEDRALSURFACE;
+
 /* COLLECTIONTYPE */
 typedef struct
 {   
@@ -305,6 +325,8 @@
 
 /* Casts LWGEOM->LW* (return NULL if cast is illegal) */
 extern LWMPOLY *lwgeom_as_lwmpoly(LWGEOM *lwgeom);
+extern LWTIN *lwgeom_as_lwtin(LWGEOM *lwgeom);
+extern LWPOLYHEDRALSURFACE *lwgeom_as_lwpolyhedralsurface(LWGEOM *lwgeom);
 extern LWMLINE *lwgeom_as_lwmline(LWGEOM *lwgeom);
 extern LWMPOINT *lwgeom_as_lwmpoint(LWGEOM *lwgeom);
 extern LWCOLLECTION *lwgeom_as_lwcollection(LWGEOM *lwgeom);
@@ -314,6 +336,8 @@
 
 /* Casts LW*->LWGEOM (always cast) */
 extern LWGEOM *lwmpoly_as_lwgeom(LWMPOLY *obj);
+extern LWGEOM *lwtin_as_lwgeom(LWTIN *obj);
+extern LWGEOM *lwpolyhedralsurface_as_lwgeom(LWPOLYHEDRALSURFACE *obj);
 extern LWGEOM *lwmline_as_lwgeom(LWMLINE *obj);
 extern LWGEOM *lwmpoint_as_lwgeom(LWMPOINT *obj);
 extern LWGEOM *lwcollection_as_lwgeom(LWCOLLECTION *obj);
@@ -446,6 +470,8 @@
 #define	MULTILINETYPE	5
 #define	MULTIPOLYGONTYPE	6
 #define	COLLECTIONTYPE	7
+#define TINTYPE		10
+#define POLYHEDRALSURFACETYPE	11
 
 #define WKBZOFFSET 0x80000000
 #define WKBMOFFSET 0x40000000
@@ -688,6 +714,8 @@
 LWMPOINT *lwmpoint_deserialize(uchar *serializedform);
 LWMLINE *lwmline_deserialize(uchar *serializedform);
 LWMPOLY *lwmpoly_deserialize(uchar *serializedform);
+LWTIN *lwtin_deserialize(uchar *serializedform);
+LWPOLYHEDRALSURFACE *lwpolyhedralsurface_deserialize(uchar *serializedform);
 LWCOLLECTION *lwcollection_deserialize(uchar *serializedform);
 LWGEOM *lwcollection_getsubgeom(LWCOLLECTION *, int);
 
@@ -992,6 +1020,8 @@
 LWGEOM *lwline_add(const LWLINE *to, uint32 where, const LWGEOM *what);
 LWGEOM *lwpoly_add(const LWPOLY *to, uint32 where, const LWGEOM *what);
 LWGEOM *lwmpoly_add(const LWMPOLY *to, uint32 where, const LWGEOM *what);
+LWGEOM *lwtin_add(const LWTIN *to, uint32 where, const LWGEOM *what);
+LWGEOM *lwpolyhedralsurface_add(const LWPOLYHEDRALSURFACE *to, uint32 where, const LWGEOM *what);
 LWGEOM *lwmline_add(const LWMLINE *to, uint32 where, const LWGEOM *what);
 LWGEOM *lwmpoint_add(const LWMPOINT *to, uint32 where, const LWGEOM *what);
 LWGEOM *lwcollection_add(const LWCOLLECTION *to, uint32 where, const LWGEOM *what);
--- postgis-svn/lwgeom/lwgeom.c	2007-09-20 16:22:47.000000000 +0200
+++ postgis-patch/lwgeom/lwgeom.c	2007-09-18 15:13:41.000000000 +0200
@@ -46,6 +46,10 @@
 			return (LWGEOM *)lwmline_deserialize(srl);
 		case MULTIPOLYGONTYPE:
 			return (LWGEOM *)lwmpoly_deserialize(srl);
+		case TINTYPE:
+			return (LWGEOM *)lwtin_deserialize(srl);
+		case POLYHEDRALSURFACETYPE:
+			return (LWGEOM *)lwpolyhedralsurface_deserialize(srl);
 		case COLLECTIONTYPE:
 			return (LWGEOM *)lwcollection_deserialize(srl);
                 case COMPOUNDTYPE:
@@ -92,6 +96,8 @@
 		case MULTILINETYPE:
                 case MULTICURVETYPE:
 		case MULTIPOLYGONTYPE:
+		case TINTYPE:
+		case POLYHEDRALSURFACETYPE:
                 case MULTISURFACETYPE:
 		case COLLECTIONTYPE:
 			return lwcollection_serialize_size((LWCOLLECTION *)lwgeom);
@@ -134,6 +140,8 @@
 		case MULTILINETYPE:
                 case MULTICURVETYPE:
 		case MULTIPOLYGONTYPE:
+		case TINTYPE:
+		case POLYHEDRALSURFACETYPE:
                 case MULTISURFACETYPE:
 		case COLLECTIONTYPE:
 			lwcollection_serialize_buf((LWCOLLECTION *)lwgeom, buf,
@@ -184,6 +192,8 @@
 			return;
 
 		case MULTIPOLYGONTYPE:
+		case TINTYPE:
+		case POLYHEDRALSURFACETYPE:
 		case COLLECTIONTYPE:
 			coll = (LWCOLLECTION *)lwgeom;
 			for (i=0; i<coll->ngeoms; i++)
@@ -209,6 +219,8 @@
 			return;
 		case MULTILINETYPE:
 		case MULTIPOLYGONTYPE:
+		case TINTYPE:
+		case POLYHEDRALSURFACETYPE:
 		case COLLECTIONTYPE:
 			col = (LWCOLLECTION *)lwgeom;
 			for (i=0; i<col->ngeoms; i++)
@@ -239,6 +251,8 @@
 		case MULTILINETYPE:
                 case MULTICURVETYPE:
 		case MULTIPOLYGONTYPE:
+		case TINTYPE:
+		case POLYHEDRALSURFACETYPE:
                 case MULTISURFACETYPE:
 		case COLLECTIONTYPE:
 			return lwcollection_compute_box2d_p((LWCOLLECTION *)lwgeom, buf);
@@ -325,7 +339,26 @@
 	else return NULL;
 }
 
+LWTIN *
+lwgeom_as_lwtin(LWGEOM *lwgeom)
+{
+        if ( TYPE_GETTYPE(lwgeom->type) == TINTYPE )
+                return (LWTIN *)lwgeom;
+        else return NULL;
+}
+
+LWPOLYHEDRALSURFACE *
+lwgeom_as_lwpolyhedralsurface(LWGEOM *lwgeom)
+{
+        if ( TYPE_GETTYPE(lwgeom->type) == POLYHEDRALSURFACETYPE )
+                return (LWPOLYHEDRALSURFACE *)lwgeom;
+        else return NULL;
+}
+
+
 LWGEOM *lwmpoly_as_lwgeom(LWMPOLY *obj) { return (LWGEOM *)obj; }
+LWGEOM *lwtin_as_lwgeom(LWTIN *obj) { return (LWGEOM *)obj; }
+LWGEOM *lwpolyhedralsurface_as_lwgeom(LWPOLYHEDRALSURFACE *obj) { return (LWGEOM *)obj; }
 LWGEOM *lwmline_as_lwgeom(LWMLINE *obj) { return (LWGEOM *)obj; }
 LWGEOM *lwmpoint_as_lwgeom(LWMPOINT *obj) { return (LWGEOM *)obj; }
 LWGEOM *lwcollection_as_lwgeom(LWCOLLECTION *obj) { return (LWGEOM *)obj; }
@@ -395,6 +428,8 @@
 		case MULTILINETYPE:
                 case MULTICURVETYPE:
 		case MULTIPOLYGONTYPE:
+		case TINTYPE:
+		case POLYHEDRALSURFACETYPE:
                 case MULTISURFACETYPE:
 		case COLLECTIONTYPE:
 			return (LWGEOM *)lwcollection_clone((LWCOLLECTION *)lwgeom);
@@ -462,6 +497,14 @@
 			return (LWGEOM *)lwmpoly_add((const LWMPOLY *)to,
 				where, what);
 
+		 case TINTYPE:
+                        return (LWGEOM *)lwtin_add((const LWTIN *)to,
+                                where, what);
+
+		 case POLYHEDRALSURFACETYPE:
+                        return (LWGEOM *)lwpolyhedralsurface_add((const LWPOLYHEDRALSURFACE *)to,
+                                where, what);
+
                 case MULTISURFACETYPE:
                         return (LWGEOM *)lwmsurface_add((const LWMSURFACE *)to,
                                 where, what);
@@ -618,6 +661,8 @@
 		case MULTIPOINTTYPE:
 		case MULTILINETYPE:
 		case MULTIPOLYGONTYPE:
+		case TINTYPE:
+		case POLYHEDRALSURFACETYPE:
 		case COLLECTIONTYPE:
 			return lwcollection_same((LWCOLLECTION *)lwgeom1,
 				(LWCOLLECTION *)lwgeom2);
@@ -678,6 +723,8 @@
 				dist);
 		case MULTILINETYPE:
 		case MULTIPOLYGONTYPE:
+		case TINTYPE:
+		case POLYHEDRALSURFACETYPE:
 		case COLLECTIONTYPE:
 			return (LWGEOM *)lwcollection_segmentize2d(
 				(LWCOLLECTION *)lwgeom, dist);
@@ -713,6 +760,8 @@
 			return;
 		case MULTILINETYPE:
 		case MULTIPOLYGONTYPE:
+		case TINTYPE:
+		case POLYHEDRALSURFACETYPE:
 		case COLLECTIONTYPE:
 			coll = (LWCOLLECTION *)lwgeom;
 			for (i=0; i<coll->ngeoms; i++)
--- postgis-svn/lwgeom/lwgparse.c	2007-09-20 16:22:47.000000000 +0200
+++ postgis-patch/lwgeom/lwgparse.c	2007-09-20 16:22:27.000000000 +0200
@@ -140,6 +140,8 @@
 void alloc_multilinestring(void);
 void alloc_multicurve(void);
 void alloc_multipolygon(void);
+void alloc_tin(void);
+void alloc_polyhedralsurface(void);
 void alloc_multisurface(void);
 void alloc_geomertycollection(void);
 void alloc_counter(void);
@@ -562,10 +564,7 @@
         lwnotice("alloc_point");
 #endif
 
-	if( the_geom.lwgi)
-		alloc_stack_tuple(POINTTYPEI,write_type,1);
-	else
-		alloc_stack_tuple(POINTTYPE,write_type,1);
+	alloc_stack_tuple(POINTTYPE,write_type,1);
 
 	minpoints=1;
 	checkclosed=0;
@@ -580,10 +579,7 @@
         lwnotice("alloc_linestring");
 #endif
 
-	if( the_geom.lwgi)
-		alloc_stack_tuple(LINETYPEI,write_type,1);
-	else
-		alloc_stack_tuple(LINETYPE,write_type,1);
+	alloc_stack_tuple(LINETYPE,write_type,1);
 
 	minpoints=2;
 	checkclosed=0;
@@ -634,15 +630,11 @@
         lwnotice("alloc_polygon");
 #endif
 
-	if( the_geom.lwgi)
-		alloc_stack_tuple(POLYGONTYPEI, write_type,1);
-	else
-		alloc_stack_tuple(POLYGONTYPE, write_type,1);
+	alloc_stack_tuple(POLYGONTYPE, write_type,1);
 
 	minpoints=3;
 	checkclosed=1;
         isodd=-1;
-
 }
 
 void
@@ -715,6 +707,29 @@
 }
 
 void
+alloc_tin(void)
+{
+
+#ifdef PGIS_DEBUG_CALLS
+        lwnotice("alloc_tin");
+#endif
+
+        alloc_stack_tuple(TINTYPE,write_type,1);
+}
+
+void
+alloc_polyhedralsurface(void)
+{
+
+#ifdef PGIS_DEBUG_CALLS
+        lwnotice("alloc_polyhedralsurface");
+#endif
+
+        alloc_stack_tuple(POLYHEDRALSURFACETYPE,write_type,1);
+}
+
+
+void
 alloc_multisurface(void)
 {
 
@@ -1021,22 +1036,8 @@
 
 	type &=0x0f;
 
-	if ( the_geom.lwgi  ){
-
-		if ( type<= POLYGONTYPE )
-			alloc_stack_tuple(type +9,write_type,1);
-		else
-			alloc_stack_tuple(type,write_type,1);
-	}
-	else{
-		/* If we are writing lwg and are reading wbki */
-		int4 towrite=type;
-		if (towrite >= POINTTYPEI && towrite <= POLYGONTYPEI){
-			towrite-=9;
-		}
-		alloc_stack_tuple(towrite,write_type,1);
-	}
-
+	alloc_stack_tuple(type,write_type,1);
+	
 	switch(type ){
 		case	POINTTYPE:
 			read_wkb_point(b);
@@ -1066,26 +1067,13 @@
 		case	MULTILINETYPE:
                 case    MULTICURVETYPE:
 		case	MULTIPOLYGONTYPE:
+		case    TINTYPE:
+                case    POLYHEDRALSURFACETYPE:
                 case    MULTISURFACETYPE:
 		case	COLLECTIONTYPE:
 			read_collection(b,parse_wkb);
 			break;
 
-		case	POINTTYPEI:
-			the_geom.from_lwgi=1;
-			read_wkb_point(b);
-			break;
-
-		case	LINETYPEI:
-			the_geom.from_lwgi=1;
-			read_collection(b,read_wkb_point);
-			break;
-
-		case	POLYGONTYPEI:
-			the_geom.from_lwgi=1;
-			read_collection(b,read_collection2);
-			break;
-
 		default:
 			error("Invalid type in wbk");
 	}
--- postgis-svn/lwgeom/lwgeom_geos_c.c	2007-09-20 16:22:47.000000000 +0200
+++ postgis-patch/lwgeom/lwgeom_geos_c.c	2007-09-18 15:13:41.000000000 +0200
@@ -2935,6 +2935,8 @@
 		case GEOS_MULTIPOINT:
 		case GEOS_MULTILINESTRING:
 		case GEOS_MULTIPOLYGON:
+		case GEOS_TIN:
+		case GEOS_POLYHEDRALSURFACE:
 		case GEOS_GEOMETRYCOLLECTION:
 #ifdef PGIS_DEBUG_GEOS2POSTGIS
 	lwnotice("lwgeom_from_geometry: it's a Collection or Multi");
@@ -3144,6 +3146,8 @@
 		case MULTIPOINTTYPE:
 		case MULTILINETYPE:
 		case MULTIPOLYGONTYPE:
+		case TINTYPE:
+                case POLYHEDRALSURFACETYPE:
 		case COLLECTIONTYPE:
 			if ( type == MULTIPOINTTYPE )
 				geostype = GEOS_MULTIPOINT;
@@ -3151,6 +3155,10 @@
 				geostype = GEOS_MULTILINESTRING;
 			else if ( type == MULTIPOLYGONTYPE )
 				geostype = GEOS_MULTIPOLYGON;
+			else if ( type == TINTYPE )
+				geostype = GEOS_TIN;
+			else if ( type == POLYHEDRALSURFACETYPE )
+                                geostype = GEOS_POLYHEDRALSURFACE;
 			else
 				geostype = GEOS_GEOMETRYCOLLECTION;
 
--- postgis-svn/lwgeom/lwgeom_jts_wrapper.cpp	2007-09-20 16:22:47.000000000 +0200
+++ postgis-patch/lwgeom/lwgeom_jts_wrapper.cpp	2007-09-18 15:13:41.000000000 +0200
@@ -86,6 +86,8 @@
 #define	MULTILINETYPE	5
 #define	MULTIPOLYGONTYPE	6
 #define	COLLECTIONTYPE	7
+#define TINTYPE  10
+#define POLYHEDRALSURFACETYPE  11
 
 //###########################################################
 
@@ -924,6 +926,8 @@
 	if ( ! strcmp(type, "MultiLineString") ) return MULTILINETYPE;
 	if ( ! strcmp(type, "MultiPoint") ) return MULTIPOINTTYPE;
 	if ( ! strcmp(type, "MultiPolygon") ) return MULTIPOLYGONTYPE;
+	if ( ! strcmp(type, "Tin") ) return TINTYPE;
+        if ( ! strcmp(type, "PolyhedralSurface") ) return POLYHEDRALSURFACETYPE;
 	if ( ! strcmp(type, "GeometryCollection") ) return COLLECTIONTYPE;
 	else
 	{
@@ -1192,6 +1196,12 @@
 			case MULTIPOLYGONTYPE:
 				g = jtsGeomFactory->createMultiPolygon((JArray<Polygon *>*)subGeoms);
 				break;
+			case TINTYPE:
+                                g = jtsGeomFactory->createTin((JArray<Polygon *>*)subGeoms);
+                                break;
+                        case POLYHEDRALSURFACETYPE:
+                                g = jtsGeomFactory->createPolyhedralSurface((JArray<Polygon *>*)subGeoms);
+                                break;
 			default:
 				NOTICE_MESSAGE("Unsupported type request for PostGIS2JTS_collection");
 				g = NULL;
--- postgis-svn/lwgeom/wktparse.h	2007-09-20 16:22:47.000000000 +0200
+++ postgis-patch/lwgeom/wktparse.h	2007-09-18 15:35:43.000000000 +0200
@@ -39,14 +39,10 @@
 #define	MULTILINETYPE	5
 #define	MULTIPOLYGONTYPE	6
 #define	COLLECTIONTYPE	7
-
-/* Extended lwgeom integer types */
-#define POINTTYPEI    10
-#define LINETYPEI     11
-#define POLYGONTYPEI  12
-
 #define CURVETYPE       8
 #define COMPOUNDTYPE    9
+#define TINTYPE                 10
+#define POLYHEDRALSURFACETYPE   11
 #define CURVEPOLYTYPE   13
 #define MULTICURVETYPE          14
 #define MULTISURFACETYPE        15
@@ -80,6 +76,8 @@
 void alloc_multilinestring(void);
 void alloc_multicurve(void);
 void alloc_multipolygon(void);
+void alloc_tin(void);
+void alloc_polyhedralsurface(void);
 void alloc_multisurface(void);
 void alloc_geomertycollection(void);
 void alloc_empty();
--- postgis-svn/lwgeom/wktparse.y	2007-09-20 16:22:47.000000000 +0200
+++ postgis-patch/lwgeom/wktparse.y	2007-09-19 09:32:15.000000000 +0200
@@ -22,8 +22,8 @@
 	const char* wkb;
 }
 
-%token POINT LINESTRING POLYGON MULTIPOINT MULTILINESTRING MULTIPOLYGON GEOMETRYCOLLECTION CIRCULARSTRING COMPOUNDCURVE CURVEPOLYGON MULTICURVE MULTISURFACE
-%token POINTM LINESTRINGM POLYGONM MULTIPOINTM MULTILINESTRINGM MULTIPOLYGONM GEOMETRYCOLLECTIONM CIRCULARSTRINGM COMPOUNDCURVEM CURVEPOLYGONM  MULTICURVEM MULTISURFACEM
+%token POINT LINESTRING POLYGON MULTIPOINT MULTILINESTRING MULTIPOLYGON GEOMETRYCOLLECTION CIRCULARSTRING COMPOUNDCURVE CURVEPOLYGON MULTICURVE MULTISURFACE TIN POLYHEDRALSURFACE
+%token POINTM LINESTRINGM POLYGONM MULTIPOINTM MULTILINESTRINGM MULTIPOLYGONM GEOMETRYCOLLECTIONM CIRCULARSTRINGM COMPOUNDCURVEM CURVEPOLYGONM  MULTICURVEM MULTISURFACEM TINM POLYHEDRALSURFACEM
 %token SRID      
 %token EMPTY
 %token <value> VALUE
@@ -60,6 +60,10 @@
 	|
 	geom_multipolygon
 	|
+	geom_tin
+	|
+	geom_polyhedralsurface
+	|
         geom_multisurface
         |
 	geom_geometrycollection
@@ -145,6 +149,11 @@
 	|
 	linestring_int COMMA a_point;
 
+linestring_t :
+	{alloc_counter();}
+	LPAREN a_point COMMA a_point COMMA a_point COMMA a_point RPAREN 
+	{popc();}
+
 /* CIRCULARSTRING */
 
 geom_circularstring :
@@ -273,6 +282,17 @@
 	|
 	polygon_int COMMA linestring_1
 
+/* TRIANGLE */
+
+nonempty_triangle :
+        { alloc_polygon(); } triangle_1  { pop(); }
+
+triangle_1 :
+        { alloc_counter(); } LPAREN triangle_int RPAREN { pop();}
+
+triangle_int :
+        linestring_t
+        
 /* CURVEPOLYGON */
 
 geom_curvepolygon :
@@ -313,6 +333,48 @@
 	|
 	multipolygon_int COMMA nonempty_polygon
 
+/* TIN */
+
+geom_tin :
+        TIN { alloc_tin(); } tin { pop(); }
+        |
+        TINM { set_zm(0, 1); alloc_tin(); }
+        tin { pop();}
+
+tin :
+        empty
+        |
+        { alloc_counter(); } LPAREN tin_int RPAREN { pop(); }
+
+tin_int :
+        nonempty_triangle
+        |
+        tin_int COMMA nonempty_triangle
+
+/* POLYHEDRALSURFACE */
+
+geom_polyhedralsurface :
+        POLYHEDRALSURFACE { alloc_polyhedralsurface(); } polyhedralsurface { pop(); }
+        |
+        POLYHEDRALSURFACEM { set_zm(0, 1); alloc_polyhedralsurface(); }
+                polyhedralsurface { pop();}
+
+polyhedralsurface :
+        empty
+        |
+        { alloc_counter(); } LPAREN polyhedralsurface_int RPAREN { pop(); }
+
+polyhedralsurface_int :
+        non_empty_polygon_one_ring
+        |
+        polyhedralsurface_int COMMA non_empty_polygon_one_ring
+
+non_empty_polygon_one_ring :
+        { alloc_polygon(); } polygon_one_ring_1  { pop(); }
+
+polygon_one_ring_1 :
+        { alloc_counter(); } LPAREN linestring_1 RPAREN { pop();}
+
 /* MULTISURFACE */
 
 geom_multisurface :
--- postgis-svn/lwgeom/wktparse.lex	2007-09-20 16:22:47.000000000 +0200
+++ postgis-patch/lwgeom/wktparse.lex	2007-09-18 15:54:52.000000000 +0200
@@ -52,6 +52,10 @@
 <*>MULTICURVEM { return MULTICURVEM; }
 <*>MULTIPOLYGON { return MULTIPOLYGON; }
 <*>MULTIPOLYGONM { return MULTIPOLYGONM; }
+<*>TIN { return TIN; }
+<*>TINM { return TINM; }
+<*>POLYHEDRALSURFACE { return POLYHEDRALSURFACE; }
+<*>POLYHEDRALSURFACEM { return POLYHEDRALSURFACEM; }
 <*>MULTISURFACE { return MULTISURFACE; }
 <*>MULTISURFACEM { return MULTISURFACEM; }
 <*>GEOMETRYCOLLECTION { return GEOMETRYCOLLECTION; }
--- postgis-svn/lwgeom/lwtin.c	1970-01-01 01:00:00.000000000 +0100
+++ postgis-patch/lwgeom/lwtin.c	2007-09-19 14:15:14.000000000 +0200
@@ -0,0 +1,122 @@
+/**********************************************************************
+ * $Id:$
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ * http://postgis.refractions.net
+ * Copyright 2001-2006 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.
+ * 
+ **********************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "liblwgeom.h"
+
+/*#define PGIS_DEBUG_CALLS 1 */
+
+LWTIN *
+lwtin_deserialize(uchar *srl)
+{
+	LWTIN *result;
+	LWGEOM_INSPECTED *insp;
+	int type = lwgeom_getType(srl[0]);
+	int i;
+
+#ifdef PGIS_DEBUG_CALLS
+	lwnotice("lwtin_deserialize called");
+#endif
+
+	if ( type != TINTYPE ) 
+	{
+		lwerror("lwtin_deserialize called on NON tin: %d",
+			type);
+		return NULL;
+	}
+
+	insp = lwgeom_inspect(srl);
+
+	result = lwalloc(sizeof(LWTIN));
+	result->type = insp->type;
+	result->SRID = insp->SRID;
+	result->ngeoms = insp->ngeometries;
+	result->geoms = lwalloc(sizeof(LWPOLY *)*insp->ngeometries);
+
+	if (lwgeom_hasBBOX(srl[0]))
+	{
+		result->bbox = lwalloc(sizeof(BOX2DFLOAT4));
+		memcpy(result->bbox, srl+1, sizeof(BOX2DFLOAT4));
+	}
+	else result->bbox = NULL;
+
+	for (i=0; i<insp->ngeometries; i++)
+	{
+		result->geoms[i] = lwpoly_deserialize(insp->sub_geoms[i]);
+		if ( TYPE_NDIMS(result->geoms[i]->type) != TYPE_NDIMS(result->type) )
+		{
+			lwerror("Mixed dimensions (multipoly:%d, poly%d:%d)",
+				TYPE_NDIMS(result->type), i,
+				TYPE_NDIMS(result->geoms[i]->type)
+			);
+			return NULL;
+		}
+	}
+
+	return result;
+}
+
+/*
+ * Add 'what' at position 'where'.
+ * where=0 == prepend
+ * where=-1 == append
+ * Returns a MULTIPOLY or a COLLECTION
+ */
+LWGEOM *
+lwtin_add(const LWTIN *to, uint32 where, const LWGEOM *what)
+{
+	LWCOLLECTION *col;
+	LWGEOM **geoms;
+	int newtype;
+	uint32 i;
+
+	if ( where == -1 ) where = to->ngeoms;
+	else if ( where < -1 || where > to->ngeoms )
+	{
+		lwerror("lwtin_add: add position out of range %d..%d",
+			-1, to->ngeoms);
+		return NULL;
+	}
+
+	/* dimensions compatibility are checked by caller */
+
+	/* Construct geoms array */
+	geoms = lwalloc(sizeof(LWGEOM *)*(to->ngeoms+1));
+	for (i=0; i<where; i++)
+	{
+		geoms[i] = lwgeom_clone((LWGEOM *)to->geoms[i]);
+	}
+	geoms[where] = lwgeom_clone(what);
+	for (i=where; i<to->ngeoms; i++)
+	{
+		geoms[i+1] = lwgeom_clone((LWGEOM *)to->geoms[i]);
+	}
+
+	
+	if ( TYPE_GETTYPE(what->type)==POLYGONTYPE){
+		if( lwgeom_as_lwpoly(what)->nrings==1 && 
+		lwgeom_as_lwpoly(what)->rings[0]->npoints==4) newtype = TINTYPE;
+	}
+	else if ( TYPE_GETTYPE(what->type) == POLYGONTYPE) newtype = MULTIPOLYGONTYPE;
+	else newtype = COLLECTIONTYPE;
+	
+	/*newtype = TINTYPE;	*/
+
+	col = lwcollection_construct(newtype,
+		to->SRID, NULL,
+		to->ngeoms+1, geoms);
+	
+	return (LWGEOM *)col;
+
+}
--- postgis-svn/lwgeom/lwpolyhedralsurf.c	1970-01-01 01:00:00.000000000 +0100
+++ postgis-patch/lwgeom/lwpolyhedralsurf.c	2007-09-19 14:15:07.000000000 +0200
@@ -0,0 +1,121 @@
+/**********************************************************************
+ * $Id:$
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ * http://postgis.refractions.net
+ * Copyright 2001-2006 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.
+ * 
+ **********************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "liblwgeom.h"
+
+/*#define PGIS_DEBUG_CALLS 1 */
+
+LWPOLYHEDRALSURFACE *
+lwpolyhedralsurface_deserialize(uchar *srl)
+{
+	LWPOLYHEDRALSURFACE *result;
+	LWGEOM_INSPECTED *insp;
+	int type = lwgeom_getType(srl[0]);
+	int i;
+
+#ifdef PGIS_DEBUG_CALLS
+	lwnotice("lwpolyhedralsurface_deserialize called");
+#endif
+
+	if ( type != POLYHEDRALSURFACETYPE ) 
+	{
+		lwerror("lwpolyhedralsurface_deserialize called on NON tin: %d",
+			type);
+		return NULL;
+	}
+
+	insp = lwgeom_inspect(srl);
+
+	result = lwalloc(sizeof(LWPOLYHEDRALSURFACE));
+	result->type = insp->type;
+	result->SRID = insp->SRID;
+	result->ngeoms = insp->ngeometries;
+	result->geoms = lwalloc(sizeof(LWPOLY *)*insp->ngeometries);
+
+	if (lwgeom_hasBBOX(srl[0]))
+	{
+		result->bbox = lwalloc(sizeof(BOX2DFLOAT4));
+		memcpy(result->bbox, srl+1, sizeof(BOX2DFLOAT4));
+	}
+	else result->bbox = NULL;
+
+	for (i=0; i<insp->ngeometries; i++)
+	{
+		result->geoms[i] = lwpoly_deserialize(insp->sub_geoms[i]);
+		if ( TYPE_NDIMS(result->geoms[i]->type) != TYPE_NDIMS(result->type) )
+		{
+			lwerror("Mixed dimensions (multipoly:%d, poly%d:%d)",
+				TYPE_NDIMS(result->type), i,
+				TYPE_NDIMS(result->geoms[i]->type)
+			);
+			return NULL;
+		}
+	}
+
+	return result;
+}
+
+/*
+ * Add 'what' at position 'where'.
+ * where=0 == prepend
+ * where=-1 == append
+ * Returns a MULTIPOLY or a COLLECTION
+ */
+LWGEOM *
+lwpolyhedralsurface_add(const LWPOLYHEDRALSURFACE *to, uint32 where, const LWGEOM *what)
+{
+	LWCOLLECTION *col;
+	LWGEOM **geoms;
+	int newtype;
+	uint32 i;
+
+	if ( where == -1 ) where = to->ngeoms;
+	else if ( where < -1 || where > to->ngeoms )
+	{
+		lwerror("lwmline_add: add position out of range %d..%d",
+			-1, to->ngeoms);
+		return NULL;
+	}
+
+	/* dimensions compatibility are checked by caller */
+
+	/* Construct geoms array */
+	geoms = lwalloc(sizeof(LWGEOM *)*(to->ngeoms+1));
+	for (i=0; i<where; i++)
+	{
+		geoms[i] = lwgeom_clone((LWGEOM *)to->geoms[i]);
+	}
+	geoms[where] = lwgeom_clone(what);
+	for (i=where; i<to->ngeoms; i++)
+	{
+		geoms[i+1] = lwgeom_clone((LWGEOM *)to->geoms[i]);
+	}
+
+	
+	if ( TYPE_GETTYPE(what->type)==POLYGONTYPE){
+                if( lwgeom_as_lwpoly(what)->nrings==1) newtype = POLYHEDRALSURFACETYPE;
+	}
+	else if ( TYPE_GETTYPE(what->type) == POLYGONTYPE ) newtype = MULTIPOLYGONTYPE;
+	else newtype = COLLECTIONTYPE;
+	
+	newtype = POLYHEDRALSURFACETYPE;	
+
+	col = lwcollection_construct(newtype,
+		to->SRID, NULL,
+		to->ngeoms+1, geoms);
+	
+	return (LWGEOM *)col;
+
+}
--- postgis-svn/lwgeom/lwgeom_x3d.c	1970-01-01 01:00:00.000000000 +0100
+++ postgis-patch/lwgeom/lwgeom_x3d.c	2007-09-20 16:09:25.000000000 +0200
@@ -0,0 +1,537 @@
+/**********************************************************************
+ * $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.
+ *
+ **********************************************************************
+ *
+ * X3D output routines.
+ *
+ **********************************************************************/
+
+
+#include "postgres.h"
+#include "executor/spi.h"
+
+#include "lwgeom_pg.h"
+#include "liblwgeom.h"
+
+Datum LWGEOM_asX3D(PG_FUNCTION_ARGS);
+char *geometry_to_x3d(uchar *srl, char *srs);
+
+static size_t asx3d_point_size(LWPOINT *point);
+static char *asx3d_point(LWPOINT *point);
+static size_t asx3d_line_size(LWLINE *line);
+static char *asx3d_line(LWLINE *line);
+static size_t asx3d_poly_size(LWPOLY *poly);
+static char *asx3d_poly(LWPOLY *poly);
+static size_t asx3d_inspected_size(LWGEOM_INSPECTED *geom);
+
+static char *asx3d_inspected(LWGEOM_INSPECTED *geom);
+static size_t pointArray_X3Dsize(POINTARRAY *pa);
+static size_t pointArray_toX3D(POINTARRAY *pa, char *buf);
+static size_t pointArrayPoly_toX3D(POINTARRAY *pa, char *buf);
+
+
+
+#define DEF_PRECISION 15
+/* Add dot, sign, exponent sign, 'e', exponent digits */
+#define SHOW_DIGS (precision + 10)
+
+/* Globals */
+int precision;
+
+
+/**
+ * Encode feature in X3D 
+ */
+PG_FUNCTION_INFO_V1(LWGEOM_asX3D);
+Datum LWGEOM_asX3D(PG_FUNCTION_ARGS)
+{
+	PG_LWGEOM *geom;
+	char *x3d;
+	text *result;
+	int len;
+		
+	precision = DEF_PRECISION;
+
+	if ( PG_ARGISNULL(0) ) PG_RETURN_NULL();
+
+	geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+
+	/* Get precision (if provided)  */
+	if ( PG_NARGS() > 1 && ! PG_ARGISNULL(1) )
+			precision = PG_GETARG_INT32(1);
+	
+	if ( precision < 1 || precision > 15 )
+	{
+		elog(ERROR, "Precision out of range 1..15");
+		PG_RETURN_NULL();
+	}
+
+	x3d = geometry_to_x3d(SERIALIZED_FORM(geom), NULL);
+	PG_FREE_IF_COPY(geom, 0);
+
+	len = strlen(x3d) + VARHDRSZ;
+
+	result = palloc(len);
+	SET_VARSIZE(result, len);
+
+	memcpy(VARDATA(result), x3d, len-VARHDRSZ);
+
+	pfree(x3d);
+
+	PG_RETURN_POINTER(result);
+}
+
+/* takes a GEOMETRY and returns a X3D representation */
+char *
+geometry_to_x3d(uchar *geom, char *srs)
+{
+	int type;
+	LWPOINT *point;
+	LWLINE *line;
+	LWPOLY *poly;
+	LWGEOM_INSPECTED *inspected;
+	
+	type = lwgeom_getType(geom[0]);
+	if(!lwgeom_hasZ(geom[0])){
+		elog(ERROR, "asX3D: 'the geometry is not in 3 dimensions !'");
+	}
+
+
+
+	switch (type)
+	{
+
+		case POINTTYPE:
+			point = lwpoint_deserialize(geom);
+			return asx3d_point(point);
+
+		case LINETYPE:
+			line = lwline_deserialize(geom);
+			return asx3d_line(line);
+
+		case POLYGONTYPE:
+			poly = lwpoly_deserialize(geom);
+			return asx3d_poly(poly);
+
+		default:
+			inspected = lwgeom_inspect(geom);
+			return asx3d_inspected(inspected);
+	}
+}
+
+static size_t
+asx3d_point_size(LWPOINT *point)
+{
+	int size;
+	size = pointArray_X3Dsize(point->point);
+	size += sizeof("<Coordinate point''/");
+	return size;
+}
+
+static size_t
+asx3d_point_buf(LWPOINT *point, char *output)
+{
+	char *ptr = output;
+	ptr += sprintf(ptr, "<Coordinate point=\"");
+	ptr += pointArray_toX3D(point->point, ptr);
+	ptr += sprintf(ptr, "\"/>\n");
+
+	return (ptr-output);
+}
+
+static char *
+asx3d_point(LWPOINT *point)
+{
+	char *output;
+	int size;
+	
+	size = asx3d_point_size(point);
+	output = palloc(size);
+	asx3d_point_buf(point, output);
+	return output;
+}
+
+static size_t
+asx3d_line_size(LWLINE *line )
+{
+	int size;
+	size = pointArray_X3Dsize(line->points);
+	size += sizeof("<LineSet vertexCount=''><Coordinate point=''/></LineSet>");
+	return size;
+}
+
+static size_t
+asx3d_line_buf(LWLINE *line, char *output)
+{
+	char *ptr=output;
+	int vcount = (line->points)->npoints;
+	ptr += sprintf(ptr, "<LineSet vertexCount=\"%d\">\n",vcount);
+	ptr += sprintf(ptr, "<Coordinate point=\"");
+	ptr += pointArray_toX3D(line->points, ptr);
+	ptr += sprintf(ptr,"\"/>\n");
+	ptr += sprintf(ptr, "</LineSet>\n");
+
+	return (ptr-output);
+}
+
+static char *
+asx3d_line(LWLINE *line)
+{
+	char *output;
+	int size;
+
+	size = asx3d_line_size(line);
+	output = palloc(size);
+	asx3d_line_buf(line, output);
+	return output;
+}
+
+static size_t
+asx3d_poly_size(LWPOLY *poly)
+{
+	size_t size;
+	int i;
+	if(poly->nrings>1){
+                        elog(ERROR, "asX3D: in X3D, polygons must have just one ring.");
+        }
+	size += sizeof("<IndexedFaceSet coordIndex=''");
+	size += 10*poly->rings[0]->npoints + poly->rings[0]->npoints -1;
+	size += sizeof("<Coordinate point=''/></IndexedFaceSet");
+	size += pointArray_X3Dsize(poly->rings[0]);
+
+	return size;
+}
+
+static size_t
+asx3d_poly_buf(LWPOLY *poly, char *output)
+{
+	int i;
+	char *ptr=output;
+	
+	ptr += sprintf(ptr, "<IndexedFaceSet coordIndex=\"");
+	for(i = 0;i<poly->rings[0]->npoints - 1 ;i++){
+		if(i)ptr += sprintf(ptr,",");
+		ptr += sprintf(ptr,"%d", i);
+	}
+	ptr += sprintf(ptr,"\">\n");
+	ptr += sprintf(ptr,"<Coordinate point=\"");
+	ptr += pointArrayPoly_toX3D(poly->rings[0], ptr);
+	ptr += sprintf(ptr,"\"/>\n");
+	ptr += sprintf(ptr,"</IndexedFaceSet>\n");
+
+	return (ptr-output);
+}
+
+static char *
+asx3d_poly(LWPOLY *poly)
+{
+	if(poly->nrings>1){
+		elog(ERROR, "asX3D: in X3D, polygons must have just one ring ");
+	}
+	char *output;
+	int size;
+
+	size = asx3d_poly_size(poly);
+	output = palloc(size);
+	asx3d_poly_buf(poly, output);
+	return output;
+}
+
+/*
+ * Compute max size required for X3D version of this 
+ * inspected geometry. Will recurse when needed.
+ * Don't call this with single-geoms inspected.
+ */
+static size_t
+asx3d_inspected_size(LWGEOM_INSPECTED *insp)
+{
+	int i;
+	int j;
+	size_t size;
+
+	size = sizeof("");
+
+	for (i=0; i<insp->ngeometries; i++)
+	{
+		LWPOINT *point;
+		LWLINE *line;
+		LWPOLY *poly;
+		LWGEOM_INSPECTED *subinsp;
+		uchar *subgeom;
+
+		if (lwgeom_getType(insp->type)==MULTIPOINTTYPE){
+			size += sizeof("<Coordinate point''/");
+			return size;
+		}
+		if (lwgeom_getType(insp->type)==MULTILINETYPE){
+			size += sizeof("<LineSet vertexCount=''><Coordinate point=\"\"/></LineSet>");
+			return size;
+		}
+		if (lwgeom_getType(insp->type)==MULTIPOLYGONTYPE || 
+		lwgeom_getType(insp->type)==POLYHEDRALSURFACETYPE ||
+                lwgeom_getType(insp->type)==TINTYPE){
+			int nbpts=0;
+			for(j=0; j<insp->ngeometries; j++)
+			{
+				if (lwgeom_getpoly_inspected(insp, i)->nrings>1){
+				elog(ERROR, "asX3D: in X3D, polygons must have just one ring.");
+				}
+				else
+				{
+				nbpts +=lwgeom_getpoly_inspected(insp, j)->rings[0]->npoints;
+				size += pointArray_X3Dsize(lwgeom_getpoly_inspected(insp, j)->rings[0]);
+				}
+			}
+			size += sizeof("<IndexedFaceSet coordIndex=''");
+		        size += (nbpts - insp->ngeometries)*10 +
+					2*(insp->ngeometries - 1) +nbpts -2;
+                        
+		        size += sizeof("<Coordinate point=\"\"/></IndexedFaceSet");
+			
+			return size;
+		}
+		if ((point=lwgeom_getpoint_inspected(insp, i)))
+		{
+			size += pointArray_X3Dsize(point->point);
+			pfree_point(point);
+			return size;
+		}
+		else if ((line=lwgeom_getline_inspected(insp, i)))
+		{
+			size +=pointArray_X3Dsize(line->points);
+			pfree_line(line);
+			return size;
+		}
+		else if ((poly=lwgeom_getpoly_inspected(insp, i)))
+		{
+			for (i=0; i<poly->nrings; i++)
+                	size += pointArray_X3Dsize(poly->rings[i]);
+			pfree_polygon(poly);
+			return size;
+		}
+		else if (lwgeom_getType(insp->type)==COLLECTIONTYPE)
+		{
+			subgeom = lwgeom_getsubgeometry_inspected(insp, i);
+			subinsp = lwgeom_inspect(subgeom);
+			size += asx3d_inspected_size(subinsp);
+			pfree_inspected(subinsp);
+			return size;
+		}
+		else
+		{
+			elog(ERROR, 
+			"asX3D: this type of geometry is not supported by the function asX3D.");
+		}
+	}
+
+	return size;
+}
+
+/*
+ * Don't call this with single-geoms inspected!
+ */
+static size_t
+asx3d_inspected_buf(LWGEOM_INSPECTED *insp, char *output)
+{
+	int i;
+	int j;
+	char *ptr;
+	ptr = output;
+
+	if(lwgeom_getType(insp->type)==MULTIPOINTTYPE)
+	{
+		ptr += sprintf(ptr, "<Coordinate point=\"");
+		for (i=0; i<insp->ngeometries; i++)
+		{
+			if(i)
+			{
+				ptr+=sprintf(ptr, ",");
+			}
+			ptr += pointArray_toX3D(lwgeom_getpoint_inspected(insp,i)->point, ptr);
+		}
+		ptr += sprintf(ptr, "\"/>\n");
+		return (ptr-output);
+	}
+	if (lwgeom_getType(insp->type)==MULTILINETYPE)
+	{
+		ptr += sprintf(ptr, "<LineSet vertexCount=\"");
+		for (i=0; i<insp->ngeometries; i++)
+		{
+			if (i)
+			{
+				ptr += sprintf(ptr," ");
+			}
+			int n = lwgeom_getline_inspected(insp,i)->points->npoints;
+			ptr += sprintf(ptr, "%d",n);
+		}
+		ptr += sprintf(ptr, "\">\n");
+		ptr += sprintf(ptr, "<Coordinate point=\"");
+		for (i=0; i<insp->ngeometries; i++)
+		{
+	       	        if(i)
+			{
+				ptr+=sprintf(ptr, ",");
+			}
+	                ptr += pointArray_toX3D(lwgeom_getline_inspected(insp,i)->points, ptr);
+       	        }
+        	ptr += sprintf(ptr, "\"/>\n");
+		ptr += sprintf(ptr, "</LineSet>\n");
+		return (ptr-output);
+	}
+
+	if (lwgeom_getType(insp->type)==MULTIPOLYGONTYPE ||
+	lwgeom_getType(insp->type)==POLYHEDRALSURFACETYPE ||
+        lwgeom_getType(insp->type)==TINTYPE){
+		ptr += sprintf(ptr, "<IndexedFaceSet coordIndex=\"");
+		int ind=0;
+		for (i=0; i<insp->ngeometries; i++)
+		{
+			if (i)
+			{
+				ptr += sprintf(ptr, ",-1");
+			}
+			for(j=0; j<lwgeom_getpoly_inspected(insp,i)->rings[0]->npoints-1; j++)
+			{
+				if(ind)
+				{
+					ptr += sprintf(ptr, ",");
+				}
+				ptr += sprintf(ptr, "%d",ind);
+				ind++;
+			}
+		}
+		ptr += sprintf(ptr, "\">\n");
+		ptr += sprintf(ptr, "<Coordinate point=\"");
+		for (i=0; i<insp->ngeometries; i++)
+	        {
+			if(i){ptr+=sprintf(ptr, ",");}
+			ptr += pointArrayPoly_toX3D(lwgeom_getpoly_inspected(insp,i)->rings[0],
+			ptr);
+		}
+		ptr += sprintf(ptr, "\"/>\n");
+	        ptr += sprintf(ptr, "</IndexedFaceSet>\n");
+		return (ptr-output);
+	}
+	else
+	{	
+		/*type = GEOMETRYCOLLECTION */
+		/* It is decomposed in several geometries*/
+		for (i=0; i<insp->ngeometries; i++)
+		{
+			LWPOINT *point;
+			LWLINE *line;
+			LWPOLY *poly;
+			LWGEOM_INSPECTED *subinsp;
+			uchar *subgeom;
+				
+			if ((point=lwgeom_getpoint_inspected(insp, i)))
+			{
+				ptr += asx3d_point_buf(point, ptr);
+				pfree_point(point);
+			}
+			else if ((line=lwgeom_getline_inspected(insp, i)))
+			{
+				ptr += asx3d_line_buf(line, ptr);
+				pfree_line(line);
+			}
+			else if ((poly=lwgeom_getpoly_inspected(insp, i)))
+			{
+				ptr += asx3d_poly_buf(poly, ptr);
+				pfree_polygon(poly);
+			}
+			else
+			{
+				subgeom = lwgeom_getsubgeometry_inspected(insp, i);
+				subinsp = lwgeom_inspect(subgeom);
+				ptr += asx3d_inspected_buf(subinsp, ptr);
+				pfree_inspected(subinsp);
+			}
+		}
+	}
+	return (ptr-output);
+}
+
+/*
+ * Don't call this with single-geoms inspected!
+ */
+static char *
+asx3d_inspected(LWGEOM_INSPECTED *insp)
+{
+	char *x3d;
+	size_t size;
+	size = asx3d_inspected_size(insp);
+	x3d = palloc(size);
+	asx3d_inspected_buf(insp, x3d);
+	return x3d;
+}
+
+
+/*
+ * Returns maximum size of rendered pointarray in bytes.
+ */
+static size_t
+pointArray_X3Dsize(POINTARRAY *pa)
+{
+	return TYPE_NDIMS(pa->dims) * pa->npoints * (SHOW_DIGS+(TYPE_NDIMS(pa->dims)-1));
+}
+
+static size_t
+pointArray_toX3D(POINTARRAY *pa, char *output)
+{
+	int i;
+	char *ptr;
+
+	ptr = output;
+	{
+		for (i=0; i<pa->npoints; i++)
+		{
+			POINT4D pt;
+			getPoint4d_p(pa, i, &pt);
+			if ( i ) ptr += sprintf(ptr, ",");
+			ptr += sprintf(ptr, "%.*g %.*g %.*g",
+				precision, pt.x,
+				precision, pt.y,
+				precision, pt.z);
+			
+		}
+	}
+
+	return ptr-output;
+}
+
+/*
+ * Same function but called when type is POLYGON
+ */
+
+static size_t
+pointArrayPoly_toX3D(POINTARRAY *pa, char *output)
+{
+        int i;
+        char *ptr;
+
+        ptr = output;
+        {
+                for (i=0; i<pa->npoints-1; i++)
+                {
+                        POINT4D pt;
+                        getPoint4d_p(pa, i, &pt);
+                        if ( i ) ptr += sprintf(ptr, ",");
+                        ptr += sprintf(ptr, "%.*g %.*g %.*g",
+                                precision, pt.x,
+                                precision, pt.y,
+                                precision, pt.z);
+
+                }
+        }
+
+        return ptr-output;
+}
+
--- postgis-svn/lwgeom/wktunparse.c	2007-09-20 16:22:47.000000000 +0200
+++ postgis-patch/lwgeom/wktunparse.c	2007-09-18 15:33:40.000000000 +0200
@@ -227,13 +227,7 @@
 	
 	if ( type  == POINTTYPE )
 		return output_point(++geom,suppress);
-	else if ( type == POINTTYPEI ){
-		lwgi++;
-		geom=output_point(++geom,0);
-		lwgi--;
-		return geom;
-	}
-	
+		
 	return output_wkt(geom,suppress);
 }
 
@@ -391,7 +385,23 @@
 			}
 			geom = output_collection(geom,output_wkt,2);
 			break;
-                case MULTISURFACETYPE:
+                case TINTYPE:
+                        if ( supress < 2 )
+                        {
+                                if (writeM) write_str("TINM");
+                                else write_str("TIN");
+                        }
+                        geom = output_collection(geom,output_wkt,2);
+                        break;
+		case POLYHEDRALSURFACETYPE:
+                        if ( supress < 2 )
+                        {
+                                if (writeM) write_str("POLYHEDRALSURFACEM");
+                                else write_str("POLYHEDRALSURFACE");
+                        }
+                        geom = output_collection(geom,output_wkt,2);
+                        break;
+		case MULTISURFACETYPE:
                         if ( supress < 2)
                         {
                                 if (writeM) write_str("MULTISURFACEM");
@@ -408,36 +418,6 @@
 			geom = output_collection(geom,output_wkt,1);
 			break;
 
-		case POINTTYPEI:
-			if ( supress < 2 )
-			{
-				if (writeM) write_str("POINTM");
-				else write_str("POINT");
-			}
-			lwgi++;
-			geom=output_single(geom,0);
-			lwgi--;
-			break;
-		case LINETYPEI:
-			if ( supress < 2 )
-			{
-				if (writeM) write_str("LINESTRINGM");
-				else write_str("LINESTRING");
-			}
-			lwgi++;
-			geom = output_collection(geom,output_point,0);
-			lwgi--;
-			break;
-		case POLYGONTYPEI:
-			if ( supress < 2 )
-			{
-				if (writeM) write_str("POLYGONM");
-				else write_str("POLYGON");
-			}
-			lwgi++;
-			geom =output_collection(geom,output_collection_2,0);
-			lwgi--;
-			break;
 	}
 	return geom;
 }
@@ -635,29 +615,6 @@
 			geom = output_wkb_collection(geom,output_wkb);
 			break;
 
-		/*
-			These don't output standard wkb at the moment
-			the output and integer version.
-
-			however you could run it through the wkt parser
-			for a lwg and then output that.  There should
-			also be a force_to_real_(lwgi)
-		*/
-		case POINTTYPEI:
-			lwgi++;
-			geom=output_wkb_point(geom);
-			lwgi--;
-			break;
-		case LINETYPEI:
-			lwgi++;
-			geom = output_wkb_collection(geom,output_wkb_point);
-			lwgi--;
-			break;
-		case POLYGONTYPEI:
-			lwgi++;
-			geom = output_wkb_collection(geom,output_wkb_collection_2);
-			lwgi--;
-			break;
 	}
 	return geom;
 }
--- postgis-svn/lwgeom/lwpostgis.sql.in	2007-09-20 16:22:47.000000000 +0200
+++ postgis-patch/lwgeom/lwpostgis.sql.in	2007-09-18 15:13:41.000000000 +0200
@@ -4720,6 +4720,48 @@
 	LANGUAGE 'SQL' _IMMUTABLE_STRICT; -- WITH (isstrict,iscachable);
 
 -----------------------------------------------------------------------
+-- X3D OUTPUT
+-----------------------------------------------------------------------
+-- AsX3D(geom, precision, version)
+-- Deprecation in 1.2.3
+CREATEFUNCTION AsX3D(geometry, int4, int4)
+        RETURNS TEXT
+        AS '@MODULE_FILENAME@','LWGEOM_asX3D'
+        LANGUAGE 'C' _IMMUTABLE_STRICT; -- WITH (isstrict,iscachable);
+
+-- Availability: 1.2.2
+CREATEFUNCTION ST_AsX3D(geometry, int4, int4)
+        RETURNS TEXT
+        AS '@MODULE_FILENAME@','LWGEOM_asX3D'
+        LANGUAGE 'C' _IMMUTABLE_STRICT; -- WITH (isstrict,iscachable);
+
+-- AsX3D(geom, precision) / version=2
+-- Deprecation in 1.2.3
+CREATEFUNCTION AsX3D(geometry, int4)
+        RETURNS TEXT
+        AS '@MODULE_FILENAME@','LWGEOM_asX3D'
+        LANGUAGE 'C' _IMMUTABLE_STRICT; -- WITH (isstrict,iscachable);
+
+-- Availability: 1.2.2
+CREATEFUNCTION ST_AsX3D(geometry, int4)
+        RETURNS TEXT
+        AS '@MODULE_FILENAME@','LWGEOM_asX3D'
+        LANGUAGE 'C' _IMMUTABLE_STRICT; -- WITH (isstrict,iscachable);
+
+-- AsX3D(geom) / precision=15 version=2
+-- Deprecation in 1.2.3
+CREATEFUNCTION AsX3D(geometry)
+        RETURNS TEXT
+        AS '@MODULE_FILENAME@','LWGEOM_asX3D'
+        LANGUAGE 'C' _IMMUTABLE_STRICT; -- WITH (isstrict,iscachable);
+
+-- Availabiltiy: 1.2.2
+CREATEFUNCTION ST_AsX3D(geometry)
+        RETURNS TEXT
+        AS '@MODULE_FILENAME@','LWGEOM_asX3D'
+        LANGUAGE 'C' _IMMUTABLE_STRICT; -- WITH (isstrict,iscachable);
+
+-----------------------------------------------------------------------
 -- KML OUTPUT
 -----------------------------------------------------------------------
 -- AsUKML(geom, precision, version)
--- postgis-svn/lwgeom/lwgeom_debug.c	2007-09-20 16:22:47.000000000 +0200
+++ postgis-patch/lwgeom/lwgeom_debug.c	2007-09-19 14:07:30.000000000 +0200
@@ -28,6 +28,8 @@
 		case MULTIPOINTTYPE:
 		case MULTILINETYPE:
 		case MULTIPOLYGONTYPE:
+		case TINTYPE:
+		case POLYHEDRALSURFACETYPE:
 		case COLLECTIONTYPE:
 			return lwcollection_summary((LWCOLLECTION *)lwgeom, offset);
 		default:
--- postgis-svn/lwgeom/Makefile	2007-09-20 16:22:47.000000000 +0200
+++ postgis-patch/lwgeom/Makefile	2007-09-18 15:13:41.000000000 +0200
@@ -74,9 +74,9 @@
 override CFLAGS += $(CSTAR_FLAGS)
 override CXXFLAGS += $(CSTAR_FLAGS)
 
-SA_OBJS=measures.o box2d.o ptarray.o lwgeom_api.o lwgeom.o lwpoint.o lwline.o lwpoly.o lwmpoint.o lwmline.o lwmpoly.o lwcollection.o $(GEOS_WRAPPER) $(JTS_WRAPPER) wktunparse.o lwgparse.o wktparse.tab.o lex.yy.o vsprintf.o
+SA_OBJS=measures.o box2d.o ptarray.o lwgeom_api.o lwgeom.o lwpoint.o lwline.o lwpoly.o lwmpoint.o lwmline.o lwmpoly.o lwpolyhedralsurf.o lwtin.o lwcollection.o $(GEOS_WRAPPER) $(JTS_WRAPPER) wktunparse.o lwgparse.o wktparse.tab.o lex.yy.o vsprintf.o
 
-OBJS=$(SA_OBJS) liblwgeom.o lwgeom_pg.o lwgeom_debug.o lwgeom_spheroid.o lwgeom_ogc.o lwgeom_functions_analytic.o $(JTS_OBJ) lwgeom_inout.o lwgeom_estimate.o lwgeom_functions_basic.o lwgeom_gist.o lwgeom_btree.o lwgeom_transform.o stringBuffer.o lwgeom_box.o lwgeom_box3d.o lwgeom_box2dfloat4.o lwgeom_chip.o lwgeom_svg.o lwgeom_gml.o lwgeom_kml.o lwgeom_triggers.o lwgeom_dump.o lwgeom_functions_lrs.o long_xact.o lwcurve.o lwcompound.o lwcurvepoly.o lwmcurve.o lwmsurface.o lwgeom_sqlmm.o lwgeom_rtree.o
+OBJS=$(SA_OBJS) liblwgeom.o lwgeom_pg.o lwgeom_debug.o lwgeom_spheroid.o lwgeom_ogc.o lwgeom_functions_analytic.o $(JTS_OBJ) lwgeom_inout.o lwgeom_estimate.o lwgeom_functions_basic.o lwgeom_gist.o lwgeom_btree.o lwgeom_transform.o stringBuffer.o lwgeom_box.o lwgeom_box3d.o lwgeom_box2dfloat4.o lwgeom_chip.o lwgeom_svg.o lwgeom_gml.o lwgeom_kml.o lwgeom_x3d.o lwgeom_triggers.o lwgeom_dump.o lwgeom_functions_lrs.o long_xact.o lwcurve.o lwcompound.o lwcurvepoly.o lwmcurve.o lwmsurface.o lwgeom_sqlmm.o lwgeom_rtree.o
 
 #OTHERS=y.output lex.yy.c wktparse.tab.c wktparse.tab.h lwpostgis.sql
 OTHERS=y.output postgis_geos_version.h
