[postgis-commits] svn - r2730 - trunk/lwgeom

postgis-commits at postgis.refractions.net postgis-commits at postgis.refractions.net
Thu Jan 17 17:04:20 PST 2008


Author: benjubb
Date: 2008-01-17 17:04:18 -0800 (Thu, 17 Jan 2008)
New Revision: 2730

Modified:
   trunk/lwgeom/lwgeom_geos_c.c
Log:
Added new functions to lwgeom_geos_c.c to support prepared geometry predicates. 
bool containsPrepared( geom, geom)
bool containsProperlyPrepared( geom, geom)
bool coversPrepared( geom, geom)
bool intersectsPrepared( geom, geom)



Modified: trunk/lwgeom/lwgeom_geos_c.c
===================================================================
--- trunk/lwgeom/lwgeom_geos_c.c	2008-01-18 00:59:13 UTC (rev 2729)
+++ trunk/lwgeom/lwgeom_geos_c.c	2008-01-18 01:04:18 UTC (rev 2730)
@@ -3,6 +3,7 @@
 #include "utils/builtins.h"
 #include "fmgr.h"
 
+
 #include "lwgeom_pg.h"
 #include "liblwgeom.h"
 #include "profile.h"
@@ -10,6 +11,13 @@
 #include "geos_c.h"
 #include "lwgeom_rtree.h"
 
