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
4467 int x,
y,
nband, width, height;
4469 double newnodatavalue = 0.0;
4470 double newinitialvalue = 0.0;
4471 double newval = 0.0;
4472 char *newexpr = NULL;
4473 char *initexpr = NULL;
4474 char *expression = NULL;
4475 int hasnodataval = 0;
4476 double nodataval = 0.;
4478 int skipcomputation = 0;
4480 const int argkwcount = 3;
4481 enum KEYWORDS { kVAL=0, kX=1, kY=2 };
4482 char *argkw[] = {
"[rast]",
"[rast.x]",
"[rast.y]"};
4483 Oid argkwtypes[] = { FLOAT8OID, INT4OID, INT4OID };
4485 Oid argtype[] = { FLOAT8OID, INT4OID, INT4OID };
4486 uint8_t argpos[3] = {0};
4491 SPIPlanPtr spi_plan = NULL;
4492 SPITupleTable * tuptable = NULL;
4494 char * strFromText = NULL;
4495 Datum *values = NULL;
4496 Datum datum = (Datum)NULL;
4498 bool isnull =
FALSE;
4505 if (PG_ARGISNULL(0)) {
4506 elog(NOTICE,
"Raster is NULL. Returning NULL");
4512 pgraster = (
rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
4515 PG_FREE_IF_COPY(pgraster, 0);
4516 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not deserialize raster");
4522 if (PG_ARGISNULL(1))
4525 nband = PG_GETARG_INT32(1);
4531 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraExpr: Creating new empty raster...");
4542 if ( NULL == newrast ) {
4543 PG_FREE_IF_COPY(pgraster, 0);
4544 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not create a new raster");
4569 elog(NOTICE,
"Raster is empty. Returning an empty raster");
4571 PG_FREE_IF_COPY(pgraster, 0);
4575 if (NULL == pgrtn) {
4577 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4581 SET_VARSIZE(pgrtn, pgrtn->
size);
4582 PG_RETURN_POINTER(pgrtn);
4593 elog(NOTICE,
"Raster does not have the required band. Returning a raster "
4596 PG_FREE_IF_COPY(pgraster, 0);
4600 if (NULL == pgrtn) {
4601 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4605 SET_VARSIZE(pgrtn, pgrtn->
size);
4606 PG_RETURN_POINTER(pgrtn);
4611 if ( NULL ==
band ) {
4612 elog(NOTICE,
"Could not get the required band. Returning a raster "
4615 PG_FREE_IF_COPY(pgraster, 0);
4619 if (NULL == pgrtn) {
4620 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4624 SET_VARSIZE(pgrtn, pgrtn->
size);
4625 PG_RETURN_POINTER(pgrtn);
4631 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraExpr: Getting NODATA value for band...");
4649 newinitialvalue = newnodatavalue;
4656 if (PG_ARGISNULL(2)) {
4661 strFromText = text_to_cstring(PG_GETARG_TEXT_P(2));
4664 if (newpixeltype ==
PT_END)
4668 if (newpixeltype ==
PT_END) {
4669 PG_FREE_IF_COPY(pgraster, 0);
4670 elog(ERROR,
"RASTER_mapAlgebraExpr: Invalid pixeltype");
4679 if (!PG_ARGISNULL(3)) {
4680 expression = text_to_cstring(PG_GETARG_TEXT_P(3));
4681 len = strlen(
"SELECT (") + strlen(expression) + strlen(
")::double precision");
4682 initexpr = (
char *)palloc(len + 1);
4684 memcpy(initexpr,
"SELECT (", strlen(
"SELECT ("));
4685 memcpy(initexpr + strlen(
"SELECT ("), expression, strlen(expression));
4686 memcpy(initexpr + strlen(
"SELECT (") + strlen(expression),
")::double precision", strlen(
")::double precision"));
4687 initexpr[len] =
'\0';
4705 if (!PG_ARGISNULL(4)) {
4707 nodataval = PG_GETARG_FLOAT8(4);
4708 newinitialvalue = nodataval;
4725 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraExpr: Band is a nodata band, returning "
4726 "a raster filled with nodata");
4729 newinitialvalue,
TRUE, newnodatavalue, 0);
4735 PG_FREE_IF_COPY(pgraster, 0);
4740 if (NULL == pgrtn) {
4741 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4745 SET_VARSIZE(pgrtn, pgrtn->
size);
4746 PG_RETURN_POINTER(pgrtn);
4754 if (initexpr != NULL && ( !strcmp(initexpr,
"SELECT [rast]") || !strcmp(initexpr,
"SELECT [rast.val]") ) && !hasnodataval) {
4757 "Returning raster with band %d from original raster",
nband);
4769 PG_FREE_IF_COPY(pgraster, 0);
4774 if (NULL == pgrtn) {
4775 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4779 SET_VARSIZE(pgrtn, pgrtn->
size);
4780 PG_RETURN_POINTER(pgrtn);
4787 if (initexpr != NULL && strstr(initexpr,
"[rast") == NULL) {
4788 ret = SPI_connect();
4789 if (ret != SPI_OK_CONNECT) {
4790 PG_FREE_IF_COPY(pgraster, 0);
4791 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not connect to the SPI manager");
4796 ret = SPI_execute(initexpr,
FALSE, 0);
4798 if (ret != SPI_OK_SELECT || SPI_tuptable == NULL || SPI_processed != 1) {
4802 SPI_freetuptable(tuptable);
4803 PG_FREE_IF_COPY(pgraster, 0);
4806 elog(ERROR,
"RASTER_mapAlgebraExpr: Invalid construction for expression");
4810 tupdesc = SPI_tuptable->tupdesc;
4811 tuptable = SPI_tuptable;
4813 tuple = tuptable->vals[0];
4814 newexpr = SPI_getvalue(tuple, tupdesc, 1);
4816 POSTGIS_RT_DEBUG(3,
"Constant expression evaluated to NULL, keeping initvalue");
4817 newval = newinitialvalue;
4819 newval = atof(newexpr);
4822 SPI_freetuptable(tuptable);
4829 skipcomputation = 1;
4835 if (!hasnodataval) {
4836 newinitialvalue = newval;
4837 skipcomputation = 2;
4841 else if (
FLT_NEQ(newval, newinitialvalue)) {
4842 skipcomputation = 2;
4851 newinitialvalue,
TRUE, newnodatavalue, 0);
4858 if (expression == NULL || skipcomputation == 2) {
4864 PG_FREE_IF_COPY(pgraster, 0);
4869 if (NULL == pgrtn) {
4870 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4874 SET_VARSIZE(pgrtn, pgrtn->
size);
4875 PG_RETURN_POINTER(pgrtn);
4878 RASTER_DEBUG(3,
"RASTER_mapAlgebraExpr: Creating new raster band...");
4882 if ( NULL == newband ) {
4883 elog(NOTICE,
"Could not modify band for new raster. Returning new "
4884 "raster with the original band");
4889 PG_FREE_IF_COPY(pgraster, 0);
4894 if (NULL == pgrtn) {
4895 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not serialize raster");
4899 SET_VARSIZE(pgrtn, pgrtn->
size);
4900 PG_RETURN_POINTER(pgrtn);
4906 if (initexpr != NULL) {
4909 pfree(initexpr); initexpr=newexpr;
4911 sprintf(place,
"$1");
4912 for (i = 0, j = 1; i < argkwcount; i++) {
4915 pfree(initexpr); initexpr=newexpr;
4917 argtype[argcount] = argkwtypes[i];
4921 sprintf(place,
"$%d", j);
4931 values = (Datum *) palloc(
sizeof(Datum) * argcount);
4932 if (values == NULL) {
4937 PG_FREE_IF_COPY(pgraster, 0);
4940 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not allocate memory for value parameters of prepared statement");
4945 nulls = (
char *)palloc(argcount);
4946 if (nulls == NULL) {
4951 PG_FREE_IF_COPY(pgraster, 0);
4954 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not allocate memory for null parameters of prepared statement");
4959 ret = SPI_connect();
4960 if (ret != SPI_OK_CONNECT) {
4965 PG_FREE_IF_COPY(pgraster, 0);
4968 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not connect to the SPI manager");
4973 spi_plan = SPI_prepare(initexpr, argcount, argtype);
4975 if (spi_plan == NULL) {
4978 PG_FREE_IF_COPY(pgraster, 0);
4985 elog(ERROR,
"RASTER_mapAlgebraExpr: Could not prepare expression");
4990 for (
x = 0;
x < width;
x++) {
4991 for(
y = 0;
y < height;
y++) {
4999 if (skipcomputation == 0) {
5000 if (initexpr != NULL) {
5002 memset(nulls,
'n', argcount);
5004 for (i = 0; i < argkwcount; i++) {
5006 if (idx < 1)
continue;
5011 values[idx] = Int32GetDatum(
x+1);
5016 values[idx] = Int32GetDatum(
y+1);
5019 else if (i == kVAL ) {
5020 values[idx] = Float8GetDatum(
r);
5026 ret = SPI_execute_plan(spi_plan, values, nulls,
FALSE, 0);
5027 if (ret != SPI_OK_SELECT || SPI_tuptable == NULL ||
5028 SPI_processed != 1) {
5030 SPI_freetuptable(tuptable);
5032 SPI_freeplan(spi_plan);
5040 PG_FREE_IF_COPY(pgraster, 0);
5043 elog(ERROR,
"RASTER_mapAlgebraExpr: Error executing prepared plan");
5048 tupdesc = SPI_tuptable->tupdesc;
5049 tuptable = SPI_tuptable;
5051 tuple = tuptable->vals[0];
5052 datum = SPI_getbinval(tuple, tupdesc, 1, &isnull);
5053 if ( SPI_result == SPI_ERROR_NOATTRIBUTE ) {
5054 POSTGIS_RT_DEBUGF(3,
"Expression for pixel %d,%d (value %g) errored, skip setting",
x+1,
y+1,
r);
5055 newval = newinitialvalue;
5057 else if ( isnull ) {
5058 POSTGIS_RT_DEBUGF(3,
"Expression for pixel %d,%d (value %g) evaluated to NULL, skip setting",
x+1,
y+1,
r);
5059 newval = newinitialvalue;
5061 newval = DatumGetFloat8(datum);
5064 SPI_freetuptable(tuptable);
5068 newval = newinitialvalue;
5081 if (initexpr != NULL) {
5082 SPI_freeplan(spi_plan);
5096 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraExpr: raster modified, serializing it.");
5100 PG_FREE_IF_COPY(pgraster, 0);
5107 SET_VARSIZE(pgrtn, pgrtn->
size);
5115 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,...)