Skip to content

Commit c5c192d

Browse files
committed
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
1 parent 3f32395 commit c5c192d

File tree

3 files changed

+123
-13
lines changed

3 files changed

+123
-13
lines changed

doc/src/sgml/datatype.sgml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3562,8 +3562,9 @@ SELECT person.name, holidays.num_weeks FROM person, holidays
35623562

35633563
<para>
35643564
Polygons are represented by lists of points (the vertexes of the
3565-
polygon). Polygons are very similar to closed paths, but are
3566-
stored differently and have their own set of support routines.
3565+
polygon). Polygons are very similar to closed paths; the essential
3566+
difference is that a polygon is considered to include the area
3567+
within it, while a path is not.
35673568
</para>
35683569

35693570
<para>

src/backend/utils/adt/geo_ops.c

Lines changed: 67 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3798,11 +3798,9 @@ poly_same(PG_FUNCTION_ARGS)
37983798
/*-----------------------------------------------------------------
37993799
* Determine if polygon A overlaps polygon B
38003800
*-----------------------------------------------------------------*/
3801-
Datum
3802-
poly_overlap(PG_FUNCTION_ARGS)
3801+
static bool
3802+
poly_overlap_internal(POLYGON *polya, POLYGON *polyb)
38033803
{
3804-
POLYGON *polya = PG_GETARG_POLYGON_P(0);
3805-
POLYGON *polyb = PG_GETARG_POLYGON_P(1);
38063804
bool result;
38073805

38083806
Assert(polya->npts > 0 && polyb->npts > 0);
@@ -3854,6 +3852,18 @@ poly_overlap(PG_FUNCTION_ARGS)
38543852
}
38553853
}
38563854

3855+
return result;
3856+
}
3857+
3858+
Datum
3859+
poly_overlap(PG_FUNCTION_ARGS)
3860+
{
3861+
POLYGON *polya = PG_GETARG_POLYGON_P(0);
3862+
POLYGON *polyb = PG_GETARG_POLYGON_P(1);
3863+
bool result;
3864+
3865+
result = poly_overlap_internal(polya, polyb);
3866+
38573867
/*
38583868
* Avoid leaking memory for toasted inputs ... needed for rtree indexes
38593869
*/
@@ -4071,16 +4081,63 @@ pt_contained_poly(PG_FUNCTION_ARGS)
40714081
Datum
40724082
poly_distance(PG_FUNCTION_ARGS)
40734083
{
4074-
#ifdef NOT_USED
40754084
POLYGON *polya = PG_GETARG_POLYGON_P(0);
40764085
POLYGON *polyb = PG_GETARG_POLYGON_P(1);
4077-
#endif
4086+
float8 min = 0.0; /* initialize to keep compiler quiet */
4087+
bool have_min = false;
4088+
float8 tmp;
4089+
int i,
4090+
j;
4091+
LSEG seg1,
4092+
seg2;
40784093

4079-
ereport(ERROR,
4080-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4081-
errmsg("function \"poly_distance\" not implemented")));
4094+
/*
4095+
* Distance is zero if polygons overlap. We must check this because the
4096+
* path distance will not give the right answer if one poly is entirely
4097+
* within the other.
4098+
*/
4099+
if (poly_overlap_internal(polya, polyb))
4100+
PG_RETURN_FLOAT8(0.0);
40824101

4083-
PG_RETURN_NULL();
4102+
/*
4103+
* When they don't overlap, the distance calculation is identical to that
4104+
* for closed paths (i.e., we needn't care about the fact that polygons
4105+
* include their contained areas). See path_distance().
4106+
*/
4107+
for (i = 0; i < polya->npts; i++)
4108+
{
4109+
int iprev;
4110+
4111+
if (i > 0)
4112+
iprev = i - 1;
4113+
else
4114+
iprev = polya->npts - 1;
4115+
4116+
for (j = 0; j < polyb->npts; j++)
4117+
{
4118+
int jprev;
4119+
4120+
if (j > 0)
4121+
jprev = j - 1;
4122+
else
4123+
jprev = polyb->npts - 1;
4124+
4125+
statlseg_construct(&seg1, &polya->p[iprev], &polya->p[i]);
4126+
statlseg_construct(&seg2, &polyb->p[jprev], &polyb->p[j]);
4127+
4128+
tmp = lseg_closept_lseg(NULL, &seg1, &seg2);
4129+
if (!have_min || float8_lt(tmp, min))
4130+
{
4131+
min = tmp;
4132+
have_min = true;
4133+
}
4134+
}
4135+
}
4136+
4137+
if (!have_min)
4138+
PG_RETURN_NULL();
4139+
4140+
PG_RETURN_FLOAT8(min);
40844141
}
40854142

40864143

src/test/regress/expected/geometry.out

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4189,7 +4189,59 @@ SELECT p1.f1, p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2 WHERE p1.f1 |&> p2.f1;
41894189

