PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches

◆ RASTER_nMapAlgebraExpr()

Datum RASTER_nMapAlgebraExpr ( PG_FUNCTION_ARGS  )

Definition at line 1295 of file rtpg_mapalgebra.c.

1296{
1297 MemoryContext mainMemCtx = CurrentMemoryContext;
1298 rtpg_nmapalgebraexpr_arg arg = NULL;
1299 rt_iterator itrset;
1300 uint16_t exprpos[3] = {1, 4, 5};
1301
1302 int i = 0;
1303 int j = 0;
1304 int k = 0;
1305
1306 int numraster = 0;
1307 int err = 0;
1308 int allnull = 0;
1309 int allempty = 0;
1310 int noband = 0;
1311 int len = 0;
1312
1313 TupleDesc tupdesc;
1314 SPITupleTable *tuptable = NULL;
1315 HeapTuple tuple;
1316 Datum datum;
1317 bool isnull = FALSE;
1318
1319 rt_raster raster = NULL;
1320 rt_band band = NULL;
1321 rt_pgraster *pgraster = NULL;
1322
1323 const int argkwcount = 12;
1324 char *argkw[] = {
1325 "[rast.x]",
1326 "[rast.y]",
1327 "[rast.val]",
1328 "[rast]",
1329 "[rast1.x]",
1330 "[rast1.y]",
1331 "[rast1.val]",
1332 "[rast1]",
1333 "[rast2.x]",
1334 "[rast2.y]",
1335 "[rast2.val]",
1336 "[rast2]"
1337 };
1338
1339 if (PG_ARGISNULL(0))
1340 PG_RETURN_NULL();
1341
1342 /* init argument struct */
1343 arg = rtpg_nmapalgebraexpr_arg_init(argkwcount, argkw);
1344 if (arg == NULL) {
1345 elog(ERROR, "RASTER_nMapAlgebraExpr: Could not initialize argument structure");
1346 PG_RETURN_NULL();
1347 }
1348
1349 /* let helper function process rastbandarg (0) */
1350 if (!rtpg_nmapalgebra_rastbandarg_process(arg->bandarg, PG_GETARG_ARRAYTYPE_P(0), &allnull, &allempty, &noband)) {
1352 elog(ERROR, "RASTER_nMapAlgebra: Could not process rastbandarg");
1353 PG_RETURN_NULL();
1354 }
1355
1356 POSTGIS_RT_DEBUGF(4, "allnull, allempty, noband = %d, %d, %d", allnull, allempty, noband);
1357
1358 /* all rasters are NULL, return NULL */
1359 if (allnull == arg->bandarg->numraster) {
1360 elog(NOTICE, "All input rasters are NULL. Returning NULL");
1362 PG_RETURN_NULL();
1363 }
1364
1365 /* only work on one or two rasters */
1366 if (arg->bandarg->numraster > 1)
1367 numraster = 2;
1368 else
1369 numraster = 1;
1370
1371 /* pixel type (2) */
1372 if (!PG_ARGISNULL(2)) {
1373 char *pixtypename = text_to_cstring(PG_GETARG_TEXT_P(2));
1374
1375 /* Get the pixel type index */
1376 arg->bandarg->pixtype = rt_pixtype_index_from_name(pixtypename);
1377 if (arg->bandarg->pixtype == PT_END) {
1379 elog(ERROR, "RASTER_nMapAlgebraExpr: Invalid pixel type: %s", pixtypename);
1380 PG_RETURN_NULL();
1381 }
1382 }
1383 POSTGIS_RT_DEBUGF(4, "pixeltype: %d", arg->bandarg->pixtype);
1384
1385 /* extent type (3) */
1386 if (!PG_ARGISNULL(3)) {
1387 char *extenttypename = rtpg_strtoupper(rtpg_trim(text_to_cstring(PG_GETARG_TEXT_P(3))));
1388 arg->bandarg->extenttype = rt_util_extent_type(extenttypename);
1389 }
1390
1391 if (arg->bandarg->extenttype == ET_CUSTOM) {
1392 if (numraster < 2) {
1393 elog(NOTICE, "CUSTOM extent type not supported. Defaulting to FIRST");
1394 arg->bandarg->extenttype = ET_FIRST;
1395 }
1396 else {
1397 elog(NOTICE, "CUSTOM extent type not supported. Defaulting to INTERSECTION");
1399 }
1400 }
1401 else if (numraster < 2)
1402 arg->bandarg->extenttype = ET_FIRST;
1403
1404 POSTGIS_RT_DEBUGF(4, "extenttype: %d", arg->bandarg->extenttype);
1405
1406 /* nodatanodataval (6) */
1407 if (!PG_ARGISNULL(6)) {
1408 arg->callback.nodatanodata.hasval = 1;
1409 arg->callback.nodatanodata.val = PG_GETARG_FLOAT8(6);
1410 }
1411
1412 err = 0;
1413 /* all rasters are empty, return empty raster */
1414 if (allempty == arg->bandarg->numraster) {
1415 elog(NOTICE, "All input rasters are empty. Returning empty raster");
1416 err = 1;
1417 }
1418 /* all rasters don't have indicated band, return empty raster */
1419 else if (noband == arg->bandarg->numraster) {
1420 elog(NOTICE, "All input rasters do not have bands at indicated indexes. Returning empty raster");
1421 err = 1;
1422 }
1423 if (err) {
1425
1426 raster = rt_raster_new(0, 0);
1427 if (raster == NULL) {
1428 elog(ERROR, "RASTER_nMapAlgebraExpr: Could not create empty raster");
1429 PG_RETURN_NULL();
1430 }
1431
1432 pgraster = rt_raster_serialize(raster);
1433 rt_raster_destroy(raster);
1434 if (!pgraster) PG_RETURN_NULL();
1435
1436 SET_VARSIZE(pgraster, pgraster->size);
1437 PG_RETURN_POINTER(pgraster);
1438 }
1439
1440 /* connect SPI */
1441 if (SPI_connect() != SPI_OK_CONNECT) {
1443 elog(ERROR, "RASTER_nMapAlgebraExpr: Could not connect to the SPI manager");
1444 PG_RETURN_NULL();
1445 }
1446
1447 /*
1448 process expressions
1449
1450 exprpos elements are:
1451 1 - expression => spi_plan[0]
1452 4 - nodata1expr => spi_plan[1]
1453 5 - nodata2expr => spi_plan[2]
1454 */
1455 for (i = 0; i < arg->callback.exprcount; i++) {
1456 char *expr = NULL;
1457 char *tmp = NULL;
1458 char *sql = NULL;
1459 char place[12] = "$1";
1460
1461 if (PG_ARGISNULL(exprpos[i]))
1462 continue;
1463
1464 expr = text_to_cstring(PG_GETARG_TEXT_P(exprpos[i]));
1465 POSTGIS_RT_DEBUGF(3, "raw expr of argument #%d: %s", exprpos[i], expr);
1466
1467 for (j = 0, k = 1; j < argkwcount; j++) {
1468 /* attempt to replace keyword with placeholder */
1469 len = 0;
1470 tmp = rtpg_strreplace(expr, argkw[j], place, &len);
1471 pfree(expr);
1472 expr = tmp;
1473
1474 if (len) {
1475 POSTGIS_RT_DEBUGF(4, "kw #%d (%s) at pos $%d", j, argkw[j], k);
1476 arg->callback.expr[i].spi_argcount++;
1477 arg->callback.expr[i].spi_argpos[j] = k++;
1478
1479 sprintf(place, "$%d", k);
1480 }
1481 else
1482 arg->callback.expr[i].spi_argpos[j] = 0;
1483 }
1484
1485 len = strlen("SELECT (") + strlen(expr) + strlen(")::double precision");
1486 sql = (char *) palloc(len + 1);
1487 if (sql == NULL) {
1489 SPI_finish();
1490 elog(ERROR, "RASTER_nMapAlgebraExpr: Could not allocate memory for expression parameter %d", exprpos[i]);
1491 PG_RETURN_NULL();
1492 }
1493
1494 memcpy(sql, "SELECT (", strlen("SELECT ("));
1495 memcpy(sql + strlen("SELECT ("), expr, strlen(expr));
1496 memcpy(sql + strlen("SELECT (") + strlen(expr), ")::double precision", strlen(")::double precision"));
1497 sql[len] = '\0';
1498
1499 POSTGIS_RT_DEBUGF(3, "sql #%d: %s", exprpos[i], sql);
1500
1501 /* prepared plan */
1502 if (arg->callback.expr[i].spi_argcount) {
1503 Oid *argtype = (Oid *) palloc(arg->callback.expr[i].spi_argcount * sizeof(Oid));
1504 POSTGIS_RT_DEBUGF(3, "expression parameter %d is a prepared plan", exprpos[i]);
1505 if (argtype == NULL) {
1506 pfree(sql);
1508 SPI_finish();
1509 elog(ERROR, "RASTER_nMapAlgebraExpr: Could not allocate memory for prepared plan argtypes of expression parameter %d", exprpos[i]);
1510 PG_RETURN_NULL();
1511 }
1512
1513 /* specify datatypes of parameters */
1514 for (j = 0, k = 0; j < argkwcount; j++) {
1515 if (arg->callback.expr[i].spi_argpos[j] < 1) continue;
1516
1517 /* positions are INT4 */
1518 if (
1519 (strstr(argkw[j], "[rast.x]") != NULL) ||
1520 (strstr(argkw[j], "[rast.y]") != NULL) ||
1521 (strstr(argkw[j], "[rast1.x]") != NULL) ||
1522 (strstr(argkw[j], "[rast1.y]") != NULL) ||
1523 (strstr(argkw[j], "[rast2.x]") != NULL) ||
1524 (strstr(argkw[j], "[rast2.y]") != NULL)
1525 )
1526 argtype[k] = INT4OID;
1527 /* everything else is FLOAT8 */
1528 else
1529 argtype[k] = FLOAT8OID;
1530
1531 k++;
1532 }
1533
1534 arg->callback.expr[i].spi_plan = SPI_prepare(sql, arg->callback.expr[i].spi_argcount, argtype);
1535 pfree(argtype);
1536 pfree(sql);
1537
1538 if (arg->callback.expr[i].spi_plan == NULL) {
1540 SPI_finish();
1541 elog(ERROR, "RASTER_nMapAlgebraExpr: Could not create prepared plan of expression parameter %d", exprpos[i]);
1542 PG_RETURN_NULL();
1543 }
1544 }
1545 /* no args, just execute query */
1546 else {
1547 POSTGIS_RT_DEBUGF(3, "expression parameter %d has no args, simply executing", exprpos[i]);
1548 err = SPI_execute(sql, TRUE, 0);
1549 pfree(sql);
1550
1551 if (err != SPI_OK_SELECT || SPI_tuptable == NULL || SPI_processed != 1) {
1553 SPI_finish();
1554 elog(ERROR, "RASTER_nMapAlgebraExpr: Could not evaluate expression parameter %d", exprpos[i]);
1555 PG_RETURN_NULL();
1556 }
1557
1558 /* get output of prepared plan */
1559 tupdesc = SPI_tuptable->tupdesc;
1560 tuptable = SPI_tuptable;
1561 tuple = tuptable->vals[0];
1562
1563 datum = SPI_getbinval(tuple, tupdesc, 1, &isnull);
1564 if (SPI_result == SPI_ERROR_NOATTRIBUTE) {
1565 if (SPI_tuptable) SPI_freetuptable(tuptable);
1567 SPI_finish();
1568 elog(ERROR, "RASTER_nMapAlgebraExpr: Could not get result of expression parameter %d", exprpos[i]);
1569 PG_RETURN_NULL();
1570 }
1571
1572 if (!isnull) {
1573 arg->callback.expr[i].hasval = 1;
1574 arg->callback.expr[i].val = DatumGetFloat8(datum);
1575 }
1576
1577 if (SPI_tuptable) SPI_freetuptable(tuptable);
1578 }
1579 }
1580
1581 /* determine nodataval and possibly pixtype */
1582 /* band to check */
1583 switch (arg->bandarg->extenttype) {
1584 case ET_LAST:
1585 case ET_SECOND:
1586 if (numraster > 1)
1587 i = 1;
1588 else
1589 i = 0;
1590 break;
1591 default:
1592 i = 0;
1593 break;
1594 }
1595 /* find first viable band */
1596 if (!arg->bandarg->hasband[i]) {
1597 for (i = 0; i < numraster; i++) {
1598 if (arg->bandarg->hasband[i])
1599 break;
1600 }
1601 if (i >= numraster)
1602 i = numraster - 1;
1603 }
1604 band = rt_raster_get_band(arg->bandarg->raster[i], arg->bandarg->nband[i]);
1605
1606 /* set pixel type if PT_END */
1607 if (arg->bandarg->pixtype == PT_END)
1608 arg->bandarg->pixtype = rt_band_get_pixtype(band);
1609
1610 /* set hasnodata and nodataval */
1611 arg->bandarg->hasnodata = 1;
1613 rt_band_get_nodata(band, &(arg->bandarg->nodataval));
1614 else
1616
1617 POSTGIS_RT_DEBUGF(4, "pixtype, hasnodata, nodataval: %s, %d, %f", rt_pixtype_name(arg->bandarg->pixtype), arg->bandarg->hasnodata, arg->bandarg->nodataval);
1618
1619 /* init itrset */
1620 itrset = palloc(sizeof(struct rt_iterator_t) * numraster);
1621 if (itrset == NULL) {
1623 SPI_finish();
1624 elog(ERROR, "RASTER_nMapAlgebra: Could not allocate memory for iterator arguments");
1625 PG_RETURN_NULL();
1626 }
1627
1628 /* set itrset */
1629 for (i = 0; i < numraster; i++) {
1630 itrset[i].raster = arg->bandarg->raster[i];
1631 itrset[i].nband = arg->bandarg->nband[i];
1632 itrset[i].nbnodata = 1;
1633 }
1634
1635 /* pass everything to iterator */
1636 err = rt_raster_iterator(
1637 itrset, numraster,
1638 arg->bandarg->extenttype, arg->bandarg->cextent,
1639 arg->bandarg->pixtype,
1640 arg->bandarg->hasnodata, arg->bandarg->nodataval,
1641 0, 0,
1642 NULL,
1643 &(arg->callback),
1645 &raster
1646 );
1647
1648 pfree(itrset);
1650
1651 if (err != ES_NONE) {
1652 SPI_finish();
1653 elog(ERROR, "RASTER_nMapAlgebraExpr: Could not run raster iterator function");
1654 PG_RETURN_NULL();
1655 }
1656 else if (raster == NULL) {
1657 SPI_finish();
1658 PG_RETURN_NULL();
1659 }
1660
1661 /* switch to prior memory context to ensure memory allocated in correct context */
1662 MemoryContextSwitchTo(mainMemCtx);
1663
1664 pgraster = rt_raster_serialize(raster);
1665 rt_raster_destroy(raster);
1666
1667 /* finish SPI */
1668 SPI_finish();
1669
1670 if (!pgraster)
1671 PG_RETURN_NULL();
1672
1673 SET_VARSIZE(pgraster, pgraster->size);
1674 PG_RETURN_POINTER(pgraster);
1675}
#define TRUE
Definition dbfopen.c:73
#define FALSE
Definition dbfopen.c:72
int rt_band_get_hasnodata_flag(rt_band band)
Get hasnodata flag value.
Definition rt_band.c:833
rt_pixtype rt_pixtype_index_from_name(const char *pixname)
Definition rt_pixel.c:82
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition rt_raster.c:86
@ PT_END
Definition librtcore.h:201
rt_raster rt_raster_new(uint32_t width, uint32_t height)
Construct a raster with given dimensions.
Definition rt_raster.c:52
rt_extenttype rt_util_extent_type(const char *name)
Definition rt_util.c:301
const char * rt_pixtype_name(rt_pixtype pixtype)
Definition rt_pixel.c:114
double rt_band_get_min_value(rt_band band)
Returns the minimal possible value for the band according to the pixel type.
Definition rt_band.c:2082
@ ES_NONE
Definition librtcore.h:182
rt_errorstate rt_raster_iterator(rt_iterator itrset, uint16_t itrcount, rt_extenttype extenttype, rt_raster customextent, rt_pixtype pixtype, uint8_t hasnodata, double nodataval, uint16_t distancex, uint16_t distancey, rt_mask mask, void *userarg, int(*callback)(rt_iterator_arg arg, void *userarg, double *value, int *nodata), rt_raster *rtnraster)
n-raster iterator.
@ ET_CUSTOM
Definition librtcore.h:210
@ ET_LAST
Definition librtcore.h:209
@ ET_INTERSECTION
Definition librtcore.h:205
@ ET_SECOND
Definition librtcore.h:208
@ ET_FIRST
Definition librtcore.h:207
rt_errorstate rt_band_get_nodata(rt_band band, double *nodata)
Get NODATA value.
Definition rt_band.c:2067
rt_pixtype rt_band_get_pixtype(rt_band band)
Return pixeltype of this band.
Definition rt_band.c:790
void * rt_raster_serialize(rt_raster raster)
Return this raster in serialized form.
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
Definition rt_raster.c:385
raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
Definition rtrowdump.py:125
char * rtpg_strreplace(const char *str, const char *oldstr, const char *newstr, int *count)
char * rtpg_trim(const char *input)
char * rtpg_strtoupper(char *str)
static void rtpg_nmapalgebraexpr_arg_destroy(rtpg_nmapalgebraexpr_arg arg)
static rtpg_nmapalgebraexpr_arg rtpg_nmapalgebraexpr_arg_init(int cnt, char **kw)
static int rtpg_nmapalgebra_rastbandarg_process(rtpg_nmapalgebra_arg arg, ArrayType *array, int *allnull, int *allempty, int *noband)
static int rtpg_nmapalgebraexpr_callback(rt_iterator_arg arg, void *userarg, double *value, int *nodata)
#define POSTGIS_RT_DEBUGF(level, msg,...)
Definition rtpostgis.h:69
rt_raster raster
Definition librtcore.h:2659
uint16_t nband
Definition librtcore.h:2660
uint8_t nbnodata
Definition librtcore.h:2661
Struct definitions.
Definition librtcore.h:2452
rtpg_nmapalgebraexpr_callback_arg callback
rtpg_nmapalgebra_arg bandarg
struct rtpg_nmapalgebraexpr_callback_arg::@26 nodatanodata
struct rtpg_nmapalgebraexpr_callback_arg::@25 expr[3]

