diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 778ea5ef1908b7920a0fb740de99c4e59ac625ad..320270e7abd19ae0190a82504424f5e4b13236f3 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -7,11 +7,12 @@
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/backend/utils/adt/geo_ops.c,v 1.12 1997/06/03 14:01:22 thomas Exp $
+ *    $Header: /cvsroot/pgsql/src/backend/utils/adt/geo_ops.c,v 1.13 1997/07/29 16:08:18 thomas Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include <math.h>
+#include <limits.h>
 #include <float.h>
 #include <stdio.h>	/* for sprintf proto, etc. */
 #include <stdlib.h>	/* for strtod, etc. */
@@ -23,8 +24,12 @@
 #include "utils/geo_decls.h"
 #include "utils/palloc.h"
 
-#define OLD_FORMAT_IN	0
-#define OLD_FORMAT_OUT	0
+#ifndef PI
+#define PI 3.1415926536
+#endif
+
+int point_inside( Point *p, int npts, Point plist[]);
+int lseg_crossing( double x, double y, double px, double py);
 
 /*
  * Delimiters for input and output strings.
@@ -46,17 +51,6 @@
 
 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.
@@ -83,6 +77,8 @@ int geo_precision(int digits)
  *  and restore that order for text output - tgl 97/01/16
  */
 
+int single_decode(char *str, float8 *x, char **ss);
+int single_encode(float8 x, char *str);
 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);
@@ -90,6 +86,32 @@ int path_decode(int opentype, int npts, char *str, int *isopen, char **ss, Point
 
 char *path_encode( bool closed, int npts, Point *pt);
 
+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);
+} /* single_decode() */
+
+int single_encode(float8 x, char *str)
+{
+    (void) sprintf(str, "%.*g", digits8, x);
+    return(TRUE);
+} /* single_encode() */
+
 int pair_decode(char *str, float8 *x, float8 *y, char **s)
 {
     int has_delim;
@@ -284,39 +306,17 @@ BOX *box_in(char *str)
     };
 
     return(box);
-}
+} /* box_in() */
 
 /*	box_out	-	convert a box to external form.
  */
 char *box_out(BOX *box)
 {
-#if OLD_FORMAT_OUT
-    char *result = PALLOC(2*(P_MAXLEN+1)+2);
-
-    char *cp;
-#endif
-
     if (!PointerIsValid(box))
 	return(NULL);
 
-#if OLD_FORMAT_OUT
-    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
-}
+} /* box_out() */
 
 
 /*	box_construct	-	fill in a new box.
@@ -498,23 +498,23 @@ double *box_area(BOX *box)
 {
     double *result = PALLOCTYPE(double);
 
-    *result = box_ln(box) * box_ht(box);
+    *result = box_wd(box) * box_ht(box);
     
     return(result);
 }
 
 
-/*	box_length	-	returns the length of the box 
+/*	box_width	-	returns the width of the box 
  *				  (horizontal magnitude).
  */
-double *box_length(BOX *box)
+double *box_width(BOX *box)
 {
     double *result = PALLOCTYPE(double);
 
     *result = box->high.x - box->low.x;
     
     return(result);
-}
+} /* box_width() */
 
 
 /*	box_height	-	returns the height of the box 
@@ -565,14 +565,14 @@ Point *box_center(BOX *box)
  */
 double box_ar(BOX *box)
 {
-    return( box_ln(box) * box_ht(box) );
+    return( box_wd(box) * box_ht(box) );
 }
 
 
-/*	box_ln	-	returns the length of the box 
+/*	box_wd	-	returns the width (length) of the box 
  *				  (horizontal magnitude).
  */
-double box_ln(BOX *box)
+double box_wd(BOX *box)
 {
     return( box->high.x - box->low.x );
 }
@@ -670,8 +670,11 @@ line_construct_pm(Point *pt, double m)
     result->A = m;
     result->B = -1.0;
     result->C = pt->y - m * pt->x;
+
+    result->m = m;
+
     return(result);
-}
+} /* line_construct_pm() */
 
 
 LINE *				/* two points */
@@ -681,19 +684,40 @@ line_construct_pp(Point *pt1, Point *pt2)
 
     if (FPeq(pt1->x, pt2->x)) {		/* vertical */
 	/* use "x = C" */
-	result->m = 0.0;
-	result->A = -1.0;
-	result->B = 0.0;
+	result->A = -1;
+	result->B = 0;
 	result->C = pt1->x;
+#ifdef GEODEBUG
+printf( "line_construct_pp- line is vertical\n");
+#endif
+	result->m = DBL_MAX;
+
+    } else if (FPeq(pt1->y, pt2->y)) {	/* horizontal */
+	/* use "x = C" */
+	result->A = 0;
+	result->B = -1;
+	result->C = pt1->y;
+#ifdef GEODEBUG
+printf( "line_construct_pp- line is horizontal\n");
+#endif
+	result->m = 0.0;
+
     } else {
 	/* use "mx - y + yinter = 0" */
-	result->m = (pt1->y - pt2->y) / (pt1->x - pt2->x);
-	result->A = result->m;
+#if FALSE
+	result->A = (pt1->y - pt2->y) / (pt1->x - pt2->x);
+#endif
+	result->A = (pt2->y - pt1->y) / (pt2->x - pt1->x);
 	result->B = -1.0;
-	result->C = pt1->y - result->m * pt1->x;
-    }
+	result->C = pt1->y - result->A * pt1->x;
+#ifdef GEODEBUG
+printf( "line_construct_pp- line is neither vertical nor horizontal (diffs x=%.*g, y=%.*g\n",
+  digits8, (pt2->x - pt1->x), digits8, (pt2->y - pt1->y));
+#endif
+	result->m = result->A;
+    };
     return(result);
