[SCM] PostGIS branch master updated. 3.4.0rc1-899-gf5d6c10b7

git at osgeo.org git at osgeo.org
Thu Jan 25 08:08:43 PST 2024


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "PostGIS".

The branch, master has been updated
       via  f5d6c10b7de4cc6cac4e809d495aa4ad25ca4743 (commit)
      from  a4909b145317932b05e7ebb9f55df127de965982 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit f5d6c10b7de4cc6cac4e809d495aa4ad25ca4743
Author: Paul Ramsey <pramsey at cleverelephant.ca>
Date:   Thu Jan 25 08:07:11 2024 -0800

    Change behaviour of ST_DFullyWithin(A, B, R)
    to be equivalent to ST_Contains(ST_Buffer(A, R), B).
    This should more correctly match the behaviour users
    expect and more logically extends on the behaviour
    of ST_DWithin(A, B, R). Closes #5659.

diff --git a/NEWS b/NEWS
index 9679ccf22..4ab25172d 100644
--- a/NEWS
+++ b/NEWS
@@ -27,6 +27,8 @@ To take advantage of all SFCGAL featurs, SFCGAL 1.5.0+ is needed.
            (Jan Tojnar)
   - #5496, ST_Clip all variants replaced, will require
            rebuilding of materialized views that use them (Regina Obe)
+  - #5659, ST_DFullyWithin behaviour has changed to 
+           be ST_Contains(ST_Buffer(A, R), B) (Paul Ramsey)
 
 * New Features *
 
