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
4483 int x,
y,
nband, width, height;
4485 double newnodatavalue = 0.0;
4486 double newinitialvalue = 0.0;
4487 double newval = 0.0;
4488 char *newexpr = NULL;
4489 char *initexpr = NULL;
4490 char *expression = NULL;
4491 int hasnodataval = 0;
4492 double nodataval = 0.;
4494 int skipcomputation = 0;
4496 const int argkwcount = 3;
4497 enum KEYWORDS { kVAL=0, kX=1, kY=2 };
4498 char *argkw[] = {
"[rast]",
"[rast.x]",
"[rast.y]"};
4499 Oid argkwtypes[] = { FLOAT8OID, INT4OID, INT4OID };
4501 Oid argtype[] = { FLOAT8OID, INT4OID, INT4OID };
4507 SPIPlanPtr spi_plan = NULL;
4508 SPITupleTable * tuptable = NULL;
4510 char * strFromText = NULL;
4511 Datum *values = NULL;
4512 Datum datum = (Datum)NULL;
4514 bool isnull =
FALSE;
4521 if (PG_ARGISNULL(0)) {
4522 elog(NOTICE,
"Raster is NULL. Returning NULL");
4528 pgraster = (
rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
4531 PG_FREE_IF_COPY(pgraster, 0);
4532 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not deserialize raster");
4538 if (PG_ARGISNULL(1))
4541 nband = PG_GETARG_INT32(1);
4547 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraExpr: Creating new empty raster...");
4558 if ( NULL == newrast ) {
4559 PG_FREE_IF_COPY(pgraster, 0);
4560 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not create a new raster");
4585 elog(NOTICE,
"Raster is empty. Returning an empty raster");
4587 PG_FREE_IF_COPY(pgraster, 0);
4591 if (NULL == pgrtn) {
4593 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4597 SET_VARSIZE(pgrtn, pgrtn->
size);
4598 PG_RETURN_POINTER(pgrtn);
4609 elog(NOTICE,
"Raster does not have the required band. Returning a raster "
4612 PG_FREE_IF_COPY(pgraster, 0);
4616 if (NULL == pgrtn) {
4617 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4621 SET_VARSIZE(pgrtn, pgrtn->
size);
4622 PG_RETURN_POINTER(pgrtn);
4627 if ( NULL ==
band ) {
4628 elog(NOTICE,
"Could not get the required band. Returning a raster "
4631 PG_FREE_IF_COPY(pgraster, 0);
4635 if (NULL == pgrtn) {
4636 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4640 SET_VARSIZE(pgrtn, pgrtn->
size);
4641 PG_RETURN_POINTER(pgrtn);
4647 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraExpr: Getting NODATA value for band...");
4665 newinitialvalue = newnodatavalue;
4672 if (PG_ARGISNULL(2)) {
4680 if (newpixeltype ==
PT_END)
4684 if (newpixeltype ==
PT_END) {
4685 PG_FREE_IF_COPY(pgraster, 0);
4686 elog(ERROR,
"RASTER_mapAlgebraExpr: Invalid pixeltype");
4695 if (!PG_ARGISNULL(3)) {
4697 len = strlen(
"SELECT (") + strlen(expression) + strlen(
")::double precision");
4698 initexpr = (
char *)palloc(len + 1);
4700 strncpy(initexpr,
"SELECT (", strlen(
"SELECT ("));
4701 strncpy(initexpr + strlen(
"SELECT ("), expression, strlen(expression));
4702 strncpy(initexpr + strlen(
"SELECT (") + strlen(expression),
")::double precision", strlen(
")::double precision"));
4703 initexpr[len] =
'\0';
4721 if (!PG_ARGISNULL(4)) {
4723 nodataval = PG_GETARG_FLOAT8(4);
4724 newinitialvalue = nodataval;
4741 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraExpr: Band is a nodata band, returning "
4742 "a raster filled with nodata");
4745 newinitialvalue,
TRUE, newnodatavalue, 0);
4751 PG_FREE_IF_COPY(pgraster, 0);
4756 if (NULL == pgrtn) {
4757 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4761 SET_VARSIZE(pgrtn, pgrtn->
size);
4762 PG_RETURN_POINTER(pgrtn);
4770 if (initexpr != NULL && ( !strcmp(initexpr,
"SELECT [rast]") || !strcmp(initexpr,
"SELECT [rast.val]") ) && !hasnodataval) {
4773 "Returning raster with band %d from original raster",
nband);
4785 PG_FREE_IF_COPY(pgraster, 0);
4790 if (NULL == pgrtn) {
4791 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4795 SET_VARSIZE(pgrtn, pgrtn->
size);
4796 PG_RETURN_POINTER(pgrtn);
4803 if (initexpr != NULL && strstr(initexpr,
"[rast") == NULL) {
4804 ret = SPI_connect();
4805 if (ret != SPI_OK_CONNECT) {
4806 PG_FREE_IF_COPY(pgraster, 0);
4807 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not connect to the SPI manager");
4812 ret = SPI_execute(initexpr,
FALSE, 0);
4814 if (ret != SPI_OK_SELECT || SPI_tuptable == NULL || SPI_processed != 1) {
4818 SPI_freetuptable(tuptable);
4819 PG_FREE_IF_COPY(pgraster, 0);
4822 elog(ERROR,
"RASTER_mapAlgebraExpr: Invalid construction for expression");
4826 tupdesc = SPI_tuptable->tupdesc;
4827 tuptable = SPI_tuptable;
4829 tuple = tuptable->vals[0];
4830 newexpr = SPI_getvalue(tuple, tupdesc, 1);
4832 POSTGIS_RT_DEBUG(3,
"Constant expression evaluated to NULL, keeping initvalue");
4833 newval = newinitialvalue;
4835 newval = atof(newexpr);
4838 SPI_freetuptable(tuptable);
4845 skipcomputation = 1;
4851 if (!hasnodataval) {
4852 newinitialvalue = newval;
4853 skipcomputation = 2;
4857 else if (
FLT_NEQ(newval, newinitialvalue)) {
4858 skipcomputation = 2;
4867 newinitialvalue,
TRUE, newnodatavalue, 0);
4874 if (expression == NULL || skipcomputation == 2) {
4880 PG_FREE_IF_COPY(pgraster, 0);
4885 if (NULL == pgrtn) {
4886 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4890 SET_VARSIZE(pgrtn, pgrtn->
size);
4891 PG_RETURN_POINTER(pgrtn);
4894 RASTER_DEBUG(3,
"RASTER_mapAlgebraExpr: Creating new raster band...");
4898 if ( NULL == newband ) {
4899 elog(NOTICE,
"Could not modify band for new raster. Returning new "
4900 "raster with the original band");
4905 PG_FREE_IF_COPY(pgraster, 0);
4910 if (NULL == pgrtn) {
4911 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4915 SET_VARSIZE(pgrtn, pgrtn->
size);
4916 PG_RETURN_POINTER(pgrtn);
4922 if (initexpr != NULL) {
4925 pfree(initexpr); initexpr=newexpr;
4927 sprintf(place,
"$1");
4928 for (i = 0, j = 1; i < argkwcount; i++) {
4931 pfree(initexpr); initexpr=newexpr;
4933 argtype[argcount] = argkwtypes[i];
4937 sprintf(place,
"$%d", j);
4947 values = (Datum *) palloc(
sizeof(Datum) * argcount);
4948 if (values == NULL) {
4953 PG_FREE_IF_COPY(pgraster, 0);
4956 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not allocate memory for value parameters of prepared statement");
4961 nulls = (
char *)palloc(argcount);
4962 if (nulls == NULL) {
4967 PG_FREE_IF_COPY(pgraster, 0);
4970 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not allocate memory for null parameters of prepared statement");
4975 ret = SPI_connect();
4976 if (ret != SPI_OK_CONNECT) {
4981 PG_FREE_IF_COPY(pgraster, 0);
4984 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not connect to the SPI manager");
4989 spi_plan = SPI_prepare(initexpr, argcount, argtype);
4991 if (spi_plan == NULL) {
4994 PG_FREE_IF_COPY(pgraster, 0);
5001 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not prepare expression");
5006 for (
x = 0;
x < width;
x++) {
5007 for(
y = 0;
y < height;
y++) {
5015 if (skipcomputation == 0) {
5016 if (initexpr != NULL) {
5018 memset(nulls,
'n', argcount);
5020 for (i = 0; i < argkwcount; i++) {
5022 if (idx < 1)
continue;
5027 values[idx] = Int32GetDatum(
x+1);
5032 values[idx] = Int32GetDatum(
y+1);
5035 else if (i == kVAL ) {
5036 values[idx] = Float8GetDatum(
r);
5042 ret = SPI_execute_plan(spi_plan, values, nulls,
FALSE, 0);
5043 if (ret != SPI_OK_SELECT || SPI_tuptable == NULL ||
5044 SPI_processed != 1) {
5046 SPI_freetuptable(tuptable);
5048 SPI_freeplan(spi_plan);
5056 PG_FREE_IF_COPY(pgraster, 0);
5059 elog(ERROR,
"RASTER_mapAlgebraExpr: Error executing prepared plan");
5064 tupdesc = SPI_tuptable->tupdesc;
5065 tuptable = SPI_tuptable;
5067 tuple = tuptable->vals[0];
5068 datum = SPI_getbinval(tuple, tupdesc, 1, &isnull);
5069 if ( SPI_result == SPI_ERROR_NOATTRIBUTE ) {
5070 POSTGIS_RT_DEBUGF(3,
"Expression for pixel %d,%d (value %g) errored, skip setting",
x+1,
y+1,
r);
5071 newval = newinitialvalue;
5073 else if ( isnull ) {
5074 POSTGIS_RT_DEBUGF(3,
"Expression for pixel %d,%d (value %g) evaluated to NULL, skip setting",
x+1,
y+1,
r);
5075 newval = newinitialvalue;
5077 newval = DatumGetFloat8(datum);
5080 SPI_freetuptable(tuptable);
5084 newval = newinitialvalue;
5097 if (initexpr != NULL) {
5098 SPI_freeplan(spi_plan);
5112 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraExpr: raster modified, serializing it.");
5116 PG_FREE_IF_COPY(pgraster, 0);
5123 SET_VARSIZE(pgrtn, pgrtn->
size);
5131 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 * text_to_cstring(const text *textptr)
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,...)