-}
+} /* line_construct_pp() */
 
 
 /*----------------------------------------------------------
@@ -707,32 +731,53 @@ bool line_intersect(LINE *l1, LINE *l2)
 
 bool line_parallel(LINE *l1, LINE *l2)
 {
+#if FALSE
     return( FPeq(l1->m, l2->m) );
-}
+#endif
+    if (FPzero(l1->B)) {
+	return(FPzero(l2->B));
+    };
+
+    return(FPeq(l2->A, l1->A*(l2->B / l1->B)));
+} /* line_parallel() */
 
 bool line_perp(LINE *l1, LINE *l2)
 {
+#if FALSE
     if (l1->m)
 	return( FPeq(l2->m / l1->m, -1.0) );
     else if (l2->m)
 	return( FPeq(l1->m / l2->m, -1.0) );
-    return(1);	/* both 0.0 */
-}
+#endif
+    if (FPzero(l1->A)) {
+	return( FPzero(l2->B) );
+    } else if (FPzero(l1->B)) {
+	return( FPzero(l2->A) );
+    };
+
+    return( FPeq(((l1->A * l2->B) / (l1->B * l2->A)), -1.0) );
+} /* line_perp() */
 
 bool line_vertical(LINE *line)
 {
+#if FALSE
     return( FPeq(line->A, -1.0) && FPzero(line->B) );
-}
+#endif
+    return( FPzero(line->B) );
+} /* line_vertical() */
 
 bool line_horizontal(LINE *line)
 {
+#if FALSE
     return( FPzero(line->m) );
-}
+#endif
+    return( FPzero(line->A) );
+} /* line_horizontal() */
 
 
 bool line_eq(LINE *l1, LINE *l2)
 {
-    double	k;
+    double k;
     
     if (! FPzero(l2->A))
 	k = l1->A / l2->A;
@@ -742,9 +787,10 @@ bool line_eq(LINE *l1, LINE *l2)
 	k = l1->C / l2->C;
     else
 	k = 1.0;
+
     return( FPeq(l1->A, k * l2->A) &&
-	   FPeq(l1->B, k * l2->B) &&
-	   FPeq(l1->C, k * l2->C) );
+	    FPeq(l1->B, k * l2->B) &&
+	    FPeq(l1->C, k * l2->C) );
 }
 
 
@@ -772,14 +818,18 @@ line_distance(LINE *l1, LINE *l2)
     return(result);
 }
 
-Point *			/* point where l1, l2 intersect (if any) */
+/* line_interpt()
+ * Point where two lines l1, l2 intersect (if any)
+ */
+Point *
 line_interpt(LINE *l1, LINE *l2)
 {
     Point	*result;
-    double	x;
+    double	x, y;
     
     if (line_parallel(l1, l2))
 	return(NULL);
+#if FALSE
     if (line_vertical(l1))
 	result = point_construct(l2->m * l1->C + l2->C, l1->C);
     else if (line_vertical(l2))
@@ -788,8 +838,42 @@ line_interpt(LINE *l1, LINE *l2)
 	x = (l1->C - l2->C) / (l2->A - l1->A);
 	result = point_construct(x, l1->m * x + l1->C);
     }
+#endif
+
+    if (line_vertical(l1)) {
+#if FALSE
+	x = l1->C;
+	y = -((l2->A * x + l2->C) / l2->B);
+#endif
+	x = l1->C;
+	y = (l2->A * x + l2->C);
+
+    } else if (line_vertical(l2)) {
+#if FALSE
+	x = l2->C;
+	y = -((l1->A * x + l1->C) / l1->B);
+#endif
+	x = l2->C;
+	y = (l1->A * x + l1->C);
+
+    } else {
+#if FALSE
+	x = (l2->B * l1->C - l1->B * l2->C) / (l2->A * l1->B - l1->A * l2->B);
+	y = -((l1->A * x + l1->C) / l1->B);
+#endif
+	x = (l1->C - l2->C) / (l2->A - l1->A);
+	y = (l1->A * x + l1->C);
+    };
+    result = point_construct(x, y);
+
+#ifdef GEODEBUG
+printf( "line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
+ digits8, l1->A, digits8, l1->B, digits8, l1->C, digits8, l2->A, digits8, l2->B, digits8, l2->C);
+printf( "line_interpt- lines intersect at (%.*g,%.*g)\n", digits8, x, digits8, y);
+#endif
     return(result);
-}
+} /* line_interpt() */
+
 
 /***********************************************************************
  **
@@ -821,12 +905,7 @@ PATH *path_in(char *str)
     char *s;
     int npts;
     int size;
-#if OLD_FORMAT_IN
-    int oldstyle = FALSE;
-    double x, y;
-#else
     int depth = 0;
-#endif
 
     if (!PointerIsValid(str))
 	elog(WARN, "Bad (null) path external representation");
@@ -837,27 +916,11 @@ PATH *path_in(char *str)
     s = str;
     while (isspace( *s)) s++;
 
-#if OLD_FORMAT_IN
-    /* 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;
-    };
-
-#else
     /* skip single leading paren */
     if ((*s == LDELIM) && (strrchr( s, LDELIM) == s)) {
 	s++;
 	depth++;
     };
-#endif
 
     size = offsetof(PATH, p[0]) + (sizeof(path->p[0]) * npts);
     path = PALLOC(size);
@@ -865,67 +928,23 @@ PATH *path_in(char *str)
     path->size = size;
     path->npts = npts;
 
-#if OLD_FORMAT_IN
-    if (oldstyle) path->closed = (! isopen);
-
-    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])))
      && (!((depth == 0) && (*s == '\0'))) && !((depth >= 1) && (*s == RDELIM)))
-#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);
-    };
-
-    if (! oldstyle) path->closed = (! isopen);
-
-#else
     path->closed = (! isopen);
-#endif
 
     return(path);
-}
+} /* path_in() */
 
 
 char *path_out(PATH *path)
 {
-#if OLD_FORMAT_OUT
-    int i;
-    char *result, *cp;
-#endif
-
     if (!PointerIsValid(path))
 	return NULL;
 
-#if OLD_FORMAT_OUT
-    result = PALLOC(path->npts*(P_MAXLEN+3)+2);
-
-    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
-}
+} /* path_out() */
 
 
 /*----------------------------------------------------------
@@ -1010,6 +1029,7 @@ path_close(PATH *path)
     return(result);
 } /* path_close() */
 
