Create a new empty raster with having the same georeference as the provided raster
If this new raster is empty (width = 0 OR height = 0) then there is nothing to compute and we return it right now
Check if the raster has the required band. Otherwise, return a raster without band
We set the initial value of the future band to nodata value. If nodata value is null, then the raster will be initialized to rt_band_get_min_value but all the values should be recomputed anyway
Optimization: If a nodataval is provided, use it for newinitialvalue. Then, we can initialize the raster with this value and skip the computation of nodata values one by one in the main computing loop
Optimization: If the raster is only filled with nodata values return right now a raster filled with the newinitialvalue TODO: Call rt_band_check_isnodata instead?
Optimization: If expression resume to 'RAST' and hasnodataval is zero, we can just return the band from the original raster
Create the raster receiving all the computed values. Initialize it to the new initial value
Optimization: If expression is NULL, or all the pixels could be set in one step, return the initialized raster now
We compute a value only for the withdata value pixel since the nodata value has already been set by the first optimization
4472 double newnodatavalue = 0.0;
4473 double newinitialvalue = 0.0;
4474 double newval = 0.0;
4475 char *newexpr = NULL;
4476 char *initexpr = NULL;
4477 char *expression = NULL;
4478 int hasnodataval = 0;
4479 double nodataval = 0.;
4481 int skipcomputation = 0;
4483 const int argkwcount = 3;
4484 enum KEYWORDS { kVAL=0, kX=1, kY=2 };
4485 char *argkw[] = {
"[rast]",
"[rast.x]",
"[rast.y]"};
4486 Oid argkwtypes[] = { FLOAT8OID, INT4OID, INT4OID };
4488 Oid argtype[] = { FLOAT8OID, INT4OID, INT4OID };
4494 SPIPlanPtr spi_plan = NULL;
4495 SPITupleTable * tuptable = NULL;
4497 char * strFromText = NULL;
4498 Datum *values = NULL;
4499 Datum datum = (Datum)NULL;
4501 bool isnull =
FALSE;
4508 if (PG_ARGISNULL(0)) {
4509 elog(NOTICE,
"Raster is NULL. Returning NULL");
4515 pgraster = (
rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
4517 if (NULL == raster) {
4518 PG_FREE_IF_COPY(pgraster, 0);
4519 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not deserialize raster");
4525 if (PG_ARGISNULL(1))
4528 nband = PG_GETARG_INT32(1);
4534 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraExpr: Creating new empty raster...");
4545 if ( NULL == newrast ) {
4546 PG_FREE_IF_COPY(pgraster, 0);
4547 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not create a new raster");
4572 elog(NOTICE,
"Raster is empty. Returning an empty raster");
4574 PG_FREE_IF_COPY(pgraster, 0);
4578 if (NULL == pgrtn) {
4580 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4584 SET_VARSIZE(pgrtn, pgrtn->
size);
4585 PG_RETURN_POINTER(pgrtn);
4589 POSTGIS_RT_DEBUGF(3,
"RASTER_mapAlgebraExpr: Getting raster band %d...", nband);
4596 elog(NOTICE,
"Raster does not have the required band. Returning a raster " 4599 PG_FREE_IF_COPY(pgraster, 0);
4603 if (NULL == pgrtn) {
4604 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4608 SET_VARSIZE(pgrtn, pgrtn->
size);
4609 PG_RETURN_POINTER(pgrtn);
4614 if ( NULL == band ) {
4615 elog(NOTICE,
"Could not get the required band. Returning a raster " 4618 PG_FREE_IF_COPY(pgraster, 0);
4622 if (NULL == pgrtn) {
4623 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4627 SET_VARSIZE(pgrtn, pgrtn->
size);
4628 PG_RETURN_POINTER(pgrtn);
4634 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraExpr: Getting NODATA value for band...");
4652 newinitialvalue = newnodatavalue;
4659 if (PG_ARGISNULL(2)) {
4664 strFromText = text_to_cstring(PG_GETARG_TEXT_P(2));
4667 if (newpixeltype ==
PT_END)
4671 if (newpixeltype ==
PT_END) {
4672 PG_FREE_IF_COPY(pgraster, 0);
4673 elog(ERROR,
"RASTER_mapAlgebraExpr: Invalid pixeltype");
4682 if (!PG_ARGISNULL(3)) {
4683 expression = text_to_cstring(PG_GETARG_TEXT_P(3));
4684 len = strlen(
"SELECT (") + strlen(expression) + strlen(
")::double precision");
4685 initexpr = (
char *)palloc(len + 1);
4687 strncpy(initexpr,
"SELECT (", strlen(
"SELECT ("));
4688 strncpy(initexpr + strlen(
"SELECT ("), expression, strlen(expression));
4689 strncpy(initexpr + strlen(
"SELECT (") + strlen(expression),
")::double precision", strlen(
")::double precision"));
4690 initexpr[len] =
'\0';
4708 if (!PG_ARGISNULL(4)) {
4710 nodataval = PG_GETARG_FLOAT8(4);
4711 newinitialvalue = nodataval;
4728 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraExpr: Band is a nodata band, returning " 4729 "a raster filled with nodata");
4732 newinitialvalue,
TRUE, newnodatavalue, 0);
4738 PG_FREE_IF_COPY(pgraster, 0);
4743 if (NULL == pgrtn) {
4744 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4748 SET_VARSIZE(pgrtn, pgrtn->
size);
4749 PG_RETURN_POINTER(pgrtn);
4757 if (initexpr != NULL && ( !strcmp(initexpr,
"SELECT [rast]") || !strcmp(initexpr,
"SELECT [rast.val]") ) && !hasnodataval) {
4760 "Returning raster with band %d from original raster", nband);
4773 PG_FREE_IF_COPY(pgraster, 0);
4778 if (NULL == pgrtn) {
4779 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4783 SET_VARSIZE(pgrtn, pgrtn->
size);
4784 PG_RETURN_POINTER(pgrtn);
4791 if (initexpr != NULL && strstr(initexpr,
"[rast") == NULL) {
4792 ret = SPI_connect();
4793 if (ret != SPI_OK_CONNECT) {
4794 PG_FREE_IF_COPY(pgraster, 0);
4795 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not connect to the SPI manager");
4800 ret = SPI_execute(initexpr,
FALSE, 0);
4802 if (ret != SPI_OK_SELECT || SPI_tuptable == NULL || SPI_processed != 1) {
4806 SPI_freetuptable(tuptable);
4807 PG_FREE_IF_COPY(pgraster, 0);
4810 elog(ERROR,
"RASTER_mapAlgebraExpr: Invalid construction for expression");
4814 tupdesc = SPI_tuptable->tupdesc;
4815 tuptable = SPI_tuptable;
4817 tuple = tuptable->vals[0];
4818 newexpr = SPI_getvalue(tuple, tupdesc, 1);
4820 POSTGIS_RT_DEBUG(3,
"Constant expression evaluated to NULL, keeping initvalue");
4821 newval = newinitialvalue;
4823 newval = atof(newexpr);
4826 SPI_freetuptable(tuptable);
4833 skipcomputation = 1;
4839 if (!hasnodataval) {
4840 newinitialvalue = newval;
4841 skipcomputation = 2;
4845 else if (
FLT_NEQ(newval, newinitialvalue)) {
4846 skipcomputation = 2;
4855 newinitialvalue,
TRUE, newnodatavalue, 0);
4862 if (expression == NULL || skipcomputation == 2) {
4868 PG_FREE_IF_COPY(pgraster, 0);
4873 if (NULL == pgrtn) {
4874 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4878 SET_VARSIZE(pgrtn, pgrtn->
size);
4879 PG_RETURN_POINTER(pgrtn);
4882 RASTER_DEBUG(3,
"RASTER_mapAlgebraExpr: Creating new raster band...");
4886 if ( NULL == newband ) {
4887 elog(NOTICE,
"Could not modify band for new raster. Returning new " 4888 "raster with the original band");
4893 PG_FREE_IF_COPY(pgraster, 0);
4898 if (NULL == pgrtn) {
4899 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4903 SET_VARSIZE(pgrtn, pgrtn->
size);
4904 PG_RETURN_POINTER(pgrtn);
4910 if (initexpr != NULL) {
4913 pfree(initexpr); initexpr=newexpr;
4915 sprintf(place,
"$1");
4916 for (i = 0, j = 1; i < argkwcount; i++) {
4919 pfree(initexpr); initexpr=newexpr;
4921 argtype[argcount] = argkwtypes[i];
4925 sprintf(place,
"$%d", j);
4935 values = (Datum *) palloc(
sizeof(Datum) * argcount);
4936 if (values == NULL) {
4941 PG_FREE_IF_COPY(pgraster, 0);
4944 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not allocate memory for value parameters of prepared statement");
4949 nulls = (
char *)palloc(argcount);
4950 if (nulls == NULL) {
4955 PG_FREE_IF_COPY(pgraster, 0);
4958 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not allocate memory for null parameters of prepared statement");
4963 ret = SPI_connect();
4964 if (ret != SPI_OK_CONNECT) {
4969 PG_FREE_IF_COPY(pgraster, 0);
4972 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not connect to the SPI manager");
4977 spi_plan = SPI_prepare(initexpr, argcount, argtype);
4979 if (spi_plan == NULL) {
4982 PG_FREE_IF_COPY(pgraster, 0);
4989 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not prepare expression");
4994 for (x = 0; x <
width; x++) {
4995 for(y = 0; y <
height; y++) {
5003 if (skipcomputation == 0) {
5004 if (initexpr != NULL) {
5006 memset(nulls,
'n', argcount);
5008 for (i = 0; i < argkwcount; i++) {
5010 if (idx < 1)
continue;
5015 values[idx] = Int32GetDatum(x+1);
5020 values[idx] = Int32GetDatum(y+1);
5023 else if (i == kVAL ) {
5024 values[idx] = Float8GetDatum(r);
5030 ret = SPI_execute_plan(spi_plan, values, nulls,
FALSE, 0);
5031 if (ret != SPI_OK_SELECT || SPI_tuptable == NULL ||
5032 SPI_processed != 1) {
5034 SPI_freetuptable(tuptable);
5036 SPI_freeplan(spi_plan);
5044 PG_FREE_IF_COPY(pgraster, 0);
5047 elog(ERROR,
"RASTER_mapAlgebraExpr: Error executing prepared plan");
5052 tupdesc = SPI_tuptable->tupdesc;
5053 tuptable = SPI_tuptable;
5055 tuple = tuptable->vals[0];
5056 datum = SPI_getbinval(tuple, tupdesc, 1, &isnull);
5057 if ( SPI_result == SPI_ERROR_NOATTRIBUTE ) {
5058 POSTGIS_RT_DEBUGF(3,
"Expression for pixel %d,%d (value %g) errored, skip setting", x+1,y+1,r);
5059 newval = newinitialvalue;
5061 else if ( isnull ) {
5062 POSTGIS_RT_DEBUGF(3,
"Expression for pixel %d,%d (value %g) evaluated to NULL, skip setting", x+1,y+1,r);
5063 newval = newinitialvalue;
5065 newval = DatumGetFloat8(datum);
5068 SPI_freetuptable(tuptable);
5072 newval = newinitialvalue;
5085 if (initexpr != NULL) {
5086 SPI_freeplan(spi_plan);
5100 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraExpr: raster modified, serializing it.");
5104 PG_FREE_IF_COPY(pgraster, 0);
5111 SET_VARSIZE(pgrtn, pgrtn->
size);
5119 PG_RETURN_POINTER(pgrtn);
void * rt_raster_serialize(rt_raster raster)
Return this raster in serialized form.
double rt_raster_get_x_offset(rt_raster raster)
Get raster x offset, in projection units.
int rt_raster_get_num_bands(rt_raster raster)
double rt_raster_get_y_skew(rt_raster raster)
Get skew about the Y axis.
raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
void rt_raster_set_skews(rt_raster raster, double skewX, double skewY)
Set skews about the X and Y axis.
char * rtpg_strreplace(const char *str, const char *oldstr, const char *newstr, int *count)
int rt_raster_is_empty(rt_raster raster)
Return TRUE if the raster is empty.
#define POSTGIS_RT_DEBUGF(level, msg,...)
rt_errorstate rt_band_get_nodata(rt_band band, double *nodata)
Get NODATA value.
rt_errorstate rt_band_get_pixel(rt_band band, int x, int y, double *value, int *nodata)
Get pixel value.
void rt_raster_set_scale(rt_raster raster, double scaleX, double scaleY)
Set scale in projection units.
int rt_raster_generate_new_band(rt_raster raster, rt_pixtype pixtype, double initialvalue, uint32_t hasnodata, double nodatavalue, int index)
Generate a new inline band and add it to a raster.
rt_pixtype rt_pixtype_index_from_name(const char *pixname)
void rt_raster_set_offsets(rt_raster raster, double x, double y)
Set insertion points in projection units.
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
int rt_raster_copy_band(rt_raster torast, rt_raster fromrast, int fromindex, int toindex)
Copy one band from one raster to another.
int rt_band_get_hasnodata_flag(rt_band band)
Get hasnodata flag value.
double rt_raster_get_x_scale(rt_raster raster)
Get scale X in projection units.
int rt_raster_has_band(rt_raster raster, int nband)
Return TRUE if the raster has a band of this number.
void rt_raster_set_srid(rt_raster raster, int32_t srid)
Set raster's SRID.
int32_t rt_raster_get_srid(rt_raster raster)
Get raster's SRID.
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
double rt_raster_get_y_scale(rt_raster raster)
Get scale Y in projection units.
rt_raster rt_raster_new(uint32_t width, uint32_t height)
Construct a raster with given dimensions.
double rt_raster_get_x_skew(rt_raster raster)
Get skew about the X axis.
uint16_t rt_raster_get_width(rt_raster raster)
#define RASTER_DEBUG(level, msg)
double rt_band_get_min_value(rt_band band)
Returns the minimal possible value for the band according to the pixel type.
const char * rt_pixtype_name(rt_pixtype pixtype)
rt_pixtype rt_band_get_pixtype(rt_band band)
Return pixeltype of this band.
int rt_band_get_isnodata_flag(rt_band band)
Get isnodata flag value.
rt_errorstate rt_band_set_pixel(rt_band band, int x, int y, double val, int *converted)
Set single pixel's value.
uint16_t rt_raster_get_height(rt_raster raster)
#define POSTGIS_RT_DEBUG(level, msg)
rt_raster rt_raster_deserialize(void *serialized, int header_only)
Return a raster from a serialized form.
double rt_raster_get_y_offset(rt_raster raster)
Get raster y offset, in projection units.