Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Implement poly_distance().
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 13 Dec 2021 22:33:32 +0000 (17:33 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 13 Dec 2021 22:33:32 +0000 (17:33 -0500)
geo_ops.c contains half a dozen functions that are just stubs throwing
ERRCODE_FEATURE_NOT_SUPPORTED.  Since it's been like that for more
than twenty years, there's clearly not a lot of interest in filling in
the stubs.  However, I'm uncomfortable with deleting poly_distance(),
since every other geometric type supports a distance-to-another-object-
of-the-same-type function.  We can easily add this capability by
cribbing from poly_overlap() and path_distance().

It's possible that the (existing) test case for this will show some
numeric instability, but hopefully the buildfarm will expose it if so.

In passing, improve the documentation to try to explain why polygons
are distinct from closed paths in the first place.

Discussion: https://postgr.es/m/3426566.1638832718@sss.pgh.pa.us

doc/src/sgml/datatype.sgml
src/backend/utils/adt/geo_ops.c
src/test/regress/expected/geometry.out

index 6929f3bb1831f683beda3c49eab5c8a85cad6a2c..0932c812da5c66bb4c98f405a7c056cb2a3c5181 100644 (file)
@@ -3562,8 +3562,9 @@ SELECT person.name, holidays.num_weeks FROM person, holidays
 
     <para>
      Polygons are represented by lists of points (the vertexes of the
-     polygon). Polygons are very similar to closed paths, but are
-     stored differently and have their own set of support routines.
+     polygon). Polygons are very similar to closed paths; the essential
+     difference is that a polygon is considered to include the area
+     within it, while a path is not.
     </para>
 
     <para>
index 9484dbc22737abfb098203f4054816d4f62fee06..e9c347cb8c6d67673d249aed3a9445c46abf080a 100644 (file)
@@ -3798,11 +3798,9 @@ poly_same(PG_FUNCTION_ARGS)
 /*-----------------------------------------------------------------
  * Determine if polygon A overlaps polygon B
  *-----------------------------------------------------------------*/
-Datum
-poly_overlap(PG_FUNCTION_ARGS)
+static bool
+poly_overlap_internal(POLYGON *polya, POLYGON *polyb)
 {
-   POLYGON    *polya = PG_GETARG_POLYGON_P(0);
-   POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
    bool        result;
 
    Assert(polya->npts > 0 && polyb->npts > 0);
@@ -3854,6 +3852,18 @@ poly_overlap(PG_FUNCTION_ARGS)
        }
    }
 
