Opened 13 months ago

Closed 11 months ago

Last modified 11 months ago

#5639 closed defect (fixed)

ST_DFullyWithin fails when dealing with LINESTRING and POLYGON

Reported by: Wenjing Owned by: pramsey
Priority: medium Milestone: PostGIS 3.4.2
Component: postgis Version: 3.4.x
Keywords: Cc: nicklas

Description

Consider the following statement:

SELECT ST_DFullyWithin(a1, a2, 100)
FROM ST_GeomFromText('LINESTRING(0 0, 0 1, 1 0, 0 0)') As a1
,ST_GeomFromText('POLYGON((0 0, 0 1, 1 0, 0 0))') As a2;
--actual{f}; expected{t} 

According to the definition below, the result of ST_DFullyWithin(a1, a2, 100) is expected to true.

Returns true if the geometries are entirely within the specified distance of one another.

Because the geometry a1 is fully within each point of a2 in the distance of 100. The same as a2 to a1. However, Postgis doesn't consider the DFullyWithin relationship. So I believe it is an unexpected behavior here.

Version:

POSTGIS="3.5.0dev 3.4.0rc1-830-g8f77e8a6b" [EXTENSION] PGSQL="170" GEOS="3.13.0dev-CAPI-1.18.0" PROJ="8.2.1 NETWORK_ENABLED=OFF URL_ENDPOINT=https://cdn.proj.org USER_WRITABLE_DIRECTORY=/tmp/proj DATABASE_PATH=/usr/share/proj/proj.db" LIBXML="2.9.13"

Change History (21)

comment:1 by Wenjing, 11 months ago

@pramsey, did you already have a chance to look at the report? After this is being fixed, we could continue finding and reporting additional potential bugs.

comment:2 by pramsey, 11 months ago

Confirmed can replicate.

comment:3 by pramsey, 11 months ago

This is quite bad one, basically handling of max distance for objects that overlap is quite bad.

SELECT ST_MaxDistance(a1, a2)
FROM (VALUES 
  ('POINT(0.5 0.5)', 'POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))')
  ) AS a(a1, a2);

SELECT ST_MaxDistance(a1, a2)
FROM (VALUES 
  ('POINT(1.5 1.5)', 'POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))')
  ) AS a(a1, a2);

SELECT ST_MaxDistance(a1, a2)
FROM (VALUES 
  ('LINESTRING(0.5 0.5, 1.1 1.1)', 'POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))')
  ) AS a(a1, a2);

SELECT ST_MaxDistance(a1, a2)
FROM (VALUES 
  ('LINESTRING(0.5 0.5, 1.5 1.5)', 'POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))')
  ) AS a(a1, a2);

SELECT ST_MaxDistance(a1, a2)
FROM (VALUES 
  ('LINESTRING(1.5 1.5, 0.5 0.5)', 'POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))')
  ) AS a(a1, a2);

And this is without getting into really fun cases where the largest distance is found at a vertex in a hole, for example.

comment:4 by pramsey, 11 months ago

Cc: nicklas added

comment:5 by Wenjing, 11 months ago

Right. It is tricky to handle overlap cases. Thank you for confirming and explaining.

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

In 5b2ae9ff/git:

Correctly handle max distance for point/polygon case, avoiding returning distance to points that are contained in the polygon (distance == 0). References #5639

comment:7 by Wenjing, 11 months ago

Thanks for the quick fix!

comment:8 by pramsey, 11 months ago

That (point/poly) was the easy one. The cases with line/poly and poly/poly are much harder, I'm not seeing anything that doesn't involve writing an immense amount of net-new code to handle these relatively unused cases.

comment:9 by Paul Ramsey <pramsey@…>, 11 months ago

In c72cdb44/git:

Revert change to max distance, as it does not conform to original understanding of the function (max distance between points in the pairing), references #5639

comment:10 by Paul Ramsey <pramsey@…>, 11 months ago

In bc681cba/git:

Correctly handle max distance for point/polygon case, avoiding returning distance to points that are contained in the polygon (distance == 0). References #5639

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

In 4e0c93a/git:

Revert change to max distance, as it does not conform to original understanding of the function (max distance between points in the pairing), references #5639

comment:12 by pramsey, 11 months ago

So, this ticket is still valid, though hopefully the fix is more of a special case change than a major re-work. The max distance mode needs a lot more test cases to prove it works as documented (max distance between vertices, no special handling for rings/areas).

comment:13 by pramsey, 11 months ago

OK, so back to the actual problem, which seems in this case confined to ST_DFullyWithin.

SELECT ST_MaxDistance(
  'LINESTRING(0 0, 0 1, 1 0, 0 0)'::geometry, 
  'POLYGON((0 0, 0 1, 1 0, 0 0))'::geometry);

   st_maxdistance   
--------------------
 1.4142135623730951

SELECT ST_DFullyWithin(
  'LINESTRING(0 0, 0 1, 1 0, 0 0)'::geometry, 
  'POLYGON((0 0, 0 1, 1 0, 0 0))'::geometry,
  100);

 st_dfullywithin 
-----------------
 f

So the maximum distance between vertices in those two rings is indeed sqrt(2). But that… is way less than 100, so something is odd with the ST_DFullyWithin test.

comment:14 by Paul Ramsey <pramsey@…>, 11 months ago

In a4909b1/git:

Do full ring check always in line/poly maxdist mode, references #5639

comment:15 by Paul Ramsey <pramsey@…>, 11 months ago

In a5d3d35/git:

Do full ring check always in line/poly maxdist mode, references #5639

comment:16 by Paul Ramsey <pramsey@…>, 11 months ago

In ad529a7f/git:

Do full ring check always in line/poly maxdist mode, references #5639

comment:17 by Paul Ramsey <pramsey@…>, 11 months ago

In b2e5dc8/git:

Do full ring check always in line/poly maxdist mode, references #5639

comment:18 by Paul Ramsey <pramsey@…>, 11 months ago

In da5ca59/git:

Do full ring check always in line/poly maxdist mode, references #5639

comment:19 by Paul Ramsey <pramsey@…>, 11 months ago

In a2b355a/git:

Do full ring check always in line/poly maxdist mode, references #5639

comment:20 by pramsey, 11 months ago

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