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
5614 int x,
y,
nband, width, height, ngbwidth, ngbheight, winwidth, winheight, u, v, nIndex, nNullItems;
5616 double newnodatavalue = 0.0;
5617 double newinitialvalue = 0.0;
5618 double newval = 0.0;
5623 #if POSTGIS_PGSQL_VERSION < 120
5624 FunctionCallInfoData cbdata;
5626 LOCAL_FCINFO(cbdata, FUNC_MAX_ARGS);
5629 ArrayType * neighborDatum;
5630 char * strFromText = NULL;
5631 text * txtNodataMode = NULL;
5632 text * txtCallbackParam = NULL;
5634 float fltReplace = 0;
5635 bool valuereplace =
false, pixelreplace, nNodataOnly =
true, nNullSkip =
false;
5636 Datum * neighborData = NULL;
5637 bool * neighborNulls = NULL;
5638 int neighborDims[2];
5647 if (PG_ARGISNULL(0)) {
5648 elog(WARNING,
"Raster is NULL. Returning NULL");
5654 pgraster = (
rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
5658 PG_FREE_IF_COPY(pgraster, 0);
5659 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not deserialize raster");
5667 if (PG_ARGISNULL(1))
5670 nband = PG_GETARG_INT32(1);
5675 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraFctNgb: Creating new empty raster...");
5686 if ( NULL == newrast ) {
5688 PG_FREE_IF_COPY(pgraster, 0);
5689 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not create a new raster");
5714 elog(NOTICE,
"Raster is empty. Returning an empty raster");
5716 PG_FREE_IF_COPY(pgraster, 0);
5720 if (NULL == pgrtn) {
5721 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5725 SET_VARSIZE(pgrtn, pgrtn->
size);
5726 PG_RETURN_POINTER(pgrtn);
5736 elog(NOTICE,
"Raster does not have the required band. Returning a raster "
5739 PG_FREE_IF_COPY(pgraster, 0);
5743 if (NULL == pgrtn) {
5744 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5748 SET_VARSIZE(pgrtn, pgrtn->
size);
5749 PG_RETURN_POINTER(pgrtn);
5754 if ( NULL ==
band ) {
5755 elog(NOTICE,
"Could not get the required band. Returning a raster "
5758 PG_FREE_IF_COPY(pgraster, 0);
5762 if (NULL == pgrtn) {
5763 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5767 SET_VARSIZE(pgrtn, pgrtn->
size);
5768 PG_RETURN_POINTER(pgrtn);
5774 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraFctNgb: Getting NODATA value for band...");
5791 newinitialvalue = newnodatavalue;
5798 if (PG_ARGISNULL(2)) {
5804 POSTGIS_RT_DEBUGF(3,
"RASTER_mapAlgebraFctNgb: Pixeltype parameter: %s", strFromText);
5807 if (newpixeltype ==
PT_END)
5811 if (newpixeltype ==
PT_END) {
5814 PG_FREE_IF_COPY(pgraster, 0);
5817 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Invalid pixeltype");
5825 if (PG_ARGISNULL(5)) {
5828 PG_FREE_IF_COPY(pgraster, 0);
5831 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Required function is missing");
5835 oid = PG_GETARG_OID(5);
5836 if (oid == InvalidOid) {
5839 PG_FREE_IF_COPY(pgraster, 0);
5842 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Got invalid function object id");
5846 fmgr_info(oid, &cbinfo);
5849 if (cbinfo.fn_retset) {
5852 PG_FREE_IF_COPY(pgraster, 0);
5855 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Function provided must return double precision not resultset");
5859 else if (cbinfo.fn_nargs != 3) {
5862 PG_FREE_IF_COPY(pgraster, 0);
5865 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Function does not have three input parameters");
5869 if (func_volatile(oid) ==
'v') {
5870 elog(NOTICE,
"Function provided is VOLATILE. Unless required and for best performance, function should be IMMUTABLE or STABLE");
5874 #if POSTGIS_PGSQL_VERSION < 120
5875 InitFunctionCallInfoData(cbdata, &cbinfo, 3, InvalidOid, NULL, NULL);
5876 memset(cbdata.argnull,
FALSE,
sizeof(
bool) * 3);
5878 InitFunctionCallInfoData(*cbdata, &cbinfo, 3, InvalidOid, NULL, NULL);
5879 cbdata->args[0].isnull =
FALSE;
5880 cbdata->args[1].isnull =
FALSE;
5881 cbdata->args[2].isnull =
FALSE;
5885 if (PG_ARGISNULL(7)) {
5886 if (cbinfo.fn_strict) {
5889 PG_FREE_IF_COPY(pgraster, 0);
5892 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Strict callback functions cannot have NULL parameters");
5896 #if POSTGIS_PGSQL_VERSION < 120
5897 cbdata.arg[2] = (Datum)NULL;
5898 cbdata.argnull[2] =
TRUE;
5900 cbdata->args[2].value = (Datum)NULL;
5901 cbdata->args[2].isnull =
TRUE;
5905 #if POSTGIS_PGSQL_VERSION < 120
5906 cbdata.arg[2] = PG_GETARG_DATUM(7);
5908 cbdata->args[2].value = PG_GETARG_DATUM(7);
5919 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraFctNgb: Band is a nodata band, returning "
5920 "a raster filled with nodata");
5923 newinitialvalue,
TRUE, newnodatavalue, 0);
5926 PG_FREE_IF_COPY(pgraster, 0);
5931 if (NULL == pgrtn) {
5932 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5936 SET_VARSIZE(pgrtn, pgrtn->
size);
5937 PG_RETURN_POINTER(pgrtn);
5946 newinitialvalue,
TRUE, newnodatavalue, 0);
5950 if ( NULL == newband ) {
5951 elog(NOTICE,
"Could not modify band for new raster. Returning new "
5952 "raster with the original band");
5955 PG_FREE_IF_COPY(pgraster, 0);
5960 if (NULL == pgrtn) {
5961 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5965 SET_VARSIZE(pgrtn, pgrtn->
size);
5966 PG_RETURN_POINTER(pgrtn);
5970 if (PG_ARGISNULL(3) || PG_GETARG_INT32(3) <= 0) {
5971 elog(NOTICE,
"Neighborhood width is NULL or <= 0. Returning new "
5972 "raster with the original band");
5975 PG_FREE_IF_COPY(pgraster, 0);
5980 if (NULL == pgrtn) {
5981 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5985 SET_VARSIZE(pgrtn, pgrtn->
size);
5986 PG_RETURN_POINTER(pgrtn);
5989 ngbwidth = PG_GETARG_INT32(3);
5990 winwidth = ngbwidth * 2 + 1;
5993 if (PG_ARGISNULL(4) || PG_GETARG_INT32(4) <= 0) {
5994 elog(NOTICE,
"Neighborhood height is NULL or <= 0. Returning new "
5995 "raster with the original band");
5998 PG_FREE_IF_COPY(pgraster, 0);
6003 if (NULL == pgrtn) {
6004 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
6008 SET_VARSIZE(pgrtn, pgrtn->
size);
6009 PG_RETURN_POINTER(pgrtn);
6012 ngbheight = PG_GETARG_INT32(4);
6013 winheight = ngbheight * 2 + 1;
6016 if (PG_ARGISNULL(6)) {
6017 elog(NOTICE,
"Neighborhood NODATA behavior defaulting to 'ignore'");
6018 txtNodataMode = cstring_to_text(
"ignore");
6021 txtNodataMode = PG_GETARG_TEXT_P(6);
6024 txtCallbackParam = (text*)palloc(VARSIZE(txtNodataMode));
6025 SET_VARSIZE(txtCallbackParam, VARSIZE(txtNodataMode));
6026 memcpy((
void *)VARDATA(txtCallbackParam), (
void *)VARDATA(txtNodataMode), VARSIZE(txtNodataMode) - VARHDRSZ);
6029 #if POSTGIS_PGSQL_VERSION < 120
6030 cbdata.arg[1] = CStringGetDatum(txtCallbackParam);
6032 cbdata->args[1].value = CStringGetDatum(txtCallbackParam);
6038 if (strcmp(strFromText,
"VALUE") == 0)
6039 valuereplace =
true;
6040 else if (strcmp(strFromText,
"IGNORE") != 0 && strcmp(strFromText,
"NULL") != 0) {
6042 if (sscanf(strFromText,
"%d", &intReplace) <= 0 && sscanf(strFromText,
"%f", &fltReplace) <= 0) {
6044 elog(NOTICE,
"Neighborhood NODATA mode is not recognized. Must be one of 'value', 'ignore', "
6045 "'NULL', or a numeric value. Returning new raster with the original band");
6048 pfree(txtCallbackParam);
6052 PG_FREE_IF_COPY(pgraster, 0);
6057 if (NULL == pgrtn) {
6058 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
6062 SET_VARSIZE(pgrtn, pgrtn->
size);
6063 PG_RETURN_POINTER(pgrtn);
6066 else if (strcmp(strFromText,
"NULL") == 0) {
6075 neighborData = (Datum *)palloc(winwidth * winheight *
sizeof(Datum));
6076 neighborNulls = (
bool *)palloc(winwidth * winheight *
sizeof(
bool));
6079 neighborDims[0] = winwidth;
6080 neighborDims[1] = winheight;
6087 get_typlenbyvalalign(FLOAT8OID, &typlen, &typbyval, &typalign);
6089 for (
x = 0 + ngbwidth;
x < width - ngbwidth;
x++) {
6090 for(
y = 0 + ngbheight;
y < height - ngbheight;
y++) {
6095 pixelreplace =
false;
6099 pixelreplace =
true;
6102 for (u =
x - ngbwidth; u <=
x + ngbwidth; u++) {
6103 for (v =
y - ngbheight; v <=
y + ngbheight; v++) {
6108 neighborData[nIndex] = Float8GetDatum((
double)
r);
6109 neighborNulls[nIndex] =
false;
6110 nNodataOnly =
false;
6114 if (valuereplace && pixelreplace) {
6116 neighborData[nIndex] = Float8GetDatum((
double)rpix);
6117 neighborNulls[nIndex] =
false;
6122 neighborData[nIndex] = PointerGetDatum(NULL);
6123 neighborNulls[nIndex] =
true;
6130 neighborData[nIndex] = PointerGetDatum(NULL);
6131 neighborNulls[nIndex] =
true;
6143 if (!(nNodataOnly ||
6144 (nNullSkip && nNullItems > 0) ||
6145 (valuereplace && nNullItems > 0))) {
6147 x,
y, winwidth, winheight);
6149 neighborDatum = construct_md_array((
void *)neighborData, neighborNulls, 2, neighborDims, neighborLbs,
6150 FLOAT8OID, typlen, typbyval, typalign);
6152 #if POSTGIS_PGSQL_VERSION < 120
6154 cbdata.arg[0] = PointerGetDatum(neighborDatum);
6157 tmpnewval = FunctionCallInvoke(&cbdata);
6160 if (cbdata.isnull) {
6161 newval = newnodatavalue;
6165 cbdata->args[0].value = PointerGetDatum(neighborDatum);
6168 tmpnewval = FunctionCallInvoke(cbdata);
6173 newval = newnodatavalue;
6177 newval = DatumGetFloat8(tmpnewval);
6193 pfree(neighborNulls);
6194 pfree(neighborData);
6196 pfree(txtCallbackParam);
6199 PG_FREE_IF_COPY(pgraster, 0);
6203 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraFctNgb: raster modified, serializing it.");
6214 SET_VARSIZE(pgrtn, pgrtn->
size);
6215 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,...)