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
4482 int x,
y,
nband, width, height;
4484 double newnodatavalue = 0.0;
4485 double newinitialvalue = 0.0;
4486 double newval = 0.0;
4487 char *newexpr = NULL;
4488 char *initexpr = NULL;
4489 char *expression = NULL;
4490 int hasnodataval = 0;
4491 double nodataval = 0.;
4493 int skipcomputation = 0;
4495 const int argkwcount = 3;
4496 enum KEYWORDS { kVAL=0, kX=1, kY=2 };
4497 char *argkw[] = {
"[rast]",
"[rast.x]",
"[rast.y]"};
4498 Oid argkwtypes[] = { FLOAT8OID, INT4OID, INT4OID };
4500 Oid argtype[] = { FLOAT8OID, INT4OID, INT4OID };
4501 uint8_t argpos[3] = {0};
4506 SPIPlanPtr spi_plan = NULL;
4507 SPITupleTable * tuptable = NULL;
4509 char * strFromText = NULL;
4510 Datum *values = NULL;
4511 Datum datum = (Datum)NULL;
4513 bool isnull =
FALSE;
4520 if (PG_ARGISNULL(0)) {
4521 elog(NOTICE,
"Raster is NULL. Returning NULL");
4527 pgraster = (
rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
4530 PG_FREE_IF_COPY(pgraster, 0);
4531 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not deserialize raster");
4537 if (PG_ARGISNULL(1))
4540 nband = PG_GETARG_INT32(1);
4546 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraExpr: Creating new empty raster...");
4557 if ( NULL == newrast ) {
4558 PG_FREE_IF_COPY(pgraster, 0);
4559 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not create a new raster");
4584 elog(NOTICE,
"Raster is empty. Returning an empty raster");
4586 PG_FREE_IF_COPY(pgraster, 0);
4590 if (NULL == pgrtn) {
4592 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4596 SET_VARSIZE(pgrtn, pgrtn->
size);
4597 PG_RETURN_POINTER(pgrtn);
4608 elog(NOTICE,
"Raster does not have the required band. Returning a raster "
4611 PG_FREE_IF_COPY(pgraster, 0);
4615 if (NULL == pgrtn) {
4616 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4620 SET_VARSIZE(pgrtn, pgrtn->
size);
4621 PG_RETURN_POINTER(pgrtn);
4626 if ( NULL ==
band ) {
4627 elog(NOTICE,
"Could not get the required band. Returning a raster "
4630 PG_FREE_IF_COPY(pgraster, 0);
4634 if (NULL == pgrtn) {
4635 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4639 SET_VARSIZE(pgrtn, pgrtn->
size);
4640 PG_RETURN_POINTER(pgrtn);
4646 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraExpr: Getting NODATA value for band...");
4664 newinitialvalue = newnodatavalue;
4671 if (PG_ARGISNULL(2)) {
4679 if (newpixeltype ==
PT_END)
4683 if (newpixeltype ==
PT_END) {
4684 PG_FREE_IF_COPY(pgraster, 0);
4685 elog(ERROR,
"RASTER_mapAlgebraExpr: Invalid pixeltype");
4694 if (!PG_ARGISNULL(3)) {
4696 len = strlen(
"SELECT (") + strlen(expression) + strlen(
")::double precision");
4697 initexpr = (
char *)palloc(len + 1);
4699 memcpy(initexpr,
"SELECT (", strlen(
"SELECT ("));
4700 memcpy(initexpr + strlen(
"SELECT ("), expression, strlen(expression));
4701 memcpy(initexpr + strlen(
"SELECT (") + strlen(expression),
")::double precision", strlen(
")::double precision"));
4702 initexpr[len] =
'\0';
4720 if (!PG_ARGISNULL(4)) {
4722 nodataval = PG_GETARG_FLOAT8(4);
4723 newinitialvalue = nodataval;
4740 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraExpr: Band is a nodata band, returning "
4741 "a raster filled with nodata");
4744 newinitialvalue,
TRUE, newnodatavalue, 0);
4750 PG_FREE_IF_COPY(pgraster, 0);
4755 if (NULL == pgrtn) {
4756 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4760 SET_VARSIZE(pgrtn, pgrtn->
size);
4761 PG_RETURN_POINTER(pgrtn);
4769 if (initexpr != NULL && ( !strcmp(initexpr,
"SELECT [rast]") || !strcmp(initexpr,
"SELECT [rast.val]") ) && !hasnodataval) {
4772 "Returning raster with band %d from original raster",
nband);
4784 PG_FREE_IF_COPY(pgraster, 0);
4789 if (NULL == pgrtn) {
4790 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4794 SET_VARSIZE(pgrtn, pgrtn->
size);
4795 PG_RETURN_POINTER(pgrtn);
4802 if (initexpr != NULL && strstr(initexpr,
"[rast") == NULL) {
4803 ret = SPI_connect();
4804 if (ret != SPI_OK_CONNECT) {
4805 PG_FREE_IF_COPY(pgraster, 0);
4806 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not connect to the SPI manager");
4811 ret = SPI_execute(initexpr,
FALSE, 0);
4813 if (ret != SPI_OK_SELECT || SPI_tuptable == NULL || SPI_processed != 1) {
4817 SPI_freetuptable(tuptable);
4818 PG_FREE_IF_COPY(pgraster, 0);
4821 elog(ERROR,
"RASTER_mapAlgebraExpr: Invalid construction for expression");
4825 tupdesc = SPI_tuptable->tupdesc;
4826 tuptable = SPI_tuptable;
4828 tuple = tuptable->vals[0];
4829 newexpr = SPI_getvalue(tuple, tupdesc, 1);
4831 POSTGIS_RT_DEBUG(3,
"Constant expression evaluated to NULL, keeping initvalue");
4832 newval = newinitialvalue;
4834 newval = atof(newexpr);
4837 SPI_freetuptable(tuptable);
4844 skipcomputation = 1;
4850 if (!hasnodataval) {
4851 newinitialvalue = newval;
4852 skipcomputation = 2;
4856 else if (
FLT_NEQ(newval, newinitialvalue)) {
4857 skipcomputation = 2;
4866 newinitialvalue,
TRUE, newnodatavalue, 0);
4873 if (expression == NULL || skipcomputation == 2) {
4879 PG_FREE_IF_COPY(pgraster, 0);
4884 if (NULL == pgrtn) {
4885 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4889 SET_VARSIZE(pgrtn, pgrtn->
size);
4890 PG_RETURN_POINTER(pgrtn);
4893 RASTER_DEBUG(3,
"RASTER_mapAlgebraExpr: Creating new raster band...");
4897 if ( NULL == newband ) {
4898 elog(NOTICE,
"Could not modify band for new raster. Returning new "
4899 "raster with the original band");
4904 PG_FREE_IF_COPY(pgraster, 0);
4909 if (NULL == pgrtn) {
4910 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4914 SET_VARSIZE(pgrtn, pgrtn->
size);
4915 PG_RETURN_POINTER(pgrtn);
4921 if (initexpr != NULL) {
4924 pfree(initexpr); initexpr=newexpr;
4926 sprintf(place,
"$1");
4927 for (i = 0, j = 1; i < argkwcount; i++) {
4930 pfree(initexpr); initexpr=newexpr;
4932 argtype[argcount] = argkwtypes[i];
4936 sprintf(place,
"$%d", j);
4946 values = (Datum *) palloc(
sizeof(Datum) * argcount);
4947 if (values == NULL) {
4952 PG_FREE_IF_COPY(pgraster, 0);
4955 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not allocate memory for value parameters of prepared statement");
4960 nulls = (
char *)palloc(argcount);
4961 if (nulls == NULL) {
4966 PG_FREE_IF_COPY(pgraster, 0);
4969 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not allocate memory for null parameters of prepared statement");
4974 ret = SPI_connect();
4975 if (ret != SPI_OK_CONNECT) {
4980 PG_FREE_IF_COPY(pgraster, 0);
4983 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not connect to the SPI manager");
4988 spi_plan = SPI_prepare(initexpr, argcount, argtype);
4990 if (spi_plan == NULL) {
4993 PG_FREE_IF_COPY(pgraster, 0);
5000 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not prepare expression");
5005 for (
x = 0;
x < width;
x++) {
5006 for(
y = 0;
y < height;
y++) {
5014 if (skipcomputation == 0) {
5015 if (initexpr != NULL) {
5017 memset(nulls,
'n', argcount);
5019 for (i = 0; i < argkwcount; i++) {
5021 if (idx < 1)
continue;
5026 values[idx] = Int32GetDatum(
x+1);
5031 values[idx] = Int32GetDatum(
y+1);
5034 else if (i == kVAL ) {
5035 values[idx] = Float8GetDatum(
r);
5041 ret = SPI_execute_plan(spi_plan, values, nulls,
FALSE, 0);
5042 if (ret != SPI_OK_SELECT || SPI_tuptable == NULL ||
5043 SPI_processed != 1) {
5045 SPI_freetuptable(tuptable);
5047 SPI_freeplan(spi_plan);
5055 PG_FREE_IF_COPY(pgraster, 0);
5058 elog(ERROR,
"RASTER_mapAlgebraExpr: Error executing prepared plan");
5063 tupdesc = SPI_tuptable->tupdesc;
5064 tuptable = SPI_tuptable;
5066 tuple = tuptable->vals[0];
5067 datum = SPI_getbinval(tuple, tupdesc, 1, &isnull);
5068 if ( SPI_result == SPI_ERROR_NOATTRIBUTE ) {
5069 POSTGIS_RT_DEBUGF(3,
"Expression for pixel %d,%d (value %g) errored, skip setting",
x+1,
y+1,
r);
5070 newval = newinitialvalue;
5072 else if ( isnull ) {
5073 POSTGIS_RT_DEBUGF(3,
"Expression for pixel %d,%d (value %g) evaluated to NULL, skip setting",
x+1,
y+1,
r);
5074 newval = newinitialvalue;
5076 newval = DatumGetFloat8(datum);
5079 SPI_freetuptable(tuptable);
5083 newval = newinitialvalue;
5096 if (initexpr != NULL) {
5097 SPI_freeplan(spi_plan);
5111 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraExpr: raster modified, serializing it.");
5115 PG_FREE_IF_COPY(pgraster, 0);
5122 SET_VARSIZE(pgrtn, pgrtn->
size);
5130 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,...)