diff --git a/src/backend/access/rtree/rtproc.c b/src/backend/access/rtree/rtproc.c
index 932feec0b391e8c86e6fad62a9d329c5a250e570..ac7a3abfecfb8d591981b6f512300fa0c19e6269 100644
--- a/src/backend/access/rtree/rtproc.c
+++ b/src/backend/access/rtree/rtproc.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtproc.c,v 1.6 1997/03/14 23:17:41 scrappy Exp $
+ *    $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtproc.c,v 1.7 1997/04/22 17:31:23 scrappy Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -30,10 +30,10 @@ BOX
     if ((n = (BOX *) palloc(sizeof (*n))) == (BOX *) NULL)
 	elog(WARN, "Cannot allocate box for union");
     
-    n->xh = Max(a->xh, b->xh);
-    n->yh = Max(a->yh, b->yh);
-    n->xl = Min(a->xl, b->xl);
-    n->yl = Min(a->yl, b->yl);
+    n->high.x = Max(a->high.x, b->high.x);
+    n->high.y = Max(a->high.y, b->high.y);
+    n->low.x = Min(a->low.x, b->low.x);
+    n->low.y = Min(a->low.y, b->low.y);
     
     return (n);
 }
@@ -46,12 +46,12 @@ rt_box_inter(BOX *a, BOX *b)
     if ((n = (BOX *) palloc(sizeof (*n))) == (BOX *) NULL)
 	elog(WARN, "Cannot allocate box for union");
     
-    n->xh = Min(a->xh, b->xh);
-    n->yh = Min(a->yh, b->yh);
-    n->xl = Max(a->xl, b->xl);
-    n->yl = Max(a->yl, b->yl);
+    n->high.x = Min(a->high.x, b->high.x);
+    n->high.y = Min(a->high.y, b->high.y);
+    n->low.x = Max(a->low.x, b->low.x);
+    n->low.y = Max(a->low.y, b->low.y);
     
-    if (n->xh < n->xl || n->yh < n->yl) {
+    if (n->high.x < n->low.x || n->high.y < n->low.y) {
 	pfree(n);
 	return ((BOX *) NULL);
     }
@@ -62,10 +62,10 @@ rt_box_inter(BOX *a, BOX *b)
 void
 rt_box_size(BOX *a, float *size)
 {
-    if (a == (BOX *) NULL || a->xh <= a->xl || a->yh <= a->yl)
+    if (a == (BOX *) NULL || a->high.x <= a->low.x || a->high.y <= a->low.y)
 	*size = 0.0;
     else
-	*size = (float) ((a->xh - a->xl) * (a->yh - a->yl));
+	*size = (float) ((a->high.x - a->low.x) * (a->high.y - a->low.y));
     
     return;
 }
@@ -97,10 +97,10 @@ rt_poly_union(POLYGON *a, POLYGON *b)
     memset((char *) p, 0, sizeof(POLYGON));	/* zero any holes */
     p->size = sizeof(POLYGON);
     p->npts = 0;
-    p->boundbox.xh = Max(a->boundbox.xh, b->boundbox.xh);
-    p->boundbox.yh = Max(a->boundbox.yh, b->boundbox.yh);
-    p->boundbox.xl = Min(a->boundbox.xl, b->boundbox.xl);
-    p->boundbox.yl = Min(a->boundbox.yl, b->boundbox.yl);
+    p->boundbox.high.x = Max(a->boundbox.high.x, b->boundbox.high.x);
+    p->boundbox.high.y = Max(a->boundbox.high.y, b->boundbox.high.y);
+    p->boundbox.low.x = Min(a->boundbox.low.x, b->boundbox.low.x);
+    p->boundbox.low.y = Min(a->boundbox.low.y, b->boundbox.low.y);
     return p;
 }
 
@@ -111,12 +111,12 @@ rt_poly_size(POLYGON *a, float *size)
     
     size = (float *) palloc(sizeof(float));
     if (a == (POLYGON *) NULL || 
-	a->boundbox.xh <= a->boundbox.xl || 
-	a->boundbox.yh <= a->boundbox.yl)
+	a->boundbox.high.x <= a->boundbox.low.x || 
+	a->boundbox.high.y <= a->boundbox.low.y)
 	*size = 0.0;
     else {
-	xdim = (a->boundbox.xh - a->boundbox.xl);
-	ydim = (a->boundbox.yh - a->boundbox.yl);
+	xdim = (a->boundbox.high.x - a->boundbox.low.x);
+	ydim = (a->boundbox.high.y - a->boundbox.low.y);
 	
 	*size = (float) (xdim * ydim);
     }
@@ -137,12 +137,12 @@ rt_poly_inter(POLYGON *a, POLYGON *b)
     memset((char *) p, 0, sizeof(POLYGON));	/* zero any holes */
     p->size = sizeof(POLYGON);
     p->npts = 0;
-    p->boundbox.xh = Min(a->boundbox.xh, b->boundbox.xh);
-    p->boundbox.yh = Min(a->boundbox.yh, b->boundbox.yh);
-    p->boundbox.xl = Max(a->boundbox.xl, b->boundbox.xl);
-    p->boundbox.yl = Max(a->boundbox.yl, b->boundbox.yl);
+    p->boundbox.high.x = Min(a->boundbox.high.x, b->boundbox.high.x);
+    p->boundbox.high.y = Min(a->boundbox.high.y, b->boundbox.high.y);
+    p->boundbox.low.x = Max(a->boundbox.low.x, b->boundbox.low.x);
+    p->boundbox.low.y = Max(a->boundbox.low.y, b->boundbox.low.y);
     
-    if (p->boundbox.xh < p->boundbox.xl || p->boundbox.yh < p->boundbox.yl)
+    if (p->boundbox.high.x < p->boundbox.low.x || p->boundbox.high.y < p->boundbox.low.y)
 	{
 	    pfree(p);
 	    return ((POLYGON *) NULL);
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 32d8d6358ec0cad25bd6eaa0e100cdd083ffb4f4..4dacd09f1c6c5bd5104caa97522142c5fdfd22ce 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -1,32 +1,247 @@
 /*-------------------------------------------------------------------------
  *
- * geo-ops.c--
+ * geo_ops.c--
  *    2D geometric operations
  *
  * Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/backend/utils/adt/geo_ops.c,v 1.2 1997/03/14 23:20:15 scrappy Exp $
+ *    $Header: /cvsroot/pgsql/src/backend/utils/adt/geo_ops.c,v 1.3 1997/04/22 17:31:32 scrappy Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include <math.h>
-#include <float.h>	/* faked on sunos */
+#include <float.h>
 #include <stdio.h>	/* for sprintf proto, etc. */
+#include <stdlib.h>	/* for strtod, etc. */
 #include <string.h>
+#include <ctype.h>
 
 #include "postgres.h"
 
 #include "utils/geo_decls.h"
 #include "utils/palloc.h"
 
+#define OLD_FORMAT_IN	1
+#define OLD_FORMAT_OUT	0
+
+/*
+ * Delimiters for input and output strings.
+ * LDELIM, RDELIM, and DELIM are left, right, and separator delimiters, respectively.
+ * LDELIM_EP, RDELIM_EP are left and right delimiters for paths with endpoints.
+ */
+
 #define LDELIM		'('
 #define RDELIM		')'
 #define	DELIM		','
-#define BOXNARGS	4
-#define	LSEGNARGS	4
-#define	POINTNARGS	2
+#define LDELIM_EP	'['
+#define RDELIM_EP	']'
+#define LDELIM_C	'<'
+#define RDELIM_C	'>'
+
+/* Maximum number of output digits printed */
+#define P_MAXDIG DBL_DIG
+#define P_MAXLEN (2*(P_MAXDIG+7)+1)
+
+static int digits8 = P_MAXDIG;
+
+int geo_precision(int digits);
+
+int geo_precision(int digits)
+{
+    if (digits > P_MAXDIG) {
+	digits8 = P_MAXDIG;
+    } else if (digits > 0) {
+	digits8 = digits;
+    };
+    return digits8;
+}
+
+/*
+ * Geometric data types are composed of points.
+ * This code tries to support a common format throughout the data types,
+ *  to allow for more predictable usage and data type conversion.
+ * The fundamental unit is the point. Other units are line segments,
+ *  open paths, boxes, closed paths, and polygons (which should be considered
+ *  non-intersecting closed paths).
+ *
+ * Data representation is as follows:
+ *  point:		(x,y)
+ *  line segment:	[(x1,y1),(x2,y2)]
+ *  box:		(x1,y1),(x2,y2)
+ *  open path:		[(x1,y1),...,(xn,yn)]
+ *  closed path:	((x1,y1),...,(xn,yn))
+ *  polygon:		((x1,y1),...,(xn,yn))
+ *
+ * For boxes, the points are opposite corners with the first point at the top right.
+ * For closed paths and polygons, the points should be reordered to allow
+ *  fast and correct equality comparisons.
+ *
+ * XXX perhaps points in complex shapes should be reordered internally
+ *  to allow faster internal operations, but should keep track of input order
+ *  and restore that order for text output - tgl 97/01/16
+ */
+
+int pair_decode(char *str, float8 *x, float8 *y, char **s);
+int pair_encode(float8 x, float8 y, char *str);
+int pair_count(char *s, char delim);
+int path_decode(int opentype, int npts, char *str, int *isopen, char **ss, Point *p);
+
+char *path_encode( bool closed, int npts, Point *pt);
+
+int pair_decode(char *str, float8 *x, float8 *y, char **s)
+{
+    int has_delim;
+    char *cp;
+
+    if (!PointerIsValid((char *)str))
+	return(FALSE);
+
+    while (isspace( *str)) str++;
+    if ((has_delim = (*str == LDELIM))) str++;
+
+    while (isspace( *str)) str++;
+    *x = strtod( str, &cp);
+    if (cp <= str) return(FALSE);
+    while (isspace( *cp)) cp++;
+    if (*cp++ != DELIM) return(FALSE);
+    while (isspace( *cp)) cp++;
+    *y = strtod( cp, &str);
+    if (str <= cp) return(FALSE);
+    while (isspace( *str)) str++;
+    if (has_delim) {
+	if (*str != RDELIM) return(FALSE);
+	str++;
+	while (isspace( *str)) str++;
+    };
+    if (s != NULL) *s = str;
+
+    return(TRUE);
+}
+
+int pair_encode(float8 x, float8 y, char *str)
+{
+    (void) sprintf(str, "%.*g,%.*g", digits8, x, digits8, y);
+    return(TRUE);
+}
+
+int path_decode(int opentype, int npts, char *str, int *isopen, char **ss, Point *p)
+{
+    int depth = 0;
+    char *s, *cp;
+    int i;
+
+    s = str;
+    while (isspace( *s)) s++;
+    if ((*isopen = (*s == LDELIM_EP))) {
+	/* no open delimiter allowed? */
+	if (! opentype) return(FALSE);
+	depth++;
+	s++;
+	while (isspace( *s)) s++;
+
+    } else if (*s == LDELIM) {
+	cp = (s+1);
+	while (isspace( *cp)) cp++;
+	if (*cp == LDELIM) {
+	    /* nested delimiters with only one point? */
+	    if (npts <= 1) return(FALSE);
+	    depth++;
+	    s = cp;
+	} else if (strrchr( s, LDELIM) == s) {
+	    depth++;
+	    s = cp;
+	};
+    };
+
+    for (i = 0; i < npts; i++) {
+	if (! pair_decode( s, &(p->x), &(p->y), &s))
+	    return(FALSE);
+
+	if (*s == DELIM) s++;
+	p++;
+    };
+
+    while (depth > 0) {
+	if ((*s == RDELIM)
+         || ((*s == RDELIM_EP) && (*isopen) && (depth == 1))) {
+	    depth--;
+	    s++;
+	    while (isspace( *s)) s++;
+	} else {
+	    return(FALSE);
+	};
+    };
+    *ss = s;
+
+    return(TRUE);
+} /* path_decode() */
+
+char *path_encode( bool closed, int npts, Point *pt)
+{
+    char *result;
+
+    char *cp;
+    int i;
+
+    if (!PointerIsValid(result = (char *)PALLOC(npts*(P_MAXLEN+3)+2)))
+	elog(WARN, "Memory allocation failed, can't output path", NULL);
+
+    cp = result;
+    switch (closed) {
+    case TRUE:
+	*cp++ = LDELIM;
+	break;
+    case FALSE:
+	*cp++ = LDELIM_EP;
+	break;
+    default:
+	break;
+    };
+
+    for (i = 0; i < npts; i++) {
+        *cp++ = LDELIM;
+	if (! pair_encode( pt->x, pt->y, cp))
+	  elog (WARN, "Unable to format path", NULL);
+	cp += strlen(cp);
+	*cp++ = RDELIM;
+	*cp++ = DELIM;
+	pt++;
+    };
+    cp--;
+    switch (closed) {
+    case TRUE:
+	*cp++ = RDELIM;
+	break;
+    case FALSE:
+	*cp++ = RDELIM_EP;
+	break;
+    default:
+	break;
+    };
+    *cp = '\0';
+
+    return(result);
+} /* path_encode() */
+
+/*-------------------------------------------------------------
+ * pair_count - count the number of points
+ * allow the following notation:
+ * '((1,2),(3,4))'
+ * '(1,3,2,4)'
+ * require an odd number of delim characters in the string
+ *-------------------------------------------------------------*/
+int pair_count(char *s, char delim)
+{
+    int ndelim = 0;
+
+    while ((s = strchr( s, delim)) != NULL) {
+	ndelim++;
+	s++;
+    };
+    return((ndelim % 2)? ((ndelim+1)/2): -1);
+}
 
 /***********************************************************************
  **
@@ -40,57 +255,76 @@
 
 /*	box_in	-	convert a string to internal form.
  *
- *	str:	input string "(f8, f8, f8, f8)"
+ *	External format: (two corners of box)
+ *		"(f8, f8), (f8, f8)"
+ *		also supports the older style "(f8, f8, f8, f8)"
  */
 BOX *box_in(char *str)
 {
-    double	tmp;
-    char	*p, *coord[BOXNARGS];
-    int	i;
-    BOX	*result;
-    
-    if (str == NULL)
-	elog (WARN," Bad (null) box external representation");
-    
-    if ((p = (char *)strchr(str, LDELIM)) == (char *)NULL)
+    BOX	*box;
+
+    int isopen;
+    char *s;
+    double x, y;
+
+    if (!PointerIsValid((char *)str))
+	elog (WARN," Bad (null) box external representation",NULL);
+
+    if (!PointerIsValid(box = PALLOCTYPE(BOX)))
+      elog(WARN, "Memory allocation failed, can't input box '%s'",str);
+
+    if ((! path_decode(FALSE, 2, str, &isopen, &s, &(box->high)))
+      || (*s != '\0'))
 	elog (WARN, "Bad box external representation '%s'",str);
-    for (i = 0, p = str; *p && i < BOXNARGS && *p != RDELIM; p++)
-	if (*p == DELIM || (*p == LDELIM && !i))
-	    coord[i++] = p + 1;
-    if (i < BOXNARGS - 1)
-	elog (WARN, "Bad box external representation '%s'", str);
-    result = PALLOCTYPE(BOX);
-    result->xh = atof(coord[0]);
-    result->yh = atof(coord[1]);
-    result->xl = atof(coord[2]);
-    result->yl = atof(coord[3]);
-    if (result->xh < result->xl) {
-	tmp = result->xh;
-	result->xh = result->xl;
-	result->xl = tmp;
-    }
-    if (result->yh < result->yl) {
-	tmp = result->yh;
-	result->yh = result->yl;
-	result->yl = tmp;
-    }
-    
-    return(result);
+
+    /* reorder corners if necessary... */
+    if (box->high.x < box->low.x) {
+	x = box->high.x;
+	box->high.x = box->low.x;
+	box->low.x = x;
+    };
+    if (box->high.y < box->low.y) {
+	y = box->high.y;
+	box->high.y = box->low.y;
+	box->low.y = y;
+    };
+
+    return(box);
 }
 
 /*	box_out	-	convert a box to external form.
  */
 char *box_out(BOX *box)
 {
-    char	*result;
-    
-    if (box == NULL)
+#if OLD_FORMAT_OUT
+    char *result;
+
+    char *cp;
+#endif
+
+    if (!PointerIsValid((char *)box))
 	return(NULL);
-    result = (char *)PALLOC(80);
-    (void) sprintf(result, "(%G,%G,%G,%G)",
-		   box->xh, box->yh, box->xl, box->yl);
-    
-    return(result);
+
+#if OLD_FORMAT_OUT
+    if (!PointerIsValid(result = (char *)PALLOC(2*(P_MAXLEN+1)+2)))
+	elog(WARN, "Memory allocation failed, can't output box", NULL);
+
+    cp = result;
+    *cp++ = LDELIM;
+    if (! pair_encode( box->high.x, box->high.y, cp))
+	  elog (WARN, "Unable to format box", NULL);
+    cp += strlen(cp);
+    *cp++ = DELIM;
+    if (! pair_encode( box->low.x, box->low.y, cp))
+	  elog (WARN, "Unable to format box", NULL);
+    cp += strlen(cp);
+    *cp++ = RDELIM;
+    *cp = '\0';
+
+    return( result);
+#else
+    return( path_encode( -1, 2, (Point *) &(box->high)));
+#endif
 }
 
 
@@ -109,22 +343,20 @@ BOX *box_construct(double x1, double x2, double y1, double y2)
  */
 BOX *box_fill(BOX *result, double x1, double x2, double y1, double y2)
 {
-    double	tmp;
-    
-    result->xh = x1;
-    result->xl = x2;
-    result->yh = y1;
-    result->yl = y2;
-    if (result->xh < result->xl) {
-	tmp = result->xh;
-	result->xh = result->xl;
-	result->xl = tmp;
-    }
-    if (result->yh < result->yl) {
-	tmp = result->yh;
-	result->yh = result->yl;
-	result->yl = tmp;
-    }
+    if (x1 > x2) {
+	result->high.x = x1;
+	result->low.x = x2;
+    } else {
+	result->high.x = x2;
+	result->low.x = x1;
+    };
+    if (y1 > y2) {
+	result->high.y = y1;
+	result->low.y = y2;
+    } else {
+	result->high.y = y2;
+	result->low.y = y1;
+    };
     
     return(result);
 }
@@ -150,20 +382,20 @@ BOX *box_copy(BOX *box)
 
 /*	box_same	-	are two boxes identical?
  */
-long box_same(BOX *box1, BOX *box2)
+bool box_same(BOX *box1, BOX *box2)
 {
-    return((box1->xh == box2->xh && box1->xl == box2->xl) &&
-	   (box1->yh == box2->yh && box1->yl == box2->yl));
+    return((FPeq(box1->high.x,box2->high.x) && FPeq(box1->low.x,box2->low.x)) &&
+	  (FPeq(box1->high.y,box2->high.y) && FPeq(box1->low.y,box2->low.y)));
 }
 
 /*	box_overlap	-	does box1 overlap box2?
  */
-long box_overlap(BOX *box1, BOX *box2)
+bool box_overlap(BOX *box1, BOX *box2)
 {
-    return(((box1->xh >= box2->xh && box1->xl <= box2->xh) ||
-	    (box2->xh >= box1->xh && box2->xl <= box1->xh)) &&
-	   ((box1->yh >= box2->yh && box1->yl <= box2->yh) ||
-	    (box2->yh >= box1->yh && box2->yl <= box1->yh)) );
+    return(((FPge(box1->high.x,box2->high.x) && FPle(box1->low.x,box2->high.x)) ||
+	    (FPge(box2->high.x,box1->high.x) && FPle(box2->low.x,box1->high.x))) &&
+	   ((FPge(box1->high.y,box2->high.y) && FPle(box1->low.y,box2->high.y)) ||
+	    (FPge(box2->high.y,box1->high.y) && FPle(box2->low.y,box1->high.y))) );
 }
 
 /*	box_overleft	-	is the right edge of box1 to the left of
@@ -172,23 +404,23 @@ long box_overlap(BOX *box1, BOX *box2)
  *	This is "less than or equal" for the end of a time range,
  *	when time ranges are stored as rectangles.
  */
-long box_overleft(BOX *box1, BOX *box2)
+bool box_overleft(BOX *box1, BOX *box2)
 {
-    return(box1->xh <= box2->xh);
+    return(FPle(box1->high.x,box2->high.x));
 }
 
 /*	box_left	-	is box1 strictly left of box2?
  */
-long box_left(BOX *box1, BOX *box2)
+bool box_left(BOX *box1, BOX *box2)
 {
-    return(box1->xh < box2->xl);
+    return(FPlt(box1->high.x,box2->low.x));
 }
 
 /*	box_right	-	is box1 strictly right of box2?
  */
-long box_right(BOX *box1, BOX *box2)
+bool box_right(BOX *box1, BOX *box2)
 {
-    return(box1->xl > box2->xh);
+    return(FPgt(box1->low.x,box2->high.x));
 }
 
 /*	box_overright	-	is the left edge of box1 to the right of
@@ -197,66 +429,66 @@ long box_right(BOX *box1, BOX *box2)
  *	This is "greater than or equal" for time ranges, when time ranges
  *	are stored as rectangles.
  */
-long box_overright(BOX *box1, BOX *box2)
+bool box_overright(BOX *box1, BOX *box2)
 {
-    return(box1->xl >= box2->xl);
+    return(box1->low.x >= box2->low.x);
 }
 
 /*	box_contained	-	is box1 contained by box2?
  */
-long box_contained(BOX *box1, BOX *box2)
+bool box_contained(BOX *box1, BOX *box2)
 {
-    return((box1->xh <= box2->xh && box1->xl >= box2->xl &&
-	    box1->yh <= box2->yh && box1->yl >= box2->yl));
+    return((FPle(box1->high.x,box2->high.x) && FPge(box1->low.x,box2->low.x)) &&
+	   (FPle(box1->high.y,box2->high.y) && FPge(box1->low.y,box2->low.y)));
 }
 
 /*	box_contain	-	does box1 contain box2?
  */
-long box_contain(BOX *box1, BOX *box2)
+bool box_contain(BOX *box1, BOX *box2)
 {
-    return((box1->xh >= box2->xh && box1->xl <= box2->xl &&
-	    box1->yh >= box2->yh && box1->yl <= box2->yl));
+    return((FPge(box1->high.x,box2->high.x) && FPle(box1->low.x,box2->low.x) &&
+	    FPge(box1->high.y,box2->high.y) && FPle(box1->low.y,box2->low.y)));
 }
 
 
 /*	box_positionop	-
- *		is box1 entirely {above, below } box2?
+ *		is box1 entirely {above,below} box2?
  */
-long box_below(BOX *box1, BOX *box2)
+bool box_below(BOX *box1, BOX *box2)
 {
-    return( box1->yh <= box2->yl );
+    return( FPle(box1->high.y,box2->low.y) );
 }
 
-long box_above(BOX *box1, BOX *box2)
+bool box_above(BOX *box1, BOX *box2)
 {
-    return( box1->yl >= box2->yh );
+    return( FPge(box1->low.y,box2->high.y) );
 }
 
 
 /*	box_relop	-	is area(box1) relop area(box2), within
  *			  	our accuracy constraint?
  */
-long box_lt(BOX *box1, BOX *box2)
+bool box_lt(BOX *box1, BOX *box2)
 {
     return( FPlt(box_ar(box1), box_ar(box2)) );
 }
 
-long box_gt(BOX *box1, BOX *box2)
+bool box_gt(BOX *box1, BOX *box2)
 {
     return( FPgt(box_ar(box1), box_ar(box2)) );
 }
 
-long box_eq(BOX *box1, BOX *box2)
+bool box_eq(BOX *box1, BOX *box2)
 {
     return( FPeq(box_ar(box1), box_ar(box2)) );
 }
 
-long box_le(BOX	*box1, BOX *box2)
+bool box_le(BOX	*box1, BOX *box2)
 {
     return( FPle(box_ar(box1), box_ar(box2)) );
 }
 
-long box_ge(BOX	*box1, BOX *box2)
+bool box_ge(BOX	*box1, BOX *box2)
 {
     return( FPge(box_ar(box1), box_ar(box2)) );
 }
@@ -292,7 +524,7 @@ double *box_length(BOX *box)
     double	*result;
     
     result = PALLOCTYPE(double);
-    *result = box->xh - box->xl;
+    *result = box->high.x - box->low.x;
     
     return(result);
 }