+   return result;
+}
+
+Datum
+poly_overlap(PG_FUNCTION_ARGS)
+{
+   POLYGON    *polya = PG_GETARG_POLYGON_P(0);
+   POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
+   bool        result;
+
+   result = poly_overlap_internal(polya, polyb);
+
    /*
     * Avoid leaking memory for toasted inputs ... needed for rtree indexes
     */
@@ -4071,16 +4081,63 @@ pt_contained_poly(PG_FUNCTION_ARGS)
 Datum
 poly_distance(PG_FUNCTION_ARGS)
 {
-#ifdef NOT_USED
    POLYGON    *polya = PG_GETARG_POLYGON_P(0);
    POLYGON    *polyb = PG_GETARG_POLYGON_P(1);
-#endif
+   float8      min = 0.0;      /* initialize to keep compiler quiet */
+   bool        have_min = false;
+   float8      tmp;
+   int         i,
+               j;
+   LSEG        seg1,
+               seg2;
 
-   ereport(ERROR,
-           (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-            errmsg("function \"poly_distance\" not implemented")));
+   /*
+    * Distance is zero if polygons overlap.  We must check this because the
+    * path distance will not give the right answer if one poly is entirely
+    * within the other.
+    */
+   if (poly_overlap_internal(polya, polyb))
+       PG_RETURN_FLOAT8(0.0);
 
-   PG_RETURN_NULL();
+   /*
+    * When they don't overlap, the distance calculation is identical to that
+    * for closed paths (i.e., we needn't care about the fact that polygons
+    * include their contained areas).  See path_distance().
+    */
+   for (i = 0; i < polya->npts; i++)
+   {
+       int         iprev;
+
+       if (i > 0)
+           iprev = i - 1;
+       else
+           iprev = polya->npts - 1;
+
+       for (j = 0; j < polyb->npts; j++)
+       {
+           int         jprev;
+
+           if (j > 0)
+               jprev = j - 1;
+           else
+               jprev = polyb->npts - 1;
+
+           statlseg_construct(&seg1, &polya->p[iprev], &polya->p[i]);
+           statlseg_construct(&seg2, &polyb->p[jprev], &polyb->p[j]);
+
+           tmp = lseg_closept_lseg(NULL, &seg1, &seg2);
+           if (!have_min || float8_lt(tmp, min))
+           {
+               min = tmp;
+               have_min = true;
+           }
+       }
+   }
+
+   if (!have_min)
+       PG_RETURN_NULL();
+
+   PG_RETURN_FLOAT8(min);
 }
 
 
index 974e2ec43a48ff01ca34749f754db0de1f285c03..eb717d364340880e935077a7140f3d708811e05e 100644 (file)
@@ -4189,7 +4189,59 @@ SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |&> p2.f1;
 
 -- Distance to polygon
 SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2;
-ERROR:  function "poly_distance" not implemented
+             f1             |             f1             |    ?column?    
+----------------------------+----------------------------+----------------
+ ((2,0),(2,4),(0,0))        | ((2,0),(2,4),(0,0))        |              0
+ ((2,0),(2,4),(0,0))        | ((3,1),(3,3),(1,0))        |              0
+ ((2,0),(2,4),(0,0))        | ((1,2),(3,4),(5,6),(7,8))  |              0
+ ((2,0),(2,4),(0,0))        | ((7,8),(5,6),(3,4),(1,2))  |              0
+ ((2,0),(2,4),(0,0))        | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ ((2,0),(2,4),(0,0))        | ((0,0))                    |              0
+ ((2,0),(2,4),(0,0))        | ((0,1),(0,1))              |   0.4472135955
+ ((3,1),(3,3),(1,0))        | ((2,0),(2,4),(0,0))        |              0
+ ((3,1),(3,3),(1,0))        | ((3,1),(3,3),(1,0))        |              0
+ ((3,1),(3,3),(1,0))        | ((1,2),(3,4),(5,6),(7,8))  | 0.707106781187
+ ((3,1),(3,3),(1,0))        | ((7,8),(5,6),(3,4),(1,2))  | 0.707106781187
+ ((3,1),(3,3),(1,0))        | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ ((3,1),(3,3),(1,0))        | ((0,0))                    |              1
+ ((3,1),(3,3),(1,0))        | ((0,1),(0,1))              |  1.38675049056
+ ((1,2),(3,4),(5,6),(7,8))  | ((2,0),(2,4),(0,0))        |              0
+ ((1,2),(3,4),(5,6),(7,8))  | ((3,1),(3,3),(1,0))        | 0.707106781187
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(3,4),(5,6),(7,8))  |              0
+ ((1,2),(3,4),(5,6),(7,8))  | ((7,8),(5,6),(3,4),(1,2))  |              0
+ ((1,2),(3,4),(5,6),(7,8))  | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,0))                    |   2.2360679775
+ ((1,2),(3,4),(5,6),(7,8))  | ((0,1),(0,1))              |  1.41421356237
+ ((7,8),(5,6),(3,4),(1,2))  | ((2,0),(2,4),(0,0))        |              0
+ ((7,8),(5,6),(3,4),(1,2))  | ((3,1),(3,3),(1,0))        | 0.707106781187
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(3,4),(5,6),(7,8))  |              0
+ ((7,8),(5,6),(3,4),(1,2))  | ((7,8),(5,6),(3,4),(1,2))  |              0
+ ((7,8),(5,6),(3,4),(1,2))  | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,0))                    |   2.2360679775
+ ((7,8),(5,6),(3,4),(1,2))  | ((0,1),(0,1))              |  1.41421356237
+ ((1,2),(7,8),(5,6),(3,-4)) | ((2,0),(2,4),(0,0))        |              0
+ ((1,2),(7,8),(5,6),(3,-4)) | ((3,1),(3,3),(1,0))        |              0
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8))  |              0
+ ((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2))  |              0
+ ((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4)) |              0
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,0))                    |  1.58113883008
+ ((1,2),(7,8),(5,6),(3,-4)) | ((0,1),(0,1))              |  1.26491106407
+ ((0,0))                    | ((2,0),(2,4),(0,0))        |              0
+ ((0,0))                    | ((3,1),(3,3),(1,0))        |              1
+ ((0,0))                    | ((1,2),(3,4),(5,6),(7,8))  |   2.2360679775
+ ((0,0))                    | ((7,8),(5,6),(3,4),(1,2))  |   2.2360679775
+ ((0,0))                    | ((1,2),(7,8),(5,6),(3,-4)) |  1.58113883008
+ ((0,0))                    | ((0,0))                    |              0
+ ((0,0))                    | ((0,1),(0,1))              |              1
+ ((0,1),(0,1))              | ((2,0),(2,4),(0,0))        |   0.4472135955
+ ((0,1),(0,1))              | ((3,1),(3,3),(1,0))        |  1.38675049056
+ ((0,1),(0,1))              | ((1,2),(3,4),(5,6),(7,8))  |  1.41421356237
+ ((0,1),(0,1))              | ((7,8),(5,6),(3,4),(1,2))  |  1.41421356237
+ ((0,1),(0,1))              | ((1,2),(7,8),(5,6),(3,-4)) |  1.26491106407
+ ((0,1),(0,1))              | ((0,0))                    |              1
+ ((0,1),(0,1))              | ((0,1),(0,1))              |              0
+(49 rows)
+
 --
 -- Circles
 --