/* determine if the first raster covers the second raster */
Datum RASTER_covers(PG_FUNCTION_ARGS);
+/* determine if the first raster is covered by the second raster */
+Datum RASTER_coveredby(PG_FUNCTION_ARGS);
+
/* determine if two rasters are aligned */
Datum RASTER_sameAlignment(PG_FUNCTION_ARGS);
}
if (!rtn) {
- elog(ERROR, "RASTER_containsProperly: Unable to test that the first raster contains the second raster");
+ elog(ERROR, "RASTER_containsProperly: Unable to test that the first raster contains properly the second raster");
PG_RETURN_NULL();
}
}
if (!rtn) {
- elog(ERROR, "RASTER_covers: Unable to test that the first raster contains the second raster");
+ elog(ERROR, "RASTER_covers: Unable to test that the first raster covers the second raster");
+ PG_RETURN_NULL();
+ }
+
+ PG_RETURN_BOOL(result);
+}
+
+/**
+ * See if the first raster is covered by the second raster
+ */
+PG_FUNCTION_INFO_V1(RASTER_coveredby);
+Datum RASTER_coveredby(PG_FUNCTION_ARGS)
+{
+ const int set_count = 2;
+ rt_pgraster *pgrast[2];
+ int pgrastpos[2] = {-1, -1};
+ 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 result;
+
+ 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_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
+ }
+ PG_RETURN_NULL();
+ }
+ pgrast[i] = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(j));
+ pgrastpos[i] = j;
+ j++;
+
+ /* raster */
+ rast[i] = rt_raster_deserialize(pgrast[i], FALSE);
+ if (!rast[i]) {
+ elog(ERROR, "RASTER_coveredby: Could not deserialize the %s raster", i < 1 ? "first" : "second");
+ for (k = 0; k <= i; k++) {
+ if (k < i)
+ rt_raster_destroy(rast[k]);
+ PG_FREE_IF_COPY(pgrast[k], pgrastpos[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");
+ if (i > 0) i++;
+ for (k = 0; k < i; k++) {
+ rt_raster_destroy(rast[k]);
+ PG_FREE_IF_COPY(pgrast[k], pgrastpos[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");
+ if (i > 0) i++;
+ for (k = 0; k < i; k++) {
+ rt_raster_destroy(rast[k]);
+ PG_FREE_IF_COPY(pgrast[k], pgrastpos[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 < set_count; k++) {
+ rt_raster_destroy(rast[k]);
+ PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
+ }
+ PG_RETURN_NULL();
+ }
+
+ /* SRID must match */
+ if (rt_raster_get_srid(rast[0]) != rt_raster_get_srid(rast[1])) {
+ elog(ERROR, "The two rasters provided have different SRIDs");
+ for (k = 0; k < set_count; k++) {
+ rt_raster_destroy(rast[k]);
+ PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
+ }
+ PG_RETURN_NULL();
+ }
+
+ rtn = rt_raster_coveredby(
+ rast[0], (hasbandindex[0] ? bandindex[0] - 1 : -1),
+ rast[1], (hasbandindex[1] ? bandindex[1] - 1 : -1),
+ &result
+ );
+ for (k = 0; k < set_count; k++) {
+ rt_raster_destroy(rast[k]);
+ PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
+ }
+
+ if (!rtn) {
+ elog(ERROR, "RASTER_coveredby: Unable to test that the first raster is covered by the second raster");
PG_RETURN_NULL();
}
LANGUAGE 'sql' IMMUTABLE
COST 1000;
+-----------------------------------------------------------------------
+-- ST_CoveredBy(raster, raster)
+-----------------------------------------------------------------------
+
+CREATE OR REPLACE FUNCTION _st_coveredby(rast1 raster, nband1 integer, rast2 raster, nband2 integer)
+ RETURNS boolean
+ AS 'MODULE_PATHNAME', 'RASTER_coveredby'
+ LANGUAGE 'c' IMMUTABLE STRICT
+ COST 1000;
+
+CREATE OR REPLACE FUNCTION st_coveredby(rast1 raster, nband1 integer, rast2 raster, nband2 integer)
+ RETURNS boolean
+ AS $$ SELECT $1 && $3 AND CASE WHEN $2 IS NULL OR $4 IS NULL THEN st_coveredby(st_convexhull($1), st_convexhull($3)) ELSE _st_coveredby($1, $2, $3, $4) END $$
+ LANGUAGE 'sql' IMMUTABLE
+ COST 1000;
+
+CREATE OR REPLACE FUNCTION st_coveredby(rast1 raster, rast2 raster)
+ RETURNS boolean
+ AS $$ SELECT st_coveredby($1, NULL::integer, $2, NULL::integer) $$
+ LANGUAGE 'sql' IMMUTABLE
+ COST 1000;
+
-----------------------------------------------------------------------
-- ST_Within(raster, raster)
-----------------------------------------------------------------------
--- /dev/null
+SET client_min_messages TO warning;
+
+DROP TABLE IF EXISTS raster_coveredby_rast;
+CREATE TABLE raster_coveredby_rast (
+ rid integer,
+ rast raster
+);
+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, 0);
+ rast := ST_AddBand(rast, 1, '8BUI', 1, 0);
+
+
+ INSERT INTO raster_coveredby_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_coveredby_rast VALUES (10, (
+ SELECT
+ ST_SetValue(rast, 1, 1, 1, 0)
+ FROM raster_coveredby_rast
+ WHERE rid = 1
+));
+INSERT INTO raster_coveredby_rast VALUES (11, (
+ SELECT
+ ST_SetValue(rast, 1, 2, 1, 0)
+ FROM raster_coveredby_rast
+ WHERE rid = 1
+));
+INSERT INTO raster_coveredby_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_coveredby_rast
+ WHERE rid = 1
+));
+INSERT INTO raster_coveredby_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_coveredby_rast
+ WHERE rid = 1
+));
+INSERT INTO raster_coveredby_rast VALUES (14, (
+ SELECT
+ ST_SetUpperLeft(rast, 2, 0)
+ FROM raster_coveredby_rast
+ WHERE rid = 1
+));
+INSERT INTO raster_coveredby_rast VALUES (15, (
+ SELECT
+ ST_SetScale(
+ ST_SetUpperLeft(rast, 0.1, 0.1),
+ 0.4, 0.4
+ )
+ FROM raster_coveredby_rast
+ WHERE rid = 1
+));
+INSERT INTO raster_coveredby_rast VALUES (16, (
+ SELECT
+ ST_SetScale(
+ ST_SetUpperLeft(rast, -0.1, 0.1),
+ 0.4, 0.4
+ )
+ FROM raster_coveredby_rast
+ WHERE rid = 1
+));
+
+INSERT INTO raster_coveredby_rast VALUES (20, (
+ SELECT
+ ST_SetUpperLeft(rast, -2, -2)
+ FROM raster_coveredby_rast
+ WHERE rid = 2
+));
+INSERT INTO raster_coveredby_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_coveredby_rast
+ WHERE rid = 20
+));
+INSERT INTO raster_coveredby_rast VALUES (22, (
+ SELECT
+ ST_SetValue(
+ ST_SetValue(
+ rast, 1, 3, 2, 0
+ ),
+ 1, 2, 3, 0
+ )
+ FROM raster_coveredby_rast
+ WHERE rid = 21
+));
+INSERT INTO raster_coveredby_rast VALUES (23, (
+ SELECT
+ ST_SetValue(
+ ST_SetValue(
+ rast, 1, 3, 1, 0
+ ),
+ 1, 1, 3, 0
+ )
+ FROM raster_coveredby_rast
+ WHERE rid = 22
+));
+
+INSERT INTO raster_coveredby_rast VALUES (30, (
+ SELECT
+ ST_SetSkew(rast, -0.5, 0.5)
+ FROM raster_coveredby_rast
+ WHERE rid = 2
+));
+INSERT INTO raster_coveredby_rast VALUES (31, (
+ SELECT
+ ST_SetSkew(rast, -1, 1)
+ FROM raster_coveredby_rast
+ WHERE rid = 2
+));
+INSERT INTO raster_coveredby_rast VALUES (32, (
+ SELECT
+ ST_SetSkew(rast, 1, -1)
+ FROM raster_coveredby_rast
+ WHERE rid = 2
+));
+
+SELECT
+ '1.1',
+ r1.rid,
+ r2.rid,
+ ST_CoveredBy(r1.rast, NULL, r2.rast, NULL)
+FROM raster_coveredby_rast r1
+CROSS JOIN raster_coveredby_rast r2
+WHERE r1.rid = 0;
+
+SELECT
+ '1.2',
+ r1.rid,
+ r2.rid,
+ ST_CoveredBy(r1.rast, 1, r2.rast, 1)
+FROM raster_coveredby_rast r1
+JOIN raster_coveredby_rast r2
+ ON r1.rid != r2.rid
+WHERE r1.rid = 0;
+
+SELECT
+ '1.3',
+ r1.rid,
+ r2.rid,
+ ST_CoveredBy(r1.rast, NULL, r2.rast, NULL)
+FROM raster_coveredby_rast r1
+JOIN raster_coveredby_rast r2
+ ON r1.rid != r2.rid
+WHERE r2.rid = 0;
+
+SELECT
+ '1.4',
+ r1.rid,
+ r2.rid,
+ ST_CoveredBy(r1.rast, 1, r2.rast, 1)
+FROM raster_coveredby_rast r1
+JOIN raster_coveredby_rast r2
+ ON r1.rid != r2.rid
+WHERE r2.rid = 0;
+
+DROP TABLE IF EXISTS raster_coveredby_rast;