References rtpg_nmapalgebraexpr_arg_t::bandarg, rtpg_nmapalgebraexpr_arg_t::callback, rtpg_nmapalgebra_arg_t::cextent, ES_NONE, ET_CUSTOM, ET_FIRST, ET_INTERSECTION, ET_LAST, ET_SECOND, rtpg_nmapalgebraexpr_callback_arg::expr, rtpg_nmapalgebraexpr_callback_arg::exprcount, rtpg_nmapalgebra_arg_t::extenttype, FALSE, rtpg_nmapalgebra_arg_t::hasband, rtpg_nmapalgebra_arg_t::hasnodata, rtpg_nmapalgebraexpr_callback_arg::hasval, rt_iterator_t::nband, rtpg_nmapalgebra_arg_t::nband, rt_iterator_t::nbnodata, rtpg_nmapalgebraexpr_callback_arg::nodatanodata, rtpg_nmapalgebra_arg_t::nodataval, rtpg_nmapalgebra_arg_t::numraster, rtpg_nmapalgebra_arg_t::pixtype, POSTGIS_RT_DEBUGF, PT_END, rt_iterator_t::raster, rtpg_nmapalgebra_arg_t::raster, rt_band_get_hasnodata_flag(), rt_band_get_min_value(), rt_band_get_nodata(), rt_band_get_pixtype(), rt_pixtype_index_from_name(), rt_pixtype_name(), rt_raster_destroy(), rt_raster_get_band(), rt_raster_iterator(), rt_raster_new(), rt_raster_serialize(), rt_util_extent_type(), rtpg_nmapalgebra_rastbandarg_process(), rtpg_nmapalgebraexpr_arg_destroy(), rtpg_nmapalgebraexpr_arg_init(), rtpg_nmapalgebraexpr_callback(), rtpg_strreplace(), rtpg_strtoupper(), rtpg_trim(), rt_raster_serialized_t::size, rtpg_nmapalgebraexpr_callback_arg::spi_argcount, rtpg_nmapalgebraexpr_callback_arg::spi_argpos, rtpg_nmapalgebraexpr_callback_arg::spi_plan, TRUE, and rtpg_nmapalgebraexpr_callback_arg::val.

Here is the call graph for this function: