]> granicus.if.org Git - postgis/commitdiff
Addition of rt_raster_overlaps and related regression tests. Fixed
authorBborie Park <bkpark at ucdavis.edu>
Thu, 19 Jul 2012 18:18:16 +0000 (18:18 +0000)
committerBborie Park <bkpark at ucdavis.edu>
Thu, 19 Jul 2012 18:18:16 +0000 (18:18 +0000)
memory leaks in rt_raster_surface.

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

raster/rt_core/rt_api.c
raster/rt_core/rt_api.h
raster/rt_pg/rt_pg.c
raster/test/core/testapi.c

index fb41b025d8adaa03de95ff717d675fd7679d3698..2dd11e011e2b78375bac1e3503636856088a565e 100644 (file)
@@ -11456,6 +11456,110 @@ rt_raster_intersects(
        return 1;
 }
 
+/**
+ * Return zero if error occurred in function.
+ * Parameter overlaps returns non-zero if two rasters overlap
+ *
+ * @param rast1 : the first raster whose band will be tested
+ * @param nband1 : the 0-based band of raster rast1 to use
+ *   if value is less than zero, bands are ignored.
+ *   if nband1 gte zero, nband2 must be gte zero
+ * @param rast2 : the second raster whose band will be tested
+ * @param nband2 : the 0-based band of raster rast2 to use
+ *   if value is less than zero, bands are ignored
+ *   if nband2 gte zero, nband1 must be gte zero
+ * @param overlaps : non-zero value if the two rasters' bands overlaps
+ *
+ * @return if zero, an error occurred in function
+ */
+int rt_raster_overlaps(
+       rt_raster rast1, int nband1,
+       rt_raster rast2, int nband2,
+       int *overlaps
+) {
+       LWMPOLY *surface1 = NULL;
+       LWMPOLY *surface2 = NULL;
+       GEOSGeometry *geom1 = NULL;
+       GEOSGeometry *geom2 = NULL;
+       int rtn = 0;
+
+       RASTER_DEBUG(3, "Starting");
+
+       assert(NULL != rast1);
+       assert(NULL != rast2);
+
+       if (nband1 < 0 && nband2 < 0) {
+               nband1 = -1;
+               nband2 = -1;
+       }
+       else {
+               assert(nband1 >= 0 && nband1 < rt_raster_get_num_bands(rast1));
+               assert(nband2 >= 0 && nband2 < rt_raster_get_num_bands(rast2));
+       }
+
+       /* initialize to zero, two rasters do not overlap */
+       *overlaps = 0;
+
+       /* same srid */
+       if (rt_raster_get_srid(rast1) != rt_raster_get_srid(rast2)) {
+               rterror("rt_raster_overlaps: The two rasters provided have different SRIDs");
+               return 0;
+       }
+
+       initGEOS(lwnotice, lwgeom_geos_error);
+
+       /* get LWMPOLY of each band */
+       surface1 = rt_raster_surface(rast1, nband1, &rtn);
+       if (!rtn) {
+               rterror("rt_raster_overlaps: Unable to get surface of the specified band from the first raster");
+               return 0;
+       }
+       surface2 = rt_raster_surface(rast2, nband2, &rtn);
+       if (!rtn) {
+               rterror("rt_raster_overlaps: Unable to get surface of the specified band from the second raster");
+               lwmpoly_free(surface1);
+               return 0;
+       }
+
+       /* either surface is NULL, does not overlap */
+       if (surface1 == NULL || surface2 == NULL) {
+               if (surface1 != NULL) lwmpoly_free(surface1);
+               if (surface2 != NULL) lwmpoly_free(surface2);
+               return 1;
+       }
+
+       /* convert LWMPOLY to GEOSGeometry */
+       geom1 = LWGEOM2GEOS(lwmpoly_as_lwgeom(surface1));
+       lwmpoly_free(surface1);
+       if (geom1 == NULL) {
+               rterror("rt_raster_overlaps: Unable to convert surface of the specified band from the first raster to a GEOSGeometry");
+               lwmpoly_free(surface2);
+               return 0;
+       }
+
+       geom2 = LWGEOM2GEOS(lwmpoly_as_lwgeom(surface2));
+       lwmpoly_free(surface2);
+       if (geom2 == NULL) {
+               rterror("rt_raster_overlaps: Unable to convert surface of the specified band from the second raster to a GEOSGeometry");
+               return 0;
+       }
+
+       rtn = GEOSOverlaps(geom1, geom2);
+       GEOSGeom_destroy(geom1);
+       GEOSGeom_destroy(geom2);
+
+       if (rtn != 2) {
+               RASTER_DEBUGF(4, "the two rasters do %soverlap", rtn != 1 ? "NOT " : "");
+               if (rtn != 0)
+                       *overlaps = 1;
+               return 1;
+       }
+       else
+               rterror("rt_raster_overlaps: Unable to run overlap test using GEOSOverlaps()");
+
+       return 0;
+}
+
 /*
  * Return zero if error occurred in function.
  * Paramter aligned returns non-zero if two rasters are aligned
@@ -11938,15 +12042,17 @@ rt_raster_pixel_as_polygon(rt_raster rast, int x, int y)
  * of the output multipolygon.
  *
  * @param raster: the raster to convert to a multipolygon
- * @param nband : the 0-based band of raster rast to use
+ * @param nband: the 0-based band of raster rast to use
  *   if value is less than zero, bands are ignored.
+ * @param err: if 0, error occurred
  *
- * @return the raster surface or NULL on error
+ * @return the raster surface or NULL
  */
