[postgis-tickets] r14613 - #75, Enhancement to PIP short circuit

Daniel Baston dbaston at gmail.com
Thu Jan 21 15:03:31 PST 2016


Author: dbaston
Date: 2016-01-21 15:03:31 -0800 (Thu, 21 Jan 2016)
New Revision: 14613

Modified:
   trunk/postgis/lwgeom_geos.c
   trunk/regress/regress_ogc.sql
   trunk/regress/regress_ogc_expected
Log:
#75, Enhancement to PIP short circuit

Modified: trunk/postgis/lwgeom_geos.c
===================================================================
--- trunk/postgis/lwgeom_geos.c	2016-01-20 12:18:14 UTC (rev 14612)
+++ trunk/postgis/lwgeom_geos.c	2016-01-21 23:03:31 UTC (rev 14613)
@@ -119,7 +119,49 @@
 	PG_RETURN_POINTER(result);
 }
 
+static char
+is_poly(const GSERIALIZED* g)
+{
+    int type = gserialized_get_type(g);
+    return type == POLYGONTYPE || type == MULTIPOLYGONTYPE;
+}
 
+static char
+is_point(const GSERIALIZED* g)
+{
+	int type = gserialized_get_type(g);
+	return type == POINTTYPE || type == MULTIPOINTTYPE;
+}
+
+/* utility function that checks a LWPOINT and a GSERIALIZED poly against
+ * a cache.  Serialized poly may be a multipart.
+ */
+static int
+pip_short_circuit(RTREE_POLY_CACHE* poly_cache, LWPOINT* point, GSERIALIZED* gpoly)
+{
+	int result;
+
+	if ( poly_cache && poly_cache->ringIndices )
+	{
+        result = point_in_multipolygon_rtree(poly_cache->ringIndices, poly_cache->polyCount, poly_cache->ringCounts, point);
+	}
+	else
+	{
+		LWGEOM* poly = lwgeom_from_gserialized(gpoly);
+		if ( lwgeom_get_type(poly) == POLYGONTYPE )
+		{
+			result = point_in_polygon(lwgeom_as_lwpoly(poly), point);
+		}
+		else
+		{
+			result = point_in_multipolygon(lwgeom_as_lwmpoly(poly), point);
+		}
+		lwgeom_free(poly);
+	}
+
+	return result;
+}
+
 /**
  *  @brief Compute the Hausdorff distance thanks to the corresponding GEOS function
  *  @example hausdorffdistance {@link #hausdorffdistance} - SELECT st_hausdorffdistance(
@@ -1663,10 +1705,6 @@
 	GSERIALIZED *geom2;
 	GEOSGeometry *g1, *g2;
 	GBOX box1, box2;
-	int type1, type2;
-	LWGEOM *lwgeom;
-	LWPOINT *point;
-	RTREE_POLY_CACHE *poly_cache;
 	int result;
 	PrepGeomCache *prep_cache;
 
@@ -1699,48 +1737,60 @@
 	** short-circuit 2: if geom2 is a point and geom1 is a polygon
 	** call the point-in-polygon function.
 	*/
