[postgis-devel] Backend crash with RC3 and RC4

strk at refractions.net strk at refractions.net
Wed Mar 23 08:55:28 PST 2005


RC4 patch is attached.
--strk;

On Wed, Mar 23, 2005 at 04:38:27PM -0000, Mark Cave-Ayland wrote:
> 
> > -----Original Message-----
> > From: postgis-devel-bounces at postgis.refractions.net 
> > [mailto:postgis-devel-bounces at postgis.refractions.net] On 
> > Behalf Of strk at refractions.net
> > Sent: 23 March 2005 16:12
> > To: 'PostGIS Development Discussion'
> > Subject: Re: [postgis-devel] Backend crash with RC3 and RC4
> > 
> > 
> > Well.. it was less dramatic then I tought.
> > Fix was two fold:
> > 	- *wrong* box3d computation for COLLECTIONS
> > 	- *missing* return value check from GEOMSTRY::BOX3D cast
> > 
> > Upgrading people will benefit from an addBBOX(dropBBOX(the_geom)) 
> > update of spatial tables. And a VACUUM ANALYZE afterwards...
> > 
> > I hope this won't require an RC5.... what about an RC4-2 
> > win32 installer Mark ?
> > 
> > --strk;
> 
> 
> Hi strk,
> 
> Hmmm... haven't got time to do a new installer but could quickly compile and
> email Martin a new liblwgeom.dll if you could supply a patch against RC4....
> 
> I would say that a crasher is definitely worth bringing out RC5, otherwise
> we get people confused as to whether they are using RC4-1 or RC4-2 (plus it
> doesn't help the Unix users). If you can send me the patch, I'll quickly
> apply and send Martin the DLL. If it works then my call would be go for RC5
> beginning of next week just to avoid confusion....
> 
> 
> Kind regards,
> 
> Mark.
> 
> ------------------------
> WebBased Ltd
> South West Technology Centre
> Tamar Science Park
> Plymouth
> PL6 8BT 
> 
> T: +44 (0)1752 791021
> F: +44 (0)1752 791023
> W: http://www.webbased.co.uk
> 
> 
> _______________________________________________
> postgis-devel mailing list
> postgis-devel at postgis.refractions.net
> http://postgis.refractions.net/mailman/listinfo/postgis-devel
-------------- next part --------------
Index: CHANGES
===================================================================
RCS file: /home/cvs/postgis/postgis/CHANGES,v
retrieving revision 1.59
retrieving revision 1.61
diff -U2 -r1.59 -r1.61
--- CHANGES	18 Mar 2005 21:04:01 -0000	1.59
+++ CHANGES	23 Mar 2005 16:24:55 -0000	1.61
@@ -1,2 +1,7 @@
+PostGIS 1.0.0
+??????????
+	- small build scripts refinements
+	- BUGFIX in box3d computation (yes, another!)
+
 PostGIS 1.0.0RC4
 2005/03/18
Index: doc/postgis.xml
===================================================================
RCS file: /home/cvs/postgis/postgis/doc/postgis.xml,v
retrieving revision 1.126
retrieving revision 1.127
diff -U2 -r1.126 -r1.127
--- doc/postgis.xml	4 Mar 2005 19:31:36 -0000	1.126
+++ doc/postgis.xml	21 Mar 2005 12:24:31 -0000	1.127
@@ -4402,13 +4402,15 @@
 		</varlistentry>
 
-			<varlistentry>
-				<term>estimated_extent([schema], table, geocolumn)</term>
-				<listitem>
-					<para> Return the 'estimated' extent of the given spatial table.  The estimated is taken from the geometry column's statistics gathered by running VACUUM ANALYZE, and is statistically about 95% of 'real' extent. The current schema will be used if not specified.  </para>
-					<para>NOTE: This is only available with PostgreSQL >= 8.0.0</para>
-				</listitem>
-			</varlistentry>
+		<varlistentry>
+			<term>estimated_extent([schema], table, geocolumn)</term>
+			<listitem>
+				<para> Return the 'estimated' extent of the given spatial table.  The estimated is taken from the geometry column's statistics. The current schema will be used if not specified.</para>
+
+				<para>For PostgreSQL>=8.0.0 statistics are gathered by VACUUM ANALYZE and resulting extent will be about 95% of the real one.</para>
+				<para>For PostgreSQL<8.0.0 statistics are gathered by update_geometry_stats() and resulting extent will be exact.</para>
+			</listitem>
+		</varlistentry>
 
-        <varlistentry>
+	<varlistentry>
           <term>find_srid(varchar,varchar,varchar)</term>
 
Index: jdbc2/.cvsignore
===================================================================
RCS file: /home/cvs/postgis/postgis/jdbc2/.cvsignore,v
retrieving revision 1.5
retrieving revision 1.6
diff -U2 -r1.5 -r1.6
--- jdbc2/.cvsignore	4 Mar 2005 15:22:01 -0000	1.5
+++ jdbc2/.cvsignore	21 Mar 2005 13:43:42 -0000	1.6
@@ -1,6 +1,5 @@
 bin
 compile
-postgis.jar
-postgis_debug.jar
+*.jar
 stubbin
 stubcompile
Index: lwgeom/Makefile
===================================================================
RCS file: /home/cvs/postgis/postgis/lwgeom/Makefile,v
retrieving revision 1.72
retrieving revision 1.73
diff -U2 -r1.72 -r1.73
--- lwgeom/Makefile	18 Mar 2005 12:43:23 -0000	1.72
+++ lwgeom/Makefile	21 Mar 2005 17:52:06 -0000	1.73
@@ -139,5 +139,5 @@
 
 lwpostgis.sql: lwpostgis.sql.in
-	cpp -P -traditional-cpp -DUSE_VERSION=$(USE_VERSION) $< | sed -e 's:@MODULE_FILENAME@:$(MODULE_FILENAME):g;s:@POSTGIS_VERSION@:$(POSTGIS_VERSION):g;s:@POSTGIS_SCRIPTS_VERSION@:$(SCRIPTS_VERSION):g;s/@POSTGIS_BUILD_DATE@/$(POSTGIS_BUILD_DATE)/g' | grep -v ^# > $@
+	cpp -P -traditional-cpp -DUSE_VERSION=$(USE_VERSION) $< | sed -e 's:@MODULE_FILENAME@:$(MODULE_FILENAME):g;s:@POSTGIS_VERSION@:$(POSTGIS_VERSION):g;s:@POSTGIS_SCRIPTS_VERSION@:$(SCRIPTS_VERSION):g;s/@POSTGIS_BUILD_DATE@/$(POSTGIS_BUILD_DATE)/g' | grep -v '^#' > $@
 
 install: all installdirs install-lwgeom-lib install-lwgeom-scripts
Index: lwgeom/liblwgeom.h
===================================================================
RCS file: /home/cvs/postgis/postgis/lwgeom/liblwgeom.h,v
retrieving revision 1.42
retrieving revision 1.43
diff -U2 -r1.42 -r1.43
--- lwgeom/liblwgeom.h	18 Mar 2005 12:36:27 -0000	1.42
+++ lwgeom/liblwgeom.h	23 Mar 2005 16:23:45 -0000	1.43
@@ -597,47 +597,4 @@
 extern int lwgeom_size_inspected(const LWGEOM_INSPECTED *inspected, int geom_number);
 
-/*
- * This structure is intended to be used for geometry collection construction.
- * Does not allow specification of collection structure
- * (serialization chooses the simpler form)
- */
-typedef struct
-{
-	int SRID;
-	uchar dims;
-	uint32 npoints;
-	uchar **points;
-	uint32 nlines;
-	uchar **lines;
-	uint32 npolys;
-	uchar **polys;
-} LWGEOM_EXPLODED;
-
-void pfree_exploded(LWGEOM_EXPLODED *exploded);
-
-// Returns a 'palloced' union of the two input exploded geoms.
-// Returns NULL if SRID or ndims do not match.
-LWGEOM_EXPLODED * lwexploded_sum(LWGEOM_EXPLODED *exp1, LWGEOM_EXPLODED *exp2);
-
-/*
- * This function recursively scan the given serialized geometry
- * and returns a list of _all_ subgeoms in it (deep-first)
- */
-extern LWGEOM_EXPLODED *lwgeom_explode(uchar *serialized);
-
-/*
- * Return the length of the serialized form corresponding
- * to this exploded structure.
- */
-extern size_t lwexploded_findlength(LWGEOM_EXPLODED *exp, int wantbbox);
-
-// Serialize an LWGEOM_EXPLODED object.
-// SRID and ndims will be taken from exploded structure.
-// wantbbox will determine result bbox.
-extern uchar *lwexploded_serialize(LWGEOM_EXPLODED *exploded, int wantbbox);
-
-// Same as lwexploded_serialize but writing to pre-allocated space
-extern void lwexploded_serialize_buf(LWGEOM_EXPLODED *exploded, int wantbbox, uchar *buf, size_t *retsize);
-
 // note - for a simple type (ie. point), this will have sub_geom[0] = serialized_form.
 // for multi-geomtries sub_geom[0] will be a few bytes into the serialized form
@@ -778,4 +735,5 @@
 extern uint32 get_uint32(const uchar *loc);
 extern int32 get_int32(const uchar *loc);
+extern void printBOX3D(BOX3D *b);
 extern void printPA(POINTARRAY *pa);
 extern void printLWPOINT(LWPOINT *point);
@@ -1043,5 +1001,4 @@
 
 extern int32 lwgeom_nrings_recursive(uchar *serialized);
-extern void dump_lwexploded(LWGEOM_EXPLODED *exploded);
 extern void ptarray_reverse(POINTARRAY *pa);
 
Index: lwgeom/lwgeom_api.c
===================================================================
RCS file: /home/cvs/postgis/postgis/lwgeom/lwgeom_api.c,v
retrieving revision 1.70
retrieving revision 1.71
diff -U2 -r1.70 -r1.71
--- lwgeom/lwgeom_api.c	18 Mar 2005 12:36:27 -0000	1.70
+++ lwgeom/lwgeom_api.c	23 Mar 2005 16:23:45 -0000	1.71
@@ -9,12 +9,8 @@
 
 //#define PGIS_DEBUG 1
-//#define PGIS_DEBUG_EXPLODED 1
 
 // This is an implementation of the functions defined in lwgeom.h
 
 //forward decs
-#ifdef PGIS_DEBUG_EXPLODED
-void checkexplodedsize(uchar *srl, LWGEOM_EXPLODED *exploded, int alloced, char wantbbox);
-#endif
 extern uchar *parse_lwg(const char* geometry, lwallocator allocfunc, lwreporter errfunc);
 
@@ -1470,9 +1466,18 @@
 	for (t=0; t<ngeoms; t++)
 	{
-		if ( ! compute_serialized_box3d_p(loc, &b1) ) continue;
-		if (result) nboxes += box3d_union_p(result, &b1, result);
-		else { 
-			result = lwalloc(sizeof(BOX3D));
-			memcpy(result, &b1, sizeof(BOX3D));
+		if ( compute_serialized_box3d_p(loc, &b1) ) 
+		{
+#ifdef PGIS_DEBUG
+			lwnotice("Geom %d have box:"); printBOX3D(&b1);
+#endif
+			if (result)
+			{
+				nboxes += box3d_union_p(result, &b1, result);
+			}
+			else
+			{ 
+				result = lwalloc(sizeof(BOX3D));
+				memcpy(result, &b1, sizeof(BOX3D));
+			}
 		}
 
@@ -1511,4 +1516,10 @@
 
 
+void printBOX3D(BOX3D *box)
+{
+	lwnotice("BOX3D: %g %g, %g %g", box->xmin, box->ymin,
+		box->xmax, box->ymax);
+}
+
 void printPA(POINTARRAY *pa)
 {
@@ -1734,620 +1745,4 @@
 }
 
-void
-pfree_exploded(LWGEOM_EXPLODED *exploded)
-{
-	if ( exploded->npoints )
-		lwfree(exploded->points);
-	if ( exploded->nlines )
-		lwfree(exploded->lines);
-	if ( exploded->npolys )
-		lwfree(exploded->polys);
-	lwfree(exploded);
-};
-
-/*
- * This function recursively scan the given serialized geometry
- * and returns a list of _all_ subgeoms in it (deep-first)
- */
-LWGEOM_EXPLODED *
-lwgeom_explode(uchar *serialized)
-{
-	LWGEOM_INSPECTED *inspected;
-	LWGEOM_EXPLODED *subexploded, *result;
-	int i;
-
-#ifdef PGIS_DEBUG
-	lwnotice("lwgeom_explode called");
-#endif
-
-	inspected = lwgeom_inspect(serialized);
-
-
-#ifdef PGIS_DEBUG
-lwnotice("lwgeom_explode: serialized inspected");
-#endif
-
-	result = lwalloc(sizeof(LWGEOM_EXPLODED));
-	result->points = lwalloc(1);
-	result->lines = lwalloc(1);
-	result->polys = lwalloc(1);
-	result->npoints = 0;
-	result->nlines = 0;
-	result->npolys = 0;
-
-	if ( ! inspected->ngeometries )
-	{
-		lwfree(result->points);
-		lwfree(result->lines);
-		lwfree(result->polys);
-		result->SRID = -1;
-		result->dims = inspected->type;
-		pfree_inspected(inspected);
-		//lwnotice("lwgeom_explode: no geometries");
-		return result;
-	}
-
-	result->SRID = lwgeom_getsrid(serialized);
-	result->dims = inspected->type; // will use ZM only
-
-	for (i=0; i<inspected->ngeometries; i++)
-	{
-
-		uchar *subgeom = inspected->sub_geoms[i];
-		int type = lwgeom_getType(subgeom[0]);
-
-		if ( type == POINTTYPE )
-		{
-#ifdef PGIS_DEBUG
-lwnotice("lwgeom_explode: it's a point");
-#endif
-			result->points = lwrealloc(result->points,
-				(result->npoints+1)*sizeof(uchar *));
-			result->points[result->npoints] = subgeom;
-			result->npoints++;
-			continue;
-		}
-
-		if ( type == LINETYPE )
-		{
-#ifdef PGIS_DEBUG
-lwnotice("lwgeom_explode: it's a line");
-#endif
-			result->lines = lwrealloc(result->lines,
-				(result->nlines+1)*sizeof(uchar *));
-			result->lines[result->nlines] = subgeom;
-			result->nlines++;
-			continue;
-		}
-
-		if ( type == POLYGONTYPE )
-		{
-#ifdef PGIS_DEBUG
-lwnotice("lwgeom_explode: it's a polygon");
-#endif
-			result->polys = lwrealloc(result->polys,
-				(result->npolys+1)*sizeof(uchar *));
-			result->polys[result->npolys] = subgeom;
-			result->npolys++;
-			continue;
-		}
-
-#ifdef PGIS_DEBUG
-		lwnotice("type of subgeom %d is %d, recursing", i, type);
-#endif
-
-		// it's a multi geometry, recurse
-		subexploded = lwgeom_explode(subgeom);
-
-#ifdef PGIS_DEBUG
-		lwnotice("subgeom %d, exploded: %d point, %d lines, %d polys", i, subexploded->npoints, subexploded->nlines, subexploded->npolys);
-#endif
-
-		// Re-allocate adding space for new exploded geoms
-		// (-1 because 1 was already allocated for the collection)
-		// Copy subgeom pointers from subexploded to current
-		// exploded.
-
-		if ( subexploded->npoints )
-		{
-			result->points = lwrealloc(result->points,
-				sizeof(uchar *)*(result->npoints+subexploded->npoints-1));
-			if ( ! result )
-				lwerror("Out of virtual memory");
-
-#ifdef PGIS_DEBUG
-			lwnotice("lwrealloc'ed exploded->points");
-#endif
-
-			memcpy(&(result->points[result->npoints]),
-				subexploded->points,
-				subexploded->npoints*sizeof(uchar *));
-
-#ifdef PGIS_DEBUG
-			lwnotice("memcpied exploded->points");
-#endif
-
-			result->npoints += subexploded->npoints;
-
-#ifdef PGIS_DEBUG
-			lwnotice("memcopied %d points from subexploded (exploded points: %d", subexploded->npoints, result->npoints);
-#endif
-		}
-
-		if ( subexploded->nlines )
-		{
-			result->lines = lwrealloc(result->lines,
-				sizeof(uchar *)*
-				(result->nlines+subexploded->nlines-1));
-
-			memcpy(&(result->lines[result->nlines]),
-				subexploded->lines,
-				subexploded->nlines*sizeof(uchar *));
-
-			result->nlines += subexploded->nlines;
-		}
-
-		if ( subexploded->npolys )
-		{
-			result->polys = lwrealloc(result->polys,
-				sizeof(uchar *)*
-				(result->npolys+subexploded->npolys-1));
-
-			memcpy(&(result->polys[result->npolys]),
-				subexploded->polys,
-				subexploded->npolys*sizeof(uchar *));
-
-			result->npolys += subexploded->npolys;
-		}
-
-		// release subexploded memory
-		pfree_exploded(subexploded);
-
-	}
-
-	pfree_inspected(inspected);
-
-#ifdef PGIS_DEBUG
-lwnotice("lwgeom_explode: returning");
-#endif
-
-	return result;
-}
-
-// Returns a 'lwalloced' union of the two input exploded geoms
-// Returns NULL if SRID or ndims do not match.
-LWGEOM_EXPLODED *
-lwexploded_sum(LWGEOM_EXPLODED *exp1, LWGEOM_EXPLODED *exp2)
-{
-	LWGEOM_EXPLODED *expcoll;
-	uchar *loc;
-
-	if ( TYPE_GETZM(exp1->dims) != TYPE_GETZM(exp2->dims) )
-	{
-		lwerror("lwexploded_sum: can't sum mixed DIMS geoms (%d/%d)",
-			TYPE_GETZM(exp1->dims), TYPE_GETZM(exp2->dims));
-		return NULL;
-	}
-	if ( exp1->SRID != exp2->SRID )
-	{
-		lwerror("lwexploded_sum: can't sum mixed SRID geoms (%d/%d)",
-			exp1->SRID, exp2->SRID);
-		return NULL;
-	}
-
-	expcoll = lwalloc(sizeof(LWGEOM_EXPLODED));
-
-	expcoll->npoints = exp1->npoints + exp2->npoints;
-	if ( expcoll->npoints ) {
-		expcoll->points = lwalloc(expcoll->npoints*sizeof(char *));
-		loc = (char *)&(expcoll->points[0]);
-		if ( exp1->npoints ) {
-			memcpy(loc, exp1->points,
-				exp1->npoints*sizeof(char *));
-			loc += exp1->npoints*sizeof(char *);
-		}
-		if ( exp2->npoints ) {
-			memcpy(loc, exp2->points,
-				exp2->npoints*sizeof(char *));
-		}
-	}
-
-	expcoll->nlines = exp1->nlines + exp2->nlines;
-	if ( expcoll->nlines ) {
-		expcoll->lines = lwalloc(expcoll->nlines*sizeof(char *));
-		loc = (char *)&(expcoll->lines[0]);
-		if ( exp1->nlines ) {
-			memcpy(loc, exp1->lines,
-				exp1->nlines*sizeof(char *));
-			loc += exp1->nlines*sizeof(char *);
-		}
-		if ( exp2->nlines ) {
-			memcpy(loc, exp2->lines,
-				exp2->nlines*sizeof(char *));
-		}
-	}
-
-	expcoll->npolys = exp1->npolys + exp2->npolys;
-	if ( expcoll->npolys ) {
-		expcoll->polys = lwalloc(expcoll->npolys*sizeof(char *));
-		loc = (char *)&(expcoll->polys[0]);
-		if ( exp1->npolys ) {
-			memcpy(loc, exp1->polys,
-				exp1->npolys*sizeof(char *));
-			loc += exp1->npolys*sizeof(char *);
-		}
-		if ( exp2->npolys ) {
-			memcpy(loc, exp2->polys,
-				exp2->npolys*sizeof(char *));
-		}
-	}
-
-	expcoll->dims = exp1->dims;
-	expcoll->SRID = exp1->SRID;
-
-	return expcoll;
-}
-
-/*
- * Serialized a LWGEOM_EXPLODED structure
- */
-uchar *
-lwexploded_serialize(LWGEOM_EXPLODED *exploded, int wantbbox)
-{
-	size_t sizecom = 0;
-	size_t size;
-	uchar *result;
-
-	size = lwexploded_findlength(exploded, wantbbox);
-	result = lwalloc(size);
-	lwexploded_serialize_buf(exploded, wantbbox, result, &sizecom);
-#ifdef PGIS_DEBUG
-	lwnotice("lwexploded_serialize: findlength:%d, serialize_buf:%d", size, sizecom);
-#endif
-	return result;
-}
-
-/*
- * Serialized a LWGEOM_EXPLODED structure into a
- * pre-allocated memory space.
- * Use lwexploded_findlength to know the required size 
- * of the provided buffer.
- */
-void
-lwexploded_serialize_buf(LWGEOM_EXPLODED *exploded, int wantbbox,
-	uchar *buf, size_t *retsize)
-{
-	size_t size=0;
-	int i;
-	int ntypes = 0;
-	int ngeoms = 0;
-	uchar *loc;
-	int outtype = 0;
-	LWPOLY *poly;
-	LWLINE *line;
-	LWPOINT *point;
-	BOX2DFLOAT4 *box2d;
-	BOX3D *box3d;
-
-	ngeoms = exploded->npoints + exploded->nlines + exploded->npolys;
-
-	if ( ngeoms == 0 )
-	{
-		lwgeom_constructempty_buf(exploded->SRID,
-			TYPE_HASZ(exploded->dims), TYPE_HASM(exploded->dims),
-			buf, retsize);
-		return;
-	}
-
-
-	// For a single geometry just set SRID and BBOX (if requested)
-	if ( ngeoms == 1 )
-	{
-		loc = buf;
-
-		if ( exploded->npoints ) {
-
-			if ( wantbbox && !
-				lwgeom_hasBBOX(exploded->points[0][0]) )
-			{
-				loc += sizeof(BOX2DFLOAT4);
-			}
-			point = lwpoint_deserialize(exploded->points[0]);
-			point->SRID = exploded->SRID;
-			lwpoint_serialize_buf(point, loc, &size);
-			pfree_point(point);
-		}
-		else if ( exploded->nlines ) {
-			if ( wantbbox && !
-				lwgeom_hasBBOX(exploded->lines[0][0]) )
-			{
-				loc += sizeof(BOX2DFLOAT4);
-			}
-			line = lwline_deserialize(exploded->lines[0]);
-			line->SRID = exploded->SRID;
-			lwline_serialize_buf(line, loc, &size);
-			pfree_line(line);
-		}
-		else if ( exploded->npolys ) {
-			if ( wantbbox && !
-				lwgeom_hasBBOX(exploded->polys[0][0]) )
-			{
-				loc += sizeof(BOX2DFLOAT4);
-			}
-			poly = lwpoly_deserialize(exploded->polys[0]);
-			poly->SRID = exploded->SRID;
-			lwpoly_serialize_buf(poly, loc, &size);
-			pfree_polygon(poly);
-
-		}
-		else {
-			if ( retsize ) *retsize = 0;
-			return; // ERROR !!
-		}
-
-
-		// Now compute the bounding box and write it
-		if ( wantbbox && ! lwgeom_hasBBOX(loc[0]) )
-		{
-			buf[0] = loc[0];
-			TYPE_SETHASBBOX(buf[0], 1);
-			box3d = compute_serialized_box3d(loc);
-			box2d = box3d_to_box2df(box3d);
-			loc = buf+1;
-			memcpy(loc, box2d, sizeof(BOX2DFLOAT4));
-			size += sizeof(BOX2DFLOAT4);
-		}
-
-		if (retsize) *retsize = size;
-		return;
-	}
-
-	if ( exploded->npoints ) {
-		ntypes++;
-		outtype = (exploded->npoints>1) ? MULTIPOINTTYPE : POINTTYPE;
-	}
-	if ( exploded->nlines ) {
-		ntypes++;
-		if ( outtype ) outtype = COLLECTIONTYPE;
-		else outtype = (exploded->nlines>1) ? MULTILINETYPE : LINETYPE;
-	}
-	if ( exploded->npolys ) {
-		ntypes++;
-		if ( outtype ) outtype = COLLECTIONTYPE;
-		else outtype = (exploded->npolys>1) ? MULTIPOLYGONTYPE : POLYGONTYPE;
-	}
-
-#ifdef PGIS_DEBUG
-	lwnotice(" computed outtype: %d, ngeoms: %d", outtype, ngeoms);
-#endif
-
-
-	loc = buf+1; // skip type
-
-	if ( wantbbox ) loc += sizeof(BOX2DFLOAT4); // skip box
-	if ( exploded->SRID != -1 ) loc += 4; // skip SRID
-
-	// If we have more then one type of geom
-	// write that number in the 'ngeoms' field of the
-	// output serialized form (internal geoms would be multi themself).
-	// Else rewind location pointer so to overwrite result type.
-	if ( ntypes > 1 ) {
-		memcpy(loc, &ntypes, 4);
-		loc += 4; 
-	} else {
-		loc--; // let the type be specified later.
-	}
-	
-	if ( exploded->npoints > 1 )
-	{
-		loc[0] = lwgeom_makeType_full(
-			TYPE_HASZ(exploded->dims), TYPE_HASM(exploded->dims),
-			0, MULTIPOINTTYPE, 0);
-		loc++;
-		memcpy(loc, &exploded->npoints, 4); // numpoints
-		loc += 4; 
-	}
-	// Serialize points stripping BBOX and SRID if any
-	for (i=0; i<exploded->npoints; i++)
-	{
-		size_t subsize;
-		point = lwpoint_deserialize(exploded->points[i]);
-		point->SRID = -1;
-		lwpoint_serialize_buf(point, loc, &subsize);
-		pfree_point(point);
-		loc += subsize;
-	}
-
-	if ( exploded->nlines > 1 )
-	{
-		loc[0] = lwgeom_makeType_full(
-			TYPE_HASZ(exploded->dims),
-			TYPE_HASM(exploded->dims),
-			0, MULTILINETYPE, 0);
-		loc++;
-		memcpy(loc, &exploded->nlines, 4); // numlines
-		loc += 4; 
-	}
-	// Serialize lines stripping BBOX and SRID if any
-	for (i=0; i<exploded->nlines; i++)
-	{
-		size_t subsize;
-
-		line = lwline_deserialize(exploded->lines[i]);
-		if ( line == NULL )
-		{
-	lwerror("Error deserializing %dnt line from exploded geom", i);
-	return;
-		}
-		line->SRID = -1;
-		lwline_serialize_buf(line, loc, &subsize);
-		pfree_line(line);
-		loc += subsize;
-	}
-
-	if ( exploded->npolys > 1 )
-	{
-		loc[0] = lwgeom_makeType_full(
-			TYPE_HASZ(exploded->dims),
-			TYPE_HASM(exploded->dims),
-			0, MULTIPOLYGONTYPE, 0);
-		loc++;
-		memcpy(loc, &exploded->npolys, 4); // numpolys
-		loc += 4; 
-	}
-	// Serialize polys stripping BBOX and SRID if any
-	for (i=0; i<exploded->npolys; i++)
-	{
-		size_t subsize;
-
-		poly = lwpoly_deserialize(exploded->polys[i]);
-		if ( poly == NULL )
-		{
-	lwerror("Error deserializing %dnt polygon from exploded geom", i);
-	return;
-		}
-		poly->SRID = -1;
-		lwpoly_serialize_buf(poly, loc, &subsize);
-		pfree_polygon(poly);
-		loc += subsize;
-	}
-
-	// Register now the number of written bytes
-	if (retsize) *retsize = (loc-buf);
-
-	// Ok. now we need to add type, SRID and bbox 
-	buf[0] = lwgeom_makeType_full(
-		TYPE_HASZ(exploded->dims),
-		TYPE_HASM(exploded->dims),
-		(exploded->SRID!=-1), outtype, wantbbox);
-	loc = buf+1;
-
-	if ( wantbbox )
-	{
-		box3d = compute_serialized_box3d(buf);
-		box2d = box3d_to_box2df(box3d);
-		memcpy(loc, box2d, sizeof(BOX2DFLOAT4));
-		loc += sizeof(BOX2DFLOAT4);
-	}
-
-	if ( exploded->SRID != -1 )
-	{
-		memcpy(loc, &(exploded->SRID), 4);
-		loc += 4; // useless.. we've finished
-	}
-
-#ifdef PGIS_DEBUG
-	lwnotice("lwexploded_serialize finished");
-	lwnotice(" type: %d", lwgeom_getType(buf[0]));
-	lwnotice(" SRID: %d", lwgeom_getsrid(buf));
-	if ( lwgeom_hasBBOX(buf[0]) )
-	{
-		{
-			BOX2DFLOAT4 boxbuf;
-			getbox2d_p(buf, &boxbuf);
-			lwnotice(" BBOX: %f,%f %f,%f",
-				boxbuf.xmin, boxbuf.ymin,
-				boxbuf.xmax, boxbuf.ymax);
-		}
-	}
-	lwnotice(" numgeoms: %d", lwgeom_getnumgeometries(buf));
-#endif
-
-	return;
-}
-
-#ifdef PGIS_DEBUG_EXPLODED
-void
-checkexplodedsize(uchar *srl, LWGEOM_EXPLODED *exp, int alloced, char wantbbox)
-{
-	lwnotice("exploded len: serialized:%d computed:%d alloced:%d",
-		lwgeom_size(srl), lwexploded_findlength(exp, wantbbox),
-		alloced);
-}
-#endif
-
-size_t
-lwexploded_findlength(LWGEOM_EXPLODED *exploded, int wantbbox)
-{
-	size_t size=0;
-	char ntypes=0;
-	uint32 i;
-	
-
-	// find sum of sizes of all geoms.
-	// substract size of eventually embedded SRID and BBOXes
-	if ( exploded->npoints )
-	{
-		ntypes++;
-		for (i=0; i<exploded->npoints; i++)
-		{
-			size += lwgeom_size_point(exploded->points[i]);
-			if ( lwgeom_hasBBOX(exploded->points[i][0]) )
-				size -= sizeof(BOX2DFLOAT4);
-			if ( lwgeom_hasSRID(exploded->points[i][0]) )
-				size -= 4;
-		}
-		// add multigeom header size
-		if ( exploded->npoints > 1 )
-		{
-			size += 1; // type
-			size += 4; // numgeometries
-		}
-	}
-	if ( exploded->nlines )
-	{
-		ntypes++;
-		for (i=0; i<exploded->nlines; i++)
-		{
-			size += lwgeom_size_line(exploded->lines[i]);
-			if ( lwgeom_hasBBOX(exploded->lines[i][0]) )
-				size -= sizeof(BOX2DFLOAT4);
-			if ( lwgeom_hasSRID(exploded->lines[i][0]) )
-				size -= 4;
-		}
-		// add multigeom header size
-		if ( exploded->nlines > 1 )
-		{
-			size += 1; // type
-			size += 4; // numgeometries
-		}
-	}
-	if ( exploded->npolys )
-	{
-		ntypes++;
-		for (i=0; i<exploded->npolys; i++)
-		{
-			size += lwgeom_size_poly(exploded->polys[i]);
-			if ( lwgeom_hasBBOX(exploded->polys[i][0]) )
-				size -= sizeof(BOX2DFLOAT4);
-			if ( lwgeom_hasSRID(exploded->polys[i][0]) )
-				size -= 4;
-		}
-		// add multigeom header size
-		if ( exploded->npolys > 1 )
-		{
-			size += 1; // type
-			size += 4; // numgeometries
-		}
-	}
-
-	/* structure is empty */
-	if ( ! ntypes ) return lwgeom_empty_length(exploded->SRID);
-
-	/* multi-typed geom (collection), add collection header */
-	if ( ntypes > 1 )
-	{
-		size += 1; // type
-		size += 4; // numgeometries
-	}
-
-	/*
-	 * Add BBOX and SRID if required
-	 */
-	if ( exploded->SRID != -1 ) size += 4;
-	if ( wantbbox ) size += sizeof(BOX2DFLOAT4);
-
-	return size;
-}
 
 char
Index: lwgeom/lwgeom_box3d.c
===================================================================
RCS file: /home/cvs/postgis/postgis/lwgeom/lwgeom_box3d.c,v
retrieving revision 1.13
retrieving revision 1.15
diff -U2 -r1.13 -r1.15
--- lwgeom/lwgeom_box3d.c	18 Mar 2005 12:36:27 -0000	1.13
+++ lwgeom/lwgeom_box3d.c	23 Mar 2005 17:10:17 -0000	1.15
@@ -1,385 +1,389 @@
-/**********************************************************************
- *
- * BOX3D IO and conversions
- *
- **********************************************************************/
-
-#include <math.h>
-#include <float.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-
-#include "postgres.h"
-#include "fmgr.h"
-#include "utils/elog.h"
-#include "utils/geo_decls.h"
-
-#include "lwgeom_pg.h"
-#include "liblwgeom.h"
-
-
-//#define PGIS_DEBUG
-// basic implementation of BOX2D
-
-#define SHOW_DIGS_DOUBLE 15
-#define MAX_DIGS_DOUBLE (SHOW_DIGS_DOUBLE + 6 + 1 + 3 +1)
-
-//forward defs
-Datum BOX3D_in(PG_FUNCTION_ARGS);
-Datum BOX3D_out(PG_FUNCTION_ARGS);
-Datum LWGEOM_to_BOX3D(PG_FUNCTION_ARGS);
-Datum BOX3D_to_LWGEOM(PG_FUNCTION_ARGS);
-Datum BOX3D_expand(PG_FUNCTION_ARGS);
-Datum BOX3D_to_BOX2DFLOAT4(PG_FUNCTION_ARGS);
-Datum BOX3D_to_BOX(PG_FUNCTION_ARGS);
-Datum BOX3D_xmin(PG_FUNCTION_ARGS);
-Datum BOX3D_ymin(PG_FUNCTION_ARGS);
-Datum BOX3D_zmin(PG_FUNCTION_ARGS);
-Datum BOX3D_xmax(PG_FUNCTION_ARGS);
-Datum BOX3D_ymax(PG_FUNCTION_ARGS);
-Datum BOX3D_zmax(PG_FUNCTION_ARGS);
-Datum BOX3D_combine(PG_FUNCTION_ARGS);
-
-/*
- *  BOX3D_in - takes a string rep of BOX3D and returns internal rep
- *
- *  example:
- *     "BOX3D(x1 y1 z1,x2 y2 z2)"
- * or  "BOX3D(x1 y1,x2 y2)"   z1 and z2 = 0.0
- *
- *
- */
-
-PG_FUNCTION_INFO_V1(BOX3D_in);
-Datum BOX3D_in(PG_FUNCTION_ARGS)
-{
-	char *str = PG_GETARG_CSTRING(0);
-	int nitems;
-	BOX3D *box = (BOX3D *) palloc(sizeof(BOX3D));
-	box->zmin = 0;
-	box->zmax = 0;
-
-
-//printf( "box3d_in gets '%s'\n",str);
-
-	if (strstr(str,"BOX3D(") !=  str )
-	{
-		 pfree(box);
-		 elog(ERROR,"BOX3D parser - doesnt start with BOX3D(");
-		 PG_RETURN_NULL();
-	}
-
-	nitems = sscanf(str,"BOX3D(%le %le %le,%le %le %le)",
-		&box->xmin, &box->ymin, &box->zmin,
-		&box->xmax, &box->ymax, &box->zmax);
-	if (nitems != 6 )
-	{
-		nitems = sscanf(str,"BOX3D(%le %le,%le %le)",
-			&box->xmin, &box->ymin, &box->xmax, &box->ymax);
-		if (nitems != 4)
-		{
-			 pfree(box);
-			 elog(ERROR,"BOX3D parser - couldnt parse.  It should look like: BOX3D(xmin ymin zmin,xmax ymax zmax) or BOX3D(xmin ymin,xmax ymax)");
-			 PG_RETURN_NULL();
-		}
-	}
-
-	if (box->xmin > box->xmax)
-	{
-		float tmp = box->xmin;
-		box->xmin = box->xmax;
-		box->xmax = tmp;
-	}
-	if (box->ymin > box->ymax)
-	{
-		float tmp = box->ymin;
-		box->ymin = box->ymax;
-		box->ymax = tmp;
-	}
-	if (box->zmin > box->zmax)
-	{
-		float tmp = box->zmin;
-		box->zmin = box->zmax;
-		box->zmax = tmp;
-	}
-	PG_RETURN_POINTER(box);
-}
-
-
-/*
- *  Takes an internal rep of a BOX3D and returns a string rep.
- *
- *  example:
- *     "BOX3D(xmin ymin zmin, xmin ymin zmin)"
- */
-PG_FUNCTION_INFO_V1(BOX3D_out);
-Datum BOX3D_out(PG_FUNCTION_ARGS)
-{
-	BOX3D  *bbox = (BOX3D *) PG_GETARG_POINTER(0);
-	int size;
-	char *result;
-
-	if (bbox == NULL)
-	{
-		result = palloc(5);
-		strcat(result,"NULL");
-		PG_RETURN_CSTRING(result);
-	}
-
-	size = MAX_DIGS_DOUBLE*6+5+2+4+5+1;
-	result = (char *) palloc(size); //double digits+ "BOX3D"+ "()" + commas +null
-	sprintf(result, "BOX3D(%.15g %.15g %.15g,%.15g %.15g %.15g)",
-			bbox->xmin, bbox->ymin, bbox->zmin,
-			bbox->xmax,bbox->ymax,bbox->zmax);
-
-	PG_RETURN_CSTRING(result);
-}
-
-PG_FUNCTION_INFO_V1(BOX3D_to_BOX2DFLOAT4);
-Datum BOX3D_to_BOX2DFLOAT4(PG_FUNCTION_ARGS)
-{
-	BOX3D *in = (BOX3D *)PG_GETARG_POINTER(0);
-	BOX2DFLOAT4 *out = box3d_to_box2df(in);
-	PG_RETURN_POINTER(out);
-}
-
-PG_FUNCTION_INFO_V1(BOX3D_to_BOX);
-Datum BOX3D_to_BOX(PG_FUNCTION_ARGS)
-{
-	BOX3D *in = (BOX3D *)PG_GETARG_POINTER(0);
-	BOX2DFLOAT4 *box2d = box3d_to_box2df(in);
-	BOX *box = palloc(sizeof(BOX));
-
-	box2df_to_box_p(box2d, box);
-	PG_RETURN_POINTER(box);
-}
-
-PG_FUNCTION_INFO_V1(BOX3D_to_LWGEOM);
-Datum BOX3D_to_LWGEOM(PG_FUNCTION_ARGS)
-{
-	BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
-	POINT2D *pts = palloc(sizeof(POINT2D)*5);
-	POINTARRAY *pa[1];
-	LWPOLY *poly;
-	int wantbbox = 0;
-	PG_LWGEOM *result;
-	char *ser;
-
-	// Assign coordinates to POINT2D array
-	pts[0].x = box->xmin; pts[0].y = box->ymin;
-	pts[1].x = box->xmin; pts[1].y = box->ymax;
-	pts[2].x = box->xmax; pts[2].y = box->ymax;
-	pts[3].x = box->xmax; pts[3].y = box->ymin;
-	pts[4].x = box->xmin; pts[4].y = box->ymin;
-
-	// Construct point array
-	pa[0] = palloc(sizeof(POINTARRAY));
-	pa[0]->serialized_pointlist = (char *)pts;
-	TYPE_SETZM(pa[0]->dims, 0, 0);
-	pa[0]->npoints = 5;
-
-	// Construct polygon
-	poly = lwpoly_construct(-1, NULL, 1, pa);
-
-	// Serialize polygon
-	ser = lwpoly_serialize(poly);
-
-	// Construct PG_LWGEOM 
-	result = PG_LWGEOM_construct(ser, -1, wantbbox);
-	
-	PG_RETURN_POINTER(result);
-}
-
-/* Expand given box of 'd' units in all directions */
-void
-expand_box3d(BOX3D *box, double d)
-{
-	box->xmin -= d;
-	box->ymin -= d;
-	box->zmin -= d;
-
-	box->xmax += d;
-	box->ymax += d;
-	box->zmax += d;
-}
-
-PG_FUNCTION_INFO_V1(BOX3D_expand);
-Datum BOX3D_expand(PG_FUNCTION_ARGS)
-{
-	BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
-	double d = PG_GETARG_FLOAT8(1);
-	BOX3D *result = (BOX3D *)palloc(sizeof(BOX3D));
-
-	memcpy(result, box, sizeof(BOX3D));
-	expand_box3d(result, d);
-
-	PG_RETURN_POINTER(result);
-}
-
-/*
- * convert a PG_LWGEOM to BOX3D
- *
- * NOTE: the bounding box is *always* recomputed as the cache
- * is a box2d, not a box3d...
- *
- */
-PG_FUNCTION_INFO_V1(LWGEOM_to_BOX3D);
-Datum LWGEOM_to_BOX3D(PG_FUNCTION_ARGS)
-{
-	PG_LWGEOM *lwgeom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
-	BOX3D *result;
-
-	result = compute_serialized_box3d(SERIALIZED_FORM(lwgeom));
-
-	PG_RETURN_POINTER(result);
-}
-
-PG_FUNCTION_INFO_V1(BOX3D_xmin);
-Datum BOX3D_xmin(PG_FUNCTION_ARGS)
-{
-	BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
-	PG_RETURN_FLOAT8(box->xmin);
-}
-
-PG_FUNCTION_INFO_V1(BOX3D_ymin);
-Datum BOX3D_ymin(PG_FUNCTION_ARGS)
-{
-	BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
-	PG_RETURN_FLOAT8(box->ymin);
-}
-
-PG_FUNCTION_INFO_V1(BOX3D_zmin);
-Datum BOX3D_zmin(PG_FUNCTION_ARGS)
-{
-	BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
-	PG_RETURN_FLOAT8(box->zmin);
-}
-
-PG_FUNCTION_INFO_V1(BOX3D_xmax);
-Datum BOX3D_xmax(PG_FUNCTION_ARGS)
-{
-	BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
-	PG_RETURN_FLOAT8(box->xmax);
-}
-
-PG_FUNCTION_INFO_V1(BOX3D_ymax);
-Datum BOX3D_ymax(PG_FUNCTION_ARGS)
-{
-	BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
-	PG_RETURN_FLOAT8(box->ymax);
-}
-
-PG_FUNCTION_INFO_V1(BOX3D_zmax);
-Datum BOX3D_zmax(PG_FUNCTION_ARGS)
-{
-	BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
-	PG_RETURN_FLOAT8(box->zmax);
-}
-
-
-PG_FUNCTION_INFO_V1(BOX3D_combine);
-Datum BOX3D_combine(PG_FUNCTION_ARGS)
-{
-	Pointer box3d_ptr = PG_GETARG_POINTER(0);
-	Pointer geom_ptr = PG_GETARG_POINTER(1);
-	BOX3D *a,*b;
-	PG_LWGEOM *lwgeom;
-	BOX3D *box, *result;
-
-	if  ( (box3d_ptr == NULL) && (geom_ptr == NULL) )
-	{
-		PG_RETURN_NULL(); 
-	}
-
-	result = (BOX3D *)palloc(sizeof(BOX3D));
-
-	if (box3d_ptr == NULL)
-	{
-		lwgeom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
-		box = compute_serialized_box3d(SERIALIZED_FORM(lwgeom));
-		if ( ! box ) {
-			PG_FREE_IF_COPY(lwgeom, 1);
-			PG_RETURN_NULL(); // must be the empty geom
-		}
-		memcpy(result, box, sizeof(BOX3D));
-		PG_RETURN_POINTER(result);
-	}
-
-	// combine_bbox(BOX3D, null) => BOX3D
-	if (geom_ptr == NULL)
-	{
-		memcpy(result, (char *)PG_GETARG_DATUM(0), sizeof(BOX3D));
-		PG_RETURN_POINTER(result);
-	}
-
-	lwgeom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
-	box = compute_serialized_box3d(SERIALIZED_FORM(lwgeom));
-	if ( ! box ) // must be the empty geom
-	{
-		PG_FREE_IF_COPY(lwgeom, 1);
-		memcpy(result, (char *)PG_GETARG_DATUM(0), sizeof(BOX3D));
-		PG_RETURN_POINTER(result);
-	}
-
-	a = (BOX3D *)PG_GETARG_DATUM(0);
-	b = box;
-
-	result->xmax = LWGEOM_Maxd(a->xmax, b->xmax);
-	result->ymax = LWGEOM_Maxd(a->ymax, b->ymax);
-	result->zmax = LWGEOM_Maxd(a->zmax, b->zmax);
-	result->xmin = LWGEOM_Mind(a->xmin, b->xmin);
-	result->ymin = LWGEOM_Mind(a->ymin, b->ymin);
-	result->zmin = LWGEOM_Mind(a->zmin, b->zmin);
-
-	PG_RETURN_POINTER(result);
-}
-
-PG_FUNCTION_INFO_V1(BOX3D_construct);
-Datum BOX3D_construct(PG_FUNCTION_ARGS)
-{
-	PG_LWGEOM *min = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
-	PG_LWGEOM *max = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
-	BOX3D *result = palloc(sizeof(BOX3D));
-	LWGEOM *minpoint, *maxpoint;
-	POINT3DZ minp, maxp;
-
-	minpoint = lwgeom_deserialize(SERIALIZED_FORM(min));
-	maxpoint = lwgeom_deserialize(SERIALIZED_FORM(max));
-
-	if ( TYPE_GETTYPE(minpoint->type) != POINTTYPE ||
-		TYPE_GETTYPE(maxpoint->type) != POINTTYPE )
-	{
-		elog(ERROR, "BOX2DFLOAT4_construct: args must be points");
-		PG_RETURN_NULL();
-	}
-
-	getPoint3dz_p(((LWPOINT *)minpoint)->point, 0, &minp);
-	getPoint3dz_p(((LWPOINT *)maxpoint)->point, 0, &maxp);
-
-	result->xmax = maxp.x;
-	result->ymax = maxp.y;
-	result->zmax = maxp.z;
-
-	result->xmin = minp.x;
-	result->ymin = minp.y;
-	result->zmin = minp.z;
-
-	PG_RETURN_POINTER(result);
-}
-
-//min(a,b)
-double LWGEOM_Mind(double a, double b)
-{
-	if (a<b)
-		return a;
-	return b;
-}
-
-//max(a,b)
-double LWGEOM_Maxd(double a, double b)
-{
-	if (b>a)
-		return b;
-	return a;
-}
+/**********************************************************************
+ *
+ * BOX3D IO and conversions
+ *
+ **********************************************************************/
+
+#include <math.h>
+#include <float.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "postgres.h"
+#include "fmgr.h"
+#include "utils/elog.h"
+#include "utils/geo_decls.h"
+
+#include "lwgeom_pg.h"
+#include "liblwgeom.h"
+
+
+//#define PGIS_DEBUG
+// basic implementation of BOX2D
+
+#define SHOW_DIGS_DOUBLE 15
+#define MAX_DIGS_DOUBLE (SHOW_DIGS_DOUBLE + 6 + 1 + 3 +1)
+
+//forward defs
+Datum BOX3D_in(PG_FUNCTION_ARGS);
+Datum BOX3D_out(PG_FUNCTION_ARGS);
+Datum LWGEOM_to_BOX3D(PG_FUNCTION_ARGS);
+Datum BOX3D_to_LWGEOM(PG_FUNCTION_ARGS);
+Datum BOX3D_expand(PG_FUNCTION_ARGS);
+Datum BOX3D_to_BOX2DFLOAT4(PG_FUNCTION_ARGS);
+Datum BOX3D_to_BOX(PG_FUNCTION_ARGS);
+Datum BOX3D_xmin(PG_FUNCTION_ARGS);
+Datum BOX3D_ymin(PG_FUNCTION_ARGS);
+Datum BOX3D_zmin(PG_FUNCTION_ARGS);
+Datum BOX3D_xmax(PG_FUNCTION_ARGS);
+Datum BOX3D_ymax(PG_FUNCTION_ARGS);
+Datum BOX3D_zmax(PG_FUNCTION_ARGS);
+Datum BOX3D_combine(PG_FUNCTION_ARGS);
+
+/*
+ *  BOX3D_in - takes a string rep of BOX3D and returns internal rep
+ *
+ *  example:
+ *     "BOX3D(x1 y1 z1,x2 y2 z2)"
+ * or  "BOX3D(x1 y1,x2 y2)"   z1 and z2 = 0.0
+ *
+ *
+ */
+
+PG_FUNCTION_INFO_V1(BOX3D_in);
+Datum BOX3D_in(PG_FUNCTION_ARGS)
+{
+	char *str = PG_GETARG_CSTRING(0);
+	int nitems;
+	BOX3D *box = (BOX3D *) palloc(sizeof(BOX3D));
+	box->zmin = 0;
+	box->zmax = 0;
+
+
+//printf( "box3d_in gets '%s'\n",str);
+
+	if (strstr(str,"BOX3D(") !=  str )
+	{
+		 pfree(box);
+		 elog(ERROR,"BOX3D parser - doesnt start with BOX3D(");
+		 PG_RETURN_NULL();
+	}
+
+	nitems = sscanf(str,"BOX3D(%le %le %le,%le %le %le)",
+		&box->xmin, &box->ymin, &box->zmin,
+		&box->xmax, &box->ymax, &box->zmax);
+	if (nitems != 6 )
+	{
+		nitems = sscanf(str,"BOX3D(%le %le,%le %le)",
+			&box->xmin, &box->ymin, &box->xmax, &box->ymax);
+		if (nitems != 4)
+		{
+			 pfree(box);
+			 elog(ERROR,"BOX3D parser - couldnt parse.  It should look like: BOX3D(xmin ymin zmin,xmax ymax zmax) or BOX3D(xmin ymin,xmax ymax)");
+			 PG_RETURN_NULL();
+		}
+	}
+
+	if (box->xmin > box->xmax)
+	{
+		float tmp = box->xmin;
+		box->xmin = box->xmax;
+		box->xmax = tmp;
+	}
+	if (box->ymin > box->ymax)
+	{
+		float tmp = box->ymin;
+		box->ymin = box->ymax;
+		box->ymax = tmp;
+	}
+	if (box->zmin > box->zmax)
+	{
+		float tmp = box->zmin;
+		box->zmin = box->zmax;
+		box->zmax = tmp;
+	}
+	PG_RETURN_POINTER(box);
+}
+
+
+/*
+ *  Takes an internal rep of a BOX3D and returns a string rep.
+ *
+ *  example:
+ *     "BOX3D(xmin ymin zmin, xmin ymin zmin)"
+ */
+PG_FUNCTION_INFO_V1(BOX3D_out);
+Datum BOX3D_out(PG_FUNCTION_ARGS)
+{
+	BOX3D  *bbox = (BOX3D *) PG_GETARG_POINTER(0);
+	int size;
+	char *result;
+
+	if (bbox == NULL)
+	{
+		result = palloc(5);
+		strcat(result,"NULL");
+		PG_RETURN_CSTRING(result);
+	}
+
+	size = MAX_DIGS_DOUBLE*6+5+2+4+5+1;
+	result = (char *) palloc(size); //double digits+ "BOX3D"+ "()" + commas +null
+	sprintf(result, "BOX3D(%.15g %.15g %.15g,%.15g %.15g %.15g)",
+			bbox->xmin, bbox->ymin, bbox->zmin,
+			bbox->xmax,bbox->ymax,bbox->zmax);
+
+	PG_RETURN_CSTRING(result);
+}
+
+PG_FUNCTION_INFO_V1(BOX3D_to_BOX2DFLOAT4);
+Datum BOX3D_to_BOX2DFLOAT4(PG_FUNCTION_ARGS)
+{
+	BOX3D *in = (BOX3D *)PG_GETARG_POINTER(0);
+	BOX2DFLOAT4 *out = box3d_to_box2df(in);
+	PG_RETURN_POINTER(out);
+}
+
+PG_FUNCTION_INFO_V1(BOX3D_to_BOX);
+Datum BOX3D_to_BOX(PG_FUNCTION_ARGS)
+{
+	BOX3D *in = (BOX3D *)PG_GETARG_POINTER(0);
+	BOX2DFLOAT4 *box2d = box3d_to_box2df(in);
+	BOX *box = palloc(sizeof(BOX));
+
+	box2df_to_box_p(box2d, box);
+	PG_RETURN_POINTER(box);
+}
+
+PG_FUNCTION_INFO_V1(BOX3D_to_LWGEOM);
+Datum BOX3D_to_LWGEOM(PG_FUNCTION_ARGS)
+{
+	BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
+	POINT2D *pts = palloc(sizeof(POINT2D)*5);
+	POINTARRAY *pa[1];
+	LWPOLY *poly;
+	int wantbbox = 0;
+	PG_LWGEOM *result;
+	char *ser;
+
+	// Assign coordinates to POINT2D array
+	pts[0].x = box->xmin; pts[0].y = box->ymin;
+	pts[1].x = box->xmin; pts[1].y = box->ymax;
+	pts[2].x = box->xmax; pts[2].y = box->ymax;
+	pts[3].x = box->xmax; pts[3].y = box->ymin;
+	pts[4].x = box->xmin; pts[4].y = box->ymin;
+
+	// Construct point array
+	pa[0] = palloc(sizeof(POINTARRAY));
+	pa[0]->serialized_pointlist = (char *)pts;
+	TYPE_SETZM(pa[0]->dims, 0, 0);
+	pa[0]->npoints = 5;
+
+	// Construct polygon
+	poly = lwpoly_construct(-1, NULL, 1, pa);
+
+	// Serialize polygon
+	ser = lwpoly_serialize(poly);
+
+	// Construct PG_LWGEOM 
+	result = PG_LWGEOM_construct(ser, -1, wantbbox);
+	
+	PG_RETURN_POINTER(result);
+}
+
+/* Expand given box of 'd' units in all directions */
+void
+expand_box3d(BOX3D *box, double d)
+{
+	box->xmin -= d;
+	box->ymin -= d;
+	box->zmin -= d;
+
+	box->xmax += d;
+	box->ymax += d;
+	box->zmax += d;
+}
+
+PG_FUNCTION_INFO_V1(BOX3D_expand);
+Datum BOX3D_expand(PG_FUNCTION_ARGS)
+{
+	BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
+	double d = PG_GETARG_FLOAT8(1);
+	BOX3D *result = (BOX3D *)palloc(sizeof(BOX3D));
+
+	memcpy(result, box, sizeof(BOX3D));
+	expand_box3d(result, d);
+
+	PG_RETURN_POINTER(result);
+}
+
+/*
+ * convert a PG_LWGEOM to BOX3D
+ *
+ * NOTE: the bounding box is *always* recomputed as the cache
+ * is a box2d, not a box3d...
+ *
+ */
+PG_FUNCTION_INFO_V1(LWGEOM_to_BOX3D);
+Datum LWGEOM_to_BOX3D(PG_FUNCTION_ARGS)
+{
+	PG_LWGEOM *lwgeom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+	BOX3D *result;
+
+	result = compute_serialized_box3d(SERIALIZED_FORM(lwgeom));
+	if ( ! result ) PG_RETURN_NULL();
+
+	PG_RETURN_POINTER(result);
+}
+
+PG_FUNCTION_INFO_V1(BOX3D_xmin);
+Datum BOX3D_xmin(PG_FUNCTION_ARGS)
+{
+	BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
+	PG_RETURN_FLOAT8(box->xmin);
+}
+
+PG_FUNCTION_INFO_V1(BOX3D_ymin);
+Datum BOX3D_ymin(PG_FUNCTION_ARGS)
+{
+	BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
+	PG_RETURN_FLOAT8(box->ymin);
+}
+
+PG_FUNCTION_INFO_V1(BOX3D_zmin);
+Datum BOX3D_zmin(PG_FUNCTION_ARGS)
+{
+	BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
+	PG_RETURN_FLOAT8(box->zmin);
+}
+
+PG_FUNCTION_INFO_V1(BOX3D_xmax);
+Datum BOX3D_xmax(PG_FUNCTION_ARGS)
+{
+	BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
+	PG_RETURN_FLOAT8(box->xmax);
+}
+
+PG_FUNCTION_INFO_V1(BOX3D_ymax);
+Datum BOX3D_ymax(PG_FUNCTION_ARGS)
+{
+	BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
+	PG_RETURN_FLOAT8(box->ymax);
+}
+
+PG_FUNCTION_INFO_V1(BOX3D_zmax);
+Datum BOX3D_zmax(PG_FUNCTION_ARGS)
+{
+	BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
+	PG_RETURN_FLOAT8(box->zmax);
+}
+
+
+PG_FUNCTION_INFO_V1(BOX3D_combine);
+Datum BOX3D_combine(PG_FUNCTION_ARGS)
+{
+	Pointer box3d_ptr = PG_GETARG_POINTER(0);
+	Pointer geom_ptr = PG_GETARG_POINTER(1);
+	BOX3D *a,*b;
+	PG_LWGEOM *lwgeom;
+	BOX3D *box, *result;
+
+	if  ( (box3d_ptr == NULL) && (geom_ptr == NULL) )
+	{
+		PG_RETURN_NULL(); 
+	}
+
+	result = (BOX3D *)palloc(sizeof(BOX3D));
+
+	if (box3d_ptr == NULL)
+	{
+		lwgeom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
+		box = compute_serialized_box3d(SERIALIZED_FORM(lwgeom));
+		if ( ! box ) {
+			PG_FREE_IF_COPY(lwgeom, 1);
+			PG_RETURN_NULL(); // must be the empty geom
+		}
+		memcpy(result, box, sizeof(BOX3D));
+		PG_RETURN_POINTER(result);
+	}
+
+	// combine_bbox(BOX3D, null) => BOX3D
+	if (geom_ptr == NULL)
+	{
+		memcpy(result, (char *)PG_GETARG_DATUM(0), sizeof(BOX3D));
+		PG_RETURN_POINTER(result);
+	}
+
+	lwgeom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
+	box = compute_serialized_box3d(SERIALIZED_FORM(lwgeom));
+	if ( ! box ) // must be the empty geom
+	{
+		PG_FREE_IF_COPY(lwgeom, 1);
+		memcpy(result, (char *)PG_GETARG_DATUM(0), sizeof(BOX3D));
+		PG_RETURN_POINTER(result);
+	}
+
+	a = (BOX3D *)PG_GETARG_DATUM(0);
+	b = box;
+
+	result->xmax = LWGEOM_Maxd(a->xmax, b->xmax);
+	result->ymax = LWGEOM_Maxd(a->ymax, b->ymax);
+	result->zmax = LWGEOM_Maxd(a->zmax, b->zmax);
+	result->xmin = LWGEOM_Mind(a->xmin, b->xmin);
+	result->ymin = LWGEOM_Mind(a->ymin, b->ymin);
+	result->zmin = LWGEOM_Mind(a->zmin, b->zmin);
+
+	PG_RETURN_POINTER(result);
+}
+
+PG_FUNCTION_INFO_V1(BOX3D_construct);
+Datum BOX3D_construct(PG_FUNCTION_ARGS)
+{
+	PG_LWGEOM *min = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+	PG_LWGEOM *max = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
+	BOX3D *result = palloc(sizeof(BOX3D));
+	LWGEOM *minpoint, *maxpoint;
+	POINT3DZ minp, maxp;
+
+	minpoint = lwgeom_deserialize(SERIALIZED_FORM(min));
+	maxpoint = lwgeom_deserialize(SERIALIZED_FORM(max));
+
+	if ( TYPE_GETTYPE(minpoint->type) != POINTTYPE ||
+		TYPE_GETTYPE(maxpoint->type) != POINTTYPE )
+	{
+		elog(ERROR, "BOX2DFLOAT4_construct: args must be points");
+		PG_RETURN_NULL();
+	}
+
+	getPoint3dz_p(((LWPOINT *)minpoint)->point, 0, &minp);
+	getPoint3dz_p(((LWPOINT *)maxpoint)->point, 0, &maxp);
+
+	result->xmax = maxp.x;
+	result->ymax = maxp.y;
+	result->zmax = maxp.z;
+
+	result->xmin = minp.x;
+	result->ymin = minp.y;
+	result->zmin = minp.z;
+
+	PG_RETURN_POINTER(result);
+}
+
+//min(a,b)
+double
+LWGEOM_Mind(double a, double b)
+{
+	if (a<b)
+		return a;
+	return b;
+}
+
+//max(a,b)
+double
+LWGEOM_Maxd(double a, double b)
+{
+	if (b>a)
+		return b;
+	return a;
+}
+
Index: regress/regress.sql
===================================================================
RCS file: /home/cvs/postgis/postgis/regress/regress.sql,v
retrieving revision 1.9
retrieving revision 1.10
diff -U2 -r1.9 -r1.10
--- regress/regress.sql	11 Mar 2005 17:47:33 -0000	1.9
+++ regress/regress.sql	23 Mar 2005 16:29:17 -0000	1.10
@@ -229,2 +229,6 @@
 
 select '136', distance('POINT(0 0)', translate('POINT(0 0)', 5, 12, 0));
+
+select '137', box3d('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION EMPTY)'::geometry);
+select '138', box3d('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION EMPTY, POINT(0 0))'::geometry);
+
Index: regress/regress_expected
===================================================================
RCS file: /home/cvs/postgis/postgis/regress/regress_expected,v
retrieving revision 1.9
retrieving revision 1.10
diff -U2 -r1.9 -r1.10
--- regress/regress_expected	11 Mar 2005 17:47:33 -0000	1.9
+++ regress/regress_expected	23 Mar 2005 16:29:17 -0000	1.10
@@ -137,2 +137,4 @@
 135|13
 136|13
+137|
+138|BOX3D(0 0 0,0 0 0)


More information about the postgis-devel mailing list