+
 PATH *
 path_open(PATH *path)
 {
@@ -1122,29 +1142,32 @@ double *path_distance(PATH *p1, PATH *p2)
 
 double *path_length(PATH *path)
 {
-    double *result = PALLOCTYPE(double);
-    int	ct, i;
-    
-    ct = path->npts - 1;
-    for (i = 0; i < ct; i++)
+    double *result;
+    int	i;
+
+    result = PALLOCTYPE(double);
+
+    *result = 0;
+    for (i = 0; i < (path->npts - 1); i++)
 	*result += point_dt(&path->p[i], &path->p[i+1]);
-    
+
     return(result);
-}
+} /* path_length() */
 
 
 
 double path_ln(PATH *path)
 {
     double result;
-    int	ct, i;
-    
-    ct = path->npts - 1;
-    for (result = i = 0; i < ct; i++)
+    int	i;
+
+    result = 0;
+    for (i = 0; i < (path->npts - 1); i++)
 	result += point_dt(&path->p[i], &path->p[i+1]);
-    
+
     return(result);
-}
+} /* path_ln() */
+
 /***********************************************************************
  **
  ** 	Routines for 2D points.
@@ -1166,10 +1189,8 @@ point_in(char *str)
     double x, y;
     char *s;
     
-    if (str == NULL) {
+    if (! PointerIsValid( str))
 	elog(WARN, "Bad (null) point external representation");
-	return NULL;
-    }
 
     if (! pair_decode( str, &x, &y, &s) || (strlen(s) > 0))
       elog (WARN, "Bad point external representation '%s'",str);
@@ -1185,7 +1206,7 @@ point_in(char *str)
 char *
 point_out(Point *pt)
 {
-    if (!PointerIsValid(pt))
+    if (! PointerIsValid(pt))
 	return(NULL);
 
     return( path_encode( -1, 1, pt));
@@ -1204,7 +1225,12 @@ Point *point_construct(double x, double y)
 
 Point *point_copy(Point *pt)
 {
-    Point *result = PALLOCTYPE(Point);
+    Point *result;
+
+    if (! PointerIsValid( pt))
+	return(NULL);
+
+    result = PALLOCTYPE(Point);
 
     result->x = pt->x;
     result->y = pt->y;
@@ -1336,7 +1362,7 @@ LSEG *lseg_in(char *str)
     lseg->m = point_sl(&lseg->p[0], &lseg->p[1]);
     
     return(lseg);
-}
+} /* lseg_in() */
 
 
 char *lseg_out(LSEG *ls)
@@ -1345,7 +1371,7 @@ char *lseg_out(LSEG *ls)
 	return(NULL);
 
     return( path_encode( FALSE, 2, (Point *) &(ls->p[0])));
-}
+} /* lseg_out() */
 
 
 /* lseg_construct -
@@ -1403,17 +1429,26 @@ bool lseg_intersect(LSEG *l1, LSEG *l2)
 
 bool lseg_parallel(LSEG *l1, LSEG *l2)
 {
+#if FALSE
     return( FPeq(l1->m, l2->m) );
-}
+#endif
+    return( FPeq( point_sl( &(l1->p[0]), &(l1->p[1])),
+      point_sl( &(l2->p[0]), &(l2->p[1]))) );
+} /* lseg_parallel() */
 
 bool lseg_perp(LSEG *l1, LSEG *l2)
 {
-    if (! FPzero(l1->m))
-	return( FPeq(l2->m / l1->m, -1.0) );
-    else if (! FPzero(l2->m))
-	return( FPeq(l1->m / l2->m, -1.0) );
+    double m1, m2;
+
+    m1 = point_sl( &(l1->p[0]), &(l1->p[1]));
+    m2 = point_sl( &(l2->p[0]), &(l2->p[1]));
+
+    if (! FPzero(m1))
+	return( FPeq(m2 / m1, -1.0) );
+    else if (! FPzero(m2))
+	return( FPeq(m1 / m2, -1.0) );
     return(0);	/* both 0.0 */
-}
+} /* lseg_perp() */
 
 bool lseg_vertical(LSEG *lseg)
 {
@@ -1454,7 +1489,8 @@ double *lseg_distance(LSEG *l1, LSEG *l2)
 }
 
 /* distance between l1, l2 */
-double lseg_dt(LSEG *l1, LSEG *l2)
+double
+lseg_dt(LSEG *l1, LSEG *l2)
 {
     double	*d, result;
     
@@ -1467,15 +1503,37 @@ double lseg_dt(LSEG *l1, LSEG *l2)
     d = dist_ps(&l1->p[1], l2);
     result = Min(result, *d);
     PFREE(d);
+#if FALSE
+/* XXX Why are we checking distances from all endpoints to the other segment?
+ * One set of endpoints should be sufficient - tgl 97/07/03
+ */
     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);
+#endif
     
     return(result);
-}
+} /* lseg_dt() */
+
+
+Point *
+lseg_center(LSEG *lseg)
+{
+    Point *result;
+
+    if (!PointerIsValid(lseg))
+	return(NULL);
+
+    result = PALLOCTYPE(Point);
+
+    result->x = (lseg->p[0].x - lseg->p[1].x) / 2;
+    result->y = (lseg->p[0].y - lseg->p[1].y) / 2;
+
+    return(result);
+} /* lseg_center() */
 
 
 /* lseg_interpt -
@@ -1483,25 +1541,44 @@ double lseg_dt(LSEG *l1, LSEG *l2)
  *	Find the intersection of the appropriate lines; if the 
  *	point is not on a given segment, there is no valid segment
  *	intersection point at all.
+ * If there is an intersection, then check explicitly for matching
+ *  endpoints since there may be rounding effects with annoying
+ *  lsb residue. - tgl 1997-07-09
  */