41904190
-- Distance to polygon
41914191
SELECT p1.f1, p2.f1, p1.f1 <-> p2.f1 FROM POLYGON_TBL p1, POLYGON_TBL p2;
4192-
ERROR: function "poly_distance" not implemented
4192+
f1 | f1 | ?column?
4193+
----------------------------+----------------------------+----------------
4194+
((2,0),(2,4),(0,0)) | ((2,0),(2,4),(0,0)) | 0
4195+
((2,0),(2,4),(0,0)) | ((3,1),(3,3),(1,0)) | 0
4196+
((2,0),(2,4),(0,0)) | ((1,2),(3,4),(5,6),(7,8)) | 0
4197+
((2,0),(2,4),(0,0)) | ((7,8),(5,6),(3,4),(1,2)) | 0
4198+
((2,0),(2,4),(0,0)) | ((1,2),(7,8),(5,6),(3,-4)) | 0
4199+
((2,0),(2,4),(0,0)) | ((0,0)) | 0
4200+
((2,0),(2,4),(0,0)) | ((0,1),(0,1)) | 0.4472135955
4201+
((3,1),(3,3),(1,0)) | ((2,0),(2,4),(0,0)) | 0
4202+
((3,1),(3,3),(1,0)) | ((3,1),(3,3),(1,0)) | 0
4203+
((3,1),(3,3),(1,0)) | ((1,2),(3,4),(5,6),(7,8)) | 0.707106781187
4204+
((3,1),(3,3),(1,0)) | ((7,8),(5,6),(3,4),(1,2)) | 0.707106781187
4205+
((3,1),(3,3),(1,0)) | ((1,2),(7,8),(5,6),(3,-4)) | 0
4206+
((3,1),(3,3),(1,0)) | ((0,0)) | 1
4207+
((3,1),(3,3),(1,0)) | ((0,1),(0,1)) | 1.38675049056
4208+
((1,2),(3,4),(5,6),(7,8)) | ((2,0),(2,4),(0,0)) | 0
4209+
((1,2),(3,4),(5,6),(7,8)) | ((3,1),(3,3),(1,0)) | 0.707106781187
4210+
((1,2),(3,4),(5,6),(7,8)) | ((1,2),(3,4),(5,6),(7,8)) | 0
4211+
((1,2),(3,4),(5,6),(7,8)) | ((7,8),(5,6),(3,4),(1,2)) | 0
4212+
((1,2),(3,4),(5,6),(7,8)) | ((1,2),(7,8),(5,6),(3,-4)) | 0
4213+
((1,2),(3,4),(5,6),(7,8)) | ((0,0)) | 2.2360679775
4214+
((1,2),(3,4),(5,6),(7,8)) | ((0,1),(0,1)) | 1.41421356237
4215+
((7,8),(5,6),(3,4),(1,2)) | ((2,0),(2,4),(0,0)) | 0
4216+
((7,8),(5,6),(3,4),(1,2)) | ((3,1),(3,3),(1,0)) | 0.707106781187
4217+
((7,8),(5,6),(3,4),(1,2)) | ((1,2),(3,4),(5,6),(7,8)) | 0
4218+
((7,8),(5,6),(3,4),(1,2)) | ((7,8),(5,6),(3,4),(1,2)) | 0
4219+
((7,8),(5,6),(3,4),(1,2)) | ((1,2),(7,8),(5,6),(3,-4)) | 0
4220+
((7,8),(5,6),(3,4),(1,2)) | ((0,0)) | 2.2360679775
4221+
((7,8),(5,6),(3,4),(1,2)) | ((0,1),(0,1)) | 1.41421356237
4222+
((1,2),(7,8),(5,6),(3,-4)) | ((2,0),(2,4),(0,0)) | 0
4223+
((1,2),(7,8),(5,6),(3,-4)) | ((3,1),(3,3),(1,0)) | 0
4224+
((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(3,4),(5,6),(7,8)) | 0
4225+
((1,2),(7,8),(5,6),(3,-4)) | ((7,8),(5,6),(3,4),(1,2)) | 0
4226+
((1,2),(7,8),(5,6),(3,-4)) | ((1,2),(7,8),(5,6),(3,-4)) | 0
4227+
((1,2),(7,8),(5,6),(3,-4)) | ((0,0)) | 1.58113883008
4228+
((1,2),(7,8),(5,6),(3,-4)) | ((0,1),(0,1)) | 1.26491106407
4229+
((0,0)) | ((2,0),(2,4),(0,0)) | 0
4230+
((0,0)) | ((3,1),(3,3),(1,0)) | 1
4231+
((0,0)) | ((1,2),(3,4),(5,6),(7,8)) | 2.2360679775
4232+
((0,0)) | ((7,8),(5,6),(3,4),(1,2)) | 2.2360679775
4233+
((0,0)) | ((1,2),(7,8),(5,6),(3,-4)) | 1.58113883008
4234+
((0,0)) | ((0,0)) | 0
4235+
((0,0)) | ((0,1),(0,1)) | 1
4236+
((0,1),(0,1)) | ((2,0),(2,4),(0,0)) | 0.4472135955
4237+
((0,1),(0,1)) | ((3,1),(3,3),(1,0)) | 1.38675049056
4238+
((0,1),(0,1)) | ((1,2),(3,4),(5,6),(7,8)) | 1.41421356237
4239+
((0,1),(0,1)) | ((7,8),(5,6),(3,4),(1,2)) | 1.41421356237
4240+
((0,1),(0,1)) | ((1,2),(7,8),(5,6),(3,-4)) | 1.26491106407
4241+
((0,1),(0,1)) | ((0,0)) | 1
4242+
((0,1),(0,1)) | ((0,1),(0,1)) | 0
4243+
(49 rows)
4244+
41934245
--
41944246
-- Circles
41954247
--

0 commit comments

Comments
 (0)