-	type1 = gserialized_get_type(geom1);
-	type2 = gserialized_get_type(geom2);
-	if ((type1 == POLYGONTYPE || type1 == MULTIPOLYGONTYPE) && type2 == POINTTYPE)
+	if (is_poly(geom1) && is_point(geom2))
 	{
+		GSERIALIZED* gpoly  = is_poly(geom1) ? geom1 : geom2;
+		GSERIALIZED* gpoint = is_point(geom1) ? geom1 : geom2;
+		RTREE_POLY_CACHE* cache = GetRtreeCache(fcinfo, gpoly);
+		int retval;
+	
 		POSTGIS_DEBUG(3, "Point in Polygon test requested...short-circuiting.");
-		lwgeom = lwgeom_from_gserialized(geom1);
-		point = lwgeom_as_lwpoint(lwgeom_from_gserialized(geom2));
+		if (gserialized_get_type(gpoint) == POINTTYPE)
+		{
+			LWGEOM* point = lwgeom_from_gserialized(gpoint);
+			int pip_result = pip_short_circuit(cache, lwgeom_as_lwpoint(point), gpoly);
+			lwgeom_free(point);
 
-		POSTGIS_DEBUGF(3, "Precall point_in_multipolygon_rtree %p, %p", lwgeom, point);
+			retval = (pip_result == 1); /* completely inside */
+		}
+		else if (gserialized_get_type(gpoint) == MULTIPOINTTYPE)
+		{
+			LWMPOINT* mpoint = lwgeom_as_lwmpoint(lwgeom_from_gserialized(gpoint));	
+			uint32_t i;
+			int found_completely_inside = LW_FALSE;
 
-		poly_cache = GetRtreeCache(fcinfo, geom1);
+			retval = LW_TRUE;
+			for (i = 0; i < mpoint->ngeoms; i++)
+			{
+				/* We need to find at least one point that's completely inside the
+				 * polygons (pip_result == 1).  As long as we have one point that's
+				 * completely inside, we can have as many as we want on the boundary
+				 * itself. (pip_result == 0)
+				 */
+				int pip_result = pip_short_circuit(cache, mpoint->geoms[i], gpoly);
+				if (pip_result == 1)
+					found_completely_inside = LW_TRUE;
 
-		if ( poly_cache && poly_cache->ringIndices )
-		{
-			result = point_in_multipolygon_rtree(poly_cache->ringIndices, poly_cache->polyCount, poly_cache->ringCounts, point);
+				if (pip_result == -1) /* completely outside */
+				{
+					retval = LW_FALSE;
+					break;
+				}
+			}
+
+			retval = retval && found_completely_inside;
+			lwmpoint_free(mpoint);
 		}
-		else if ( type1 == POLYGONTYPE )
-		{
-			result = point_in_polygon((LWPOLY*)lwgeom, point);
-		}
-		else if ( type1 == MULTIPOLYGONTYPE )
-		{
-			result = point_in_multipolygon((LWMPOLY*)lwgeom, point);
-		}
 		else
 		{
-			/* Gulp! Should not be here... */
-			elog(ERROR,"Type isn't poly or multipoly!");
+			/* Never get here */
+			elog(ERROR,"Type isn't point or multipoint!");
 			PG_RETURN_NULL();
 		}
-		lwgeom_free(lwgeom);
-		lwpoint_free(point);
+
 		PG_FREE_IF_COPY(geom1, 0);
 		PG_FREE_IF_COPY(geom2, 1);
-		if ( result == 1 ) /* completely inside */
-		{
-			PG_RETURN_BOOL(TRUE);
-		}
-		else
-		{
-			PG_RETURN_BOOL(FALSE);
-		}
+		PG_RETURN_BOOL(retval);
 	}
 	else
 	{
@@ -1888,10 +1938,6 @@
 	GSERIALIZED *geom2;
 	int result;
 	GBOX box1, box2;
-	int type1, type2;
-	LWGEOM *lwgeom;
-	LWPOINT *point;
-	RTREE_POLY_CACHE *poly_cache;
 	PrepGeomCache *prep_cache;
 
 	geom1 = PG_GETARG_GSERIALIZED_P(0);
@@ -1920,50 +1966,50 @@
 	 * short-circuit 2: if geom2 is a point and geom1 is a polygon
 	 * call the point-in-polygon function.
 	 */
-	type1 = gserialized_get_type(geom1);
-	type2 = gserialized_get_type(geom2);
-	if ((type1 == POLYGONTYPE || type1 == MULTIPOLYGONTYPE) && type2 == POINTTYPE)
+	if (is_poly(geom1) && is_point(geom2))
 	{
+		GSERIALIZED* gpoly  = is_poly(geom1) ? geom1 : geom2;
+		GSERIALIZED* gpoint = is_point(geom1) ? geom1 : geom2;
+		RTREE_POLY_CACHE* cache = GetRtreeCache(fcinfo, gpoly);
+		int retval;
+
 		POSTGIS_DEBUG(3, "Point in Polygon test requested...short-circuiting.");
+		if (gserialized_get_type(gpoint) == POINTTYPE)
+		{
+			LWGEOM* point = lwgeom_from_gserialized(gpoint);
+			int pip_result = pip_short_circuit(cache, lwgeom_as_lwpoint(point), gpoly);
+			lwgeom_free(point);
 
-		lwgeom = lwgeom_from_gserialized(geom1);
-		point = lwgeom_as_lwpoint(lwgeom_from_gserialized(geom2));
+			retval = (pip_result != -1); /* not outside */
+		}
+		else if (gserialized_get_type(gpoint) == MULTIPOINTTYPE)
+		{
+			LWMPOINT* mpoint = lwgeom_as_lwmpoint(lwgeom_from_gserialized(gpoint));
+			uint32_t i;
 
-		POSTGIS_DEBUGF(3, "Precall point_in_multipolygon_rtree %p, %p", lwgeom, point);
+			retval = LW_TRUE;
+			for (i = 0; i < mpoint->ngeoms; i++)
+			{
+				int pip_result = pip_short_circuit(cache, mpoint->geoms[i], gpoly);
+				if (pip_result == -1)
+				{
+					retval = LW_FALSE;
+					break;
+				}
+			}
 
-		poly_cache = GetRtreeCache(fcinfo, geom1);
-
-		if ( poly_cache && poly_cache->ringIndices )
-		{
-			result = point_in_multipolygon_rtree(poly_cache->ringIndices, poly_cache->polyCount, poly_cache->ringCounts, point);
+			lwmpoint_free(mpoint);
 		}
-		else if ( type1 == POLYGONTYPE )
-		{
-			result = point_in_polygon((LWPOLY*)lwgeom, point);
-		}
-		else if ( type1 == MULTIPOLYGONTYPE )
-		{
-			result = point_in_multipolygon((LWMPOLY*)lwgeom, point);
-		}
 		else
 		{
-			/* Gulp! Should not be here... */
-			elog(ERROR,"Type isn't poly or multipoly!");
+			/* Never get here */
+			elog(ERROR,"Type isn't point or multipoint!");
 			PG_RETURN_NULL();
 		}
 
-		lwgeom_free(lwgeom);
-		lwpoint_free(point);
 		PG_FREE_IF_COPY(geom1, 0);
 		PG_FREE_IF_COPY(geom2, 1);
-		if ( result != -1 ) /* not outside */
-		{
-			PG_RETURN_BOOL(TRUE);
-		}
-		else
-		{
-			PG_RETURN_BOOL(FALSE);
-		}
+		PG_RETURN_BOOL(retval);
 	}
 	else
 	{
@@ -2041,10 +2087,6 @@
 	GEOSGeometry *g1, *g2;
 	int result;
 	GBOX box1, box2;
-	LWGEOM *lwgeom;
-	LWPOINT *point;
-	int type1, type2;
-	RTREE_POLY_CACHE *poly_cache;
 	char *patt = "**F**F***";
 
 	geom1 = PG_GETARG_GSERIALIZED_P(0);
@@ -2075,49 +2117,55 @@
 	 * short-circuit 2: if geom1 is a point and geom2 is a polygon
 	 * call the point-in-polygon function.
 	 */
-	type1 = gserialized_get_type(geom1);
-	type2 = gserialized_get_type(geom2);
-	if ((type2 == POLYGONTYPE || type2 == MULTIPOLYGONTYPE) && type1 == POINTTYPE)
+	if (is_point(geom1) && is_poly(geom2))
 	{
+		GSERIALIZED* gpoly  = is_poly(geom1) ? geom1 : geom2;
+		GSERIALIZED* gpoint = is_point(geom1) ? geom1 : geom2;
+		RTREE_POLY_CACHE* cache = GetRtreeCache(fcinfo, gpoly);
+		int retval;
+
 		POSTGIS_DEBUG(3, "Point in Polygon test requested...short-circuiting.");
+		if (gserialized_get_type(gpoint) == POINTTYPE)
+		{
+			LWGEOM* point = lwgeom_from_gserialized(gpoint);
+			int pip_result = pip_short_circuit(cache, lwgeom_as_lwpoint(point), gpoly);
+			lwgeom_free(point);
 
-		point = lwgeom_as_lwpoint(lwgeom_from_gserialized(geom1));
-		lwgeom = lwgeom_from_gserialized(geom2);
+			retval = (pip_result != -1); /* not outside */
+		}
+		else if (gserialized_get_type(gpoint) == MULTIPOINTTYPE)
+		{
+			LWMPOINT* mpoint = lwgeom_as_lwmpoint(lwgeom_from_gserialized(gpoint));	
+			uint32_t i;
 
-		poly_cache = GetRtreeCache(fcinfo, geom2);
+			retval = LW_TRUE;
+			for (i = 0; i < mpoint->ngeoms; i++)
+			{
+				int pip_result = pip_short_circuit(cache, mpoint->geoms[i], gpoly);
+				if (pip_result == -1)
+				{
+					retval = LW_FALSE;
+					break;
+				}
+			}
 
-		if ( poly_cache && poly_cache->ringIndices )
-		{
-			result = point_in_multipolygon_rtree(poly_cache->ringIndices, poly_cache->polyCount, poly_cache->ringCounts, point);
+			lwmpoint_free(mpoint);
 		}
-		else if ( type2 == POLYGONTYPE )
-		{
-			result = point_in_polygon((LWPOLY*)lwgeom, point);
-		}
-		else if ( type2 == MULTIPOLYGONTYPE )
-		{
-			result = point_in_multipolygon((LWMPOLY*)lwgeom, point);
-		}
 		else
 		{
-			/* Gulp! Should not be here... */
-			elog(ERROR,"Type isn't poly or multipoly!");
+			/* Never get here */
+			elog(ERROR,"Type isn't point or multipoint!");
 			PG_RETURN_NULL();
 		}
 
-		lwgeom_free(lwgeom);
-		lwpoint_free(point);
 		PG_FREE_IF_COPY(geom1, 0);
 		PG_FREE_IF_COPY(geom2, 1);
-		if ( result != -1 ) /* not outside */
-		{
-			PG_RETURN_BOOL(TRUE);
-		}
-		else
-		{
-			PG_RETURN_BOOL(FALSE);
-		}
+		PG_RETURN_BOOL(retval);
 	}
+	else
+	{
+		POSTGIS_DEBUGF(3, "CoveredBy: type1: %d, type2: %d", type1, type2);
+	}
 
 	initGEOS(lwpgnotice, lwgeom_geos_error);
 
@@ -2223,19 +2271,13 @@
 	PG_RETURN_BOOL(result);
 }
 
-
 PG_FUNCTION_INFO_V1(geos_intersects);
 Datum geos_intersects(PG_FUNCTION_ARGS)
 {
 	GSERIALIZED *geom1;
 	GSERIALIZED *geom2;
-	GSERIALIZED *serialized_poly;
 	int result;
 	GBOX box1, box2;
-	int type1, type2, polytype;
-	LWPOINT *point;
-	LWGEOM *lwgeom;
-	RTREE_POLY_CACHE *poly_cache;
 	PrepGeomCache *prep_cache;
 
 	geom1 = PG_GETARG_GSERIALIZED_P(0);
@@ -2265,61 +2307,50 @@
 	 * short-circuit 2: if the geoms are a point and a polygon,
 	 * call the point_outside_polygon function.
 	 */
-	type1 = gserialized_get_type(geom1);
-	type2 = gserialized_get_type(geom2);
-	if ( (type1 == POINTTYPE && (type2 == POLYGONTYPE || type2 == MULTIPOLYGONTYPE)) ||
-	        (type2 == POINTTYPE && (type1 == POLYGONTYPE || type1 == MULTIPOLYGONTYPE)))
+	if ((is_point(geom1) && is_poly(geom2)) || (is_poly(geom1) && is_point(geom2)))
 	{
+		GSERIALIZED* gpoly  = is_poly(geom1) ? geom1 : geom2;
+		GSERIALIZED* gpoint = is_point(geom1) ? geom1 : geom2;
+		RTREE_POLY_CACHE* cache = GetRtreeCache(fcinfo, gpoly);
+		int retval;
+
 		POSTGIS_DEBUG(3, "Point in Polygon test requested...short-circuiting.");
+		if (gserialized_get_type(gpoint) == POINTTYPE)
+		{
+			LWGEOM* point = lwgeom_from_gserialized(gpoint);
+			int pip_result = pip_short_circuit(cache, lwgeom_as_lwpoint(point), gpoly);
+			lwgeom_free(point);
 
-		if ( type1 == POINTTYPE )
-		{
-			point = lwgeom_as_lwpoint(lwgeom_from_gserialized(geom1));
-			lwgeom = lwgeom_from_gserialized(geom2);
-			serialized_poly = geom2;
-			polytype = type2;
+			retval = (pip_result != -1); /* not outside */
 		}
-		else
+		else if (gserialized_get_type(gpoint) == MULTIPOINTTYPE)
 		{
-			point = lwgeom_as_lwpoint(lwgeom_from_gserialized(geom2));
-			lwgeom = lwgeom_from_gserialized(geom1);
-			serialized_poly = geom1;
-			polytype = type1;
-		}
+			LWMPOINT* mpoint = lwgeom_as_lwmpoint(lwgeom_from_gserialized(gpoint));	
+			uint32_t i;
 
-		poly_cache = GetRtreeCache(fcinfo, serialized_poly);
+			retval = LW_FALSE;
+			for (i = 0; i < mpoint->ngeoms; i++)
+			{
+				int pip_result = pip_short_circuit(cache, mpoint->geoms[i], gpoly);
+				if (pip_result != -1) /* not outside */
+				{
+					retval = LW_TRUE;
+					break;
+				}
+			}
 
-		if ( poly_cache && poly_cache->ringIndices )
-		{
-			result = point_in_multipolygon_rtree(poly_cache->ringIndices, poly_cache->polyCount, poly_cache->ringCounts, point);
+			lwmpoint_free(mpoint);
 		}
-		else if ( polytype == POLYGONTYPE )
-		{
-			result = point_in_polygon((LWPOLY*)lwgeom, point);
-		}
-		else if ( polytype == MULTIPOLYGONTYPE )
-		{
-			result = point_in_multipolygon((LWMPOLY*)lwgeom, point);
-		}
 		else
 		{
-			/* Gulp! Should not be here... */
-			elog(ERROR,"Type isn't poly or multipoly!");
+			/* Never get here */
+			elog(ERROR,"Type isn't point or multipoint!");
 			PG_RETURN_NULL();
 		}
 
-		lwgeom_free(lwgeom);
-		lwpoint_free(point);
 		PG_FREE_IF_COPY(geom1, 0);
 		PG_FREE_IF_COPY(geom2, 1);
-		if ( result != -1 ) /* not outside */
-		{
-			PG_RETURN_BOOL(TRUE);
-		}
-		else
-		{
-			PG_RETURN_BOOL(FALSE);
-		}
+		PG_RETURN_BOOL(retval);
 	}
 
 	initGEOS(lwpgnotice, lwgeom_geos_error);
@@ -2409,7 +2440,7 @@
 	 * geom1 bounding box we can prematurely return FALSE.
 	 */
 	if ( gserialized_get_gbox_p(geom1, &box1) &&
-	        gserialized_get_gbox_p(geom2, &box2) )
+			gserialized_get_gbox_p(geom2, &box2) )
 	{
 		if ( gbox_overlaps_2d(&box1, &box2) == LW_FALSE )
 		{

Modified: trunk/regress/regress_ogc.sql
===================================================================
--- trunk/regress/regress_ogc.sql	2016-01-20 12:18:14 UTC (rev 14612)
+++ trunk/regress/regress_ogc.sql	2016-01-21 23:03:31 UTC (rev 14613)
@@ -30,6 +30,15 @@
 SELECT 'within105', ST_within(ST_GeomFromText('POINT(521513 5377804)', 32631), ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631));
 -- PIP - repeated vertex 
 SELECT 'within106', ST_within(ST_GeomFromText('POINT(521513 5377804)', 32631), ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631));
+-- PIP - multipoint within polygon
+SELECT 'within107', ST_within('MULTIPOINT(5 5)'::geometry, 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry);
+SELECT 'within108', ST_within('MULTIPOINT(5 5, 5 7)'::geometry, 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry);
+-- PIP - multipoint on vertices of polygon
+SELECT 'within109', ST_within('MULTIPOINT(0 0, 10 10)'::geometry, 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry);
+-- PIP - multipoint partly outside of polygon
+SELECT 'within110', ST_within('MULTIPOINT(5 5, 15 7)'::geometry, 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry);
+-- PIP - multipoint not fully within polygon (but at least one point still fully within, so "within" passes)
+SELECT 'within111', ST_within('MULTIPOINT(5 5, 10 10)'::geometry, 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry);
 -- PIP - point within polygon
 SELECT 'disjoint100', ST_disjoint('POINT(5 5)'::geometry, 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry);
 -- PIP - point on polygon vertex
@@ -72,6 +81,25 @@
 SELECT 'intersects105', ST_intersects(ST_GeomFromText('POINT(521513 5377804)', 32631), ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631));
 -- PIP - repeated vertex
 SELECT 'intersects106', ST_intersects(ST_GeomFromText('POINT(521543 5377804)', 32631), ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631));
+-- PIP - multipoint on polygon vertex
+SELECT 'intersects111', ST_Intersects('MULTIPOINT ((0 0))'::geometry, 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry);
+-- PIP - multipoint outside polygon
+SELECT 'intersects112', ST_intersects('MULTIPOINT ((-1 0))'::geometry, 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry);
+-- PIP - multipoint on polygon edge
+SELECT 'intersects113', ST_intersects('MULTIPOINT ((0 5))'::geometry, 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry);
+SELECT 'intersects114', ST_intersects('MULTIPOINT ((0 5), (0 8))'::geometry, 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry);
+-- PIP - multipoint in line with polygon edge
+SELECT 'intersects115', ST_intersects('MULTIPOINT ((0 12))'::geometry, 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry);
+-- PIP - multipoint vertically aligned with polygon vertex 
+SELECT 'intersects116', ST_intersects(ST_GeomFromText('MULTIPOINT ((521513 5377804))', 32631), ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631));
+-- PIP - repeated vertex
+SELECT 'intersects117', ST_intersects(ST_GeomFromText('MULTIPOINT ((521543 5377804))', 32631), ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631));
+-- PIP - multipoint within polygon
+SELECT 'intersects118', ST_intersects('MULTIPOINT ((5 5))'::geometry, 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry);
+SELECT 'intersects119', ST_intersects('MULTIPOINT ((5 5), (7 7))'::geometry, 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry);
+-- PIP - multipoint partially within polygon
+SELECT 'intersects120', ST_intersects('MULTIPOINT ((5 5),  (15 5))'::geometry, 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry);
+SELECT 'intersects121', ST_intersects('MULTIPOINT ((15 5), (5 5))'::geometry, 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry);
 -- PIP - point within polygon
 SELECT 'intersects150', ST_intersects('POINT(5 5)'::geometry, 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry);
 -- PIP - point on polygon vertex
@@ -100,11 +128,29 @@
 SELECT 'contains105', ST_contains(ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631), ST_GeomFromText('POINT(521513 5377804)', 32631));
 -- PIP - repeated vertex 
 SELECT 'contains106', ST_contains(ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631), ST_GeomFromText('POINT(521513 5377804)', 32631));