-Point *lseg_interpt(LSEG *l1, LSEG *l2)
+Point *
+lseg_interpt(LSEG *l1, LSEG *l2)
 {
     Point	*result;
     LINE	*tmp1, *tmp2;
-    
+
+    if (!PointerIsValid(l1) || !PointerIsValid(l2))
+	return(NULL);
+
     tmp1 = line_construct_pp(&l1->p[0], &l1->p[1]);
     tmp2 = line_construct_pp(&l2->p[0], &l2->p[1]);
     result = line_interpt(tmp1, tmp2);
-    if (result)
-	if (! on_ps(result, l1)) {
+    if (PointerIsValid(result)) {
+	if (on_ps(result, l1)) {
+	    if ((FPeq( l1->p[0].x, l2->p[0].x) && FPeq( l1->p[0].y, l2->p[0].y))
+	     || (FPeq( l1->p[0].x, l2->p[1].x) && FPeq( l1->p[0].y, l2->p[1].y))) {
+		result->x = l1->p[0].x;
+		result->y = l1->p[0].y;
+
+	    } else if ((FPeq( l1->p[1].x, l2->p[0].x) && FPeq( l1->p[1].y, l2->p[0].y))
+	     || (FPeq( l1->p[1].x, l2->p[1].x) && FPeq( l1->p[1].y, l2->p[1].y))) {
+		result->x = l1->p[1].x;
+		result->y = l1->p[1].y;
+	    };
+	} else {
 	    PFREE(result);
 	    result = NULL;
-	}
-    
+	};
+    };
     PFREE(tmp1);
     PFREE(tmp2);
+
     return(result);
-}
+} /* lseg_interpt() */
 
 /***********************************************************************
  **
@@ -1536,27 +1613,49 @@ double *dist_ps(Point *pt, LSEG *lseg)
     LINE *ln;
     double *result, *tmpdist;
     Point *ip;
-    
-    /* construct a line that's perpendicular.  See if the intersection of
-       the two lines is on the line segment. */
-    if (lseg->p[1].x == lseg->p[0].x)
+
+/*
+ * Construct a line perpendicular to the input segment
+ * and through the input point
+ */
+    if (lseg->p[1].x == lseg->p[0].x) {
 	m = 0;
-    else if (lseg->p[1].y == lseg->p[0].y) /* slope is infinite */
+    } else if (lseg->p[1].y == lseg->p[0].y) { /* slope is infinite */
 	m = (double)DBL_MAX;
-    else m = (-1) * (lseg->p[1].y - lseg->p[0].y) / 
-	(lseg->p[1].x - lseg->p[0].x);
+    } else {
+#if FALSE
+	m = (-1) * (lseg->p[1].y - lseg->p[0].y) / 
+	 (lseg->p[1].x - lseg->p[0].x);
+#endif
+	m = ((lseg->p[0].y - lseg->p[1].y) / (lseg->p[1].x - lseg->p[0].x));
+    };
     ln = line_construct_pm(pt, m);
-    
-    if ((ip = interpt_sl(lseg, ln)) != NULL)
+
+#ifdef GEODEBUG
+printf( "dist_ps- line is A=%g B=%g C=%g from (point) slope (%f,%f) %g\n",
+ ln->A, ln->B, ln->C, pt->x, pt->y, m);
+#endif
+
+/*
+ * Calculate distance to the line segment
+ *  or to the endpoints of the segment.
+ */
+
+    /* intersection is on the line segment? */
+    if ((ip = interpt_sl(lseg, ln)) != NULL) {
 	result = point_distance(pt, ip);
-    else  /* intersection is not on line segment, so distance is min
-	     of distance from point to an endpoint */
-	{
+#ifdef GEODEBUG
+printf( "dist_ps- distance is %f to intersection point is (%f,%f)\n",
+ *result, ip->x, ip->y);
+#endif
+
+    /* otherwise, intersection is not on line segment */
+    } else {
 	    result = point_distance(pt, &lseg->p[0]);
 	    tmpdist = point_distance(pt, &lseg->p[1]);
 	    if (*tmpdist < *result) *result = *tmpdist;
 	    PFREE (tmpdist);
-	}
+    };
     
     if (ip != NULL) PFREE(ip);
     PFREE(ln);
@@ -1567,7 +1666,7 @@ double *dist_ps(Point *pt, LSEG *lseg)
 /*
  ** Distance from a point to a path 
  */
-double *dist_ppth(Point *pt, PATH *path)
+double *dist_ppath(Point *pt, PATH *path)
 {
     double *result;
     double *tmp;
@@ -1675,6 +1774,58 @@ double *dist_lb(LINE *line, BOX *box)
 }
 
 
+double *
+dist_cpoly(CIRCLE *circle, POLYGON *poly)
+{
+    double *result;
+    int i;
+    double *d;
+    LSEG seg;
+
+    if (!PointerIsValid(circle) || !PointerIsValid(poly))
+	elog (WARN, "Invalid (null) input for distance", NULL);
+
+    if (point_inside( &(circle->center), poly->npts, poly->p)) {
+#ifdef GEODEBUG
+printf( "dist_cpoly- center inside of polygon\n");
+#endif
+	result = PALLOCTYPE(double);
+
+	*result = 0;
+	return(result);
+    };
+
+    /* initialize distance with segment between first and last points */
+    seg.p[0].x = poly->p[0].x;
+    seg.p[0].y = poly->p[0].y;
+    seg.p[1].x = poly->p[poly->npts-1].x;
+    seg.p[1].y = poly->p[poly->npts-1].y;
+    result = dist_ps( &(circle->center), &seg);
+#ifdef GEODEBUG
+printf( "dist_cpoly- segment 0/n distance is %f\n", *result);
+#endif
+
+    /* check distances for other segments */
+    for (i = 0; (i < poly->npts - 1); i++) {
+	seg.p[0].x = poly->p[i].x;
+	seg.p[0].y = poly->p[i].y;
+	seg.p[1].x = poly->p[i+1].x;
+	seg.p[1].y = poly->p[i+1].y;
+	d = dist_ps( &(circle->center), &seg);
+#ifdef GEODEBUG
+printf( "dist_cpoly- segment %d distance is %f\n", (i+1), *d);
+#endif
+	if (*d < *result) *result = *d;
+	PFREE(d);
+    };
+
+    *result -= circle->radius;
+    if (*result < 0) *result = 0;
+
+    return(result);
+} /* dist_cpoly() */
+
+
 /*---------------------------------------------------------------------
  *	interpt_
  *		Intersection point of objects.
@@ -1689,11 +1840,26 @@ Point *interpt_sl(LSEG *lseg, LINE *line)
     
     tmp = line_construct_pp(&lseg->p[0], &lseg->p[1]);
     p = line_interpt(tmp, line);
-    if (p)
-	if (! on_ps(p, lseg)) {
+#ifdef GEODEBUG
+printf( "interpt_sl- segment is (%.*g %.*g) (%.*g %.*g)\n",
+ digits8, lseg->p[0].x, digits8, lseg->p[0].y, digits8, lseg->p[1].x, digits8, lseg->p[1].y);
+printf( "interpt_sl- segment becomes line A=%.*g B=%.*g C=%.*g\n",
+ digits8, tmp->A, digits8, tmp->B, digits8, tmp->C);
+#endif
+    if (PointerIsValid(p)) {
+#ifdef GEODEBUG
+printf( "interpt_sl- intersection point is (%.*g %.*g)\n", digits8, p->x, digits8, p->y);
+#endif
+	if (on_ps(p, lseg)) {
+#ifdef GEODEBUG
+printf( "interpt_sl- intersection point is on segment\n");
+#endif
+
+	} else {
 	    PFREE(p);
 	    p = NULL;
-	}
+	};
+    };
     
     PFREE(tmp);
     return(p);
@@ -1716,21 +1882,32 @@ Point *close_pl(Point *pt, LINE *line)
     double	invm;
     
     result = PALLOCTYPE(Point);
+#if FALSE
     if (FPeq(line->A, -1.0) && FPzero(line->B)) {	/* vertical */
