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
5510 int x,
y,
nband, width, height, ngbwidth, ngbheight, winwidth, winheight, u, v, nIndex, nNullItems;
5512 double newnodatavalue = 0.0;
5513 double newinitialvalue = 0.0;
5514 double newval = 0.0;
5519 LOCAL_FCINFO(cbdata, FUNC_MAX_ARGS);
5521 ArrayType * neighborDatum;
5522 char * strFromText = NULL;
5523 text * txtNodataMode = NULL;
5524 text * txtCallbackParam = NULL;
5526 float fltReplace = 0;
5527 bool valuereplace =
false, pixelreplace, nNodataOnly =
true, nNullSkip =
false;
5528 Datum * neighborData = NULL;
5529 bool * neighborNulls = NULL;
5530 int neighborDims[2];
5539 if (PG_ARGISNULL(0)) {
5540 elog(WARNING,
"Raster is NULL. Returning NULL");
5546 pgraster = (
rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
5550 PG_FREE_IF_COPY(pgraster, 0);
5551 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not deserialize raster");
5559 if (PG_ARGISNULL(1))
5562 nband = PG_GETARG_INT32(1);
5567 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraFctNgb: Creating new empty raster...");
5578 if ( NULL == newrast ) {
5580 PG_FREE_IF_COPY(pgraster, 0);
5581 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not create a new raster");
5606 elog(NOTICE,
"Raster is empty. Returning an empty raster");
5608 PG_FREE_IF_COPY(pgraster, 0);
5612 if (NULL == pgrtn) {
5613 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5617 SET_VARSIZE(pgrtn, pgrtn->
size);
5618 PG_RETURN_POINTER(pgrtn);
5628 elog(NOTICE,
"Raster does not have the required band. Returning a raster "
5631 PG_FREE_IF_COPY(pgraster, 0);
5635 if (NULL == pgrtn) {
5636 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5640 SET_VARSIZE(pgrtn, pgrtn->
size);
5641 PG_RETURN_POINTER(pgrtn);
5646 if ( NULL ==
band ) {
5647 elog(NOTICE,
"Could not get the required band. Returning a raster "
5650 PG_FREE_IF_COPY(pgraster, 0);
5654 if (NULL == pgrtn) {
5655 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5659 SET_VARSIZE(pgrtn, pgrtn->
size);
5660 PG_RETURN_POINTER(pgrtn);
5666 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraFctNgb: Getting NODATA value for band...");
5683 newinitialvalue = newnodatavalue;
5690 if (PG_ARGISNULL(2)) {
5695 strFromText = text_to_cstring(PG_GETARG_TEXT_P(2));
5696 POSTGIS_RT_DEBUGF(3,
"RASTER_mapAlgebraFctNgb: Pixeltype parameter: %s", strFromText);
5699 if (newpixeltype ==
PT_END)
5703 if (newpixeltype ==
PT_END) {
5706 PG_FREE_IF_COPY(pgraster, 0);
5709 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Invalid pixeltype");
5717 if (PG_ARGISNULL(5)) {
5720 PG_FREE_IF_COPY(pgraster, 0);
5723 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Required function is missing");
5727 oid = PG_GETARG_OID(5);
5728 if (oid == InvalidOid) {
5731 PG_FREE_IF_COPY(pgraster, 0);
5734 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Got invalid function object id");
5738 fmgr_info(oid, &cbinfo);
5741 if (cbinfo.fn_retset) {
5744 PG_FREE_IF_COPY(pgraster, 0);
5747 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Function provided must return double precision not resultset");
5751 else if (cbinfo.fn_nargs != 3) {
5754 PG_FREE_IF_COPY(pgraster, 0);
5757 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Function does not have three input parameters");
5761 if (func_volatile(oid) ==
'v') {
5762 elog(NOTICE,
"Function provided is VOLATILE. Unless required and for best performance, function should be IMMUTABLE or STABLE");
5766 InitFunctionCallInfoData(*cbdata, &cbinfo, 3, InvalidOid, NULL, NULL);
5767 cbdata->args[0].isnull =
FALSE;
5768 cbdata->args[1].isnull =
FALSE;
5769 cbdata->args[2].isnull =
FALSE;
5772 if (PG_ARGISNULL(7)) {
5773 if (cbinfo.fn_strict) {
5776 PG_FREE_IF_COPY(pgraster, 0);
5779 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Strict callback functions cannot have NULL parameters");
5783 cbdata->args[2].value = (Datum)NULL;
5784 cbdata->args[2].isnull =
TRUE;
5787 cbdata->args[2].value = PG_GETARG_DATUM(7);
5797 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraFctNgb: Band is a nodata band, returning "
5798 "a raster filled with nodata");
5801 newinitialvalue,
TRUE, newnodatavalue, 0);
5804 PG_FREE_IF_COPY(pgraster, 0);
5809 if (NULL == pgrtn) {
5810 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5814 SET_VARSIZE(pgrtn, pgrtn->
size);
5815 PG_RETURN_POINTER(pgrtn);
5824 newinitialvalue,
TRUE, newnodatavalue, 0);
5828 if ( NULL == newband ) {
5829 elog(NOTICE,
"Could not modify band for new raster. Returning new "
5830 "raster with the original band");
5833 PG_FREE_IF_COPY(pgraster, 0);
5838 if (NULL == pgrtn) {
5839 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5843 SET_VARSIZE(pgrtn, pgrtn->
size);
5844 PG_RETURN_POINTER(pgrtn);
5848 if (PG_ARGISNULL(3) || PG_GETARG_INT32(3) <= 0) {
5849 elog(NOTICE,
"Neighborhood width is NULL or <= 0. Returning new "
5850 "raster with the original band");
5853 PG_FREE_IF_COPY(pgraster, 0);
5858 if (NULL == pgrtn) {
5859 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5863 SET_VARSIZE(pgrtn, pgrtn->
size);
5864 PG_RETURN_POINTER(pgrtn);
5867 ngbwidth = PG_GETARG_INT32(3);
5868 winwidth = ngbwidth * 2 + 1;
5871 if (PG_ARGISNULL(4) || PG_GETARG_INT32(4) <= 0) {
5872 elog(NOTICE,
"Neighborhood height is NULL or <= 0. Returning new "
5873 "raster with the original band");
5876 PG_FREE_IF_COPY(pgraster, 0);
5881 if (NULL == pgrtn) {
5882 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5886 SET_VARSIZE(pgrtn, pgrtn->
size);
5887 PG_RETURN_POINTER(pgrtn);
5890 ngbheight = PG_GETARG_INT32(4);
5891 winheight = ngbheight * 2 + 1;
5894 if (PG_ARGISNULL(6)) {
5895 elog(NOTICE,
"Neighborhood NODATA behavior defaulting to 'ignore'");
5896 txtNodataMode = cstring_to_text(
"ignore");
5899 txtNodataMode = PG_GETARG_TEXT_P(6);
5902 txtCallbackParam = (text*)palloc(VARSIZE(txtNodataMode));
5903 SET_VARSIZE(txtCallbackParam, VARSIZE(txtNodataMode));
5904 memcpy((
void *)VARDATA(txtCallbackParam), (
void *)VARDATA(txtNodataMode), VARSIZE(txtNodataMode) - VARHDRSZ);
5907 cbdata->args[1].value = PointerGetDatum(txtCallbackParam);
5909 strFromText = text_to_cstring(txtNodataMode);
5912 if (strcmp(strFromText,
"VALUE") == 0)
5913 valuereplace =
true;
5914 else if (strcmp(strFromText,
"IGNORE") != 0 && strcmp(strFromText,
"NULL") != 0) {
5916 if (sscanf(strFromText,
"%d", &intReplace) <= 0 && sscanf(strFromText,
"%f", &fltReplace) <= 0) {
5918 elog(NOTICE,
"Neighborhood NODATA mode is not recognized. Must be one of 'value', 'ignore', "
5919 "'NULL', or a numeric value. Returning new raster with the original band");
5922 pfree(txtCallbackParam);
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);
5940 else if (strcmp(strFromText,
"NULL") == 0) {
5949 neighborData = (Datum *)palloc(winwidth * winheight *
sizeof(Datum));
5950 neighborNulls = (
bool *)palloc(winwidth * winheight *
sizeof(
bool));
5953 neighborDims[0] = winwidth;
5954 neighborDims[1] = winheight;
5961 get_typlenbyvalalign(FLOAT8OID, &typlen, &typbyval, &typalign);
5963 for (
x = 0 + ngbwidth;
x < width - ngbwidth;
x++) {
5964 for(
y = 0 + ngbheight;
y < height - ngbheight;
y++) {
5969 pixelreplace =
false;
5973 pixelreplace =
true;
5976 for (u =
x - ngbwidth; u <=
x + ngbwidth; u++) {
5977 for (v =
y - ngbheight; v <=
y + ngbheight; v++) {
5982 neighborData[nIndex] = Float8GetDatum((
double)
r);
5983 neighborNulls[nIndex] =
false;
5984 nNodataOnly =
false;
5988 if (valuereplace && pixelreplace) {
5990 neighborData[nIndex] = Float8GetDatum((
double)rpix);
5991 neighborNulls[nIndex] =
false;
5996 neighborData[nIndex] = PointerGetDatum(NULL);
5997 neighborNulls[nIndex] =
true;
6004 neighborData[nIndex] = PointerGetDatum(NULL);
6005 neighborNulls[nIndex] =
true;
6017 if (!(nNodataOnly ||
6018 (nNullSkip && nNullItems > 0) ||
6019 (valuereplace && nNullItems > 0))) {
6021 x,
y, winwidth, winheight);
6023 neighborDatum = construct_md_array((
void *)neighborData, neighborNulls, 2, neighborDims, neighborLbs,
6024 FLOAT8OID, typlen, typbyval, typalign);
6027 cbdata->args[0].value = PointerGetDatum(neighborDatum);
6030 tmpnewval = FunctionCallInvoke(cbdata);
6035 newval = newnodatavalue;
6038 newval = DatumGetFloat8(tmpnewval);
6054 pfree(neighborNulls);
6055 pfree(neighborData);
6057 pfree(txtCallbackParam);
6060 PG_FREE_IF_COPY(pgraster, 0);
6064 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraFctNgb: raster modified, serializing it.");
6075 SET_VARSIZE(pgrtn, pgrtn->
size);
6076 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,...)