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 the raster is only filled with nodata values return right now a raster filled with the nodatavalueexpr TODO: Call rt_band_check_isnodata instead?
Create the raster receiving all the computed values. Initialize it to the new initial value
We compute a value only for the withdata value neighborhood since the nodata value has already been set by the first optimization
5615 int x,
y,
nband, width, height, ngbwidth, ngbheight, winwidth, winheight, u, v, nIndex, nNullItems;
5617 double newnodatavalue = 0.0;
5618 double newinitialvalue = 0.0;
5619 double newval = 0.0;
5624 #if POSTGIS_PGSQL_VERSION < 120
5625 FunctionCallInfoData cbdata;
5627 LOCAL_FCINFO(cbdata, FUNC_MAX_ARGS);
5630 ArrayType * neighborDatum;
5631 char * strFromText = NULL;
5632 text * txtNodataMode = NULL;
5633 text * txtCallbackParam = NULL;
5635 float fltReplace = 0;
5636 bool valuereplace =
false, pixelreplace, nNodataOnly =
true, nNullSkip =
false;
5637 Datum * neighborData = NULL;
5638 bool * neighborNulls = NULL;
5639 int neighborDims[2];
5648 if (PG_ARGISNULL(0)) {
5649 elog(WARNING,
"Raster is NULL. Returning NULL");
5655 pgraster = (
rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
5659 PG_FREE_IF_COPY(pgraster, 0);
5660 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not deserialize raster");
5668 if (PG_ARGISNULL(1))
5671 nband = PG_GETARG_INT32(1);
5676 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraFctNgb: Creating new empty raster...");
5687 if ( NULL == newrast ) {
5689 PG_FREE_IF_COPY(pgraster, 0);
5690 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not create a new raster");
5715 elog(NOTICE,
"Raster is empty. Returning an empty raster");
5717 PG_FREE_IF_COPY(pgraster, 0);
5721 if (NULL == pgrtn) {
5722 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5726 SET_VARSIZE(pgrtn, pgrtn->
size);
5727 PG_RETURN_POINTER(pgrtn);
5737 elog(NOTICE,
"Raster does not have the required band. Returning a raster "
5740 PG_FREE_IF_COPY(pgraster, 0);
5744 if (NULL == pgrtn) {
5745 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5749 SET_VARSIZE(pgrtn, pgrtn->
size);
5750 PG_RETURN_POINTER(pgrtn);
5755 if ( NULL ==
band ) {
5756 elog(NOTICE,
"Could not get the required band. Returning a raster "
5759 PG_FREE_IF_COPY(pgraster, 0);
5763 if (NULL == pgrtn) {
5764 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5768 SET_VARSIZE(pgrtn, pgrtn->
size);
5769 PG_RETURN_POINTER(pgrtn);
5775 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraFctNgb: Getting NODATA value for band...");
5792 newinitialvalue = newnodatavalue;
5799 if (PG_ARGISNULL(2)) {
5805 POSTGIS_RT_DEBUGF(3,
"RASTER_mapAlgebraFctNgb: Pixeltype parameter: %s", strFromText);
5808 if (newpixeltype ==
PT_END)
5812 if (newpixeltype ==
PT_END) {
5815 PG_FREE_IF_COPY(pgraster, 0);
5818 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Invalid pixeltype");
5826 if (PG_ARGISNULL(5)) {
5829 PG_FREE_IF_COPY(pgraster, 0);
5832 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Required function is missing");
5836 oid = PG_GETARG_OID(5);
5837 if (oid == InvalidOid) {
5840 PG_FREE_IF_COPY(pgraster, 0);
5843 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Got invalid function object id");
5847 fmgr_info(oid, &cbinfo);
5850 if (cbinfo.fn_retset) {
5853 PG_FREE_IF_COPY(pgraster, 0);
5856 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Function provided must return double precision not resultset");
5860 else if (cbinfo.fn_nargs != 3) {
5863 PG_FREE_IF_COPY(pgraster, 0);
5866 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Function does not have three input parameters");
5870 if (func_volatile(oid) ==
'v') {
5871 elog(NOTICE,
"Function provided is VOLATILE. Unless required and for best performance, function should be IMMUTABLE or STABLE");
5875 #if POSTGIS_PGSQL_VERSION < 120
5876 InitFunctionCallInfoData(cbdata, &cbinfo, 3, InvalidOid, NULL, NULL);
5877 memset(cbdata.argnull,
FALSE,
sizeof(
bool) * 3);
5879 InitFunctionCallInfoData(*cbdata, &cbinfo, 3, InvalidOid, NULL, NULL);
5880 cbdata->args[0].isnull =
FALSE;
5881 cbdata->args[1].isnull =
FALSE;
5882 cbdata->args[2].isnull =
FALSE;
5886 if (PG_ARGISNULL(7)) {
5887 if (cbinfo.fn_strict) {
5890 PG_FREE_IF_COPY(pgraster, 0);
5893 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Strict callback functions cannot have NULL parameters");
5897 #if POSTGIS_PGSQL_VERSION < 120
5898 cbdata.arg[2] = (Datum)NULL;
5899 cbdata.argnull[2] =
TRUE;
5901 cbdata->args[2].value = (Datum)NULL;
5902 cbdata->args[2].isnull =
TRUE;
5906 #if POSTGIS_PGSQL_VERSION < 120
5907 cbdata.arg[2] = PG_GETARG_DATUM(7);
5909 cbdata->args[2].value = PG_GETARG_DATUM(7);
5920 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraFctNgb: Band is a nodata band, returning "
5921 "a raster filled with nodata");
5924 newinitialvalue,
TRUE, newnodatavalue, 0);
5927 PG_FREE_IF_COPY(pgraster, 0);
5932 if (NULL == pgrtn) {
5933 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5937 SET_VARSIZE(pgrtn, pgrtn->
size);
5938 PG_RETURN_POINTER(pgrtn);
5947 newinitialvalue,
TRUE, newnodatavalue, 0);
5951 if ( NULL == newband ) {
5952 elog(NOTICE,
"Could not modify band for new raster. Returning new "
5953 "raster with the original band");
5956 PG_FREE_IF_COPY(pgraster, 0);
5961 if (NULL == pgrtn) {
5962 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5966 SET_VARSIZE(pgrtn, pgrtn->
size);
5967 PG_RETURN_POINTER(pgrtn);
5971 if (PG_ARGISNULL(3) || PG_GETARG_INT32(3) <= 0) {
5972 elog(NOTICE,
"Neighborhood width is NULL or <= 0. Returning new "
5973 "raster with the original band");
5976 PG_FREE_IF_COPY(pgraster, 0);
5981 if (NULL == pgrtn) {
5982 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5986 SET_VARSIZE(pgrtn, pgrtn->
size);
5987 PG_RETURN_POINTER(pgrtn);
5990 ngbwidth = PG_GETARG_INT32(3);
5991 winwidth = ngbwidth * 2 + 1;
5994 if (PG_ARGISNULL(4) || PG_GETARG_INT32(4) <= 0) {
5995 elog(NOTICE,
"Neighborhood height is NULL or <= 0. Returning new "
5996 "raster with the original band");
5999 PG_FREE_IF_COPY(pgraster, 0);
6004 if (NULL == pgrtn) {
6005 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
6009 SET_VARSIZE(pgrtn, pgrtn->
size);
6010 PG_RETURN_POINTER(pgrtn);
6013 ngbheight = PG_GETARG_INT32(4);
6014 winheight = ngbheight * 2 + 1;
6017 if (PG_ARGISNULL(6)) {
6018 elog(NOTICE,
"Neighborhood NODATA behavior defaulting to 'ignore'");
6019 txtNodataMode = cstring_to_text(
"ignore");
6022 txtNodataMode = PG_GETARG_TEXT_P(6);
6025 txtCallbackParam = (text*)palloc(VARSIZE(txtNodataMode));
6026 SET_VARSIZE(txtCallbackParam, VARSIZE(txtNodataMode));
6027 memcpy((
void *)VARDATA(txtCallbackParam), (
void *)VARDATA(txtNodataMode), VARSIZE(txtNodataMode) - VARHDRSZ);
6030 #if POSTGIS_PGSQL_VERSION < 120
6031 cbdata.arg[1] = CStringGetDatum(txtCallbackParam);
6033 cbdata->args[1].value = CStringGetDatum(txtCallbackParam);
6039 if (strcmp(strFromText,
"VALUE") == 0)
6040 valuereplace =
true;
6041 else if (strcmp(strFromText,
"IGNORE") != 0 && strcmp(strFromText,
"NULL") != 0) {
6043 if (sscanf(strFromText,
"%d", &intReplace) <= 0 && sscanf(strFromText,
"%f", &fltReplace) <= 0) {
6045 elog(NOTICE,
"Neighborhood NODATA mode is not recognized. Must be one of 'value', 'ignore', "
6046 "'NULL', or a numeric value. Returning new raster with the original band");
6049 pfree(txtCallbackParam);
6053 PG_FREE_IF_COPY(pgraster, 0);
6058 if (NULL == pgrtn) {
6059 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
6063 SET_VARSIZE(pgrtn, pgrtn->
size);
6064 PG_RETURN_POINTER(pgrtn);
6067 else if (strcmp(strFromText,
"NULL") == 0) {
6076 neighborData = (Datum *)palloc(winwidth * winheight *
sizeof(Datum));
6077 neighborNulls = (
bool *)palloc(winwidth * winheight *
sizeof(
bool));
6080 neighborDims[0] = winwidth;
6081 neighborDims[1] = winheight;
6088 get_typlenbyvalalign(FLOAT8OID, &typlen, &typbyval, &typalign);
6090 for (
x = 0 + ngbwidth;
x < width - ngbwidth;
x++) {
6091 for(
y = 0 + ngbheight;
y < height - ngbheight;
y++) {
6096 pixelreplace =
false;
6100 pixelreplace =
true;
6103 for (u =
x - ngbwidth; u <=
x + ngbwidth; u++) {
6104 for (v =
y - ngbheight; v <=
y + ngbheight; v++) {
6109 neighborData[nIndex] = Float8GetDatum((
double)
r);
6110 neighborNulls[nIndex] =
false;
6111 nNodataOnly =
false;
6115 if (valuereplace && pixelreplace) {
6117 neighborData[nIndex] = Float8GetDatum((
double)rpix);
6118 neighborNulls[nIndex] =
false;
6123 neighborData[nIndex] = PointerGetDatum(NULL);
6124 neighborNulls[nIndex] =
true;
6131 neighborData[nIndex] = PointerGetDatum(NULL);
6132 neighborNulls[nIndex] =
true;
6144 if (!(nNodataOnly ||
6145 (nNullSkip && nNullItems > 0) ||
6146 (valuereplace && nNullItems > 0))) {
6148 x,
y, winwidth, winheight);
6150 neighborDatum = construct_md_array((
void *)neighborData, neighborNulls, 2, neighborDims, neighborLbs,
6151 FLOAT8OID, typlen, typbyval, typalign);
6153 #if POSTGIS_PGSQL_VERSION < 120
6155 cbdata.arg[0] = PointerGetDatum(neighborDatum);
6158 tmpnewval = FunctionCallInvoke(&cbdata);
6161 if (cbdata.isnull) {
6162 newval = newnodatavalue;
6166 cbdata->args[0].value = PointerGetDatum(neighborDatum);
6169 tmpnewval = FunctionCallInvoke(cbdata);
6174 newval = newnodatavalue;
6178 newval = DatumGetFloat8(tmpnewval);
6194 pfree(neighborNulls);
6195 pfree(neighborData);
6197 pfree(txtCallbackParam);
6200 PG_FREE_IF_COPY(pgraster, 0);
6204 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraFctNgb: raster modified, serializing it.");
6215 SET_VARSIZE(pgrtn, pgrtn->
size);
6216 PG_RETURN_POINTER(pgrtn);
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_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)
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_strtoupper(char *str)
#define POSTGIS_RT_DEBUG(level, msg)
#define POSTGIS_RT_DEBUGF(level, msg,...)