diff --git a/doc/reference_relationship.xml b/doc/reference_relationship.xml
index b1570598d..fb42bf111 100644
--- a/doc/reference_relationship.xml
+++ b/doc/reference_relationship.xml
@@ -2102,7 +2102,7 @@ ST_DWithin(
     <refnamediv>
     <refname>ST_DFullyWithin</refname>
 
-    <refpurpose>Tests if two geometries are entirely within a given distance</refpurpose>
+    <refpurpose>Tests if a geometry is entirely inside a distance of another</refpurpose>
     </refnamediv>
 
     <refsynopsisdiv>
@@ -2125,26 +2125,33 @@ ST_DWithin(
     <refsection>
     <title>Description</title>
 
-    <para>Returns true if the geometries are entirely within the specified distance
-    of one another. The distance is specified in units defined by the
-    spatial reference system of the geometries.  For this function to make
-    sense, the source geometries must both be of the same coordinate projection,
-    having the same SRID.</para>
+    <para>Returns true if <code>g2</code> is entirely within
+    <code>distance</code> of <code>g1</code>. Visually, the
+    condition is true if <code>g2</code> is contained within
+    a <code>distance</code> buffer of <code>g1</code>.
+    The distance is specified in units defined by the
+    spatial reference system of the geometries.</para>
 
     <note><para>&index_aware;</para></note>
 
     <para role="availability" conformance="1.5.0">Availability: 1.5.0</para>
+    <para role="changed" conformance="3.5.0">Changed: 3.5.0 : the logic behind the function now uses a test of containment within a buffer, rather than the ST_MaxDistance algorithm. Results will differ from prior versions, but should be closer to user expectations.</para>
     </refsection>
 
     <refsection>
     <title>Examples</title>
-    <programlisting>postgis=# SELECT ST_DFullyWithin(geom_a, geom_b, 10) as DFullyWithin10, ST_DWithin(geom_a, geom_b, 10) as DWithin10, ST_DFullyWithin(geom_a, geom_b, 20) as DFullyWithin20 from
-    (select ST_GeomFromText('POINT(1 1)') as geom_a,ST_GeomFromText('LINESTRING(1 5, 2 7, 1 9, 14 12)') as geom_b) t1;
+    <programlisting>SELECT
+    ST_DFullyWithin(geom_a, geom_b, 10) AS DFullyWithin10,
+    ST_DWithin(geom_a, geom_b, 10) AS DWithin10,
+    ST_DFullyWithin(geom_a, geom_b, 20) AS DFullyWithin20
+FROM (VALUES
+    ('POINT(1 1)', 'LINESTRING(1 5, 2 7, 1 9, 14 12)')
+    ) AS v(geom_a, geom_b)
 
------------------
- DFullyWithin10 | DWithin10 | DFullyWithin20 |
----------------+----------+---------------+
- f             | t        | t             |  </programlisting>
+ dfullywithin10 | dwithin10 | dfullywithin20
+----------------+-----------+----------------
+ f              | t         | t
+</programlisting>
     </refsection>
 
     <refsection>
diff --git a/postgis/gserialized_supportfn.c b/postgis/gserialized_supportfn.c
index 58f65dbd9..bd4a9f56a 100644
--- a/postgis/gserialized_supportfn.c
+++ b/postgis/gserialized_supportfn.c
@@ -85,7 +85,7 @@ static const int16 GeometryStrategies[] = {
 	[ST_OVERLAPS_IDX]               = RTOverlapStrategyNumber,
 	[ST_COVERS_IDX]                 = RTContainsStrategyNumber,
 	[ST_CROSSES_IDX]                = RTOverlapStrategyNumber,
-	[ST_DFULLYWITHIN_IDX]           = RTOverlapStrategyNumber,
+	[ST_DFULLYWITHIN_IDX]           = RTContainsStrategyNumber,
 	[ST_3DDWITHIN_IDX]              = RTOverlapStrategyNumber,
 	[ST_3DDFULLYWITHIN_IDX]         = RTOverlapStrategyNumber,
 	[ST_LINECROSSINGDIRECTION_IDX]  = RTOverlapStrategyNumber,
diff --git a/postgis/lwgeom_functions_basic.c b/postgis/lwgeom_functions_basic.c
index 0be7433ca..e9e8bf96d 100644
--- a/postgis/lwgeom_functions_basic.c
+++ b/postgis/lwgeom_functions_basic.c
@@ -67,7 +67,6 @@ Datum LWGEOM_closestpoint(PG_FUNCTION_ARGS);
 Datum LWGEOM_shortestline2d(PG_FUNCTION_ARGS);
 Datum LWGEOM_longestline2d(PG_FUNCTION_ARGS);
 Datum LWGEOM_dwithin(PG_FUNCTION_ARGS);
-Datum LWGEOM_dfullywithin(PG_FUNCTION_ARGS);
 
 Datum LWGEOM_maxdistance3d(PG_FUNCTION_ARGS);
 Datum LWGEOM_mindistance3d(PG_FUNCTION_ARGS);
@@ -760,41 +759,6 @@ Datum LWGEOM_dwithin(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(tolerance >= mindist);
 }
 
-/**
-Returns boolean describing if
-maximum 2d distance between objects in
-geom1 and geom2 is shorter than tolerance
-*/
-PG_FUNCTION_INFO_V1(LWGEOM_dfullywithin);
-Datum LWGEOM_dfullywithin(PG_FUNCTION_ARGS)
-{
-	double maxdist;
-	GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
-	GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
-	double tolerance = PG_GETARG_FLOAT8(2);
-	LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
-	LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
-
-	if (tolerance < 0)
-	{
-		elog(ERROR, "Tolerance cannot be less than zero\n");
-		PG_RETURN_NULL();
-	}
-
-	gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
-
-	maxdist = lwgeom_maxdistance2d_tolerance(lwgeom1, lwgeom2, tolerance);
-
-	PG_FREE_IF_COPY(geom1, 0);
-	PG_FREE_IF_COPY(geom2, 1);
-
-	/*If function is feed with empty geometries we should return false*/
-	if (maxdist > -1)
-		PG_RETURN_BOOL(tolerance >= maxdist);
-
-	PG_RETURN_BOOL(LW_FALSE);
-}
-
 /**
  Maximum 2d distance between objects in geom1 and geom2.
  */
diff --git a/postgis/lwgeom_geos.c b/postgis/lwgeom_geos.c
index 16ae6dd3d..bd49bafca 100644
--- a/postgis/lwgeom_geos.c
+++ b/postgis/lwgeom_geos.c
@@ -3519,4 +3519,53 @@ Datum ST_OrientedEnvelope(PG_FUNCTION_ARGS)
 }
 
 
+/**
+* Returns boolean true if the second argument
+* is fully contained in a buffer of the first
+* argument.
+*/
+Datum LWGEOM_dfullywithin(PG_FUNCTION_ARGS);
+PG_FUNCTION_INFO_V1(LWGEOM_dfullywithin);
+Datum LWGEOM_dfullywithin(PG_FUNCTION_ARGS)
+{
+	GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
+	GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
+	double radius = PG_GETARG_FLOAT8(2);
+	GEOSGeometry *buffer1 = NULL;
+	GEOSGeometry *geos1 = NULL, *geos2 = NULL;
+	char contained;
 
+	if (radius < 0.0)
+	{
+		elog(ERROR, "Tolerance cannot be less than zero\n");
+		PG_RETURN_NULL();
+	}
+
+	if (gserialized_is_empty(geom1) || gserialized_is_empty(geom2))
+		PG_RETURN_BOOL(false);
+
+	initGEOS(lwpgnotice, lwgeom_geos_error);
+
+	gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
+
+	geos1 = POSTGIS2GEOS(geom1);
+	geos2 = POSTGIS2GEOS(geom2);
+	if (!(geos1 && geos2))
+		HANDLE_GEOS_ERROR("Geometry could not be converted to GEOS");
+
+	buffer1 = GEOSBuffer(geos1, radius, 16);
+	GEOSGeom_destroy(geos1);
+	if (!(buffer1))
+		HANDLE_GEOS_ERROR("Buffer operation failed");
+
+	contained = GEOSContains(buffer1, geos2);
+	GEOSGeom_destroy(buffer1);
+	GEOSGeom_destroy(geos2);
+
+	if (contained == 2) HANDLE_GEOS_ERROR("GEOSContains");
+
+	PG_FREE_IF_COPY(geom1, 0);
+	PG_FREE_IF_COPY(geom2, 1);
+
+	PG_RETURN_BOOL(contained == 1);
+}
diff --git a/raster/test/regress/rt_geos_relationships_expected b/raster/test/regress/rt_geos_relationships_expected
index 8d1a83f9d..2d1ae6b92 100644
--- a/raster/test/regress/rt_geos_relationships_expected
+++ b/raster/test/regress/rt_geos_relationships_expected
@@ -1,4 +1,4 @@
-1.1|0|0|t|f|t|t|f|f|f|t|t|t|t|t|t|f|f|f|f|t
+1.1|0|0|t|f|t|t|f|f|f|t|t|t|t|t|t|t|f|f|f|t
 1.1|0|1|f|f|f|f|f|t|f|f|t|t|t|t|t|f|f|f|f|t
 1.1|0|2|f|f|f|f|f|t|f|f|t|t|t|t|t|f|f|f|f|t
 1.1|0|3|f|f|f|f|t|f|f|f|f|f|f|f|t|f|f|f|f|f
@@ -7,8 +7,8 @@
 1.1|0|12|f|f|f|f|f|t|f|f|t|t|t|t|t|f|f|f|f|t
 1.1|0|13|f|f|f|f|f|t|f|f|t|f|f|f|f|f|f|f|f|f
 1.1|0|14|f|f|f|f|t|f|f|f|f|f|t|t|t|f|f|f|f|t
-1.1|0|15|t|t|f|t|f|f|f|f|t|t|t|t|t|f|f|f|f|t
-1.1|0|16|t|t|f|t|f|f|f|f|t|t|t|t|t|f|f|f|f|t
+1.1|0|15|t|t|f|t|f|f|f|f|t|t|t|t|t|t|f|f|f|t
+1.1|0|16|t|t|f|t|f|f|f|f|t|t|t|t|t|t|f|f|f|t
 1.1|0|20|f|f|t|f|f|f|f|t|t|t|t|t|t|f|f|f|f|t
 1.1|0|21|f|f|t|f|f|f|f|t|t|t|t|t|t|f|f|f|f|t
 1.1|0|22|f|f|t|f|f|f|f|t|t|t|t|t|t|f|f|f|f|t
diff --git a/regress/core/tickets.sql b/regress/core/tickets.sql
index be93a47cb..dd94af1b5 100644
--- a/regress/core/tickets.sql
+++ b/regress/core/tickets.sql
@@ -1527,3 +1527,13 @@ FROM
 ST_GeomFromText('MULTIPOINT((-2 0), EMPTY)') AS a1,
 ST_GeomFromText('MULTIPOINT((1 0),(0 0))') AS a2;
 
+SELECT '#5639','fullywithin' || id, ST_DFullyWithin(a, b, r)
+FROM (VALUES
+ (1, 'POLYGON((0 0, 1 0, 1 1, 1 0, 0 0))', 'POINT(1 2)', 2)
+,(2, 'POLYGON((0 0, 1 0, 1 1, 1 0, 0 0))', 'POINT(1 2)', 0.5)
+,(3, 'POLYGON((0 0, 1 0, 1 1, 1 0, 0 0))', 'LINESTRING(1.5 0.5, 2.5 0.5)', 1)
+,(4, 'POLYGON((0 0, 1 0, 1 1, 1 0, 0 0))', 'LINESTRING(1.5 0.5, 2.5 0.5)', 2)
+,(5, 'LINESTRING(0 0, 10 0)', 'LINESTRING(0 2, 10 4)', 1)
+,(6, 'LINESTRING(0 0, 10 0)', 'LINESTRING(0 2, 10 4)', 3)
+,(7, 'LINESTRING(0 0, 10 0)', 'LINESTRING(0 2, 10 4)', 4)
+) AS t(id, a, b, r);
diff --git a/regress/core/tickets_expected b/regress/core/tickets_expected
index b9f3cf854..41d2f1e91 100644
--- a/regress/core/tickets_expected
+++ b/regress/core/tickets_expected
@@ -470,3 +470,10 @@ ERROR:  Geometry contains invalid coordinates
 #5378|4269
 #5627|t
 #5604|2|POINT(0 0)|2|POINT(-2 0)
+#5639|fullywithin1|t
+#5639|fullywithin2|f
+#5639|fullywithin3|f
+#5639|fullywithin4|t
+#5639|fullywithin5|f
+#5639|fullywithin6|f
+#5639|fullywithin7|t

-----------------------------------------------------------------------

Summary of changes:
 NEWS                                               |  2 +
 doc/reference_relationship.xml                     | 33 +++++++++------
 postgis/gserialized_supportfn.c                    |  2 +-
 postgis/lwgeom_functions_basic.c                   | 36 ----------------
 postgis/lwgeom_geos.c                              | 49 ++++++++++++++++++++++
 raster/test/regress/rt_geos_relationships_expected |  6 +--
 regress/core/tickets.sql                           | 10 +++++
 regress/core/tickets_expected                      |  7 ++++
 8 files changed, 92 insertions(+), 53 deletions(-)


hooks/post-receive
-- 
PostGIS


More information about the postgis-tickets mailing list