]> granicus.if.org Git - postgis/commitdiff
Further tweaks to rt_raster_gdal_rasterize to correctly handle auto-computed extents...
authorBborie Park <bkpark at ucdavis.edu>
Thu, 22 Sep 2011 15:07:25 +0000 (15:07 +0000)
committerBborie Park <bkpark at ucdavis.edu>
Thu, 22 Sep 2011 15:07:25 +0000 (15:07 +0000)
Associated ticket is #1176

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

raster/rt_core/rt_api.c
raster/rt_core/rt_api.h
raster/rt_pg/rt_pg.c
raster/rt_pg/rtpostgis.sql.in.c
raster/test/core/testapi.c
raster/test/regress/Makefile.in
raster/test/regress/rt_intersects.sql [new file with mode: 0644]
raster/test/regress/rt_intersects_expected [new file with mode: 0644]
raster/test/regress/rt_spatial_relationship.sql
raster/test/regress/rt_spatial_relationship_expected

index c1608f9f6da55a154b69f8061cba7f4e1805d635..0935fe6d8b80ae41ccd413b7c65aaf2b472b55b0 100644 (file)
@@ -768,29 +768,6 @@ rt_pixtype_name(rt_pixtype pixtype) {
 
 /*- rt_band ----------------------------------------------------------*/
 
-struct rt_extband_t {
-    uint8_t bandNum;
-    char* path; /* externally owned ? */
-};
-
-struct rt_band_t {
-    rt_pixtype pixtype;
-    int32_t offline;
-    uint16_t width;
-    uint16_t height;
-    int32_t hasnodata; /* a flag indicating if this band contains nodata values */
-    int32_t isnodata;   /* a flag indicating if this band is filled only with
-                           nodata values */
-    double nodataval; /* int will be converted ... */
-    int32_t ownsData; /* XXX mloskot: its behaviour needs to be documented */
-
-    union {
-        void* mem; /* actual data, externally owned */
-        struct rt_extband_t offline;
-    } data;
-
-};
-
 rt_band
 rt_band_new_inline(uint16_t width, uint16_t height,
         rt_pixtype pixtype, uint32_t hasnodata, double nodataval,
@@ -1051,7 +1028,9 @@ rt_band_get_isnodata_flag(rt_band band) {
 int
 rt_band_set_nodata(rt_band band, double val) {
     rt_pixtype pixtype = PT_END;
-    //double oldnodataval = band->nodataval;
+    /*
+               double oldnodataval = band->nodataval;
+               */
 
     int32_t checkvalint = 0;
     uint32_t checkvaluint = 0;
@@ -1146,7 +1125,7 @@ rt_band_set_nodata(rt_band band, double val) {
     RASTER_DEBUGF(3, "rt_band_set_nodata: band->nodataval = %f", band->nodataval);
 
 
-    // the nodata value was just set, so this band has NODATA
+    /* the nodata value was just set, so this band has NODATA */
     rt_band_set_hasnodata_flag(band, 1);
 
 #ifdef POSTGIS_RASTER_WARN_ON_TRUNCATION
@@ -4010,26 +3989,112 @@ rt_raster_generate_new_band(rt_raster raster, rt_pixtype pixtype,
     return index;
 }
 
-
+/**
+ * Convert an xr, yr raster point to an xw, yw point on map
+ *
+ * @param raster : the raster to get info from
+ * @param xr : the pixel's column
+ * @param yr : the pixel's row
+ * @param xw : output parameter, X ordinate of the geographical point
+ * @param yw : output parameter, Y ordinate of the geographical point
+ */
 void
 rt_raster_cell_to_geopoint(rt_raster raster,
-        double x, double y,
-        double* x1, double* y1) {
+       double xr, double yr,
+       double* xw, double* yw
+) {
+       assert(NULL != raster);
+       assert(NULL != xw);
+       assert(NULL != yw);
 
+       /* Six parameters affine transformation */
+       *xw = raster->scaleX * xr + raster->skewX * yr + raster->ipX;
+       *yw = raster->scaleY * yr + raster->skewY * xr + raster->ipY;
 
-    assert(NULL != raster);
-    assert(NULL != x1);
-    assert(NULL != y1);
+       RASTER_DEBUGF(3, "rt_raster_cell_to_geopoint(%g, %g) = %g, %g",
+               xr, yr, *xw, *yw);
 
-    /* Six parameters affine transformation */
-    *x1 = raster->scaleX * x + raster->skewX * y + raster->ipX;
-    *y1 = raster->scaleY * y + raster->skewY * x + raster->ipY;
+       /*
+       {
+               double gt[] = {0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
+               double x1;
+               double y1;
+
+               gt[0] = rt_raster_get_x_offset(raster);
+               gt[1] = rt_raster_get_x_scale(raster);
+               gt[2] = rt_raster_get_x_skew(raster);
+               gt[3] = rt_raster_get_y_offset(raster);
+               gt[4] = rt_raster_get_y_skew(raster);
+               gt[5] = rt_raster_get_y_scale(raster);
+
+               GDALApplyGeoTransform(gt, xr, yr, &x1, &y1);
+               RASTER_DEBUGF(4, "GDALApplyGeoTransform for (%f, %f) = (%f, %f)",
+                       xr, yr, x1, y1);
+       }
+       */
+}
 
-    RASTER_DEBUGF(3, "rt_raster_cell_to_geopoint(%g,%g)", x, y);
-    RASTER_DEBUGF(3, " ipx/y:%g/%g", raster->ipX, raster->ipY);
-    RASTER_DEBUGF(3, "cell_to_geopoint: ipX:%g, ipY:%g, %g,%g -> %g,%g",
-            raster->ipX, raster->ipY, x, y, *x1, *y1);
+/**
+ * Convert an xw,yw map point to a xr,yr raster point
+ *
+ * @param raster : the raster to get info from
+ * @param xw : X ordinate of the geographical point
+ * @param yw : Y ordinate of the geographical point
+ * @param xr : output parameter, the pixel's column
+ * @param yr : output parameter, the pixel's row
+ *
+ * @return if zero, error occurred in function
+ */
+int
+rt_raster_geopoint_to_cell(rt_raster raster,
+       double xw, double yw,
+       double *xr, double *yr
+) {
+       double d;
+
+       assert(NULL != raster);
+       assert(NULL != xr);
+       assert(NULL != yr);
+
+       /* Six parameters affine transformation */
+       d = raster->skewX * raster->skewY - raster->scaleX * raster->scaleY;
+       if (FLT_EQ(d, 0)) {
+               rterror("rt_raster_geopoint_to_cell: Attempting to compute coordinates on a raster with scale equal to 0");
+               return 0;
+       }
+
+       *xr = (raster->skewX * (yw - raster->ipY) - raster->scaleY * (xw - raster->ipX)) / d;
+       *yr = (raster->scaleX * (yw - raster->ipY) + raster->skewY * (raster->ipX - xw)) / (-1 * d);
+
+       *xr = floor(*xr);
+       *yr = floor(*yr);
+
+       RASTER_DEBUGF(3, "rt_raster_geopoint_to_cell(%g, %g) = %g, %g",
+               xw, yw, *xr, *yr);
+
+       /*
+       {
+               double gt[] = {0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
+               double igt[6];
+               double x1;
+               double y1;
+
+               gt[0] = rt_raster_get_x_offset(raster);
+               gt[1] = rt_raster_get_x_scale(raster);
+               gt[2] = rt_raster_get_x_skew(raster);
+               gt[3] = rt_raster_get_y_offset(raster);
+               gt[4] = rt_raster_get_y_skew(raster);
+               gt[5] = rt_raster_get_y_scale(raster);
 
+               GDALInvGeoTransform(gt, igt);
+
+               GDALApplyGeoTransform(igt, xw, yw, &x1, &y1);
+               RASTER_DEBUGF(4, "GDALApplyGeoTransform for (%f, %f) = (%f, %f)",
+                       xw, yw, x1, y1);
+       }
+       */
+
+       return 1;
 }
 
 rt_geomval
@@ -4270,7 +4335,7 @@ rt_raster_dump_as_wktpolygons(rt_raster raster, int nband, int * pnElements)
          * postgresql memory context to work with, and the memory created
          * for pszSrcText is created outside this context.
          **/
-         //rtdealloc(pszSrcText);
+        /*rtdealloc(pszSrcText);*/
         free(pszSrcText);
         pszSrcText = NULL;
 
@@ -4883,7 +4948,7 @@ rt_band_from_wkb(uint16_t width, uint16_t height,
 
     /* And we should check if the band is a nodata band */
     /* TODO: No!! This is too slow */
-    //rt_band_check_is_nodata(band);
+    /*rt_band_check_is_nodata(band);*/
 
     return band;
 }
@@ -5172,7 +5237,7 @@ rt_raster_to_wkb(rt_raster raster, uint32_t *wkbsize) {
         if (band->isnodata) *ptr |= BANDTYPE_FLAG_ISNODATA;
         ptr += 1;
 
-#if 0 // no padding required for WKB
+#if 0 /* no padding required for WKB */
         /* Add padding (if needed) */
         if (pixbytes > 1) {
             memset(ptr, '\0', pixbytes - 1);
@@ -5239,7 +5304,7 @@ rt_raster_to_wkb(rt_raster raster, uint32_t *wkbsize) {
                 return 0;
         }
 
-#if 0 // no padding for WKB
+#if 0 /* no padding for WKB */
         /* Consistency checking (ptr is pixbytes-aligned) */
         assert(!((uint64_t) ptr % pixbytes));
 #endif
@@ -5262,7 +5327,7 @@ rt_raster_to_wkb(rt_raster raster, uint32_t *wkbsize) {
             }
         }
 
-#if 0 // no padding for WKB
+#if 0 /* no padding for WKB */
         /* Pad up to 8-bytes boundary */
         while ((uint64_t) ptr % 8) {
             *ptr = 0;
@@ -5361,7 +5426,7 @@ rt_raster_serialized_size(rt_raster raster) {
         /* Align size to 8-bytes boundary (trailing padding) */
         /* XXX jorgearevalo: bug here. If the size is actually 8-bytes aligned,
          this line will add 8 bytes trailing padding, and it's not necessary */
-        //size += 8 - (size % 8);
+        /*size += 8 - (size % 8);*/
         if (size % 8)
             size += 8 - (size % 8);
 
@@ -7324,6 +7389,7 @@ rt_raster rt_raster_gdal_warp(
  * @param grid_yw : the Y value of point on grid to align raster to
  * @param skew_x : the X skew of the raster
  * @param skew_y : the Y skew of the raster
+ * @param options : array of options.  only option is "ALL_TOUCHED"
  *
  * @return the raster of the provided geometry
  */
@@ -7337,7 +7403,8 @@ rt_raster_gdal_rasterize(const unsigned char *wkb,
        double *scale_x, double *scale_y,
        double *ul_xw, double *ul_yw,
        double *grid_xw, double *grid_yw,
-       double *skew_x, double *skew_y
+       double *skew_x, double *skew_y,
+       char **options
 ) {
        rt_raster rast;
        int i = 0;
@@ -7362,6 +7429,7 @@ rt_raster_gdal_rasterize(const unsigned char *wkb,
        OGRSpatialReferenceH src_sr = NULL;
        OGRGeometryH src_geom;
        OGREnvelope src_env;
+       OGRwkbGeometryType wkbtype = wkbUnknown;
 
        int ul_user = 0;
        double djunk = 0;
@@ -7499,10 +7567,17 @@ rt_raster_gdal_rasterize(const unsigned char *wkb,
        RASTER_DEBUGF(3, "scale (x, y) = %f, %f", _scale_x, _scale_y);
        RASTER_DEBUGF(3, "dim (x, y) = %d, %d", _width, _height);
 
-       if (
-               (wkbFlatten(OGR_G_GetGeometryType(src_geom)) == wkbPoint) &&
-               FLT_NEQ(_scale_x, 0) &&
-               FLT_NEQ(_scale_y, 0)
+       /*
+               if geometry is a point or point-like and bounds not set, increase
+               extent by half-pixel to avoid missing points on border
+       */
+       wkbtype = wkbFlatten(OGR_G_GetGeometryType(src_geom));
+       if ((
+                       (wkbtype == wkbPoint) ||
+                       (wkbtype == wkbMultiPoint)
+               ) &&
+               FLT_EQ(_width, 0) &&
+               FLT_EQ(_height, 0)
        ) {
                src_env.MinX -= (_scale_x / 2.);
                src_env.MaxX += (_scale_x / 2.);
@@ -7795,7 +7870,7 @@ rt_raster_gdal_rasterize(const unsigned char *wkb,
                1, &src_geom,
                NULL, NULL,
                _value,
-               NULL,
+               options,
                NULL, NULL
        );
        rtdealloc(band_list);
@@ -7851,3 +7926,657 @@ rt_raster_gdal_rasterize(const unsigned char *wkb,
 
        return rast;
 }
+
+static
+int rt_raster_intersects_algorithm(
+       rt_raster rast1, rt_raster rast2,
+       rt_band band1, rt_band band2,
+       int hasnodata1, int hasnodata2,
+       double nodata1, double nodata2
+) {
+       int i;
+       int byHeight = 1;
+       uint32_t dimValue;
+
+       uint32_t row;
+       uint32_t rowoffset;
+       uint32_t col;
+       uint32_t coloffset;
+
+       enum line_points {X1, Y1, X2, Y2};
+       enum point {pX, pY};
+       double line1[4];
+       double line2[4];
+       double P[2];
+       double Qw[2];
+       double Qr[2];
+       double d;
+       double val1;
+       int noval1;
+       double val2;
+       int noval2;
+       uint32_t adjacent[8] = {0};
+
+       double xscale;
+       double yscale;
+
+       uint16_t width1;
+       uint16_t height1;
+       uint16_t width2;
+       uint16_t height2;
+
+       width1 = rt_raster_get_width(rast1);
+       height1 = rt_raster_get_height(rast1);
+       width2 = rt_raster_get_width(rast2);
+       height2 = rt_raster_get_height(rast2);
+
+       /* sampling scale */
+       xscale = fmin(rt_raster_get_x_scale(rast1), rt_raster_get_x_scale(rast2)) / 10.;
+       yscale = fmin(rt_raster_get_y_scale(rast1), rt_raster_get_y_scale(rast2)) / 10.;
+
+       /* see if skew made rast2's rows are parallel to rast1's cols */
+       rt_raster_cell_to_geopoint(
+               rast1,
+               0, 0,
+               &(line1[X1]), &(line1[Y1])
+       );
+
+       rt_raster_cell_to_geopoint(
+               rast1,
+               0, height1,
+               &(line1[X2]), &(line1[Y2])
+       );
+
+       rt_raster_cell_to_geopoint(
+               rast2,
+               0, 0,
+               &(line2[X1]), &(line2[Y1])
+       );
+
+       rt_raster_cell_to_geopoint(
+               rast2,
+               width2, 0,
+               &(line2[X2]), &(line2[Y2])
+       );
+
+       /* parallel vertically */
+       if (FLT_EQ(line1[X2] - line1[X1], 0.) && FLT_EQ(line2[X2] - line2[X1], 0.))
+               byHeight = 0;
+       /* parallel */
+       else if (FLT_EQ(((line1[Y2] - line1[Y1]) / (line1[X2] - line1[X1])), ((line2[Y2] - line2[Y1]) / (line2[X2] - line2[X1]))))
+               byHeight = 0;
+
+       if (byHeight)
+               dimValue = height2;
+       else
+               dimValue = width2;
+       RASTER_DEBUGF(4, "byHeight: %d, dimValue: %d", byHeight, dimValue);
+
+       /* 3 x 3 search */
+       for (coloffset = 0; coloffset < 3; coloffset++) {
+               for (rowoffset = 0; rowoffset < 3; rowoffset++) {
+                       /* smaller raster */
+                       for (col = coloffset; col <= width1; col += 3) {
+
+                               rt_raster_cell_to_geopoint(
+                                       rast1,
+                                       col, 0,
+                                       &(line1[X1]), &(line1[Y1])
+                               );
+
+                               rt_raster_cell_to_geopoint(
+                                       rast1,
+                                       col, height1,
+                                       &(line1[X2]), &(line1[Y2])
+                               );
+
+                               /* larger raster */
+                               for (row = rowoffset; row <= dimValue; row += 3) {
+
+                                       if (byHeight) {
+                                               rt_raster_cell_to_geopoint(
+                                                       rast2,
+                                                       0, row,
+                                                       &(line2[X1]), &(line2[Y1])
+                                               );
+
+                                               rt_raster_cell_to_geopoint(
+                                                       rast2,
+                                                       width2, row,
+                                                       &(line2[X2]), &(line2[Y2])
+                                               );
+                                       }
+                                       else {
+                                               rt_raster_cell_to_geopoint(
+                                                       rast2,
+                                                       row, 0,
+                                                       &(line2[X1]), &(line2[Y1])
+                                               );
+
+                                               rt_raster_cell_to_geopoint(
+                                                       rast2,
+                                                       row, height2,
+                                                       &(line2[X2]), &(line2[Y2])
+                                               );
+                                       }
+
+                                       RASTER_DEBUGF(4, "(col, row) = (%d, %d)", col, row);
+                                       RASTER_DEBUGF(4, "line1(x1, y1, x2, y2) = (%f, %f, %f, %f)",
+                                               line1[X1], line1[Y1], line1[X2], line1[Y2]);
+                                       RASTER_DEBUGF(4, "line2(x1, y1, x2, y2) = (%f, %f, %f, %f)",
+                                               line2[X1], line2[Y1], line2[X2], line2[Y2]);
+
+                                       /* intersection */
+                                       /* http://en.wikipedia.org/wiki/Line-line_intersection */
+                                       d = ((line1[X1] - line1[X2]) * (line2[Y1] - line2[Y2])) - ((line1[Y1] - line1[Y2]) * (line2[X1] - line2[X2]));
+                                       /* no intersection */
+                                       if (FLT_EQ(d, 0.)) {
+                                               continue;
+                                       }
+
+                                       P[pX] = (((line1[X1] * line1[Y2]) - (line1[Y1] * line1[X2])) * (line2[X1] - line2[X2])) -
+                                               ((line1[X1] - line1[X2]) * ((line2[X1] * line2[Y2]) - (line2[Y1] * line2[X2])));
+                                       P[pX] = P[pX] / d;
+
+                                       P[pY] = (((line1[X1] * line1[Y2]) - (line1[Y1] * line1[X2])) * (line2[Y1] - line2[Y2])) -
+                                               ((line1[Y1] - line1[Y2]) * ((line2[X1] * line2[Y2]) - (line2[Y1] * line2[X2])));
+                                       P[pY] = P[pY] / d;
+
+                                       RASTER_DEBUGF(4, "P(x, y) = (%f, %f)", P[pX], P[pY]);
+
+                                       /* intersection within bounds */
+                                       if ((
+                                                       (FLT_EQ(P[pX], line1[X1]) || FLT_EQ(P[pX], line1[X2])) ||
+                                                               (P[pX] > fmin(line1[X1], line1[X2]) && (P[pX] < fmax(line1[X1], line1[X2])))
+                                               ) && (
+                                                       (FLT_EQ(P[pY], line1[Y1]) || FLT_EQ(P[pY], line1[Y2])) ||
+                                                               (P[pY] > fmin(line1[Y1], line1[Y2]) && (P[pY] < fmax(line1[Y1], line1[Y2])))
+                                               ) && (
+                                                       (FLT_EQ(P[pX], line2[X1]) || FLT_EQ(P[pX], line2[X2])) ||
+                                                               (P[pX] > fmin(line2[X1], line2[X2]) && (P[pX] < fmax(line2[X1], line2[X2])))
+                                               ) && (
+                                                       (FLT_EQ(P[pY], line2[Y1]) || FLT_EQ(P[pY], line2[Y2])) ||
+                                                               (P[pY] > fmin(line2[Y1], line2[Y2]) && (P[pY] < fmax(line2[Y1], line2[Y2])))
+                                       )) {
+                                               RASTER_DEBUG(4, "within bounds");
+
+                                               for (i = 0; i < 8; i++) adjacent[i] = 0;
+
+                                               /* test points around intersection */
+                                               for (i = 0; i < 8; i++) {
+                                                       switch (i) {
+                                                               case 7:
+                                                                       Qw[pX] = P[pX] - xscale;
+                                                                       Qw[pY] = P[pY] + yscale;
+                                                                       break;
+                                                               /* 270 degrees = 09:00 */
+                                                               case 6:
+                                                                       Qw[pX] = P[pX] - xscale;
+                                                                       Qw[pY] = P[pY];
+                                                                       break;
+                                                               case 5:
+                                                                       Qw[pX] = P[pX] - xscale;
+                                                                       Qw[pY] = P[pY] - yscale;
+                                                                       break;
+                                                               /* 180 degrees = 06:00 */
+                                                               case 4:
+                                                                       Qw[pX] = P[pX];
+                                                                       Qw[pY] = P[pY] - yscale;
+                                                                       break;
+                                                               case 3:
+                                                                       Qw[pX] = P[pX] + xscale;
+                                                                       Qw[pY] = P[pY] - yscale;
+                                                                       break;
+                                                               /* 90 degrees = 03:00 */
+                                                               case 2:
+                                                                       Qw[pX] = P[pX] + xscale;
+                                                                       Qw[pY] = P[pY];
+                                                                       break;
+                                                               /* 45 degrees */
+                                                               case 1:
+                                                                       Qw[pX] = P[pX] + xscale;
+                                                                       Qw[pY] = P[pY] + yscale;
+                                                                       break;
+                                                               /* 0 degrees = 00:00 */
+                                                               case 0:
+                                                                       Qw[pX] = P[pX];
+                                                                       Qw[pY] = P[pY] + yscale;
+                                                                       break;
+                                                       }
+
+                                                       /* unable to convert point to cell */
+                                                       noval1 = 0;
+                                                       if (!rt_raster_geopoint_to_cell(
+                                                               rast1,
+                                                               Qw[pX], Qw[pY],
+                                                               &(Qr[pX]), &(Qr[pY])
+                                                       )) {
+                                                               noval1 = 1;
+                                                       }
+                                                       /* cell is outside bounds of grid */
+                                                       else if (
+                                                               (Qr[pX] < 0 || Qr[pX] > width1 || FLT_EQ(Qr[pX], width1)) ||
+                                                               (Qr[pY] < 0 || Qr[pY] > height1 || FLT_EQ(Qr[pY], height1))
+                                                       ) {
+                                                               noval1 = 1;
+                                                       }
+                                                       else if (hasnodata1 == FALSE)
+                                                               val1 = 1;
+                                                       /* unable to get value at cell */
+                                                       else if (rt_band_get_pixel(band1, Qr[pX], Qr[pY], &val1) < 0)
+                                                               noval1 = 1;
+
+                                                       /* unable to convert point to cell */
+                                                       noval2 = 0;
+                                                       if (!rt_raster_geopoint_to_cell(
+                                                               rast2,
+                                                               Qw[pX], Qw[pY],
+                                                               &(Qr[pX]), &(Qr[pY])
+                                                       )) {
+                                                               noval2 = 1;
+                                                       }
+                                                       /* cell is outside bounds of grid */
+                                                       else if (
+                                                               (Qr[pX] < 0 || Qr[pX] > width2 || FLT_EQ(Qr[pX], width2)) ||
+                                                               (Qr[pY] < 0 || Qr[pY] > height2 || FLT_EQ(Qr[pY], height2))
+                                                       ) {
+                                                               noval2 = 1;
+                                                       }
+                                                       else if (hasnodata2 == FALSE)
+                                                               val2 = 1;
+                                                       /* unable to get value at cell */
+                                                       else if (rt_band_get_pixel(band2, Qr[pX], Qr[pY], &val2) < 0)
+                                                               noval2 = 1;
+
+                                                       if (!noval1) {
+                                                               RASTER_DEBUGF(4, "val1 = %f", val1);
+                                                       }
+                                                       if (!noval2) {
+                                                               RASTER_DEBUGF(4, "val2 = %f", val2);
+                                                       }
+
+                                                       /* pixels touch */
+                                                       if (!noval1 && (
+                                                               (hasnodata1 == FALSE) || (
+                                                                       (hasnodata1 != FALSE) &&
+                                                                       FLT_NEQ(val1, nodata1)
+                                                               )
+                                                       )) {
+                                                               adjacent[i]++;
+                                                       }
+                                                       if (!noval2 && (
+                                                               (hasnodata2 == FALSE) || (
+                                                                       (hasnodata2 != FALSE) &&
+                                                                       FLT_NEQ(val2, nodata2)
+                                                               )
+                                                       )) {
+                                                               adjacent[i] += 3;
+                                                       }
+
+                                                       /* two pixel values not present */
+                                                       if (noval1 || noval2) {
+                                                               RASTER_DEBUGF(4, "noval1 = %d, noval2 = %d", noval1, noval2);
+                                                               continue;
+                                                       }
+
+                                                       /* pixels valid, so intersect */
+                                                       if ((
+                                                                       (hasnodata1 == FALSE) || (
+                                                                               (hasnodata1 != FALSE) &&
+                                                                               FLT_NEQ(val1, nodata1)
+                                                                       )
+                                                               ) && (
+                                                                       (hasnodata2 == FALSE) || (
+                                                                               (hasnodata2 != FALSE) &&
+                                                                               FLT_NEQ(val2, nodata2)
+                                                                       )
+                                                       )) {
+                                                               RASTER_DEBUG(3, "The two rasters do intersect");
+
+                                                               return 1;
+                                                       }
+                                               }
+
+                                               /* pixels touch */
+                                               for (i = 0; i < 4; i++) {
+                                                       RASTER_DEBUGF(4, "adjacent[%d] = %d, adjacent[%d] = %d"
+                                                               , i, adjacent[i], i + 4, adjacent[i + 4]);
+                                                       if (adjacent[i] == 0) continue;
+
+                                                       if (adjacent[i] + adjacent[i + 4] == 4) {
+                                                               RASTER_DEBUG(3, "The two rasters touch");
+
+                                                               return 1;
+                                                       }
+                                               }
+                                       }
+                                       else {
+                                               RASTER_DEBUG(4, "outside of bounds");
+                                       }
+                               }
+                       }
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * Return zero if error occurred in function.
+ * Parameter intersects returns non-zero if two rasters intersect
+ *
+ * @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 intersects : non-zero value if the two rasters' bands intersects
+ *
+ * @return if zero, an error occurred in function
+ */
+int
+rt_raster_intersects(
+       rt_raster rast1, int nband1,
+       rt_raster rast2, int nband2,
+       int *intersects
+) {
+       int i;
+       int j;
+       int within = 0;
+
+       LWPOLY *hull[2] = {NULL};
+       GEOSGeometry *ghull[2] = {NULL};
+
+       uint16_t width1;
+       uint16_t height1;
+       uint16_t width2;
+       uint16_t height2;
+       double area1;
+       double area2;
+       double pixarea1;
+       double pixarea2;
+       rt_raster rastS = NULL;
+       rt_raster rastL = NULL;
+       uint16_t *widthS = NULL;
+       uint16_t *heightS = NULL;
+       uint16_t *widthL = NULL;
+       uint16_t *heightL = NULL;
+       int nbandS;
+       int nbandL;
+       rt_band bandS = NULL;
+       rt_band bandL = NULL;
+       int hasnodataS = FALSE;
+       int hasnodataL = FALSE;
+       double nodataS = 0;
+       double nodataL = 0;
+
+       uint32_t row;
+       uint32_t rowoffset;
+       uint32_t col;
+       uint32_t coloffset;
+
+       enum line_points {X1, Y1, X2, Y2};
+       enum point {pX, pY};
+       double lineS[4];
+       double Qr[2];
+       double valS;
+       double valL;
+
+       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));
+       }
+
+       /* same srid */
+       if (rt_raster_get_srid(rast1) != rt_raster_get_srid(rast2)) {
+               rterror("rt_raster_intersects: The two rasters provided have different SRIDs");
+               *intersects = 0;
+               return 0;
+       }
+
+       /* raster extents need to intersect */
+       do {
+               int rtn;
+
+               initGEOS(lwnotice, lwgeom_geos_error);
+
+               rtn = 1;
+               for (i = 0; i < 2; i++) {
+                       hull[i] = rt_raster_get_convex_hull(i < 1 ? rast1 : rast2);
+                       if (NULL == hull[i]) {
+                               for (j = 0; j < i; j++) {
+                                       GEOSGeom_destroy(ghull[j]);
+                                       lwpoly_free(hull[j]);
+                               }
+                               rtn = 0;
+                               break;
+                       }
+                       ghull[i] = (GEOSGeometry *) LWGEOM2GEOS((LWGEOM *) hull[i]);
+                       if (NULL == ghull[i]) {
+                               for (j = 0; j < i; j++) {
+                                       GEOSGeom_destroy(ghull[j]);
+                                       lwpoly_free(hull[j]);
+                               }
+                               lwpoly_free(hull[i]);
+                               rtn = 0;
+                               break;
+                       }
+               }
+               if (!rtn) break;
+
+               /* test to see if raster within the other */
+               within = 0;
+               if (GEOSWithin(ghull[0], ghull[1]) == 1)
+                       within = -1;
+               else if (GEOSWithin(ghull[1], ghull[0]) == 1)
+                       within = 1;
+
+               if (within != 0)
+                       rtn = 1;
+               else
+                       rtn = GEOSIntersects(ghull[0], ghull[1]);
+
+               for (i = 0; i < 2; i++) {
+                       GEOSGeom_destroy(ghull[i]);
+                       lwpoly_free(hull[i]);
+               }
+
+               if (rtn != 2) {
+                       RASTER_DEBUGF(4, "convex hulls of rasters do %sintersect", rtn != 1 ? "NOT " : "");
+                       if (rtn != 1) {
+                               *intersects = 0;
+                               return 1;
+                       }
+                       /* band isn't specified */
+                       else if (nband1 < 0) {
+                               *intersects = 1;
+                               return 1;
+                       }
+               }
+       }
+       while (0);
+
+       /* smaller raster by area or width */
+       width1 = rt_raster_get_width(rast1);
+       height1 = rt_raster_get_height(rast1);
+       width2 = rt_raster_get_width(rast2);
+       height2 = rt_raster_get_height(rast2);
+       pixarea1 = fabs(rt_raster_get_x_scale(rast1) * rt_raster_get_y_scale(rast1));
+       pixarea2 = fabs(rt_raster_get_x_scale(rast2) * rt_raster_get_y_scale(rast2));
+       area1 = fabs(width1 * height1 * pixarea1);
+       area2 = fabs(width2 * height2 * pixarea2);
+       RASTER_DEBUGF(4, "pixarea1, pixarea2, area1, area2 = %f, %f, %f, %f",
+               pixarea1, pixarea2, area1, area2);
+       if (
+               (within <= 0) ||
+               (area1 < area2) ||
+               FLT_EQ(area1, area2) ||
+               (area1 < pixarea2) || /* area of rast1 smaller than pixel area of rast2 */
+               FLT_EQ(area1, pixarea2)
+       ) {
+               rastS = rast1;
+               nbandS = nband1;
+               widthS = &width1;
+               heightS = &height1;
+
+               rastL = rast2;
+               nbandL = nband2;
+               widthL = &width2;
+               heightL = &height2;
+       }
+       else {
+               rastS = rast2;
+               nbandS = nband2;
+               widthS = &width2;
+               heightS = &height2;
+
+               rastL = rast1;
+               nbandL = nband1;
+               widthL = &width1;
+               heightL = &height1;
+       }
+
+       /* no band to use, set band to zero */
+       if (nband1 < 0) {
+               nbandS = 0;
+               nbandL = 0;
+       }
+
+       RASTER_DEBUGF(4, "rast1 @ %p", rast1);
+       RASTER_DEBUGF(4, "rast2 @ %p", rast2);
+       RASTER_DEBUGF(4, "rastS @ %p", rastS);
+       RASTER_DEBUGF(4, "rastL @ %p", rastL);
+
+       /* load band of smaller raster */
+       bandS = rt_raster_get_band(rastS, nbandS);
+       if (NULL == bandS) {
+               rterror("rt_raster_intersects: Unable to get band %d of the first raster\n", nbandS);
+               *intersects = 0;
+               return 0;
+       }
+       if (bandS->offline) {
+               rterror("rt_raster_intersects not implemented yet for OFFDB bands");
+               *intersects = 0;
+               return 0;
+       }
+
+       hasnodataS = rt_band_get_hasnodata_flag(bandS);
+       if (hasnodataS != FALSE)
+               nodataS = rt_band_get_nodata(bandS);
+
+       /* load band of larger raster */
+       bandL = rt_raster_get_band(rastL, nbandL);
+       if (NULL == bandL) {
+               rterror("rt_raster_intersects: Unable to get band %d of the first raster\n", nbandL);
+               *intersects = 0;
+               return 0;
+       }
+       if (bandL->offline) {
+               rterror("rt_raster_intersects not implemented yet for OFFDB bands");
+               *intersects = 0;
+               return 0;
+       }
+
+       hasnodataL = rt_band_get_hasnodata_flag(bandL);
+       if (hasnodataL != FALSE)
+               nodataL = rt_band_get_nodata(bandL);
+
+       /* no band to use, ignore nodata */
+       if (nband1 < 0) {
+               hasnodataS = FALSE;
+               hasnodataL = FALSE;
+       }
+
+       /* special case where a raster can fit inside another raster's pixel */
+       if (within != 0 && ((pixarea1 > area2) || (pixarea2 > area1))) {
+               RASTER_DEBUG(4, "Using special case of raster fitting into another raster's pixel");
+               /* 3 x 3 search */
+               for (coloffset = 0; coloffset < 3; coloffset++) {
+                       for (rowoffset = 0; rowoffset < 3; rowoffset++) {
+                               for (col = coloffset; col < *widthS; col += 3) {
+                                       for (row = rowoffset; row < *heightS; row += 3) {
+                                               if (hasnodataS == FALSE)
+                                                       valS = 1;
+                                               else if (rt_band_get_pixel(bandS, col, row, &valS) < 0)
+                                                       continue;
+
+                                               if ((hasnodataS == FALSE) || (
+                                                       (hasnodataS != FALSE) &&
+                                                       FLT_NEQ(valS, nodataS)
+                                               )) {
+                                                       rt_raster_cell_to_geopoint(
+                                                               rastS,
+                                                               col, row,
+                                                               &(lineS[X1]), &(lineS[Y1])
+                                                       );
+
+                                                       if (!rt_raster_geopoint_to_cell(
+                                                               rastL,
+                                                               lineS[X1], lineS[Y1],
+                                                               &(Qr[pX]), &(Qr[pY])
+                                                       )) {
+                                                               continue;
+                                                       }
+
+                                                       if (
+                                                               (Qr[pX] < 0 || Qr[pX] > *widthL || FLT_EQ(Qr[pX], *widthL)) ||
+                                                               (Qr[pY] < 0 || Qr[pY] > *heightL || FLT_EQ(Qr[pY], *heightL))
+                                                       ) {
+                                                               continue;
+                                                       }
+
+                                                       if (hasnodataS == FALSE)
+                                                               valL = 1;
+                                                       else if (rt_band_get_pixel(bandL, Qr[pX], Qr[pY], &valL) < 0)
+                                                               continue;
+
+                                                       if ((hasnodataL == FALSE) || (
+                                                               (hasnodataL != FALSE) &&
+                                                               FLT_NEQ(valL, nodataL)
+                                                       )) {
+                                                               RASTER_DEBUG(3, "The two rasters do intersect");
+                                                               *intersects = 1;
+                                                               return 1;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       *intersects = rt_raster_intersects_algorithm(
+               rastS, rastL,
+               bandS, bandL,
+               hasnodataS, hasnodataL,
+               nodataS, nodataL
+       );
+
+       if (*intersects) return 1;
+
+       *intersects = rt_raster_intersects_algorithm(
+               rastL, rastS,
+               bandL, bandS,
+               hasnodataL, hasnodataS,
+               nodataL, nodataS
+       );
+
+       if (*intersects) return 1;
+
+       RASTER_DEBUG(3, "The two rasters do not intersect");
+
+       *intersects = 0;
+       return 1;
+}
index 7d60c43ed0be1ef9621e10b9e6737cf33fc21c36..4c8e6713924e7b12ba93422538dc36c65d0e8ed8 100644 (file)
 #endif
 #endif
 
+/* Microsoft does not support fmax or fmin in math.h */
+#if defined(WIN32)
+#if !defined(HAVE_MAX)
+#define fmax max
+#endif
+#if !defined(HAVE_MIN)
+#define fmin min
+#endif
+#endif
+
 #include <stdlib.h> /* For size_t, srand and rand */
 #include <stdint.h> /* For C99 int types */
 
 #include "liblwgeom.h"
+#include "lwgeom_geos.h"
 
 #include "gdal_alg.h"
 #include "gdal_frmts.h"
@@ -137,170 +148,6 @@ typedef struct rt_valuecount_t* rt_valuecount;
 typedef struct rt_gdaldriver_t* rt_gdaldriver;
 typedef struct rt_reclassexpr_t* rt_reclassexpr;
 
-
-/**
- * Struct definitions
- *
- * These structs are defined here as they are needed elsewhere
- * including rt_pg/rt_pg.c and reduce duplicative declarations
- *
- */
-struct rt_raster_serialized_t {
-    /*---[ 8 byte boundary ]---{ */
-    uint32_t size; /* required by postgresql: 4 bytes */
-    uint16_t version; /* format version (this is version 0): 2 bytes */
-    uint16_t numBands; /* Number of bands: 2 bytes */
-
-    /* }---[ 8 byte boundary ]---{ */
-    double scaleX; /* pixel width: 8 bytes */
-
-    /* }---[ 8 byte boundary ]---{ */
-    double scaleY; /* pixel height: 8 bytes */
-
-    /* }---[ 8 byte boundary ]---{ */
-    double ipX; /* insertion point X: 8 bytes */
-
-    /* }---[ 8 byte boundary ]---{ */
-    double ipY; /* insertion point Y: 8 bytes */
-
-    /* }---[ 8 byte boundary ]---{ */
-    double skewX; /* skew about the X axis: 8 bytes */
-
-    /* }---[ 8 byte boundary ]---{ */
-    double skewY; /* skew about the Y axis: 8 bytes */
-
-    /* }---[ 8 byte boundary ]--- */
-    int32_t srid; /* Spatial reference id: 4 bytes */
-    uint16_t width; /* pixel columns: 2 bytes */
-    uint16_t height; /* pixel rows: 2 bytes */
-};
-
-/* NOTE: the initial part of this structure matches the layout
- *       of data in the serialized form version 0, starting
- *       from the numBands element
- */
-struct rt_raster_t {
-    uint32_t size;
-    uint16_t version;
-
-    /* Number of bands, all share the same dimension
-     * and georeference */
-    uint16_t numBands;
-
-    /* Georeference (in projection units) */
-    double scaleX; /* pixel width */
-    double scaleY; /* pixel height */
-    double ipX; /* geo x ordinate of the corner of upper-left pixel */
-    double ipY; /* geo y ordinate of the corner of bottom-right pixel */
-    double skewX; /* skew about the X axis*/
-    double skewY; /* skew about the Y axis */
-
-    int32_t srid; /* spatial reference id */
-    uint16_t width; /* pixel columns - max 65535 */
-    uint16_t height; /* pixel rows - max 65535 */
-    rt_band *bands; /* actual bands */
-
-};
-
-/* WKT string representing each polygon in WKT format acompagned by its
-correspoding value */
-struct rt_geomval_t {
-    int srid;
-    double val;
-    char * geom;
-};
-
-/* summary stats of specified band */
-struct rt_bandstats_t {
-       double sample;
-       uint32_t count;
-
-       double min;
-       double max;
-       double sum;
-       double mean;
-       double stddev;
-
-       double *values;
-       int sorted; /* flag indicating that values is sorted ascending by value */
-};
-
-/* histogram bin(s) of specified band */
-struct rt_histogram_t {
-       uint32_t count;
-       double percent;
-
-       double min;
-       double max;
-
-       int inc_min;
-       int inc_max;
-};
-
-/* quantile(s) of the specified band */
-struct rt_quantile_t {
-       double quantile;
-       double value;
-};
-
-/* listed-list structures for rt_band_get_quantiles_stream */
-struct quantile_llist {
-       uint8_t algeq; /* AL-GEQ (1) or AL-GT (0) */
-       double quantile;
-       uint64_t tau; /* position in sequence */
-
-       struct quantile_llist_element *head; /* H index 0 */
-       struct quantile_llist_element *tail; /* H index last */
-       uint32_t count; /* # of elements in H */
-
-       /* faster access to elements at specific intervals */
-       struct quantile_llist_index *index;
-       uint32_t index_max; /* max # of elements in index */
-
-       uint64_t sum1; /* N1H */
-       uint64_t sum2; /* N2H */
-};
-
-struct quantile_llist_element {
-       double value;
-       uint32_t count;
-
-       struct quantile_llist_element *prev;
-       struct quantile_llist_element *next;
-};
-
-struct quantile_llist_index {
-       struct quantile_llist_element *element;
-       uint32_t index;
-};
-
-/* number of times a value occurs */
-struct rt_valuecount_t {
-       double value;
-       uint32_t count;
-       double percent;
-};
-
-/* reclassification expression */
-struct rt_reclassexpr_t {
-       struct rt_reclassrange {
-               double min;
-               double max;
-               int inc_min; /* include min */
-               int inc_max; /* include max */
-               int exc_min; /* exceed min */
-               int exc_max; /* exceed max */
-       } src, dst;
-};
-
-/* gdal driver information */
-struct rt_gdaldriver_t {
-    int idx;
-    char *short_name;
-    char *long_name;
-               char *create_options;
-};
-
 /**
 * Global functions for memory/logging handlers.
 */
@@ -676,6 +523,7 @@ rt_histogram rt_band_get_histogram(rt_bandstats stats,
 rt_quantile rt_band_get_quantiles(rt_bandstats stats,
        double *quantiles, int quantiles_count, uint32_t *rtn_count);
 
+struct quantile_llist;
 int quantile_llist_destroy(struct quantile_llist **list,
        uint32_t list_count);
 
@@ -966,17 +814,32 @@ void rt_raster_set_srid(rt_raster raster, int32_t srid);
 int32_t rt_raster_get_srid(rt_raster raster);
 
 /**
- * Convert an x,y raster point to an x1,y1 point on map
+ * Convert an xr, yr raster point to an xw, yw point on map
  *
  * @param raster : the raster to get info from
- * @param x : the pixel's column
- * @param y : the pixel's row
- * @param x1 : output parameter, X ordinate of the geographical point
- * @param y1 : output parameter, Y ordinate of the geographical point
+ * @param xr : the pixel's column
+ * @param yr : the pixel's row
+ * @param xw : output parameter, X ordinate of the geographical point
+ * @param yw : output parameter, Y ordinate of the geographical point
  */
 void rt_raster_cell_to_geopoint(rt_raster raster,
-                                double x, double y,
-                                double* x1, double* y1);
+       double xr, double yr,
+       double* xw, double* yw);
+
+/**
+ * Convert an xw, yw map point to a xr, yr raster point
+ *
+ * @param raster : the raster to get info from
+ * @param xw : X ordinate of the geographical point
+ * @param yw : Y ordinate of the geographical point
+ * @param xr : output parameter, the pixel's column
+ * @param yr : output parameter, the pixel's row
+ *
+ * @return if zero, error occurred in function
+ */
+int rt_raster_geopoint_to_cell(rt_raster raster,
+       double xw, double yw,
+       double *xr, double *yr);
 
 /**
  * Get raster's polygon convex hull.
@@ -1184,6 +1047,7 @@ rt_raster rt_raster_gdal_warp(rt_raster raster, const char *src_srs,
  * @param grid_yw : the Y value of point on grid to align raster to
  * @param skew_x : the X skew of the raster
  * @param skew_y : the Y skew of the raster
+ * @param options : array of options.  only option is "ALL_TOUCHED"
  *
  * @return the raster of the provided geometry
  */
@@ -1196,7 +1060,31 @@ rt_raster rt_raster_gdal_rasterize(const unsigned char *wkb,
        double *scale_x, double *scale_y,
        double *ul_xw, double *ul_yw,
        double *grid_xw, double *grid_yw,
-       double *skew_x, double *skew_y);
+       double *skew_x, double *skew_y,
+       char **options
+);
+
+/**
+ * Return zero if error occurred in function.
+ * Parameter intersects returns non-zero if two rasters intersect
+ *
+ * @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 intersects : non-zero value if the two rasters' bands intersects
+ *
+ * @return if zero, an error occurred in function
+ */
+int rt_raster_intersects(
+       rt_raster rast1, int nband1,
+       rt_raster rast2, int nband2,
+       int *intersects
+);
 
 /*- utilities -------------------------------------------------------*/
 
@@ -1279,4 +1167,190 @@ rt_util_pixtype_to_gdal_datatype(rt_pixtype pt);
 */
 #define ROUND(x, y) (((x > 0.0) ? floor((x * pow(10, y) + 0.5)) : ceil((x * pow(10, y) - 0.5))) / pow(10, y));
 
+/**
+ * Struct definitions
+ *
+ * These structs are defined here as they are needed elsewhere
+ * including rt_pg/rt_pg.c and reduce duplicative declarations
+ *
+ */
+struct rt_raster_serialized_t {
+    /*---[ 8 byte boundary ]---{ */
+    uint32_t size; /* required by postgresql: 4 bytes */
+    uint16_t version; /* format version (this is version 0): 2 bytes */
+    uint16_t numBands; /* Number of bands: 2 bytes */
+
+    /* }---[ 8 byte boundary ]---{ */
+    double scaleX; /* pixel width: 8 bytes */
+
+    /* }---[ 8 byte boundary ]---{ */
+    double scaleY; /* pixel height: 8 bytes */
+
+    /* }---[ 8 byte boundary ]---{ */
+    double ipX; /* insertion point X: 8 bytes */
+
+    /* }---[ 8 byte boundary ]---{ */
+    double ipY; /* insertion point Y: 8 bytes */
+
+    /* }---[ 8 byte boundary ]---{ */
+    double skewX; /* skew about the X axis: 8 bytes */
+
+    /* }---[ 8 byte boundary ]---{ */
+    double skewY; /* skew about the Y axis: 8 bytes */
+
+    /* }---[ 8 byte boundary ]--- */
+    int32_t srid; /* Spatial reference id: 4 bytes */
+    uint16_t width; /* pixel columns: 2 bytes */
+    uint16_t height; /* pixel rows: 2 bytes */
+};
+
+/* NOTE: the initial part of this structure matches the layout
+ *       of data in the serialized form version 0, starting
+ *       from the numBands element
+ */
+struct rt_raster_t {
+    uint32_t size;
+    uint16_t version;
+
+    /* Number of bands, all share the same dimension
+     * and georeference */
+    uint16_t numBands;
+
+    /* Georeference (in projection units) */
+    double scaleX; /* pixel width */
+    double scaleY; /* pixel height */
+    double ipX; /* geo x ordinate of the corner of upper-left pixel */
+    double ipY; /* geo y ordinate of the corner of bottom-right pixel */
+    double skewX; /* skew about the X axis*/
+    double skewY; /* skew about the Y axis */
+
+    int32_t srid; /* spatial reference id */
+    uint16_t width; /* pixel columns - max 65535 */
+    uint16_t height; /* pixel rows - max 65535 */
+    rt_band *bands; /* actual bands */
+
+};
+
+struct rt_extband_t {
+    uint8_t bandNum;
+    char* path; /* externally owned ? */
+};
+
+struct rt_band_t {
+    rt_pixtype pixtype;
+    int32_t offline;
+    uint16_t width;
+    uint16_t height;
+    int32_t hasnodata; /* a flag indicating if this band contains nodata values */
+    int32_t isnodata;   /* a flag indicating if this band is filled only with
+                           nodata values */
+    double nodataval; /* int will be converted ... */
+    int32_t ownsData; /* XXX mloskot: its behaviour needs to be documented */
+
+    union {
+        void* mem; /* actual data, externally owned */
+        struct rt_extband_t offline;
+    } data;
+
+};
+
+/* WKT string representing each polygon in WKT format accompanied by its
+corresponding value */
+struct rt_geomval_t {
+    int srid;
+    double val;
+    char * geom;
+};
+
+/* summary stats of specified band */
+struct rt_bandstats_t {
+       double sample;
+       uint32_t count;
+
+       double min;
+       double max;
+       double sum;
+       double mean;
+       double stddev;
+
+       double *values;
+       int sorted; /* flag indicating that values is sorted ascending by value */
+};
+
+/* histogram bin(s) of specified band */
+struct rt_histogram_t {
+       uint32_t count;
+       double percent;
+
+       double min;
+       double max;
+
+       int inc_min;
+       int inc_max;
+};
+
+/* quantile(s) of the specified band */
+struct rt_quantile_t {
+       double quantile;
+       double value;
+};
+
+/* listed-list structures for rt_band_get_quantiles_stream */
+struct quantile_llist {
+       uint8_t algeq; /* AL-GEQ (1) or AL-GT (0) */
+       double quantile;
+       uint64_t tau; /* position in sequence */
+
+       struct quantile_llist_element *head; /* H index 0 */
+       struct quantile_llist_element *tail; /* H index last */
+       uint32_t count; /* # of elements in H */
+
+       /* faster access to elements at specific intervals */
+       struct quantile_llist_index *index;
+       uint32_t index_max; /* max # of elements in index */
+
+       uint64_t sum1; /* N1H */
+       uint64_t sum2; /* N2H */
+};
+
+struct quantile_llist_element {
+       double value;
+       uint32_t count;
+
+       struct quantile_llist_element *prev;
+       struct quantile_llist_element *next;
+};
+
+struct quantile_llist_index {
+       struct quantile_llist_element *element;
+       uint32_t index;
+};
+
+/* number of times a value occurs */
+struct rt_valuecount_t {
+       double value;
+       uint32_t count;
+       double percent;
+};
+
+/* reclassification expression */
+struct rt_reclassexpr_t {
+       struct rt_reclassrange {
+               double min;
+               double max;
+               int inc_min; /* include min */
+               int inc_max; /* include max */
+               int exc_min; /* exceed min */
+               int exc_max; /* exceed max */
+       } src, dst;
+};
+
+/* gdal driver information */
+struct rt_gdaldriver_t {
+       int idx;
+       char *short_name;
+       char *long_name;
+       char *create_options;
+};
+
 #endif /* RT_API_H_INCLUDED */
index ab7973dde95ef53fc4545d81d3a311aec305a2a5..cfb9d41de669f0e7489152fa7fb3d19ab413b3d0 100644 (file)
@@ -236,6 +236,9 @@ Datum RASTER_metadata(PG_FUNCTION_ARGS);
 /* get raster band's meta data */
 Datum RASTER_bandmetadata(PG_FUNCTION_ARGS);
 
+/* determine if two rasters intersect */
+Datum RASTER_intersects(PG_FUNCTION_ARGS);
+
 /* Replace function taken from
  * http://ubuntuforums.org/showthread.php?s=aa6f015109fd7e4c7e30d2fd8b717497&t=141670&page=3
  */
@@ -6497,6 +6500,9 @@ Datum RASTER_asRaster(PG_FUNCTION_ARGS)
        double *skew_x = NULL;
        double *skew_y = NULL;
 
+       char **options = NULL;
+       int options_len = 0;
+
        uint32_t num_bands = 0;
 
        int srid = SRID_UNKNOWN;
@@ -6907,6 +6913,27 @@ Datum RASTER_asRaster(PG_FUNCTION_ARGS)
        }
        POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: skew (x, y) = %f, %f", skew[0], skew[1]);
 
+       /* all touched */
+       if (!PG_ARGISNULL(14) && PG_GETARG_BOOL(14) == TRUE) {
+               if (options_len < 1) {
+                       options_len = 1;
+                       options = (char **) palloc(sizeof(char *) * options_len);
+               }
+               else {
+                       options_len++;
+                       options = (char **) repalloc(options, sizeof(char *) * options_len);
+               }
+
+               options[options_len - 1] = palloc(sizeof(char*) * (strlen("ALL_TOUCHED=TRUE") + 1));
+               options[options_len - 1] = "ALL_TOUCHED=TRUE";
+       }
+
+       if (options_len) {
+               options_len++;
+               options = (char **) repalloc(options, sizeof(char *) * options_len);
+               options[options_len - 1] = NULL;
+       }
+
        /* get geometry's srid */
 #ifdef GSERIALIZED_ON
        srid = gserialized_get_srid(pggeom);
@@ -6926,6 +6953,7 @@ Datum RASTER_asRaster(PG_FUNCTION_ARGS)
                                pfree(hasnodatas);
                                pfree(nodatavals);
                        }
+                       if (options_len) pfree(options);
 
                        lwgeom_free(geom);
                        PG_FREE_IF_COPY(pggeom, 0);
@@ -6979,7 +7007,8 @@ Datum RASTER_asRaster(PG_FUNCTION_ARGS)
                scale_x, scale_y,
                ul_xw, ul_yw,
                grid_xw, grid_yw,
-               skew_x, skew_y
+               skew_x, skew_y,
+               options
        );
 
        if (pixtypes_len) pfree(pixtypes);
@@ -6988,9 +7017,10 @@ Datum RASTER_asRaster(PG_FUNCTION_ARGS)
                pfree(hasnodatas);
                pfree(nodatavals);
        }
+       if (options_len) pfree(options);
 
        if (!rast) {
-               elog(ERROR, "RASTER_asRaster: Could not create rasterize geometry");
+               elog(ERROR, "RASTER_asRaster: Could not rasterize geometry");
                PG_RETURN_NULL();
        }
 
@@ -7446,6 +7476,151 @@ Datum RASTER_bandmetadata(PG_FUNCTION_ARGS)
        PG_RETURN_DATUM(result);
 }
 
+/**
+ * See if two rasters intersect
+ */
+PG_FUNCTION_INFO_V1(RASTER_intersects);
+Datum RASTER_intersects(PG_FUNCTION_ARGS)
+{
+       const int set_count = 2;
+       rt_pgraster *pgrast;
+       rt_raster rast[2] = {NULL};
+       uint32_t bandindex[2] = {0};
+       uint32_t hasbandindex[2] = {0};
+
+       uint32_t i;
+       uint32_t j;
+       uint32_t k;
+       uint32_t numBands;
+       int rtn;
+       int intersects;
+
+       LWPOLY *hull[2] = {NULL};
+       GEOSGeometry *ghull[2] = {NULL};
+
+       for (i = 0, j = 0; i < set_count; i++) {
+               /* pgrast is null, return null */
+               if (PG_ARGISNULL(j)) {
+                       for (k = 0; k < i; k++) rt_raster_destroy(rast[k]);
+                       PG_RETURN_NULL();
+               }
+               pgrast = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(j));
+               j++;
+
+               /* raster */
+               rast[i] = rt_raster_deserialize(pgrast, FALSE);
+               if (!rast[i]) {
+                       elog(ERROR, "RASTER_intersects: Could not deserialize the %s raster", i < 1 ? "first" : "second");
+                       for (k = 0; k < i; k++) rt_raster_destroy(rast[k]);
+                       PG_RETURN_NULL();
+               }
+
+               /* numbands */
+               numBands = rt_raster_get_num_bands(rast[i]);
+               if (numBands < 1) {
+                       elog(NOTICE, "The %s raster provided has no bands", i < 1 ? "first" : "second");
+                       for (k = 0; k < i; k++) rt_raster_destroy(rast[k]);
+                       PG_RETURN_NULL();
+               }
+
+               /* band index */
+               if (!PG_ARGISNULL(j)) {
+                       bandindex[i] = PG_GETARG_INT32(j);
+                       if (bandindex[i] < 1 || bandindex[i] > numBands) {
+                               elog(NOTICE, "Invalid band index (must use 1-based) for the %s raster. Returning NULL", i < 1 ? "first" : "second");
+                               for (k = 0; k < i; k++) rt_raster_destroy(rast[k]);
+                               PG_RETURN_NULL();
+                       }
+                       hasbandindex[i] = 1;
+               }
+               else
+                       hasbandindex[i] = 0;
+               POSTGIS_RT_DEBUGF(4, "hasbandindex[%d] = %d", i, hasbandindex[i]);
+               POSTGIS_RT_DEBUGF(4, "bandindex[%d] = %d", i, bandindex[i]);
+               j++;
+       }
+
+       /* hasbandindex must be balanced */
+       if (
+               (hasbandindex[0] && !hasbandindex[1]) ||
+               (!hasbandindex[0] && hasbandindex[1])
+       ) {
+               elog(NOTICE, "Missing band index.  Band indices must be provided for both rasters if any one is provided");
+               for (k = 0; k < i; k++) rt_raster_destroy(rast[k]);
+               PG_RETURN_NULL();
+       }
+
+       /* SRID must match */
+       if (rt_raster_get_srid(rast[0]) != rt_raster_get_srid(rast[1])) {
+               elog(NOTICE, "The two rasters provided have different SRIDs");
+               for (k = 0; k < set_count; k++) rt_raster_destroy(rast[k]);
+               PG_RETURN_NULL();
+       }
+
+       /* raster extents need to intersect */
+       do {
+               initGEOS(lwnotice, lwgeom_geos_error);
+
+               rtn = 1;
+               for (i = 0; i < 2; i++) {
+                       hull[i] = rt_raster_get_convex_hull(rast[i]);
+                       if (NULL == hull[i]) {
+                               for (j = 0; j < i; j++) {
+                                       GEOSGeom_destroy(ghull[j]);
+                                       lwpoly_free(hull[j]);
+                               }
+                               rtn = 0;
+                               break;
+                       }
+                       ghull[i] = (GEOSGeometry *) LWGEOM2GEOS((LWGEOM *) hull[i]);
+                       if (NULL == ghull[i]) {
+                               for (j = 0; j < i; j++) {
+                                       GEOSGeom_destroy(ghull[j]);
+                                       lwpoly_free(hull[j]);
+                               }
+                               lwpoly_free(hull[i]);
+                               rtn = 0;
+                               break;
+                       }
+               }
+               if (!rtn) break;
+
+               rtn = GEOSIntersects(ghull[0], ghull[1]);
+
+               for (i = 0; i < 2; i++) {
+                       GEOSGeom_destroy(ghull[i]);
+                       lwpoly_free(hull[i]);
+               }
+
+               if (rtn != 2) {
+                       if (rtn != 1) {
+                               for (k = 0; k < set_count; k++) rt_raster_destroy(rast[k]);
+                               PG_RETURN_BOOL(0);
+                       }
+                       /* band isn't specified */
+                       else if (!hasbandindex[0]) {
+                               for (k = 0; k < set_count; k++) rt_raster_destroy(rast[k]);
+                               PG_RETURN_BOOL(1);
+                       }
+               }
+       }
+       while (0);
+
+       rtn = rt_raster_intersects(
+               rast[0], (hasbandindex[0] ? bandindex[0] - 1 : -1),
+               rast[1], (hasbandindex[1] ? bandindex[1] - 1 : -1),
+               &intersects
+       );
+       for (k = 0; k < set_count; k++) rt_raster_destroy(rast[k]);
+
+       if (!rtn) {
+               elog(ERROR, "RASTER_intersects: Unable to test for intersection on the two rasters");
+               PG_RETURN_NULL();
+       }
+
+       PG_RETURN_BOOL(intersects);
+}
+
 /* ---------------------------------------------------------------- */
 /*  Memory allocation / error reporting hooks                       */
 /* ---------------------------------------------------------------- */
index 7875cea5902bdf5d1eea335a71804e8cccdaa1b0..61a83fc32679c2bbef23301ee03e944dd3f61a65 100644 (file)
@@ -1302,7 +1302,8 @@ CREATE OR REPLACE FUNCTION _st_asraster(
        nodataval double precision[] DEFAULT ARRAY[0]::double precision[],
        upperleftx double precision DEFAULT NULL, upperlefty double precision DEFAULT NULL,
        gridx double precision DEFAULT NULL, gridy double precision DEFAULT NULL,
-       skewx double precision DEFAULT 0, skewy double precision DEFAULT 0
+       skewx double precision DEFAULT 0, skewy double precision DEFAULT 0,
+       touched boolean DEFAULT FALSE
 )
        RETURNS raster
        AS 'MODULE_PATHNAME', 'RASTER_asRaster'
@@ -1315,10 +1316,11 @@ CREATE OR REPLACE FUNCTION st_asraster(
        pixeltype text[] DEFAULT ARRAY['8BUI']::text[],
        value double precision[] DEFAULT ARRAY[1]::double precision[],
        nodataval double precision[] DEFAULT ARRAY[0]::double precision[],
-       skewx double precision DEFAULT 0, skewy double precision DEFAULT 0
+       skewx double precision DEFAULT 0, skewy double precision DEFAULT 0,
+       touched boolean DEFAULT FALSE
 )
        RETURNS raster
-       AS $$ SELECT _st_asraster($1, $2, $3, NULL, NULL, $6, $7, $8, NULL, NULL, $4, $5, $9, $10) $$
+       AS $$ SELECT _st_asraster($1, $2, $3, NULL, NULL, $6, $7, $8, NULL, NULL, $4, $5, $9, $10, $11) $$
        LANGUAGE 'sql' STABLE;
 
 CREATE OR REPLACE FUNCTION st_asraster(
@@ -1328,10 +1330,11 @@ CREATE OR REPLACE FUNCTION st_asraster(
        value double precision[] DEFAULT ARRAY[1]::double precision[],
        nodataval double precision[] DEFAULT ARRAY[0]::double precision[],
        upperleftx double precision DEFAULT NULL, upperlefty double precision DEFAULT NULL,
-       skewx double precision DEFAULT 0, skewy double precision DEFAULT 0
+       skewx double precision DEFAULT 0, skewy double precision DEFAULT 0,
+       touched boolean DEFAULT FALSE
 )
        RETURNS raster
-       AS $$ SELECT _st_asraster($1, $2, $3, NULL, NULL, $4, $5, $6, $7, $8, NULL, NULL,       $9, $10) $$
+       AS $$ SELECT _st_asraster($1, $2, $3, NULL, NULL, $4, $5, $6, $7, $8, NULL, NULL,       $9, $10, $11) $$
        LANGUAGE 'sql' STABLE;
 
 CREATE OR REPLACE FUNCTION st_asraster(
@@ -1341,10 +1344,11 @@ CREATE OR REPLACE FUNCTION st_asraster(
        pixeltype text[] DEFAULT ARRAY['8BUI']::text[],
        value double precision[] DEFAULT ARRAY[1]::double precision[],
        nodataval double precision[] DEFAULT ARRAY[0]::double precision[],
-       skewx double precision DEFAULT 0, skewy double precision DEFAULT 0
+       skewx double precision DEFAULT 0, skewy double precision DEFAULT 0,
+       touched boolean DEFAULT FALSE
 )
        RETURNS raster
-       AS $$ SELECT _st_asraster($1, NULL, NULL, $2, $3, $6, $7, $8, NULL, NULL, $4, $5, $9, $10) $$
+       AS $$ SELECT _st_asraster($1, NULL, NULL, $2, $3, $6, $7, $8, NULL, NULL, $4, $5, $9, $10, $11) $$
        LANGUAGE 'sql' STABLE;
 
 CREATE OR REPLACE FUNCTION st_asraster(
@@ -1354,10 +1358,11 @@ CREATE OR REPLACE FUNCTION st_asraster(
        value double precision[] DEFAULT ARRAY[1]::double precision[],
        nodataval double precision[] DEFAULT ARRAY[0]::double precision[],
        upperleftx double precision DEFAULT NULL, upperlefty double precision DEFAULT NULL,
-       skewx double precision DEFAULT 0, skewy double precision DEFAULT 0
+       skewx double precision DEFAULT 0, skewy double precision DEFAULT 0,
+       touched boolean DEFAULT FALSE
 )
        RETURNS raster
-       AS $$ SELECT _st_asraster($1, NULL, NULL, $2, $3, $4, $5, $6, $7, $8, NULL, NULL,       $9, $10) $$
+       AS $$ SELECT _st_asraster($1, NULL, NULL, $2, $3, $4, $5, $6, $7, $8, NULL, NULL,       $9, $10, $11) $$
        LANGUAGE 'sql' STABLE;
 
 CREATE OR REPLACE FUNCTION st_asraster(
@@ -1367,10 +1372,11 @@ CREATE OR REPLACE FUNCTION st_asraster(
        pixeltype text,
        value double precision DEFAULT 1,
        nodataval double precision DEFAULT 0,
-       skewx double precision DEFAULT 0, skewy double precision DEFAULT 0
+       skewx double precision DEFAULT 0, skewy double precision DEFAULT 0,
+       touched boolean DEFAULT FALSE
 )
        RETURNS raster
-       AS $$ SELECT _st_asraster($1, $2, $3, NULL, NULL, ARRAY[$6]::text[], ARRAY[$7]::double precision[], ARRAY[$8]::double precision[], NULL, NULL, $4, $5, $9, $10) $$
+       AS $$ SELECT _st_asraster($1, $2, $3, NULL, NULL, ARRAY[$6]::text[], ARRAY[$7]::double precision[], ARRAY[$8]::double precision[], NULL, NULL, $4, $5, $9, $10, $11) $$
        LANGUAGE 'sql' STABLE;
 
 CREATE OR REPLACE FUNCTION st_asraster(
@@ -1380,10 +1386,11 @@ CREATE OR REPLACE FUNCTION st_asraster(
        value double precision DEFAULT 1,
        nodataval double precision DEFAULT 0,
        upperleftx double precision DEFAULT NULL, upperlefty double precision DEFAULT NULL,
-       skewx double precision DEFAULT 0, skewy double precision DEFAULT 0
+       skewx double precision DEFAULT 0, skewy double precision DEFAULT 0,
+       touched boolean DEFAULT FALSE
 )
        RETURNS raster
-       AS $$ SELECT _st_asraster($1, $2, $3, NULL, NULL, ARRAY[$4]::text[], ARRAY[$5]::double precision[], ARRAY[$6]::double precision[], $7, $8, NULL, NULL, $9, $10) $$
+       AS $$ SELECT _st_asraster($1, $2, $3, NULL, NULL, ARRAY[$4]::text[], ARRAY[$5]::double precision[], ARRAY[$6]::double precision[], $7, $8, NULL, NULL, $9, $10, $11) $$
        LANGUAGE 'sql' STABLE;
 
 CREATE OR REPLACE FUNCTION st_asraster(
@@ -1393,10 +1400,11 @@ CREATE OR REPLACE FUNCTION st_asraster(
        pixeltype text,
        value double precision DEFAULT 1,
        nodataval double precision DEFAULT 0,
-       skewx double precision DEFAULT 0, skewy double precision DEFAULT 0
+       skewx double precision DEFAULT 0, skewy double precision DEFAULT 0,
+       touched boolean DEFAULT FALSE
 )
        RETURNS raster
-       AS $$ SELECT _st_asraster($1, NULL, NULL, $2, $3, ARRAY[$6]::text[], ARRAY[$7]::double precision[], ARRAY[$8]::double precision[], NULL, NULL, $4, $5, $9, $10) $$
+       AS $$ SELECT _st_asraster($1, NULL, NULL, $2, $3, ARRAY[$6]::text[], ARRAY[$7]::double precision[], ARRAY[$8]::double precision[], NULL, NULL, $4, $5, $9, $10, $11) $$
        LANGUAGE 'sql' STABLE;
 
 CREATE OR REPLACE FUNCTION st_asraster(
@@ -1406,10 +1414,11 @@ CREATE OR REPLACE FUNCTION st_asraster(
        value double precision DEFAULT 1,
        nodataval double precision DEFAULT 0,
        upperleftx double precision DEFAULT NULL, upperlefty double precision DEFAULT NULL,
-       skewx double precision DEFAULT 0, skewy double precision DEFAULT 0
+       skewx double precision DEFAULT 0, skewy double precision DEFAULT 0,
+       touched boolean DEFAULT FALSE
 )
        RETURNS raster
-       AS $$ SELECT _st_asraster($1, NULL, NULL, $2, $3, ARRAY[$4]::text[], ARRAY[$5]::double precision[], ARRAY[$6]::double precision[], $7, $8, NULL, NULL,$9, $10) $$
+       AS $$ SELECT _st_asraster($1, NULL, NULL, $2, $3, ARRAY[$4]::text[], ARRAY[$5]::double precision[], ARRAY[$6]::double precision[], $7, $8, NULL, NULL,$9, $10, $11) $$
        LANGUAGE 'sql' STABLE;
 
 CREATE OR REPLACE FUNCTION st_asraster(
@@ -1417,7 +1426,8 @@ CREATE OR REPLACE FUNCTION st_asraster(
        ref raster,
        pixeltype text[] DEFAULT ARRAY['8BUI']::text[],
        value double precision[] DEFAULT ARRAY[1]::double precision[],
-       nodataval double precision[] DEFAULT ARRAY[0]::double precision[]
+       nodataval double precision[] DEFAULT ARRAY[0]::double precision[],
+       touched boolean DEFAULT FALSE
 )
        RETURNS raster
        AS $$
@@ -1445,7 +1455,7 @@ CREATE OR REPLACE FUNCTION st_asraster(
                        g := geom;
                END IF;
        
-               RETURN _st_asraster(g, scale_x, scale_y, NULL, NULL, $3, $4, $5, NULL, NULL, ul_x, ul_y, skew_x, skew_y);
+               RETURN _st_asraster(g, scale_x, scale_y, NULL, NULL, $3, $4, $5, NULL, NULL, ul_x, ul_y, skew_x, skew_y, $6);
        END;
        $$ LANGUAGE 'plpgsql' STABLE;
 
@@ -1454,10 +1464,11 @@ CREATE OR REPLACE FUNCTION st_asraster(
        ref raster,
        pixeltype text,
        value double precision DEFAULT 1,
-       nodataval double precision DEFAULT 0
+       nodataval double precision DEFAULT 0,
+       touched boolean DEFAULT FALSE
 )
        RETURNS raster
-       AS $$ SELECT st_asraster($1, $2, ARRAY[$3]::text[], ARRAY[$4]::double precision[], ARRAY[$5]::double precision[]) $$
+       AS $$ SELECT st_asraster($1, $2, ARRAY[$3]::text[], ARRAY[$4]::double precision[], ARRAY[$5]::double precision[], $6) $$
        LANGUAGE 'sql' STABLE;
 
 -----------------------------------------------------------------------
@@ -2105,7 +2116,7 @@ CREATE OR REPLACE FUNCTION st_world2rastercoordx(rast raster, xw float8, yw floa
     LANGUAGE 'plpgsql' IMMUTABLE STRICT;
 
 ---------------------------------------------------------------------------------
--- ST_World2RasteCoordX(rast raster, xw float8)
+-- ST_World2RasterCoordX(rast raster, xw float8)
 -- Returns the column number of the pixels covering the provided world X coordinate
 -- for a non-rotated raster.
 -- This function works even if the world coordinate is outside the raster extent.
@@ -2508,183 +2519,200 @@ CREATE OPERATOR ~ (
     RESTRICT = contsel, JOIN = contjoinsel
     );
 
+-----------------------------------------------------------------------
+-- Raster/Raster Spatial Relationship
+-----------------------------------------------------------------------
+CREATE OR REPLACE FUNCTION _st_intersects(rastA raster, nbandA integer, rastB raster, nbandB integer)
+       RETURNS boolean
+       AS 'MODULE_PATHNAME', 'RASTER_intersects'
+       LANGUAGE 'C' IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION st_intersects(rastA raster, nbandA integer, rastB raster, nbandB integer)
+       RETURNS boolean
+       AS $$ SELECT $1 && $3 AND _st_intersects($1, $2, $3, $4) $$
+       LANGUAGE 'SQL' IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION st_intersects(rastA raster, rastB raster, nbandA integer DEFAULT NULL, nbandB integer DEFAULT NULL)
+       RETURNS boolean
+       AS $$ SELECT $1 && $2 AND _st_intersects($1, $3, $2, $4) $$
+       LANGUAGE 'SQL' IMMUTABLE;
+
 -----------------------------------------------------------------------
 -- Raster/Geometry Spatial Relationship
 -----------------------------------------------------------------------
 
+CREATE OR REPLACE FUNCTION _st_intersects(rast raster, geom geometry, nband integer DEFAULT NULL)
+       RETURNS boolean
+       AS $$
+       DECLARE
+               gr raster;
+               scale double precision;
+       BEGIN
+               IF ST_Intersects(geom, ST_ConvexHull(rast)) IS NOT TRUE THEN
+                       RETURN FALSE;
+               ELSEIF nband IS NULL THEN
+                       RETURN TRUE;
+               END IF;
+
+               -- scale is set to 1/100th of raster for granularity
+               SELECT CASE WHEN scaley < scalex THEN scaley ELSE scalex END / 100 INTO scale FROM ST_Metadata(rast);
+               gr := ST_AsRaster(geom, scale, scale);
+               IF gr IS NULL THEN
+                       RAISE EXCEPTION 'Unable to convert geometry to a raster';
+                       RETURN FALSE;
+               END IF;
+
+               RETURN ST_Intersects(rast, 1, gr, 1);
+       END;
+       $$ LANGUAGE 'plpgsql' IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION st_intersects(rast raster, geom geometry, nband integer DEFAULT NULL)
+       RETURNS boolean
+       AS $$ SELECT $1 && $2 AND _st_intersects($1, $2, $3) $$
+       LANGUAGE 'SQL' IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION st_intersects(rast raster, nband integer, geom geometry)
+       RETURNS boolean
+       AS $$ SELECT $1 && $3 AND _st_intersects($1, $3, $2) $$
+       LANGUAGE 'SQL' IMMUTABLE STRICT;
+
 -----------------------------------------------------------------------
--- _st_intersects(geomin geometry, rast raster, band integer, hasnodata boolean)
--- If hasnodata is true, check for the presence of withvalue pixels in the area
+-- _st_intersects(geom geometry, rast raster, nband integer)
+-- If band is provided, check for the presence of withvalue pixels in the area
 -- shared by the raster and the geometry. If only nodata value pixels are found, the
 -- geometry does not intersect with the raster.
 -----------------------------------------------------------------------
-CREATE OR REPLACE FUNCTION _st_intersects(geomin geometry, rast raster, band integer, hasnodata boolean)
-    RETURNS boolean AS
-    $$
-    DECLARE
-        nodata float8 := 0.0;
-        geomintersect geometry;
-        x1w double precision := 0.0;
-        x2w double precision := 0.0;
-        y1w double precision := 0.0;
-        y2w double precision := 0.0;
-        x1 integer := 0;
-        x2 integer := 0;
-        x3 integer := 0;
-        x4 integer := 0;
-        y1 integer := 0;
-        y2 integer := 0;
-        y3 integer := 0;
-        y4 integer := 0;
-        x integer := 0;
-        y integer := 0;
-        xinc integer := 0;
-        yinc integer := 0;
-        pixelval double precision;
-        bintersect boolean := FALSE;
-        gtype text;
-        scale float8;
-                               w int;
-                               h int;
-    BEGIN
+-- This function can not be STRICT
+CREATE OR REPLACE FUNCTION _st_intersects(geom geometry, rast raster, nband integer DEFAULT NULL)
+       RETURNS boolean AS $$
+       DECLARE
+               hasnodata boolean := TRUE;
+               nodata float8 := 0.0;
+               convexhull geometry;
+               geomintersect geometry;
+               x1w double precision := 0.0;
+               x2w double precision := 0.0;
+               y1w double precision := 0.0;
+               y2w double precision := 0.0;
+               x1 integer := 0;
+               x2 integer := 0;
+               x3 integer := 0;
+               x4 integer := 0;
+               y1 integer := 0;
+               y2 integer := 0;
+               y3 integer := 0;
+               y4 integer := 0;
+               x integer := 0;
+               y integer := 0;
+               xinc integer := 0;
+               yinc integer := 0;
+               pixelval double precision;
+               bintersect boolean := FALSE;
+               gtype text;
+               scale float8;
+               w int;
+               h int;
+       BEGIN
+               convexhull := ST_ConvexHull(rast);
+               IF nband IS NOT NULL THEN
+                       SELECT hasnodatavalue INTO hasnodata FROM ST_BandMetaData(rast, nband);
+               END IF;
 
-        -- Get the intersection between with the geometry.
-        -- We will search for withvalue pixel only in this area.
-        geomintersect := st_intersection(geomin, st_convexhull(rast));
+               IF ST_Intersects(geom, convexhull) IS NOT TRUE THEN
+                       RETURN FALSE;
+               ELSEIF nband IS NULL OR hasnodata IS FALSE THEN
+                       RETURN TRUE;
+               END IF;
 
---RAISE NOTICE 'geomintersect1=%', astext(geomintersect);
+               -- Get the intersection between with the geometry.
+               -- We will search for withvalue pixel only in this area.
+               geomintersect := st_intersection(geom, convexhull);
 
-        -- If the intersection is empty, return false
-        IF st_isempty(geomintersect) THEN
-            RETURN FALSE;
-        END IF;
+--RAISE NOTICE 'geomintersect=%', st_astext(geomintersect);
 
-        -- If the band does not have a nodatavalue, there is no need to search for with value pixels
-        IF NOT hasnodata OR st_bandnodatavalue(rast, band) IS NULL THEN
-            RETURN TRUE;
-        END IF;
+               -- If the intersection is empty, return false
+               IF st_isempty(geomintersect) THEN
+                       RETURN FALSE;
+               END IF;
 
-        -- We create a minimalistic buffer around the intersection in order to scan every pixels
-        -- that would touch the edge or intersect with the geometry
-        SELECT (scalex * skewy), width, height INTO scale, w, h FROM ST_Metadata(rast);
-        geomintersect := st_buffer(geomintersect, scale / 1000000);
+               -- We create a minimalistic buffer around the intersection in order to scan every pixels
+               -- that would touch the edge or intersect with the geometry
+               SELECT (scalex * skewy), width, height INTO scale, w, h FROM ST_Metadata(rast);
+               geomintersect := st_buffer(geomintersect, scale / 1000000);
 
 --RAISE NOTICE 'geomintersect2=%', astext(geomintersect);
 
-        -- Find the world coordinates of the bounding box of the intersecting area
-        x1w := st_xmin(geomintersect);
-        y1w := st_ymin(geomintersect);
-        x2w := st_xmax(geomintersect);
-        y2w := st_ymax(geomintersect);
-        nodata := st_bandnodatavalue(rast, band);
+               -- Find the world coordinates of the bounding box of the intersecting area
+               x1w := st_xmin(geomintersect);
+               y1w := st_ymin(geomintersect);
+               x2w := st_xmax(geomintersect);
+               y2w := st_ymax(geomintersect);
+               nodata := st_bandnodatavalue(rast, nband);
 
 --RAISE NOTICE 'x1w=%, y1w=%, x2w=%, y2w=%', x1w, y1w, x2w, y2w;
 
-        -- Convert world coordinates to raster coordinates
-        x1 := st_world2rastercoordx(rast, x1w, y1w);
-        y1 := st_world2rastercoordy(rast, x1w, y1w);
-        x2 := st_world2rastercoordx(rast, x2w, y1w);
-        y2 := st_world2rastercoordy(rast, x2w, y1w);
-        x3 := st_world2rastercoordx(rast, x1w, y2w);
-        y3 := st_world2rastercoordy(rast, x1w, y2w);
-        x4 := st_world2rastercoordx(rast, x2w, y2w);
-        y4 := st_world2rastercoordy(rast, x2w, y2w);
+               -- Convert world coordinates to raster coordinates
+               x1 := st_world2rastercoordx(rast, x1w, y1w);
+               y1 := st_world2rastercoordy(rast, x1w, y1w);
+               x2 := st_world2rastercoordx(rast, x2w, y1w);
+               y2 := st_world2rastercoordy(rast, x2w, y1w);
+               x3 := st_world2rastercoordx(rast, x1w, y2w);
+               y3 := st_world2rastercoordy(rast, x1w, y2w);
+               x4 := st_world2rastercoordx(rast, x2w, y2w);
+               y4 := st_world2rastercoordy(rast, x2w, y2w);
 
 --RAISE NOTICE 'x1=%, y1=%, x2=%, y2=%, x3=%, y3=%, x4=%, y4=%', x1, y1, x2, y2, x3, y3, x4, y4;
 
-        -- Order the raster coordinates for the upcoming FOR loop.
-        x1 := int4smaller(int4smaller(int4smaller(x1, x2), x3), x4);
-        y1 := int4smaller(int4smaller(int4smaller(y1, y2), y3), y4);
-        x2 := int4larger(int4larger(int4larger(x1, x2), x3), x4);
-        y2 := int4larger(int4larger(int4larger(y1, y2), y3), y4);
+               -- Order the raster coordinates for the upcoming FOR loop.
+               x1 := int4smaller(int4smaller(int4smaller(x1, x2), x3), x4);
+               y1 := int4smaller(int4smaller(int4smaller(y1, y2), y3), y4);
+               x2 := int4larger(int4larger(int4larger(x1, x2), x3), x4);
+               y2 := int4larger(int4larger(int4larger(y1, y2), y3), y4);
 
-        -- Make sure the range is not lower than 1.
-        -- This can happen when world coordinate are exactly on the left border
-        -- of the raster and that they do not span on more than one pixel.
-        x1 := int4smaller(int4larger(x1, 1), w);
-        y1 := int4smaller(int4larger(y1, 1), h);
+               -- Make sure the range is not lower than 1.
+               -- This can happen when world coordinate are exactly on the left border
+               -- of the raster and that they do not span on more than one pixel.
+               x1 := int4smaller(int4larger(x1, 1), w);
+               y1 := int4smaller(int4larger(y1, 1), h);
 
-        -- Also make sure the range does not exceed the width and height of the raster.
-        -- This can happen when world coordinate are exactly on the lower right border
-        -- of the raster.
-        x2 := int4smaller(x2, w);
-        y2 := int4smaller(y2, h);
+               -- Also make sure the range does not exceed the width and height of the raster.
+               -- This can happen when world coordinate are exactly on the lower right border
+               -- of the raster.
+               x2 := int4smaller(x2, w);
+               y2 := int4smaller(y2, h);
 
 --RAISE NOTICE 'x1=%, y1=%, x2=%, y2=%', x1, y1, x2, y2;
 
-        -- Search exhaustively for withvalue pixel on a moving 3x3 grid
-        -- (very often more efficient than searching on a mere 1x1 grid)
-        FOR xinc in 0..2 LOOP
-            FOR yinc in 0..2 LOOP
-                FOR x IN x1+xinc..x2 BY 3 LOOP
-                    FOR y IN y1+yinc..y2 BY 3 LOOP
-                        -- Check first if the pixel intersects with the geometry. Often many won't.
-                        bintersect := NOT st_isempty(st_intersection(st_pixelaspolygon(rast, band, x, y), geomin));
-
-                        IF bintersect THEN
-                            -- If the pixel really intersects, check its value. Return TRUE if with value.
-                            pixelval := st_value(rast, band, x, y);
-                            IF pixelval != nodata THEN
-                                RETURN TRUE;
-                            END IF;
-                        END IF;
-                    END LOOP;
-                END LOOP;
-            END LOOP;
-        END LOOP;
-        RETURN FALSE;
-    END;
-    $$
-    LANGUAGE 'plpgsql' IMMUTABLE STRICT;
-
-
--- This function can not be STRICT
-CREATE OR REPLACE FUNCTION st_intersects(geometry, raster, integer)
-    RETURNS boolean AS
-    $$ SELECT $1 && $2 AND _st_intersects($1, $2, $3, TRUE);
-    $$ LANGUAGE 'SQL' IMMUTABLE;
-
--- This function can not be STRICT
-CREATE OR REPLACE FUNCTION st_intersects(raster, integer, geometry)
-    RETURNS boolean AS
-    $$ SELECT st_intersects($3, $1, $2);
-    $$ LANGUAGE 'SQL' IMMUTABLE;
-
--- This function can not be STRICT
-CREATE OR REPLACE FUNCTION st_intersects(geometry, raster)
-    RETURNS boolean AS
-    $$ SELECT st_intersects($1, $2, 1);
-    $$ LANGUAGE 'SQL' IMMUTABLE;
-
--- This function can not be STRICT
-CREATE OR REPLACE FUNCTION st_intersects(raster, geometry)
-    RETURNS boolean AS
-    $$ SELECT st_intersects($2, $1, 1);
-    $$ LANGUAGE 'SQL' IMMUTABLE;
-
--- This function can not be STRICT
-CREATE OR REPLACE FUNCTION st_intersects(geometry, raster, integer, boolean)
-    RETURNS boolean AS
-    $$ SELECT $1 && $2 AND _st_intersects($1, $2, $3, $4);
-    $$ LANGUAGE 'SQL' IMMUTABLE;
-
--- This function can not be STRICT
-CREATE OR REPLACE FUNCTION st_intersects(raster, integer, boolean, geometry)
-    RETURNS boolean AS
-    $$ SELECT st_intersects($4, $1, $2, $3);
-    $$ LANGUAGE 'SQL' IMMUTABLE;
+               -- Search exhaustively for withvalue pixel on a moving 3x3 grid
+               -- (very often more efficient than searching on a mere 1x1 grid)
+               FOR xinc in 0..2 LOOP
+                       FOR yinc in 0..2 LOOP
+                               FOR x IN x1+xinc..x2 BY 3 LOOP
+                                       FOR y IN y1+yinc..y2 BY 3 LOOP
+                                               -- Check first if the pixel intersects with the geometry. Often many won't.
+                                               bintersect := NOT st_isempty(st_intersection(st_pixelaspolygon(rast, nband, x, y), geom));
+                                               
+                                               IF bintersect THEN
+                                                       -- If the pixel really intersects, check its value. Return TRUE if with value.
+                                                       pixelval := st_value(rast, nband, x, y);
+                                                       IF pixelval != nodata THEN
+                                                               RETURN TRUE;
+                                                       END IF;
+                                               END IF;
+                                       END LOOP;
+                               END LOOP;
+                       END LOOP;
+               END LOOP;
 
--- This function can not be STRICT
-CREATE OR REPLACE FUNCTION st_intersects(geometry, raster, boolean)
-    RETURNS boolean AS
-    $$ SELECT st_intersects($1, $2, 1, $3);
-    $$ LANGUAGE 'SQL' IMMUTABLE;
+               RETURN FALSE;
+       END;
+       $$ LANGUAGE 'plpgsql' IMMUTABLE;
 
 -- This function can not be STRICT
-CREATE OR REPLACE FUNCTION st_intersects(raster, boolean, geometry)
-    RETURNS boolean AS
-    $$ SELECT st_intersects($3, $1, 1, $2);
-    $$ LANGUAGE 'SQL' IMMUTABLE;
+CREATE OR REPLACE FUNCTION st_intersects(geom geometry, rast raster, nband integer DEFAULT NULL)
+       RETURNS boolean AS
+       $$ SELECT $1 && $2 AND _st_intersects($1, $2, $3); $$
+       LANGUAGE 'SQL' IMMUTABLE;
 
 -----------------------------------------------------------------------
 -- _st_intersection(geom geometry, rast raster, band integer)
@@ -2695,58 +2723,50 @@ CREATE OR REPLACE FUNCTION st_intersects(raster, boolean, geometry)
 -- Raster nodata value areas are not vectorized and hence do not intersect
 -- with any geometries.
 -----------------------------------------------------------------------
-CREATE OR REPLACE FUNCTION ST_Intersection(geomin geometry, rast raster, band integer)
-  RETURNS SETOF geomval AS
-$BODY$
-    DECLARE
-        intersects boolean := FALSE;
-    BEGIN
-        intersects := ST_Intersects(geomin, rast, band);
-        IF intersects THEN
-            -- Return the intersections of the geometry with the vectorized parts of
-            -- the raster and the values associated with those parts, if really their
-            -- intersection is not empty.
-            RETURN QUERY
-                SELECT intgeom,
-                       val
-                FROM (SELECT ST_Intersection((gv).geom, geomin) AS intgeom,
-                             (gv).val
-                      FROM ST_DumpAsPolygons(rast, band) gv
-                      WHERE ST_Intersects((gv).geom, geomin)
-                     ) foo
-                WHERE NOT ST_IsEmpty(intgeom);
-        ELSE
-            -- If the geometry does not intersect with the raster, return an empty
-            -- geometry and a null value
-            RETURN QUERY
-                SELECT emptygeom,
-                       NULL::float8
-                FROM ST_GeomCollFromText('GEOMETRYCOLLECTION EMPTY', ST_SRID($1)) emptygeom;
-        END IF;
-    END;
-    $BODY$
-  LANGUAGE 'plpgsql' IMMUTABLE STRICT;
+CREATE OR REPLACE FUNCTION st_intersection(geomin geometry, rast raster, band integer DEFAULT 1)
+       RETURNS SETOF geomval AS $$
+       DECLARE
+               intersects boolean := FALSE;
+       BEGIN
+               intersects := ST_Intersects(geomin, rast, band);
+               IF intersects THEN
+                       -- Return the intersections of the geometry with the vectorized parts of
+                       -- the raster and the values associated with those parts, if really their
+                       -- intersection is not empty.
+                       RETURN QUERY
+                               SELECT
+                                       intgeom,
+                                       val
+                               FROM (
+                                       SELECT
+                                               ST_Intersection((gv).geom, geomin) AS intgeom,
+                                               (gv).val
+                                       FROM ST_DumpAsPolygons(rast, band) gv
+                                       WHERE ST_Intersects((gv).geom, geomin)
+                               ) foo
+                               WHERE NOT ST_IsEmpty(intgeom);
+               ELSE
+                       -- If the geometry does not intersect with the raster, return an empty
+                       -- geometry and a null value
+                       RETURN QUERY
+                               SELECT
+                                       emptygeom,
+                                       NULL::float8
+                               FROM ST_GeomCollFromText('GEOMETRYCOLLECTION EMPTY', ST_SRID($1)) emptygeom;
+               END IF;
+       END;
+       $$
+       LANGUAGE 'plpgsql' IMMUTABLE STRICT;
 
 CREATE OR REPLACE FUNCTION st_intersection(rast raster, geom geometry)
-    RETURNS SETOF geomval AS
-    $$
-        SELECT (gv).geom, (gv).val FROM st_intersection($2, $1, 1) gv;
-    $$
-    LANGUAGE SQL IMMUTABLE STRICT;
-
-CREATE OR REPLACE FUNCTION st_intersection(geom geometry, rast raster)
-    RETURNS SETOF geomval AS
-    $$
-        SELECT (gv).geom, (gv).val FROM st_intersection($1, $2, 1) gv;
-    $$
-    LANGUAGE SQL IMMUTABLE STRICT;
+       RETURNS SETOF geomval
+       AS $$ SELECT (gv).geom, (gv).val FROM st_intersection($2, $1, 1) gv; $$
+       LANGUAGE SQL IMMUTABLE STRICT;
 
 CREATE OR REPLACE FUNCTION st_intersection(rast raster, band integer, geom geometry)
-    RETURNS SETOF geomval AS
-    $$
-        SELECT (gv).geom, (gv).val FROM st_intersection($3, $1, $2) gv;
-    $$
-    LANGUAGE SQL IMMUTABLE STRICT;
+       RETURNS SETOF geomval
+       AS $$ SELECT (gv).geom, (gv).val FROM st_intersection($3, $1, $2) gv; $$
+       LANGUAGE SQL IMMUTABLE STRICT;
 
 ------------------------------------------------------------------------------
 -- RASTER_COLUMNS
index dd7ae4abb1694b59a7ac59193b8b5edc20c8c524..d27f815a7b36545246ac64f33c3ec6a2b7ae163d 100644 (file)
@@ -1138,6 +1138,8 @@ static void testBandStats() {
        qlls = NULL;
        qlls_count = 0;
 
+       deepRelease(raster);
+
        xmax = 100;
        ymax = 100;
        raster = rt_raster_new(xmax, ymax);
@@ -1579,7 +1581,8 @@ static void testGDALRasterize() {
                &scale_x, &scale_y,
                NULL, NULL,
                NULL, NULL,
-               NULL, NULL
+               NULL, NULL,
+               NULL
        );
 
        free(wkb);
@@ -1594,6 +1597,469 @@ static void testGDALRasterize() {
        deepRelease(raster);
 }
 
+static void testIntersects() {
+       rt_raster rast1;
+       rt_raster rast2;
+       rt_band band1;
+       rt_band band2;
+       double nodata;
+       int rtn;
+       int intersects;
+
+       /*
+               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);
+
+       /*
+               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_intersects(
+               rast1, 0,
+               rast2, 0,
+               &intersects
+       );
+       CHECK((rtn != 0));
+       CHECK((intersects == 1));
+
+       rtn = rt_raster_intersects(
+               rast1, -1,
+               rast2, -1,
+               &intersects
+       );
+       CHECK((rtn != 0));
+       CHECK((intersects == 1));
+
+       /*
+               rast2
+
+               (0, 0)
+                                               +-+-+
+                                               |0|1|
+                                               +-+-+
+                                               |1|1|
+                                               +-+-+
+                                                               (2, 2)
+       */
+       rtn = rt_band_set_pixel(band2, 0, 0, 0);
+
+       rtn = rt_raster_intersects(
+               rast1, 0,
+               rast2, 0,
+               &intersects
+       );
+       CHECK((rtn != 0));
+       CHECK((intersects == 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_intersects(
+               rast1, 0,
+               rast2, 0,
+               &intersects
+       );
+       CHECK((rtn != 0));
+       CHECK((intersects == 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_intersects(
+               rast1, 0,
+               rast2, 0,
+               &intersects
+       );
+       CHECK((rtn != 0));
+       CHECK((intersects == 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_intersects(
+               rast1, 0,
+               rast2, 0,
+               &intersects
+       );
+       CHECK((rtn != 0));
+       CHECK((intersects != 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_intersects(
+               rast1, 0,
+               rast2, 0,
+               &intersects
+       );
+       CHECK((rtn != 0));
+       CHECK((intersects != 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_intersects(
+               rast1, 0,
+               rast2, 0,
+               &intersects
+       );
+       CHECK((rtn != 0));
+       CHECK((intersects == 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_intersects(
+               rast1, 0,
+               rast2, 0,
+               &intersects
+       );
+       CHECK((rtn != 0));
+       CHECK((intersects == 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_intersects(
+               rast1, 0,
+               rast2, 0,
+               &intersects
+       );
+       CHECK((rtn != 0));
+       CHECK((intersects == 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_intersects(
+               rast1, 0,
+               rast2, 0,
+               &intersects
+       );
+       CHECK((rtn != 0));
+       CHECK((intersects == 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_intersects(
+               rast1, 0,
+               rast2, 0,
+               &intersects
+       );
+       CHECK((rtn != 0));
+       CHECK((intersects == 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_intersects(
+               rast1, 0,
+               rast2, 0,
+               &intersects
+       );
+       CHECK((rtn != 0));
+       CHECK((intersects == 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_intersects(
+               rast1, 0,
+               rast2, 0,
+               &intersects
+       );
+       CHECK((rtn != 0));
+       CHECK((intersects == 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_intersects(
+               rast1, 0,
+               rast2, 0,
+               &intersects
+       );
+       CHECK((rtn != 0));
+       CHECK((intersects == 1));
+
+       /* rast2 (skewed by -1, 1) */
+       rt_raster_set_skews(rast2, -1, 1);
+
+       rtn = rt_raster_intersects(
+               rast1, 0,
+               rast2, 0,
+               &intersects
+       );
+       CHECK((rtn != 0));
+       CHECK((intersects == 1));
+
+       /* rast2 (skewed by 1, -1) */
+       rt_raster_set_skews(rast2, 1, -1);
+
+       rtn = rt_raster_intersects(
+               rast1, 0,
+               rast2, 0,
+               &intersects
+       );
+       CHECK((rtn != 0));
+       CHECK((intersects == 1));
+
+       deepRelease(rast2);
+       deepRelease(rast1);
+}
+
 int
 main()
 {
@@ -2020,6 +2486,10 @@ main()
                testGDALRasterize();
                printf("Successfully tested rt_raster_gdal_rasterize\n");
 
+               printf("Testing rt_raster_intersects\n");
+               testIntersects();
+               printf("Successfully tested rt_raster_intersects\n");
+
     deepRelease(raster);
 
     return EXIT_SUCCESS;
index 6b55e3929d7742a08b8c038c10c359ca3aa03c07..f088a2c2ca0324dfd36fd769680dc1e1ced69fe1 100644 (file)
@@ -110,6 +110,7 @@ TEST_GIST = \
        
 TEST_SREL = \
        rt_spatial_relationship.sql \
+       rt_intersects.sql \
        $(NULL)
        
 TEST_BUGS = \
diff --git a/raster/test/regress/rt_intersects.sql b/raster/test/regress/rt_intersects.sql
new file mode 100644 (file)
index 0000000..63c6e8c
--- /dev/null
@@ -0,0 +1,437 @@
+DROP TABLE IF EXISTS raster_intersects_rast;
+DROP TABLE IF EXISTS raster_intersects_geom;
+CREATE TABLE raster_intersects_rast (
+       rid integer,
+       rast raster
+);
+CREATE TABLE raster_intersects_geom (
+       gid integer,
+       geom geometry
+);
+CREATE OR REPLACE FUNCTION make_test_raster(rid integer, width integer DEFAULT 2, height integer DEFAULT 2, ul_x double precision DEFAULT 0, ul_y double precision DEFAULT 0, skew_x double precision DEFAULT 0, skew_y double precision DEFAULT 0)
+       RETURNS void
+       AS $$
+       DECLARE
+               x int;
+               y int;
+               rast raster;
+       BEGIN
+               rast := ST_MakeEmptyRaster(width, height, ul_x, ul_y, 1, 1, skew_x, skew_y, -1);
+               rast := ST_AddBand(rast, 1, '8BUI', 1, 0);
+
+
+               INSERT INTO raster_intersects_rast VALUES (rid, rast);
+
+               RETURN;
+       END;
+       $$ LANGUAGE 'plpgsql';
+SELECT make_test_raster(0, 2, 2, -1, -1);
+SELECT make_test_raster(1, 2, 2);
+SELECT make_test_raster(2, 3, 3);
+DROP FUNCTION make_test_raster(integer, integer, integer, double precision, double precision, double precision, double precision);
+
+INSERT INTO raster_intersects_rast VALUES (10, (
+       SELECT
+               ST_SetValue(rast, 1, 1, 1, 0)
+       FROM raster_intersects_rast
+       WHERE rid = 1
+));
+INSERT INTO raster_intersects_rast VALUES (11, (
+       SELECT
+               ST_SetValue(rast, 1, 2, 1, 0)
+       FROM raster_intersects_rast
+       WHERE rid = 1
+));
+INSERT INTO raster_intersects_rast VALUES (12, (
+       SELECT
+               ST_SetValue(
+                       ST_SetValue(
+                               ST_SetValue(rast, 1, 1, 1, 0),
+                               1, 2, 1, 0
+                       ),
+                       1, 1, 2, 0
+               )
+       FROM raster_intersects_rast
+       WHERE rid = 1
+));
+INSERT INTO raster_intersects_rast VALUES (13, (
+       SELECT
+               ST_SetValue(
+                       ST_SetValue(
+                               ST_SetValue(
+                                       ST_SetValue(rast, 1, 1, 1, 0),
+                                       1, 2, 1, 0
+                               ),
+                               1, 1, 2, 0
+                       ),
+                       1, 2, 2, 0
+               )
+       FROM raster_intersects_rast
+       WHERE rid = 1
+));
+INSERT INTO raster_intersects_rast VALUES (14, (
+       SELECT
+               ST_SetUpperLeft(rast, 2, 0)
+       FROM raster_intersects_rast
+       WHERE rid = 1
+));
+INSERT INTO raster_intersects_rast VALUES (15, (
+       SELECT
+               ST_SetScale(
+                       ST_SetUpperLeft(rast, 0.1, 0.1),
+                       0.4, 0.4
+               )
+       FROM raster_intersects_rast
+       WHERE rid = 1
+));
+INSERT INTO raster_intersects_rast VALUES (16, (
+       SELECT
+               ST_SetScale(
+                       ST_SetUpperLeft(rast, -0.1, 0.1),
+                       0.4, 0.4
+               )
+       FROM raster_intersects_rast
+       WHERE rid = 1
+));
+
+INSERT INTO raster_intersects_rast VALUES (20, (
+       SELECT
+               ST_SetUpperLeft(rast, -2, -2)
+       FROM raster_intersects_rast
+       WHERE rid = 2
+));
+INSERT INTO raster_intersects_rast VALUES (21, (
+       SELECT
+               ST_SetValue(
+                       ST_SetValue(
+                               ST_SetValue(rast, 1, 1, 1, 0),
+                               1, 2, 2, 0
+                       ),
+                       1, 3, 3, 0
+               )
+       FROM raster_intersects_rast
+       WHERE rid = 20
+));
+INSERT INTO raster_intersects_rast VALUES (22, (
+       SELECT
+               ST_SetValue(
+                       ST_SetValue(
+                               rast, 1, 3, 2, 0
+                       ),
+                       1, 2, 3, 0
+               )
+       FROM raster_intersects_rast
+       WHERE rid = 21
+));
+INSERT INTO raster_intersects_rast VALUES (23, (
+       SELECT
+               ST_SetValue(
+                       ST_SetValue(
+                               rast, 1, 3, 1, 0
+                       ),
+                       1, 1, 3, 0
+               )
+       FROM raster_intersects_rast
+       WHERE rid = 22
+));
+
+INSERT INTO raster_intersects_rast VALUES (30, (
+       SELECT
+               ST_SetSkew(rast, -0.5, 0.5)
+       FROM raster_intersects_rast
+       WHERE rid = 2
+));
+INSERT INTO raster_intersects_rast VALUES (31, (
+       SELECT
+               ST_SetSkew(rast, -1, 1)
+       FROM raster_intersects_rast
+       WHERE rid = 2
+));
+INSERT INTO raster_intersects_rast VALUES (32, (
+       SELECT
+               ST_SetSkew(rast, 1, -1)
+       FROM raster_intersects_rast
+       WHERE rid = 2
+));
+
+SELECT
+       '1.1',
+       r1.rid,
+       r2.rid,
+       ST_Intersects(r1.rast, r2.rast)
+FROM raster_intersects_rast r1
+JOIN raster_intersects_rast r2
+       ON r1.rid != r2.rid
+WHERE r1.rid = 0;
+
+SELECT
+       '1.2',
+       r1.rid,
+       r2.rid,
+       ST_Intersects(r1.rast, 1, r2.rast, 1)
+FROM raster_intersects_rast r1
+JOIN raster_intersects_rast r2
+       ON r1.rid != r2.rid
+WHERE r1.rid = 0;
+
+-- point
+INSERT INTO raster_intersects_geom VALUES (
+       1, (
+               SELECT ST_MakePoint(0, 0)
+       )
+), (
+       2, (
+               SELECT ST_MakePoint(0.1, 0.1)
+       )
+), (
+       3, (
+               SELECT ST_MakePoint(-0.1, -0.1)
+       )
+), (
+       4, (
+               SELECT ST_MakePoint(-1, -1)
+       )
+), (
+       5, (
+               SELECT ST_MakePoint(-1.1, -1)
+       )
+), (
+       6, (
+               SELECT ST_MakePoint(-1, -1.1)
+       )
+), (
+       7, (
+               SELECT ST_MakePoint(-1.5, -1.5)
+       )
+), (
+       8, (
+               SELECT ST_MakePoint(3, 3)
+       )
+);
+
+-- multipoint
+INSERT INTO raster_intersects_geom VALUES (
+       11, (
+               SELECT ST_Collect(geom) FROM raster_intersects_geom WHERE gid BETWEEN 1 AND 10
+       )
+), (
+       12, (
+               SELECT ST_Collect(geom) FROM raster_intersects_geom WHERE gid BETWEEN 3 AND 10
+       )
+), (
+       13, (
+               SELECT ST_Collect(geom) FROM raster_intersects_geom WHERE gid BETWEEN 4 AND 10
+       )
+), (
+       14, (
+               SELECT ST_Collect(geom) FROM raster_intersects_geom WHERE gid BETWEEN 5 AND 10
+       )
+), (
+       15, (
+               SELECT ST_Collect(geom) FROM raster_intersects_geom WHERE gid BETWEEN 6 AND 10
+       )
+);
+
+-- linestring
+INSERT INTO raster_intersects_geom VALUES (
+       21, (
+               SELECT ST_MakeLine(ARRAY[
+                       ST_MakePoint(1, 1),
+                       ST_MakePoint(1, 0)
+               ])
+       )
+), (
+       22, (
+               SELECT ST_MakeLine(ARRAY[
+                       ST_MakePoint(-1, -1),
+                       ST_MakePoint(1, 1),
+                       ST_MakePoint(1, 0)
+               ])
+       )
+), (
+       23, (
+               SELECT ST_MakeLine(ARRAY[
+                       ST_MakePoint(-1, -1),
+                       ST_MakePoint(-1, 1),
+                       ST_MakePoint(1, 1),
+                       ST_MakePoint(1, -1)
+               ])
+       )
+), (
+       24, (
+               SELECT ST_MakeLine(ARRAY[
+                       ST_MakePoint(-1.1, 1.1),
+                       ST_MakePoint(1.1, 1.1),
+                       ST_MakePoint(1.1, -1.1),
+                       ST_MakePoint(-1.1, -1.1),
+                       ST_MakePoint(-1.1, 1.1)
+               ])
+       )
+), (
+       25, (
+               SELECT ST_MakeLine(ARRAY[
+                       ST_MakePoint(-2, 1),
+                       ST_MakePoint(1, 2),
+                       ST_MakePoint(2, -1),
+                       ST_MakePoint(-1, -2),
+                       ST_MakePoint(-2, 1)
+               ])
+       )
+), (
+       26, (
+               SELECT ST_MakeLine(ARRAY[
+                       ST_MakePoint(-0.5, 0.5),
+                       ST_MakePoint(0, 0.5),
+                       ST_MakePoint(0, 0),
+                       ST_MakePoint(0, -0.5),
+                       ST_MakePoint(-0.5, 0.5)
+               ])
+       )
+), (
+       27, (
+               SELECT ST_MakeLine(ARRAY[
+                       ST_MakePoint(0.5, 0.5),
+                       ST_MakePoint(1, 1),
+                       ST_MakePoint(1, 0),
+                       ST_MakePoint(0.5, 0.5)
+               ])
+       )
+), (
+       28, (
+               SELECT ST_MakeLine(ARRAY[
+                       ST_MakePoint(1, 1),
+                       ST_MakePoint(0, 2),
+                       ST_MakePoint(1, 2),
+                       ST_MakePoint(1, 1)
+               ])
+       )
+), (
+       29, (
+               SELECT ST_MakeLine(ARRAY[
+                       ST_MakePoint(0, 2),
+                       ST_MakePoint(1, 2),
+                       ST_MakePoint(1, 4),
+                       ST_MakePoint(0, 2)
+               ])
+       )
+);
+
+-- polygon
+INSERT INTO raster_intersects_geom VALUES (
+       31, (
+               SELECT ST_MakePolygon(geom) FROM raster_intersects_geom WHERE gid = 24
+       )
+), (
+       32, (
+               SELECT ST_MakePolygon(geom) FROM raster_intersects_geom WHERE gid = 25
+       )
+), (
+       33, (
+               SELECT ST_MakePolygon(geom) FROM raster_intersects_geom WHERE gid = 26
+       )
+), (
+       34, (
+               SELECT ST_MakePolygon(geom) FROM raster_intersects_geom WHERE gid = 27
+       )
+), (
+       35, (
+               SELECT ST_MakePolygon(geom) FROM raster_intersects_geom WHERE gid = 28
+       )
+), (
+       36, (
+               SELECT ST_MakePolygon(geom) FROM raster_intersects_geom WHERE gid = 29
+       )
+);
+
+-- multipolygon
+INSERT INTO raster_intersects_geom VALUES (
+       41, (
+               SELECT ST_Collect(geom) FROM raster_intersects_geom WHERE gid BETWEEN 31 and 40
+       )
+), (
+       42, (
+               SELECT ST_Collect(geom) FROM raster_intersects_geom WHERE gid BETWEEN 32 and 40
+       )
+), (
+       43, (
+               SELECT ST_Collect(geom) FROM raster_intersects_geom WHERE gid BETWEEN 33 and 40
+       )
+), (
+       44, (
+               SELECT ST_Collect(geom) FROM raster_intersects_geom WHERE gid BETWEEN 34 and 40
+       )
+), (
+       45, (
+               SELECT ST_Collect(geom) FROM raster_intersects_geom WHERE gid BETWEEN 35 and 40
+       )
+), (
+       46, (
+               SELECT ST_Collect(geom) FROM raster_intersects_geom WHERE gid BETWEEN 36 and 40
+       )
+);
+
+SELECT
+       '2.1',
+       r1.rid,
+       g1.gid,
+       ST_GeometryType(g1.geom),
+       ST_Intersects(r1.rast, g1.geom)
+FROM raster_intersects_rast r1
+JOIN raster_intersects_geom g1
+       ON 1 = 1
+WHERE r1.rid = 0;
+
+SELECT
+       '2.2',
+       r1.rid,
+       g1.gid,
+       ST_GeometryType(g1.geom),
+       ST_Intersects(g1.geom, r1.rast)
+FROM raster_intersects_rast r1
+JOIN raster_intersects_geom g1
+       ON 1 = 1
+WHERE r1.rid = 0;
+
+SELECT
+       '2.3',
+       r1.rid,
+       g1.gid,
+       ST_GeometryType(g1.geom),
+       ST_Intersects(r1.rast, g1.geom)
+FROM raster_intersects_rast r1
+JOIN raster_intersects_geom g1
+       ON 1 = 1
+WHERE r1.rid = 2;
+
+SELECT
+       '2.4',
+       r1.rid,
+       g1.gid,
+       ST_GeometryType(g1.geom),
+       ST_Intersects(g1.geom, r1.rast)
+FROM raster_intersects_rast r1
+JOIN raster_intersects_geom g1
+       ON 1 = 1
+WHERE r1.rid = 2;
+
+SELECT
+       '2.5',
+       r1.rid,
+       g1.gid,
+       ST_GeometryType(g1.geom),
+       ST_Intersects(r1.rast, g1.geom, 1)
+FROM raster_intersects_rast r1
+JOIN raster_intersects_geom g1
+       ON 1 = 1
+WHERE r1.rid = 0;
+
+SELECT
+       '2.6',
+       r1.rid,
+       g1.gid,
+       ST_GeometryType(g1.geom),
+       ST_Intersects(r1.rast, g1.geom, 1)
+FROM raster_intersects_rast r1
+JOIN raster_intersects_geom g1
+       ON 1 = 1
+WHERE r1.rid = 2;
diff --git a/raster/test/regress/rt_intersects_expected b/raster/test/regress/rt_intersects_expected
new file mode 100644 (file)
index 0000000..e47990f
--- /dev/null
@@ -0,0 +1,238 @@
+NOTICE:  table "raster_intersects_rast" does not exist, skipping
+NOTICE:  table "raster_intersects_geom" does not exist, skipping
+1.1|0|1|t
+1.1|0|2|t
+1.1|0|10|t
+1.1|0|11|t
+1.1|0|12|t
+1.1|0|13|t
+1.1|0|14|f
+1.1|0|15|t
+1.1|0|16|t
+1.1|0|20|t
+1.1|0|21|t
+1.1|0|22|t
+1.1|0|23|t
+1.1|0|30|t
+1.1|0|31|t
+1.1|0|32|t
+1.2|0|1|t
+1.2|0|2|t
+1.2|0|10|t
+1.2|0|11|t
+1.2|0|12|t
+1.2|0|13|f
+1.2|0|14|f
+1.2|0|15|t
+1.2|0|16|t
+1.2|0|20|t
+1.2|0|21|t
+1.2|0|22|t
+1.2|0|23|t
+1.2|0|30|t
+1.2|0|31|t
+1.2|0|32|t
+2.1|0|1|ST_Point|t
+2.1|0|2|ST_Point|t
+2.1|0|3|ST_Point|t
+2.1|0|4|ST_Point|t
+2.1|0|5|ST_Point|f
+2.1|0|6|ST_Point|f
+2.1|0|7|ST_Point|f
+2.1|0|8|ST_Point|f
+2.1|0|11|ST_MultiPoint|t
+2.1|0|12|ST_MultiPoint|t
+2.1|0|13|ST_MultiPoint|t
+2.1|0|14|ST_MultiPoint|f
+2.1|0|15|ST_MultiPoint|f
+2.1|0|21|ST_LineString|t
+2.1|0|22|ST_LineString|t
+2.1|0|23|ST_LineString|t
+2.1|0|24|ST_LineString|f
+2.1|0|25|ST_LineString|f
+2.1|0|26|ST_LineString|t
+2.1|0|27|ST_LineString|t
+2.1|0|28|ST_LineString|t
+2.1|0|29|ST_LineString|f
+2.1|0|31|ST_Polygon|t
+2.1|0|32|ST_Polygon|t
+2.1|0|33|ST_Polygon|t
+2.1|0|34|ST_Polygon|t
+2.1|0|35|ST_Polygon|t
+2.1|0|36|ST_Polygon|f
+2.1|0|41|ST_MultiPolygon|t
+2.1|0|42|ST_MultiPolygon|t
+2.1|0|43|ST_MultiPolygon|t
+2.1|0|44|ST_MultiPolygon|t
+2.1|0|45|ST_MultiPolygon|t
+2.1|0|46|ST_MultiPolygon|f
+2.2|0|1|ST_Point|t
+2.2|0|2|ST_Point|t
+2.2|0|3|ST_Point|t
+2.2|0|4|ST_Point|t
+2.2|0|5|ST_Point|f
+2.2|0|6|ST_Point|f
+2.2|0|7|ST_Point|f
+2.2|0|8|ST_Point|f
+2.2|0|11|ST_MultiPoint|t
+2.2|0|12|ST_MultiPoint|t
+2.2|0|13|ST_MultiPoint|t
+2.2|0|14|ST_MultiPoint|f
+2.2|0|15|ST_MultiPoint|f
+2.2|0|21|ST_LineString|t
+2.2|0|22|ST_LineString|t
+2.2|0|23|ST_LineString|t
+2.2|0|24|ST_LineString|f
+2.2|0|25|ST_LineString|f
+2.2|0|26|ST_LineString|t
+2.2|0|27|ST_LineString|t
+2.2|0|28|ST_LineString|t
+2.2|0|29|ST_LineString|f
+2.2|0|31|ST_Polygon|t
+2.2|0|32|ST_Polygon|t
+2.2|0|33|ST_Polygon|t
+2.2|0|34|ST_Polygon|t
+2.2|0|35|ST_Polygon|t
+2.2|0|36|ST_Polygon|f
+2.2|0|41|ST_MultiPolygon|t
+2.2|0|42|ST_MultiPolygon|t
+2.2|0|43|ST_MultiPolygon|t
+2.2|0|44|ST_MultiPolygon|t
+2.2|0|45|ST_MultiPolygon|t
+2.2|0|46|ST_MultiPolygon|f
+2.3|2|1|ST_Point|t
+2.3|2|2|ST_Point|t
+2.3|2|3|ST_Point|f
+2.3|2|4|ST_Point|f
+2.3|2|5|ST_Point|f
+2.3|2|6|ST_Point|f
+2.3|2|7|ST_Point|f
+2.3|2|8|ST_Point|t
+2.3|2|11|ST_MultiPoint|t
+2.3|2|12|ST_MultiPoint|t
+2.3|2|13|ST_MultiPoint|t
+2.3|2|14|ST_MultiPoint|t
+2.3|2|15|ST_MultiPoint|t
+2.3|2|21|ST_LineString|t
+2.3|2|22|ST_LineString|t
+2.3|2|23|ST_LineString|t
+2.3|2|24|ST_LineString|t
+2.3|2|25|ST_LineString|t
+2.3|2|26|ST_LineString|t
+2.3|2|27|ST_LineString|t
+2.3|2|28|ST_LineString|t
+2.3|2|29|ST_LineString|t
+2.3|2|31|ST_Polygon|t
+2.3|2|32|ST_Polygon|t
+2.3|2|33|ST_Polygon|t
+2.3|2|34|ST_Polygon|t
+2.3|2|35|ST_Polygon|t
+2.3|2|36|ST_Polygon|t
+2.3|2|41|ST_MultiPolygon|t
+2.3|2|42|ST_MultiPolygon|t
+2.3|2|43|ST_MultiPolygon|t
+2.3|2|44|ST_MultiPolygon|t
+2.3|2|45|ST_MultiPolygon|t
+2.3|2|46|ST_MultiPolygon|t
+2.4|2|1|ST_Point|t
+2.4|2|2|ST_Point|t
+2.4|2|3|ST_Point|f
+2.4|2|4|ST_Point|f
+2.4|2|5|ST_Point|f
+2.4|2|6|ST_Point|f
+2.4|2|7|ST_Point|f
+2.4|2|8|ST_Point|t
+2.4|2|11|ST_MultiPoint|t
+2.4|2|12|ST_MultiPoint|t
+2.4|2|13|ST_MultiPoint|t
+2.4|2|14|ST_MultiPoint|t
+2.4|2|15|ST_MultiPoint|t
+2.4|2|21|ST_LineString|t
+2.4|2|22|ST_LineString|t
+2.4|2|23|ST_LineString|t
+2.4|2|24|ST_LineString|t
+2.4|2|25|ST_LineString|t
+2.4|2|26|ST_LineString|t
+2.4|2|27|ST_LineString|t
+2.4|2|28|ST_LineString|t
+2.4|2|29|ST_LineString|t
+2.4|2|31|ST_Polygon|t
+2.4|2|32|ST_Polygon|t
+2.4|2|33|ST_Polygon|t
+2.4|2|34|ST_Polygon|t
+2.4|2|35|ST_Polygon|t
+2.4|2|36|ST_Polygon|t
+2.4|2|41|ST_MultiPolygon|t
+2.4|2|42|ST_MultiPolygon|t
+2.4|2|43|ST_MultiPolygon|t
+2.4|2|44|ST_MultiPolygon|t
+2.4|2|45|ST_MultiPolygon|t
+2.4|2|46|ST_MultiPolygon|t
+2.5|0|1|ST_Point|t
+2.5|0|2|ST_Point|t
+2.5|0|3|ST_Point|t
+2.5|0|4|ST_Point|t
+2.5|0|5|ST_Point|f
+2.5|0|6|ST_Point|f
+2.5|0|7|ST_Point|f
+2.5|0|8|ST_Point|f
+2.5|0|11|ST_MultiPoint|t
+2.5|0|12|ST_MultiPoint|t
+2.5|0|13|ST_MultiPoint|t
+2.5|0|14|ST_MultiPoint|f
+2.5|0|15|ST_MultiPoint|f
+2.5|0|21|ST_LineString|t
+2.5|0|22|ST_LineString|t
+2.5|0|23|ST_LineString|t
+2.5|0|24|ST_LineString|f
+2.5|0|25|ST_LineString|f
+2.5|0|26|ST_LineString|t
+2.5|0|27|ST_LineString|t
+2.5|0|28|ST_LineString|t
+2.5|0|29|ST_LineString|f
+2.5|0|31|ST_Polygon|t
+2.5|0|32|ST_Polygon|t
+2.5|0|33|ST_Polygon|t
+2.5|0|34|ST_Polygon|t
+2.5|0|35|ST_Polygon|f
+2.5|0|36|ST_Polygon|f
+2.5|0|41|ST_MultiPolygon|t
+2.5|0|42|ST_MultiPolygon|t
+2.5|0|43|ST_MultiPolygon|t
+2.5|0|44|ST_MultiPolygon|t
+2.5|0|45|ST_MultiPolygon|f
+2.5|0|46|ST_MultiPolygon|f
+2.6|2|1|ST_Point|t
+2.6|2|2|ST_Point|t
+2.6|2|3|ST_Point|f
+2.6|2|4|ST_Point|f
+2.6|2|5|ST_Point|f
+2.6|2|6|ST_Point|f
+2.6|2|7|ST_Point|f
+2.6|2|8|ST_Point|t
+2.6|2|11|ST_MultiPoint|t
+2.6|2|12|ST_MultiPoint|t
+2.6|2|13|ST_MultiPoint|t
+2.6|2|14|ST_MultiPoint|t
+2.6|2|15|ST_MultiPoint|t
+2.6|2|21|ST_LineString|t
+2.6|2|22|ST_LineString|t
+2.6|2|23|ST_LineString|t
+2.6|2|24|ST_LineString|t
+2.6|2|25|ST_LineString|t
+2.6|2|26|ST_LineString|t
+2.6|2|27|ST_LineString|t
+2.6|2|28|ST_LineString|t
+2.6|2|29|ST_LineString|t
+2.6|2|31|ST_Polygon|t
+2.6|2|32|ST_Polygon|t
+2.6|2|33|ST_Polygon|t
+2.6|2|34|ST_Polygon|t
+2.6|2|35|ST_Polygon|t
+2.6|2|36|ST_Polygon|t
+2.6|2|41|ST_MultiPolygon|t
+2.6|2|42|ST_MultiPolygon|t
+2.6|2|43|ST_MultiPolygon|t
+2.6|2|44|ST_MultiPolygon|t
+2.6|2|45|ST_MultiPolygon|t
+2.6|2|46|ST_MultiPolygon|t
index addd95307bf854624eb120375b5697dc069b71e0..2205d8dabea65158391d3f8749713c05194c812e 100644 (file)
@@ -273,19 +273,19 @@ VALUES ( 46, 2, st_setsrid(st_makeline(ARRAY[st_makepoint(
 -- Test 1 - st_intersect(geometry, raster) 
 -----------------------------------------------------------------------
 
-SELECT 'test 1.1', rid, geomid, st_intersects(geom, rast) AS intersect
+SELECT 'test 1.1', rid, geomid, ST_Intersects(geom, rast) AS intersect
        FROM rt_spatial_relationship_test, rt_spatial_relationship_test_geom
        WHERE forrast = rid ORDER BY rid, geomid;
        
-SELECT 'test 1.2', rid, geomid, st_intersects(geom, rast) AS intersect
+SELECT 'test 1.2', rid, geomid, ST_Intersects(geom, rast) AS intersect
        FROM rt_spatial_relationship_test, rt_spatial_relationship_test_geom
        WHERE forrast = rid AND ST_Intersects(geom, rast, 1) ORDER BY rid, geomid;
        
-SELECT 'test 1.3', rid, geomid, st_intersects(geom, st_setbandnodatavalue(rast, NULL))
+SELECT 'test 1.3', rid, geomid, ST_Intersects(geom, st_setbandnodatavalue(rast, NULL), 1)
        FROM rt_spatial_relationship_test, rt_spatial_relationship_test_geom
        WHERE forrast = rid ORDER BY rid, geomid;
 
-SELECT 'test 1.4', rid, geomid, st_intersects(geom, st_setbandnodatavalue(rast, NULL))
+SELECT 'test 1.4', rid, geomid, ST_Intersects(geom, st_setbandnodatavalue(rast, NULL))
        FROM rt_spatial_relationship_test, rt_spatial_relationship_test_geom
        WHERE forrast = rid AND ST_Intersects(geom, rast, 1) ORDER BY rid, geomid;
 
@@ -301,7 +301,7 @@ FROM (SELECT *, ST_Intersection(geom, rast) gv
 SELECT 'test 2.2', rid, geomid, ST_AsText((gv).geom), (gv).val
 FROM (SELECT *, ST_Intersection(geom, rast) gv
       FROM rt_spatial_relationship_test, rt_spatial_relationship_test_geom
-      WHERE forrast = rid AND ST_Intersects(geom, rast)
+      WHERE forrast = rid AND ST_Intersects(geom, rast, 1)
      ) foo;
 
 SELECT 'test 2.3', rid, geomid, ST_AsText((gv).geom), (gv).val
@@ -313,6 +313,6 @@ FROM (SELECT *, ST_Intersection(geom, st_setbandnodatavalue(rast, NULL)) gv
 SELECT 'test 2.4', rid, geomid, ST_AsText((gv).geom), (gv).val
 FROM (SELECT *, ST_Intersection(geom, st_setbandnodatavalue(rast, NULL)) gv
       FROM rt_spatial_relationship_test, rt_spatial_relationship_test_geom
-      WHERE forrast = rid AND ST_Intersects(geom, st_setbandnodatavalue(rast, NULL))
+      WHERE forrast = rid AND ST_Intersects(geom, st_setbandnodatavalue(rast, NULL), 1)
      ) foo;
 
index 3dff47213f394a4365405ad41b8b09f371b6ed71..66e61d0f33f188720192859e0184b90dd71e2b84 100644 (file)
@@ -1,28 +1,28 @@
 test 1.1|1|1|t
 test 1.1|1|2|t
 test 1.1|1|3|f
-test 1.1|1|4|f
+test 1.1|1|4|t
 test 1.1|1|5|t
 test 1.1|1|6|t
 test 1.1|1|7|f
 test 1.1|1|11|f
 test 1.1|1|12|t
 test 1.1|1|13|t
-test 1.1|1|14|f
+test 1.1|1|14|t
 test 1.1|1|15|t
-test 1.1|1|16|f
+test 1.1|1|16|t
 test 1.1|1|17|t
 test 1.1|1|18|t
 test 1.1|2|31|t
 test 1.1|2|32|t
 test 1.1|2|33|f
-test 1.1|2|34|f
-test 1.1|2|35|f
-test 1.1|2|36|f
+test 1.1|2|34|t
+test 1.1|2|35|t
+test 1.1|2|36|t
 test 1.1|2|41|f
 test 1.1|2|42|t
 test 1.1|2|43|t
-test 1.1|2|44|f
+test 1.1|2|44|t
 test 1.1|2|45|f
 test 1.1|2|46|f
 test 1.2|1|1|t
@@ -58,7 +58,7 @@ test 1.3|2|32|t
 test 1.3|2|33|f
 test 1.3|2|34|t
 test 1.3|2|35|t
-test 1.3|2|36|f
+test 1.3|2|36|t
 test 1.3|2|41|f
 test 1.3|2|42|t
 test 1.3|2|43|t
@@ -153,7 +153,6 @@ test 2.3|2|32|POINT(-75.5532328537098 49.2824585505576)|1
 test 2.3|2|33|GEOMETRYCOLLECTION EMPTY|
 test 2.3|2|34|POINT(-75.5518328537098 49.2814585505576)|4
 test 2.3|2|35|POINT(-75.5523150760919 49.2818643977074)|4
-test 2.3|2|36|GEOMETRYCOLLECTION EMPTY|
 test 2.3|2|41|GEOMETRYCOLLECTION EMPTY|
 test 2.3|2|42|LINESTRING(-75.5533120424461 49.2823793618213,-75.5531972042327 49.2824942000347)|1
 test 2.3|2|43|LINESTRING(-75.5529884291587 49.2811479840607,-75.5522356128797 49.2815620330142)|3