Implement poly_distance().

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
This commit is contained in:
Tom Lane 2021-12-13 17:33:32 -05:00
parent 3f32395612
commit c5c192d7bd
3 changed files with 123 additions and 13 deletions

View 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>

View 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);
}

View 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
--