path_inter, path_distance, path_length, dist_ppath now do the right
authorTom Lane
Sat, 13 Oct 2001 17:40:24 +0000 (17:40 +0000)
committerTom Lane
Sat, 13 Oct 2001 17:40:24 +0000 (17:40 +0000)
things with closed paths --- ie, include the closing line segment in
their calculations.  Per bug report from Curtis Barrett 9-Oct-01.

src/backend/utils/adt/geo_ops.c

index aac191b377856163e190cdf1326f1c8c71e36227..4590500ecad39ac9518947b832d8a4b09b0755e2 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/adt/geo_ops.c,v 1.58 2001/03/22 03:59:50 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/adt/geo_ops.c,v 1.59 2001/10/13 17:40:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -948,7 +948,7 @@ line_construct_pts(LINE *line, Point *pt1, Point *pt2)
    }
    else if (FPeq(pt1->y, pt2->y))
    {                           /* horizontal */
-       /* use "x = C" */
+       /* use "y = C" */
        line->A = 0;
        line->B = -1;
        line->C = pt1->y;
@@ -1376,6 +1376,9 @@ path_inter(PG_FUNCTION_ARGS)
    LSEG        seg1,
                seg2;
 
+   if (p1->npts <= 0 || p2->npts <= 0)
+       PG_RETURN_BOOL(false);
+
    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++)
@@ -1398,12 +1401,34 @@ path_inter(PG_FUNCTION_ARGS)
        PG_RETURN_BOOL(false);
 
    /* pairwise check lseg intersections */
-   for (i = 0; i < p1->npts - 1; i++)
+   for (i = 0; i < p1->npts; i++)
    {
-       for (j = 0; j < p2->npts - 1; j++)
+       int iprev;
+
+       if (i > 0)
+           iprev = i-1;
+       else
        {
-           statlseg_construct(&seg1, &p1->p[i], &p1->p[i + 1]);
-           statlseg_construct(&seg2, &p2->p[j], &p2->p[j + 1]);
+           if (!p1->closed)
+               continue;
+           iprev = p1->npts-1; /* include the closure segment */
+       }
+
+       for (j = 0; j < p2->npts; j++)
+       {
+           int jprev;
+
+           if (j > 0)
+               jprev = j-1;
+           else
+           {
+               if (!p2->closed)
+                   continue;
+               jprev = p2->npts-1; /* include the closure segment */
+           }
+
+           statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
+           statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
            if (lseg_intersect_internal(&seg1, &seg2))
                PG_RETURN_BOOL(true);
        }
@@ -1422,20 +1447,42 @@ path_distance(PG_FUNCTION_ARGS)
 {
    PATH       *p1 = PG_GETARG_PATH_P(0);
    PATH       *p2 = PG_GETARG_PATH_P(1);
-   bool        have_min = false;
    float8      min = 0.0;      /* initialize to keep compiler quiet */
+   bool        have_min = false;
    float8      tmp;
    int         i,
                j;
    LSEG        seg1,
                seg2;
 
-   for (i = 0; i < p1->npts - 1; i++)
+   for (i = 0; i < p1->npts; i++)
    {
-       for (j = 0; j < p2->npts - 1; j++)
+       int iprev;
+
+       if (i > 0)
+           iprev = i-1;
+       else
        {
-           statlseg_construct(&seg1, &p1->p[i], &p1->p[i + 1]);
-           statlseg_construct(&seg2, &p2->p[j], &p2->p[j + 1]);
+           if (!p1->closed)
+               continue;
+           iprev = p1->npts-1; /* include the closure segment */
+       }
+
+       for (j = 0; j < p2->npts; j++)
+       {
+           int jprev;
+
+           if (j > 0)
+               jprev = j-1;
+           else
+           {
+               if (!p2->closed)
+                   continue;
+               jprev = p2->npts-1; /* include the closure segment */
+           }
+
+           statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
+           statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
 
            tmp = DatumGetFloat8(DirectFunctionCall2(lseg_distance,
                                                     LsegPGetDatum(&seg1),
@@ -1463,12 +1510,24 @@ Datum
 path_length(PG_FUNCTION_ARGS)
 {
    PATH       *path = PG_GETARG_PATH_P(0);
-   float8      result;
+   float8      result = 0.0;
    int         i;
 
-   result = 0.0;
-   for (i = 0; i < (path->npts - 1); i++)
-       result += point_dt(&path->p[i], &path->p[i + 1]);
+   for (i = 0; i < path->npts; i++)
+   {
+       int iprev;
+
+       if (i > 0)
+           iprev = i-1;
+       else
+       {
+           if (!path->closed)
+               continue;
+           iprev = path->npts-1;   /* include the closure segment */
+       }
+
+       result += point_dt(&path->p[iprev], &path->p[i]);
+   }
 
    PG_RETURN_FLOAT8(result);
 }
@@ -2133,17 +2192,18 @@ dist_ppath(PG_FUNCTION_ARGS)
    Point      *pt = PG_GETARG_POINT_P(0);
    PATH       *path = PG_GETARG_PATH_P(1);
    float8      result = 0.0;   /* keep compiler quiet */
+   bool        have_min = false;
    float8      tmp;
    int         i;
    LSEG        lseg;
 
    switch (path->npts)
    {
-           /* no points in path? then result is undefined... */
        case 0:
+           /* no points in path? then result is undefined... */
            PG_RETURN_NULL();
-           /* one point in path? then get distance between two points... */
        case 1:
+           /* one point in path? then get distance between two points... */
            result = point_dt(pt, &path->p[0]);
            break;
        default:
@@ -2154,12 +2214,26 @@ dist_ppath(PG_FUNCTION_ARGS)
             * the distance from a point to a path is the smallest
             * distance from the point to any of its constituent segments.
             */
-           for (i = 0; i < path->npts - 1; i++)
+           for (i = 0; i < path->npts; i++)
            {
-               statlseg_construct(&lseg, &path->p[i], &path->p[i + 1]);
+               int iprev;
+
+               if (i > 0)
+                   iprev = i-1;
+               else
+               {
+                   if (!path->closed)
+                       continue;
+                   iprev = path->npts-1;   /* include the closure segment */
+               }
+
+               statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
                tmp = dist_ps_internal(pt, &lseg);
-               if (i == 0 || tmp < result)
+               if (!have_min || tmp < result)
+               {
                    result = tmp;
+                   have_min = true;
+               }
            }
            break;
    }
@@ -2824,8 +2898,6 @@ on_pb(PG_FUNCTION_ARGS)
  *             but not cross.
  *             (we can do p-in-p in lg(n), but it takes preprocessing)
  */
-#define NEXT(A) (((A)+1) % path->npts) /* cyclic "i+1" */
-
 Datum
 on_ppath(PG_FUNCTION_ARGS)
 {