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
5667{
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;
5680 int ret = -1;
5681 Oid oid;
5682 FmgrInfo cbinfo;
5683 LOCAL_FCINFO(cbdata, FUNC_MAX_ARGS);
5684 Datum tmpnewval;
5685 ArrayType * neighborDatum;
5686 char * strFromText = NULL;
5687 text * txtNodataMode = NULL;
5688 text * txtCallbackParam = NULL;
5689 int intReplace = 0;
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];
5695 int neighborLbs[2];
5696 int16 typlen;
5697 bool typbyval;
5698 char typalign;
5699
5701
5702
5703 if (PG_ARGISNULL(0)) {
5704 elog(WARNING, "Raster is NULL. Returning NULL");
5705 PG_RETURN_NULL();
5706 }
5707
5708
5709
5710 pgraster = (
rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
5712 if (NULL == raster)
5713 {
5714 PG_FREE_IF_COPY(pgraster, 0);
5715 elog(ERROR, "RASTER_mapAlgebraFctNgb: Could not deserialize raster");
5716 PG_RETURN_NULL();
5717 }
5718
5720
5721
5722
5723 if (PG_ARGISNULL(1))
5725 else
5726 nband = PG_GETARG_INT32(1);
5727
5728 if (nband < 1)
5730
5731 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraFctNgb: Creating new empty raster...");
5732
5739
5741
5742 if ( NULL == newrast ) {
5744 PG_FREE_IF_COPY(pgraster, 0);
5745 elog(ERROR, "RASTER_mapAlgebraFctNgb: Could not create a new raster");
5746 PG_RETURN_NULL();
5747 }
5748
5752
5756
5760
5762
5763
5769 {
5770 elog(NOTICE, "Raster is empty. Returning an empty raster");
5772 PG_FREE_IF_COPY(pgraster, 0);
5773
5776 if (NULL == pgrtn) {
5777 elog(ERROR, "RASTER_mapAlgebraFctNgb: Could not serialize raster");
5778 PG_RETURN_NULL();
5779 }
5780
5781 SET_VARSIZE(pgrtn, pgrtn->
size);
5782 PG_RETURN_POINTER(pgrtn);
5783 }
5784
5785 POSTGIS_RT_DEBUGF(3,
"RASTER_mapAlgebraFctNgb: Getting raster band %d...", nband);
5786
5792 elog(NOTICE, "Raster does not have the required band. Returning a raster "
5793 "without a band");
5795 PG_FREE_IF_COPY(pgraster, 0);
5796
5799 if (NULL == pgrtn) {
5800 elog(ERROR, "RASTER_mapAlgebraFctNgb: Could not serialize raster");
5801 PG_RETURN_NULL();
5802 }
5803
5804 SET_VARSIZE(pgrtn, pgrtn->
size);
5805 PG_RETURN_POINTER(pgrtn);
5806 }
5807
5808
5810 if ( NULL == band ) {
5811 elog(NOTICE, "Could not get the required band. Returning a raster "
5812 "without a band");
5814 PG_FREE_IF_COPY(pgraster, 0);
5815
5818 if (NULL == pgrtn) {
5819 elog(ERROR, "RASTER_mapAlgebraFctNgb: Could not serialize raster");
5820 PG_RETURN_NULL();
5821 }
5822
5823 SET_VARSIZE(pgrtn, pgrtn->
size);
5824 PG_RETURN_POINTER(pgrtn);
5825 }
5826
5827
5828
5829
5830 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraFctNgb: Getting NODATA value for band...");
5831
5834 }
5835
5836 else {
5838 }
5839
5841 newnodatavalue);
5847 newinitialvalue = newnodatavalue;
5848
5853
5854 if (PG_ARGISNULL(2)) {
5856 }
5857
5858 else {
5859 strFromText = text_to_cstring(PG_GETARG_TEXT_P(2));
5860 POSTGIS_RT_DEBUGF(3,
"RASTER_mapAlgebraFctNgb: Pixeltype parameter: %s", strFromText);
5862 pfree(strFromText);
5863 if (newpixeltype ==
PT_END)
5865 }
5866
5867 if (newpixeltype ==
PT_END) {
5868
5870 PG_FREE_IF_COPY(pgraster, 0);
5872
5873 elog(ERROR, "RASTER_mapAlgebraFctNgb: Invalid pixeltype");
5874 PG_RETURN_NULL();
5875 }
5876
5879
5880
5881 if (PG_ARGISNULL(5)) {
5882
5884 PG_FREE_IF_COPY(pgraster, 0);
5886
5887 elog(ERROR, "RASTER_mapAlgebraFctNgb: Required function is missing");
5888 PG_RETURN_NULL();
5889 }
5890
5891 oid = PG_GETARG_OID(5);
5892 if (oid == InvalidOid) {
5893
5895 PG_FREE_IF_COPY(pgraster, 0);
5897
5898 elog(ERROR, "RASTER_mapAlgebraFctNgb: Got invalid function object id");
5899 PG_RETURN_NULL();
5900 }
5901
5902 fmgr_info(oid, &cbinfo);
5903
5904
5905 if (cbinfo.fn_retset) {
5906
5908 PG_FREE_IF_COPY(pgraster, 0);
5910
5911 elog(ERROR, "RASTER_mapAlgebraFctNgb: Function provided must return double precision not resultset");
5912 PG_RETURN_NULL();
5913 }
5914
5915 else if (cbinfo.fn_nargs != 3) {
5916
5918 PG_FREE_IF_COPY(pgraster, 0);
5920
5921 elog(ERROR, "RASTER_mapAlgebraFctNgb: Function does not have three input parameters");
5922 PG_RETURN_NULL();
5923 }
5924
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");
5927 }
5928
5929
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;
5934
5935
5936 if (PG_ARGISNULL(7)) {
5937 if (cbinfo.fn_strict) {
5938
5940 PG_FREE_IF_COPY(pgraster, 0);
5942
5943 elog(ERROR, "RASTER_mapAlgebraFctNgb: Strict callback functions cannot have NULL parameters");
5944 PG_RETURN_NULL();
5945 }
5946
5947 cbdata->args[2].value = (Datum)NULL;
5948 cbdata->args[2].isnull =
TRUE;
5949 }
5950 else {
5951 cbdata->args[2].value = PG_GETARG_DATUM(7);
5952 }
5953
5960
5961 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraFctNgb: Band is a nodata band, returning "
5962 "a raster filled with nodata");
5963
5965 newinitialvalue,
TRUE, newnodatavalue, 0);
5966
5968 PG_FREE_IF_COPY(pgraster, 0);
5969
5970
5973 if (NULL == pgrtn) {
5974 elog(ERROR, "RASTER_mapAlgebraFctNgb: Could not serialize raster");
5975 PG_RETURN_NULL();
5976 }
5977
5978 SET_VARSIZE(pgrtn, pgrtn->
size);
5979 PG_RETURN_POINTER(pgrtn);
5980 }
5981
5982
5988 newinitialvalue,
TRUE, newnodatavalue, 0);
5989
5990
5992 if ( NULL == newband ) {
5993 elog(NOTICE, "Could not modify band for new raster. Returning new "
5994 "raster with the original band");
5995
5997 PG_FREE_IF_COPY(pgraster, 0);
5998
5999
6002 if (NULL == pgrtn) {
6003 elog(ERROR, "RASTER_mapAlgebraFctNgb: Could not serialize raster");
6004 PG_RETURN_NULL();
6005 }
6006
6007 SET_VARSIZE(pgrtn, pgrtn->
size);
6008 PG_RETURN_POINTER(pgrtn);
6009 }
6010
6011
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");
6015
6017 PG_FREE_IF_COPY(pgraster, 0);
6018
6019
6022 if (NULL == pgrtn) {
6023 elog(ERROR, "RASTER_mapAlgebraFctNgb: Could not serialize raster");
6024 PG_RETURN_NULL();
6025 }
6026
6027 SET_VARSIZE(pgrtn, pgrtn->
size);
6028 PG_RETURN_POINTER(pgrtn);
6029 }
6030
6031 ngbwidth = PG_GETARG_INT32(3);
6032 winwidth = ngbwidth * 2 + 1;
6033
6034
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");
6038
6040 PG_FREE_IF_COPY(pgraster, 0);
6041
6042
6045 if (NULL == pgrtn) {
6046 elog(ERROR, "RASTER_mapAlgebraFctNgb: Could not serialize raster");
6047 PG_RETURN_NULL();
6048 }
6049
6050 SET_VARSIZE(pgrtn, pgrtn->
size);
6051 PG_RETURN_POINTER(pgrtn);
6052 }
6053
6054 ngbheight = PG_GETARG_INT32(4);
6055 winheight = ngbheight * 2 + 1;
6056
6057
6058 if (PG_ARGISNULL(6)) {
6059 elog(NOTICE, "Neighborhood NODATA behavior defaulting to 'ignore'");
6060 txtNodataMode = cstring_to_text("ignore");
6061 }
6062 else {
6063 txtNodataMode = PG_GETARG_TEXT_P(6);
6064 }
6065
6066 txtCallbackParam = (text*)palloc(VARSIZE(txtNodataMode));
6067 SET_VARSIZE(txtCallbackParam, VARSIZE(txtNodataMode));
6068 memcpy((void *)VARDATA(txtCallbackParam), (void *)VARDATA(txtNodataMode), VARSIZE(txtNodataMode) - VARHDRSZ);
6069
6070
6071 cbdata->args[1].value = PointerGetDatum(txtCallbackParam);
6072
6073 strFromText = text_to_cstring(txtNodataMode);
6075
6076 if (strcmp(strFromText, "VALUE") == 0)
6077 valuereplace = true;
6078 else if (strcmp(strFromText, "IGNORE") != 0 && strcmp(strFromText, "NULL") != 0) {
6079
6080 if (sscanf(strFromText, "%d", &intReplace) <= 0 && sscanf(strFromText, "%f", &fltReplace) <= 0) {
6081
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");
6084
6085
6086 pfree(txtCallbackParam);
6087 pfree(strFromText);
6088
6090 PG_FREE_IF_COPY(pgraster, 0);
6091
6092
6095 if (NULL == pgrtn) {
6096 elog(ERROR, "RASTER_mapAlgebraFctNgb: Could not serialize raster");
6097 PG_RETURN_NULL();
6098 }
6099
6100 SET_VARSIZE(pgrtn, pgrtn->
size);
6101 PG_RETURN_POINTER(pgrtn);
6102 }
6103 }
6104 else if (strcmp(strFromText, "NULL") == 0) {
6105
6106 nNullSkip = true;
6107 }
6108
6110 width, height);
6111
6112
6113 neighborData = (Datum *)palloc(sizeof(Datum) * winwidth * winheight);
6114 neighborNulls = (bool *)palloc(sizeof(bool) * winwidth * winheight);
6115
6116
6117 neighborDims[0] = winwidth;
6118 neighborDims[1] = winheight;
6119
6120
6121 neighborLbs[0] = 1;
6122 neighborLbs[1] = 1;
6123
6124
6125 get_typlenbyvalalign(FLOAT8OID, &typlen, &typbyval, &typalign);
6126
6127 for (x = 0 + ngbwidth;
x < width - ngbwidth;
x++) {
6128 for(y = 0 + ngbheight;
y < height - ngbheight;
y++) {
6129
6130 nIndex = 0;
6131 nNullItems = 0;
6132 nNodataOnly = true;
6133 pixelreplace = false;
6134 if (valuereplace) {
6137 pixelreplace = true;
6138 }
6139 }
6140 for (u = x - ngbwidth; u <=
x + ngbwidth; u++) {
6141 for (v = y - ngbheight; v <=
y + ngbheight; v++) {
6145
6146 neighborData[nIndex] = Float8GetDatum((
double)
r);
6147 neighborNulls[nIndex] = false;
6148 nNodataOnly = false;
6149 }
6150 else {
6151
6152 if (valuereplace && pixelreplace) {
6153
6154 neighborData[nIndex] = Float8GetDatum((double)rpix);
6155 neighborNulls[nIndex] = false;
6156
6157
6158 }
6159 else {
6160 neighborData[nIndex] = PointerGetDatum(NULL);
6161 neighborNulls[nIndex] = true;
6162 nNullItems++;
6163 }
6164 }
6165 }
6166 else {
6167
6168 neighborData[nIndex] = PointerGetDatum(NULL);
6169 neighborNulls[nIndex] = true;
6170 nNullItems++;
6171 }
6172
6173 nIndex++;
6174 }
6175 }
6176
6181 if (!(nNodataOnly ||
6182 (nNullSkip && nNullItems > 0) ||
6183 (valuereplace && nNullItems > 0))) {
6185 x, y, winwidth, winheight);
6186
6187 neighborDatum = construct_md_array((void *)neighborData, neighborNulls, 2, neighborDims, neighborLbs,
6188 FLOAT8OID, typlen, typbyval, typalign);
6189
6190
6191 cbdata->args[0].value = PointerGetDatum(neighborDatum);
6192
6193
6194 tmpnewval = FunctionCallInvoke(cbdata);
6195
6196
6197 if (cbdata->isnull)
6198 {
6199 newval = newnodatavalue;
6200 }
6201 else {
6202 newval = DatumGetFloat8(tmpnewval);
6203 }
6204
6206 newval);
6207
6209 }
6210
6211
6212 nNullItems = 0;
6213 }
6214 }
6215
6216
6217
6218 pfree(neighborNulls);
6219 pfree(neighborData);
6220 pfree(strFromText);
6221 pfree(txtCallbackParam);
6222
6224 PG_FREE_IF_COPY(pgraster, 0);
6225
6226
6227
6228 POSTGIS_RT_DEBUG(3,
"RASTER_mapAlgebraFctNgb: raster modified, serializing it.");
6229
6230
6233 if (NULL == pgrtn)
6234 PG_RETURN_NULL();
6235
6238
6239 SET_VARSIZE(pgrtn, pgrtn->
size);
6240 PG_RETURN_POINTER(pgrtn);
6241}
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.
double rt_raster_get_x_scale(rt_raster raster)
Get scale X in projection units.
const char * rt_pixtype_name(rt_pixtype pixtype)
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.
uint16_t rt_raster_get_width(rt_raster raster)
void * rt_raster_serialize(rt_raster raster)
Return this raster in serialized form.
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,...)