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

postgis-commits at postgis.refractions.net postgis-commits at postgis.refractions.net
Thu Aug 2 12:58:47 PDT 2007


Author: mleslie
Date: 2007-08-02 12:58:46 -0700 (Thu, 02 Aug 2007)
New Revision: 2678

Modified:
   trunk/lwgeom/lwgeom_jts.c
   trunk/lwgeom/lwgeom_jts_wrapper.cpp
Log:
Added PreparedGeometry and caching support to the intersects function in the jts connector.  Created wrapper functions for the PreparedGeometry functionality.

Modified: trunk/lwgeom/lwgeom_jts.c
===================================================================
--- trunk/lwgeom/lwgeom_jts.c	2007-08-02 19:57:38 UTC (rev 2677)
+++ trunk/lwgeom/lwgeom_jts.c	2007-08-02 19:58:46 UTC (rev 2678)
@@ -14,6 +14,7 @@
 Datum disjoint(PG_FUNCTION_ARGS);
 Datum touches(PG_FUNCTION_ARGS);
 Datum intersects(PG_FUNCTION_ARGS);
+Datum intersects_old(PG_FUNCTION_ARGS);
 Datum crosses(PG_FUNCTION_ARGS);
 Datum within(PG_FUNCTION_ARGS);
 Datum contains(PG_FUNCTION_ARGS);
@@ -55,11 +56,12 @@
  * If you're having problems with JTS<->POSTGIS conversions
  * you can define these to use WKT
  */
-#define WKT_J2P 0
-#define WKT_P2J 0
+#define WKT_J2P 1
+#define WKT_P2J 1
 
 typedef void (*noticefunc)(const char *fmt, ...);
-typedef  struct JTSGeometry JTSGeometry;
+typedef struct JTSGeometry JTSGeometry;
+typedef struct JTSPrepGeometry JTSPrepGeometry;
 
 extern const char * createJTSPoint(POINT3D *pt);
 extern void initJTS(noticefunc);
@@ -127,8 +129,21 @@
 LWPOLY *lwpoly_from_geometry(JTSGeometry *g, char want3d);
 LWCOLLECTION *lwcollection_from_geometry(JTSGeometry *geom, char want3d);
 LWGEOM *JTS2LWGEOM(JTSGeometry *g, char want3d);
+void JTSPrintPreparedGeometry(JTSGeometry *pg);
+JTSPrepGeometry *JTSGetRHSCache();
+JTSPrepGeometry *JTSGetLHSCache();
+void JTSPutRHSCache(JTSPrepGeometry *rhs);
+void JTSPutLHSCache(JTSPrepGeometry *lhs);
 
+typedef struct
+{
+        uchar *serializedGeomA;
+        uchar *serializedGeomB;
+} PREPARED_GEOMETRY_CACHE;
 
