]> granicus.if.org Git - postgis/commitdiff
Backport memory improvements and multi-polygon support for p-i-p
authorPaul Ramsey <pramsey@cleverelephant.ca>
Mon, 29 Sep 2008 18:25:00 +0000 (18:25 +0000)
committerPaul Ramsey <pramsey@cleverelephant.ca>
Mon, 29 Sep 2008 18:25:00 +0000 (18:25 +0000)
shortcuts from trunk.

git-svn-id: http://svn.osgeo.org/postgis/branches/1.3@3028 b70326c6-7e19-0410-871a-916f4a2858ee

lwgeom/lwgeom_functions_analytic.c
lwgeom/lwgeom_functions_lrs.c
lwgeom/lwgeom_geos_c.c
lwgeom/lwgeom_rtree.c
lwgeom/lwgeom_rtree.h

index a88e675a093f6408fa3bbb54031060219daf6b8f..a1dfa128c5938b34989263b4ebfe71cf67cb81d7 100644 (file)
@@ -1136,7 +1136,7 @@ int isOnSegment(POINT2D *seg1, POINT2D *seg2, POINT2D *point)
  * return 1 iff point is inside ring pts
  * return 0 iff point is on ring pts
  */
-int point_in_ring(RTREE_NODE *root, POINT2D *point)
+int point_in_ring_rtree(RTREE_NODE *root, POINT2D *point)
 {
         int wn = 0;
         int i;
@@ -1224,7 +1224,7 @@ int point_in_ring(RTREE_NODE *root, POINT2D *point)
  * return 1 iff point is inside ring pts
  * return 0 iff point is on ring pts
  */
-int point_in_ring_deprecated(POINTARRAY *pts, POINT2D *point)
+int point_in_ring(POINTARRAY *pts, POINT2D *point)
 {
         int wn = 0;
         int i;
@@ -1306,7 +1306,7 @@ int point_in_ring_deprecated(POINTARRAY *pts, POINT2D *point)
  * return 0 iff point outside polygon or on boundary
  * return 1 iff point inside polygon
  */
-int point_in_polygon(RTREE_NODE **root, int ringCount, LWPOINT *point)
+int point_in_polygon_rtree(RTREE_NODE **root, int ringCount, LWPOINT *point)
 {
         int i;
         POINT2D pt;
@@ -1318,7 +1318,7 @@ int point_in_polygon(RTREE_NODE **root, int ringCount, LWPOINT *point)
         getPoint2d_p(point->point, 0, &pt);
         /* assume bbox short-circuit has already been attempted */
         
-        if(point_in_ring(root[0], &pt) != 1) 
+        if(point_in_ring_rtree(root[0], &pt) != 1) 
         {
 #ifdef PGIS_DEBUG
                 lwnotice("point_in_polygon: outside exterior ring.");
@@ -1328,7 +1328,7 @@ int point_in_polygon(RTREE_NODE **root, int ringCount, LWPOINT *point)
 
         for(i=1; i<ringCount; i++)
         {
-                if(point_in_ring(root[i], &pt) != -1)
+                if(point_in_ring_rtree(root[i], &pt) != -1)
                 {
 #ifdef PGIS_DEBUG
                         lwnotice("point_in_polygon: within hole %d.", i);
@@ -1340,150 +1340,192 @@ int point_in_polygon(RTREE_NODE **root, int ringCount, LWPOINT *point)
 }
 
 /*
- * return 0 iff point outside polygon or on boundary
- * return 1 iff point inside polygon
+ * return -1 if point outside polygon
+ * return 0 if point on boundary
+ * return 1 if point inside polygon
+ *
+ * Expected **root order is all the exterior rings first, then all the holes
+ *
+ * TODO: this could be made slightly more efficient by ordering the rings in 
+ * EIIIEIIIEIEI order (exterior/interior) and including list of exterior ring 
+ * positions on the cache object.
  */
-int point_in_polygon_deprecated(LWPOLY *polygon, LWPOINT *point)
+int point_in_multipolygon_rtree(RTREE_NODE **root, int polyCount, int ringCount, LWPOINT *point)
 {
-        int i;
-        POINTARRAY *ring;
-        POINT2D pt;
+    int i;
+    POINT2D pt;
+    int result = -1;
 
 #ifdef PGIS_DEBUG_CALLS
-        lwnotice("point_in_polygon_deprecated called.");
+    lwnotice("point_in_multipolygon_rtree called for %p %d %d %p.", root, polyCount, ringCount, point);
 #endif
 
-        getPoint2d_p(point->point, 0, &pt);
-        /* assume bbox short-circuit has already been attempted */
-        
-        ring = polygon->rings[0];
-        /* root = createTree(ring); */
-        /* if(point_in_ring(root, &pt) != 1)  */
-        if(point_in_ring_deprecated(polygon->rings[0], &pt) != 1)
-        {
-#ifdef PGIS_DEBUG
-                lwnotice("point_in_polygon: outside exterior ring.");
-#endif
-                return 0;
-        }
+    getPoint2d_p(point->point, 0, &pt);
+    /* assume bbox short-circuit has already been attempted */
 
-        for(i=1; i<polygon->nrings; i++)
-        {
-                ring = polygon->rings[i];
-                /* root = createTree(ring); */
-                /* if(point_in_ring(root, &pt) != -1) */
-                if(point_in_ring_deprecated(polygon->rings[i], &pt) != -1)
-                {
-#ifdef PGIS_DEBUG
-                        lwnotice("point_in_polygon: within hole %d.", i);
+       /* is the point inside (not outside) any of the exterior rings? */
+    for( i = 0; i < polyCount; i++ )
+    {
+               int in_ring = point_in_ring_rtree(root[i], &pt);
+#ifdef PGIS_DEBUG_CALLS
+       lwnotice("point_in_multipolygon_rtree: exterior ring (%d), point_in_ring returned %d", i, in_ring);
 #endif
-                        return 0;
-                }
-        }
-        return 1;
+               if( in_ring != -1 ) /* not outside this ring */
+               {
+#ifdef PGIS_DEBUG_CALLS
+               lwnotice("point_in_multipolygon_rtree: inside exterior ring.");
+#endif
+               result = in_ring;
+               break;
+               }
+    }
+    
+    if( result == -1 ) /* strictly outside all rings */
+        return result;
+
+       /* ok, it's in a ring, but if it's in a hole it's still outside */
+    for( i = polyCount; i < ringCount; i++ )
+    {
+               int in_ring = point_in_ring_rtree(root[i], &pt);
+#ifdef PGIS_DEBUG_CALLS
+       lwnotice("point_in_multipolygon_rtree: hole (%d), point_in_ring returned %d", i, in_ring);
+#endif
+               if( in_ring == 1 ) /* completely inside hole */
+               {
+#ifdef PGIS_DEBUG_CALLS
+               lwnotice("point_in_multipolygon_rtree: within hole %d.", i);
+#endif
+               return -1;
+               }
+               if( in_ring == 0 ) /* on the boundary of a hole */
+               {
+                       result = 0;
+               }
+    }
+    return result; /* -1 = outside, 0 = boundary, 1 = inside */
+
 }
 
+
+
 /*
- * return 0 iff point inside polygon or on boundary
- * return 1 iff point outside polygon
+ * return -1 iff point outside polygon
+ * return 0 iff point on boundary
+ * return 1 iff point inside polygon
  */
-int point_outside_polygon(RTREE_NODE **root, int ringCount, LWPOINT *point)
+int point_in_polygon(LWPOLY *polygon, LWPOINT *point)
 {
-        int i;
+        int i, result, in_ring;
+        POINTARRAY *ring;
         POINT2D pt;
 
 #ifdef PGIS_DEBUG_CALLS
-        lwnotice("point_outside_polygon called.");
+        lwnotice("point_in_polygon_deprecated called.");
 #endif
 
         getPoint2d_p(point->point, 0, &pt);
         /* assume bbox short-circuit has already been attempted */
         
-        if(point_in_ring(root[0], &pt) == -1)
+        ring = polygon->rings[0];
+               in_ring = point_in_ring(polygon->rings[0], &pt);
+        if( in_ring == -1) /* outside the exterior ring */
         {
 #ifdef PGIS_DEBUG
-                lwnotice("point_outside_polygon: outside exterior ring.");
+                lwnotice("point_in_polygon: outside exterior ring.");
 #endif
-                return 1;
+                return -1;
         }
+               result = in_ring;
 
-        for(i=1; i<ringCount; i++)
+        for(i=1; i<polygon->nrings; i++)
         {
-                if(point_in_ring(root[i], &pt) == 1)
+                ring = polygon->rings[i];
+                               in_ring = point_in_ring(polygon->rings[i], &pt);
+                if(in_ring == 1) /* inside a hole => outside the polygon */
                 {
 #ifdef PGIS_DEBUG
-                        lwnotice("point_outside_polygon: within hole %d.", i);
+                       lwnotice("point_in_polygon: within hole %d.", i);
 #endif
-                        return 1;
+                    return -1;
+                }
+                               if(in_ring == 0) /* on the edge of a hole */
+                {
+#ifdef PGIS_DEBUG
+                       lwnotice("point_in_polygon: on edge of hole %d.", i);
+#endif
+                                       return 0;
                 }
         }
-        return 0;
+        return result; /* -1 = outside, 0 = boundary, 1 = inside */
 }
 
 /*
- * return 0 iff point inside polygon or on boundary
- * return 1 iff point outside polygon
+ * return -1 iff point outside multipolygon
+ * return 0 iff point on multipolygon boundary
+ * return 1 iff point inside multipolygon
  */
-int point_outside_polygon_deprecated(LWPOLY *polygon, LWPOINT *point)
+int point_in_multipolygon(LWMPOLY *mpolygon, LWPOINT *point)
 {
-        int i;
+        int i, j, result, in_ring;
         POINTARRAY *ring;
         POINT2D pt;
 
-#ifdef PGIS_DEBUG_CALLS
-        lwnotice("point_outside_polygon_deprecated called.");
+#ifdef PGIS_DEBUG
+        lwnotice("point_in_polygon called.");
 #endif
 
         getPoint2d_p(point->point, 0, &pt);
         /* assume bbox short-circuit has already been attempted */
-        
-        ring = polygon->rings[0];
-        /* root = createTree(ring); */
-        /* if(point_in_ring(root, &pt) == -1) */
-        if(point_in_ring_deprecated(ring, &pt) == -1)
-        {
+
+               result = -1;
+
+               for(j = 0; j < mpolygon->ngeoms; j++ ) 
+               {
+               
+                       LWPOLY *polygon = mpolygon->geoms[j];
+                       ring = polygon->rings[0];
+                       in_ring = point_in_ring(polygon->rings[0], &pt);
+                       if( in_ring == -1) /* outside the exterior ring */
+               {
 #ifdef PGIS_DEBUG
-                lwnotice("point_outside_polygon_deprecated: outside exterior ring.");
+                       lwnotice("point_in_polygon: outside exterior ring.");
 #endif
-                return 1;
-        }
+                               continue;
+               }
+                       if( in_ring == 0 ) 
+                       {
+                               return 0;
+                       }
 
-        for(i=1; i<polygon->nrings; i++)
-        {
+                       result = in_ring;
+
+               for(i=1; i<polygon->nrings; i++)
+               {
                 ring = polygon->rings[i];
-                /* root = createTree(ring); */
-                /* if(point_in_ring(root, &pt) == 1)  */
-                if(point_in_ring_deprecated(ring, &pt) == 1)
+                               in_ring = point_in_ring(polygon->rings[i], &pt);
+                if(in_ring == 1) /* inside a hole => outside the polygon */
                 {
 #ifdef PGIS_DEBUG
-                        lwnotice("point_outside_polygon_deprecated: within hole %d.", i);
+                               lwnotice("point_in_polygon: within hole %d.", i);
 #endif
-                        return 1;
+                                       result = -1;
+                    break;
                 }
-        }
-        return 0;
-}
-
-
-/*
- * return 0 iff point is outside every polygon
- */
-/* Not yet functional.
-int point_in_multipolygon(LWMPOLY *mpolygon, LWPOINT *point)
-{
-        int i;
-
-#ifdef PGIS_DEBUG_CALLS
-        lwnotice("point_in_multipolygon called.");
+                               if(in_ring == 0) /* on the edge of a hole */
+                               {
+#ifdef PGIS_DEBUG
+                               lwnotice("point_in_polygon: on edge of hole %d.", i);
 #endif
-
-        for(i=1; i<mpolygon->ngeoms; i++)
-        {
-                if(point_in_polygon((LWPOLY *)mpolygon->geoms[i], point)!=0) return 1;
-        }
-        return 0;
+                                       return 0;
+                               }
+               }
+               if( result != -1) 
+                       {
+                               return result;
+                       }
+               }
+               return result;
 }
-*/
 
 
 /*******************************************************************************
index f7e1e8a535b4e437ef2839c596139f6420178cf9..dc9f62ce8cf8f0c2351b06466b2db35b77661272 100644 (file)
@@ -16,8 +16,8 @@
 #include "lwgeom_pg.h"
 #include "math.h"
 
-#define DEBUG_LRS 0
-#define DEBUG_INTERPOLATION 0
+#define DEBUG_LRS 1
+#define DEBUG_INTERPOLATION 1
 
 Datum LWGEOM_locate_between_m(PG_FUNCTION_ARGS);
 
@@ -151,7 +151,7 @@ clip_seg_by_m_range(POINT4D *p1, POINT4D *p2, double m0, double m1)
         * numbers.
         *
         * The two points must be equal anyway.
-        */
+
        if ( m0 == m1 )
        {
                memcpy(p2, p1, sizeof(POINT4D));
@@ -159,6 +159,7 @@ clip_seg_by_m_range(POINT4D *p1, POINT4D *p2, double m0, double m1)
                else ret |= 0x0100;
                return ret;
        }
+XXX             */
 
        /* 
         * Second point out of range, project 
@@ -338,7 +339,7 @@ lwpoint_locate_between_m(LWPOINT *lwpoint, double m0, double m1)
  */
 static LWGEOM *
 lwline_locate_between_m(LWLINE *lwline_in, double m0, double m1)
-{
+{              
        POINTARRAY *ipa=lwline_in->points;
        int i;
        LWGEOM **geoms;
@@ -377,6 +378,7 @@ lwline_locate_between_m(LWLINE *lwline_in, double m0, double m1)
                /* This is a point */
                if ( pa->npoints == 1 )
                {
+
                        lwpoint=lwalloc(sizeof(LWPOINT));
                        lwpoint->type=lwgeom_makeType_full(
                                TYPE_HASZ(pa->dims),
@@ -414,6 +416,8 @@ lwline_locate_between_m(LWLINE *lwline_in, double m0, double m1)
                        lwerror("ptarray_locate_between_m returned a POINARRAY set containing POINTARRAY with 0 points");
                }
 
+
+
        }
 
        if ( ngeoms == 1 )
@@ -427,6 +431,9 @@ lwline_locate_between_m(LWLINE *lwline_in, double m0, double m1)
                else if ( typeflag == 2 ) outtype=MULTILINETYPE;
                else outtype = COLLECTIONTYPE;
 
+       lwnotice(" XXX lwline_locate_between_m: %s", lwgeom_to_ewkt((LWGEOM *)lwcollection_construct(outtype,
+                       lwline_in->SRID, NULL, ngeoms, geoms)));
+
                return (LWGEOM *)lwcollection_construct(outtype,
                        lwline_in->SRID, NULL, ngeoms, geoms);
        }
index 440b4e00940bd2614895ee24ff89674781b141a1..f74247e916e8d6977c9410e5fc1241450cc03a69 100644 (file)
@@ -46,6 +46,8 @@
 /* #define UNITE_USING_BUFFER 1 */
 /* #define MAXGEOMSPOINTS 21760 */
 
+/* PROTOTYPES start */
+
 Datum relate_full(PG_FUNCTION_ARGS);
 Datum relate_pattern(PG_FUNCTION_ARGS);
 Datum disjoint(PG_FUNCTION_ARGS);
@@ -85,6 +87,12 @@ GEOSGeom POSTGIS2GEOS(PG_LWGEOM *g);
 GEOSGeom LWGEOM2GEOS(LWGEOM *g);
 
 void errorIfGeometryCollection(PG_LWGEOM *g1, PG_LWGEOM *g2);
+int point_in_polygon_rtree(RTREE_NODE **root, int ringCount, LWPOINT *point);
+int point_in_multipolygon_rtree(RTREE_NODE **root, int polyCount, int ringCount, LWPOINT *point);
+int point_in_polygon(LWPOLY *polygon, LWPOINT *point);
+int point_in_multipolygon(LWMPOLY *mpolygon, LWPOINT *pont);
+
+/* PROTOTYPES end */
 
 PG_FUNCTION_INFO_V1(postgis_geos_version);
 Datum postgis_geos_version(PG_FUNCTION_ARGS)
@@ -1430,12 +1438,6 @@ Datum overlaps(PG_FUNCTION_ARGS)
        PG_RETURN_BOOL(result);
 }
 
-int point_in_polygon(RTREE_NODE **root, int ringCount, LWPOINT *point);
-int point_in_polygon_deprecated(LWPOLY *polygon, LWPOINT *point);
-int point_outside_polygon(RTREE_NODE **root, int ringCount, LWPOINT *point);
-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)
@@ -1446,7 +1448,7 @@ Datum contains(PG_FUNCTION_ARGS)
        bool result;
        BOX2DFLOAT4 box1, box2;
         int type1, type2;
-        LWPOLY *poly;
+       LWGEOM *lwgeom;
         /* LWMPOLY *mpoly; */
         LWPOINT *point;
         RTREE_POLY_CACHE *poly_cache;
@@ -1467,13 +1469,14 @@ Datum contains(PG_FUNCTION_ARGS)
         * 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 ( 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);
+               if ( ( box2.xmin < box1.xmin ) || ( box2.xmax > box1.xmax ) ||
+                    ( box2.ymin < box1.ymin ) || ( box2.ymax > box1.ymax ) ) 
+               {
+                   PG_RETURN_BOOL(FALSE);
+               }
        }
         /*
          * short-circuit 2: if geom2 is a point and geom1 is a polygon
@@ -1481,13 +1484,13 @@ Datum contains(PG_FUNCTION_ARGS)
          */
         type1 = lwgeom_getType((uchar)SERIALIZED_FORM(geom1)[0]);
         type2 = lwgeom_getType((uchar)SERIALIZED_FORM(geom2)[0]);
-        if(type1 == POLYGONTYPE && type2 == POINTTYPE)
-        {
+       if((type1 == POLYGONTYPE || type1 == MULTIPOLYGONTYPE) && type2 == POINTTYPE)
+               {
 #ifdef PGIS_DEBUG
                 lwnotice("Point in Polygon test requested...short-circuiting.");
 #endif
 
-                poly = lwpoly_deserialize(SERIALIZED_FORM(geom1));
+                       lwgeom = lwgeom_deserialize(SERIALIZED_FORM(geom1));
                 point = lwpoint_deserialize(SERIALIZED_FORM(geom2));
 #ifdef PGIS_DEBUG
                 lwnotice("Precall point_in_polygon %p, %p", poly, point);
@@ -1499,53 +1502,40 @@ Datum contains(PG_FUNCTION_ARGS)
                  * future use, then switch back to the local context.
                  */                 
                 old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
-                poly_cache = retrieveCache(poly, SERIALIZED_FORM(geom1), fcinfo->flinfo->fn_extra);
+                poly_cache = retrieveCache(lwgeom, SERIALIZED_FORM(geom1), fcinfo->flinfo->fn_extra);
                 fcinfo->flinfo->fn_extra = poly_cache;
                 MemoryContextSwitchTo(old_context);
 
-                if(point_in_polygon(poly_cache->ringIndices, poly_cache->ringCount, point) == 0)
-                {
-                       PG_FREE_IF_COPY(geom1, 0);
-                       PG_FREE_IF_COPY(geom2, 1);
-                        lwgeom_release((LWGEOM *)poly);
-                        lwgeom_release((LWGEOM *)point);
-                        PG_RETURN_BOOL(FALSE);
-                }
-                else
-                {
-                        PG_FREE_IF_COPY(geom1, 0);
-                        PG_FREE_IF_COPY(geom2, 1);
-                        lwgeom_release((LWGEOM *)poly);
-                        lwgeom_release((LWGEOM *)point);
-                        PG_RETURN_BOOL(TRUE);
-                }
+                               if( poly_cache->ringIndices ) 
+                               {
+                                       result = point_in_multipolygon_rtree(poly_cache->ringIndices, poly_cache->polyCount, poly_cache->ringCount, point);
+                               }
+                               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!");
+                                       PG_RETURN_NULL(); 
+                               }
+                       PG_FREE_IF_COPY(geom1, 0);
+                       PG_FREE_IF_COPY(geom2, 1);
+                       lwgeom_release((LWGEOM *)lwgeom);
+                       lwgeom_release((LWGEOM *)point);
+                               if( result == 1 ) /* completely inside */
+                               {
+                                       PG_RETURN_BOOL(TRUE);
+                               }
+                               else
+                               {
+                                       PG_RETURN_BOOL(FALSE);
+                               }
         } 
-        /* Not yet functional 
-        else if(type1 == MULTIPOLYGONTYPE && type2 == POINTTYPE)
-        {
-#ifdef PGIS_DEBUG
-                lwnotice("Point in MultiPolygon test requested...short-circuiting.");
-#endif
-                mpoly = lwmpoly_deserialize(SERIALIZED_FORM(geom1));
-                point = lwpoint_deserialize(SERIALIZED_FORM(geom2));
-                if(point_in_multipolygon(mpoly, point) == 0)
-                {
-                        PG_FREE_IF_COPY(geom1, 0);
-                        PG_FREE_IF_COPY(geom2, 1);
-                        lwgeom_release((LWGEOM *)mpoly);
-                        lwgeom_release((LWGEOM *)point);
-                        PG_RETURN_BOOL(FALSE);
-                }
-                else
-                {
-                        PG_FREE_IF_COPY(geom1, 0);
-                        PG_FREE_IF_COPY(geom2, 1);
-                        lwgeom_release((LWGEOM *)mpoly);
-                        lwgeom_release((LWGEOM *)point);
-                        PG_RETURN_BOOL(TRUE);
-                }
-        }
-        */
         else 
         {
 #ifdef PGIS_DEBUG
@@ -1612,7 +1602,7 @@ Datum covers(PG_FUNCTION_ARGS)
        bool result;
        BOX2DFLOAT4 box1, box2;
         int type1, type2;
-        LWPOLY *poly;
+        LWGEOM *lwgeom;
         /* LWMPOLY *mpoly; */
         LWPOINT *point;
         RTREE_POLY_CACHE *poly_cache;
@@ -1648,13 +1638,13 @@ Datum covers(PG_FUNCTION_ARGS)
          */
         type1 = lwgeom_getType((uchar)SERIALIZED_FORM(geom1)[0]);
         type2 = lwgeom_getType((uchar)SERIALIZED_FORM(geom2)[0]);
-        if(type1 == POLYGONTYPE && type2 == POINTTYPE)
+       if((type1 == POLYGONTYPE || type1 == MULTIPOLYGONTYPE) && type2 == POINTTYPE)
         {
 #ifdef PGIS_DEBUG
                 lwnotice("Point in Polygon test requested...short-circuiting.");
 #endif
 
-                poly = lwpoly_deserialize(SERIALIZED_FORM(geom1));
+                lwgeom = lwgeom_deserialize(SERIALIZED_FORM(geom1));
                 point = lwpoint_deserialize(SERIALIZED_FORM(geom2));
 #ifdef PGIS_DEBUG
                 lwnotice("Precall point_in_polygon %p, %p", poly, point);
@@ -1666,26 +1656,40 @@ Datum covers(PG_FUNCTION_ARGS)
                  * future use, then switch back to the local context.
                  */                 
                 old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
-                poly_cache = retrieveCache(poly, SERIALIZED_FORM(geom1), fcinfo->flinfo->fn_extra);
+                poly_cache = retrieveCache(lwgeom, SERIALIZED_FORM(geom1), fcinfo->flinfo->fn_extra);
                 fcinfo->flinfo->fn_extra = poly_cache;
                 MemoryContextSwitchTo(old_context);
 
-                if(point_outside_polygon(poly_cache->ringIndices, poly_cache->ringCount, point) == 0)
-                {
-                       PG_FREE_IF_COPY(geom1, 0);
-                       PG_FREE_IF_COPY(geom2, 1);
-                        lwgeom_release((LWGEOM *)poly);
-                        lwgeom_release((LWGEOM *)point);
-                        PG_RETURN_BOOL(TRUE);
-                }
-                else
-                {
-                        PG_FREE_IF_COPY(geom1, 0);
-                        PG_FREE_IF_COPY(geom2, 1);
-                        lwgeom_release((LWGEOM *)poly);
-                        lwgeom_release((LWGEOM *)point);
-                        PG_RETURN_BOOL(FALSE);
-                }
+                               if( poly_cache->ringIndices ) 
+                               {
+                                       result = point_in_multipolygon_rtree(poly_cache->ringIndices, poly_cache->polyCount, poly_cache->ringCount, point);
+                               }
+                               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!");
+                                       PG_RETURN_NULL(); 
+                               }
+
+                PG_FREE_IF_COPY(geom1, 0);
+                PG_FREE_IF_COPY(geom2, 1);
+                               lwgeom_release((LWGEOM *)lwgeom);
+                               lwgeom_release((LWGEOM *)point);
+                               if( result != -1 ) /* not outside */
+                               {
+                                       PG_RETURN_BOOL(TRUE);
+                               }
+                               else
+                               {
+                                       PG_RETURN_BOOL(FALSE);
+                               }
         } 
         else 
         {
@@ -1747,7 +1751,7 @@ Datum within(PG_FUNCTION_ARGS)
        GEOSGeom g1,g2;
        bool result;
        BOX2DFLOAT4 box1, box2;
-        LWPOLY *poly;
+        LWGEOM *lwgeom;
         LWPOINT *point;
         int type1, type2;
         MemoryContext old_context;
@@ -1782,14 +1786,14 @@ Datum within(PG_FUNCTION_ARGS)
          */
         type1 = lwgeom_getType((uchar)SERIALIZED_FORM(geom1)[0]);
         type2 = lwgeom_getType((uchar)SERIALIZED_FORM(geom2)[0]);
-        if(type1 == POINTTYPE && type2 == POLYGONTYPE)
+       if((type2 == POLYGONTYPE || type2 == MULTIPOLYGONTYPE) && type1 == POINTTYPE)
         {
 #ifdef PGIS_DEBUG
                 lwnotice("Point in Polygon test requested...short-circuiting.");
 #endif
 
                 point = lwpoint_deserialize(SERIALIZED_FORM(geom1));
-                poly = lwpoly_deserialize(SERIALIZED_FORM(geom2));
+                lwgeom = lwgeom_deserialize(SERIALIZED_FORM(geom2));
 
                 /*
                  * Switch the context to the function-scope context,
@@ -1797,26 +1801,40 @@ Datum within(PG_FUNCTION_ARGS)
                  * future use, then switch back to the local context.
                  */                 
                 old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
-                poly_cache = retrieveCache(poly, SERIALIZED_FORM(geom2), fcinfo->flinfo->fn_extra);
+                poly_cache = retrieveCache(lwgeom, SERIALIZED_FORM(geom2), fcinfo->flinfo->fn_extra);
                 fcinfo->flinfo->fn_extra = poly_cache;
                 MemoryContextSwitchTo(old_context);
 
-                if(point_in_polygon(poly_cache->ringIndices, poly_cache->ringCount, point) == 0)
-                {
-                       PG_FREE_IF_COPY(geom1, 0);
-                       PG_FREE_IF_COPY(geom2, 1);
-                        lwgeom_release((LWGEOM *)poly);
-                        lwgeom_release((LWGEOM *)point);
-                        PG_RETURN_BOOL(FALSE);
-                }
-                else
-                {
-                        PG_FREE_IF_COPY(geom1, 0);
-                        PG_FREE_IF_COPY(geom2, 1);
-                        lwgeom_release((LWGEOM *)poly);
-                        lwgeom_release((LWGEOM *)point);
-                        PG_RETURN_BOOL(TRUE);
-                }
+                               if( poly_cache->ringIndices ) 
+                               {
+                                       result = point_in_multipolygon_rtree(poly_cache->ringIndices, poly_cache->polyCount, poly_cache->ringCount, point);
+                               }
+                               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!");
+                                       PG_RETURN_NULL(); 
+                               }
+
+                PG_FREE_IF_COPY(geom1, 0);
+                PG_FREE_IF_COPY(geom2, 1);
+                lwgeom_release((LWGEOM *)lwgeom);
+                lwgeom_release((LWGEOM *)point);
+                               if( result == 1 ) /* completely inside */
+                               {
+                                       PG_RETURN_BOOL(TRUE);
+                               }
+                               else
+                               {
+                                       PG_RETURN_BOOL(FALSE);
+                               }
         }
 
        initGEOS(lwnotice, lwnotice);
@@ -1877,7 +1895,7 @@ Datum coveredby(PG_FUNCTION_ARGS)
        GEOSGeom g1,g2;
        bool result;
        BOX2DFLOAT4 box1, box2;
-        LWPOLY *poly;
+        LWGEOM *lwgeom;
         LWPOINT *point;
         int type1, type2;
         MemoryContext old_context;
@@ -1917,14 +1935,14 @@ Datum coveredby(PG_FUNCTION_ARGS)
          */
         type1 = lwgeom_getType((uchar)SERIALIZED_FORM(geom1)[0]);
         type2 = lwgeom_getType((uchar)SERIALIZED_FORM(geom2)[0]);
-        if(type1 == POINTTYPE && type2 == POLYGONTYPE)
+       if((type2 == POLYGONTYPE || type2 == MULTIPOLYGONTYPE) && type1 == POINTTYPE)
         {
 #ifdef PGIS_DEBUG
                 lwnotice("Point in Polygon test requested...short-circuiting.");
 #endif
 
                 point = lwpoint_deserialize(SERIALIZED_FORM(geom1));
-                poly = lwpoly_deserialize(SERIALIZED_FORM(geom2));
+                lwgeom = lwgeom_deserialize(SERIALIZED_FORM(geom2));
 
                 /*
                  * Switch the context to the function-scope context,
@@ -1932,26 +1950,40 @@ Datum coveredby(PG_FUNCTION_ARGS)
                  * future use, then switch back to the local context.
                  */                 
                 old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
-                poly_cache = retrieveCache(poly, SERIALIZED_FORM(geom2), fcinfo->flinfo->fn_extra);
+                poly_cache = retrieveCache(lwgeom, SERIALIZED_FORM(geom2), fcinfo->flinfo->fn_extra);
                 fcinfo->flinfo->fn_extra = poly_cache;
                 MemoryContextSwitchTo(old_context);
 
-                if(point_outside_polygon(poly_cache->ringIndices, poly_cache->ringCount, point) == 0)
-                {
-                       PG_FREE_IF_COPY(geom1, 0);
-                       PG_FREE_IF_COPY(geom2, 1);
-                        lwgeom_release((LWGEOM *)poly);
-                        lwgeom_release((LWGEOM *)point);
-                        PG_RETURN_BOOL(TRUE);
-                }
-                else
-                {
-                        PG_FREE_IF_COPY(geom1, 0);
-                        PG_FREE_IF_COPY(geom2, 1);
-                        lwgeom_release((LWGEOM *)poly);
-                        lwgeom_release((LWGEOM *)point);
-                        PG_RETURN_BOOL(FALSE);
-                }
+                               if( poly_cache->ringIndices ) 
+                               {
+                                       result = point_in_multipolygon_rtree(poly_cache->ringIndices, poly_cache->polyCount, poly_cache->ringCount, point);
+                               }
+                               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!");
+                                       PG_RETURN_NULL(); 
+                               }
+                               
+                PG_FREE_IF_COPY(geom1, 0);
+                PG_FREE_IF_COPY(geom2, 1);
+                lwgeom_release((LWGEOM *)lwgeom);
+                lwgeom_release((LWGEOM *)point);
+                               if( result != -1 ) /* not outside */
+                               {
+                                       PG_RETURN_BOOL(TRUE);
+                               }
+                               else
+                               {
+                                       PG_RETURN_BOOL(FALSE);
+                               }
         }
 
        initGEOS(lwnotice, lwnotice);
@@ -2085,13 +2117,14 @@ PG_FUNCTION_INFO_V1(intersects);
 Datum intersects(PG_FUNCTION_ARGS)
 {
        PG_LWGEOM *geom1;
-       PG_LWGEOM *geom2;
+       PG_LWGEOM *geom2;       
+       uchar *serialized_poly;
        GEOSGeom g1,g2;
        bool result;
        BOX2DFLOAT4 box1, box2;
-       int type1, type2;
+       int type1, type2, polytype;
        LWPOINT *point;
-       LWPOLY *poly;
+       LWGEOM *lwgeom;
         MemoryContext old_context;
         RTREE_POLY_CACHE *poly_cache;
 
@@ -2125,76 +2158,63 @@ Datum intersects(PG_FUNCTION_ARGS)
         */
        type1 = lwgeom_getType((uchar)SERIALIZED_FORM(geom1)[0]);
        type2 = lwgeom_getType((uchar)SERIALIZED_FORM(geom2)[0]);
-       if(type1 == POINTTYPE && type2 == POLYGONTYPE)
+       if( (type1 == POINTTYPE && (type2 == POLYGONTYPE || type2 == MULTIPOLYGONTYPE)) || 
+           (type2 == POINTTYPE && (type1 == POLYGONTYPE || type1 == MULTIPOLYGONTYPE)))
        {
 #ifdef PGIS_DEBUG
                lwnotice("Point in Polygon test requested...short-circuiting.");
 #endif
-               point = lwpoint_deserialize(SERIALIZED_FORM(geom1));
-               poly = lwpoly_deserialize(SERIALIZED_FORM(geom2));
-
-                /*
-                 * Switch the context to the function-scope context,
-                 * retrieve the appropriate cache object, cache it for 
-                 * future use, then switch back to the local context.
-                 */                 
-                old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
-                poly_cache = retrieveCache(poly, SERIALIZED_FORM(geom2), fcinfo->flinfo->fn_extra);
-                fcinfo->flinfo->fn_extra = poly_cache;
-                MemoryContextSwitchTo(old_context);
+        if( type1 == POINTTYPE ) {
+                   point = lwpoint_deserialize(SERIALIZED_FORM(geom1));
+                   lwgeom = lwgeom_deserialize(SERIALIZED_FORM(geom2));
+                       serialized_poly = SERIALIZED_FORM(geom2);
+                       polytype = type2;
+        } else {
+                   point = lwpoint_deserialize(SERIALIZED_FORM(geom2));
+                   lwgeom = lwgeom_deserialize(SERIALIZED_FORM(geom1));
+                       serialized_poly = SERIALIZED_FORM(geom1);
+                       polytype = type1;
+               }
 
-               if(point_outside_polygon(poly_cache->ringIndices, poly_cache->ringCount, point) == 0)
+        /*
+         * Switch the context to the function-scope context,
+         * retrieve the appropriate cache object, cache it for 
+         * future use, then switch back to the local context.
+         */                 
+               old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
+               poly_cache = retrieveCache(lwgeom, SERIALIZED_FORM(geom2), fcinfo->flinfo->fn_extra);
+               fcinfo->flinfo->fn_extra = poly_cache;
+               MemoryContextSwitchTo(old_context);
+
+               if( poly_cache->ringIndices ) 
                {
-                       PG_FREE_IF_COPY(geom1, 0);
-                       PG_FREE_IF_COPY(geom2, 1);
-                       lwgeom_release((LWGEOM *)poly);
-                       lwgeom_release((LWGEOM *)point);
-                       PG_RETURN_BOOL(TRUE);
+                       result = point_in_multipolygon_rtree(poly_cache->ringIndices, poly_cache->polyCount, poly_cache->ringCount, point);
                }
-               else
+               else if ( polytype == POLYGONTYPE ) 
                {
-                       PG_FREE_IF_COPY(geom1, 0);
-                       PG_FREE_IF_COPY(geom2, 1);
-                       lwgeom_release((LWGEOM *)poly);
-                       lwgeom_release((LWGEOM *)point);
-                       PG_RETURN_BOOL(FALSE);
+                       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!");
+                       PG_RETURN_NULL(); 
                }
-       }
-       else if(type1 == POLYGONTYPE && type2 == POINTTYPE)
-       {
-       #ifdef PGIS_DEBUG
-               lwnotice("Point in Polygon test requested...short-circuiting.");
-#endif
-               point = lwpoint_deserialize(SERIALIZED_FORM(geom2));
-               poly = lwpoly_deserialize(SERIALIZED_FORM(geom1));
-
-                /*
-                 * Switch the context to the function-scope context,
-                 * retrieve the appropriate cache object, cache it for 
-                 * future use, then switch back to the local context.
-                 */                 
-                old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
-                poly_cache = retrieveCache(poly, SERIALIZED_FORM(geom1), fcinfo->flinfo->fn_extra);
-                fcinfo->flinfo->fn_extra = poly_cache;
-                MemoryContextSwitchTo(old_context);
 
-               if(point_outside_polygon(poly_cache->ringIndices, poly_cache->ringCount, point) == 0)
+               PG_FREE_IF_COPY(geom1, 0);
+               PG_FREE_IF_COPY(geom2, 1);
+               lwgeom_release((LWGEOM *)lwgeom);
+               lwgeom_release((LWGEOM *)point);
+               if( result != -1 ) /* not outside */ 
                {
-                       PG_FREE_IF_COPY(geom1, 0);
-                       PG_FREE_IF_COPY(geom2, 1);
-                       lwgeom_release((LWGEOM *)poly);
-                       lwgeom_release((LWGEOM *)point);
                        PG_RETURN_BOOL(TRUE);
                }
-               else
-               {
-                       PG_FREE_IF_COPY(geom1, 0);
-                       PG_FREE_IF_COPY(geom2, 1);
-                       lwgeom_release((LWGEOM *)poly);
-                       lwgeom_release((LWGEOM *)point);
+               else {
                        PG_RETURN_BOOL(FALSE);
                }
-
        }
 
 
@@ -2329,11 +2349,6 @@ Datum disjoint(PG_FUNCTION_ARGS)
        GEOSGeom g1,g2;
        bool result;
        BOX2DFLOAT4 box1, box2;
-       int type1, type2;
-       LWPOLY *poly;
-       LWPOINT *point;
-        MemoryContext old_context;
-        RTREE_POLY_CACHE *poly_cache;
 
 #ifdef PROFILE
        profstart(PROF_QRUN);
@@ -2359,83 +2374,6 @@ Datum disjoint(PG_FUNCTION_ARGS)
                if ( box2.ymin > box1.ymax ) PG_RETURN_BOOL(TRUE);
        }
 
-       /*
-        * short-circuit 2: if the geoms are a point and a polygon, 
-        * call the point_outside_polygon function.
-        */
-       type1 = lwgeom_getType((uchar)SERIALIZED_FORM(geom1)[0]);
-       type2 = lwgeom_getType((uchar)SERIALIZED_FORM(geom2)[0]);
-       if(type1 == POINTTYPE && type2 == POLYGONTYPE)
-       {
-#ifdef PGIS_DEBUG
-               lwnotice("Point outside Polygon test requested...short-circuiting.");
-#endif
-               point = lwpoint_deserialize(SERIALIZED_FORM(geom1));
-               poly = lwpoly_deserialize(SERIALIZED_FORM(geom2));
-
-                /*
-                 * Switch the context to the function-scope context,
-                 * retrieve the appropriate cache object, cache it for 
-                 * future use, then switch back to the local context.
-                 */                 
-                old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
-                poly_cache = retrieveCache(poly, SERIALIZED_FORM(geom2), fcinfo->flinfo->fn_extra);
-                fcinfo->flinfo->fn_extra = poly_cache;
-                MemoryContextSwitchTo(old_context);
-
-               if(point_outside_polygon(poly_cache->ringIndices, poly_cache->ringCount, point) == 0) 
-               {
-                       PG_FREE_IF_COPY(geom1, 0);
-                       PG_FREE_IF_COPY(geom2, 0);
-                       lwgeom_release((LWGEOM *)poly);
-                       lwgeom_release((LWGEOM *)point);
-                       PG_RETURN_BOOL(FALSE);
-               }
-               else
-               {
-                       PG_FREE_IF_COPY(geom1, 0);
-                       PG_FREE_IF_COPY(geom2, 0);
-                       lwgeom_release((LWGEOM *)poly);
-                       lwgeom_release((LWGEOM *)point);
-                       PG_RETURN_BOOL(TRUE);
-               }
-       }
-       else if(type1 == POLYGONTYPE && type2 == POINTTYPE)
-       {
-#ifdef PGIS_DEBUG
-               lwnotice("Point outside Polygon test requested...short-circuiting.");
-#endif
-               point = lwpoint_deserialize(SERIALIZED_FORM(geom2));
-               poly = lwpoly_deserialize(SERIALIZED_FORM(geom1));
-
-                /*
-                 * Switch the context to the function-scope context,
-                 * retrieve the appropriate cache object, cache it for 
-                 * future use, then switch back to the local context.
-                 */                 
-                old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
-                poly_cache = retrieveCache(poly, SERIALIZED_FORM(geom2), fcinfo->flinfo->fn_extra);
-                fcinfo->flinfo->fn_extra = poly_cache;
-                MemoryContextSwitchTo(old_context);
-
-               if(point_outside_polygon(poly_cache->ringIndices, poly_cache->ringCount, point) == 0) 
-               {
-                       PG_FREE_IF_COPY(geom1, 0);
-                       PG_FREE_IF_COPY(geom2, 0);
-                       lwgeom_release((LWGEOM *)poly);
-                       lwgeom_release((LWGEOM *)point);
-                       PG_RETURN_BOOL(FALSE);
-               }
-               else
-               {
-                       PG_FREE_IF_COPY(geom1, 0);
-                       PG_FREE_IF_COPY(geom2, 0);
-                       lwgeom_release((LWGEOM *)poly);
-                       lwgeom_release((LWGEOM *)point);
-                       PG_RETURN_BOOL(TRUE);
-               }
-       }
-
        initGEOS(lwnotice, lwnotice);
 
 #ifdef PROFILE
index 66d294b9fec4e4af73184a88d57cf5174b7ac4e9..74b8e5325f564b86bfcd4026fd8ef853e4dff291 100644 (file)
@@ -77,6 +77,7 @@ RTREE_NODE *createTree(POINTARRAY *pointArray)
         }\r
 \r
         root = nodes[0];\r
+               lwfree(nodes);\r
 \r
 #ifdef PGIS_DEBUG\r
         lwnotice("createTree returning %p", root);\r
@@ -207,16 +208,41 @@ void freeTree(RTREE_NODE *root)
 #ifdef PGIS_DEBUG_CALLS\r
         lwnotice("freeTree called for %p", root);\r
 #endif\r
-        if(root->leftNode)\r
-                freeTree(root->leftNode);\r
-        if(root->rightNode)\r
-                freeTree(root->rightNode);\r
-        lwfree(root->interval);\r
-        if(root->segment)\r
-                lwfree(root->segment);\r
-        lwfree(root);\r
+               if(root->leftNode)\r
+                               freeTree(root->leftNode);\r
+               if(root->rightNode)\r
+                               freeTree(root->rightNode);\r
+               lwfree(root->interval);\r
+               if(root->segment) {\r
+                       lwfree(root->segment->points->serialized_pointlist);\r
+                       lwfree(root->segment->points);\r
+                       lwgeom_release((LWGEOM *)root->segment);\r
+               }\r
+               lwfree(root);\r
 }\r
 \r
