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
5599 int x,
y,
nband, width, height, ngbwidth, ngbheight, winwidth, winheight, u, v, nIndex, nNullItems;
5601 double newnodatavalue = 0.0;
5602 double newinitialvalue = 0.0;
5603 double newval = 0.0;
5608 #if POSTGIS_PGSQL_VERSION < 120
5609 FunctionCallInfoData cbdata;
5611 LOCAL_FCINFO(cbdata, FUNC_MAX_ARGS);
5614 ArrayType * neighborDatum;
5615 char * strFromText = NULL;
5616 text * txtNodataMode = NULL;
5617 text * txtCallbackParam = NULL;
5619 float fltReplace = 0;
5620 bool valuereplace =
false, pixelreplace, nNodataOnly =
true, nNullSkip =
false;
5621 Datum * neighborData = NULL;
5622 bool * neighborNulls = NULL;
5623 int neighborDims[2];
5632 if (PG_ARGISNULL(0)) {
5633 elog(WARNING,
"Raster is NULL. Returning NULL");
5639 pgraster = (
rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
5643 PG_FREE_IF_COPY(pgraster, 0);
5644 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not deserialize raster");
5652 if (PG_ARGISNULL(1))
5655 nband = PG_GETARG_INT32(1);
5660 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraFctNgb: Creating new empty raster...");
5671 if ( NULL == newrast ) {
5673 PG_FREE_IF_COPY(pgraster, 0);
5674 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not create a new raster");
5699 elog(NOTICE,
"Raster is empty. Returning an empty raster");
5701 PG_FREE_IF_COPY(pgraster, 0);
5705 if (NULL == pgrtn) {
5706 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5710 SET_VARSIZE(pgrtn, pgrtn->
size);
5711 PG_RETURN_POINTER(pgrtn);
5721 elog(NOTICE,
"Raster does not have the required band. Returning a raster "
5724 PG_FREE_IF_COPY(pgraster, 0);
5728 if (NULL == pgrtn) {
5729 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5733 SET_VARSIZE(pgrtn, pgrtn->
size);
5734 PG_RETURN_POINTER(pgrtn);
5739 if ( NULL ==
band ) {
5740 elog(NOTICE,
"Could not get the required band. Returning a raster "
5743 PG_FREE_IF_COPY(pgraster, 0);
5747 if (NULL == pgrtn) {
5748 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5752 SET_VARSIZE(pgrtn, pgrtn->
size);
5753 PG_RETURN_POINTER(pgrtn);
5759 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraFctNgb: Getting NODATA value for band...");
5776 newinitialvalue = newnodatavalue;
5783 if (PG_ARGISNULL(2)) {
5788 strFromText = text_to_cstring(PG_GETARG_TEXT_P(2));
5789 POSTGIS_RT_DEBUGF(3,
"RASTER_mapAlgebraFctNgb: Pixeltype parameter: %s", strFromText);
5792 if (newpixeltype ==
PT_END)
5796 if (newpixeltype ==
PT_END) {
5799 PG_FREE_IF_COPY(pgraster, 0);
5802 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Invalid pixeltype");
5810 if (PG_ARGISNULL(5)) {
5813 PG_FREE_IF_COPY(pgraster, 0);
5816 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Required function is missing");
5820 oid = PG_GETARG_OID(5);
5821 if (oid == InvalidOid) {
5824 PG_FREE_IF_COPY(pgraster, 0);
5827 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Got invalid function object id");
5831 fmgr_info(oid, &cbinfo);
5834 if (cbinfo.fn_retset) {
5837 PG_FREE_IF_COPY(pgraster, 0);
5840 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Function provided must return double precision not resultset");
5844 else if (cbinfo.fn_nargs != 3) {
5847 PG_FREE_IF_COPY(pgraster, 0);
5850 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Function does not have three input parameters");
5854 if (func_volatile(oid) ==
'v') {
5855 elog(NOTICE,
"Function provided is VOLATILE. Unless required and for best performance, function should be IMMUTABLE or STABLE");
5859 #if POSTGIS_PGSQL_VERSION < 120
5860 InitFunctionCallInfoData(cbdata, &cbinfo, 3, InvalidOid, NULL, NULL);
5861 memset(cbdata.argnull,
FALSE,
sizeof(
bool) * 3);
5863 InitFunctionCallInfoData(*cbdata, &cbinfo, 3, InvalidOid, NULL, NULL);
5864 cbdata->args[0].isnull =
FALSE;
5865 cbdata->args[1].isnull =
FALSE;
5866 cbdata->args[2].isnull =
FALSE;
5870 if (PG_ARGISNULL(7)) {
5871 if (cbinfo.fn_strict) {
5874 PG_FREE_IF_COPY(pgraster, 0);
5877 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Strict callback functions cannot have NULL parameters");
5881 #if POSTGIS_PGSQL_VERSION < 120
5882 cbdata.arg[2] = (Datum)NULL;
5883 cbdata.argnull[2] =
TRUE;
5885 cbdata->args[2].value = (Datum)NULL;
5886 cbdata->args[2].isnull =
TRUE;
5890 #if POSTGIS_PGSQL_VERSION < 120
5891 cbdata.arg[2] = PG_GETARG_DATUM(7);
5893 cbdata->args[2].value = PG_GETARG_DATUM(7);
5904 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraFctNgb: Band is a nodata band, returning "
5905 "a raster filled with nodata");
5908 newinitialvalue,
TRUE, newnodatavalue, 0);
5911 PG_FREE_IF_COPY(pgraster, 0);
5916 if (NULL == pgrtn) {
5917 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5921 SET_VARSIZE(pgrtn, pgrtn->
size);
5922 PG_RETURN_POINTER(pgrtn);
5931 newinitialvalue,
TRUE, newnodatavalue, 0);
5935 if ( NULL == newband ) {
5936 elog(NOTICE,
"Could not modify band for new raster. Returning new "
5937 "raster with the original band");
5940 PG_FREE_IF_COPY(pgraster, 0);
5945 if (NULL == pgrtn) {
5946 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5950 SET_VARSIZE(pgrtn, pgrtn->
size);
5951 PG_RETURN_POINTER(pgrtn);
5955 if (PG_ARGISNULL(3) || PG_GETARG_INT32(3) <= 0) {
5956 elog(NOTICE,
"Neighborhood width is NULL or <= 0. Returning new "
5957 "raster with the original band");
5960 PG_FREE_IF_COPY(pgraster, 0);
5965 if (NULL == pgrtn) {
5966 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5970 SET_VARSIZE(pgrtn, pgrtn->
size);
5971 PG_RETURN_POINTER(pgrtn);
5974 ngbwidth = PG_GETARG_INT32(3);
5975 winwidth = ngbwidth * 2 + 1;
5978 if (PG_ARGISNULL(4) || PG_GETARG_INT32(4) <= 0) {
5979 elog(NOTICE,
"Neighborhood height is NULL or <= 0. Returning new "
5980 "raster with the original band");
5983 PG_FREE_IF_COPY(pgraster, 0);
5988 if (NULL == pgrtn) {
5989 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
5993 SET_VARSIZE(pgrtn, pgrtn->
size);
5994 PG_RETURN_POINTER(pgrtn);
5997 ngbheight = PG_GETARG_INT32(4);
5998 winheight = ngbheight * 2 + 1;
6001 if (PG_ARGISNULL(6)) {
6002 elog(NOTICE,
"Neighborhood NODATA behavior defaulting to 'ignore'");
6003 txtNodataMode = cstring_to_text(
"ignore");
6006 txtNodataMode = PG_GETARG_TEXT_P(6);
6009 txtCallbackParam = (text*)palloc(VARSIZE(txtNodataMode));
6010 SET_VARSIZE(txtCallbackParam, VARSIZE(txtNodataMode));
6011 memcpy((
void *)VARDATA(txtCallbackParam), (
void *)VARDATA(txtNodataMode), VARSIZE(txtNodataMode) - VARHDRSZ);
6014 #if POSTGIS_PGSQL_VERSION < 120
6015 cbdata.arg[1] = PointerGetDatum(txtCallbackParam);
6017 cbdata->args[1].value = PointerGetDatum(txtCallbackParam);
6020 strFromText = text_to_cstring(txtNodataMode);
6023 if (strcmp(strFromText,
"VALUE") == 0)
6024 valuereplace =
true;
6025 else if (strcmp(strFromText,
"IGNORE") != 0 && strcmp(strFromText,
"NULL") != 0) {
6027 if (sscanf(strFromText,
"%d", &intReplace) <= 0 && sscanf(strFromText,
"%f", &fltReplace) <= 0) {
6029 elog(NOTICE,
"Neighborhood NODATA mode is not recognized. Must be one of 'value', 'ignore', "
6030 "'NULL', or a numeric value. Returning new raster with the original band");
6033 pfree(txtCallbackParam);
6037 PG_FREE_IF_COPY(pgraster, 0);
6042 if (NULL == pgrtn) {
6043 elog(ERROR,
"RASTER_mapAlgebraFctNgb: Could not serialize raster");
6047 SET_VARSIZE(pgrtn, pgrtn->
size);
6048 PG_RETURN_POINTER(pgrtn);
6051 else if (strcmp(strFromText,
"NULL") == 0) {
6060 neighborData = (Datum *)palloc(winwidth * winheight *
sizeof(Datum));
6061 neighborNulls = (
bool *)palloc(winwidth * winheight *
sizeof(
bool));
6064 neighborDims[0] = winwidth;
6065 neighborDims[1] = winheight;
6072 get_typlenbyvalalign(FLOAT8OID, &typlen, &typbyval, &typalign);
6074 for (
x = 0 + ngbwidth;
x < width - ngbwidth;
x++) {
6075 for(
y = 0 + ngbheight;
y < height - ngbheight;
y++) {
6080 pixelreplace =
false;
6084 pixelreplace =
true;
6087 for (u =
x - ngbwidth; u <=
x + ngbwidth; u++) {
6088 for (v =
y - ngbheight; v <=
y + ngbheight; v++) {
6093 neighborData[nIndex] = Float8GetDatum((
double)
r);
6094 neighborNulls[nIndex] =
false;
6095 nNodataOnly =
false;
6099 if (valuereplace && pixelreplace) {
6101 neighborData[nIndex] = Float8GetDatum((
double)rpix);
6102 neighborNulls[nIndex] =
false;
6107 neighborData[nIndex] = PointerGetDatum(NULL);
6108 neighborNulls[nIndex] =
true;
6115 neighborData[nIndex] = PointerGetDatum(NULL);
6116 neighborNulls[nIndex] =
true;
6128 if (!(nNodataOnly ||
6129 (nNullSkip && nNullItems > 0) ||
6130 (valuereplace && nNullItems > 0))) {
6132 x,
y, winwidth, winheight);
6134 neighborDatum = construct_md_array((
void *)neighborData, neighborNulls, 2, neighborDims, neighborLbs,
6135 FLOAT8OID, typlen, typbyval, typalign);
6137 #if POSTGIS_PGSQL_VERSION < 120
6139 cbdata.arg[0] = PointerGetDatum(neighborDatum);
6142 tmpnewval = FunctionCallInvoke(&cbdata);
6145 if (cbdata.isnull) {
6146 newval = newnodatavalue;
6150 cbdata->args[0].value = PointerGetDatum(neighborDatum);
6153 tmpnewval = FunctionCallInvoke(cbdata);
6158 newval = newnodatavalue;
6162 newval = DatumGetFloat8(tmpnewval);
6178 pfree(neighborNulls);
6179 pfree(neighborData);
6181 pfree(txtCallbackParam);
6184 PG_FREE_IF_COPY(pgraster, 0);
6188 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraFctNgb: raster modified, serializing it.");
6199 SET_VARSIZE(pgrtn, pgrtn->
size);
6200 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,...)