* 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;
* 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;
* 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;
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.");
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);
}
/*
- * 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;
}
-*/
/*******************************************************************************
/* #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);
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)
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)
bool result;
BOX2DFLOAT4 box1, box2;
int type1, type2;
- LWPOLY *poly;
+ LWGEOM *lwgeom;
/* LWMPOLY *mpoly; */
LWPOINT *point;
RTREE_POLY_CACHE *poly_cache;
* 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
*/
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);
* 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
bool result;
BOX2DFLOAT4 box1, box2;
int type1, type2;
- LWPOLY *poly;
+ LWGEOM *lwgeom;
/* LWMPOLY *mpoly; */
LWPOINT *point;
RTREE_POLY_CACHE *poly_cache;
*/
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);
* 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
{
GEOSGeom g1,g2;
bool result;
BOX2DFLOAT4 box1, box2;
- LWPOLY *poly;
+ LWGEOM *lwgeom;
LWPOINT *point;
int type1, type2;
MemoryContext old_context;
*/
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,
* 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);
GEOSGeom g1,g2;
bool result;
BOX2DFLOAT4 box1, box2;
- LWPOLY *poly;
+ LWGEOM *lwgeom;
LWPOINT *point;
int type1, type2;
MemoryContext old_context;
*/
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,
* 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);
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;
*/
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);
}
-
}
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);
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
}\r
\r
root = nodes[0];\r
+ lwfree(nodes);\r
\r
#ifdef PGIS_DEBUG\r
lwnotice("createTree returning %p", root);\r
#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
\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
* 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
#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