+/*\r
+ * Free the cache object and all the sub-objects properly.\r
+ */\r
+void clearCache(RTREE_POLY_CACHE *cache)\r
+{\r
+       int i;\r
+#ifdef PGIS_DEBUG_CALLS\r
+    lwnotice("clearCache called for %p", cache);\r
+#endif\r
+       for(i = 0; i < cache->ringCount; i++)\r
+       { \r
+               freeTree(cache->ringIndices[i]);\r
+       }\r
+       lwfree(cache->ringIndices);\r
+       lwfree(cache->poly);\r
+       cache->poly = 0;\r
+       cache->ringIndices = 0;\r
+       cache->ringCount = 0;\r
+       cache->polyCount = 0;\r
+}\r
+\r
+\r
 /*\r
  * Retrieves a collection of line segments given the root and crossing value.\r
  * The collection is a multilinestring consisting of two point lines \r
@@ -387,28 +413,98 @@ Datum LWGEOM_polygon_index(PG_FUNCTION_ARGS)
         \r
 }\r
 \r
-RTREE_POLY_CACHE *createNewCache(LWPOLY *poly, uchar *serializedPoly)\r
+RTREE_POLY_CACHE * createCache()\r
 {\r
-        RTREE_POLY_CACHE *result;\r
-        int i, length;\r
+       RTREE_POLY_CACHE *result;\r
+       result = lwalloc(sizeof(RTREE_POLY_CACHE));\r
+       result->polyCount = 0;\r
+       result->ringCount = 0;\r
+       result->ringIndices = 0;\r
+       result->poly = 0;\r
+       return result;\r
+}\r
 \r
+void populateCache(RTREE_POLY_CACHE *currentCache, LWGEOM *lwgeom, uchar *serializedPoly)\r
+{\r
+       int i, j, k, length;\r
+       LWMPOLY *mpoly;\r
+       LWPOLY *poly;\r
+       int nrings;\r
+       \r
 #ifdef PGIS_DEBUG_CALLS\r
-        lwnotice("createNewCache called with %p", poly);\r
+    lwnotice("populateCache called with cache %p geom %p", currentCache, lwgeom);\r
 #endif\r
-        result = lwalloc(sizeof(RTREE_POLY_CACHE));\r
-        result->ringIndices = lwalloc(sizeof(RTREE_NODE *) * poly->nrings);\r
-        result->ringCount = poly->nrings;\r
-        length = lwgeom_size_poly(serializedPoly);\r
-        result->poly = lwalloc(length);\r
-        memcpy(result->poly, serializedPoly, length); \r
-        for(i = 0; i < result->ringCount; i++)\r
-        {\r
-                result->ringIndices[i] = createTree(poly->rings[i]);\r
-        }\r
-#ifdef PGIS_DEBUG\r
-        lwnotice("createNewCache returning %p", result);\r
+\r
+       if(TYPE_GETTYPE(lwgeom->type) == MULTIPOLYGONTYPE) \r
+       {\r
+#ifdef PGIS_DEBUG_CALLS\r
+               lwnotice("populateCache MULTIPOLYGON");\r
+#endif\r
+               mpoly = (LWMPOLY *)lwgeom;\r
+               nrings = 0;\r
+               /*\r
+               ** Count the total number of rings.\r
+               */\r
+               for( i = 0; i < mpoly->ngeoms; i++ ) \r
+               {\r
+                       nrings += mpoly->geoms[i]->nrings;\r
+               }\r
+               currentCache->polyCount = mpoly->ngeoms;\r
+               currentCache->ringCount = nrings;\r
+               currentCache->ringIndices = lwalloc(sizeof(RTREE_NODE *) * nrings);\r
+               /*\r
+               ** Load the exterior rings onto the ringIndices array first\r
+               */\r
+               for( i = 0; i < mpoly->ngeoms; i++ ) \r
+               {\r
+                       currentCache->ringIndices[i] = createTree(mpoly->geoms[i]->rings[0]);\r
+               }\r
+               /*\r
+               ** Load the interior rings (holes) onto ringIndices next\r
+               */\r
+               for( j = 0; j < mpoly->ngeoms; j++ )\r
+               {\r
+                       for( k = 1; k < mpoly->geoms[j]->nrings; k++ ) \r
+                       {\r
+                               currentCache->ringIndices[i] = createTree(mpoly->geoms[j]->rings[k]);\r
+                               i++;\r
+                       }\r
+               }\r
+       }\r
+       else if ( TYPE_GETTYPE(lwgeom->type) == POLYGONTYPE ) \r
+       {\r
+#ifdef PGIS_DEBUG_CALLS\r
+               lwnotice("populateCache POLYGON");\r
+#endif\r
+               poly = (LWPOLY *)lwgeom;\r
+               currentCache->polyCount = 1;\r
+               currentCache->ringCount = poly->nrings;\r
+               /*\r
+               ** Just load the rings on in order\r
+               */\r
+               currentCache->ringIndices = lwalloc(sizeof(RTREE_NODE *) * poly->nrings);\r
+               for( i = 0; i < poly->nrings; i++ ) \r
+               {\r
+                       currentCache->ringIndices[i] = createTree(poly->rings[i]);\r
+               }\r
+       }\r
+       else \r
+       {\r
+               /* Uh oh, shouldn't be here. */\r
+               return;\r
+       }\r
+\r
+       /*\r
+       ** Copy the serialized form of the polygon into the cache so\r
+       ** we can test for equality against subsequent polygons.\r
+       */\r
+       length = lwgeom_size(serializedPoly);\r
+       currentCache->poly = lwalloc(length);\r
+       memcpy(currentCache->poly, serializedPoly, length); \r
+#ifdef PGIS_DEBUG_CALLS\r
+       lwnotice("populateCache returning %p", currentCache);\r
 #endif\r