+#include <string.h>
+
+
+#ifdef PROFILE
+#warning PROFILE enabled!
+#endif
+
 /*
  * Define this to have have many notices printed
  * during postgis->geos and geos->postgis conversions
@@ -1347,6 +1355,7 @@
 int point_outside_polygon_deprecated(LWPOLY *polygon, LWPOINT *point);
 int point_in_multipolygon(LWMPOLY *mpolygon, LWPOINT *point);
 
+
 PG_FUNCTION_INFO_V1(contains);
 Datum contains(PG_FUNCTION_ARGS)
 {
@@ -1499,7 +1508,7 @@
 
 #ifdef PROFILE
 	profstop(PROF_QRUN);
-	profreport("geos",geom1, geom2, NULL);
+	profreport("cont",geom1, geom2, NULL);
 #endif
 
 	PG_FREE_IF_COPY(geom1, 0);
@@ -1508,6 +1517,7 @@
 	PG_RETURN_BOOL(result);
 }
 
+
 /*
  * Described at 
  * http://lin-ear-th-inking.blogspot.com/2007/06/subtleties-of-ogc-covers-spatial.html
@@ -3575,3 +3585,413 @@
 	PG_RETURN_POINTER(result);
 
 }
+
+
+//#define NO_PREPARED_GEOM
+#ifndef NO_PREPARED_GEOM
+
+Datum containsPrepared(PG_FUNCTION_ARGS);
+Datum containsProperlyPrepared(PG_FUNCTION_ARGS);
+Datum coversPrepared(PG_FUNCTION_ARGS);
+Datum intersectsPrepared(PG_FUNCTION_ARGS);
+
+typedef struct
+{
+	Size 					serialized_geom_length;
+	uchar * 				serialized_geom;
+	GEOSPreparedGeometry * 	prepared_geom;
+} PREPARED_GEOM_CACHE;
+
+/*
+char
+compare_bytes( uchar *obj1, uchar *obj2, Size len)
+{
+	Size i = 0;
+	
+	while ( i < len ) 
+		if ( obj1[ i ] != obj2[ i ] )
+			return 0;
+		else
+			i++;
+			
+	return 1;
+}
+*/
+
+/* 
+ * get cached prepared geometry for geom1
+ * only geom1 is potentially prepared as only
+ * the first arg of the prepared predicates CAN be prepared
+ * briefly, the following does:
+ *
+ * get cache
+ * if cache not exist
+ *   create cache 
+ *   arg1 into cache
+ *   return test( geom1, geom2)
+ *
+ * else if geom1 matches cached geom1
+ *    if cached prepared not exist
+ *        geom1 prepared into cache
+ *    
+ *    prepare geom1get prepared 
+ *
+ * else
+ *   geom1 into cache geom1
+ */
+PREPARED_GEOM_CACHE *
+get_prepared_geometry_cache( 
+	PREPARED_GEOM_CACHE * 	cache, 
+	uchar * 				serialized_geom, 
+	Size 					serialized_geom_length)
+	//GEOSGeom 				geom)
+{
+	GEOSGeom g;
+
+	if ( !cache || !cache->serialized_geom )
+	{
+		//lwnotice("get_prepared_geometry_cache: creating cache: %x", cache);
+
+		cache = lwalloc( sizeof( PREPARED_GEOM_CACHE ));
+		
+		cache->prepared_geom = 0;
+		cache->serialized_geom_length = serialized_geom_length;
+		cache->serialized_geom = lwalloc(serialized_geom_length);
+        memcpy( cache->serialized_geom, serialized_geom, serialized_geom_length); 
+	}
+	else if ( serialized_geom_length == cache->serialized_geom_length 
+		&& 0 == memcmp( cache->serialized_geom, serialized_geom, cache->serialized_geom_length ))
+	{
+		if ( !cache->prepared_geom )
+		{
+			//lwnotice("get_prepared_geometry_cache: preparing obj");
+			g = POSTGIS2GEOS( serialized_geom);
+			cache->prepared_geom = GEOSPrepare( g);
+		}
+		else
+		{
+			//lwnotice("get_prepared_geometry_cache: prepared obj in cache");
+		}
+	}
+	else
+	{
+		//lwnotice("get_prepared_geometry_cache: obj NOT in cache");
+
+		lwfree( cache->serialized_geom);
+		cache->serialized_geom = 0;
+		
+		GEOSPreparedGeom_destroy( cache->prepared_geom);
+		cache->prepared_geom = 0;
+
+		cache->serialized_geom_length = serialized_geom_length;
+		cache->serialized_geom = lwalloc(serialized_geom_length);
+        memcpy( cache->serialized_geom, serialized_geom, serialized_geom_length); 
+	}
+	
+	return cache;
+}
+
+
+PG_FUNCTION_INFO_V1(containsPrepared);
+Datum containsPrepared(PG_FUNCTION_ARGS)
+{
+    Size 					arg1_length;
+	PG_LWGEOM *				geom1;
+	PG_LWGEOM *				geom2;
+	GEOSGeom 				g1, g2;
+	GEOSPreparedGeometry * 	pg;
+	bool 					result;
+	BOX2DFLOAT4 			box1, box2;
+	PREPARED_GEOM_CACHE *	prep_cache;
+	MemoryContext 			old_context;
+
+	//(varattrib *) datum
+	//(struct varlena *) DatumGetPointer(datum)
+    arg1_length = toast_raw_datum_size(PG_GETARG_DATUM(0)) - VARHDRSZ;
+
+	geom1 = (PG_LWGEOM *)  PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+	geom2 = (PG_LWGEOM *)  PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
+
+	errorIfGeometryCollection(geom1,geom2);
+	errorIfSRIDMismatch(pglwgeom_getSRID(geom1), pglwgeom_getSRID(geom2));
+
+	/*
+	 * short-circuit: if geom2 bounding box is not completely inside
+	 * geom1 bounding box we can prematurely return FALSE.
+	 * Do the test IFF BOUNDING BOX AVAILABLE.
+	 */
+	if ( getbox2d_p(SERIALIZED_FORM(geom1), &box1) &&
+		getbox2d_p(SERIALIZED_FORM(geom2), &box2) )
+	{
+		if ( box2.xmin < box1.xmin ) PG_RETURN_BOOL(FALSE);
+		if ( box2.xmax > box1.xmax ) PG_RETURN_BOOL(FALSE);
+		if ( box2.ymin < box1.ymin ) PG_RETURN_BOOL(FALSE);
+		if ( box2.ymax > box1.ymax ) PG_RETURN_BOOL(FALSE);
+	}
+	
+	old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
+	prep_cache =  fcinfo->flinfo->fn_extra;
+	//lwnotice("prep_cache before: %x", prep_cache);
+	prep_cache = get_prepared_geometry_cache( prep_cache, geom1, arg1_length);
+	//lwnotice("prep_cache after: %x", prep_cache);
+	fcinfo->flinfo->fn_extra = prep_cache;
+	MemoryContextSwitchTo(old_context);
+
+	g2 = POSTGIS2GEOS(geom2);
+
+	if ( !prep_cache || !prep_cache->prepared_geom )
+	{
+		g1 = POSTGIS2GEOS(geom1);
+		//lwnotice("invoking GEOSContains");
+		result = GEOSContains( g1, g2);
+		
+		GEOSGeom_destroy(g1);
+	}
+	else
+	{
+		pg = prep_cache->prepared_geom;
+
+		//lwnotice("invoking GEOSPreparedContains");
+		result = GEOSPreparedContains( pg, g2);	
+	}
+	GEOSGeom_destroy(g2);
+
+	if (result == 2)
+	{
+		elog(ERROR,"GEOS contains() threw an error!");
+		PG_RETURN_NULL(); /* never get here */
+	}
+
+	PG_FREE_IF_COPY(geom1, 0);
+	PG_FREE_IF_COPY(geom2, 1);
+
+	PG_RETURN_BOOL(result);
+}
+
+PG_FUNCTION_INFO_V1(containsProperlyPrepared);
+Datum containsProperlyPrepared(PG_FUNCTION_ARGS)
+{
+    Size 					arg1_length;
+	PG_LWGEOM *				geom1;
+	PG_LWGEOM *				geom2;
+	GEOSGeom 				g1, g2;
+	GEOSPreparedGeometry * 	pg;
+	bool 					result;
+	BOX2DFLOAT4 			box1, box2;
+	PREPARED_GEOM_CACHE *	prep_cache;
+	MemoryContext 			old_context;
+
+	//(varattrib *) datum
+	//(struct varlena *) DatumGetPointer(datum)
+    arg1_length = toast_raw_datum_size(PG_GETARG_DATUM(0)) - VARHDRSZ;
+
+	geom1 = (PG_LWGEOM *)  PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+	geom2 = (PG_LWGEOM *)  PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
+
+	errorIfGeometryCollection(geom1,geom2);
+	errorIfSRIDMismatch(pglwgeom_getSRID(geom1), pglwgeom_getSRID(geom2));
+
+	/*
+	 * short-circuit: if geom2 bounding box is not completely inside
+	 * geom1 bounding box we can prematurely return FALSE.
+	 * Do the test IFF BOUNDING BOX AVAILABLE.
+	 */
+	if ( getbox2d_p(SERIALIZED_FORM(geom1), &box1) &&
+		getbox2d_p(SERIALIZED_FORM(geom2), &box2) )
+	{
+		if ( box2.xmin < box1.xmin ) PG_RETURN_BOOL(FALSE);
+		if ( box2.xmax > box1.xmax ) PG_RETURN_BOOL(FALSE);
+		if ( box2.ymin < box1.ymin ) PG_RETURN_BOOL(FALSE);
+		if ( box2.ymax > box1.ymax ) PG_RETURN_BOOL(FALSE);
+	}
+	
+	old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
+	prep_cache =  fcinfo->flinfo->fn_extra;
+	//lwnotice("prep_cache before: %x", prep_cache);
+	prep_cache = get_prepared_geometry_cache( prep_cache, geom1, arg1_length);
+	//lwnotice("prep_cache after: %x", prep_cache);
+	fcinfo->flinfo->fn_extra = prep_cache;
+	MemoryContextSwitchTo(old_context);
+
+	g2 = POSTGIS2GEOS(geom2);
+
+	if ( !prep_cache || !prep_cache->prepared_geom )
+	{
+		g1 = POSTGIS2GEOS(geom1);
+		
+		result = GEOSRelatePattern( g1, g2, "T**FF*FF*");
+		
+		GEOSGeom_destroy(g1);
+	}
+	else
+	{
+		pg = prep_cache->prepared_geom;
+
+		result = GEOSPreparedContainsProperly( pg, g2);	
+	}
+	GEOSGeom_destroy(g2);
+
+	if (result == 2)
+	{
+		elog(ERROR,"GEOS contains() threw an error!");
+		PG_RETURN_NULL(); /* never get here */
+	}
+
+	PG_FREE_IF_COPY(geom1, 0);
+	PG_FREE_IF_COPY(geom2, 1);
+
+	PG_RETURN_BOOL(result);
+}
+
+PG_FUNCTION_INFO_V1(coversPrepared);
+Datum coversPrepared(PG_FUNCTION_ARGS)
+{
+    Size 					arg1_length;
+	PG_LWGEOM *				geom1;
+	PG_LWGEOM *				geom2;
+	GEOSGeom 				g1, g2;
+	GEOSPreparedGeometry * 	pg;
+	bool 					result;
+	BOX2DFLOAT4 			box1, box2;
+	PREPARED_GEOM_CACHE *	prep_cache;
+	MemoryContext 			old_context;
+
+	//(varattrib *) datum
+	//(struct varlena *) DatumGetPointer(datum)
+    arg1_length = toast_raw_datum_size(PG_GETARG_DATUM(0)) - VARHDRSZ;
+
+	geom1 = (PG_LWGEOM *)  PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+	geom2 = (PG_LWGEOM *)  PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
+
+	errorIfGeometryCollection(geom1,geom2);
+	errorIfSRIDMismatch(pglwgeom_getSRID(geom1), pglwgeom_getSRID(geom2));
+
+	/*
+	 * short-circuit: if geom2 bounding box is not completely inside
+	 * geom1 bounding box we can prematurely return FALSE.
+	 * Do the test IFF BOUNDING BOX AVAILABLE.
+	 */
+	if ( getbox2d_p(SERIALIZED_FORM(geom1), &box1) &&
+		getbox2d_p(SERIALIZED_FORM(geom2), &box2) )
+	{
+		if ( box2.xmin < box1.xmin ) PG_RETURN_BOOL(FALSE);
+		if ( box2.xmax > box1.xmax ) PG_RETURN_BOOL(FALSE);
+		if ( box2.ymin < box1.ymin ) PG_RETURN_BOOL(FALSE);
+		if ( box2.ymax > box1.ymax ) PG_RETURN_BOOL(FALSE);
+	}
+	
+	old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
+	prep_cache =  fcinfo->flinfo->fn_extra;
+	//lwnotice("prep_cache before: %x", prep_cache);
+	prep_cache = get_prepared_geometry_cache( prep_cache, geom1, arg1_length);
+	//lwnotice("prep_cache after: %x", prep_cache);
+	fcinfo->flinfo->fn_extra = prep_cache;
+	MemoryContextSwitchTo(old_context);
+
+	g2 = POSTGIS2GEOS(geom2);
+
+	if ( !prep_cache || !prep_cache->prepared_geom )
+	{
+		g1 = POSTGIS2GEOS(geom1);
+
+		result = GEOSRelatePattern( g1, g2, "******FF*");
+		
+		GEOSGeom_destroy(g1);
+	}
+	else
+	{
+		pg = prep_cache->prepared_geom;
+
+		//lwnotice("invoking GEOSPreparedContains");
+		result = GEOSPreparedCovers( pg, g2);	
+	}
+	GEOSGeom_destroy(g2);
+
+	if (result == 2)
+	{
+		elog(ERROR,"GEOS contains() threw an error!");
+		PG_RETURN_NULL(); /* never get here */
+	}
+
+	PG_FREE_IF_COPY(geom1, 0);
+	PG_FREE_IF_COPY(geom2, 1);
+
+	PG_RETURN_BOOL(result);
+}
+
+PG_FUNCTION_INFO_V1(intersectsPrepared);
+Datum intersectsPrepared(PG_FUNCTION_ARGS)
+{
+    Size 					arg1_length;
+	PG_LWGEOM *				geom1;
+	PG_LWGEOM *				geom2;
+	GEOSGeom 				g1, g2;
+	GEOSPreparedGeometry * 	pg;
+	bool 					result;
+	BOX2DFLOAT4 			box1, box2;
+	PREPARED_GEOM_CACHE *	prep_cache;
+	MemoryContext 			old_context;
+
+	//(varattrib *) datum
+	//(struct varlena *) DatumGetPointer(datum)
+    arg1_length = toast_raw_datum_size(PG_GETARG_DATUM(0)) - VARHDRSZ;
+
+	geom1 = (PG_LWGEOM *)  PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+	geom2 = (PG_LWGEOM *)  PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
+
+	errorIfGeometryCollection(geom1,geom2);
+	errorIfSRIDMismatch(pglwgeom_getSRID(geom1), pglwgeom_getSRID(geom2));
+
+	/*
+	 * short-circuit 1: if geom2 bounding box does not overlap
+	 * geom1 bounding box we can prematurely return FALSE.
+	 * Do the test IFF BOUNDING BOX AVAILABLE.
+	 */
+	if ( getbox2d_p(SERIALIZED_FORM(geom1), &box1) &&
+		getbox2d_p(SERIALIZED_FORM(geom2), &box2) )
+	{
+		if ( box2.xmax < box1.xmin ) PG_RETURN_BOOL(FALSE);
+		if ( box2.xmin > box1.xmax ) PG_RETURN_BOOL(FALSE);
+		if ( box2.ymax < box1.ymin ) PG_RETURN_BOOL(FALSE);
+		if ( box2.ymin > box2.ymax ) PG_RETURN_BOOL(FALSE);
+	}
+	
+	old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
+	prep_cache =  fcinfo->flinfo->fn_extra;
+	//lwnotice("prep_cache before: %x", prep_cache);
+	prep_cache = get_prepared_geometry_cache( prep_cache, geom1, arg1_length);
+	//lwnotice("prep_cache after: %x", prep_cache);
+	fcinfo->flinfo->fn_extra = prep_cache;
+	MemoryContextSwitchTo(old_context);
+
+	g2 = POSTGIS2GEOS(geom2);
+
+	if ( !prep_cache || !prep_cache->prepared_geom )
+	{
+		g1 = POSTGIS2GEOS(geom1);
+
+		result = GEOSIntersects( g1, g2);
+		
+		GEOSGeom_destroy(g1);
+	}
+	else
+	{
+		pg = prep_cache->prepared_geom;
+
+		result = GEOSPreparedIntersects( pg, g2);	
+	}
+	GEOSGeom_destroy(g2);
+
+	if (result == 2)
+	{
+		elog(ERROR,"GEOS contains() threw an error!");
+		PG_RETURN_NULL(); /* never get here */
+	}
+
+	PG_FREE_IF_COPY(geom1, 0);
+	PG_FREE_IF_COPY(geom2, 1);
+
+	PG_RETURN_BOOL(result);
+}
+
+#endif



More information about the postgis-commits mailing list