+-- PIP - multipoint within polygon
+SELECT 'contains110', ST_contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry, 'MULTIPOINT ((5 5))'::geometry);
+-- PIP - multipoint on vertex of polygon
+SELECT 'contains111', ST_contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry, 'MULTIPOINT ((0 0))'::geometry);
+SELECT 'contains112', ST_contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry, 'MULTIPOINT ((0 0), (10 0))'::geometry);
+-- PIP - multipoint outside polygon
+SELECT 'contains113', ST_contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry, 'MULTIPOINT ((-1 0))'::geometry);
+-- PIP - multipoint partially outside polygon
+SELECT 'contains114', ST_contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry, 'MULTIPOINT ((-1 0), (5 5))'::geometry);
+SELECT 'contains115', ST_contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry, 'MULTIPOINT ((5 5), (-1 0))'::geometry);
+-- PIP - point on edge of polygon
+SELECT 'contains116', ST_contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry, 'MULTIPOINT ((0 5))'::geometry);
+-- PIP - point in line with polygon edge
+SELECT 'contains117', ST_contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry, 'MULTIPOINT ((0 12))'::geometry);
+-- PIP - multipoint within polygon
+SELECT 'contains118', ST_contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry, 'MULTIPOINT ((5 5), (7 7))'::geometry);
+-- PIP - point on edge of polygon and within
+SELECT 'contains119', ST_contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry, 'MULTIPOINT ((0 5), (5 5))'::geometry);
 -- moved here from regress.sql
 select 'within119', ST_within('LINESTRING(-1 -1, -1 101, 101 101, 101 -1)'::GEOMETRY,'BOX3D(0 0, 100 100)'::BOX3D);
 select 'within120', ST_within('LINESTRING(-1 -1, -1 100, 101 100, 101 -1)'::GEOMETRY,'BOX3D(0 0, 100 100)'::BOX3D);