-        return result;\r
+\r
 }\r
 \r
 /* \r
@@ -418,10 +514,10 @@ RTREE_POLY_CACHE *createNewCache(LWPOLY *poly, uchar *serializedPoly)
  * method.  The method will allocate memory for the cache it creates,\r
  * as well as freeing the memory of any cache that is no longer applicable.\r
  */\r
-RTREE_POLY_CACHE *retrieveCache(LWPOLY *poly, uchar *serializedPoly, \r
+RTREE_POLY_CACHE *retrieveCache(LWGEOM *lwgeom, uchar *serializedPoly, \r
                 RTREE_POLY_CACHE *currentCache)\r
 {\r
-        int i, length;\r
+        int length;\r
 \r
 #ifdef PGIS_DEBUG_CALLS\r
         lwnotice("retrieveCache called with %p %p %p", poly, serializedPoly, currentCache);\r
@@ -431,51 +527,35 @@ RTREE_POLY_CACHE *retrieveCache(LWPOLY *poly, uchar *serializedPoly,
 #ifdef PGIS_DEBUG\r
                 lwnotice("No existing cache, create one.");\r
 #endif\r
-                return createNewCache(poly, serializedPoly);\r
+                               return createCache();\r
         }\r
         if(!(currentCache->poly))\r
         {\r
 #ifdef PGIS_DEBUG\r
-                lwnotice("Cache contains no polygon, creating new cache.");\r
+                lwnotice("Cache contains no polygon, populating it.");\r
 #endif\r
-                return createNewCache(poly, serializedPoly);\r
+                               populateCache(currentCache, lwgeom, serializedPoly);\r
+                               return currentCache;\r
         }\r
 \r
         length = lwgeom_size_poly(serializedPoly);\r
 \r
-        if(lwgeom_size_poly(currentCache->poly) != length)\r
+               if(lwgeom_size(currentCache->poly) != length)\r
         {\r
 #ifdef PGIS_DEBUG\r
                 lwnotice("Polygon size mismatch, creating new cache.");\r
 #endif\r
-                for(i = 0; i < currentCache->ringCount; i++)\r
-                {\r
-                        freeTree(currentCache->ringIndices[i]);\r
-                }\r
-                lwfree(currentCache->ringIndices);\r
-                lwfree(currentCache->poly);\r
-                lwfree(currentCache);\r
-                return createNewCache(poly, serializedPoly);\r
-        }\r
-        for(i = 0; i < length; i++) \r
-        {\r
-                uchar a = serializedPoly[i];\r
-                uchar b = currentCache->poly[i];\r
-                if(a != b) \r
-                {\r
+                               clearCache(currentCache);\r
+                               return currentCache;\r
+               }\r
+               if( memcmp(serializedPoly, currentCache->poly, length) ) \r
+               {\r
 #ifdef PGIS_DEBUG\r
-                        lwnotice("Polygon mismatch, creating new cache. %c, %c", a, b);\r
-#endif\r
-                        for(i = 0; i < currentCache->ringCount; i++)\r
-                        { \r
-                                freeTree(currentCache->ringIndices[i]);\r
-                        }\r
-                        lwfree(currentCache->ringIndices);\r
-                        lwfree(currentCache->poly);\r
-                        lwfree(currentCache);\r
-                        return createNewCache(poly, serializedPoly);\r
-                }\r
-        }\r
+                               lwnotice("Polygon mismatch, creating new cache. %c, %c", a, b);\r
+#endif\r
+                               clearCache(currentCache);\r
+                               return currentCache;\r
+               }\r
 \r
 #ifdef PGIS_DEBUG\r
         lwnotice("Polygon match, retaining current cache, %p.", currentCache);\r
index db17de7cc462cb0bc753a66c8c164d562761c043..cc694cfb269336c26d4a1af2dbc023320bcae4a6 100644 (file)
@@ -47,6 +47,7 @@ typedef struct
 {\r
         RTREE_NODE **ringIndices;\r
         int ringCount;\r
+        int polyCount;\r
         uchar *poly;\r
 } RTREE_POLY_CACHE;\r
 \r
@@ -54,6 +55,10 @@ typedef struct
  * Creates a new cachable index if needed, or returns the current cache if\r
  * it is applicable to the current polygon.\r
  */\r
-RTREE_POLY_CACHE *retrieveCache(LWPOLY *poly, uchar *serializedPoly, RTREE_POLY_CACHE *currentCache);\r
+RTREE_POLY_CACHE *retrieveCache(LWGEOM *lwgeom, uchar *serializedPoly, RTREE_POLY_CACHE *currentCache);\r
+RTREE_POLY_CACHE *createCache(void);\r
+/* Frees the cache. */\r
+void populateCache(RTREE_POLY_CACHE *cache, LWGEOM *lwgeom, uchar *serializedPoly);\r
+void clearCache(RTREE_POLY_CACHE *cache);\r
 \r
 #endif /* !defined _LIBLWGEOM_H */\r