+#endif
+    if (line_vertical(line)) {
 	result->x = line->C;
 	result->y = pt->y;
 	return(result);
+
+#if FALSE
     } else if (FPzero(line->m)) {			/* horizontal */
+#endif
+    } else if (line_horizontal(line)) {
 	result->x = pt->x;
 	result->y = line->C;
 	return(result);
     }
     /* drop a perpendicular and find the intersection point */
+#if FALSE
     invm = -1.0 / line->m;
+#endif
+    /* invert and flip the sign on the slope to get a perpendicular */
+    invm = line->B / line->A;
     tmp = line_construct_pm(pt, invm);
     result = line_interpt(tmp, line);
     return(result);
-}
+} /* close_pl() */
 
 
 /* close_ps - 
@@ -1758,26 +1935,36 @@ Point *close_ps(Point *pt, LSEG *lseg)
 	result = point_copy(&lseg->p[yh]);
     if (result)
 	return(result);
+#if FALSE
     if (FPeq(lseg->p[0].x, lseg->p[1].x)) {	/* vertical */
+#endif
+    if (lseg_vertical(lseg)) {
 	result->x = lseg->p[0].x;
 	result->y = pt->y;
 	return(result);
+#if FALSE
     } else if (FPzero(lseg->m)) {			/* horizontal */
+#endif
+    } else if (lseg_horizontal(lseg)) {
 	result->x = pt->x;
 	result->y = lseg->p[0].y;
 	return(result);
     }
     
+#if FALSE
     invm = -1.0 / lseg->m;
+#endif
+    invm = -1.0 / point_sl(&(lseg->p[0]), &(lseg->p[1]));
     tmp = line_construct_pm(pt, invm);
     result = interpt_sl(lseg, tmp);
     return(result);
-}
+} /* close_ps() */
 
 Point *close_pb(Point *pt, BOX *box)
 {
     /* think about this one for a while */
-    
+    elog(WARN, "close_pb not implemented", NULL);
+
     return(NULL);
 }
 
@@ -1804,14 +1991,16 @@ Point *close_sl(LSEG *lseg, LINE *line)
 Point *close_sb(LSEG *lseg, BOX *box)
 {
     /* think about this one for a while */
-    
+    elog(WARN, "close_sb not implemented", NULL);
+
     return(NULL);
 }
 
 Point *close_lb(LINE *line, BOX *box)
 {
     /* think about this one for a while */
-    
+    elog(WARN, "close_lb not implemented", NULL);
+
     return(NULL);
 }
 
@@ -1825,21 +2014,31 @@ Point *close_lb(LINE *line, BOX *box)
  */
 bool on_pl(Point *pt, LINE *line)
 {
+    if (!PointerIsValid(pt) || !PointerIsValid(line))
+	return(FALSE);
+
     return( FPzero(line->A * pt->x + line->B * pt->y + line->C) );
 }
 
 
 /* on_ps -
  *	Determine colinearity by detecting a triangle inequality.
+ * This algorithm seems to behave nicely even with lsb residues - tgl 1997-07-09
  */
 bool on_ps(Point *pt, LSEG *lseg)
 {
+    if (!PointerIsValid(pt) || !PointerIsValid(lseg))
+	return(FALSE);
+
     return( FPeq (point_dt(pt, &lseg->p[0]) + point_dt(pt, &lseg->p[1]),
             point_dt(&lseg->p[0], &lseg->p[1])) );
 }
 
 bool on_pb(Point *pt, BOX *box)
 {
+    if (!PointerIsValid(pt) || !PointerIsValid(box))
+	return(FALSE);
+
     return( pt->x <= box->high.x && pt->x >= box->low.x &&
 	   pt->y <= box->high.y && pt->y >= box->low.y );
 }
@@ -1847,6 +2046,7 @@ bool on_pb(Point *pt, BOX *box)
 /* on_ppath - 
  *	Whether a point lies within (on) a polyline.
  *	If open, we have to (groan) check each segment.
+ * (uses same algorithm as for point intersecting segment - tgl 1997-07-09)
  *	If closed, we use the old O(n) ray method for point-in-polygon.
  *		The ray is horizontal, from pt out to the right.
  *		Each segment that crosses the ray counts as an 
@@ -1858,13 +2058,18 @@ bool on_pb(Point *pt, BOX *box)
 
 bool on_ppath(Point *pt, PATH *path)
 {
+#if FALSE
     int	above, next,	/* is the seg above the ray? */
     inter,		/* # of times path crosses ray */
-    hi,		/* index inc of higher seg (0,1) */
-    i, n;
-    double a, b, x, 
-    yh, yl, xh, xl;
-    
+    hi;		/* index inc of higher seg (0,1) */
+    double x, yh, yl, xh, xl;
+#endif
+    int i, n;
+    double a, b;
+
+    if (!PointerIsValid(pt) || !PointerIsValid(path))
+	return(FALSE);
+
     if (! path->closed) {		/*-- OPEN --*/
 	n = path->npts - 1;
 	a = point_dt(pt, &path->p[0]);
@@ -1878,6 +2083,8 @@ bool on_ppath(Point *pt, PATH *path)
 	return(0);
     }
     
+    return(point_inside( pt, path->npts, path->p));
+#if FALSE
     inter = 0;			/*-- CLOSED --*/
     above = FPgt(path->p[0].y, pt->y) ? ABOVE : 
 	FPlt(path->p[0].y, pt->y) ? BELOW : UNDEF;