@@ -306,7 +538,7 @@ double *box_height(BOX *box)
     double	*result;
     
     result = PALLOCTYPE(double);
-    *result = box->yh - box->yl;
+    *result = box->high.y - box->low.y;
     
     return(result);
 }
@@ -318,7 +550,7 @@ double *box_height(BOX *box)
 double *box_distance(BOX *box1, BOX *box2)
 {
     double	*result;
-    Point	*box_center(), *a, *b;
+    Point	*a, *b;
     
     result = PALLOCTYPE(double);
     a = box_center(box1);
@@ -338,8 +570,8 @@ Point *box_center(BOX *box)
     Point	*result;
     
     result = PALLOCTYPE(Point);
-    result->x = (box->xh + box->xl) / 2.0;
-    result->y = (box->yh + box->yl) / 2.0;
+    result->x = (box->high.x + box->low.x) / 2.0;
+    result->y = (box->high.y + box->low.y) / 2.0;
     
     return(result);
 }
@@ -358,7 +590,7 @@ double box_ar(BOX *box)
  */
 double box_ln(BOX *box)
 {
-    return( box->xh - box->xl );
+    return( box->high.x - box->low.x );
 }
 
 
@@ -367,7 +599,7 @@ double box_ln(BOX *box)
  */
 double box_ht(BOX *box)
 {
-    return( box->yh - box->yl );
+    return( box->high.y - box->low.y );
 }
 
 