-SELECT 'contains110', ST_Contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry, 'LINESTRING(1 10, 9 10, 9 8)'::geometry);
-SELECT 'contains111', ST_Contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry, 'LINESTRING(1 10, 10 10, 10 8)'::geometry);
+SELECT 'contains120', ST_Contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry, 'LINESTRING(1 10, 9 10, 9 8)'::geometry);
+SELECT 'contains121', ST_Contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry, 'LINESTRING(1 10, 10 10, 10 8)'::geometry);
 SELECT 'within130', ST_Within('LINESTRING(1 10, 9 10, 9 8)'::geometry, 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry);
 SELECT 'within131', ST_Within('LINESTRING(1 10, 10 10, 10 8)'::geometry, 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry);
 SELECT 'overlaps', ST_overlaps('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry,'POINT(5 5)'::geometry);

Modified: trunk/regress/regress_ogc_expected
===================================================================
--- trunk/regress/regress_ogc_expected	2016-01-20 12:18:14 UTC (rev 14612)
+++ trunk/regress/regress_ogc_expected	2016-01-21 23:03:31 UTC (rev 14613)
@@ -16,6 +16,11 @@
 within104|f
 within105|t
 within106|t
+within107|t
+within108|t
+within109|f
+within110|f
+within111|t
 disjoint100|f
 disjoint101|f
 disjoint102|t
@@ -37,6 +42,17 @@
 intersects104|f
 intersects105|t
 intersects106|f
+intersects111|t
+intersects112|f
+intersects113|t
+intersects114|t
+intersects115|f
+intersects116|t
+intersects117|f
+intersects118|t
+intersects119|t
+intersects120|t
+intersects121|t
 intersects150|t
 intersects151|t
 intersects152|f
@@ -51,10 +67,20 @@
 contains104|f
 contains105|t
 contains106|t
+contains110|t
+contains111|f
+contains112|f
+contains113|f
+contains114|f
+contains115|f
+contains116|f
+contains117|f
+contains118|t
+contains119|t
 within119|f
 within120|f
-contains110|t
-contains111|f
+contains120|t
+contains121|f
 within130|t
 within131|f
 overlaps|f



More information about the postgis-tickets mailing list