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
5603 int x,
y,
nband,
width,
height, ngbwidth, ngbheight, winwidth, winheight, u, v, nIndex, nNullItems;
5605 double newnodatavalue = 0.0;
5606 double newinitialvalue = 0.0;
5607 double newval = 0.0;
5612 #if POSTGIS_PGSQL_VERSION < 120 5613 FunctionCallInfoData cbdata;
5615 LOCAL_FCINFO(cbdata, FUNC_MAX_ARGS);
5618 ArrayType * neighborDatum;
5619 char * strFromText = NULL;
5620 text * txtNodataMode = NULL;
5621 text * txtCallbackParam = NULL;
5623 float fltReplace = 0;
5624 bool valuereplace =
false, pixelreplace, nNodataOnly =
true, nNullSkip =
false;
5625 Datum * neighborData = NULL;
5626 bool * neighborNulls = NULL;
5627 int neighborDims[2];
5636 if (PG_ARGISNULL(0)) {
5637 elog(WARNING,
"Raster is NULL. Returning NULL");
5643 pgraster = (
rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
5647 PG_FREE_IF_COPY(pgraster, 0);
5648 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not deserialize raster");
5656 if (PG_ARGISNULL(1))
5659 nband = PG_GETARG_INT32(1);
5664 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraFctNgb: Creating new empty raster...");
5675 if ( NULL == newrast ) {
5677 PG_FREE_IF_COPY(pgraster, 0);
5678 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not create a new raster");
5703 elog(NOTICE,
"Raster is empty. Returning an empty raster");
5705 PG_FREE_IF_COPY(pgraster, 0);
5709 if (NULL == pgrtn) {
5710 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5714 SET_VARSIZE(pgrtn, pgrtn->
size);
5715 PG_RETURN_POINTER(pgrtn);
5718 POSTGIS_RT_DEBUGF(3,
"RASTER_mapAlgebraFctNgb: Getting raster band %d...", nband);
5725 elog(NOTICE,
"Raster does not have the required band. Returning a raster " 5728 PG_FREE_IF_COPY(pgraster, 0);
5732 if (NULL == pgrtn) {
5733 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5737 SET_VARSIZE(pgrtn, pgrtn->
size);
5738 PG_RETURN_POINTER(pgrtn);
5743 if ( NULL == band ) {
5744 elog(NOTICE,
"Could not get the required band. Returning a raster " 5747 PG_FREE_IF_COPY(pgraster, 0);
5751 if (NULL == pgrtn) {
5752 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5756 SET_VARSIZE(pgrtn, pgrtn->
size);
5757 PG_RETURN_POINTER(pgrtn);
5763 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraFctNgb: Getting NODATA value for band...");
5780 newinitialvalue = newnodatavalue;
5787 if (PG_ARGISNULL(2)) {
5792 strFromText = text_to_cstring(PG_GETARG_TEXT_P(2));
5793 POSTGIS_RT_DEBUGF(3,
"RASTER_mapAlgebraFctNgb: Pixeltype parameter: %s", strFromText);
5796 if (newpixeltype ==
PT_END)
5800 if (newpixeltype ==
PT_END) {
5803 PG_FREE_IF_COPY(pgraster, 0);
5806 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Invalid pixeltype");
5814 if (PG_ARGISNULL(5)) {
5817 PG_FREE_IF_COPY(pgraster, 0);
5820 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Required function is missing");
5824 oid = PG_GETARG_OID(5);
5825 if (oid == InvalidOid) {
5828 PG_FREE_IF_COPY(pgraster, 0);
5831 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Got invalid function object id");
5835 fmgr_info(oid, &cbinfo);
5838 if (cbinfo.fn_retset) {
5841 PG_FREE_IF_COPY(pgraster, 0);
5844 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Function provided must return double precision not resultset");
5848 else if (cbinfo.fn_nargs != 3) {
5851 PG_FREE_IF_COPY(pgraster, 0);
5854 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Function does not have three input parameters");
5858 if (func_volatile(oid) ==
'v') {
5859 elog(NOTICE,
"Function provided is VOLATILE. Unless required and for best performance, function should be IMMUTABLE or STABLE");
5863 #if POSTGIS_PGSQL_VERSION < 120 5864 InitFunctionCallInfoData(cbdata, &cbinfo, 3, InvalidOid, NULL, NULL);
5865 memset(cbdata.argnull,
FALSE,
sizeof(
bool) * 3);
5867 InitFunctionCallInfoData(*cbdata, &cbinfo, 3, InvalidOid, NULL, NULL);
5868 cbdata->args[0].isnull =
FALSE;
5869 cbdata->args[1].isnull =
FALSE;
5870 cbdata->args[2].isnull =
FALSE;
5874 if (PG_ARGISNULL(7)) {
5875 if (cbinfo.fn_strict) {
5878 PG_FREE_IF_COPY(pgraster, 0);
5881 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Strict callback functions cannot have NULL parameters");
5885 #if POSTGIS_PGSQL_VERSION < 120 5886 cbdata.arg[2] = (Datum)NULL;
5887 cbdata.argnull[2] =
TRUE;
5889 cbdata->args[2].value = (Datum)NULL;
5890 cbdata->args[2].isnull =
TRUE;
5894 #if POSTGIS_PGSQL_VERSION < 120 5895 cbdata.arg[2] = PG_GETARG_DATUM(7);
5897 cbdata->args[2].value = PG_GETARG_DATUM(7);
5908 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraFctNgb: Band is a nodata band, returning " 5909 "a raster filled with nodata");
5912 newinitialvalue,
TRUE, newnodatavalue, 0);
5915 PG_FREE_IF_COPY(pgraster, 0);
5920 if (NULL == pgrtn) {
5921 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5925 SET_VARSIZE(pgrtn, pgrtn->
size);
5926 PG_RETURN_POINTER(pgrtn);
5935 newinitialvalue,
TRUE, newnodatavalue, 0);
5939 if ( NULL == newband ) {
5940 elog(NOTICE,
"Could not modify band for new raster. Returning new " 5941 "raster with the original band");
5944 PG_FREE_IF_COPY(pgraster, 0);
5949 if (NULL == pgrtn) {
5950 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5954 SET_VARSIZE(pgrtn, pgrtn->
size);
5955 PG_RETURN_POINTER(pgrtn);
5959 if (PG_ARGISNULL(3) || PG_GETARG_INT32(3) <= 0) {
5960 elog(NOTICE,
"Neighborhood width is NULL or <= 0. Returning new " 5961 "raster with the original band");
5964 PG_FREE_IF_COPY(pgraster, 0);
5969 if (NULL == pgrtn) {
5970 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5974 SET_VARSIZE(pgrtn, pgrtn->
size);
5975 PG_RETURN_POINTER(pgrtn);
5978 ngbwidth = PG_GETARG_INT32(3);
5979 winwidth = ngbwidth * 2 + 1;
5982 if (PG_ARGISNULL(4) || PG_GETARG_INT32(4) <= 0) {
5983 elog(NOTICE,
"Neighborhood height is NULL or <= 0. Returning new " 5984 "raster with the original band");
5987 PG_FREE_IF_COPY(pgraster, 0);
5992 if (NULL == pgrtn) {
5993 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5997 SET_VARSIZE(pgrtn, pgrtn->
size);
5998 PG_RETURN_POINTER(pgrtn);
6001 ngbheight = PG_GETARG_INT32(4);
6002 winheight = ngbheight * 2 + 1;
6005 if (PG_ARGISNULL(6)) {
6006 elog(NOTICE,
"Neighborhood NODATA behavior defaulting to 'ignore'");
6007 txtNodataMode = cstring_to_text(
"ignore");
6010 txtNodataMode = PG_GETARG_TEXT_P(6);
6013 txtCallbackParam = (text*)palloc(VARSIZE(txtNodataMode));
6014 SET_VARSIZE(txtCallbackParam, VARSIZE(txtNodataMode));
6015 memcpy((
void *)VARDATA(txtCallbackParam), (
void *)VARDATA(txtNodataMode), VARSIZE(txtNodataMode) - VARHDRSZ);
6018 #if POSTGIS_PGSQL_VERSION < 120 6019 cbdata.arg[1] = CStringGetDatum(txtCallbackParam);
6021 cbdata->args[1].value = CStringGetDatum(txtCallbackParam);
6024 strFromText = text_to_cstring(txtNodataMode);
6027 if (strcmp(strFromText,
"VALUE") == 0)
6028 valuereplace =
true;
6029 else if (strcmp(strFromText,
"IGNORE") != 0 && strcmp(strFromText,
"NULL") != 0) {
6031 if (sscanf(strFromText,
"%d", &intReplace) <= 0 && sscanf(strFromText,
"%f", &fltReplace) <= 0) {
6033 elog(NOTICE,
"Neighborhood NODATA mode is not recognized. Must be one of 'value', 'ignore', " 6034 "'NULL', or a numeric value. Returning new raster with the original band");
6037 pfree(txtCallbackParam);
6041 PG_FREE_IF_COPY(pgraster, 0);
6046 if (NULL == pgrtn) {
6047 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
6051 SET_VARSIZE(pgrtn, pgrtn->
size);
6052 PG_RETURN_POINTER(pgrtn);
6055 else if (strcmp(strFromText,
"NULL") == 0) {
6064 neighborData = (Datum *)palloc(winwidth * winheight *
sizeof(Datum));
6065 neighborNulls = (
bool *)palloc(winwidth * winheight *
sizeof(
bool));
6068 neighborDims[0] = winwidth;
6069 neighborDims[1] = winheight;
6076 get_typlenbyvalalign(FLOAT8OID, &typlen, &typbyval, &typalign);
6078 for (x = 0 + ngbwidth; x < width - ngbwidth; x++) {
6079 for(y = 0 + ngbheight; y < height - ngbheight; y++) {
6084 pixelreplace =
false;
6088 pixelreplace =
true;
6091 for (u = x - ngbwidth; u <= x + ngbwidth; u++) {
6092 for (v = y - ngbheight; v <= y + ngbheight; v++) {
6095 if (
FLT_NEQ(r, newnodatavalue)) {
6097 neighborData[nIndex] = Float8GetDatum((
double)r);
6098 neighborNulls[nIndex] =
false;
6099 nNodataOnly =
false;
6103 if (valuereplace && pixelreplace) {
6105 neighborData[nIndex] = Float8GetDatum((
double)rpix);
6106 neighborNulls[nIndex] =
false;
6111 neighborData[nIndex] = PointerGetDatum(NULL);
6112 neighborNulls[nIndex] =
true;
6119 neighborData[nIndex] = PointerGetDatum(NULL);
6120 neighborNulls[nIndex] =
true;
6132 if (!(nNodataOnly ||
6133 (nNullSkip && nNullItems > 0) ||
6134 (valuereplace && nNullItems > 0))) {
6136 x, y, winwidth, winheight);
6138 neighborDatum = construct_md_array((
void *)neighborData, neighborNulls, 2, neighborDims, neighborLbs,
6139 FLOAT8OID, typlen, typbyval, typalign);
6141 #if POSTGIS_PGSQL_VERSION < 120 6143 cbdata.arg[0] = PointerGetDatum(neighborDatum);
6146 tmpnewval = FunctionCallInvoke(&cbdata);
6149 if (cbdata.isnull) {
6150 newval = newnodatavalue;
6154 cbdata->args[0].value = PointerGetDatum(neighborDatum);
6157 tmpnewval = FunctionCallInvoke(cbdata);
6162 newval = newnodatavalue;
6166 newval = DatumGetFloat8(tmpnewval);
6182 pfree(neighborNulls);
6183 pfree(neighborData);
6185 pfree(txtCallbackParam);
6188 PG_FREE_IF_COPY(pgraster, 0);
6192 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraFctNgb: raster modified, serializing it.");
6203 SET_VARSIZE(pgrtn, pgrtn->
size);
6204 PG_RETURN_POINTER(pgrtn);
void * rt_raster_serialize(rt_raster raster)
Return this raster in serialized form.
double rt_raster_get_x_offset(rt_raster raster)
Get raster x offset, in projection units.
double rt_raster_get_y_skew(rt_raster raster)
Get skew about the Y axis.
raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
void rt_raster_set_skews(rt_raster raster, double skewX, double skewY)
Set skews about the X and Y axis.
int rt_raster_is_empty(rt_raster raster)
Return TRUE if the raster is empty.
#define POSTGIS_RT_DEBUGF(level, msg,...)
rt_errorstate rt_band_get_nodata(rt_band band, double *nodata)
Get NODATA value.
rt_errorstate rt_band_get_pixel(rt_band band, int x, int y, double *value, int *nodata)
Get pixel value.
void rt_raster_set_scale(rt_raster raster, double scaleX, double scaleY)
Set scale 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.
rt_pixtype rt_pixtype_index_from_name(const char *pixname)
void rt_raster_set_offsets(rt_raster raster, double x, double y)
Set insertion points in projection units.
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
int rt_band_get_hasnodata_flag(rt_band band)
Get hasnodata flag value.
double rt_raster_get_x_scale(rt_raster raster)
Get scale X in projection units.
int rt_raster_has_band(rt_raster raster, int nband)
Return TRUE if the raster has a band of this number.
void rt_raster_set_srid(rt_raster raster, int32_t srid)
Set raster's SRID.
int32_t rt_raster_get_srid(rt_raster raster)
Get raster's SRID.
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
double rt_raster_get_y_scale(rt_raster raster)
Get scale Y in projection units.
rt_raster rt_raster_new(uint32_t width, uint32_t height)
Construct a raster with given dimensions.
double rt_raster_get_x_skew(rt_raster raster)
Get skew about the X axis.
uint16_t rt_raster_get_width(rt_raster raster)
double rt_band_get_min_value(rt_band band)
Returns the minimal possible value for the band according to the pixel type.
const char * rt_pixtype_name(rt_pixtype pixtype)
rt_pixtype rt_band_get_pixtype(rt_band band)
Return pixeltype of this band.
int rt_band_get_isnodata_flag(rt_band band)
Get isnodata flag value.
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)
#define POSTGIS_RT_DEBUG(level, msg)
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.
char * rtpg_strtoupper(char *str)