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
4585 int x,
y,
nband, width, height;
4587 double newnodatavalue = 0.0;
4588 double newinitialvalue = 0.0;
4589 double newval = 0.0;
4590 char *newexpr = NULL;
4591 char *initexpr = NULL;
4592 char *expression = NULL;
4593 int hasnodataval = 0;
4594 double nodataval = 0.;
4596 int skipcomputation = 0;
4598 const int argkwcount = 3;
4599 enum KEYWORDS { kVAL=0, kX=1, kY=2 };
4600 char *argkw[] = {
"[rast]",
"[rast.x]",
"[rast.y]"};
4601 Oid argkwtypes[] = { FLOAT8OID, INT4OID, INT4OID };
4603 Oid argtype[] = { FLOAT8OID, INT4OID, INT4OID };
4604 uint8_t argpos[3] = {0};
4609 SPIPlanPtr spi_plan = NULL;
4610 SPITupleTable * tuptable = NULL;
4612 char * strFromText = NULL;
4613 Datum *values = NULL;
4614 Datum datum = (Datum)NULL;
4616 bool isnull =
FALSE;
4623 if (PG_ARGISNULL(0)) {
4624 elog(NOTICE,
"Raster is NULL. Returning NULL");
4630 pgraster = (
rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
4633 PG_FREE_IF_COPY(pgraster, 0);
4634 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not deserialize raster");
4640 if (PG_ARGISNULL(1))
4643 nband = PG_GETARG_INT32(1);
4649 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraExpr: Creating new empty raster...");
4660 if ( NULL == newrast ) {
4661 PG_FREE_IF_COPY(pgraster, 0);
4662 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not create a new raster");
4687 elog(NOTICE,
"Raster is empty. Returning an empty raster");
4689 PG_FREE_IF_COPY(pgraster, 0);
4693 if (NULL == pgrtn) {
4695 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4699 SET_VARSIZE(pgrtn, pgrtn->
size);
4700 PG_RETURN_POINTER(pgrtn);
4711 elog(NOTICE,
"Raster does not have the required band. Returning a raster "
4714 PG_FREE_IF_COPY(pgraster, 0);
4718 if (NULL == pgrtn) {
4719 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4723 SET_VARSIZE(pgrtn, pgrtn->
size);
4724 PG_RETURN_POINTER(pgrtn);
4729 if ( NULL ==
band ) {
4730 elog(NOTICE,
"Could not get the required band. Returning a raster "
4733 PG_FREE_IF_COPY(pgraster, 0);
4737 if (NULL == pgrtn) {
4738 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4742 SET_VARSIZE(pgrtn, pgrtn->
size);
4743 PG_RETURN_POINTER(pgrtn);
4749 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraExpr: Getting NODATA value for band...");
4767 newinitialvalue = newnodatavalue;
4774 if (PG_ARGISNULL(2)) {
4779 strFromText = text_to_cstring(PG_GETARG_TEXT_P(2));
4782 if (newpixeltype ==
PT_END)
4786 if (newpixeltype ==
PT_END) {
4787 PG_FREE_IF_COPY(pgraster, 0);
4788 elog(ERROR,
"RASTER_mapAlgebraExpr: Invalid pixeltype");
4797 if (!PG_ARGISNULL(3)) {
4798 expression = text_to_cstring(PG_GETARG_TEXT_P(3));
4799 len = strlen(
"SELECT (") + strlen(expression) + strlen(
")::double precision");
4800 initexpr = (
char *)palloc(len + 1);
4802 memcpy(initexpr,
"SELECT (", strlen(
"SELECT ("));
4803 memcpy(initexpr + strlen(
"SELECT ("), expression, strlen(expression));
4804 memcpy(initexpr + strlen(
"SELECT (") + strlen(expression),
")::double precision", strlen(
")::double precision"));
4805 initexpr[len] =
'\0';
4823 if (!PG_ARGISNULL(4)) {
4825 nodataval = PG_GETARG_FLOAT8(4);
4826 newinitialvalue = nodataval;
4843 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraExpr: Band is a nodata band, returning "
4844 "a raster filled with nodata");
4847 newinitialvalue,
TRUE, newnodatavalue, 0);
4853 PG_FREE_IF_COPY(pgraster, 0);
4858 if (NULL == pgrtn) {
4859 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4863 SET_VARSIZE(pgrtn, pgrtn->
size);
4864 PG_RETURN_POINTER(pgrtn);
4872 if (initexpr != NULL && ( !strcmp(initexpr,
"SELECT [rast]") || !strcmp(initexpr,
"SELECT [rast.val]") ) && !hasnodataval) {
4875 "Returning raster with band %d from original raster",
nband);
4887 PG_FREE_IF_COPY(pgraster, 0);
4892 if (NULL == pgrtn) {
4893 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4897 SET_VARSIZE(pgrtn, pgrtn->
size);
4898 PG_RETURN_POINTER(pgrtn);
4905 if (initexpr != NULL && strstr(initexpr,
"[rast") == NULL) {
4906 ret = SPI_connect();
4907 if (ret != SPI_OK_CONNECT) {
4908 PG_FREE_IF_COPY(pgraster, 0);
4909 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not connect to the SPI manager");
4914 ret = SPI_execute(initexpr,
FALSE, 0);
4916 if (ret != SPI_OK_SELECT || SPI_tuptable == NULL || SPI_processed != 1) {
4920 SPI_freetuptable(tuptable);
4921 PG_FREE_IF_COPY(pgraster, 0);
4924 elog(ERROR,
"RASTER_mapAlgebraExpr: Invalid construction for expression");
4928 tupdesc = SPI_tuptable->tupdesc;
4929 tuptable = SPI_tuptable;
4931 tuple = tuptable->vals[0];
4932 newexpr = SPI_getvalue(tuple, tupdesc, 1);
4934 POSTGIS_RT_DEBUG(3,
"Constant expression evaluated to NULL, keeping initvalue");
4935 newval = newinitialvalue;
4937 newval = atof(newexpr);
4940 SPI_freetuptable(tuptable);
4947 skipcomputation = 1;
4953 if (!hasnodataval) {
4954 newinitialvalue = newval;
4955 skipcomputation = 2;
4959 else if (
FLT_NEQ(newval, newinitialvalue)) {
4960 skipcomputation = 2;
4969 newinitialvalue,
TRUE, newnodatavalue, 0);
4976 if (expression == NULL || skipcomputation == 2) {
4982 PG_FREE_IF_COPY(pgraster, 0);
4987 if (NULL == pgrtn) {
4988 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4992 SET_VARSIZE(pgrtn, pgrtn->
size);
4993 PG_RETURN_POINTER(pgrtn);
4996 RASTER_DEBUG(3,
"RASTER_mapAlgebraExpr: Creating new raster band...");
5000 if ( NULL == newband ) {
5001 elog(NOTICE,
"Could not modify band for new raster. Returning new "
5002 "raster with the original band");
5007 PG_FREE_IF_COPY(pgraster, 0);
5012 if (NULL == pgrtn) {
5013 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
5017 SET_VARSIZE(pgrtn, pgrtn->
size);
5018 PG_RETURN_POINTER(pgrtn);
5024 if (initexpr != NULL) {
5027 pfree(initexpr); initexpr=newexpr;
5029 sprintf(place,
"$1");
5030 for (i = 0, j = 1; i < argkwcount; i++) {
5033 pfree(initexpr); initexpr=newexpr;
5035 argtype[argcount] = argkwtypes[i];
5039 sprintf(place,
"$%d", j);
5049 values = (Datum *) palloc(
sizeof(Datum) * argcount);
5050 if (values == NULL) {
5055 PG_FREE_IF_COPY(pgraster, 0);
5058 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not allocate memory for value parameters of prepared statement");
5063 nulls = (
char *)palloc(argcount);
5064 if (nulls == NULL) {
5069 PG_FREE_IF_COPY(pgraster, 0);
5072 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not allocate memory for null parameters of prepared statement");
5077 ret = SPI_connect();
5078 if (ret != SPI_OK_CONNECT) {
5083 PG_FREE_IF_COPY(pgraster, 0);
5086 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not connect to the SPI manager");
5091 spi_plan = SPI_prepare(initexpr, argcount, argtype);
5093 if (spi_plan == NULL) {
5096 PG_FREE_IF_COPY(pgraster, 0);
5103 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not prepare expression");
5108 for (
x = 0;
x < width;
x++) {
5109 for(
y = 0;
y < height;
y++) {
5117 if (skipcomputation == 0) {
5118 if (initexpr != NULL) {
5120 memset(nulls,
'n', argcount);
5122 for (i = 0; i < argkwcount; i++) {
5124 if (idx < 1)
continue;
5129 values[idx] = Int32GetDatum(
x+1);
5134 values[idx] = Int32GetDatum(
y+1);
5137 else if (i == kVAL ) {
5138 values[idx] = Float8GetDatum(
r);
5144 ret = SPI_execute_plan(spi_plan, values, nulls,
FALSE, 0);
5145 if (ret != SPI_OK_SELECT || SPI_tuptable == NULL ||
5146 SPI_processed != 1) {
5148 SPI_freetuptable(tuptable);
5150 SPI_freeplan(spi_plan);
5158 PG_FREE_IF_COPY(pgraster, 0);
5161 elog(ERROR,
"RASTER_mapAlgebraExpr: Error executing prepared plan");
5166 tupdesc = SPI_tuptable->tupdesc;
5167 tuptable = SPI_tuptable;
5169 tuple = tuptable->vals[0];
5170 datum = SPI_getbinval(tuple, tupdesc, 1, &isnull);
5171 if ( SPI_result == SPI_ERROR_NOATTRIBUTE ) {
5172 POSTGIS_RT_DEBUGF(3,
"Expression for pixel %d,%d (value %g) errored, skip setting",
x+1,
y+1,
r);
5173 newval = newinitialvalue;
5175 else if ( isnull ) {
5176 POSTGIS_RT_DEBUGF(3,
"Expression for pixel %d,%d (value %g) evaluated to NULL, skip setting",
x+1,
y+1,
r);
5177 newval = newinitialvalue;
5179 newval = DatumGetFloat8(datum);
5182 SPI_freetuptable(tuptable);
5186 newval = newinitialvalue;
5199 if (initexpr != NULL) {
5200 SPI_freeplan(spi_plan);
5214 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraExpr: raster modified, serializing it.");
5218 PG_FREE_IF_COPY(pgraster, 0);
5225 SET_VARSIZE(pgrtn, pgrtn->
size);
5233 PG_RETURN_POINTER(pgrtn);
#define RASTER_DEBUG(level, msg)
int32_t rt_raster_get_srid(rt_raster raster)
Get raster's SRID.
double rt_raster_get_x_skew(rt_raster raster)
Get skew about the X axis.
double rt_raster_get_x_offset(rt_raster raster)
Get raster x offset, 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.
void rt_raster_set_scale(rt_raster raster, double scaleX, double scaleY)
Set scale in projection units.
int rt_band_get_hasnodata_flag(rt_band band)
Get hasnodata flag value.
rt_pixtype rt_pixtype_index_from_name(const char *pixname)
rt_errorstate rt_band_get_pixel(rt_band band, int x, int y, double *value, int *nodata)
Get pixel value.
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
void rt_raster_set_skews(rt_raster raster, double skewX, double skewY)
Set skews about the X and Y axis.
int rt_band_get_isnodata_flag(rt_band band)
Get isnodata flag value.
rt_raster rt_raster_new(uint32_t width, uint32_t height)
Construct a raster with given dimensions.
int rt_raster_has_band(rt_raster raster, int nband)
Return TRUE if the raster has a band of this number.
void * rt_raster_serialize(rt_raster raster)
Return this raster in serialized form.
double rt_raster_get_x_scale(rt_raster raster)
Get scale X in projection units.
double rt_band_get_min_value(rt_band band)
Returns the minimal possible value for the band according to the pixel type.
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_num_bands(rt_raster raster)
uint16_t rt_raster_get_height(rt_raster raster)
void rt_raster_set_srid(rt_raster raster, int32_t srid)
Set raster's SRID.
rt_errorstate rt_band_get_nodata(rt_band band, double *nodata)
Get NODATA value.
rt_pixtype rt_band_get_pixtype(rt_band band)
Return pixeltype of this band.
const char * rt_pixtype_name(rt_pixtype pixtype)
uint16_t rt_raster_get_width(rt_raster raster)
int rt_raster_copy_band(rt_raster torast, rt_raster fromrast, int fromindex, int toindex)
Copy one band from one raster to another.
double rt_raster_get_y_scale(rt_raster raster)
Get scale Y in projection units.
double rt_raster_get_y_skew(rt_raster raster)
Get skew about the Y axis.
void rt_raster_set_offsets(rt_raster raster, double x, double y)
Set insertion points in projection units.
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.
int rt_raster_is_empty(rt_raster raster)
Return TRUE if the raster is empty.
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
char * rtpg_strreplace(const char *str, const char *oldstr, const char *newstr, int *count)
#define POSTGIS_RT_DEBUG(level, msg)
#define POSTGIS_RT_DEBUGF(level, msg,...)