-LWMPOLY* rt_raster_surface(rt_raster raster, int nband) {
+LWMPOLY* rt_raster_surface(rt_raster raster, int nband, int *err) {
        rt_band band = NULL;
        LWGEOM *mpoly = NULL;
        LWGEOM *tmp = NULL;
+       LWGEOM *clone = NULL;
        rt_geomval gv = NULL;
        int gvcount = 0;
        GEOSGeometry *gc = NULL;
@@ -11955,23 +12061,33 @@ LWMPOLY* rt_raster_surface(rt_raster raster, int nband) {
        int geomscount = 0;
        int i = 0;
 
+       /* initialize to 1, no error occurred */
+       *err = 1;
+
        /* raster is empty, return NULL */
        if (rt_raster_is_empty(raster))
                return NULL;
 
        /* if nband < 0, return the convex hull as a multipolygon */
        if (nband < 0) {
-               return lwgeom_as_lwmpoly(
-                       lwgeom_as_multi(
-                               lwpoly_as_lwgeom(
-                                       rt_raster_get_convex_hull(raster)
-                               )
-                       )
-               );
+               /*
+                       lwgeom_as_multi() only does a shallow clone internally
+                       so input and output geometries may share memory
+                       hence the deep clone of the output geometry for returning
+                       is the only way to guarentee the memory isn't shared
+               */
+               tmp = lwpoly_as_lwgeom(rt_raster_get_convex_hull(raster));
+               mpoly = lwgeom_as_multi(tmp);
+               clone = lwgeom_clone_deep(mpoly);
+               lwgeom_free(tmp);
+               lwgeom_free(mpoly);
+
+               return lwgeom_as_lwmpoly(clone);
        }
        /* check that nband is valid */
        else if (nband >= rt_raster_get_num_bands(raster)) {
                rterror("rt_raster_surface: The band index %d is invalid", nband);
+               *err = 0;
                return NULL;
        }
 
@@ -11979,6 +12095,7 @@ LWMPOLY* rt_raster_surface(rt_raster raster, int nband) {
        band = rt_raster_get_band(raster, nband);
        if (band == NULL) {
                rterror("rt_raster_surface: Error getting band %d from raster", nband);
+               *err = 0;
                return NULL;
        }
 
@@ -11987,13 +12104,19 @@ LWMPOLY* rt_raster_surface(rt_raster raster, int nband) {
                rt_band_get_isnodata_flag(band) || 
                !rt_band_get_hasnodata_flag(band)
        ) {
-               return lwgeom_as_lwmpoly(
-                       lwgeom_as_multi(
-                               lwpoly_as_lwgeom(
-                                       rt_raster_get_convex_hull(raster)
-                               )
-                       )
-               );
+               /*
+                       lwgeom_as_multi() only does a shallow clone internally
+                       so input and output geometries may share memory
+                       hence the deep clone of the output geometry for returning
+                       is the only way to guarentee the memory isn't shared
+               */
+               tmp = lwpoly_as_lwgeom(rt_raster_get_convex_hull(raster));
+               mpoly = lwgeom_as_multi(tmp);
+               clone = lwgeom_clone_deep(mpoly);
+               lwgeom_free(tmp);
+               lwgeom_free(mpoly);
+
+               return lwgeom_as_lwmpoly(clone);
        }
 
        /* initialize GEOS */
@@ -12004,6 +12127,7 @@ LWMPOLY* rt_raster_surface(rt_raster raster, int nband) {
        /* no polygons returned */
        if (gvcount < 1) {
                RASTER_DEBUG(3, "All pixels of band are NODATA.  Returning NULL");
+               if (gv != NULL) rtdealloc(gv);
                return NULL;
        }
        /* more than 1 polygon */
@@ -12015,6 +12139,7 @@ LWMPOLY* rt_raster_surface(rt_raster raster, int nband) {
                        rterror("rt_raster_surface: Unable to allocate memory for pixel polygons as GEOSGeometry");
                        for (i = 0; i < gvcount; i++) lwpoly_free(gv[i].geom);
                        rtdealloc(gv);
+                       *err = 0;
                        return NULL;
                }
                for (i = 0; i < gvcount; i++) {
@@ -12048,6 +12173,7 @@ LWMPOLY* rt_raster_surface(rt_raster raster, int nband) {
                        for (i = 0; i < geomscount; i++)
                                GEOSGeom_destroy(geoms[i]);
                        rtdealloc(geoms);
+                       *err = 0;
                        return NULL;
                }
 
@@ -12066,6 +12192,7 @@ LWMPOLY* rt_raster_surface(rt_raster raster, int nband) {
 #else
                        rterror("rt_raster_surface: Unable to union the pixel polygons using GEOSUnionCascaded()");
 #endif
+                       *err = 0;
                        return NULL;
                }
 
@@ -12111,7 +12238,6 @@ LWMPOLY* rt_raster_surface(rt_raster raster, int nband) {
        if (mpoly != NULL) {
                /* convert to multi */
                if (!lwgeom_is_collection(mpoly)) {
-                       LWGEOM *tmp2 = NULL;
                        tmp = mpoly;
 
 #if POSTGIS_DEBUG_LEVEL > 3
@@ -12131,10 +12257,10 @@ LWMPOLY* rt_raster_surface(rt_raster raster, int nband) {
                                is the only way to guarentee the memory isn't shared
                        */
                        mpoly = lwgeom_as_multi(tmp);
-                       tmp2 = lwgeom_clone_deep(mpoly);
+                       clone = lwgeom_clone_deep(mpoly);
                        lwgeom_free(tmp);
                        lwgeom_free(mpoly);
-                       mpoly = tmp2;
+                       mpoly = clone;
 
                        RASTER_DEBUGF(4, "mpoly @ %p", mpoly);
 
index e4740d1cce19a2648a735895d2930f5ef13cbb9d..c6ef5b160efe48340afa79a39fbb94ef73d194fb 100644 (file)
@@ -1177,12 +1177,13 @@ LWPOLY* rt_raster_pixel_as_polygon(rt_raster raster, int x, int y);
  * of the output multipolygon.
  *
  * @param raster: the raster to convert to a multipolygon
- * @param nband : the 0-based band of raster rast to use
+ * @param nband: the 0-based band of raster rast to use
  *   if value is less than zero, bands are ignored.
+ * @param err: if 0, error occurred
  *
- * @return the raster surface or NULL on error
+ * @return the raster surface or NULL
  */
-LWMPOLY* rt_raster_surface(rt_raster raster, int nband);
+LWMPOLY* rt_raster_surface(rt_raster raster, int nband, int *err);
 
 /**
  * Returns a set of "geomval" value, one for each group of pixel
@@ -1449,6 +1450,28 @@ int rt_raster_intersects(
        int *intersects
 );
 
+/**
+ * Return zero if error occurred in function.
+ * Parameter overlaps returns non-zero if two rasters overlap
+ *
+ * @param rast1 : the first raster whose band will be tested
+ * @param nband1 : the 0-based band of raster rast1 to use
+ *   if value is less than zero, bands are ignored.
+ *   if nband1 gte zero, nband2 must be gte zero
+ * @param rast2 : the second raster whose band will be tested
+ * @param nband2 : the 0-based band of raster rast2 to use
+ *   if value is less than zero, bands are ignored
+ *   if nband2 gte zero, nband1 must be gte zero
+ * @param overlaps : non-zero value if the two rasters' bands overlaps
+ *
+ * @return if zero, an error occurred in function
+ */
+int rt_raster_overlaps(
+       rt_raster rast1, int nband1,
+       rt_raster rast2, int nband2,
+       int *overlaps
+);
+
 /*
  * Return zero if error occurred in function.
  * Paramter aligned returns non-zero if two rasters are aligned
index 80661614317744d4f7617e93608816f80eedd12a..0bb727d8e89516f678695549348330d9293a6bbf 100644 (file)
@@ -2754,6 +2754,7 @@ Datum RASTER_getPolygon(PG_FUNCTION_ARGS)
        rt_raster raster = NULL;
        int num_bands = 0;
        int nband = 1;
+       int err;
        LWMPOLY *surface = NULL;
        GSERIALIZED *rtn = NULL;
 
@@ -2789,14 +2790,18 @@ Datum RASTER_getPolygon(PG_FUNCTION_ARGS)
        }
 
        /* get band surface */
-       surface = rt_raster_surface(raster, nband - 1);
+       surface = rt_raster_surface(raster, nband - 1, &err);
        rt_raster_destroy(raster);
        PG_FREE_IF_COPY(pgraster, 0);
 
-       if (surface == NULL) {
+       if (!err) {
                elog(ERROR, "RASTER_getPolygon: Could not get raster band's surface");
                PG_RETURN_NULL();
        }
+       else if (surface == NULL) {
+               elog(NOTICE, "Raster is empty or all pixels of band are NODATA. Returning NULL");
+               PG_RETURN_NULL();
+       }
 
        rtn = geometry_serialize(lwmpoly_as_lwgeom(surface));
        lwmpoly_free(surface);
index f3fc9a794c7239f3528357156ec19e730accf396..620b5bafc45e4e0a4c5c41d08841483b7c371f40 100644 (file)
@@ -2375,6 +2375,477 @@ static void testIntersects() {
        deepRelease(rast1);
 }
 
+static void testOverlaps() {
+       rt_raster rast1;
+       rt_raster rast2;
+       rt_band band1;
+       rt_band band2;
+       double nodata;
+       int rtn;
+       int overlaps;
+
+       /*
+               rast1
+
+               (-1, -1)
+                                               +-+-+
+                                               |1|1|
+                                               +-+-+
+                                               |1|1|
+                                               +-+-+
+                                                               (1, 1)
+       */
+       rast1 = rt_raster_new(2, 2);
+       assert(rast1);
+       rt_raster_set_offsets(rast1, -1, -1);
+
+       band1 = addBand(rast1, PT_8BUI, 1, 0);
+       CHECK(band1);
+       rt_band_set_nodata(band1, 0);
+       rtn = rt_band_set_pixel(band1, 0, 0, 1);
+       rtn = rt_band_set_pixel(band1, 0, 1, 1);
+       rtn = rt_band_set_pixel(band1, 1, 0, 1);
+       rtn = rt_band_set_pixel(band1, 1, 1, 1);
+
+       nodata = rt_band_get_nodata(band1);
+       CHECK_EQUALS(nodata, 0);
+
+       rtn = rt_raster_overlaps(
+               rast1, 0,
+               rast1, 0,
+               &overlaps
+       );
+       CHECK((rtn != 0));
+       CHECK((overlaps != 1));
+
+       /*
+               rast2
+
+               (0, 0)
+                                               +-+-+
+                                               |1|1|
+                                               +-+-+
+                                               |1|1|
+                                               +-+-+
+                                                               (2, 2)
+       */
+       rast2 = rt_raster_new(2, 2);
+       assert(rast2);
+
+       band2 = addBand(rast2, PT_8BUI, 1, 0);
+       CHECK(band2);
+       rt_band_set_nodata(band2, 0);
+       rtn = rt_band_set_pixel(band2, 0, 0, 1);
+       rtn = rt_band_set_pixel(band2, 0, 1, 1);
+       rtn = rt_band_set_pixel(band2, 1, 0, 1);
+       rtn = rt_band_set_pixel(band2, 1, 1, 1);
+
+       nodata = rt_band_get_nodata(band2);
+       CHECK_EQUALS(nodata, 0);
+
+       rtn = rt_raster_overlaps(
+               rast1, 0,
+               rast2, 0,
+               &overlaps
+       );
+       CHECK((rtn != 0));
+       CHECK((overlaps == 1));
+
+       rtn = rt_raster_overlaps(
+               rast1, -1,
+               rast2, -1,
+               &overlaps
+       );
+       CHECK((rtn != 0));
+       CHECK((overlaps == 1));
+
+       /*
+               rast2
+
+               (0, 0)
+                                               +-+-+
+                                               |0|1|
+                                               +-+-+
+                                               |1|1|
+                                               +-+-+
+                                                               (2, 2)
+       */
+       rtn = rt_band_set_pixel(band2, 0, 0, 0);
+
+       rtn = rt_raster_overlaps(
+               rast1, 0,
+               rast2, 0,
+               &overlaps
+       );
+       CHECK((rtn != 0));
+       CHECK((overlaps != 1));
+
+       /*
+               rast2
+
+               (0, 0)
+                                               +-+-+
+                                               |1|0|
+                                               +-+-+
+                                               |1|1|
+                                               +-+-+
+                                                               (2, 2)
+       */
+       rtn = rt_band_set_pixel(band2, 0, 0, 1);
+       rtn = rt_band_set_pixel(band2, 1, 0, 0);
+
+       rtn = rt_raster_overlaps(
+               rast1, 0,
+               rast2, 0,
+               &overlaps
+       );
+       CHECK((rtn != 0));
+       CHECK((overlaps == 1));
+
+       /*
+               rast2
+
+               (0, 0)
+                                               +-+-+
+                                               |0|0|
+                                               +-+-+
+                                               |0|1|
+                                               +-+-+
+                                                               (2, 2)
+       */
+       rtn = rt_band_set_pixel(band2, 0, 0, 0);
+       rtn = rt_band_set_pixel(band2, 1, 0, 0);
+       rtn = rt_band_set_pixel(band2, 0, 1, 0);
+
+       rtn = rt_raster_overlaps(
+               rast1, 0,
+               rast2, 0,
+               &overlaps
+       );
+       CHECK((rtn != 0));
+       CHECK((overlaps != 1));
+
+       /*
+               rast2
+
+               (0, 0)
+                                               +-+-+
+                                               |0|0|
+                                               +-+-+
+                                               |0|0|
+                                               +-+-+
+                                                               (2, 2)
+       */
+       rtn = rt_band_set_pixel(band2, 0, 0, 0);
+       rtn = rt_band_set_pixel(band2, 1, 0, 0);
+       rtn = rt_band_set_pixel(band2, 0, 1, 0);
+       rtn = rt_band_set_pixel(band2, 1, 1, 0);
+
+       rtn = rt_raster_overlaps(
+               rast1, 0,
+               rast2, 0,
+               &overlaps
+       );
+       CHECK((rtn != 0));
+       CHECK((overlaps != 1));
+
+       /*
+               rast2
+
+               (2, 0)
+                                               +-+-+
+                                               |1|1|
+                                               +-+-+
+                                               |1|1|
+                                               +-+-+
+                                                               (4, 2)
+       */
+       rt_raster_set_offsets(rast2, 2, 0);
+
+       rtn = rt_band_set_pixel(band2, 0, 0, 1);
+       rtn = rt_band_set_pixel(band2, 1, 0, 1);
+       rtn = rt_band_set_pixel(band2, 0, 1, 1);
+       rtn = rt_band_set_pixel(band2, 1, 1, 1);
+
+       rtn = rt_raster_overlaps(
+               rast1, 0,
+               rast2, 0,
+               &overlaps
+       );
+       CHECK((rtn != 0));
+       CHECK((overlaps != 1));
+
+       /*
+               rast2
+
+               (0.1, 0.1)
+                                               +-+-+
+                                               |1|1|
+                                               +-+-+
+                                               |1|1|
+                                               +-+-+
+                                                               (0.9, 0.9)
+       */
+       rt_raster_set_offsets(rast2, 0.1, 0.1);
+       rt_raster_set_scale(rast2, 0.4, 0.4);
+
+       rtn = rt_band_set_pixel(band2, 0, 0, 1);
+       rtn = rt_band_set_pixel(band2, 1, 0, 1);
+       rtn = rt_band_set_pixel(band2, 0, 1, 1);
+       rtn = rt_band_set_pixel(band2, 1, 1, 1);
+
+       rtn = rt_raster_overlaps(
+               rast1, 0,
+               rast2, 0,
+               &overlaps
+       );
+       CHECK((rtn != 0));
+       CHECK((overlaps != 1));
+
+       /*
+               rast2
+
+               (-0.1, 0.1)
+                                               +-+-+
+                                               |1|1|
+                                               +-+-+
+                                               |1|1|
+                                               +-+-+
+                                                               (0.9, 0.9)
+       */
+       rt_raster_set_offsets(rast2, -0.1, 0.1);
+
+       rtn = rt_raster_overlaps(
+               rast1, 0,
+               rast2, 0,
+               &overlaps
+       );
+       CHECK((rtn != 0));
+       CHECK((overlaps != 1));
+
+       deepRelease(rast2);
+
+       /*
+               rast2
+
+               (0, 0)
+                                               +-+-+-+
+                                               |1|1|1|
+                                               +-+-+-+
+                                               |1|1|1|
+                                               +-+-+-+
+                                               |1|1|1|
+                                               +-+-+-+
+                                                                       (3, 3)
+       */
+       rast2 = rt_raster_new(3, 3);
+       assert(rast2);
+
+       band2 = addBand(rast2, PT_8BUI, 1, 0);
+       CHECK(band2);
+       rt_band_set_nodata(band2, 0);
+       rtn = rt_band_set_pixel(band2, 0, 0, 1);
+       rtn = rt_band_set_pixel(band2, 0, 1, 1);
+       rtn = rt_band_set_pixel(band2, 0, 2, 1);
+       rtn = rt_band_set_pixel(band2, 1, 0, 1);
+       rtn = rt_band_set_pixel(band2, 1, 1, 1);
+       rtn = rt_band_set_pixel(band2, 1, 2, 1);
+       rtn = rt_band_set_pixel(band2, 2, 0, 1);
+       rtn = rt_band_set_pixel(band2, 2, 1, 1);
+       rtn = rt_band_set_pixel(band2, 2, 2, 1);
+
+       nodata = rt_band_get_nodata(band2);
+       CHECK_EQUALS(nodata, 0);
+
+       rtn = rt_raster_overlaps(
+               rast1, 0,
+               rast2, 0,
+               &overlaps
+       );
+       CHECK((rtn != 0));
+       CHECK((overlaps == 1));
+
+       /*
+               rast2
+
+               (-2, -2)
+                                               +-+-+-+
+                                               |1|1|1|
+                                               +-+-+-+
+                                               |1|1|1|
+                                               +-+-+-+
+                                               |1|1|1|
+                                               +-+-+-+
+                                                                       (1, 1)
+       */
+       rt_raster_set_offsets(rast2, -2, -2);
+
+       rtn = rt_band_set_pixel(band2, 0, 0, 1);
+       rtn = rt_band_set_pixel(band2, 0, 1, 1);
+       rtn = rt_band_set_pixel(band2, 0, 2, 1);
+       rtn = rt_band_set_pixel(band2, 1, 0, 1);
+       rtn = rt_band_set_pixel(band2, 1, 1, 1);
+       rtn = rt_band_set_pixel(band2, 1, 2, 1);
+       rtn = rt_band_set_pixel(band2, 2, 0, 1);
+       rtn = rt_band_set_pixel(band2, 2, 1, 1);
+       rtn = rt_band_set_pixel(band2, 2, 2, 1);
+
+       rtn = rt_raster_overlaps(
+               rast1, 0,
+               rast2, 0,
+               &overlaps
+       );
+       CHECK((rtn != 0));
+       CHECK((overlaps != 1));
+
+       /*
+               rast2
+
+               (-2, -2)
+                                               +-+-+-+
+                                               |0|1|1|
+                                               +-+-+-+
+                                               |1|0|1|
+                                               +-+-+-+
+                                               |1|1|0|
+                                               +-+-+-+
+                                                                       (1, 1)
+       */
+       rtn = rt_band_set_pixel(band2, 0, 0, 0);
+       rtn = rt_band_set_pixel(band2, 0, 1, 1);
+       rtn = rt_band_set_pixel(band2, 0, 2, 1);
+       rtn = rt_band_set_pixel(band2, 1, 0, 1);
+       rtn = rt_band_set_pixel(band2, 1, 1, 0);
+       rtn = rt_band_set_pixel(band2, 1, 2, 1);
+       rtn = rt_band_set_pixel(band2, 2, 0, 1);
+       rtn = rt_band_set_pixel(band2, 2, 1, 1);
+       rtn = rt_band_set_pixel(band2, 2, 2, 0);
+
+       rtn = rt_raster_overlaps(
+               rast1, 0,
+               rast2, 0,
+               &overlaps
+       );
+       CHECK((rtn != 0));
+       CHECK((overlaps == 1));
+
+       /*
+               rast2
+
+               (-2, -2)
+                                               +-+-+-+
+                                               |0|1|1|
+                                               +-+-+-+
+                                               |1|0|0|
+                                               +-+-+-+
+                                               |1|0|0|
+                                               +-+-+-+
+                                                                       (1, 1)
+       */
+       rtn = rt_band_set_pixel(band2, 0, 0, 0);
+       rtn = rt_band_set_pixel(band2, 0, 1, 1);
+       rtn = rt_band_set_pixel(band2, 0, 2, 1);
+       rtn = rt_band_set_pixel(band2, 1, 0, 1);
+       rtn = rt_band_set_pixel(band2, 1, 1, 0);
+       rtn = rt_band_set_pixel(band2, 1, 2, 0);
+       rtn = rt_band_set_pixel(band2, 2, 0, 1);
+       rtn = rt_band_set_pixel(band2, 2, 1, 0);
+       rtn = rt_band_set_pixel(band2, 2, 2, 0);
+
+       rtn = rt_raster_overlaps(
+               rast1, 0,
+               rast2, 0,
+               &overlaps
+       );
+       CHECK((rtn != 0));
+       CHECK((overlaps != 1));
+
+       /*
+               rast2
+
+               (-2, -2)
+                                               +-+-+-+
+                                               |0|1|0|
+                                               +-+-+-+
+                                               |1|0|0|
+                                               +-+-+-+
+                                               |0|0|0|
+                                               +-+-+-+
+                                                                       (1, 1)
+       */
+       rtn = rt_band_set_pixel(band2, 0, 0, 0);
+       rtn = rt_band_set_pixel(band2, 0, 1, 1);
+       rtn = rt_band_set_pixel(band2, 0, 2, 0);
+       rtn = rt_band_set_pixel(band2, 1, 0, 1);
+       rtn = rt_band_set_pixel(band2, 1, 1, 0);
+       rtn = rt_band_set_pixel(band2, 1, 2, 0);
+       rtn = rt_band_set_pixel(band2, 2, 0, 0);
+       rtn = rt_band_set_pixel(band2, 2, 1, 0);
+       rtn = rt_band_set_pixel(band2, 2, 2, 0);
+
+       rtn = rt_raster_overlaps(
+               rast1, 0,
+               rast2, 0,
+               &overlaps
+       );
+       CHECK((rtn != 0));
+       CHECK((overlaps != 1));
+
+       deepRelease(rast2);
+
+       /* skew tests */
+       /* rast2 (skewed by -0.5, 0.5) */
+       rast2 = rt_raster_new(3, 3);
+       assert(rast2);
+       rt_raster_set_skews(rast2, -0.5, 0.5);
+
+       band2 = addBand(rast2, PT_8BUI, 1, 0);
+       CHECK(band2);
+       rt_band_set_nodata(band2, 0);
+       rtn = rt_band_set_pixel(band2, 0, 0, 1);
+       rtn = rt_band_set_pixel(band2, 0, 1, 2);
+       rtn = rt_band_set_pixel(band2, 0, 2, 3);
+       rtn = rt_band_set_pixel(band2, 1, 0, 1);
+       rtn = rt_band_set_pixel(band2, 1, 1, 2);
+       rtn = rt_band_set_pixel(band2, 1, 2, 3);
+       rtn = rt_band_set_pixel(band2, 2, 0, 1);
+       rtn = rt_band_set_pixel(band2, 2, 1, 2);
+       rtn = rt_band_set_pixel(band2, 2, 2, 3);
+
+       rtn = rt_raster_overlaps(
+               rast1, 0,
+               rast2, 0,
+               &overlaps
+       );
+       CHECK((rtn != 0));
+       CHECK((overlaps == 1));
+
+       /* rast2 (skewed by -1, 1) */
+       rt_raster_set_skews(rast2, -1, 1);
+
+       rtn = rt_raster_overlaps(
+               rast1, 0,
+               rast2, 0,
+               &overlaps
+       );
+       CHECK((rtn != 0));
+       CHECK((overlaps == 1));
+
+       /* rast2 (skewed by 1, -1) */
+       rt_raster_set_skews(rast2, 1, -1);
+
+       rtn = rt_raster_overlaps(
+               rast1, 0,
+               rast2, 0,
+               &overlaps
+       );
+       CHECK((rtn != 0));
+       CHECK((overlaps == 1));
+
+       deepRelease(rast2);
+       deepRelease(rast1);
+}
+
 static void testAlignment() {
        rt_raster rast1;
        rt_raster rast2;
@@ -2949,6 +3420,7 @@ static void testRasterSurface() {
        int x, y;
        char *wkt = NULL;
        LWMPOLY *mpoly = NULL;
+       int err;
 
        rast = rt_raster_new(maxX, maxY);
        assert(rast);
@@ -2965,7 +3437,8 @@ static void testRasterSurface() {
                }
        }
 
-       mpoly = rt_raster_surface(rast, 0);
+       mpoly = rt_raster_surface(rast, 0, &err);
+       CHECK(err);
        CHECK((mpoly != NULL));
        wkt = lwgeom_to_text(lwmpoly_as_lwgeom(mpoly));
        CHECK(!strcmp(wkt, "MULTIPOLYGON(((0 0,0 -5,5 -5,5 0,0 0)))"));
@@ -2976,7 +3449,8 @@ static void testRasterSurface() {
        /* 0,0 NODATA */
        rt_band_set_pixel(band, 0, 0, 0);
 
-       mpoly = rt_raster_surface(rast, 0);
+       mpoly = rt_raster_surface(rast, 0, &err);
+       CHECK(err);
        CHECK((mpoly != NULL));
        wkt = lwgeom_to_text(lwmpoly_as_lwgeom(mpoly));
        CHECK(!strcmp(wkt, "MULTIPOLYGON(((1 0,1 -1,0 -1,0 -5,4 -5,5 -5,5 0,1 0)))"));
@@ -2987,7 +3461,8 @@ static void testRasterSurface() {
        /* plus 1,1 NODATA */
        rt_band_set_pixel(band, 1, 1, 0);
 
-       mpoly = rt_raster_surface(rast, 0);
+       mpoly = rt_raster_surface(rast, 0, &err);
+       CHECK(err);
        CHECK((mpoly != NULL));
        wkt = lwgeom_to_text(lwmpoly_as_lwgeom(mpoly));
        CHECK(!strcmp(wkt, "MULTIPOLYGON(((1 0,1 -1,0 -1,0 -5,4 -5,5 -5,5 0,1 0),(1 -1,1 -2,2 -2,2 -1,1 -1)))"));
@@ -2998,7 +3473,8 @@ static void testRasterSurface() {
        /* plus 2,2 NODATA */
        rt_band_set_pixel(band, 2, 2, 0);
 
-       mpoly = rt_raster_surface(rast, 0);
+       mpoly = rt_raster_surface(rast, 0, &err);
+       CHECK(err);
        CHECK((mpoly != NULL));
        wkt = lwgeom_to_text(lwmpoly_as_lwgeom(mpoly));
 #if POSTGIS_GEOS_VERSION >= 33
@@ -3013,7 +3489,8 @@ static void testRasterSurface() {
        /* plus 3,3 NODATA */
        rt_band_set_pixel(band, 3, 3, 0);
 
-       mpoly = rt_raster_surface(rast, 0);
+       mpoly = rt_raster_surface(rast, 0, &err);
+       CHECK(err);
        CHECK((mpoly != NULL));
        wkt = lwgeom_to_text(lwmpoly_as_lwgeom(mpoly));
 #if POSTGIS_GEOS_VERSION >= 33
@@ -3028,7 +3505,8 @@ static void testRasterSurface() {
        /* plus 4,4 NODATA */
        rt_band_set_pixel(band, 4, 4, 0);
 
-       mpoly = rt_raster_surface(rast, 0);
+       mpoly = rt_raster_surface(rast, 0, &err);
+       CHECK(err);
        CHECK((mpoly != NULL));
        wkt = lwgeom_to_text(lwmpoly_as_lwgeom(mpoly));
        CHECK(!strcmp(wkt, "MULTIPOLYGON(((4 -4,4 -5,0 -5,0 -1,1 -1,1 -2,2 -2,2 -3,3 -3,3 -4,4 -4)),((1 -1,1 0,5 0,5 -4,4 -4,4 -3,3 -3,3 -2,2 -2,2 -1,1 -1)))"));
@@ -3042,7 +3520,8 @@ static void testRasterSurface() {
        rt_band_set_pixel(band, 1, 3, 0);
        rt_band_set_pixel(band, 0, 4, 0);
 
-       mpoly = rt_raster_surface(rast, 0);
+       mpoly = rt_raster_surface(rast, 0, &err);
+       CHECK(err);
        CHECK((mpoly != NULL));
        wkt = lwgeom_to_text(lwmpoly_as_lwgeom(mpoly));
        CHECK(!strcmp(wkt, "MULTIPOLYGON(((1 -4,2 -4,2 -3,3 -3,3 -4,4 -4,4 -5,3 -5,1 -5,1 -4)),((1 -4,0 -4,0 -1,1 -1,1 -2,2 -2,2 -3,1 -3,1 -4)),((3 -2,4 -2,4 -1,5 -1,5 -4,4 -4,4 -3,3 -3,3 -2)),((3 -2,2 -2,2 -1,1 -1,1 0,4 0,4 -1,3 -1,3 -2)))"));
@@ -3303,6 +3782,10 @@ main()
                testIntersects();
                printf("OK\n");
 
+               printf("Testing rt_raster_overlaps... ");
+               testOverlaps();
+               printf("OK\n");
+
                printf("Testing rt_raster_same_alignment... ");
                testAlignment();
                printf("OK\n");