Opened 5 months ago

Closed 3 months ago

#5740 closed defect (fixed)

ST_DistanceSpheroid doesn't return 0 when one geometry contains the other

Reported by: cdestigter Owned by: pramsey
Priority: medium Milestone: PostGIS 3.4.3
Component: postgis Version: 3.4.x
Keywords: Cc:

Description (last modified by cdestigter)

The docs say

Returns minimum distance in meters between two lon/lat geometries given a particular spheroid

Based on this description it seems that any intersection between the two geometries should cause the result to be 0 (the minimum distance between the geometries is 0 because they overlap)

However, it seems that actually compares the _edges_ of the geometries - if one geometry contains the other you get a positive number:

-- touching the edge of the polygon, the result is zero
=> select st_distancespheroid('SRID=4326;POLYGON((0 0,0 1,1 1,1 0,0 0))'::GEOMETRY, 'SRID=4326;POINT(0 0.5)'::geometry);

0


-- close to the edge, the result is nonzero
=> select st_distancespheroid('SRID=4326;POLYGON((0 0,0 1,1 1,1 0,0 0))'::GEOMETRY, 'SRID=4326;POINT(0.1 0.5)'::geometry);

11131.528045775543


-- the further you get from the edge, the larger the result
=> select st_distancespheroid('SRID=4326;POLYGON((0 0,0 1,1 1,1 0,0 0))'::GEOMETRY, 'SRID=4326;POINT(0.5 0.5)'::geometry);

55657.640177233385

Interestingly, ST_DistanceSphere gives the expected result:

=> select st_distancesphere('SRID=4326;POLYGON((0 0,0 1,1 1,1 0,0 0))'::GEOMETRY, 'SRID=4326;POINT(0.5 0.5)'::geometry);

0

Change History (8)

comment:1 by cdestigter, 5 months ago

Description: modified (diff)

comment:2 by cdestigter, 5 months ago

I've had a browse around the code, and it seems like the bug is here - the code checks for edge intersections and returns 0 if there are any but it doesn't check for containment.

I'm not sure how ST_DistanceSphere avoids the issue since it looks like it probably goes down a similar codepath

ST_DistanceSphere actually has the same issue IF you explicitly provide the optional third parameter (world radius in metres)

=> select st_distancesphere('SRID=4326;POLYGON((0 0,0 1,1 1,1 0,0 0))'::GEOMETRY, 'SRID=4326;POINT(0.5 0.5)'::geometry, 6371008);
 55595.41609801024

It looks like if you omit that parameter it doesn't use the buggy codepath - instead it casts your geometries to geographies and calls geography_distance which doesn't have the same problem.

Last edited 5 months ago by cdestigter (previous) (diff)

comment:3 by pramsey, 3 months ago

Hm, I really thought we had all these things draining into the geography code path by now.

comment:4 by Paul Ramsey <pramsey@…>, 3 months ago

In cc1f1c2/git:

Error in ST_DistanceSpheroid due to planar box leaking into geodetic code, references #5740

comment:5 by pramsey, 3 months ago

Yep, a little more subtle. The geometry bounding box was sneaking into the geodetic covers operation, causing a mis-fire when the code started from a geometry (as in this example).

comment:6 by Paul Ramsey <pramsey@…>, 3 months ago

In f2bf5ce/git:

Error in ST_DistanceSpheroid due to planar box leaking into geodetic code, references #5740

comment:7 by Paul Ramsey <pramsey@…>, 3 months ago

In f3b71b1d/git:

Error in ST_DistanceSpheroid due to planar box leaking into geodetic code, references #5740

comment:8 by pramsey, 3 months ago

Resolution: fixed
Status: newclosed
Note: See TracTickets for help on using tickets.