+char JTSpreparedIntersects(JTSPrepGeometry *pg, JTSGeometry *g);
+JTSPrepGeometry *JTSPrepareGeometry(JTSGeometry *g);
+
 /*
  * Using BUFFER(0) version of unite_garray takes
  * processing to a segfault (after spending a lot of time!)
@@ -1426,13 +1441,7 @@
 		if ( box2.ymin < box1.ymin ) PG_RETURN_BOOL(FALSE);
 		if ( box2.ymax > box1.ymax ) PG_RETURN_BOOL(FALSE);
 	}
-        else 
-        {
-#ifdef PGIS_DEBUG
-                lwnotice("Covers: type1: %d, type2: %d", type1, type2);
-#endif
-        }
-        
+
 	initJTS(lwnotice);
 
 #ifdef PROFILE
@@ -1716,14 +1725,232 @@
 	PG_RETURN_BOOL(result);
 }
 
-
-
+/*
+ * TODO: PREPARED INTERSECTS
+#define DISABLE_CACHE 1
+ */
 PG_FUNCTION_INFO_V1(intersects);
 Datum intersects(PG_FUNCTION_ARGS)
 {
+        PG_LWGEOM *geom1;
+        PG_LWGEOM *geom2;
+        bool result;
+        BOX2DFLOAT4 box1, box2;
+        MemoryContext oldContext;
+        PREPARED_GEOMETRY_CACHE *cache = NULL;
+        JTSPrepGeometry *preparedGeom = NULL;
+        JTSGeometry *jtsGeom = NULL;
+        int i, length;
+        uchar *serialized;
+
+#ifdef PGIS_DEBUG_CALLS
+        lwnotice("intersects (prepared jts geometry) called");
+#endif 
+
+        geom1 = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+        geom2 = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
+
+        errorIfJTSGeometryCollection(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 > box1.ymax) PG_RETURN_BOOL(FALSE);
+        }
+
+	initJTS(lwnotice);
+
+        /*
+         * Any memory allocation that must survive beyond this function call
+         * must be made in the function context.  The terminology is a touch 
+         * confusing.  The function context will persist across all calls to 
+         * this function within the currently running query.
+         */
+        oldContext = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
+        /*
+         * Find the cache.  If there is none, create it.
+         */
+
+#ifndef DISABLE_CACHE
+        cache = fcinfo->flinfo->fn_extra;
+#endif
+
+#ifdef PGIS_DEBUG
+        lwnotice("intersects: cache retrieved %p", cache);
+#endif
+        if(!cache)
+        {
+#ifdef PGIS_DEBUG
+                lwnotice("intersects: no cache found.  Creating one.");
+#endif
+                cache = lwalloc(sizeof(PREPARED_GEOMETRY_CACHE));
+                preparedGeom = JTSPrepareGeometry(POSTGIS2JTS(geom1));
+                
+                JTSPutLHSCache(preparedGeom);
+                length = lwgeom_size(SERIALIZED_FORM(geom1));
+                cache->serializedGeomA = lwalloc(length);
+                memcpy(cache->serializedGeomA, SERIALIZED_FORM(geom1), length);
+                jtsGeom = POSTGIS2JTS(geom2);
+                JTSPutRHSCache(JTSPrepareGeometry(jtsGeom));
+                length = lwgeom_size(SERIALIZED_FORM(geom2));
+                cache->serializedGeomB = lwalloc(length);
+                memcpy(cache->serializedGeomB, SERIALIZED_FORM(geom2), length);
+                fcinfo->flinfo->fn_extra = cache;
+#ifdef PGIS_DEBUG
+                lwnotice("Cache created containing geoms:");
+#endif
+        }
+        /*
+         * There is a cache.  We must determine which geometry, if either,
+         * is found in the cache.
+         */
+        else
+        {
+#ifdef PGIS_DEBUG
+                lwnotice("intersects: checking cache");
+#endif
+                serialized = SERIALIZED_FORM(geom1);
+                length = lwgeom_size(serialized);
+                if(lwgeom_size(cache->serializedGeomA) == length)
+                {
+                        for(i = 0; i < length; i++)
+                        {
+                                uchar a = serialized[i];
+                                uchar b = cache->serializedGeomA[i];
+                                if(a != b)
+                                        break;
+                        }
+                        if(i >= length)
+                        {
+#ifdef PGIS_DEBUG
+                                lwnotice("intersects: LHS geom found in cache.");
+#endif
+                                preparedGeom = JTSGetLHSCache();
+                                jtsGeom = POSTGIS2JTS(geom2);
+#ifdef PGIS_DEBUG
+                                lwnotice("Cache hit, geom:");
+                                lwnotice("preparedGeom %p, jtsGeom %p",
+                                        preparedGeom, jtsGeom);
+#endif
+                        }
+                }
+                
+                serialized = SERIALIZED_FORM(geom2);
+                length = lwgeom_size(serialized);
+                if(!preparedGeom && lwgeom_size(cache->serializedGeomB) == length)
+                {
+                        for(i = 0; i < length; i++)
+                        {
+                                uchar a = serialized[i];
+                                uchar b = cache->serializedGeomB[i];
+                                if(a != b)
+                                        break;
+                        }
+                        if(i >= length)
+                        {
+#ifdef PGIS_DEBUG
+                                lwnotice("intersects: RHS geom found in cache.");
+#endif
+                                preparedGeom = JTSGetRHSCache();
+                                jtsGeom = POSTGIS2JTS(geom1);
+#ifdef PGIS_DEBUG
+                                lwnotice("Cache hit, geom:");
+                                lwnotice("preparedGeom %p, jtsGeom %p",
+                                        preparedGeom, jtsGeom);
+#endif
+                        }
+                }
+
+                if(!preparedGeom)
+                {
+#ifdef PGIS_DEBUG
+                        lwnotice("intersects: cache miss.");
+#endif
+                        if(cache->serializedGeomA)
+                                lwfree(cache->serializedGeomA);
+                        preparedGeom = JTSPrepareGeometry(POSTGIS2JTS(geom1));
+                        JTSPutLHSCache(preparedGeom);
+                        length = lwgeom_size(SERIALIZED_FORM(geom1));
+                        cache->serializedGeomA = lwalloc(length);
+                        memcpy(cache->serializedGeomA, 
+                                SERIALIZED_FORM(geom1), length);
+
+                        if(cache->serializedGeomB)
+                                lwfree(cache->serializedGeomB);
+                        jtsGeom = POSTGIS2JTS(geom2);
+                        JTSPutRHSCache(JTSPrepareGeometry(jtsGeom));
+                        length = lwgeom_size(SERIALIZED_FORM(geom2));
+                        cache->serializedGeomB = lwalloc(length);
+                        memcpy(cache->serializedGeomB, 
+                                SERIALIZED_FORM(geom2), length);
+                }
+        }
+        MemoryContextSwitchTo(oldContext);
+#ifdef PGIS_DEBUG
+        lwnotice("intersects: prepared-%p, geom-%p", preparedGeom, jtsGeom);
+        JTSPrintPreparedGeometry(preparedGeom);
+#endif
+
+        if(!preparedGeom || !jtsGeom)
+        {
+
+                lwnotice("intersects error: Unable to prepare geometery (%p, %p)", preparedGeom, jtsGeom);
+	        result = JTSrelateIntersects(POSTGIS2JTS(geom1), 
+                        POSTGIS2JTS(geom2));
+                if (result == 2)
+                {
+                        lwerror("JTS intersects() threw an error!");
+                        PG_FREE_IF_COPY(geom1, 0);
+                        PG_FREE_IF_COPY(geom2, 1);
+                        PG_RETURN_NULL();
+                }
+                
+        }
+        else
+        {
+
+                result = JTSpreparedIntersects(preparedGeom, jtsGeom);
+
+                /*
+	        finishJTS();
+                */
+	        if (result == 2)
+	        {
+		        lwerror("JTS intersects() threw an error!");
+	                PG_FREE_IF_COPY(geom1, 0);
+	                PG_FREE_IF_COPY(geom2, 1);
+		        PG_RETURN_NULL(); //never get here
+	        }
+        }
+
+	PG_FREE_IF_COPY(geom1, 0);
+	PG_FREE_IF_COPY(geom2, 1);
+
+#ifdef PGIS_DEBUG_CALLS
+        lwnotice("intersects() returning.");
+#endif
+
+	PG_RETURN_BOOL(result);
+}
+
+
+
+PG_FUNCTION_INFO_V1(intersects_old);
+Datum intersects_old(PG_FUNCTION_ARGS)
+{
 	PG_LWGEOM *geom1;
 	PG_LWGEOM *geom2;
-	JTSGeometry *g1,*g2;
+        JTSGeometry *g1;
+        JTSGeometry *g2;
 	bool result;
 	BOX2DFLOAT4 box1, box2;
 

Modified: trunk/lwgeom/lwgeom_jts_wrapper.cpp
===================================================================
--- trunk/lwgeom/lwgeom_jts_wrapper.cpp	2007-08-02 19:57:38 UTC (rev 2677)
+++ trunk/lwgeom/lwgeom_jts_wrapper.cpp	2007-08-02 19:58:46 UTC (rev 2678)
@@ -14,6 +14,7 @@
 
 //#define DEBUG_JARRAY 1
 
+using namespace com::vividsolutions::jts::geom::prep;
 using namespace com::vividsolutions::jts::geom;
 using namespace com::vividsolutions::jts::io;
 using namespace com::vividsolutions::jts;
@@ -112,6 +113,15 @@
 extern "C" char *JTSjtsport();
 extern "C" int JTSGeometryTypeId(Geometry *g1);
 
+extern "C" char JTSpreparedIntersects(PreparedGeometry *pg, Geometry* g);
+extern "C" PreparedGeometry *JTSPrepareGeometry(Geometry* g);
+extern "C" void JTSgc(void);
+extern "C" void JTSPrintPreparedGeometry(PreparedGeometry *pg);
+extern "C" PreparedGeometry *JTSGetRHSCache();
+extern "C" PreparedGeometry *JTSGetLHSCache();
+extern "C" void JTSPutRHSCache(PreparedGeometry *rhs);
+extern "C" void JTSPutLHSCache(PreparedGeometry *lhs);
+
 extern "C" char JTSisvalid(Geometry *g1);
 
 /* Converters */
@@ -167,11 +177,14 @@
 	if (jtsGeomFactory == NULL)
 	{
 		JvCreateJavaVM(NULL);
-		JvAttachCurrentThread(NULL, NULL);	
+	        JvAttachCurrentThread(NULL, NULL);	
 		JvInitClass(&Geometry::class$);
 		JvInitClass(&GeometryFactory::class$);
 		JvInitClass(&Coordinate::class$);
 		JvInitClass(&JTSVersion::class$);
+                JvInitClass(&PreparedGeometry::class$);
+                JvInitClass(&PreparedGeometryFactory::class$);
+                JvInitClass(&PreparedGeometryCache::class$);
 
 		// NOTE: SRID will have to be changed after geometry creation
 		jtsGeomFactory = new GeometryFactory( new PrecisionModel(), -1);
@@ -188,11 +201,19 @@
 	JvDetachCurrentThread();
 }
 
+void
+JTSgc(void)
+{
+        System::gc();
+}
+
 Geometry *
 JTSGeometryFromWKT(const char *wkt)
 {
 	try {
+#ifdef DEBUG_POSTGIS2GEOS
 		NOTICE_MESSAGE("JTSGeometryFromWKT called");
+#endif
 		static WKTReader *r = new WKTReader;
 		jstring wkt_j = JvNewStringLatin1(wkt);
 		Geometry *g = r->read(wkt_j);
@@ -250,6 +271,104 @@
 	}
 }
 
+char JTSpreparedIntersects(PreparedGeometry *pg, Geometry* g)
+{
+        try {
+                bool result;
+                result = pg->intersects(g);
+                return result;
+        }
+        catch (Throwable *t)
+        {
+                NOTICE_MESSAGE(StringToChar(t->getMessage()));
+                return 2;
+        }
+}
+
+PreparedGeometry *JTSPrepareGeometry(Geometry* g)
+{
+        try {
+                PreparedGeometryFactory *pgFact;
+                PreparedGeometry *pg;
+                pgFact = new PreparedGeometryFactory();
+                pg = pgFact->create(g);
+                return pg;
+        }
+        catch (Throwable *t)
+        {
+                NOTICE_MESSAGE(StringToChar(t->getMessage()));
+                return NULL;
+        }
+}
+
+void JTSPrintPreparedGeometry(PreparedGeometry *pg)
+{
+        try {
+                NOTICE_MESSAGE(StringToChar(pg->getGeometry()->toString()));
+        }
+        catch (Throwable *t)
+        {
+                NOTICE_MESSAGE(StringToChar(t->getMessage()));
+        }
+}
+
+PreparedGeometry *JTSGetRHSCache()
+{
+        try {
+                PreparedGeometryCache *cache;
+                PreparedGeometry *pg;
+                cache = PreparedGeometryCache::instance;
+                pg = cache->getRightHandSide();
+                return pg;
+        }
+        catch (Throwable *t)
+        {
+                NOTICE_MESSAGE(StringToChar(t->getMessage()));
+                return NULL;
+        }
+}
+
+PreparedGeometry *JTSGetLHSCache()
+{
+        try {
+                PreparedGeometryCache *cache;
+                PreparedGeometry *pg;
+                cache = PreparedGeometryCache::instance;
+                pg = cache->getLeftHandSide();
+                return pg;
+        }
+        catch (Throwable *t)
+        {
+                NOTICE_MESSAGE(StringToChar(t->getMessage()));
+                return NULL;
+        }
+}
+
+void JTSPutRHSCache(PreparedGeometry *rhs)
+{
+        try {
+                PreparedGeometryCache *cache;
+                cache = PreparedGeometryCache::instance;
+                cache->putRightHandSide(rhs);
+        }
+        catch (Throwable *t)
+        {
+                NOTICE_MESSAGE(StringToChar(t->getMessage()));
+        }
+}
+void JTSPutLHSCache(PreparedGeometry *lhs)
+{
+        try {
+                PreparedGeometryCache *cache;
+                cache = PreparedGeometryCache::instance;
+                cache->putLeftHandSide(lhs);
+        }
+        catch (Throwable *t)
+        {
+                NOTICE_MESSAGE(StringToChar(t->getMessage()));
+        }
+}
+
 char JTSrelateCrosses(Geometry *g1, Geometry*g2)
 {
 	try {
@@ -785,6 +904,14 @@
 	//return res;
 }
 
+bool
+ensureMinimumVersion(int major, int minor, int patch)
+{
+        JTSVersion *v = JTSVersion::CURRENT_VERSION;
+        if (!v) return false;
+        return false;
+}
+
 bool 
 JTSHasZ(Geometry *g)
 {



More information about the postgis-commits mailing list