@@ -1922,18 +2129,25 @@ bool on_ppath(Point *pt, PATH *path)
     }
     return(	above == UNDEF || 	/* path is horizontal */
 	   inter % 2);		/* odd # of intersections */
-}
+#endif
+} /* on_ppath() */
 
 
 bool on_sl(LSEG *lseg, LINE *line)
 {
+    if (!PointerIsValid(lseg) || !PointerIsValid(line))
+	return(FALSE);
+
     return( on_pl(&lseg->p[0], line) && on_pl(&lseg->p[1], line) );
-}
+} /* on_sl() */
 
 bool on_sb(LSEG *lseg, BOX *box)
 {
+    if (!PointerIsValid(lseg) || !PointerIsValid(box))
+	return(FALSE);
+
     return( on_pb(&lseg->p[0], box) && on_pb(&lseg->p[1], box) );
-}
+} /* on_sb() */
 
 /*---------------------------------------------------------------------
  *	inter_
@@ -1944,6 +2158,9 @@ bool inter_sl(LSEG *lseg, LINE *line)
 {
     Point	*tmp;
 
+    if (!PointerIsValid(lseg) || !PointerIsValid(line))
+	return(FALSE);
+
     tmp = interpt_sl(lseg, line);
     if (tmp) {
 	PFREE(tmp);
@@ -2013,12 +2230,6 @@ POLYGON *poly_in(char *str)
     int size;
     int isopen;
     char *s;
-#if OLD_FORMAT_IN
-    int oldstyle;
-    int oddcount;
-    int i;
-    double x1, x2;
-#endif
 
     if (!PointerIsValid(str))
 	elog (WARN," Bad (null) polygon external representation");
@@ -2033,62 +2244,10 @@ POLYGON *poly_in(char *str)
     poly->size = size;
     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'))
+    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);
@@ -2101,33 +2260,11 @@ POLYGON *poly_in(char *str)
  *---------------------------------------------------------------*/
 char *poly_out(POLYGON *poly)
 {
-#if OLD_FORMAT_OUT
-    int i;
-    char *result, *cp;
-#endif
-
     if (!PointerIsValid(poly))
 	return NULL;
 
-#if OLD_FORMAT_OUT
-    result = PALLOC(poly->npts*(P_MAXLEN+3)+2);
-
-    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
-}
+} /* poly_out() */
 
 
 /*-------------------------------------------------------
@@ -2173,20 +2310,29 @@ bool poly_overright(POLYGON *polya, POLYGON *polyb)
 /*-------------------------------------------------------
  * Is polygon A the same as polygon B? i.e. are all the
  * points the same?
+ * Check all points for matches in both forward and reverse
+ *  direction since polygons are non-directional and are
+ *  closed shapes.
  *-------------------------------------------------------*/
 bool poly_same(POLYGON *polya, POLYGON *polyb)
 {
-    int i;
+    if (! PointerIsValid( polya) || ! PointerIsValid( polyb))
+	return FALSE;
+
     if (polya->npts != polyb->npts)
 	return FALSE;
 
+    return(plist_same( polya->npts, polya->p, polyb->p));
+
+#if 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;
-}
+#endif
+} /* poly_same() */
 
 /*-----------------------------------------------------------------
  * Determine if polygon A overlaps polygon B by determining if
@@ -2197,23 +2343,114 @@ bool poly_overlap(POLYGON *polya, POLYGON *polyb)
     return box_overlap(&(polya->boundbox), &(polyb->boundbox));
 }
 
+
 /*-----------------------------------------------------------------
  * Determine if polygon A contains polygon B by determining if A's
  * bounding box contains B's bounding box.
  *-----------------------------------------------------------------*/
+#if FALSE
 bool poly_contain(POLYGON *polya, POLYGON *polyb)
 {
     return box_contain(&(polya->boundbox), &(polyb->boundbox));
 }
+#endif
+
+bool
+poly_contain(POLYGON *polya, POLYGON *polyb)
+{
+    int i;
+
+    if (!PointerIsValid(polya) || !PointerIsValid(polyb))
+	return(FALSE);
+
+    if (box_contain(&(polya->boundbox), &(polyb->boundbox))) {
+	for (i = 0; i < polyb->npts; i++) {
+	    if (point_inside(&(polyb->p[i]), polya->npts, &(polya->p[0])) == 0) {
+#if GEODEBUG
+printf( "poly_contain- point (%f,%f) not in polygon\n", polyb->p[i].x, polyb->p[i].y);
+#endif
+		return(FALSE);
+	    };
+	};
+	for (i = 0; i < polya->npts; i++) {
+	    if (point_inside(&(polya->p[i]), polyb->npts, &(polyb->p[0])) == 1) {
+#if GEODEBUG
+printf( "poly_contain- point (%f,%f) in polygon\n", polya->p[i].x, polya->p[i].y);
+#endif
+		return(FALSE);
+	    };
+	};
+	return(TRUE);
+    };
+#if GEODEBUG
+printf( "poly_contain- bound box ((%f,%f),(%f,%f)) not inside ((%f,%f),(%f,%f))\n",
+ polyb->boundbox.low.x,polyb->boundbox.low.y,polyb->boundbox.high.x,polyb->boundbox.high.y,
+ polya->boundbox.low.x,polya->boundbox.low.y,polya->boundbox.high.x,polya->boundbox.high.y);
+#endif
+    return(FALSE);
+} /* poly_contain() */
+
 
 /*-----------------------------------------------------------------
  * Determine if polygon A is contained by polygon B by determining 
  * if A's bounding box is contained by B's bounding box.
  *-----------------------------------------------------------------*/
+#if FALSE
 bool poly_contained(POLYGON *polya, POLYGON *polyb)
 {
-    return box_contained(&(polya->boundbox), &(polyb->boundbox));
+    return(box_contained(&(polya->boundbox), &(polyb->boundbox)));
 }
