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
5674 int x,
y,
nband, width, height, ngbwidth, ngbheight, winwidth, winheight, u, v, nIndex, nNullItems;
5676 double newnodatavalue = 0.0;
5677 double newinitialvalue = 0.0;
5678 double newval = 0.0;
5683 LOCAL_FCINFO(cbdata, FUNC_MAX_ARGS);
5685 ArrayType * neighborDatum;
5686 char * strFromText = NULL;
5687 text * txtNodataMode = NULL;
5688 text * txtCallbackParam = NULL;
5690 float fltReplace = 0;
5691 bool valuereplace =
false, pixelreplace, nNodataOnly =
true, nNullSkip =
false;
5692 Datum * neighborData = NULL;
5693 bool * neighborNulls = NULL;
5694 int neighborDims[2];
5703 if (PG_ARGISNULL(0)) {
5704 elog(WARNING,
"Raster is NULL. Returning NULL");
5710 pgraster = (
rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
5714 PG_FREE_IF_COPY(pgraster, 0);
5715 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not deserialize raster");
5723 if (PG_ARGISNULL(1))
5726 nband = PG_GETARG_INT32(1);
5731 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraFctNgb: Creating new empty raster...");
5742 if ( NULL == newrast ) {
5744 PG_FREE_IF_COPY(pgraster, 0);
5745 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not create a new raster");
5770 elog(NOTICE,
"Raster is empty. Returning an empty raster");
5772 PG_FREE_IF_COPY(pgraster, 0);
5776 if (NULL == pgrtn) {
5777 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5781 SET_VARSIZE(pgrtn, pgrtn->
size);
5782 PG_RETURN_POINTER(pgrtn);
5792 elog(NOTICE,
"Raster does not have the required band. Returning a raster "
5795 PG_FREE_IF_COPY(pgraster, 0);
5799 if (NULL == pgrtn) {
5800 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5804 SET_VARSIZE(pgrtn, pgrtn->
size);
5805 PG_RETURN_POINTER(pgrtn);
5810 if ( NULL ==
band ) {
5811 elog(NOTICE,
"Could not get the required band. Returning a raster "
5814 PG_FREE_IF_COPY(pgraster, 0);
5818 if (NULL == pgrtn) {
5819 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5823 SET_VARSIZE(pgrtn, pgrtn->
size);
5824 PG_RETURN_POINTER(pgrtn);
5830 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraFctNgb: Getting NODATA value for band...");
5847 newinitialvalue = newnodatavalue;
5854 if (PG_ARGISNULL(2)) {
5859 strFromText = text_to_cstring(PG_GETARG_TEXT_P(2));
5860 POSTGIS_RT_DEBUGF(3,
"RASTER_mapAlgebraFctNgb: Pixeltype parameter: %s", strFromText);
5863 if (newpixeltype ==
PT_END)
5867 if (newpixeltype ==
PT_END) {
5870 PG_FREE_IF_COPY(pgraster, 0);
5873 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Invalid pixeltype");
5881 if (PG_ARGISNULL(5)) {
5884 PG_FREE_IF_COPY(pgraster, 0);
5887 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Required function is missing");
5891 oid = PG_GETARG_OID(5);
5892 if (oid == InvalidOid) {
5895 PG_FREE_IF_COPY(pgraster, 0);
5898 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Got invalid function object id");
5902 fmgr_info(oid, &cbinfo);
5905 if (cbinfo.fn_retset) {
5908 PG_FREE_IF_COPY(pgraster, 0);
5911 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Function provided must return double precision not resultset");
5915 else if (cbinfo.fn_nargs != 3) {
5918 PG_FREE_IF_COPY(pgraster, 0);
5921 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Function does not have three input parameters");
5925 if (func_volatile(oid) ==
'v') {
5926 elog(NOTICE,
"Function provided is VOLATILE. Unless required and for best performance, function should be IMMUTABLE or STABLE");
5930 InitFunctionCallInfoData(*cbdata, &cbinfo, 3, InvalidOid, NULL, NULL);
5931 cbdata->args[0].isnull =
FALSE;
5932 cbdata->args[1].isnull =
FALSE;
5933 cbdata->args[2].isnull =
FALSE;
5936 if (PG_ARGISNULL(7)) {
5937 if (cbinfo.fn_strict) {
5940 PG_FREE_IF_COPY(pgraster, 0);
5943 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Strict callback functions cannot have NULL parameters");
5947 cbdata->args[2].value = (Datum)NULL;
5948 cbdata->args[2].isnull =
TRUE;
5951 cbdata->args[2].value = PG_GETARG_DATUM(7);
5961 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraFctNgb: Band is a nodata band, returning "
5962 "a raster filled with nodata");
5965 newinitialvalue,
TRUE, newnodatavalue, 0);
5968 PG_FREE_IF_COPY(pgraster, 0);
5973 if (NULL == pgrtn) {
5974 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5978 SET_VARSIZE(pgrtn, pgrtn->
size);
5979 PG_RETURN_POINTER(pgrtn);
5988 newinitialvalue,
TRUE, newnodatavalue, 0);
5992 if ( NULL == newband ) {
5993 elog(NOTICE,
"Could not modify band for new raster. Returning new "
5994 "raster with the original band");
5997 PG_FREE_IF_COPY(pgraster, 0);
6002 if (NULL == pgrtn) {
6003 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
6007 SET_VARSIZE(pgrtn, pgrtn->
size);
6008 PG_RETURN_POINTER(pgrtn);
6012 if (PG_ARGISNULL(3) || PG_GETARG_INT32(3) <= 0) {
6013 elog(NOTICE,
"Neighborhood width is NULL or <= 0. Returning new "
6014 "raster with the original band");
6017 PG_FREE_IF_COPY(pgraster, 0);
6022 if (NULL == pgrtn) {
6023 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
6027 SET_VARSIZE(pgrtn, pgrtn->
size);
6028 PG_RETURN_POINTER(pgrtn);
6031 ngbwidth = PG_GETARG_INT32(3);
6032 winwidth = ngbwidth * 2 + 1;
6035 if (PG_ARGISNULL(4) || PG_GETARG_INT32(4) <= 0) {
6036 elog(NOTICE,
"Neighborhood height is NULL or <= 0. Returning new "
6037 "raster with the original band");
6040 PG_FREE_IF_COPY(pgraster, 0);
6045 if (NULL == pgrtn) {
6046 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
6050 SET_VARSIZE(pgrtn, pgrtn->
size);
6051 PG_RETURN_POINTER(pgrtn);
6054 ngbheight = PG_GETARG_INT32(4);
6055 winheight = ngbheight * 2 + 1;
6058 if (PG_ARGISNULL(6)) {
6059 elog(NOTICE,
"Neighborhood NODATA behavior defaulting to 'ignore'");
6060 txtNodataMode = cstring_to_text(
"ignore");
6063 txtNodataMode = PG_GETARG_TEXT_P(6);
6066 txtCallbackParam = (text*)palloc(VARSIZE(txtNodataMode));
6067 SET_VARSIZE(txtCallbackParam, VARSIZE(txtNodataMode));
6068 memcpy((
void *)VARDATA(txtCallbackParam), (
void *)VARDATA(txtNodataMode), VARSIZE(txtNodataMode) - VARHDRSZ);
6071 cbdata->args[1].value = PointerGetDatum(txtCallbackParam);
6073 strFromText = text_to_cstring(txtNodataMode);
6076 if (strcmp(strFromText,
"VALUE") == 0)
6077 valuereplace =
true;
6078 else if (strcmp(strFromText,
"IGNORE") != 0 && strcmp(strFromText,
"NULL") != 0) {
6080 if (sscanf(strFromText,
"%d", &intReplace) <= 0 && sscanf(strFromText,
"%f", &fltReplace) <= 0) {
6082 elog(NOTICE,
"Neighborhood NODATA mode is not recognized. Must be one of 'value', 'ignore', "
6083 "'NULL', or a numeric value. Returning new raster with the original band");
6086 pfree(txtCallbackParam);
6090 PG_FREE_IF_COPY(pgraster, 0);
6095 if (NULL == pgrtn) {
6096 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
6100 SET_VARSIZE(pgrtn, pgrtn->
size);
6101 PG_RETURN_POINTER(pgrtn);
6104 else if (strcmp(strFromText,
"NULL") == 0) {
6113 neighborData = (Datum *)palloc(
sizeof(Datum) * winwidth * winheight);
6114 neighborNulls = (
bool *)palloc(
sizeof(
bool) * winwidth * winheight);
6117 neighborDims[0] = winwidth;
6118 neighborDims[1] = winheight;
6125 get_typlenbyvalalign(FLOAT8OID, &typlen, &typbyval, &typalign);
6127 for (
x = 0 + ngbwidth;
x < width - ngbwidth;
x++) {
6128 for(
y = 0 + ngbheight;
y < height - ngbheight;
y++) {
6133 pixelreplace =
false;
6137 pixelreplace =
true;
6140 for (u =
x - ngbwidth; u <=
x + ngbwidth; u++) {
6141 for (v =
y - ngbheight; v <=
y + ngbheight; v++) {
6146 neighborData[nIndex] = Float8GetDatum((
double)
r);
6147 neighborNulls[nIndex] =
false;
6148 nNodataOnly =
false;
6152 if (valuereplace && pixelreplace) {
6154 neighborData[nIndex] = Float8GetDatum((
double)rpix);
6155 neighborNulls[nIndex] =
false;
6160 neighborData[nIndex] = PointerGetDatum(NULL);
6161 neighborNulls[nIndex] =
true;
6168 neighborData[nIndex] = PointerGetDatum(NULL);
6169 neighborNulls[nIndex] =
true;
6181 if (!(nNodataOnly ||
6182 (nNullSkip && nNullItems > 0) ||
6183 (valuereplace && nNullItems > 0))) {
6185 x,
y, winwidth, winheight);
6187 neighborDatum = construct_md_array((
void *)neighborData, neighborNulls, 2, neighborDims, neighborLbs,
6188 FLOAT8OID, typlen, typbyval, typalign);
6191 cbdata->args[0].value = PointerGetDatum(neighborDatum);
6194 tmpnewval = FunctionCallInvoke(cbdata);
6199 newval = newnodatavalue;
6202 newval = DatumGetFloat8(tmpnewval);
6218 pfree(neighborNulls);
6219 pfree(neighborData);
6221 pfree(txtCallbackParam);
6224 PG_FREE_IF_COPY(pgraster, 0);
6228 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraFctNgb: raster modified, serializing it.");
6239 SET_VARSIZE(pgrtn, pgrtn->
size);
6240 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 * rtpg_strtoupper(char *str)
#define POSTGIS_RT_DEBUG(level, msg)
#define POSTGIS_RT_DEBUGF(level, msg,...)