@@ -377,8 +609,7 @@ double box_ht(BOX *box)
 double box_dt(BOX *box1, BOX *box2)
 {
     double	result;
-    Point	*box_center(),
-    *a, *b;
+    Point	*a, *b;
     
     a = box_center(box1);
     b = box_center(box2);
@@ -400,15 +631,14 @@ double box_dt(BOX *box1, BOX *box2)
 BOX *box_intersect(BOX	*box1, BOX *box2)
 {
     BOX	*result;
-    long	box_overlap();
-    
+
     if (! box_overlap(box1,box2))
 	return(NULL);
     result = PALLOCTYPE(BOX);
-    result->xh = Min(box1->xh, box2->xh);
-    result->xl = Max(box1->xl, box2->xl);
-    result->yh = Min(box1->yh, box2->yh);
-    result->yl = Max(box1->yl, box2->yl);
+    result->high.x = Min(box1->high.x, box2->high.x);
+    result->low.x = Max(box1->low.x, box2->low.x);
+    result->high.y = Min(box1->high.y, box2->high.y);
+    result->low.y = Max(box1->low.y, box2->low.y);
     
     return(result);
 }
@@ -423,10 +653,10 @@ LSEG *box_diagonal(BOX *box)
 {
     Point	p1, p2;
     
-    p1.x = box->xh;
-    p1.y = box->yh;
-    p2.x = box->xl;
-    p2.y = box->yl;
+    p1.x = box->high.x;
+    p1.y = box->high.y;
+    p2.x = box->low.x;
+    p2.y = box->low.y;
     return( lseg_construct( &p1, &p2 ) );
     
 }
@@ -486,17 +716,17 @@ line_construct_pp(Point *pt1, Point *pt2)
  *  Relative position routines.
  *---------------------------------------------------------*/
 
-long line_intersect(LINE *l1, LINE *l2)
+bool line_intersect(LINE *l1, LINE *l2)
 {
     return( ! line_parallel(l1, l2) );
 }
 
-long line_parallel(LINE *l1, LINE *l2)
+bool line_parallel(LINE *l1, LINE *l2)
 {
     return( FPeq(l1->m, l2->m) );
 }
 
-long line_perp(LINE *l1, LINE *l2)
+bool line_perp(LINE *l1, LINE *l2)
 {
     if (l1->m)
 	return( FPeq(l2->m / l1->m, -1.0) );
@@ -505,18 +735,18 @@ long line_perp(LINE *l1, LINE *l2)
     return(1);	/* both 0.0 */
 }
 
-long line_vertical(LINE *line)
+bool line_vertical(LINE *line)
 {
     return( FPeq(line->A, -1.0) && FPzero(line->B) );
 }
 
-long line_horizontal(LINE *line)
+bool line_horizontal(LINE *line)
 {
     return( FPzero(line->m) );
 }
 
 
-long line_eq(LINE *l1, LINE *l2)
+bool line_eq(LINE *l1, LINE *l2)
 {
     double	k;
     
@@ -589,88 +819,116 @@ line_interpt(LINE *l1, LINE *l2)
  **
  ***********************************************************************/
 
-#define	PATHALLOCSIZE(N) \
-    (long) ((unsigned) (sizeof(PATH) + \
-			(((N)-1) > 0 ? ((N)-1) : 0) \
-			* sizeof(Point)))
-
 /*----------------------------------------------------------
  *  String to path / path to string conversion.
  *	External format: 
+ *		"((xcoord, ycoord),... )"
+ *		"[(xcoord, ycoord),... ]"
+ *		"(xcoord, ycoord),... "
+ *		"[xcoord, ycoord,... ]"
+ *	Also support older format:
  *		"(closed, npts, xcoord, ycoord,... )"
  *---------------------------------------------------------*/
 
 PATH *path_in(char *str)
 {
-    double	coord;
-    long	field[2];
-    char	*s;
-    int	ct, i;
-    PATH	*result;
-    long	pathsize;
-    
-    if (str == NULL)
+    PATH *path;
+
+    int isopen;
+    char *s;
+    int npts;
+    int size;
+#if OLD_FORMAT_IN
+    int oldstyle = FALSE;
+    double x, y;
+#endif
+
+    if (!PointerIsValid((char *)str))
 	elog(WARN, "Bad (null) path external representation");
-    
-    /* read the path header information */
-    for (i = 0, s = str; *s && i < 2 && *s != RDELIM; ++s)
-	if (*s == DELIM || (*s == LDELIM && !i))
-	    field[i++] = atol(s + 1);
-    if (i < 1)
-	elog(WARN, "Bad path external representation '%s'", str);
-    pathsize = PATHALLOCSIZE(field[1]);
-    result = (PATH *)palloc(pathsize);
-    result->length = pathsize;
-    result->closed = field[0];
-    result->npts =  field[1];
-    
-    /* read the path points */
-    
-    ct = result->npts * 2;	/* two coords for every point */
-    for (i = 0;
-	 *s && i < ct && *s != RDELIM; 
-	 ++s) {
-	if (*s == ',') {
-	    coord = atof(s + 1);
-	    if (i % 2)
-		(result->p[i/2]).y = coord;
-	    else
-		(result->p[i/2]).x = coord;
-	    ++i;
-	}
-    }
-    if (i % 2 || i < --ct) {
-	PFREE(result);
+
+    if ((npts = pair_count(str, ',')) <= 0)
 	elog(WARN, "Bad path external representation '%s'", str);
-    } 
-    
-    return(result);
+
+#if OLD_FORMAT_IN
+    s = str;
+    while (isspace( *s)) s++;
+    /* identify old style format as having only one left delimiter in string... */
+    oldstyle = ((*s == LDELIM) && (strrchr( s, LDELIM) == s));
+
+    /* old-style format? then first two fields are closed flag and point count... */
+    if (oldstyle) {
+	s++;
+	if ((! pair_decode( s, &x, &y, &s)) || (*s++ != DELIM)
+	  || ((x != 0) && (x != 1)) || (y <= 0))
+	    elog (WARN, "Bad path external representation '%s'",str);
+	isopen = (x == 0);
+	npts = y;
+    };
+#endif
+
+    size = offsetof(PATH, p[0]) + (sizeof(path->p[0]) * npts);
+    if (!PointerIsValid(path = PALLOC(size)))
+	elog(WARN, "Memory allocation failed, can't input path '%s'",str);
+
+    path->size = size;
+    path->npts =  npts;
+    if (oldstyle) path->closed = (! isopen);
+
+#if OLD_FORMAT_IN
+    if ((! path_decode(TRUE, npts, s, &isopen, &s, &(path->p[0])))
+     || ! (oldstyle? (*s++ == RDELIM): (*s == '\0')))
+#else
+    if ((! path_decode(TRUE, npts, s, &isopen, &s, &(path->p[0])))
+     || (*s != '\0'))
+#endif
+	elog (WARN, "Bad path external representation '%s'",str);
+
+#if OLD_FORMAT_IN
+    if (oldstyle) {
+	while (isspace( *s)) s++;
+	if (*s != '\0')
+	    elog (WARN, "Bad path external representation '%s'",str);
+    };
+#endif
+
+    if (! oldstyle) path->closed = (! isopen);
+
+    return(path);
 }
 
 
 char *path_out(PATH *path)
 {
-    char 		buf[BUFSIZ + 20000], *result, *s;
-    int		i;
-    char	tmp[64];
-    
-    if (path == NULL)
-	return(NULL);
-    (void) sprintf(buf,"%c%d,%d", LDELIM, 
-		   path->closed, path->npts);
-    s = buf + strlen(buf);
-    for (i = 0; i < path->npts; ++i) {
-	(void) sprintf(tmp, ",%G,%G", 
-		       path->p[i].x, path->p[i].y);
-	(void) strcpy(s, tmp);
-	s += strlen(tmp);
-    }
-    *s++ = RDELIM;
-    *s = '\0';
-    result = (char *)PALLOC(strlen(buf) + 1);
-    (void) strcpy(result, buf);
-    
+#if OLD_FORMAT_OUT
+    int i;
+    char *result, *cp;
+#endif
+
+    if (!PointerIsValid((char *)path))
+	return NULL;
+
+#if OLD_FORMAT_OUT
+    if (!PointerIsValid(result = (char *)PALLOC(path->npts*(P_MAXLEN+3)+2)))
+	elog(WARN, "Memory allocation failed, can't output path", NULL);
+
+    cp = result;
+    *cp++ = LDELIM;
+    if (! pair_encode( path->closed, path->npts, cp))
+	elog (WARN, "Unable to format path", NULL);
+    cp += strlen(cp);
+
+    for (i=0; i<path->npts; i++) {
+        *cp++ = DELIM;
+	if (! pair_encode( path->p[i].x, path->p[i].y, cp))
+	    elog (WARN, "Unable to format path", NULL);
+	cp += strlen(cp);
+    };
+    *cp++ = RDELIM;
+    *cp = '\0';
     return(result);
+#else
+    return( path_encode( path->closed, path->npts, (Point *) &(path->p[0])));
+#endif
 }
 
 
@@ -682,55 +940,133 @@ char *path_out(PATH *path)
  *	Better relops and access methods coming soon.
  *---------------------------------------------------------*/
 
-long path_n_lt(PATH *p1, PATH *p2)
+bool path_n_lt(PATH *p1, PATH *p2)
 {
     return( (p1->npts < p2->npts ) );
 }
 
-long path_n_gt(PATH *p1, PATH *p2)
+bool path_n_gt(PATH *p1, PATH *p2)
 {
     return( (p1->npts > p2->npts ) );
 }
 
-long path_n_eq(PATH *p1, PATH *p2)
+bool path_n_eq(PATH *p1, PATH *p2)
 {
     return( (p1->npts == p2->npts) );
 }
 
-long path_n_le(PATH *p1, PATH *p2)
+bool path_n_le(PATH *p1, PATH *p2)
 {
     return( (p1->npts <= p2->npts ) );
 }
 
-long path_n_ge(PATH *p1, PATH *p2)
+bool path_n_ge(PATH *p1, PATH *p2)
 {
     return( (p1->npts >= p2->npts ) );
 }
 
+
+/*----------------------------------------------------------
+ * Conversion operators.
+ *---------------------------------------------------------*/
+
+PATH *path_copy(PATH *path);
+
+bool
+path_isclosed( PATH *path)
+{
+    if (!PointerIsValid((char *)path))
+	return FALSE;
+
+    return(path->closed);
+} /* path_isclosed() */
+
+bool
+path_isopen( PATH *path)
+{
+    if (!PointerIsValid((char *)path))
+	return FALSE;
+
+    return(! path->closed);
+} /* path_isopen() */
+
+
+int4
+path_npoints( PATH *path)
+{
+    if (!PointerIsValid((char *)path))
+	return 0;
+
+    return(path->npts);
+} /* path_npoints() */
+
+PATH *
+path_close(PATH *path)
+{
+    PATH *result;
+
+    if (PointerIsValid((char *)result = path_copy(path)))
+	result->closed = TRUE;
+
+    return(result);
+} /* path_close() */
+
+PATH *
+path_open(PATH *path)
+{
+    PATH *result;
+
+    if (PointerIsValid((char *)result = path_copy(path)))
+	result->closed = FALSE;
+
+    return(result);
+} /* path_open() */
+
+
+PATH *
+path_copy(PATH *path)
+{
+    PATH *result;
+    int size;
+
+    if (!PointerIsValid((char *)path))
+	return NULL;
+
+    size = offsetof(PATH, p[0]) + (sizeof(path->p[0]) * path->npts);
+    if (!PointerIsValid(result = PALLOC(size)))
+	elog(WARN, "Memory allocation failed, can't copy path",NULL);
+
+    memmove((char *) result, (char *) path, size);
+    return(result);
+} /* path_copy() */
+
+
 /* path_inter -
  *	Does p1 intersect p2 at any point?
  *	Use bounding boxes for a quick (O(n)) check, then do a 
  *	O(n^2) iterative edge check.
  */
-long path_inter(PATH *p1, PATH *p2)
+bool path_inter(PATH *p1, PATH *p2)
 {
     BOX	b1, b2;
     int	i, j;
     LSEG seg1, seg2;
     
-    b1.xh = b1.yh = b2.xh = b2.yh = (double)DBL_MAX;
-    b1.xl = b1.yl = b2.xl = b2.yl = -(double)DBL_MAX;
-    for (i = 0; i < p1->npts; ++i) {
-	b1.xh = Max(p1->p[i].x, b1.xh);
-	b1.yh = Max(p1->p[i].y, b1.yh);
-	b1.xl = Min(p1->p[i].x, b1.xl);
-	b1.yl = Min(p1->p[i].y, b1.yl);
+    b1.high.x = b1.low.x = p1->p[0].x;
+    b1.high.y = b1.low.y = p1->p[0].y;
+    for (i = 1; i < p1->npts; i++) {
+	b1.high.x = Max(p1->p[i].x, b1.high.x);
+	b1.high.y = Max(p1->p[i].y, b1.high.y);
+	b1.low.x = Min(p1->p[i].x, b1.low.x);
+	b1.low.y = Min(p1->p[i].y, b1.low.y);
     }
-    for (i = 0; i < p2->npts; ++i) {
-	b2.xh = Max(p2->p[i].x, b2.xh);
-	b2.yh = Max(p2->p[i].y, b2.yh);
-	b2.xl = Min(p2->p[i].x, b2.xl);
-	b2.yl = Min(p2->p[i].y, b2.yl);
+    b2.high.x = b2.low.x = p2->p[0].x;
+    b2.high.y = b2.low.y = p2->p[0].y;
+    for (i = 1; i < p2->npts; i++) {
+	b2.high.x = Max(p2->p[i].x, b2.high.x);
+	b2.high.y = Max(p2->p[i].y, b2.high.y);
+	b2.low.x = Min(p2->p[i].x, b2.low.x);
+	b2.low.y = Min(p2->p[i].y, b2.low.y);
     }
     if (! box_overlap(&b1, &b2))
 	return(0);
@@ -753,25 +1089,31 @@ long path_inter(PATH *p1, PATH *p2)
    two paths, and finds the min distance between any two lsegs */
 double *path_distance(PATH *p1, PATH *p2)
 {
-    double *min, *tmp;
+    double *min = NULL, *tmp;
     int i,j;
     LSEG seg1, seg2;
-    
+
+/*
     statlseg_construct(&seg1, &p1->p[0], &p1->p[1]);
     statlseg_construct(&seg2, &p2->p[0], &p2->p[1]);
     min = lseg_distance(&seg1, &seg2);
-    
+*/
+
     for (i = 0; i < p1->npts - 1; i++)
 	for (j = 0; j < p2->npts - 1; j++)
 	    {
 		statlseg_construct(&seg1, &p1->p[i], &p1->p[i+1]);
 		statlseg_construct(&seg2, &p2->p[j], &p2->p[j+1]);
 		
-		if (*min < *(tmp = lseg_distance(&seg1, &seg2)))
-		    *min = *tmp;
-		PFREE(tmp);
+		tmp = lseg_distance(&seg1, &seg2);
+		if ((min == NULL) || (*min < *tmp)) {
+		    if (min != NULL) PFREE(min);
+		    min = tmp;
+		} else {
+		    PFREE(tmp);
+		};
 	    }
-    
+
     return(min);
 }
 
@@ -782,12 +1124,12 @@ double *path_distance(PATH *p1, PATH *p2)
 
 double *path_length(PATH *path)
 {
-    double	*result;
+    double *result;
     int	ct, i;
     
     result = PALLOCTYPE(double);
     ct = path->npts - 1;
-    for (i = 0; i < ct; ++i)
+    for (i = 0; i < ct; i++)
 	*result += point_dt(&path->p[i], &path->p[i+1]);
     
     return(result);
@@ -797,11 +1139,11 @@ double *path_length(PATH *path)
 
 double path_ln(PATH *path)
 {
-    double	result;
+    double result;
     int	ct, i;
     
     ct = path->npts - 1;
-    for (result = i = 0; i < ct; ++i)
+    for (result = i = 0; i < ct; i++)
 	result += point_dt(&path->p[i], &path->p[i+1]);
     
     return(result);
@@ -814,52 +1156,49 @@ double path_ln(PATH *path)
 
 /*----------------------------------------------------------
  *  String to point, point to string conversion.
- *	External form:	"(x, y)"
+ *	External format:
+ *		"(x,y)"
+ *		"x,y"
  *---------------------------------------------------------*/
 
-Point *point_in(char *str)
+Point *
+point_in(char *str)
 {
-    char	*coord[POINTNARGS], *p, *r;
-    int	i;
-    Point	*result;
+    Point *point;
+
+    double x, y;
+    char *s;
     
-    if (str == NULL)
+    if (str == NULL) {
 	elog(WARN, "Bad (null) point external representation");
-    
-    if ((p = (char *)strchr(str, LDELIM)) == (char *)NULL)
-	elog (WARN, "Bad point external representation '%s'",str);
-    for (i = 0, p++; *p && i < POINTNARGS-1 && *p != RDELIM; p = r+1)
-	if ((r = (char *)strchr(p, DELIM)) == (char *)NULL)
-	    elog (WARN, "Bad point external representation '%s'",str);
-	else	
-	    coord[i++] = p;
-    if ((r = (char *)strchr(p, RDELIM)) == (char *)NULL)
-	elog (WARN, "Bad point external representation '%s'",str);
-    coord[i++] = p;
-    
-    if (i < POINTNARGS - 1)
-	elog(WARN, "Bad point external representation '%s'",str);
-    result = PALLOCTYPE(Point);
-    result->x = atof(coord[0]);
-    result->y = atof(coord[1]);
-    return(result);
-}
+	return NULL;
+    }
+
+    if (! pair_decode( str, &x, &y, &s) || (strlen(s) > 0))
+      elog (WARN, "Bad point external representation '%s'",str);
 
-char *point_out(Point *pt)
+    if (!PointerIsValid(point = PALLOCTYPE(Point)))
+      elog (WARN, "Unable to allocate point storage for '%s'",str);
+
+    point->x = x;
+    point->y = y;
+
+    return(point);
+} /* point_in() */
+
+char *
+point_out(Point *pt)
 {
-    char	*result;
-    
-    if (pt == NULL)
+    if (!PointerIsValid((char *)pt))
 	return(NULL);
-    result = (char *)PALLOC(40);
-    (void) sprintf(result, "(%G,%G)", pt->x, pt->y);
-    return(result);
-}
+
+    return( path_encode( -1, 1, pt));
+} /* point_out() */
 
 
 Point *point_construct(double x, double y)
 {
-    Point	*result;
+    Point *result;
     
     result = PALLOCTYPE(Point);
     result->x = x;
@@ -870,7 +1209,7 @@ Point *point_construct(double x, double y)
 
 Point *point_copy(Point *pt)
 {
-    Point	*result;
+    Point *result;
     
     result = PALLOCTYPE(Point);
     result->x = pt->x;
@@ -888,37 +1227,37 @@ Point *point_copy(Point *pt)
  *	EPSILON = 0.0).
  *---------------------------------------------------------*/
 
-long point_left(Point *pt1, Point *pt2)
+bool point_left(Point *pt1, Point *pt2)
 {
     return( FPlt(pt1->x, pt2->x) );
 }
 
-long point_right(Point *pt1, Point *pt2)
+bool point_right(Point *pt1, Point *pt2)
 {
     return( FPgt(pt1->x, pt2->x) );
 }
 
-long point_above(Point *pt1, Point *pt2)
+bool point_above(Point *pt1, Point *pt2)
 {
     return( FPgt(pt1->y, pt2->y) );
 }
 
-long point_below(Point *pt1, Point *pt2)
+bool point_below(Point *pt1, Point *pt2)
 {
     return( FPlt(pt1->y, pt2->y) );
 }
 
-long point_vert(Point *pt1, Point *pt2)
+bool point_vert(Point *pt1, Point *pt2)
 {
     return( FPeq( pt1->x, pt2->x ) );
 }
 
-long point_horiz(Point *pt1, Point *pt2)
+bool point_horiz(Point *pt1, Point *pt2)
 {
     return( FPeq( pt1->y, pt2->y ) );
 }
 
-long point_eq(Point *pt1, Point *pt2)
+bool point_eq(Point *pt1, Point *pt2)
 {
     return( point_horiz(pt1, pt2) && point_vert(pt1, pt2) );
 }
@@ -927,9 +1266,9 @@ long point_eq(Point *pt1, Point *pt2)
  *  "Arithmetic" operators on points.
  *---------------------------------------------------------*/
 
-long pointdist(Point *p1, Point *p2)
+int32 pointdist(Point *p1, Point *p2)
 {
-    long result;
+    int32 result;
     
     result = point_dt(p1, p2);
     return(result);
@@ -937,7 +1276,7 @@ long pointdist(Point *p1, Point *p2)
 
 double *point_distance(Point *pt1, Point *pt2)
 {
-    double	*result;
+    double *result;
     
     result = PALLOCTYPE(double);
     *result = HYPOT( pt1->x - pt2->x, pt1->y - pt2->y );
@@ -952,7 +1291,7 @@ double point_dt(Point *pt1, Point *pt2)
 
 double *point_slope(Point *pt1, Point *pt2)
 {
-    double	*result;
+    double *result;
     
     result = PALLOCTYPE(double);
     if (point_vert(pt1, pt2))
@@ -970,6 +1309,7 @@ double point_sl(Point *pt1, Point *pt2)
 	   : (pt1->y - pt2->y) / (pt1->x - pt2->x) );
 }
 
+
 /***********************************************************************
  **
  ** 	Routines for 2D line segments.
@@ -978,46 +1318,42 @@ double point_sl(Point *pt1, Point *pt2)
 
 /*----------------------------------------------------------
  *  String to lseg, lseg to string conversion.
- *	External form:	"(id, info, x1, y1, x2, y2)"
+ *	External forms:	"[(x1, y1), (x2, y2)]"
+ *			"(x1, y1), (x2, y2)"
+ *			"x1, y1, x2, y2"
+ *	closed form ok	"((x1, y1), (x2, y2))"
+ *	(old form)	"(x1, y1, x2, y2)"
  *---------------------------------------------------------*/
 
 LSEG *lseg_in(char *str)
 {
-    char	*coord[LSEGNARGS], *p;
-    int	i;
-    LSEG	*result;
-    
-    if (str == NULL)
-	elog (WARN," Bad (null) box external representation");
-    
-    if ((p = (char *)strchr(str, LDELIM)) == (char *)NULL)
+    LSEG *lseg;
+
+    int isopen;
+    char *s;
+
+    if (!PointerIsValid((char *)str))
+	elog (WARN," Bad (null) lseg external representation",NULL);
+
+    if (!PointerIsValid(lseg = PALLOCTYPE(LSEG)))
+      elog(WARN, "Memory allocation failed, can't input lseg '%s'",str);
+
+    if ((! path_decode(TRUE, 2, str, &isopen, &s, &(lseg->p[0])))
+      || (*s != '\0'))
 	elog (WARN, "Bad lseg external representation '%s'",str);
-    for (i = 0, p = str; *p && i < LSEGNARGS && *p != RDELIM; p++)
-	if (*p == DELIM || (*p == LDELIM && !i))
-	    coord[i++] = p + 1;
-    if (i < LSEGNARGS - 1)
-	elog (WARN, "Bad lseg external representation '%s'", str);
-    result = PALLOCTYPE(LSEG);
-    result->p[0].x = atof(coord[0]);
-    result->p[0].y = atof(coord[1]);
-    result->p[1].x = atof(coord[2]);
-    result->p[1].y = atof(coord[3]);
-    result->m = point_sl(&result->p[0], &result->p[1]);
+
+    lseg->m = point_sl(&lseg->p[0], &lseg->p[1]);
     
-    return(result);
+    return(lseg);
 }
 
 
 char *lseg_out(LSEG *ls)
 {
-    char	*result;
-    
-    if (ls == NULL)
+    if (!PointerIsValid((char *)ls))
 	return(NULL);
-    result = (char *)PALLOC(80);
-    (void) sprintf(result, "(%G,%G,%G,%G)",
-		   ls->p[0].x, ls->p[0].y, ls->p[1].x, ls->p[1].y);
-    return(result);
+
+    return( path_encode( FALSE, 2, (Point *) &(ls->p[0])));
 }
 
 
@@ -1033,6 +1369,7 @@ LSEG *lseg_construct(Point *pt1, Point *pt2)
     result->p[0].y = pt1->y;
     result->p[1].x = pt2->x;
     result->p[1].y = pt2->y;
+
     result->m = point_sl(pt1, pt2);
     
     return(result);
@@ -1045,6 +1382,7 @@ void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2)
     lseg->p[0].y = pt1->y;
     lseg->p[1].x = pt2->x;
     lseg->p[1].y = pt2->y;
+
     lseg->m = point_sl(pt1, pt2);
 }
 
@@ -1056,29 +1394,29 @@ void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2)
  **  find intersection of the two lines, and see if it falls on 
  **  both segments.
  */
-long lseg_intersect(LSEG *l1, LSEG *l2)
+bool lseg_intersect(LSEG *l1, LSEG *l2)
 {
     LINE *ln;
     Point *interpt;
-    long retval;
+    bool retval;
     
     ln = line_construct_pp(&l2->p[0], &l2->p[1]);
     interpt = interpt_sl(l1, ln);
     
     if (interpt != NULL && on_ps(interpt, l2)) /* interpt on l1 and l2 */
-	retval = 1;
-    else retval = 0;
+	retval = TRUE;
+    else retval = FALSE;
     if (interpt != NULL) PFREE(interpt);
     PFREE(ln);
     return(retval);
 }
 
-long lseg_parallel(LSEG *l1, LSEG *l2)
+bool lseg_parallel(LSEG *l1, LSEG *l2)
 {
     return( FPeq(l1->m, l2->m) );
 }
 
-long lseg_perp(LSEG *l1, LSEG *l2)
+bool lseg_perp(LSEG *l1, LSEG *l2)
 {
     if (! FPzero(l1->m))
 	return( FPeq(l2->m / l1->m, -1.0) );
@@ -1087,18 +1425,18 @@ long lseg_perp(LSEG *l1, LSEG *l2)
     return(0);	/* both 0.0 */
 }
 
-long lseg_vertical(LSEG *lseg)
+bool lseg_vertical(LSEG *lseg)
 {
     return( FPeq(lseg->p[0].x, lseg->p[1].x) );
 }
 
-long lseg_horizontal(LSEG *lseg)
+bool lseg_horizontal(LSEG *lseg)
 {
     return( FPeq(lseg->p[0].y, lseg->p[1].y) );
 }
 
 
-long lseg_eq(LSEG *l1, LSEG *l2)
+bool lseg_eq(LSEG *l1, LSEG *l2)
 {
     return( FPeq(l1->p[0].x, l2->p[0].x) &&
 	   FPeq(l1->p[1].y, l2->p[1].y) &&
@@ -1118,27 +1456,11 @@ long lseg_eq(LSEG *l1, LSEG *l2)
  */
 double *lseg_distance(LSEG *l1, LSEG *l2)
 {
-    double	*d, *result;
+    double *result;
     
     result = PALLOCTYPE(double);
-    if (lseg_intersect(l1, l2)) {
-	*result = 0.0;
-	return(result);
-    }
-    *result = (double)DBL_MAX;
-    d = dist_ps(&l1->p[0], l2);
-    *result = Min(*result, *d);
-    PFREE(d);
-    d = dist_ps(&l1->p[1], l2);
-    *result = Min(*result, *d);
-    PFREE(d);
-    d = dist_ps(&l2->p[0], l1);
-    *result = Min(*result, *d);
-    PFREE(d);
-    d = dist_ps(&l2->p[1], l1);
-    *result = Min(*result, *d);
-    PFREE(d);
-    
+    *result = lseg_dt( l1, l2);
+
     return(result);
 }
 
@@ -1149,9 +1471,9 @@ double lseg_dt(LSEG *l1, LSEG *l2)
     
     if (lseg_intersect(l1, l2))
 	return(0.0);
-    result = (double)DBL_MAX;
+
     d = dist_ps(&l1->p[0], l2);
-    result = Min(result, *d);
+    result = *d;
     PFREE(d);
     d = dist_ps(&l1->p[1], l2);
     result = Min(result, *d);
@@ -1265,21 +1587,23 @@ double *dist_ppth(Point *pt, PATH *path)
     LSEG lseg;
     
     switch (path->npts) {
+    /* no points in path? then result is undefined... */
     case 0:
-	result = PALLOCTYPE(double);
-	*result = Abs((double) DBL_MAX);	/* +infinity */
+	result = NULL;
 	break;
+    /* one point in path? then get distance between two points... */
     case 1:
 	result = point_distance(pt, &path->p[0]);
 	break;
     default:
+	/* make sure the path makes sense... */
+	Assert(path->npts > 1);
 	/*
 	 * the distance from a point to a path is the smallest distance
 	 * from the point to any of its constituent segments.
 	 */
-	Assert(path->npts > 1);
 	result = PALLOCTYPE(double);
-	for (i = 0; i < path->npts - 1; ++i) {
+	for (i = 0; i < path->npts - 1; i++) {
 	    statlseg_construct(&lseg, &path->p[i], &path->p[i+1]);
 	    tmp = dist_ps(pt, &lseg);
 	    if (i == 0 || *tmp < *result)
@@ -1298,21 +1622,30 @@ double *dist_pb(Point *pt, BOX *box)
     
     tmp = close_pb(pt, box);
     result = point_distance(tmp, pt);
-    
     PFREE(tmp);
+
     return(result);
 }
 
 
 double *dist_sl(LSEG *lseg, LINE *line)
 {
-    double	*result;
-    
+    double *result, *d2;
+
     if (inter_sl(lseg, line)) {
 	result = PALLOCTYPE(double);
 	*result = 0.0;
-    } else	/* parallel */
+
+    } else {
 	result = dist_pl(&lseg->p[0], line);
+	d2 = dist_pl(&lseg->p[1], line);
+	if (*d2 > *result) {
+	    PFREE( result);
+	    result = d2;
+	} else {
+	    PFREE( d2);
+	};
+    };
     
     return(result);
 }
@@ -1502,7 +1835,7 @@ Point *close_lb(LINE *line, BOX *box)
 /* on_pl -
  *	Does the point satisfy the equation? 
  */
-long on_pl(Point *pt, LINE *line)
+bool on_pl(Point *pt, LINE *line)
 {
     return( FPzero(line->A * pt->x + line->B * pt->y + line->C) );
 }
@@ -1511,16 +1844,16 @@ long on_pl(Point *pt, LINE *line)
 /* on_ps -
  *	Determine colinearity by detecting a triangle inequality.
  */
-long on_ps(Point *pt, LSEG *lseg)
+bool on_ps(Point *pt, LSEG *lseg)
 {
     return( FPeq (point_dt(pt, &lseg->p[0]) + point_dt(pt, &lseg->p[1]),
             point_dt(&lseg->p[0], &lseg->p[1])) );
 }
 
-long on_pb(Point *pt, BOX *box)
+bool on_pb(Point *pt, BOX *box)
 {
-    return( pt->x <= box->xh && pt->x >= box->xl &&
-	   pt->y <= box->yh && pt->y >= box->yl );
+    return( pt->x <= box->high.x && pt->x >= box->low.x &&
+	   pt->y <= box->high.y && pt->y >= box->low.y );
 }
 
 /* on_ppath - 
@@ -1535,7 +1868,7 @@ long on_pb(Point *pt, BOX *box)
  */
 #define NEXT(A)	((A+1) % path->npts)	/* cyclic "i+1" */
 
-long on_ppath(Point *pt, PATH *path)
+bool on_ppath(Point *pt, PATH *path)
 {
     int	above, next,	/* is the seg above the ray? */
     inter,		/* # of times path crosses ray */
@@ -1604,12 +1937,12 @@ long on_ppath(Point *pt, PATH *path)
 }
 
 
-long on_sl(LSEG *lseg, LINE *line)
+bool on_sl(LSEG *lseg, LINE *line)
 {
     return( on_pl(&lseg->p[0], line) && on_pl(&lseg->p[1], line) );
 }
 
-long on_sb(LSEG *lseg, BOX *box)
+bool on_sb(LSEG *lseg, BOX *box)
 {
     return( on_pb(&lseg->p[0], box) && on_pb(&lseg->p[1], box) );
 }
@@ -1619,7 +1952,7 @@ long on_sb(LSEG *lseg, BOX *box)
  *		Whether one object intersects another.
  *-------------------------------------------------------------------*/
 
-long inter_sl(LSEG *lseg, LINE *line)
+bool inter_sl(LSEG *lseg, LINE *line)
 {
     Point	*tmp;
 
@@ -1631,207 +1964,195 @@ long inter_sl(LSEG *lseg, LINE *line)
     return(0);
 }
 
-long inter_sb(LSEG *lseg, BOX *box)
+/* XXX segment and box should be able to intersect; tgl - 97/01/09 */
+
+bool inter_sb(LSEG *lseg, BOX *box)
 {
     return(0);
 }
 
-long inter_lb(LINE *line, BOX *box)
+/* XXX line and box should be able to intersect; tgl - 97/01/09 */
+
+bool inter_lb(LINE *line, BOX *box)
 {
     return(0);
 }
 
 /*------------------------------------------------------------------
  * The following routines define a data type and operator class for
- * POLYGONS .... Part of which (the polygon's bounding box is built on 
+ * POLYGONS .... Part of which (the polygon's bounding box) is built on 
  * top of the BOX data type.
  *
  * make_bound_box - create the bounding box for the input polygon
  *------------------------------------------------------------------*/
 
-/* Maximum number of output digits printed */
-#define P_MAXDIG 12
-
 /*---------------------------------------------------------------------
  * Make the smallest bounding box for the given polygon.
  *---------------------------------------------------------------------*/
 void make_bound_box(POLYGON *poly)
 {
+    int i;
     double x1,y1,x2,y2;
-    int npts = poly->npts;
-    
-    if (npts > 0) {
-	x1 = poly_min((double *)poly->pts, npts);
-	x2 = poly_max((double *)poly->pts, npts);
-	y1 = poly_min(((double *)poly->pts)+npts, npts),
-	y2 = poly_max(((double *)poly->pts)+npts, npts);
+
+    if (poly->npts > 0) {
+	x2 = x1 = poly->p[0].x;
+	y2 = y1 = poly->p[0].y;
+	for (i = 1; i < poly->npts; i++) {
+	    if (poly->p[i].x < x1) x1 = poly->p[i].x;
+	    if (poly->p[i].x > x2) x2 = poly->p[i].x;
+	    if (poly->p[i].y < y1) y1 = poly->p[i].y;
+	    if (poly->p[i].y > y2) y2 = poly->p[i].y;
+	};
+
 	box_fill(&(poly->boundbox), x1, x2, y1, y2); 
-    }
+    } else {
+	elog (WARN, "Unable to create bounding box for empty polygon", NULL);
+    };
 }
 
 /*------------------------------------------------------------------
- * polygon_in - read in the polygon from a string specification
- *              the string is of the form "(f8,f8,f8,f8,...,f8)"
+ * poly_in - read in the polygon from a string specification
+ *
+ *	External format:
+ *              "((x0,y0),...,(xn,yn))"
+ *              "x0,y0,...,xn,yn"
+ *		also supports the older style "(x1,...,xn,y1,...yn)"
  *------------------------------------------------------------------*/
-POLYGON *poly_in(char *s)
+POLYGON *poly_in(char *str)
 {
     POLYGON *poly;
-    long points;
-    double *xp, *yp, strtod();
-    int i, size;
-    
-    if((points = poly_pt_count(s, ',')) < 0)
-	elog(WARN, "Bad polygon external representation '%s'", s);
-    
-    size = offsetof(POLYGON, pts[0]) + 2 * sizeof(double) * points;
-    poly = (POLYGON *) PALLOC(size);
+    int npts;
+    int size;
+    int isopen;
+
+#if OLD_FORMAT_IN
+    char *s;
+    int oldstyle;
+    int oddcount;
+    int i;
+    double x1, x2;
+#endif
+
+    if (!PointerIsValid((char *)str))
+	elog (WARN," Bad (null) polygon external representation");
+
+    if ((npts = pair_count(str, ',')) <= 0)
+	elog(WARN, "Bad polygon external representation '%s'", str);
+
+    size = offsetof(POLYGON, p[0]) + (sizeof(poly->p[0]) * npts);
+    if (!PointerIsValid(poly = (POLYGON *) PALLOC(size)))
+      elog(WARN, "Memory allocation failed, can't input polygon '%s'",str);
+
     memset((char *) poly, 0, size);	/* zero any holes */
-    
-    if (!PointerIsValid(poly))
-	elog(WARN, "Memory allocation failed, can't input polygon");
-    
-    poly->npts = points;
     poly->size = size;
-    
-    /* Store all x coords followed by all y coords */
-    xp = (double *) &(poly->pts[0]);
-    yp = (double *) (poly->pts + points*sizeof(double));
-    
-    s++;				/* skip LDELIM */
-    
-    for (i=0; i<points; i++,xp++,yp++)
-	{
-	    *xp = strtod(s, &s);
-	    s++;					/* skip delimiter */
-	    *yp = strtod(s, &s);
-	    s++;					/* skip delimiter */
-	}
+    poly->npts = npts;
+
+#if OLD_FORMAT_IN
+    s = str;
+    while (isspace( *s)) s++;
+    /* identify old style format as having only one left delimiter in string... */
+    oldstyle = ((*s == LDELIM) && (strrchr( s, LDELIM) == s));
+
+    if (oldstyle) {
+	s++;
+	while (isspace( *s)) s++;
+
+	for (i=0; i<npts/2; i++) {
+	    if (! pair_decode( s, &x1, &x2, &s))
+		elog (WARN, "Bad polygon external representation '%s'",str);
+
+	    if (*s == DELIM) s++;
+	    poly->p[i*2].x = x1;
+	    poly->p[i*2+1].x = x2;
+	};
+	oddcount = (npts % 2);
+	if (oddcount) {
+	    if (! pair_decode( s, &x1, &x2, &s))
+		elog (WARN, "Bad polygon external representation '%s'",str);
+
+	    if (*s == DELIM) s++;
+	    poly->p[npts-1].x = x1;
+	    poly->p[0].y = x2;
+	};
+	for (i=0; i<npts/2; i++) {
+	    if (! pair_decode( s, &x1, &x2, &s))
+		elog (WARN, "Bad polygon external representation '%s'",str);
+
+	    if (*s == DELIM) s++;
+	    poly->p[i*2+oddcount].y = x1;
+	    poly->p[i*2+1+oddcount].y = x2;
+	};
+
+	if (*s == RDELIM) {
+	    s++;
+	    while (isspace( *s)) s++;
+	    if (*s != '\0')
+		elog(WARN, "Bad polygon external representation '%s'", str);
+
+	} else {
+	    elog(WARN, "Bad polygon external representation '%s'", str);
+	};
+
+    } else {
+#endif
+	if ((! path_decode(FALSE, npts, str, &isopen, &s, &(poly->p[0])))
+	  || (*s != '\0'))
+	elog (WARN, "Bad polygon external representation '%s'",str);
+
+#if OLD_FORMAT_IN
+    };
+#endif;
+
     make_bound_box(poly);
-    return (poly);
-}
 
-/*-------------------------------------------------------------
- * poly_pt_count - count the number of points specified in the
- *                 polygon.
- *-------------------------------------------------------------*/
-long poly_pt_count(char *s, char delim)
-{
-    long total = 0;
-    
-    if (*s++ != LDELIM)		/* no left delimeter */
-	return (long) -1;
-    
-    while (*s && (*s != RDELIM))
-	{
-	    while (*s && (*s != delim))
-		s++;
-	    total++;	/* found one */
-	    if (*s)
-		s++;	/* bump s past the delimiter */
-	}
-    
-    /* if there was no right delimiter OR an odd number of points */
-    
-    if ((*(s-1) != RDELIM) || ((total%2) != 0))
-	return (long) -1;
-    
-    return (total/2);
-}
+    return( poly);
+} /* poly_in() */
 
 /*---------------------------------------------------------------
  * poly_out - convert internal POLYGON representation to the 
- *            character string format "(f8,f8,f8,f8,...f8)"
+ *            character string format "((f8,f8),...,(f8,f8))"
+ *            also support old format "(f8,f8,...,f8,f8)"
  *---------------------------------------------------------------*/
 char *poly_out(POLYGON *poly)
 {
+#if OLD_FORMAT_OUT
     int i;
-    double *xp, *yp;
-    char *output, *outptr;
-    
-    /*-----------------------------------------------------
-     * Get enough space for "(f8,f8,f8,f8,...,f8)"
-     * which P_MAXDIG+1 for each coordinate plus 2
-     * for parens and 1 for the null
-     *-----------------------------------------------------*/
-    output = (char *)PALLOC(2*(P_MAXDIG+1)*poly->npts + 3);
-    outptr = output;
-    
-    if (!output)
-	elog(WARN, "Memory allocation failed, can't output polygon");
-    
-    *outptr++ = LDELIM;
-    
-    xp = (double *) poly->pts;
-    yp = (double *) (poly->pts + (poly->npts * sizeof(double)));
-    
-    sprintf(outptr, "%*g,%*g", P_MAXDIG, *xp++, P_MAXDIG, *yp++);
-    outptr += (2*P_MAXDIG + 1);
-    
-    for (i=1; i<poly->npts; i++,xp++,yp++)
-	{
-	    sprintf(outptr, ",%*g,%*g", P_MAXDIG, *xp, P_MAXDIG, *yp);
-	    outptr += 2*(P_MAXDIG + 1);
-	}
-    *outptr++ = RDELIM;
-    *outptr = '\0';
-    return (output);
-}
-
-/*-------------------------------------------------------
- * Find the largest coordinate out of n coordinates
- *-------------------------------------------------------*/
-double poly_max(double *coords, int ncoords)
-{
-    double max;
-    
-    max = *coords++;
-    ncoords--;
-    while (ncoords--)
-	{
-	    if (*coords > max)
-		max = *coords;
-	    coords++;
-	}
-    return max;
+    char *result, *cp;
+#endif
+
+    if (!PointerIsValid((char *)poly))
+	return NULL;
+
+#if OLD_FORMAT_OUT
+    if (!PointerIsValid(result = (char *)PALLOC(poly->npts*(P_MAXLEN+3)+2)))
+	elog(WARN, "Memory allocation failed, can't output polygon", NULL);
+
+    cp = result;
+    *cp++ = LDELIM;
+
+    for (i=0; i<poly->npts; i++) {
+	if (! pair_encode( poly->p[i].x, poly->p[i].y, cp))
+	    elog (WARN, "Unable to format polygon", NULL);
+	cp += strlen(cp);
+	*cp++ = DELIM;
+    };
+    *(cp-1) = RDELIM;
+    *cp = '\0';
+    return(result);
+#else
+    return( path_encode( TRUE, poly->npts, &(poly->p[0])));
+#endif
 }
 
-/*-------------------------------------------------------
- * Find the smallest coordinate out of n coordinates
- *-------------------------------------------------------*/
-double poly_min(double *coords, int ncoords)
-{
-    double min;
-    
-    min = *coords++;
-    ncoords--;
-    while (ncoords--)
-	{
-	    if (*coords < min)
-		min = *coords;
-	    coords++;
-	}
-    return min;
-}
 
 /*-------------------------------------------------------
  * Is polygon A strictly left of polygon B? i.e. is
  * the right most point of A left of the left most point
  * of B?
  *-------------------------------------------------------*/
-long poly_left(POLYGON *polya, POLYGON *polyb)
+bool poly_left(POLYGON *polya, POLYGON *polyb)
 {
-    double right, left;
-    
-    if (polya->npts > 0)
-	right = poly_max((double *)polya->pts, polya->npts);
-    else
-	right = polya->boundbox.xh;
-    if (polyb->npts > 0)
-	left = poly_min((double *)polyb->pts, polyb->npts);
-    else
-	left = polyb->boundbox.xl;
-    
-    return (right < left);
+    return (polya->boundbox.high.x < polyb->boundbox.low.x);
 }
 
 /*-------------------------------------------------------
@@ -1839,20 +2160,9 @@ long poly_left(POLYGON *polya, POLYGON *polyb)
  * the left most point of A left of the right most point
  * of B?
  *-------------------------------------------------------*/
-long poly_overleft(POLYGON *polya, POLYGON *polyb)
+bool poly_overleft(POLYGON *polya, POLYGON *polyb)
 {
-    double left, right;
-    
-    if (polya->npts > 0)
-	left = poly_min((double *)polya->pts, polya->npts);
-    else
-	left = polya->boundbox.xl;
-    if (polyb->npts > 0)
-	right = poly_max((double *)polyb->pts, polyb->npts);
-    else
-	right = polyb->boundbox.xh;
-    
-    return (left <= right);
+    return (polya->boundbox.low.x <= polyb->boundbox.high.x);
 }
 
 /*-------------------------------------------------------
@@ -1860,20 +2170,9 @@ long poly_overleft(POLYGON *polya, POLYGON *polyb)
  * the left most point of A right of the right most point
  * of B?
  *-------------------------------------------------------*/
-long poly_right(POLYGON *polya, POLYGON *polyb)
+bool poly_right(POLYGON *polya, POLYGON *polyb)
 {
-    double right, left;
-    
-    if (polya->npts > 0)
-	left = poly_min((double *)polya->pts, polya->npts);
-    else
-	left = polya->boundbox.xl;
-    if (polyb->npts > 0)
-	right = poly_max((double *)polyb->pts, polyb->npts);
-    else
-	right = polyb->boundbox.xh;
-    
-    return (left > right);
+    return( polya->boundbox.low.x > polyb->boundbox.high.x);
 }
 
 /*-------------------------------------------------------
@@ -1881,50 +2180,34 @@ long poly_right(POLYGON *polya, POLYGON *polyb)
  * the right most point of A right of the left most point
  * of B?
  *-------------------------------------------------------*/
-long poly_overright(POLYGON *polya, POLYGON *polyb)
+bool poly_overright(POLYGON *polya, POLYGON *polyb)
 {
-    double right, left;
-    
-    if (polya->npts > 0)
-	right = poly_max((double *)polya->pts, polya->npts);
-    else
-	right = polya->boundbox.xh;
-    if (polyb->npts > 0)
-	left = poly_min((double *)polyb->pts, polyb->npts);
-    else
-	left = polyb->boundbox.xl;
-    
-    return (right > left);
+    return( polya->boundbox.high.x > polyb->boundbox.low.x);
 }
 
 /*-------------------------------------------------------
  * Is polygon A the same as polygon B? i.e. are all the
  * points the same?
  *-------------------------------------------------------*/
-long poly_same(POLYGON *polya, POLYGON *polyb)
+bool poly_same(POLYGON *polya, POLYGON *polyb)
 {
     int i;
-    double *axp, *bxp; /* point to x coordinates for a and b */
-    
     if (polya->npts != polyb->npts)
-	return 0;
-    
-    axp = (double *)polya->pts;
-    bxp = (double *)polyb->pts;
-    
-    for (i=0; i<polya->npts; axp++, bxp++, i++)
-	{
-	    if (*axp != *bxp)
-		return 0;
-	}
-    return 1;
+	return FALSE;
+
+    for (i = 0; i < polya->npts; i++) {
+	if ((polya->p[i].x != polyb->p[i].x)
+	 || (polya->p[i].y != polyb->p[i].y))
+	    return FALSE;
+    };
+    return TRUE;
 }
 
 /*-----------------------------------------------------------------
  * Determine if polygon A overlaps polygon B by determining if
  * their bounding boxes overlap.
  *-----------------------------------------------------------------*/
-long poly_overlap(POLYGON *polya, POLYGON *polyb)
+bool poly_overlap(POLYGON *polya, POLYGON *polyb)
 {
     return box_overlap(&(polya->boundbox), &(polyb->boundbox));
 }
@@ -1933,7 +2216,7 @@ long poly_overlap(POLYGON *polya, POLYGON *polyb)
  * Determine if polygon A contains polygon B by determining if A's
  * bounding box contains B's bounding box.
  *-----------------------------------------------------------------*/
-long poly_contain(POLYGON *polya, POLYGON *polyb)
+bool poly_contain(POLYGON *polya, POLYGON *polyb)
 {
     return box_contain(&(polya->boundbox), &(polyb->boundbox));
 }
@@ -1942,7 +2225,995 @@ long poly_contain(POLYGON *polya, POLYGON *polyb)
  * Determine if polygon A is contained by polygon B by determining 
  * if A's bounding box is contained by B's bounding box.
  *-----------------------------------------------------------------*/
-long poly_contained(POLYGON *polya, POLYGON *polyb)
+bool poly_contained(POLYGON *polya, POLYGON *polyb)
 {
     return box_contained(&(polya->boundbox), &(polyb->boundbox));
 }
+
+
+/***********************************************************************
+ **
+ ** 	Routines for 2D points.
+ **
+ ***********************************************************************/
+
+Point *
+point(float8 *x, float8 *y)
+{
+    if (! (PointerIsValid(x) && PointerIsValid(y)))
+	return(NULL);
+
+    return(point_construct(*x, *y));
+} /* point() */
+
+
+Point *
+point_add(Point *p1, Point *p2)
+{
+    Point *result;
+
+    if (! (PointerIsValid(p1) && PointerIsValid(p2)))
+	return(NULL);
+
+    if (!PointerIsValid(result = PALLOCTYPE(Point)))
+	elog(WARN, "Memory allocation failed, can't add points",NULL);
+
+    result->x = (p1->x + p2->x);
+    result->y = (p1->y + p2->y);
+
+    return(result);
+} /* point_add() */
+
+Point *
+point_sub(Point *p1, Point *p2)
+{
+    Point *result;
+
+    if (! (PointerIsValid(p1) && PointerIsValid(p2)))
+	return(NULL);
+
+    if (!PointerIsValid(result = PALLOCTYPE(Point)))
+	elog(WARN, "Memory allocation failed, can't add points",NULL);
+
+    result->x = (p1->x - p2->x);
+    result->y = (p1->y - p2->y);
+
+    return(result);
+} /* point_sub() */
+
+Point *
+point_mul(Point *p1, Point *p2)
+{
+    Point *result;
+
+    if (! (PointerIsValid(p1) && PointerIsValid(p2)))
+	return(NULL);
+
+    if (!PointerIsValid(result = PALLOCTYPE(Point)))
+	elog(WARN, "Memory allocation failed, can't multiply points",NULL);
+
+    result->x = (p1->x*p2->x) - (p1->y*p2->y);
+    result->y = (p1->x*p2->y) + (p1->y*p2->x);
+
+    return(result);
+} /* point_mul() */
+
+Point *
+point_div(Point *p1, Point *p2)
+{
+    Point *result;
+    double div;
+
+    if (! (PointerIsValid(p1) && PointerIsValid(p2)))
+	return(NULL);
+
+    if (!PointerIsValid(result = PALLOCTYPE(Point)))
+	elog(WARN, "Memory allocation failed, can't multiply path",NULL);
+
+    div = (p2->x*p2->x) + (p2->y*p2->y);
+
+    result->x = ((p1->x*p2->x) + (p1->y*p2->y)) / div;
+    result->y = ((p2->x*p1->y) - (p2->y*p1->x)) / div;
+
+    return(result);
+} /* point_div() */
+
+
+/***********************************************************************
+ **
+ ** 	Routines for 2D boxes.
+ **
+ ***********************************************************************/
+
+BOX *
+box(Point *p1, Point *p2)
+{
+    BOX *result;
+
+    if (! (PointerIsValid(p1) && PointerIsValid(p2)))
+	return(NULL);
+
+    result = box_construct( p1->x, p2->x, p1->y, p2->y);
+
+    return(result);
+} /* box() */
+
+BOX *
+box_add(BOX *box, Point *p)
+{
+    BOX *result;
+
+    if (! (PointerIsValid(box) && PointerIsValid(p)))
+	return(NULL);
+
+    result = box_construct( (box->high.x + p->x), (box->low.x + p->x),
+      (box->high.y + p->y), (box->low.y + p->y));
+
+    return(result);
+} /* box_add() */
+
+BOX *
+box_sub(BOX *box, Point *p)
+{
+    BOX *result;
+
+    if (! (PointerIsValid(box) && PointerIsValid(p)))
+	return(NULL);
+
+    result = box_construct( (box->high.x - p->x), (box->low.x - p->x),
+      (box->high.y - p->y), (box->low.y - p->y));
+
+    return(result);
+} /* box_sub() */
+
+BOX *
+box_mul(BOX *box, Point *p)
+{
+    BOX *result;
+    Point *high, *low;
+
+    if (! (PointerIsValid(box) && PointerIsValid(p)))
+	return(NULL);
+
+    high = point_mul( &box->high, p);
+    low = point_mul( &box->low, p);
+
+    result = box_construct( high->x, low->x, high->y, low->y);
+    PFREE( high);
+    PFREE( low);
+
+    return(result);
+} /* box_mul() */
+
+BOX *
+box_div(BOX *box, Point *p)
+{
+    BOX *result;
+    Point *high, *low;
+
+    if (! (PointerIsValid(box) && PointerIsValid(p)))
+	return(NULL);
+
+    high = point_div( &box->high, p);
+    low = point_div( &box->low, p);
+
+    result = box_construct( high->x, low->x, high->y, low->y);
+    PFREE( high);
+    PFREE( low);
+
+    return(result);
+} /* box_div() */
+
+
+/***********************************************************************
+ **
+ ** 	Routines for 2D lines.
+ **		Lines are not intended to be used as ADTs per se,
+ **		but their ops are useful tools for other ADT ops.  Thus,
+ **		there are few relops.
+ **
+ ***********************************************************************/
+
+
+/***********************************************************************
+ **
+ ** 	Routines for 2D paths.
+ **
+ ***********************************************************************/
+
+POLYGON *path_poly(PATH *path);
+
+/* path_add()
+ * Concatenate two paths (only if they are both open).
+ */
+PATH *
+path_add(PATH *p1, PATH *p2)
+{
+    PATH *result;
+    int size;
+    int i;
+
+    if (! (PointerIsValid(p1) && PointerIsValid(p2))
+      || p1->closed || p2->closed)
+	return(NULL);
+
+    size = offsetof(PATH, p[0]) + (sizeof(p1->p[0]) * (p1->npts+p2->npts));
+    if (!PointerIsValid(result = PALLOC(size)))
+	elog(WARN, "Memory allocation failed, can't add paths",NULL);
+
+    result->size = size;
+    result->npts = (p1->npts+p2->npts);
+    result->closed = p1->closed;
+
+    for (i=0; i<p1->npts; i++) {
+	result->p[i].x = p1->p[i].x;
+	result->p[i].y = p1->p[i].y;
+    };
+    for (i=0; i<p2->npts; i++) {
+	result->p[i+p1->npts].x = p2->p[i].x;
+	result->p[i+p1->npts].y = p2->p[i].y;
+    };
+
+    return(result);
+} /* path_add() */
+
+/* path_add_pt()
+ * Translation operator.
+ */
+PATH *
+path_add_pt(PATH *path, Point *point)
+{
+    PATH *result;
+    int i;
+
+    if (! (PointerIsValid(path) && PointerIsValid(point)))
+	return(NULL);
+
+    if (! PointerIsValid(result = path_copy(path)))
+	elog(WARN, "Memory allocation failed, can't add path",NULL);
+
+    for (i=0; i<path->npts; i++) {
+	result->p[i].x += point->x;
+	result->p[i].y += point->y;
+    };
+
+    return(result);
+} /* path_add_pt() */
+
+PATH *
+path_sub_pt(PATH *path, Point *point)
+{
+    PATH *result;
+    int i;
+
+    if (! (PointerIsValid(path) && PointerIsValid(point)))
+	return(NULL);
+
+    if (! PointerIsValid(result = path_copy(path)))
+	elog(WARN, "Memory allocation failed, can't subtract path",NULL);
+
+    for (i=0; i<path->npts; i++) {
+	result->p[i].x -= point->x;
+	result->p[i].y -= point->y;
+    };
+
+    return(result);
+} /* path_sub_pt() */
+
+
+/* path_mul_pt()
+ * Rotation and scaling operators.
+ */
+PATH *
+path_mul_pt(PATH *path, Point *point)
+{
+    PATH *result;
+    Point *p;
+    int i;
+
+    if (! (PointerIsValid(path) && PointerIsValid(point)))
+	return(NULL);
+
+    if (! PointerIsValid(result = path_copy(path)))
+	elog(WARN, "Memory allocation failed, can't multiply path",NULL);
+
+    for (i=0; i<path->npts; i++) {
+	p = point_mul( &path->p[i], point);
+	result->p[i].x = p->x;
+	result->p[i].y = p->y;
+	PFREE(p);
+    };
+
+    return(result);
+} /* path_mul_pt() */
+
+PATH *
+path_div_pt(PATH *path, Point *point)
+{
+    PATH *result;
+    Point *p;
+    int i;
+
+    if (! (PointerIsValid(path) && PointerIsValid(point)))
+	return(NULL);
+
+    if (! PointerIsValid(result = path_copy(path)))
+	elog(WARN, "Memory allocation failed, can't divide path",NULL);
+
+    for (i=0; i<path->npts; i++) {
+	p = point_div( &path->p[i], point);
+	result->p[i].x = p->x;
+	result->p[i].y = p->y;
+	PFREE(p);
+    };
+
+    return(result);
+} /* path_div_pt() */
+
+
+POLYGON *path_poly(PATH *path)
+{
+    POLYGON *poly;
+    int size;
+    int i;
+
+    if (!PointerIsValid(path))
+	return(NULL);
+
+    if (!path->closed)
+	elog(WARN, "Open path cannot be converted to polygon",NULL);
+
+    size = offsetof(POLYGON, p[0]) + (sizeof(poly->p[0]) * path->npts);
+    if (!PointerIsValid(poly = PALLOC(size)))
+	elog(WARN, "Memory allocation failed, can't convert path to polygon",NULL);
+
+    poly->size = size;
+    poly->npts = path->npts;
+
+    for (i=0; i<path->npts; i++) {
+	poly->p[i].x = path->p[i].x;
+	poly->p[i].y = path->p[i].y;
+    };
+
+    make_bound_box(poly);
+
+    return(poly);
+} /* path_polygon() */
+
+
+/***********************************************************************
+ **
+ ** 	Routines for 2D polygons.
+ **
+ ***********************************************************************/
+
+int4
+poly_npoints( POLYGON *poly)
+{
+    if (!PointerIsValid(poly))
+	return(0);
+
+    return(poly->npts);
+} /* poly_npoints() */
+
+BOX *
+poly_box(POLYGON *poly)
+{
+    BOX *box;
+
+    if (!PointerIsValid(poly) || (poly->npts < 1))
+	return(NULL);
+
+    box = box_copy( &poly->boundbox);
+
+    return(box);
+} /* poly_box() */
+
+POLYGON *
+box_poly(BOX *box)
+{
+    POLYGON *poly;
+    int size;
+
+    if (!PointerIsValid(box))
+	return(NULL);
+
+    size = offsetof(POLYGON, p[0]) + (sizeof(poly->p[0]) * 4);
+    if (!PointerIsValid(poly = PALLOC(size)))
+	elog(WARN, "Memory allocation failed, can't convert box to polygon",NULL);
+
+    poly->size = size;
+    poly->npts = 4;
+
+    poly->p[0].x = box->low.x;
+    poly->p[0].y = box->low.y;
+    poly->p[1].x = box->low.x;
+    poly->p[1].y = box->high.y;
+    poly->p[2].x = box->high.x;
+    poly->p[2].y = box->high.y;
+    poly->p[3].x = box->high.x;
+    poly->p[3].y = box->low.y;
+
+    box_fill( &poly->boundbox, box->high.x, box->low.x, box->high.y, box->low.y);
+
+    return(poly);
+} /* box_poly() */
+
+PATH *
+poly_path(POLYGON *poly)
+{
+    PATH *path;
+    int size;
+    int i;
+
+    if (!PointerIsValid(poly) || (poly->npts < 0))
+	return(NULL);
+
+    size = offsetof(PATH, p[0]) + (sizeof(path->p[0]) * poly->npts);
+    if (!PointerIsValid(path = PALLOC(size)))
+	elog(WARN, "Memory allocation failed, can't convert polygon to path",NULL);
+
+    path->size = size;
+    path->npts = poly->npts;
+    path->closed = TRUE;
+
+    for (i=0; i<poly->npts; i++) {
+	path->p[i].x = poly->p[i].x;
+	path->p[i].y = poly->p[i].y;
+    };
+
+    return(path);
+} /* poly_path() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * circle.c--
+ *    2D geometric operations
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *    $Header: /cvsroot/pgsql/src/backend/utils/adt/geo_ops.c,v 1.3 1997/04/22 17:31:32 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PI
+#define PI 3.1415926536
+#endif
+
+int single_decode(char *str, float8 *x, char **ss);
+int single_encode(float8 x, char *str);
+
+int single_decode(char *str, float8 *x, char **s)
+{
+    char *cp;
+
+    if (!PointerIsValid(str))
+	return(FALSE);
+
+    while (isspace( *str)) str++;
+    *x = strtod( str, &cp);
+#ifdef GEODEBUG
+fprintf( stderr, "single_decode- (%x) try decoding %s to %g\n", (cp-str), str, *x);
+#endif
+    if (cp <= str) return(FALSE);
+    while (isspace( *cp)) cp++;
+
+    if (s != NULL) *s = cp;
+
+    return(TRUE);
+}
+
+int single_encode(float8 x, char *str)
+{
+    (void) sprintf(str, "%.*g", digits8, x);
+    return(TRUE);
+}
+
+
+/***********************************************************************
+ **
+ ** 	Routines for circles.
+ **
+ ***********************************************************************/
+
+/*----------------------------------------------------------
+ * Formatting and conversion routines.
+ *---------------------------------------------------------*/
+
+/*	circle_in	-	convert a string to internal form.
+ *
+ *	External format: (center and radius of circle)
+ *		"((f8,f8)<f8>)"
+ *		also supports quick entry style "(f8,f8,f8)"
+ */
+CIRCLE *circle_in(char *str)
+{
+    CIRCLE *circle;
+
+    char *s, *cp;
+    int depth = 0;
+
+    if (!PointerIsValid(str))
+	elog (WARN," Bad (null) circle external representation",NULL);
+
+    if (!PointerIsValid(circle = PALLOCTYPE(CIRCLE)))
+      elog(WARN, "Memory allocation failed, can't input circle '%s'",str);
+
+    s = str;
+    while (isspace( *s)) s++;
+    if ((*s == LDELIM_C) || (*s == LDELIM)) {
+	depth++;
+	cp = (s+1);
+	while (isspace( *cp)) cp++;
+	if (*cp == LDELIM) {
+	    s = cp;
+	};
+    };
+
+    if (! pair_decode( s, &circle->center.x, &circle->center.y, &s))
+      elog (WARN, "Bad circle external representation '%s'",str);
+
+    if (*s == DELIM) s++;
+    while (isspace( *s)) s++;
+
+    if (! single_decode( s, &circle->radius, &s))
+      elog (WARN, "Bad circle external representation '%s'",str);
+
+    while (depth > 0) {
+	if ((*s == RDELIM)
+         || ((*s == RDELIM_C) && (depth == 1))) {
+	    depth--;
+	    s++;
+	    while (isspace( *s)) s++;
+	} else {
+	    elog (WARN, "Bad circle external representation '%s'",str);
+	};
+    };
+
+    if (*s != '\0')
+      elog (WARN, "Bad circle external representation '%s'",str);
+
+    return(circle);
+} /* circle_in() */
+
+/*	circle_out	-	convert a circle to external form.
+ */
+char *circle_out(CIRCLE *circle)
+{
+    char *result;
+    char *cp;
+
+    if (!PointerIsValid(circle))
+	return(NULL);
+
+    if (!PointerIsValid(result = (char *)PALLOC(3*(P_MAXLEN+1)+3)))
+	elog(WARN, "Memory allocation failed, can't output circle", NULL);
+
+    cp = result;
+    *cp++ = LDELIM_C;
+    *cp++ = LDELIM;
+    if (! pair_encode( circle->center.x, circle->center.y, cp))
+	  elog (WARN, "Unable to format circle", NULL);
+
+    cp += strlen(cp);
+    *cp++ = RDELIM;
+    *cp++ = DELIM;
+    if (! single_encode( circle->radius, cp))
+	  elog (WARN, "Unable to format circle", NULL);
+
+    cp += strlen(cp);
+    *cp++ = RDELIM_C;
+    *cp = '\0';
+
+    return(result);
+} /* circle_out() */
+
+
+/*----------------------------------------------------------
+ *  Relational operators for CIRCLEs.
+ *	<, >, <=, >=, and == are based on circle area.
+ *---------------------------------------------------------*/
+
+/*	circles identical?
+ */
+bool circle_same(CIRCLE *circle1, CIRCLE *circle2)
+{
+    return( FPeq(circle1->radius,circle2->radius)
+      && FPeq(circle1->center.x,circle2->center.x)
+      && FPeq(circle1->center.y,circle2->center.y));
+}
+
+/*	circle_overlap	-	does circle1 overlap circle2?
+ */
+bool circle_overlap(CIRCLE *circle1, CIRCLE *circle2)
+{
+    return( FPle(point_dt(&circle1->center,&circle2->center),(circle1->radius+circle2->radius)));
+}
+
+/*	circle_overleft	-	is the right edge of circle1 to the left of
+ *				the right edge of circle2?
+ */
+bool circle_overleft(CIRCLE *circle1, CIRCLE *circle2)
+{
+    return( FPle((circle1->center.x+circle1->radius),(circle2->center.x+circle2->radius)));
+}
+
+/*	circle_left	-	is circle1 strictly left of circle2?
+ */
+bool circle_left(CIRCLE *circle1, CIRCLE *circle2)
+{
+    return( FPle((circle1->center.x+circle1->radius),(circle2->center.x-circle2->radius)));
+}
+
+/*	circle_right	-	is circle1 strictly right of circle2?
+ */
+bool circle_right(CIRCLE *circle1, CIRCLE *circle2)
+{
+    return( FPge((circle1->center.x-circle1->radius),(circle2->center.x+circle2->radius)));
+}
+
+/*	circle_overright	-	is the left edge of circle1 to the right of
+ *				the left edge of circle2?
+ */
+bool circle_overright(CIRCLE *circle1, CIRCLE *circle2)
+{
+    return( FPge((circle1->center.x-circle1->radius),(circle2->center.x-circle2->radius)));
+}
+
+/*	circle_contained	-	is circle1 contained by circle2?
+ */
+bool circle_contained(CIRCLE *circle1, CIRCLE *circle2)
+{
+    return( FPle((point_dt(&circle1->center,&circle2->center)+circle1->radius),circle2->radius));
+}
+
+/*	circle_contain	-	does circle1 contain circle2?
+ */
+bool circle_contain(CIRCLE *circle1, CIRCLE *circle2)
+{
+    return( FPle((point_dt(&circle1->center,&circle2->center)+circle2->radius),circle1->radius));
+}
+
+
+/*	circle_positionop	-
+ *		is circle1 entirely {above,below} circle2?
+ */
+bool circle_below(CIRCLE *circle1, CIRCLE *circle2)
+{
+    return( FPle((circle1->center.y+circle1->radius),(circle2->center.y-circle2->radius)));
+}
+
+bool circle_above(CIRCLE *circle1, CIRCLE *circle2)
+{
+    return( FPge((circle1->center.y-circle1->radius),(circle2->center.y+circle2->radius)));
+}
+
+
+/*	circle_relop	-	is area(circle1) relop area(circle2), within
+ *			  	our accuracy constraint?
+ */
+bool circle_eq(CIRCLE *circle1, CIRCLE *circle2)
+{
+    return( FPeq(circle_ar(circle1), circle_ar(circle2)) );
+} /* circle_eq() */
+
+bool circle_ne(CIRCLE *circle1, CIRCLE *circle2)
+{
+    return( !circle_eq(circle1, circle2));
+} /* circle_ne() */
+
+bool circle_lt(CIRCLE *circle1, CIRCLE *circle2)
+{
+    return( FPlt(circle_ar(circle1), circle_ar(circle2)) );
+} /* circle_lt() */
+
+bool circle_gt(CIRCLE *circle1, CIRCLE *circle2)
+{
+    return( FPgt(circle_ar(circle1), circle_ar(circle2)) );
+} /* circle_gt() */
+
+bool circle_le(CIRCLE *circle1, CIRCLE *circle2)
+{
+    return( FPle(circle_ar(circle1), circle_ar(circle2)) );
+} /* circle_le() */
+
+bool circle_ge(CIRCLE	*circle1, CIRCLE *circle2)
+{
+    return( FPge(circle_ar(circle1), circle_ar(circle2)) );
+} /* circle_ge() */
+
+
+/*----------------------------------------------------------
+ *  "Arithmetic" operators on circles.
+ *	circle_foo	returns foo as an object (pointer) that
+ can be passed between languages.
+ *	circle_xx	is an internal routine which returns the
+ *			actual value.
+ *---------------------------------------------------------*/
+
+CIRCLE *circle_copy(CIRCLE *circle);
+
+CIRCLE *
+circle_copy(CIRCLE *circle)
+{
+    CIRCLE *result;
+
+    if (!PointerIsValid(circle))
+	return NULL;
+
+    if (!PointerIsValid(result = PALLOCTYPE(CIRCLE)))
+	elog(WARN, "Memory allocation failed, can't copy circle",NULL);
+
+    memmove((char *) result, (char *) circle, sizeof(CIRCLE));
+    return(result);
+} /* circle_copy() */
+
+
+/* circle_add_pt()
+ * Translation operator.
+ */
+CIRCLE *
+circle_add_pt(CIRCLE *circle, Point *point)
+{
+    CIRCLE *result;
+
+    if (!PointerIsValid(circle) && !PointerIsValid(point))
+	return(NULL);
+
+    if (! PointerIsValid(result = circle_copy(circle)))
+	elog(WARN, "Memory allocation failed, can't add circle",NULL);
+
+    result->center.x += point->x;
+    result->center.y += point->y;
+
+    return(result);
+} /* circle_add_pt() */
+
+CIRCLE *
+circle_sub_pt(CIRCLE *circle, Point *point)
+{
+    CIRCLE *result;
+
+    if (!PointerIsValid(circle) && !PointerIsValid(point))
+	return(NULL);
+
+    if (! PointerIsValid(result = circle_copy(circle)))
+	elog(WARN, "Memory allocation failed, can't subtract circle",NULL);
+
+    result->center.x -= point->x;
+    result->center.y -= point->y;
+
+    return(result);
+} /* circle_sub_pt() */
+
+
+/* circle_mul_pt()
+ * Rotation and scaling operators.
+ */
+CIRCLE *
+circle_mul_pt(CIRCLE *circle, Point *point)
+{
+    CIRCLE *result;
+    Point *p;
+
+    if (!PointerIsValid(circle) && !PointerIsValid(point))
+	return(NULL);
+
+    if (! PointerIsValid(result = circle_copy(circle)))
+	elog(WARN, "Memory allocation failed, can't multiply circle",NULL);
+
+    p = point_mul( &circle->center, point);
+    result->center.x = p->x;
+    result->center.y = p->y;
+    PFREE(p);
+    result->radius *= HYPOT( point->x, point->y);
+
+    return(result);
+} /* circle_mul_pt() */
+
+CIRCLE *
+circle_div_pt(CIRCLE *circle, Point *point)
+{
+    CIRCLE *result;
+    Point *p;
+
+    if (!PointerIsValid(circle) && !PointerIsValid(point))
+	return(NULL);
+
+    if (! PointerIsValid(result = circle_copy(circle)))
+	elog(WARN, "Memory allocation failed, can't add circle",NULL);
+
+    p = point_div( &circle->center, point);
+    result->center.x = p->x;
+    result->center.y = p->y;
+    PFREE(p);
+    result->radius /= HYPOT( point->x, point->y);
+
+    return(result);
+} /* circle_div_pt() */
+
+
+/*	circle_area	-	returns the area of the circle.
+ */
+double *circle_area(CIRCLE *circle)
+{
+    double *result;
+
+    result = PALLOCTYPE(double);
+    *result = circle_ar(circle);
+
+    return(result);
+}
+
+
+/*	circle_diameter	-	returns the diameter of the circle.
+ */
+double *circle_diameter(CIRCLE *circle)
+{
+    double	*result;
+
+    result = PALLOCTYPE(double);
+    *result = (2*circle->radius);
+
+    return(result);
+}
+
+
+/*	circle_radius	-	returns the radius of the circle.
+ */
+double *circle_radius(CIRCLE *circle)
+{
+    double	*result;
+
+    result = PALLOCTYPE(double);
+    *result = circle->radius;
+
+    return(result);
+}
+
+
+/*	circle_distance	-	returns the distance between the
+ *				  center points of two circlees.
+ */
+double *circle_distance(CIRCLE *circle1, CIRCLE *circle2)
+{
+    double	*result;
+
+    result = PALLOCTYPE(double);
+    *result = point_dt(&circle1->center,&circle2->center);
+
+    return(result);
+}
+
+
+/*	circle_center	-	returns the center point of the circle.
+ */
+Point *circle_center(CIRCLE *circle)
+{
+    Point	*result;
+
+    result = PALLOCTYPE(Point);
+    result->x = circle->center.x;
+    result->y = circle->center.y;
+
+    return(result);
+}
+
+
+/*	circle_ar	-	returns the area of the circle.
+ */
+double circle_ar(CIRCLE *circle)
+{
+    return(PI*(circle->radius*circle->radius));
+}
+
+
+/*	circle_dt	-	returns the distance between the
+ *			  center points of two circlees.
+ */
+double circle_dt(CIRCLE *circle1, CIRCLE *circle2)
+{
+    double	result;
+
+    result = point_dt(&circle1->center,&circle2->center);
+
+    return(result);
+}
+
+
+/*----------------------------------------------------------
+ *  Conversion operators.
+ *---------------------------------------------------------*/
+
+CIRCLE *circle(Point *center, float8 *radius)
+{
+    CIRCLE *result;
+
+    if (! (PointerIsValid(center) && PointerIsValid(radius)))
+	return(NULL);
+
+    if (!PointerIsValid(result = PALLOCTYPE(CIRCLE)))
+      elog(WARN, "Memory allocation failed, can't convert point to circle",NULL);
+
+    result->center.x = center->x;
+    result->center.y = center->y;
+    result->radius = *radius;
+
+    return(result);
+}
+
+POLYGON *circle_poly(int npts, CIRCLE *circle)
+{
+    POLYGON *poly;
+    int size;
+    int i;
+    double angle;
+
+    if (!PointerIsValid(circle))
+	return(NULL);
+
+    if (FPzero(circle->radius) || (npts <= 2))
+	  elog (WARN, "Unable to convert circle to polygon", NULL);
+
+    size = offsetof(POLYGON, p[0]) + (sizeof(poly->p[0]) * npts);
+    if (!PointerIsValid(poly = (POLYGON *) PALLOC(size)))
+      elog(WARN, "Memory allocation failed, can't convert circle to polygon",NULL);
+
+    memset((char *) poly, 0, size);	/* zero any holes */
+    poly->size = size;
+    poly->npts = npts;
+
+    for (i=0;i<npts;i++) {
+	angle = i*(2*PI/npts);
+	poly->p[i].x = circle->center.x - (circle->radius*cos(angle));
+	poly->p[i].y = circle->center.y + (circle->radius*sin(angle));
+    };
+
+    make_bound_box(poly);
+
+    return(poly);
+}
+
+/*	poly_circle	- convert polygon to circle
+ *
+ * XXX This algorithm should use weighted means of line segments
+ *  rather than straight average values of points - tgl 97/01/21.
+ */
+CIRCLE *poly_circle(POLYGON *poly)
+{
+    CIRCLE *circle;
+    int i;
+
+    if (!PointerIsValid(poly))
+	return(NULL);
+
+    if (poly->npts <= 2)
+	  elog (WARN, "Unable to convert polygon to circle", NULL);
+
+    if (!PointerIsValid(circle = PALLOCTYPE(CIRCLE)))
+      elog(WARN, "Memory allocation failed, can't convert polygon to circle",NULL);
+
+    circle->center.x = 0;
+    circle->center.y = 0;
+    circle->radius = 0;
+
+    for (i=0;i<poly->npts;i++) {
+	circle->center.x += poly->p[i].x;
+	circle->center.y += poly->p[i].y;
+    };
+    circle->center.x /= poly->npts;
+    circle->center.y /= poly->npts;
+
+    for (i=0;i<poly->npts;i++) {
+	circle->radius += point_dt( &poly->p[i], &circle->center);
+    };
+    circle->radius /= poly->npts;
+
+    if (FPzero(circle->radius))
+	  elog (WARN, "Unable to convert polygon to circle", NULL);
+
+    return(circle);
+}
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index fa8a48068733a144d318df64814b0d5ed02dde96..2b61ac73edcafb3299c8b29c624109190717e33f 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -7,7 +7,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_operator.h,v 1.8 1997/04/15 17:40:44 scrappy Exp $
+ * $Id: pg_operator.h,v 1.9 1997/04/22 17:31:49 scrappy Exp $
  *
  * NOTES
  *    the genbki.sh script reads this file and generates .bki
@@ -185,7 +185,7 @@ DATA(insert OID = 513 (  "@@"      PGUID 0 l t f   0 603 600   0   0   0   0 box
 DATA(insert OID = 514 (  "*"       PGUID 0 b t f  23  23  23 514   0   0   0 int4mul intltsel intltjoinsel ));
 DATA(insert OID = 515 (  "!"       PGUID 0 r t f  23   0  23   0   0   0   0 int4fac intltsel intltjoinsel ));
 DATA(insert OID = 516 (  "!!"      PGUID 0 l t f   0  23  23   0   0   0   0 int4fac intltsel intltjoinsel ));
-DATA(insert OID = 517 (  "<===>"   PGUID 0 b t f 600 600 701   0   0   0   0 point_distance intltsel intltjoinsel ));
+DATA(insert OID = 517 (  "<===>"   PGUID 0 b t f 600 600 701 517   0   0   0 point_distance intltsel intltjoinsel ));
 DATA(insert OID = 518 (  "<>"      PGUID 0 b t f  23  23  16 518  96  0  0 int4ne neqsel neqjoinsel ));
 DATA(insert OID = 519 (  "<>"      PGUID 0 b t f  21  21  16 519  94  0  0 int2ne neqsel neqjoinsel ));
 DATA(insert OID = 520 (  ">"       PGUID 0 b t f  21  21  16  95   0  0  0 int2gt intgtsel intgtjoinsel ));
@@ -279,6 +279,14 @@ DATA(insert OID = 609 (  "<"       PGUID 0 b t f  26  26  16 610 612  0  0 int4l
 DATA(insert OID = 610 (  ">"       PGUID 0 b t f  26  26  16 609 611  0  0 int4gt intgtsel intgtjoinsel ));
 DATA(insert OID = 611 (  "<="      PGUID 0 b t f  26  26  16 612 610  0  0 int4le intltsel intltjoinsel ));
 DATA(insert OID = 612 (  ">="      PGUID 0 b t f  26  26  16 611 609  0  0 int4ge intgtsel intgtjoinsel ));
+
+DATA(insert OID = 613 (  "<===>"   PGUID 0 b t f 600 603 701 613   0  0  0 dist_pl intltsel intltjoinsel ));
+DATA(insert OID = 614 (  "<===>"   PGUID 0 b t f 600 601 701 614   0  0  0 dist_ps intltsel intltjoinsel ));
+DATA(insert OID = 615 (  "<===>"   PGUID 0 b t f 600 603 701 615   0  0  0 dist_pb intltsel intltjoinsel ));
+DATA(insert OID = 616 (  "<===>"   PGUID 0 b t f 600 603 701 616   0  0  0 dist_ps intltsel intltjoinsel ));
+DATA(insert OID = 617 (  "<===>"   PGUID 0 b t f 601 603 701 617   0  0  0 dist_sb intltsel intltjoinsel ));
+DATA(insert OID = 618 (  "<===>"   PGUID 0 b t f 600 602 701 618   0  0  0 dist_ppth intltsel intltjoinsel ));
+
 DATA(insert OID = 620 (  "="       PGUID 0 b t t  700  700  16 620 621  622 622 float4eq eqsel eqjoinsel ));
 DATA(insert OID = 621 (  "<>"      PGUID 0 b t f  700  700  16 621 620  0 0 float4ne neqsel neqjoinsel ));
 DATA(insert OID = 622 (  "<"       PGUID 0 b t f  700  700  16 623 625  0 0 float4lt intltsel intltjoinsel ));
@@ -341,6 +349,11 @@ DATA(insert OID = 681 (  "<>"      PGUID 0 b t f  911  911  16 681 678  0 0 oidn
 DATA(insert OID = 697 (  "~"       PGUID 0 b t f  411  25  16 0 698  0 0 char8regexeq eqsel eqjoinsel ));
 DATA(insert OID = 698 (  "!~"      PGUID 0 b t f  411  25  16 0 697  0 0 char8regexne neqsel neqjoinsel ));
 
+DATA(insert OID = 706 (  "<===>"   PGUID 0 b t f 603 603 701 706   0  0  0 box_distance intltsel intltjoinsel ));
+DATA(insert OID = 707 (  "<===>"   PGUID 0 b t f 602 602 701 707   0  0  0 path_distance intltsel intltjoinsel ));
+DATA(insert OID = 708 (  "<===>"   PGUID 0 b t f 603 603 701 708   0  0  0 line_distance intltsel intltjoinsel ));
+DATA(insert OID = 709 (  "<===>"   PGUID 0 b t f 601 601 701 709   0  0  0 lseg_distance intltsel intltjoinsel ));
+
 DATA(insert OID = 830 (  "<"       PGUID 0 b t f  810  810  16 834 833  0 0 oidint2lt intltsel intltjoinsel ));
 DATA(insert OID = 831 (  "<="      PGUID 0 b t f  810  810  16 833 834  0 0 oidint2le intltsel intltjoinsel ));
 DATA(insert OID = 832 (  "="       PGUID 0 b t f  810  810  16 832 835  0 0 oidint2eq intltsel intltjoinsel ));
@@ -509,7 +522,32 @@ DATA(insert OID = 1303 (  ">"       PGUID 0 b t f  1296 1296 16 1302 1304 0 0 ti
 DATA(insert OID = 1304 (  "<="      PGUID 0 b t f  1296 1296 16 1305 1303 0 0 timestample intltsel intltjoinsel ));
 DATA(insert OID = 1305 (  ">="      PGUID 0 b t f  1296 1296 16 1304 1302 0 0 timestampge intltsel intltjoinsel ));
 
-
+/* additional geometric operators - tgl 97/04/18 */
+DATA(insert OID = 1500 (  "="     PGUID 0 b t t  718  718   16 1500 1501 1502 1502 circle_eq eqsel eqjoinsel ));
+DATA(insert OID = 1501 (  "<>"    PGUID 0 b t f  718  718   16 1501 1500    0    0 circle_ne neqsel neqjoinsel ));
+DATA(insert OID = 1502 (  "<"     PGUID 0 b t f  718  718   16 1503 1505    0    0 circle_eq eqsel eqjoinsel ));
+DATA(insert OID = 1503 (  ">"     PGUID 0 b t f  718  718   16 1502 1504    0    0 circle_eq eqsel eqjoinsel ));
+DATA(insert OID = 1504 (  "<="    PGUID 0 b t f  718  718   16 1505 1503    0    0 circle_eq eqsel eqjoinsel ));
+DATA(insert OID = 1505 (  ">="    PGUID 0 b t f  718  718   16 1504 1502    0    0 circle_eq eqsel eqjoinsel ));
+
+DATA(insert OID = 1506 (  "<<"    PGUID 0 b t f  718  718   16    0    0    0    0 circle_left intltsel intltjoinsel ));
+DATA(insert OID = 1507 (  "&<"    PGUID 0 b t f  718  718   16    0    0    0    0 circle_overleft intltsel intltjoinsel ));
+DATA(insert OID = 1508 (  "&>"    PGUID 0 b t f  718  718   16    0    0    0    0 circle_overright intltsel intltjoinsel ));
+DATA(insert OID = 1509 (  ">>"    PGUID 0 b t f  718  718   16    0    0    0    0 circle_right intltsel intltjoinsel ));
+DATA(insert OID = 1510 (  "@"     PGUID 0 b t f  718  718   16    0    0    0    0 circle_contained intltsel intltjoinsel ));
+DATA(insert OID = 1511 (  "~"     PGUID 0 b t f  718  718   16    0    0    0    0 circle_contain intltsel intltjoinsel ));
+DATA(insert OID = 1512 (  "~="    PGUID 0 b t f  718  718   16 1512    0    0    0 circle_same intltsel intltjoinsel ));
+DATA(insert OID = 1513 (  "&&"    PGUID 0 b t f  718  718   16    0    0    0    0 circle_overlap intltsel intltjoinsel ));
+DATA(insert OID = 1514 (  "!^"    PGUID 0 b t f  718  718   16    0    0    0    0 circle_above intltsel intltjoinsel ));
+DATA(insert OID = 1515 (  "!|"    PGUID 0 b t f  718  718   16    0    0    0    0 circle_below intltsel intltjoinsel ));
+
+DATA(insert OID = 1516 (  "+"     PGUID 0 b t f  718  600  718 1516    0    0    0 circle_add_pt - - ));
+DATA(insert OID = 1517 (  "-"     PGUID 0 b t f  718  600  718    0    0    0    0 circle_sub_pt - - ));
+DATA(insert OID = 1518 (  "*"     PGUID 0 b t f  718  600  718 1518    0    0    0 circle_mul_pt - - ));
+DATA(insert OID = 1519 (  "/"     PGUID 0 b t f  718  600  718    0    0    0    0 circle_div_pt - - ));
+
+DATA(insert OID = 1520 (  "<===>" PGUID 0 b t f  718  718  701 1520    0    0    0 circle_distance intltsel intltjoinsel ));
+DATA(insert OID = 1521 (  "#"     PGUID 0 l t f    0  604   23    0    0    0    0 poly_npoints - - ));
 
 /*
  * function prototypes
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index bd1cf4f208bc003a3c47f9280d02b52681776d59..ff346f04dfd5599dc2c1d7d458bcbf8466367560 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_proc.h,v 1.17 1997/04/15 17:41:03 scrappy Exp $
+ * $Id: pg_proc.h,v 1.18 1997/04/22 17:32:12 scrappy Exp $
  *
  * NOTES
  *    The script catalog/genbki.sh reads this file and generates .bki
@@ -92,6 +92,7 @@ typedef FormData_pg_proc	*Form_pg_proc;
 /* keep the following ordered by OID so that later changes can be made easier*/
 
 /* OIDS 1 - 99 */
+
 DATA(insert OID = 1242 (  boolin           PGUID 11 f t f 1 f 16 "0" 100 0 0  100  foo bar ));
 DATA(insert OID = 1243 (  boolout          PGUID 11 f t f 1 f 23 "0" 100 0 0 100  foo bar ));
 DATA(insert OID = 1244 (  byteain          PGUID 11 f t f 1 f 17 "0" 100 0 0 100  foo bar ));
@@ -524,6 +525,7 @@ DATA(insert OID = 696 (  char8regexne      PGUID 11 f t f 2 f 16 "411 25" 100 0
 DATA(insert OID = 699 (  char2regexeq      PGUID 11 f t f 2 f 16 "409 25" 100 0 0 100  foo bar ));
 
 /* OIDS 700 - 799 */
+
 DATA(insert OID = 1288 (  char16regexeq    PGUID 11 f t f 2 f 16 "19 25" 100 0 0 100  foo bar ));
 DATA(insert OID = 1289 (  char16regexne    PGUID 11 f t f 2 f 16 "19 25" 100 0 0 100  foo bar ));
 
@@ -534,13 +536,16 @@ DATA(insert OID = 715 (  oidsrand          PGUID 11 f t f 1 f 16 "23" 100 0 0 10
 DATA(insert OID = 716 (  oideqint4         PGUID 11 f t f 2 f 16 "26 23" 100 0 0 100  foo bar ));
 DATA(insert OID = 717 (  int4eqoid         PGUID 11 f t f 2 f 16 "23 26" 100 0 0 100  foo bar ));
 
-
 DATA(insert OID = 720 (  byteaGetSize	   PGUID 11 f t f 1 f 23 "17" 100 0 0 100  foo bar ));
 DATA(insert OID = 721 (  byteaGetByte	   PGUID 11 f t f 2 f 23 "17 23" 100 0 0 100  foo bar ));
 DATA(insert OID = 722 (  byteaSetByte	   PGUID 11 f t f 3 f 17 "17 23 23" 100 0 0 100  foo bar ));
 DATA(insert OID = 723 (  byteaGetBit	   PGUID 11 f t f 2 f 23 "17 23" 100 0 0 100  foo bar ));
 DATA(insert OID = 724 (  byteaSetBit	   PGUID 11 f t f 3 f 17 "17 23 23" 100 0 0 100  foo bar ));
 
+DATA(insert OID = 725 (  dist_pl           PGUID 11 f t f 2 f 701 "600 654" 100 0 0 100  foo bar ));
+DATA(insert OID = 726 (  dist_lb           PGUID 11 f t f 2 f 701 "654 603" 100 0 0 100  foo bar ));
+DATA(insert OID = 727 (  dist_sl           PGUID 11 f t f 2 f 701 "601 654" 100 0 0 100  foo bar ));
+
 DATA(insert OID = 730 (  pqtest            PGUID 11 f t f 1 f 23 "25" 100 0 0 100  foo bar ));
 
 DATA(insert OID = 740 (  text_lt           PGUID 11 f t f 2 f 16 "25 25" 100 0 0 0  foo bar ));
@@ -587,6 +592,7 @@ DATA(insert OID = 781 (  gistrestrpos      PGUID 11 f t f 1 f 23 "0" 100 0 0 100
 DATA(insert OID = 782 (  gistbuild         PGUID 11 f t f 9 f 23 "0" 100 0 0 100  foo bar ));
 
 /* OIDS 800 - 899 */
+
 DATA(insert OID = 820 (  oidint2in	   PGUID 11 f t f 1 f 810 "0" 100 0 0 100  foo bar));
 DATA(insert OID = 821 (  oidint2out	   PGUID 11 f t f 1 f 19 "0" 100 0 0 100  foo bar));
 DATA(insert OID = 822 (  oidint2lt	   PGUID 11 f t f 2 f 16 "810 810" 100 0 0 100  foo bar));
@@ -747,6 +753,7 @@ DATA(insert OID = 1091 (  date_ne          PGUID 11 f t f 2 f 16 "1082 1082" 100
 DATA(insert OID = 1092 (  date_cmp         PGUID 11 f t f 2 f 23 "1082 1082" 100 0 0 100  foo bar ));
 
 /* OIDS 1100 - 1199 */
+
 DATA(insert OID = 1102 (  time_lt          PGUID 11 f t f 2 f 16 "1083 1083" 100 0 0 100  foo bar ));
 DATA(insert OID = 1103 (  time_le          PGUID 11 f t f 2 f 16 "1083 1083" 100 0 0 100  foo bar ));
 DATA(insert OID = 1104 (  time_gt          PGUID 11 f t f 2 f 16 "1083 1083" 100 0 0 100  foo bar ));
@@ -806,6 +813,7 @@ DATA(insert OID = 1194 (  timespan_reltime   PGUID 11 f t f 1 f  703 "1186" 100
 /* reserve OIDs 1195-1199 for additional date/time conversion routines! tgl 97/03/19 */
 
 /* OIDS 1200 - 1299 */
+
 DATA(insert OID = 1200 (  int42reltime     PGUID 11 f t f 1 f 703 "21" 100 0 0 100  foo bar ));
 
 DATA(insert OID = 1290 (  char2icregexeq   PGUID 11 f t f 2 f 16 "409 25" 100 0 0 100  foo bar ));
@@ -826,6 +834,7 @@ DATA(insert OID = 1298 (  timestamp_out    PGUID 11 f t f 1 f 23 "0" 100 0 0 100
 DATA(insert OID = 1299 (  now              PGUID 11 f t f 0 f 1296 "0" 100 0 0 100  foo bar ));
 
 /* OIDS 1300 - 1399 */
+
 DATA(insert OID = 1306 (  timestampeq      PGUID 11 f t f 2 f 16 "1296 1296" 100 0 0 100  foo bar ));
 DATA(insert OID = 1307 (  timestampne      PGUID 11 f t f 2 f 16 "1296 1296" 100 0 0 100  foo bar ));
 DATA(insert OID = 1308 (  timestamplt      PGUID 11 f t f 2 f 16 "1296 1296" 100 0 0 100  foo bar ));
@@ -873,6 +882,7 @@ DATA(insert OID = 1392 (  isfinite     PGUID 14 f t f 1 f   16  "702" 100 0 0 10
 /* reserve OIDs 1370-1399 for additional date/time conversion routines! tgl 97/04/01 */
 
 /* OIDS 1400 - 1499 */
+
 DATA(insert OID = 1400 (  float        PGUID 14 f t f 1 f  701  "701" 100 0 0 100  "select $1" - ));
 DATA(insert OID = 1401 (  float        PGUID 14 f t f 1 f  701  "700" 100 0 0 100  "select ftod($1)" - ));
 DATA(insert OID = 1402 (  float4       PGUID 14 f t f 1 f  700  "700" 100 0 0 100  "select $1" - ));
@@ -880,6 +890,109 @@ DATA(insert OID = 1403 (  float4       PGUID 14 f t f 1 f  700  "701" 100 0 0 10
 DATA(insert OID = 1404 (  int          PGUID 14 f t f 1 f   23   "23" 100 0 0 100  "select $1" - ));
 DATA(insert OID = 1405 (  int2         PGUID 14 f t f 1 f   21   "21" 100 0 0 100  "select $1" - ));
 
+DATA(insert OID = 1421 (  box               PGUID 11 f t f 2 f 603 "600 600" 100 0 0 100  foo bar ));
+DATA(insert OID = 1422 (  box_add           PGUID 11 f t f 2 f 603 "603 600" 100 0 0 100  foo bar ));
+DATA(insert OID = 1423 (  box_sub           PGUID 11 f t f 2 f 603 "603 600" 100 0 0 100  foo bar ));
+DATA(insert OID = 1424 (  box_mul           PGUID 11 f t f 2 f 603 "603 600" 100 0 0 100  foo bar ));
+DATA(insert OID = 1425 (  box_div           PGUID 11 f t f 2 f 603 "603 600" 100 0 0 100  foo bar ));
+
+DATA(insert OID = 1430 (  path_isclosed     PGUID 11 f t f 1 f  16 "602" 100 0 0 100  foo bar ));
+DATA(insert OID = 1431 (  path_isopen       PGUID 11 f t f 1 f  16 "602" 100 0 0 100  foo bar ));
+DATA(insert OID = 1432 (  path_npoints      PGUID 11 f t f 1 f  23 "602" 100 0 0 100  foo bar ));
+DATA(insert OID = 1433 (  path_close        PGUID 11 f t f 1 f 602 "602" 100 0 0 100  foo bar ));
+DATA(insert OID = 1434 (  path_open         PGUID 11 f t f 1 f 602 "602" 100 0 0 100  foo bar ));
+DATA(insert OID = 1435 (  path_add          PGUID 11 f t f 2 f 602 "602 602" 100 0 0 100  foo bar ));
+DATA(insert OID = 1436 (  path_add_pt       PGUID 11 f t f 2 f 602 "602 600" 100 0 0 100  foo bar ));
+DATA(insert OID = 1437 (  path_sub_pt       PGUID 11 f t f 2 f 602 "602 600" 100 0 0 100  foo bar ));
+DATA(insert OID = 1438 (  path_mul_pt       PGUID 11 f t f 2 f 602 "602 600" 100 0 0 100  foo bar ));
+DATA(insert OID = 1439 (  path_div_pt       PGUID 11 f t f 2 f 602 "602 600" 100 0 0 100  foo bar ));
+
+DATA(insert OID = 1440 (  point             PGUID 11 f t f 2 f 600 "701 701" 100 0 0 100  foo bar ));
+DATA(insert OID = 1441 (  point_add         PGUID 11 f t f 2 f 600 "600 600" 100 0 0 100  foo bar ));
+DATA(insert OID = 1442 (  point_sub         PGUID 11 f t f 2 f 600 "600 600" 100 0 0 100  foo bar ));
+DATA(insert OID = 1443 (  point_mul         PGUID 11 f t f 2 f 600 "600 600" 100 0 0 100  foo bar ));
+DATA(insert OID = 1444 (  point_div         PGUID 11 f t f 2 f 600 "600 600" 100 0 0 100  foo bar ));
+
+DATA(insert OID = 1445 (  poly_npoints      PGUID 11 f t f 1 f  23 "604" 100 0 0 100  foo bar ));
+DATA(insert OID = 1446 (  poly_box          PGUID 11 f t f 1 f 603 "604" 100 0 0 100  foo bar ));
+DATA(insert OID = 1447 (  poly_path         PGUID 11 f t f 1 f 602 "604" 100 0 0 100  foo bar ));
+DATA(insert OID = 1448 (  box_poly          PGUID 11 f t f 1 f 604 "603" 100 0 0 100  foo bar ));
+DATA(insert OID = 1449 (  path_poly         PGUID 11 f t f 1 f 604 "602" 100 0 0 100  foo bar ));
+
+DATA(insert OID = 1450 (  circle_in         PGUID 11 f t f 1 f 718 "0" 100 0 1 0  foo bar ));
+DATA(insert OID = 1451 (  circle_out        PGUID 11 f t f 1 f  23  "0" 100 0 1 0  foo bar ));
+DATA(insert OID = 1452 (  circle_same       PGUID 11 f t f 2 f  16 "718 718" 100 0 1 0  foo bar ));
+DATA(insert OID = 1453 (  circle_contain    PGUID 11 f t f 2 f  16 "718 718" 100 0 1 0  foo bar ));
+DATA(insert OID = 1454 (  circle_left       PGUID 11 f t f 2 f  16 "718 718" 100 0 1 0  foo bar ));
+DATA(insert OID = 1455 (  circle_overleft   PGUID 11 f t f 2 f  16 "718 718" 100 0 1 0  foo bar ));
+DATA(insert OID = 1456 (  circle_overright  PGUID 11 f t f 2 f  16 "718 718" 100 0 1 0  foo bar ));
+DATA(insert OID = 1457 (  circle_right      PGUID 11 f t f 2 f  16 "718 718" 100 0 1 0  foo bar ));
+DATA(insert OID = 1458 (  circle_contained  PGUID 11 f t f 2 f  16 "718 718" 100 0 1 0  foo bar ));
+DATA(insert OID = 1459 (  circle_overlap    PGUID 11 f t f 2 f  16 "718 718" 100 0 1 0  foo bar ));
+DATA(insert OID = 1460 (  circle_below      PGUID 11 f t f 2 f  16 "718 718" 100 0 1 0  foo bar ));
+DATA(insert OID = 1461 (  circle_above      PGUID 11 f t f 2 f  16 "718 718" 100 0 1 0  foo bar ));
+DATA(insert OID = 1462 (  circle_eq         PGUID 11 f t f 2 f  16 "718 718" 100 0 1 0  foo bar ));
+DATA(insert OID = 1463 (  circle_ne         PGUID 11 f t f 2 f  16 "718 718" 100 0 1 0  foo bar ));
+DATA(insert OID = 1464 (  circle_lt         PGUID 11 f t f 2 f  16 "718 718" 100 0 1 0  foo bar ));
+DATA(insert OID = 1465 (  circle_gt         PGUID 11 f t f 2 f  16 "718 718" 100 0 1 0  foo bar ));
+DATA(insert OID = 1466 (  circle_le         PGUID 11 f t f 2 f  16 "718 718" 100 0 1 0  foo bar ));
+DATA(insert OID = 1467 (  circle_ge         PGUID 11 f t f 2 f  16 "718 718" 100 0 1 0  foo bar ));
+DATA(insert OID = 1468 (  circle_area       PGUID 11 f t f 1 f 701 "718" 100 0 1 0  foo bar ));
+DATA(insert OID = 1469 (  circle_diameter   PGUID 11 f t f 1 f 701 "718" 100 0 1 0  foo bar ));
+DATA(insert OID = 1470 (  circle_radius     PGUID 11 f t f 1 f 701 "718" 100 0 1 0  foo bar ));
+DATA(insert OID = 1471 (  circle_distance   PGUID 11 f t f 2 f 701 "718 718" 100 0 1 0  foo bar ));
+DATA(insert OID = 1472 (  circle_center     PGUID 11 f t f 1 f 600 "718" 100 0 1 0  foo bar ));
+DATA(insert OID = 1473 (  circle            PGUID 11 f t f 2 f 718 "600 701" 100 0 1 0  foo bar ));
+DATA(insert OID = 1474 (  poly_circle       PGUID 11 f t f 1 f 718 "604" 100 0 1 0  foo bar ));
+DATA(insert OID = 1475 (  circle_poly       PGUID 11 f t f 2 f 604 "23 718" 100 0 1 0  foo bar ));
+
+DATA(insert OID = 1530 (  point             PGUID 14 f t f 2 f 600 "601 601" 100 0 0 100  "select lseg_interpt($1, $2)" - ));
+DATA(insert OID = 1531 (  point             PGUID 14 f t f 1 f 600 "718" 100 0 0 100  "select circle_center($1)" - ));
+DATA(insert OID = 1532 (  isvertical        PGUID 14 f t f 2 f  16 "600 600" 100 0 0 100  "select point_vert($1, $2)" - ));
+DATA(insert OID = 1533 (  ishorizonal       PGUID 14 f t f 2 f  16 "600 600" 100 0 0 100  "select point_horiz($1, $2)" - ));
+DATA(insert OID = 1534 (  slope             PGUID 14 f t f 2 f 701 "600 600" 100 0 0 100  "select point_slope($1, $2)" - ));
+
+DATA(insert OID = 1540 (  lseg              PGUID 14 f t f 2 f 601 "600 600" 100 0 0 100  "select lseg_construct($1, $2)" - ));
+DATA(insert OID = 1541 (  lseg              PGUID 14 f t f 1 f 601 "603" 100 0 0 100  "select box_diagonal($1)" - ));
+DATA(insert OID = 1542 (  isparallel        PGUID 14 f t f 2 f  16 "601 601" 100 0 0 100  "select lseg_parallel($1, $2)" - ));
+DATA(insert OID = 1543 (  isperpendicular   PGUID 14 f t f 2 f  16 "601 601" 100 0 0 100  "select lseg_perp($1, $2)" - ));
+DATA(insert OID = 1544 (  isvertical        PGUID 14 f t f 1 f  16 "601" 100 0 0 100  "select lseg_vertical($1)" - ));
+DATA(insert OID = 1545 (  ishorizontal      PGUID 14 f t f 1 f  16 "601" 100 0 0 100  "select lseg_horizontal($1)" - ));
+
+/* XXX "length" for boxes is different than "length" for paths, so use "width" for boxes instead.
+ * should go back into code and change subroutine name from "box_length" to "box_width".
+ * pclose and popen might better be named close and open, but that crashes initdb.
+ * - tgl 97/04/20
+ */
+
+DATA(insert OID = 1550 (  path              PGUID 14 f t f 1 f 602 "604" 100 0 0 100  "select poly_path($1)" - ));
+DATA(insert OID = 1551 (  length            PGUID 14 f t f 1 f 701 "602" 100 0 1 0  "select path_length($1)" - ));
+DATA(insert OID = 1552 (  points            PGUID 14 f t f 1 f  23 "602" 100 0 0 100  "select path_npoints($1)" - ));
+DATA(insert OID = 1553 (  pclose            PGUID 14 f t f 1 f 602 "602" 100 0 0 100  "select path_close($1)" - ));
+DATA(insert OID = 1554 (  popen             PGUID 14 f t f 1 f 602 "602" 100 0 0 100  "select path_open($1)" - ));
+DATA(insert OID = 1555 (  isopen            PGUID 14 f t f 1 f  16 "602" 100 0 0 100  "select path_isopen($1)" - ));
+DATA(insert OID = 1555 (  isclosed          PGUID 14 f t f 1 f  16 "602" 100 0 0 100  "select path_isclosed($1)" - ));
+
+DATA(insert OID = 1560 (  box               PGUID 14 f t f 2 f 603 "603 603" 100 0 0 100  "select box_intersect($1, $2)" - ));
+DATA(insert OID = 1561 (  box               PGUID 14 f t f 1 f 603 "604" 100 0 0 100  "select poly_box($1)" - ));
+DATA(insert OID = 1562 (  width             PGUID 14 f t f 1 f 701 "603" 100 0 0 100  "select box_length($1)" - ));
+DATA(insert OID = 1563 (  height            PGUID 14 f t f 1 f 701 "603" 100 0 0 100  "select box_height($1)" - ));
+DATA(insert OID = 1564 (  center            PGUID 14 f t f 1 f 600 "603" 100 0 0 100  "select box_center($1)" - ));
+DATA(insert OID = 1565 (  area              PGUID 14 f t f 1 f 701 "603" 100 0 0 100  "select box_area($1)" - ));
+
+DATA(insert OID = 1570 (  polygon           PGUID 14 f t f 1 f 604 "602" 100 0 0 100  "select path_poly($1)" - ));
+DATA(insert OID = 1571 (  polygon           PGUID 14 f t f 1 f 604 "603" 100 0 0 100  "select box_poly($1)" - ));
+DATA(insert OID = 1572 (  polygon           PGUID 14 f t f 2 f 604 "23 718" 100 0 0 100  "select circle_poly($1, $2)" - ));
+DATA(insert OID = 1573 (  polygon           PGUID 14 f t f 1 f 604 "718" 100 0 0 100  "select circle_poly(12, $1)" - ));
+DATA(insert OID = 1574 (  points            PGUID 14 f t f 1 f  23 "604" 100 0 0 100  "select poly_npoints($1)" - ));
+DATA(insert OID = 1575 (  center            PGUID 14 f t f 1 f 600 "604" 100 0 0 100  "select poly_center($1)" - ));
+
+DATA(insert OID = 1580 (  circle            PGUID 14 f t f 1 f 701 "604" 100 0 0 100  "select poly_circle($1)" - ));
+DATA(insert OID = 1581 (  center            PGUID 14 f t f 1 f 600 "718" 100 0 0 100  "select circle_center($1)" - ));
+DATA(insert OID = 1582 (  radius            PGUID 14 f t f 1 f 701 "718" 100 0 0 100  "select circle_radius($1)" - ));
+DATA(insert OID = 1583 (  diameter          PGUID 14 f t f 1 f 701 "718" 100 0 0 100  "select circle_diameter($1)" - ));
+DATA(insert OID = 1584 (  area              PGUID 14 f t f 1 f 701 "718" 100 0 0 100  "select circle_area($1)" - ));
+
 /* Oracle Compatibility Related Functions - By Edmund Mergl <E.Mergl@bawue.de> */
 DATA(insert OID =  870 (  lower        PGUID 11 f t f 1 f 25 "25" 100 0 0 100  foo bar ));
 DATA(insert OID =  871 (  upper        PGUID 11 f t f 1 f 25 "25" 100 0 0 100  foo bar ));
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index f5a59fffd42658e9ba7d528752b02720bb2c087f..ccd01349eac43b7124e8d1b5daa41fd8b01bcbe1 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -7,7 +7,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_type.h,v 1.10 1997/04/15 17:41:19 scrappy Exp $
+ * $Id: pg_type.h,v 1.11 1997/04/22 17:32:26 scrappy Exp $
  *
  * NOTES
  *    the genbki.sh script reads this file and generates .bki
@@ -220,7 +220,10 @@ DATA(insert OID = 601 (  lseg      PGUID 32  48 f b t \054 0 600 lseg_in lseg_ou
 DATA(insert OID = 602 (  path      PGUID -1  -1 f b t \054 0 600 path_in path_out path_in path_out d _null_ ));
 DATA(insert OID = 603 (  box       PGUID 32 100 f b t \073 0 600 box_in box_out box_in box_out d _null_ ));
 DATA(insert OID = 604 (  polygon   PGUID -1  -1 f b t \054 0  -1 poly_in poly_out poly_in poly_out d _null_ ));
-DATA(insert OID = 605 (  filename  PGUID 256 -1 f b t \054 0 18 filename_in filename_out filename_in filename_out i _null_ ));
+DATA(insert OID = 605 (  filename  PGUID 256 -1 f b t \054 0  18 filename_in filename_out filename_in filename_out i _null_ ));
+
+DATA(insert OID = 628 (  line      PGUID 32  48 f b t \054 0 701 line_in line_out line_in line_out d _null_ ));
+DATA(insert OID = 629 (  _line     PGUID  -1 -1 f b t \054 0 628 array_in array_out array_in array_out d _null_ ));
 
 /* OIDS 700 - 799 */
 
@@ -234,8 +237,9 @@ DATA(insert OID = 704 (  tinterval PGUID 12  47 f b t \054 0   0 tintervalin tin
 DATA(insert OID = 705 (  unknown   PGUID -1  -1 f b t \054 0   18 textin textout textin textout i _null_ ));
 #define UNKNOWNOID	705
 
-DATA(insert OID = 790 (  money     PGUID  4  47 f b t \054 0    0 cash_in cash_out cash_in cash_out i _null_ ));
-#define CASHOID	790
+DATA(insert OID = 718 (  circle    PGUID  24 47 f b t \054 0    0 circle_in circle_out circle_in circle_out d _null_ ));
+DATA(insert OID = 719 (  _circle   PGUID  -1 -1 f b t \054 0  718 array_in array_out array_in array_out i _null_ ));
+DATA(insert OID = 790 (  money     PGUID   4 24 f b t \054 0    0 cash_in cash_out cash_in cash_out i _null_ ));
 DATA(insert OID = 791 (  _money    PGUID  -1 -1 f b t \054 0  790 array_in array_out array_in array_out i _null_ ));
 
 /* OIDS 800 - 899 */
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index d9f156d422ca6812f0fc03b622397d89f93ed492..cdd9f6895a687381f5f89e680d0022ee8e2821e3 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -1,17 +1,18 @@
 /*-------------------------------------------------------------------------
  *
- * geo_decls.h--
- *    Declarations for various 2D constructs.
+ * geo_decls.h - Declarations for various 2D constructs.
  *
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: geo_decls.h,v 1.1 1997/03/14 23:33:27 scrappy Exp $
+ * $Id: geo_decls.h,v 1.2 1997/04/22 17:32:41 scrappy Exp $
  *
  * NOTE
  *    These routines do *not* use the float types from adt/.
  *
  *    XXX These routines were not written by a numerical analyst.
+ *    XXX I have made some attempt to flesh out the operators
+ *	and data types. There are still some more to do. - tgl 97/04/19
  *
  *-------------------------------------------------------------------------
  */
@@ -23,23 +24,32 @@
 /*#ifndef FmgrIncluded -- seems like always included. (it's FMgrIncluded) AY */
 
 /*--------------------------------------------------------------------
- *	Useful floating point utilities and constants.
+ * Useful floating point utilities and constants.
  *-------------------------------------------------------------------*/
 
 
 #define	EPSILON			1.0E-06
 
+#ifdef EPSILON
 #define	FPzero(A)		(fabs(A) <= EPSILON)
 #define	FPeq(A,B)		(fabs((A) - (B)) <= EPSILON)
 #define	FPlt(A,B)		((B) - (A) > EPSILON)
 #define	FPle(A,B)		((A) - (B) <= EPSILON)
 #define	FPgt(A,B)		((A) - (B) > EPSILON)
 #define	FPge(A,B)		((B) - (A) <= EPSILON)
+#else
+#define	FPzero(A)		(A == 0)
+#define	FPeq(A,B)		(A == B)
+#define	FPlt(A,B)		(A < B)
+#define	FPle(A,B)		(A <= B)
+#define	FPgt(A,B)		(A > B)
+#define	FPge(A,B)		(A >= B)
+#endif
 
 #define	HYPOT(A, B)		sqrt((A) * (A) + (B) * (B))
 
 /*--------------------------------------------------------------------
- *	Memory management.
+ * Memory management.
  *-------------------------------------------------------------------*/
 
 #define	PALLOC(SIZE)		palloc(SIZE)
@@ -49,7 +59,7 @@
 /*#endif !FmgrIncluded */
 
 /*---------------------------------------------------------------------
- *	Point	-	(x,y)
+ * Point - (x,y)
  *-------------------------------------------------------------------*/
 typedef struct {
 	double	x, y;
@@ -57,7 +67,7 @@ typedef struct {
 
 
 /*---------------------------------------------------------------------
- *	LSEG	- 	A straight line, specified by endpoints.
+ * LSEG	- A straight line, specified by endpoints.
  *-------------------------------------------------------------------*/
 typedef	struct {
 	Point	p[2];
@@ -67,24 +77,24 @@ typedef	struct {
 
 
 /*---------------------------------------------------------------------
- *	PATH	- 	Specified by vertex points.
+ * PATH	- Specified by vertex points.
  *-------------------------------------------------------------------*/
 typedef	struct {
-	int32	length;	/* XXX varlena */
+	int32	size;	/* XXX varlena */
 	int32	npts;
 	int32	closed;	/* is this a closed polygon? */
 	int32	dummy;	/* padding to make it double align */
-	Point	p[1];	/* variable length array of POINTs */
+	Point	p[0];	/* variable length array of POINTs */
 } PATH;
 
 
 /*---------------------------------------------------------------------
- *	LINE	-	Specified by its general equation (Ax+By+C=0).
- *			If there is a y-intercept, it is C, which
- *			 incidentally gives a freebie point on the line
- *			 (if B=0, then C is the x-intercept).
- *			Slope m is precalculated to save time; if
- *			 the line is not vertical, m == A.
+ * LINE	- Specified by its general equation (Ax+By+C=0).
+ *	If there is a y-intercept, it is C, which
+ *	 incidentally gives a freebie point on the line
+ *	 (if B=0, then C is the x-intercept).
+ *	Slope m is precalculated to save time; if
+ *	 the line is not vertical, m == A.
  *-------------------------------------------------------------------*/
 typedef struct {
 	double	A, B, C;
@@ -93,25 +103,32 @@ typedef struct {
 
 
 /*---------------------------------------------------------------------
- *	BOX	- 	Specified by two corner points, which are
- *			 sorted to save calculation time later.
+ * BOX	- Specified by two corner points, which are
+ *	 sorted to save calculation time later.
  *-------------------------------------------------------------------*/
 typedef struct {
-	double	xh, yh, xl, yl;		/* high and low coords */
+	Point	high, low;	/* corner POINTs */
 } BOX;
 
 /*---------------------------------------------------------------------
- *  POLYGON - Specified by an array of doubles defining the points, 
- *			  keeping the number of points and the bounding box for 
- *			  speed purposes.
+ * POLYGON - Specified by an array of doubles defining the points, 
+ *	keeping the number of points and the bounding box for 
+ *	speed purposes.
  *-------------------------------------------------------------------*/
 typedef struct {
 	int32 size;	/* XXX varlena */
 	int32 npts;
 	BOX boundbox;
-	char pts[1];
+	Point p[0];	/* variable length array of POINTs */
 } POLYGON;
 
+/*---------------------------------------------------------------------
+ * CIRCLE - Specified by a center point and radius.
+ *-------------------------------------------------------------------*/
+typedef struct {
+    Point       center;
+    double      radius;
+} CIRCLE;
 
 /* 
  * in geo_ops.h
@@ -121,81 +138,115 @@ extern char *box_out(BOX *box);
 extern BOX *box_construct(double x1, double x2, double y1, double y2);
 extern BOX *box_fill(BOX *result, double x1, double x2, double y1, double y2);
 extern BOX *box_copy(BOX *box);
-extern long box_same(BOX *box1, BOX *box2);
-extern long box_overlap(BOX *box1, BOX *box2);
-extern long box_overleft(BOX *box1, BOX *box2);
-extern long box_left(BOX *box1, BOX *box2);
-extern long box_right(BOX *box1, BOX *box2);
-extern long box_overright(BOX *box1, BOX *box2);
-extern long box_contained(BOX *box1, BOX *box2);
-extern long box_contain(BOX *box1, BOX *box2);
-extern long box_below(BOX *box1, BOX *box2);
-extern long box_above(BOX *box1, BOX *box2);
-extern long box_lt(BOX *box1, BOX *box2);
-extern long box_gt(BOX *box1, BOX *box2);
-extern long box_eq(BOX *box1, BOX *box2);
-extern long box_le(BOX *box1, BOX *box2);
-extern long box_ge(BOX *box1, BOX *box2);
+extern bool box_same(BOX *box1, BOX *box2);
+extern bool box_overlap(BOX *box1, BOX *box2);
+extern bool box_overleft(BOX *box1, BOX *box2);
+extern bool box_left(BOX *box1, BOX *box2);
+extern bool box_right(BOX *box1, BOX *box2);
+extern bool box_overright(BOX *box1, BOX *box2);
+extern bool box_contained(BOX *box1, BOX *box2);
+extern bool box_contain(BOX *box1, BOX *box2);
+extern bool box_below(BOX *box1, BOX *box2);
+extern bool box_above(BOX *box1, BOX *box2);
+extern bool box_lt(BOX *box1, BOX *box2);
+extern bool box_gt(BOX *box1, BOX *box2);
+extern bool box_eq(BOX *box1, BOX *box2);
+extern bool box_le(BOX *box1, BOX *box2);
+extern bool box_ge(BOX *box1, BOX *box2);
+extern Point *box_center(BOX *box);
 extern double *box_area(BOX *box);
 extern double *box_length(BOX *box);
 extern double *box_height(BOX *box);
 extern double *box_distance(BOX *box1, BOX *box2);
 extern Point *box_center(BOX *box);
+extern BOX *box_intersect(BOX *box1, BOX *box2);
+extern LSEG *box_diagonal(BOX *box);
+
+/* private routines */
 extern double box_ar(BOX *box);
 extern double box_ln(BOX *box);
 extern double box_ht(BOX *box);
 extern double box_dt(BOX *box1, BOX *box2);
-extern BOX *box_intersect(BOX *box1, BOX *box2);
-extern LSEG *box_diagonal(BOX *box);
+
+extern BOX *box(Point *p1, Point *p2);
+extern BOX *box_add(BOX *box, Point *p);
+extern BOX *box_sub(BOX *box, Point *p);
+extern BOX *box_mul(BOX *box, Point *p);
+extern BOX *box_div(BOX *box, Point *p);
+
 extern LINE *line_construct_pm(Point *pt, double m);
 extern LINE *line_construct_pp(Point *pt1, Point *pt2);
-extern long line_intersect(LINE *l1, LINE *l2);
-extern long line_parallel(LINE *l1, LINE *l2);
-extern long line_perp(LINE *l1, LINE *l2);
-extern long line_vertical(LINE *line);
-extern long line_horizontal(LINE *line);
-extern long line_eq(LINE *l1, LINE *l2);
+extern bool line_intersect(LINE *l1, LINE *l2);
+extern bool line_parallel(LINE *l1, LINE *l2);
+extern bool line_perp(LINE *l1, LINE *l2);
+extern bool line_vertical(LINE *line);
+extern bool line_horizontal(LINE *line);
+extern bool line_eq(LINE *l1, LINE *l2);
 extern double *line_distance(LINE *l1, LINE *l2);
 extern Point *line_interpt(LINE *l1, LINE *l2);
+
 extern PATH *path_in(char *str);
 extern char *path_out(PATH *path);
-extern long path_n_lt(PATH *p1, PATH *p2);
-extern long path_n_gt(PATH *p1, PATH *p2);
-extern long path_n_eq(PATH *p1, PATH *p2);
-extern long path_n_le(PATH *p1, PATH *p2);
-extern long path_n_ge(PATH *p1, PATH *p2);
-extern long path_inter(PATH *p1, PATH *p2);
+extern bool path_n_lt(PATH *p1, PATH *p2);
+extern bool path_n_gt(PATH *p1, PATH *p2);
+extern bool path_n_eq(PATH *p1, PATH *p2);
+extern bool path_n_le(PATH *p1, PATH *p2);
+extern bool path_n_ge(PATH *p1, PATH *p2);
+extern bool path_inter(PATH *p1, PATH *p2);
 extern double *path_distance(PATH *p1, PATH *p2);
 extern double *path_length(PATH *path);
+
+/* private routines */
 extern double path_ln(PATH *path);
+
+extern bool path_isclosed(PATH *path);
+extern bool path_isopen(PATH *path);
+extern int4 path_npoints(PATH *path);
+
+extern PATH *path_close(PATH *path);
+extern PATH *path_open(PATH *path);
+extern PATH *path_add(PATH *p1, PATH *p2);
+extern PATH *path_add_pt(PATH *path, Point *point);
+extern PATH *path_sub_pt(PATH *path, Point *point);
+extern PATH *path_mul_pt(PATH *path, Point *point);
+extern PATH *path_div_pt(PATH *path, Point *point);
+
+extern POLYGON *path_poly(PATH *path);
+
 extern Point *point_in(char *str);
 extern char *point_out(Point *pt);
 extern Point *point_construct(double x, double y);
 extern Point *point_copy(Point *pt);
-extern long point_left(Point *pt1, Point *pt2);
-extern long point_right(Point *pt1, Point *pt2);
-extern long point_above(Point *pt1, Point *pt2);
-extern long point_below(Point *pt1, Point *pt2);
-extern long point_vert(Point *pt1, Point *pt2);
-extern long point_horiz(Point *pt1, Point *pt2);
-extern long point_eq(Point *pt1, Point *pt2);
-extern long pointdist(Point *p1, Point *p2);
+extern bool point_left(Point *pt1, Point *pt2);
+extern bool point_right(Point *pt1, Point *pt2);
+extern bool point_above(Point *pt1, Point *pt2);
+extern bool point_below(Point *pt1, Point *pt2);
+extern bool point_vert(Point *pt1, Point *pt2);
+extern bool point_horiz(Point *pt1, Point *pt2);
+extern bool point_eq(Point *pt1, Point *pt2);
+extern int32 pointdist(Point *p1, Point *p2);
 extern double *point_distance(Point *pt1, Point *pt2);
-extern double point_dt(Point *pt1, Point *pt2);
 extern double *point_slope(Point *pt1, Point *pt2);
+
+/* private routines */
+extern double point_dt(Point *pt1, Point *pt2);
 extern double point_sl(Point *pt1, Point *pt2);
+
+extern Point *point(float8 *x, float8 *y);
+extern Point *point_add(Point *p1, Point *p2);
+extern Point *point_sub(Point *p1, Point *p2);
+extern Point *point_mul(Point *p1, Point *p2);
+extern Point *point_div(Point *p1, Point *p2);
+
 extern LSEG *lseg_in(char *str);
 extern char *lseg_out(LSEG *ls);
-extern LSEG *lseg_construct(Point *pt1, Point *pt2);
-extern void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
-extern long lseg_intersect(LSEG *l1, LSEG *l2);
-extern long lseg_parallel(LSEG *l1, LSEG *l2);
-extern long lseg_perp(LSEG *l1, LSEG *l2);
-extern long lseg_vertical(LSEG *lseg);
-extern long lseg_horizontal(LSEG *lseg);
-extern long lseg_eq(LSEG *l1, LSEG *l2);
+extern bool lseg_intersect(LSEG *l1, LSEG *l2);
+extern bool lseg_parallel(LSEG *l1, LSEG *l2);
+extern bool lseg_perp(LSEG *l1, LSEG *l2);
+extern bool lseg_vertical(LSEG *lseg);
+extern bool lseg_horizontal(LSEG *lseg);
+extern bool lseg_eq(LSEG *l1, LSEG *l2);
 extern double *lseg_distance(LSEG *l1, LSEG *l2);
-extern double lseg_dt(LSEG *l1, LSEG *l2);
 extern Point *lseg_interpt(LSEG *l1, LSEG *l2);
 extern double *dist_pl(Point *pt, LINE *line);
 extern double *dist_ps(Point *pt, LSEG *lseg);
@@ -211,29 +262,73 @@ extern Point *close_pb(Point *pt, BOX *box);
 extern Point *close_sl(LSEG *lseg, LINE *line);
 extern Point *close_sb(LSEG *lseg, BOX *box);
 extern Point *close_lb(LINE *line, BOX *box);
-extern long on_pl(Point *pt, LINE *line);
-extern long on_ps(Point *pt, LSEG *lseg);
-extern long on_pb(Point *pt, BOX *box);
-extern long on_ppath(Point *pt, PATH *path);
-extern long on_sl(LSEG *lseg, LINE *line);
-extern long on_sb(LSEG *lseg, BOX *box);
-extern long inter_sl(LSEG *lseg, LINE *line);
-extern long inter_sb(LSEG *lseg, BOX *box);
-extern long inter_lb(LINE *line, BOX *box);
+extern bool on_pl(Point *pt, LINE *line);
+extern bool on_ps(Point *pt, LSEG *lseg);
+extern bool on_pb(Point *pt, BOX *box);
+extern bool on_ppath(Point *pt, PATH *path);
+extern bool on_sl(LSEG *lseg, LINE *line);
+extern bool on_sb(LSEG *lseg, BOX *box);
+extern bool inter_sl(LSEG *lseg, LINE *line);
+extern bool inter_sb(LSEG *lseg, BOX *box);
+extern bool inter_lb(LINE *line, BOX *box);
+
+/* private routines */
+extern LSEG *lseg_construct(Point *pt1, Point *pt2);
+extern void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
+extern double lseg_dt(LSEG *l1, LSEG *l2);
 extern void make_bound_box(POLYGON *poly);
+
 extern POLYGON *poly_in(char *s);
-extern long poly_pt_count(char *s, char delim);
 extern char *poly_out(POLYGON *poly);
-extern double poly_max(double *coords, int ncoords);
-extern double poly_min(double *coords, int ncoords);
-extern long poly_left(POLYGON *polya, POLYGON *polyb);
-extern long poly_overleft(POLYGON *polya, POLYGON *polyb);
-extern long poly_right(POLYGON *polya, POLYGON *polyb);
-extern long poly_overright(POLYGON *polya, POLYGON *polyb);
-extern long poly_same(POLYGON *polya, POLYGON *polyb);
-extern long poly_overlap(POLYGON *polya, POLYGON *polyb);
-extern long poly_contain(POLYGON *polya, POLYGON *polyb);
-extern long poly_contained(POLYGON *polya, POLYGON *polyb);
+extern bool poly_left(POLYGON *polya, POLYGON *polyb);
+extern bool poly_overleft(POLYGON *polya, POLYGON *polyb);
+extern bool poly_right(POLYGON *polya, POLYGON *polyb);
+extern bool poly_overright(POLYGON *polya, POLYGON *polyb);
+extern bool poly_same(POLYGON *polya, POLYGON *polyb);
+extern bool poly_overlap(POLYGON *polya, POLYGON *polyb);
+extern bool poly_contain(POLYGON *polya, POLYGON *polyb);
+extern bool poly_contained(POLYGON *polya, POLYGON *polyb);
+
+extern int4 poly_npoints(POLYGON *poly);
+extern BOX *poly_box(POLYGON *poly);
+extern PATH *poly_path(POLYGON *poly);
+extern POLYGON *box_poly(BOX *box);
+
+extern CIRCLE *circle_in(char *str);
+extern char *circle_out(CIRCLE *circle);
+extern bool circle_same(CIRCLE *circle1, CIRCLE *circle2);
+extern bool circle_overlap(CIRCLE *circle1, CIRCLE *circle2);
+extern bool circle_overleft(CIRCLE *circle1, CIRCLE *circle2);
+extern bool circle_left(CIRCLE *circle1, CIRCLE *circle2);
+extern bool circle_right(CIRCLE *circle1, CIRCLE *circle2);
+extern bool circle_overright(CIRCLE *circle1, CIRCLE *circle2);
+extern bool circle_contained(CIRCLE *circle1, CIRCLE *circle2);
+extern bool circle_contain(CIRCLE *circle1, CIRCLE *circle2);
+extern bool circle_below(CIRCLE *circle1, CIRCLE *circle2);
+extern bool circle_above(CIRCLE *circle1, CIRCLE *circle2);
+
+extern bool circle_eq(CIRCLE *circle1, CIRCLE *circle2);
+extern bool circle_ne(CIRCLE *circle1, CIRCLE *circle2);
+extern bool circle_lt(CIRCLE *circle1, CIRCLE *circle2);
+extern bool circle_gt(CIRCLE *circle1, CIRCLE *circle2);
+extern bool circle_le(CIRCLE *circle1, CIRCLE *circle2);
+extern bool circle_ge(CIRCLE *circle1, CIRCLE *circle2);
+extern CIRCLE *circle_add_pt(CIRCLE *circle, Point *point);
+extern CIRCLE *circle_sub_pt(CIRCLE *circle, Point *point);
+extern CIRCLE *circle_mul_pt(CIRCLE *circle, Point *point);
+extern CIRCLE *circle_div_pt(CIRCLE *circle, Point *point);
+extern double *circle_area(CIRCLE *circle);
+extern double *circle_diameter(CIRCLE *circle);
+extern double *circle_radius(CIRCLE *circle);
+extern double *circle_distance(CIRCLE *circle1, CIRCLE *circle2);
+extern Point *circle_center(CIRCLE *circle);
+extern CIRCLE *circle(Point *center, float8 *radius);
+extern CIRCLE *poly_circle(POLYGON *poly);
+extern POLYGON *circle_poly(int npts, CIRCLE *circle);
+
+/* private routines */
+extern double circle_ar(CIRCLE *circle);
+extern double circle_dt(CIRCLE *circle1, CIRCLE *circle2);
 
 /* geo_selfuncs.c */
 extern float64 areasel(Oid opid, Oid relid, AttrNumber attno, 
@@ -247,6 +342,6 @@ extern float64 leftjoinsel(Oid opid, Oid relid, AttrNumber attno,
 extern float64 contsel(Oid opid, Oid relid, AttrNumber attno,
 	char *value, int32 flag);
 extern float64 contjoinsel(Oid opid, Oid relid, AttrNumber attno,
-	    char *value, int32 flag);
+	char *value, int32 flag);
 
 #endif	/* GEO_DECLS_H */
diff --git a/src/test/regress/expected/create_operator.out b/src/test/regress/expected/create_operator.out
index c45e48a839633928d85d8ca8c6dfc1a725e2a14b..cc9217826d2524ceece702b54e75d7b9b7c1cdf1 100644
--- a/src/test/regress/expected/create_operator.out
+++ b/src/test/regress/expected/create_operator.out
@@ -6,8 +6,8 @@ QUERY: CREATE OPERATOR ## (
 );
 QUERY: CREATE OPERATOR <% (
    leftarg = point,
-   rightarg = circle,
-   procedure = pt_in_circle,
+   rightarg = widget,
+   procedure = pt_in_widget,
    commutator = >=%
 );
 QUERY: CREATE OPERATOR @#@ (
diff --git a/src/test/regress/expected/create_type.out b/src/test/regress/expected/create_type.out
index 7919b01e37b0a907ed442d928469ce519dd4076d..104a9eb5b8e5ca349e17c8458f4e4901a120be85 100644
--- a/src/test/regress/expected/create_type.out
+++ b/src/test/regress/expected/create_type.out
@@ -1,7 +1,7 @@
-QUERY: CREATE TYPE circle (
+QUERY: CREATE TYPE widget (
    internallength = 24,
-   input = circle_in,
-   output = circle_out,
+   input = widget_in,
+   output = widget_out,
    alignment = double
 );
 QUERY: CREATE TYPE city_budget (
diff --git a/src/test/regress/expected/misc.out b/src/test/regress/expected/misc.out
index 4466bd91874d877a78ab413702762029a9a0e189..5bc297a346baf6be90ea7e4d57e9b6ade16bd529 100644
--- a/src/test/regress/expected/misc.out
+++ b/src/test/regress/expected/misc.out
@@ -3357,20 +3357,20 @@ QUERY: DROP FUNCTION hobbies(person);
 QUERY: DROP FUNCTION hobby_construct(text,text);
 QUERY: DROP FUNCTION equipment(hobbies_r);
 QUERY: DROP FUNCTION user_relns();
-QUERY: DROP FUNCTION circle_in(opaque);
-QUERY: DROP FUNCTION circle_out(opaque);
-QUERY: DROP FUNCTION pt_in_circle(point,circle);
+QUERY: DROP FUNCTION widget_in(opaque);
+QUERY: DROP FUNCTION widget_out(opaque);
+QUERY: DROP FUNCTION pt_in_widget(point,widget);
 QUERY: DROP FUNCTION overpaid(emp);
 QUERY: DROP FUNCTION boxarea(box);
 QUERY: DROP FUNCTION interpt_pp(path,path);
 QUERY: DROP FUNCTION reverse_c16(char16);
 QUERY: DROP OPERATOR ## (path, path);
-QUERY: DROP OPERATOR <% (point, circle);
+QUERY: DROP OPERATOR <% (point, widget);
 QUERY: DROP OPERATOR @#@ (none, int4);
 QUERY: DROP OPERATOR #@# (int4, none);
 QUERY: DROP OPERATOR #%# (int4, none);
 QUERY: DROP TYPE city_budget;
-QUERY: DROP TYPE circle;
+QUERY: DROP TYPE widget;
 QUERY: DROP AGGREGATE newavg;
 QUERY: DROP AGGREGATE newsum;
 QUERY: DROP AGGREGATE newcnt;
diff --git a/src/test/regress/input/create_function.source b/src/test/regress/input/create_function.source
index fc944c4e1d913a7c654730294f886e44d189e792..602f0ca4e3e97b0e37cc17a565322c1acf9b8049 100644
--- a/src/test/regress/input/create_function.source
+++ b/src/test/regress/input/create_function.source
@@ -3,12 +3,12 @@
 --
 --
 
-CREATE FUNCTION circle_in(opaque)
-   RETURNS circle
+CREATE FUNCTION widget_in(opaque)
+   RETURNS widget
    AS '_OBJWD_/regress_DLSUFFIX_'
    LANGUAGE 'c';
 
-CREATE FUNCTION circle_out(opaque)
+CREATE FUNCTION widget_out(opaque)
    RETURNS opaque
    AS '_OBJWD_/regress_DLSUFFIX_'
    LANGUAGE 'c';
@@ -42,7 +42,7 @@ CREATE FUNCTION user_relns()
              relkind <> ''i'' '
    LANGUAGE 'sql';
 
-CREATE FUNCTION pt_in_circle(point, circle)
+CREATE FUNCTION pt_in_widget(point, widget)
    RETURNS int4
    AS '_OBJWD_/regress_DLSUFFIX_'
    LANGUAGE 'c';
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index 28f04d89558dc71e7d179c68dce32457b0c591a4..8eb70daf3f078b95f7cbcc6757afa9ff281c656c 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -1,5 +1,5 @@
 /*
- * $Header: /cvsroot/pgsql/src/test/regress/regress.c,v 1.5 1997/03/14 23:34:16 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/test/regress/regress.c,v 1.6 1997/04/22 17:33:00 scrappy Exp $
  */
 
 #include <float.h>		/* faked on sunos */
@@ -103,22 +103,19 @@ poly2path(poly)
 {
     int i;
     char *output = (char *)PALLOC(2*(P_MAXDIG + 1)*poly->npts + 64);
-    char *outptr = output;
-    double *xp, *yp;
+    char buf[2*(P_MAXDIG)+20];
 
-    sprintf(outptr, "(1, %*d", P_MAXDIG, poly->npts);
-    xp = (double *) poly->pts;
-    yp = (double *) (poly->pts + (poly->npts * sizeof(double *)));
+    sprintf(output, "(1, %*d", P_MAXDIG, poly->npts);
 
-    for (i=1; i<poly->npts; i++,xp++,yp++)
+    for (i=0; i<poly->npts; i++)
      {
-	 sprintf(outptr, ",%*g,%*g", P_MAXDIG, *xp, P_MAXDIG, *yp);
-	 outptr += 2*(P_MAXDIG + 1);
+	 sprintf(buf, ",%*g,%*g", P_MAXDIG, poly->p[i].x, P_MAXDIG, poly->p[i].y);
+	 strcat(output, buf);
      }
 
-    *outptr++ = RDELIM;
-    *outptr = '\0';
-    return(path_in(outptr));
+    sprintf(buf, "%c", RDELIM);
+    strcat(output, buf);
+    return(path_in(output));
 }
 
 /* return the point where two paths intersect.  Assumes that they do. */
@@ -176,24 +173,29 @@ char overpaid(tuple)
     return(salary > 699);
 }
 
+/* New type "widget"
+ * This used to be "circle", but I added circle to builtins,
+ *  so needed to make sure the names do not collide. - tgl 97/04/21
+ */
+
 typedef struct {
 	Point	center;
 	double	radius;
-} CIRCLE;
+} WIDGET;
 
-extern CIRCLE *circle_in (char *str);
-extern char *circle_out (CIRCLE *circle);
-extern int pt_in_circle (Point *point, CIRCLE *circle);
+extern WIDGET *widget_in (char *str);
+extern char *widget_out (WIDGET *widget);
+extern int pt_in_widget (Point *point, WIDGET *widget);
 
 #define NARGS	3
 
-CIRCLE *
-circle_in(str)
+WIDGET *
+widget_in(str)
 char	*str;
 {
 	char	*p, *coord[NARGS], buf2[1000];
 	int	i;
-	CIRCLE	*result;
+	WIDGET	*result;
 
 	if (str == NULL)
 		return(NULL);
@@ -202,39 +204,39 @@ char	*str;
 			coord[i++] = p + 1;
 	if (i < NARGS - 1)
 		return(NULL);
-	result = (CIRCLE *) palloc(sizeof(CIRCLE));
+	result = (WIDGET *) palloc(sizeof(WIDGET));
 	result->center.x = atof(coord[0]);
 	result->center.y = atof(coord[1]);
 	result->radius = atof(coord[2]);
 
-	sprintf(buf2, "circle_in: read (%f, %f, %f)\n", result->center.x,
+	sprintf(buf2, "widget_in: read (%f, %f, %f)\n", result->center.x,
 	result->center.y,result->radius);
 	return(result);
 }
 
 char *
-circle_out(circle)
-    CIRCLE	*circle;
+widget_out(widget)
+    WIDGET	*widget;
 {
     char	*result;
 
-    if (circle == NULL)
+    if (widget == NULL)
 	return(NULL);
 
     result = (char *) palloc(60);
     (void) sprintf(result, "(%g,%g,%g)",
-		   circle->center.x, circle->center.y, circle->radius);
+		   widget->center.x, widget->center.y, widget->radius);
     return(result);
 }
 
 int
-pt_in_circle(point, circle)
+pt_in_widget(point, widget)
 	Point	*point;
-	CIRCLE	*circle;
+	WIDGET	*widget;
 {
 	extern double	point_dt();
 
-	return( point_dt(point, &circle->center) < circle->radius );
+	return( point_dt(point, &widget->center) < widget->radius );
 }
 
 #define ABS(X) ((X) > 0 ? (X) : -(X))
@@ -247,8 +249,8 @@ BOX *box;
 {
 	int width, height;
 
-	width  = ABS(box->xh - box->xl);
-	height = ABS(box->yh - box->yl);
+	width  = ABS(box->high.x - box->low.x);
+	height = ABS(box->high.y - box->low.y);
 	return (width * height);
 }
 
diff --git a/src/test/regress/sql/create_operator.sql b/src/test/regress/sql/create_operator.sql
index 60e44207820c652479d3dbac7c571b63f6994a07..74fdd8eb4f90568c5338a8178783abe9be21056e 100644
--- a/src/test/regress/sql/create_operator.sql
+++ b/src/test/regress/sql/create_operator.sql
@@ -10,8 +10,8 @@ CREATE OPERATOR ## (
 
 CREATE OPERATOR <% (
    leftarg = point,
-   rightarg = circle,
-   procedure = pt_in_circle,
+   rightarg = widget,
+   procedure = pt_in_widget,
    commutator = >=% 
 );
 
diff --git a/src/test/regress/sql/create_type.sql b/src/test/regress/sql/create_type.sql
index 87d1737c64079119dabab46660aa7dfae6fa390e..1a75ba52950623dda992d598329034ab72cfbe1f 100644
--- a/src/test/regress/sql/create_type.sql
+++ b/src/test/regress/sql/create_type.sql
@@ -3,10 +3,10 @@
 --
 --
 
-CREATE TYPE circle (
+CREATE TYPE widget (
    internallength = 24, 
-   input = circle_in,
-   output = circle_out,
+   input = widget_in,
+   output = widget_out,
    alignment = double
 );