+#endif
+
+bool poly_contained(POLYGON *polya, POLYGON *polyb)
+{
+    return(poly_contain(polyb, polya));
+} /* poly_contained() */
+
+
+/* poly_contain_pt()
+ * Test to see if the point is inside the polygon.
+ * Code adapted from integer-based routines in
+ *  Wn: A Server for the HTTP
+ *  File: wn/image.c
+ *  Version 1.15.1
+ *  Copyright (C) 1995  <by John Franks>
+ * (code offered for use by J. Franks in Linux Journal letter.)
+ */
+
+bool
+poly_contain_pt( POLYGON *poly, Point *p)
+{
+    if (!PointerIsValid(poly) || !PointerIsValid(p))
+	return(FALSE);
+
+    return(point_inside(p, poly->npts, &(poly->p[0])) != 0);
+} /* poly_contain_pt() */
+
+bool
+pt_contained_poly( Point *p, POLYGON *poly)
+{
+    if (!PointerIsValid(p) || !PointerIsValid(poly))
+	return(FALSE);
+
+    return(poly_contain_pt( poly, p));
+} /* pt_contained_poly() */
+
+
+double *
+poly_distance( POLYGON *polya, POLYGON *polyb)
+{
+    double *result;
+
+    if (!PointerIsValid(polya) || !PointerIsValid(polyb))
+	return(NULL);
+
+    result = PALLOCTYPE(double);
+
+    *result = 0;
+
+    return(result);
+} /* poly_distance() */
 
 
 /***********************************************************************
@@ -2402,8 +2639,6 @@ box_div(BOX *box, Point *p)
  **
  ***********************************************************************/
 
-POLYGON *path_poly(PATH *path);
-
 /* path_add()
  * Concatenate two paths (only if they are both open).
  */
@@ -2527,6 +2762,41 @@ path_div_pt(PATH *path, Point *point)
 } /* path_div_pt() */
 
 
+bool
+path_contain_pt( PATH *path, Point *p)
+{
+    if (!PointerIsValid(path) || !PointerIsValid(p))
+	return(FALSE);
+
+    return( (path->closed? (point_inside(p, path->npts, &(path->p[0])) != 0): FALSE));
+} /* path_contain_pt() */
+
+bool
+pt_contained_path( Point *p, PATH *path)
+{
+    if (!PointerIsValid(p) || !PointerIsValid(path))
+	return(FALSE);
+
+    return( path_contain_pt( path, p));
+} /* pt_contained_path() */
+
+
+Point *
+path_center(PATH *path)
+{
+    Point *result;
+
+    if (!PointerIsValid(path))
+	return(NULL);
+
+    elog(WARN, "path_center not implemented", NULL);
+
+    result = PALLOCTYPE(Point);
+    result = NULL;
+
+    return(result);
+} /* path_center() */
+
 POLYGON *path_poly(PATH *path)
 {
     POLYGON *poly;
@@ -2597,7 +2867,7 @@ bool
 isoldpath(PATH *path)
 {
     if (!PointerIsValid(path) || (path->npts < 2))
-	return(0);
+	return(FALSE);
 
     return(path->npts == (path->p[0].y+1));
 } /* isoldpath() */
@@ -2610,7 +2880,7 @@ isoldpath(PATH *path)
  ***********************************************************************/
 
 int4
-poly_npoints( POLYGON *poly)
+poly_npoints(POLYGON *poly)
 {
     if (!PointerIsValid(poly))
 	return(0);
@@ -2618,6 +2888,28 @@ poly_npoints( POLYGON *poly)
     return(poly->npts);
 } /* poly_npoints() */
 
+
+Point *
+poly_center(POLYGON *poly)
+{
+    Point *result;
+    CIRCLE *circle;
+
+    if (!PointerIsValid(poly))
+	return(NULL);
+
+    if (PointerIsValid(circle = poly_circle(poly))) {
+	result = circle_center(circle);
+	PFREE(circle);
+
+    } else {
+	result = NULL;
+    };
+
+    return(result);
+} /* poly_center() */
+
+
 BOX *
 poly_box(POLYGON *poly)
 {
@@ -2631,6 +2923,7 @@ poly_box(POLYGON *poly)
     return(box);
 } /* poly_box() */
 
+
 /* box_poly()
  * Convert a box to a polygon.
  */
@@ -2664,6 +2957,7 @@ box_poly(BOX *box)
     return(poly);
 } /* box_poly() */
 
+
 PATH *
 poly_path(POLYGON *poly)
 {
@@ -2773,53 +3067,6 @@ POLYGON
 } /* revertpoly() */
 
 
-/*-------------------------------------------------------------------------
- *
- * 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.12 1997/06/03 14:01:22 thomas 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.
@@ -3191,6 +3438,30 @@ double *circle_distance(CIRCLE *circle1, CIRCLE *circle2)
 } /* circle_distance() */
 
 
+bool
+circle_contain_pt(CIRCLE *circle, Point *point)
+{
+    bool within;
+    double *d;
+
+    if (!PointerIsValid(circle) || !PointerIsValid(point))
+	return(FALSE);
+
+    d = point_distance(&(circle->center), point);
+    within = (*d <= circle->radius);
+    PFREE(d);
+
+    return(within);
+} /* circle_contain_pt() */
+
+
+bool
+pt_contained_circle(Point *point, CIRCLE *circle)
+{
+    return(circle_contain_pt(circle,point));
+} /* circle_contain_pt() */
+
+
 /*	dist_pc	-	returns the distance between
  *			  a point and a circle.
  */
@@ -3199,6 +3470,7 @@ double *dist_pc(Point *point, CIRCLE *circle)
     double	*result;
 
     result = PALLOCTYPE(double);
+
     *result = (point_dt(point,&circle->center) - circle->radius);
     if (*result < 0) *result = 0;
 
@@ -3261,6 +3533,50 @@ CIRCLE *circle(Point *center, float8 *radius)
     return(result);
 }
 
+
+BOX *
+circle_box(CIRCLE *circle)
+{
+    BOX *box;
+    double delta;
+
+    if (!PointerIsValid(circle))
+	return(NULL);
+
+    box = PALLOCTYPE(BOX);
+
+    delta = circle->radius / sqrt(2.0e0);
+
+    box->high.x = circle->center.x + delta;
+    box->low.x = circle->center.x - delta;
+    box->high.y = circle->center.y + delta;
+    box->low.y = circle->center.y - delta;
+
+    return(box);
+} /* circle_box() */
+
+/* box_circle()
+ * Convert a box to a circle.
+ */
+CIRCLE *
+box_circle(BOX *box)
+{
+    CIRCLE *circle;
+
+    if (!PointerIsValid(box))
+	return(NULL);
+
+    circle = PALLOCTYPE(CIRCLE);
+
+    circle->center.x = (box->high.x + box->low.x) / 2;
+    circle->center.y = (box->high.y + box->low.y) / 2;
+
+    circle->radius = point_dt(&circle->center, &box->high);
+
+    return(circle);
+} /* box_circle() */
+
+
 POLYGON *circle_poly(int npts, CIRCLE *circle)
 {
     POLYGON *poly;
@@ -3271,7 +3587,7 @@ POLYGON *circle_poly(int npts, CIRCLE *circle)
     if (!PointerIsValid(circle))
 	return(NULL);
 
-    if (FPzero(circle->radius) || (npts <= 2))
+    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);
@@ -3305,7 +3621,7 @@ CIRCLE *poly_circle(POLYGON *poly)
     if (!PointerIsValid(poly))
 	return(NULL);
 
