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
4421 int x,
y,
nband, width, height;
4423 double newnodatavalue = 0.0;
4424 double newinitialvalue = 0.0;
4425 double newval = 0.0;
4426 char *newexpr = NULL;
4427 char *initexpr = NULL;
4428 char *expression = NULL;
4429 int hasnodataval = 0;
4430 double nodataval = 0.;
4432 int skipcomputation = 0;
4434 const int argkwcount = 3;
4435 enum KEYWORDS { kVAL=0, kX=1, kY=2 };
4436 char *argkw[] = {
"[rast]",
"[rast.x]",
"[rast.y]"};
4437 Oid argkwtypes[] = { FLOAT8OID, INT4OID, INT4OID };
4439 Oid argtype[] = { FLOAT8OID, INT4OID, INT4OID };
4440 uint8_t argpos[3] = {0};
4445 SPIPlanPtr spi_plan = NULL;
4446 SPITupleTable * tuptable = NULL;
4448 char * strFromText = NULL;
4449 Datum *values = NULL;
4450 Datum datum = (Datum)NULL;
4452 bool isnull =
FALSE;
4459 if (PG_ARGISNULL(0)) {
4460 elog(NOTICE,
"Raster is NULL. Returning NULL");
4466 pgraster = (
rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
4469 PG_FREE_IF_COPY(pgraster, 0);
4470 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not deserialize raster");
4476 if (PG_ARGISNULL(1))
4479 nband = PG_GETARG_INT32(1);
4485 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraExpr: Creating new empty raster...");
4496 if ( NULL == newrast ) {
4497 PG_FREE_IF_COPY(pgraster, 0);
4498 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not create a new raster");
4523 elog(NOTICE,
"Raster is empty. Returning an empty raster");
4525 PG_FREE_IF_COPY(pgraster, 0);
4529 if (NULL == pgrtn) {
4531 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4535 SET_VARSIZE(pgrtn, pgrtn->
size);
4536 PG_RETURN_POINTER(pgrtn);
4547 elog(NOTICE,
"Raster does not have the required band. Returning a raster "
4550 PG_FREE_IF_COPY(pgraster, 0);
4554 if (NULL == pgrtn) {
4555 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4559 SET_VARSIZE(pgrtn, pgrtn->
size);
4560 PG_RETURN_POINTER(pgrtn);
4565 if ( NULL ==
band ) {
4566 elog(NOTICE,
"Could not get the required band. Returning a raster "
4569 PG_FREE_IF_COPY(pgraster, 0);
4573 if (NULL == pgrtn) {
4574 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4578 SET_VARSIZE(pgrtn, pgrtn->
size);
4579 PG_RETURN_POINTER(pgrtn);
4585 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraExpr: Getting NODATA value for band...");
4603 newinitialvalue = newnodatavalue;
4610 if (PG_ARGISNULL(2)) {
4615 strFromText = text_to_cstring(PG_GETARG_TEXT_P(2));
4618 if (newpixeltype ==
PT_END)
4622 if (newpixeltype ==
PT_END) {
4623 PG_FREE_IF_COPY(pgraster, 0);
4624 elog(ERROR,
"RASTER_mapAlgebraExpr: Invalid pixeltype");
4633 if (!PG_ARGISNULL(3)) {
4634 expression = text_to_cstring(PG_GETARG_TEXT_P(3));
4635 len = strlen(
"SELECT (") + strlen(expression) + strlen(
")::double precision");
4636 initexpr = (
char *)palloc(len + 1);
4638 memcpy(initexpr,
"SELECT (", strlen(
"SELECT ("));
4639 memcpy(initexpr + strlen(
"SELECT ("), expression, strlen(expression));
4640 memcpy(initexpr + strlen(
"SELECT (") + strlen(expression),
")::double precision", strlen(
")::double precision"));
4641 initexpr[len] =
'\0';
4659 if (!PG_ARGISNULL(4)) {
4661 nodataval = PG_GETARG_FLOAT8(4);
4662 newinitialvalue = nodataval;
4679 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraExpr: Band is a nodata band, returning "
4680 "a raster filled with nodata");
4683 newinitialvalue,
TRUE, newnodatavalue, 0);
4689 PG_FREE_IF_COPY(pgraster, 0);
4694 if (NULL == pgrtn) {
4695 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4699 SET_VARSIZE(pgrtn, pgrtn->
size);
4700 PG_RETURN_POINTER(pgrtn);
4708 if (initexpr != NULL && ( !strcmp(initexpr,
"SELECT [rast]") || !strcmp(initexpr,
"SELECT [rast.val]") ) && !hasnodataval) {
4711 "Returning raster with band %d from original raster",
nband);
4723 PG_FREE_IF_COPY(pgraster, 0);
4728 if (NULL == pgrtn) {
4729 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4733 SET_VARSIZE(pgrtn, pgrtn->
size);
4734 PG_RETURN_POINTER(pgrtn);
4741 if (initexpr != NULL && strstr(initexpr,
"[rast") == NULL) {
4742 ret = SPI_connect();
4743 if (ret != SPI_OK_CONNECT) {
4744 PG_FREE_IF_COPY(pgraster, 0);
4745 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not connect to the SPI manager");
4750 ret = SPI_execute(initexpr,
FALSE, 0);
4752 if (ret != SPI_OK_SELECT || SPI_tuptable == NULL || SPI_processed != 1) {
4756 SPI_freetuptable(tuptable);
4757 PG_FREE_IF_COPY(pgraster, 0);
4760 elog(ERROR,
"RASTER_mapAlgebraExpr: Invalid construction for expression");
4764 tupdesc = SPI_tuptable->tupdesc;
4765 tuptable = SPI_tuptable;
4767 tuple = tuptable->vals[0];
4768 newexpr = SPI_getvalue(tuple, tupdesc, 1);
4770 POSTGIS_RT_DEBUG(3,
"Constant expression evaluated to NULL, keeping initvalue");
4771 newval = newinitialvalue;
4773 newval = atof(newexpr);
4776 SPI_freetuptable(tuptable);
4783 skipcomputation = 1;
4789 if (!hasnodataval) {
4790 newinitialvalue = newval;
4791 skipcomputation = 2;
4795 else if (
FLT_NEQ(newval, newinitialvalue)) {
4796 skipcomputation = 2;
4805 newinitialvalue,
TRUE, newnodatavalue, 0);
4812 if (expression == NULL || skipcomputation == 2) {
4818 PG_FREE_IF_COPY(pgraster, 0);
4823 if (NULL == pgrtn) {
4824 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4828 SET_VARSIZE(pgrtn, pgrtn->
size);
4829 PG_RETURN_POINTER(pgrtn);
4832 RASTER_DEBUG(3,
"RASTER_mapAlgebraExpr: Creating new raster band...");
4836 if ( NULL == newband ) {
4837 elog(NOTICE,
"Could not modify band for new raster. Returning new "
4838 "raster with the original band");
4843 PG_FREE_IF_COPY(pgraster, 0);
4848 if (NULL == pgrtn) {
4849 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4853 SET_VARSIZE(pgrtn, pgrtn->
size);
4854 PG_RETURN_POINTER(pgrtn);
4860 if (initexpr != NULL) {
4863 pfree(initexpr); initexpr=newexpr;
4865 sprintf(place,
"$1");
4866 for (i = 0, j = 1; i < argkwcount; i++) {
4869 pfree(initexpr); initexpr=newexpr;
4871 argtype[argcount] = argkwtypes[i];
4875 sprintf(place,
"$%d", j);
4885 values = (Datum *) palloc(
sizeof(Datum) * argcount);
4886 if (values == NULL) {
4891 PG_FREE_IF_COPY(pgraster, 0);
4894 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not allocate memory for value parameters of prepared statement");
4899 nulls = (
char *)palloc(argcount);
4900 if (nulls == NULL) {
4905 PG_FREE_IF_COPY(pgraster, 0);
4908 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not allocate memory for null parameters of prepared statement");
4913 ret = SPI_connect();
4914 if (ret != SPI_OK_CONNECT) {
4919 PG_FREE_IF_COPY(pgraster, 0);
4922 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not connect to the SPI manager");
4927 spi_plan = SPI_prepare(initexpr, argcount, argtype);
4929 if (spi_plan == NULL) {
4932 PG_FREE_IF_COPY(pgraster, 0);
4939 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not prepare expression");
4944 for (
x = 0;
x < width;
x++) {
4945 for(
y = 0;
y < height;
y++) {
4953 if (skipcomputation == 0) {
4954 if (initexpr != NULL) {
4956 memset(nulls,
'n', argcount);
4958 for (i = 0; i < argkwcount; i++) {
4960 if (idx < 1)
continue;
4965 values[idx] = Int32GetDatum(
x+1);
4970 values[idx] = Int32GetDatum(
y+1);
4973 else if (i == kVAL ) {
4974 values[idx] = Float8GetDatum(
r);
4980 ret = SPI_execute_plan(spi_plan, values, nulls,
FALSE, 0);
4981 if (ret != SPI_OK_SELECT || SPI_tuptable == NULL ||
4982 SPI_processed != 1) {
4984 SPI_freetuptable(tuptable);
4986 SPI_freeplan(spi_plan);
4994 PG_FREE_IF_COPY(pgraster, 0);
4997 elog(ERROR,
"RASTER_mapAlgebraExpr: Error executing prepared plan");
5002 tupdesc = SPI_tuptable->tupdesc;
5003 tuptable = SPI_tuptable;
5005 tuple = tuptable->vals[0];
5006 datum = SPI_getbinval(tuple, tupdesc, 1, &isnull);
5007 if ( SPI_result == SPI_ERROR_NOATTRIBUTE ) {
5008 POSTGIS_RT_DEBUGF(3,
"Expression for pixel %d,%d (value %g) errored, skip setting",
x+1,
y+1,
r);
5009 newval = newinitialvalue;
5011 else if ( isnull ) {
5012 POSTGIS_RT_DEBUGF(3,
"Expression for pixel %d,%d (value %g) evaluated to NULL, skip setting",
x+1,
y+1,
r);
5013 newval = newinitialvalue;
5015 newval = DatumGetFloat8(datum);
5018 SPI_freetuptable(tuptable);
5022 newval = newinitialvalue;
5035 if (initexpr != NULL) {
5036 SPI_freeplan(spi_plan);
5050 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraExpr: raster modified, serializing it.");
5054 PG_FREE_IF_COPY(pgraster, 0);
5061 SET_VARSIZE(pgrtn, pgrtn->
size);
5069 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,...)