-    if (poly->npts <= 2)
+    if (poly->npts < 2)
 	  elog (WARN, "Unable to convert polygon to circle", NULL);
 
     circle = PALLOCTYPE(CIRCLE);
@@ -3330,4 +3646,162 @@ CIRCLE *poly_circle(POLYGON *poly)
 	  elog (WARN, "Unable to convert polygon to circle", NULL);
 
     return(circle);
-}
+} /* poly_circle() */
+
+
+/***********************************************************************
+ **
+ ** 	Private routines for multiple types.
+ **
+ ***********************************************************************/
+
+#define HIT_IT INT_MAX
+
+int
+point_inside( Point *p, int npts, Point plist[])
+{
+    double x0, y0;
+    double px, py;
+
+    int i;
+    double x, y;
+    int cross, crossnum;
+
+/*
+ * We calculate crossnum, which is twice the crossing number of a
+ * ray from the origin parallel to the positive X axis.
+ * A coordinate change is made to move the test point to the origin.
+ * Then the function lseg_crossing() is called to calculate the crossnum of
+ * one segment of the translated polygon with the ray which is the
+ * positive X-axis.
+ */
+
+    crossnum = 0; 
+    i = 0;
+    if (npts <= 0) return 0;
+
+    x0 = plist[0].x - p->x;
+    y0 = plist[0].y - p->y;
+
+    px = x0;
+    py = y0;
+    for (i = 1; i < npts; i++) {
+	x = plist[i].x - p->x;
+	y = plist[i].y - p->y;
+
+	if ( (cross = lseg_crossing( x, y, px, py)) == HIT_IT ) {
+	    return 2;
+	}
+	crossnum += cross;
+
+	px = x;
+	py = y;
+    }
+    if ( (cross = lseg_crossing( x0, y0, px, py)) == HIT_IT ) {
+	return 2;
+    }
+    crossnum += cross;
+    if ( crossnum != 0 ) {
+	return 1;
+    }
+    return 0;
+} /* point_inside() */
+
+
+/* lseg_crossing()
+ * The function lseg_crossing() returns +2, or -2 if the segment from (x,y)
+ * to previous (x,y) crosses the positive X-axis positively or negatively.
+ * It returns +1 or -1 if one endpoint is on this ray, or 0 if both are.
+ * It returns 0 if the ray and the segment don't intersect.
+ * It returns HIT_IT if the segment contains (0,0)
+ */
+
+int
+lseg_crossing( double x, double y, double px, double py)
+{
+    double z;
+    int sgn;
+
+    /* If (px,py) = (0,0) and not first call we have already sent HIT_IT */
+
+    if (FPzero( y)) {
+	if (FPzero( x)) {
+	    return(HIT_IT);
+
+	} else if (FPgt( x, 0)) {
+	    if (FPzero( py)) return(FPgt( px, 0)? 0 : HIT_IT);
+	    return(FPlt( py, 0)? 1 : -1);
+
+	} else { /* x < 0 */
+	    if (FPzero( py)) return(FPlt( px, 0)? 0 : HIT_IT);
+	    return(0);
+	};
+    };
+
+    /* Now we know y != 0;  set sgn to sign of y */
+    sgn = (FPgt( y, 0)? 1 : -1);
+    if (FPzero( py)) return(FPlt( px, 0)? 0 : sgn);
+
+    if (FPgt( (sgn * py), 0)) {	/* y and py have same sign */
+	return(0);
+
+    } else {			/* y and py have opposite signs */
+	if (FPge( x, 0) && FPgt( px, 0)) return(2 * sgn);
+	if (FPlt( x, 0) && FPle( px, 0)) return(0);
+
+	z = (x-px) * y - (y-py) * x;
+	if (FPzero( z)) return(HIT_IT);
+	return( FPgt( (sgn*z), 0)? 0 : 2 * sgn);
+    };
+} /* lseg_crossing() */
+
+
+bool
+plist_same(int npts, Point p1[], Point p2[])
+{
+    int i, ii, j;
+
+    /* find match for first point */
+    for (i = 0; i < npts; i++) {
+	if ((FPeq( p2[i].x, p1[0].x))
+	 && (FPeq( p2[i].y, p1[0].y))) {
+
+	    /* match found? then look forward through remaining points */
+	    for (ii = 1, j = i+1; ii < npts; ii++, j++) {
+		if (j >= npts) j = 0;
+		if ((!FPeq( p2[j].x, p1[ii].x))
+		 || (!FPeq( p2[j].y, p1[ii].y))) {
+#ifdef GEODEBUG
+printf( "plist_same- %d failed forward match with %d\n", j, ii);
+#endif
+		    break;
+		};
+	    };
+#ifdef GEODEBUG
+printf( "plist_same- ii = %d/%d after forward match\n", ii, npts);
+#endif
+	    if (ii == npts)
+		return(TRUE);
+
+	    /* match not found forwards? then look backwards */
+	    for (ii = 1, j = i-1; ii < npts; ii++, j--) {
+		if (j < 0) j = (npts-1);
+		if ((!FPeq( p2[j].x, p1[ii].x))
+		 || (!FPeq( p2[j].y, p1[ii].y))) {
+#ifdef GEODEBUG
+printf( "plist_same- %d failed reverse match with %d\n", j, ii);
+#endif
+		    break;
+		};
+	    };
+#ifdef GEODEBUG
+printf( "plist_same- ii = %d/%d after reverse match\n", ii, npts);
+#endif
+	    if (ii == npts)
+		return(TRUE);
+	};
+    };
+
+    return(FALSE);
+} /* plist_same() */
+