PostGIS  2.1.10dev-r@@SVN_REVISION@@
Datum RASTER_dumpValues ( PG_FUNCTION_ARGS  )

Definition at line 2853 of file rt_pg.c.

References ovdump::band, rtpg_dumpvalues_arg_t::columns, ES_NONE, FALSE, pixval::nband, rtpg_dumpvalues_arg_t::nbands, rtpg_dumpvalues_arg_t::nodata, rtpg_dumpvalues_arg_t::numbands, POSTGIS_RT_DEBUG, POSTGIS_RT_DEBUGF, rtrowdump::raster, result, rtpg_dumpvalues_arg_t::rows, rt_band_clamped_value_is_nodata(), rt_band_get_isnodata_flag(), rt_band_get_pixel(), rt_raster_deserialize(), rt_raster_destroy(), rt_raster_get_band(), rt_raster_get_height(), rt_raster_get_num_bands(), rt_raster_get_width(), rt_raster_has_band(), rt_raster_is_empty(), rtpg_dumpvalues_arg_destroy(), rtpg_dumpvalues_arg_init(), TRUE, rtpg_dumpvalues_arg_t::values, pixval::x, and pixval::y.

2854 {
2855  FuncCallContext *funcctx;
2856  TupleDesc tupdesc;
2857  int call_cntr;
2858  int max_calls;
2859  int i = 0;
2860  int x = 0;
2861  int y = 0;
2862  int z = 0;
2863 
2864  int16 typlen;
2865  bool typbyval;
2866  char typalign;
2867 
2868  rtpg_dumpvalues_arg arg1 = NULL;
2869  rtpg_dumpvalues_arg arg2 = NULL;
2870 
2871  /* stuff done only on the first call of the function */
2872  if (SRF_IS_FIRSTCALL()) {
2873  MemoryContext oldcontext;
2874  rt_pgraster *pgraster = NULL;
2875  rt_raster raster = NULL;
2876  rt_band band = NULL;
2877  int numbands = 0;
2878  int j = 0;
2879  bool exclude_nodata_value = TRUE;
2880 
2881  ArrayType *array;
2882  Oid etype;
2883  Datum *e;
2884  bool *nulls;
2885 
2886  double val = 0;
2887  int isnodata = 0;
2888 
2889  POSTGIS_RT_DEBUG(2, "RASTER_dumpValues first call");
2890 
2891  /* create a function context for cross-call persistence */
2892  funcctx = SRF_FIRSTCALL_INIT();
2893 
2894  /* switch to memory context appropriate for multiple function calls */
2895  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
2896 
2897  /* Get input arguments */
2898  if (PG_ARGISNULL(0)) {
2899  MemoryContextSwitchTo(oldcontext);
2900  SRF_RETURN_DONE(funcctx);
2901  }
2902  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
2903 
2904  raster = rt_raster_deserialize(pgraster, FALSE);
2905  if (!raster) {
2906  PG_FREE_IF_COPY(pgraster, 0);
2907  ereport(ERROR, (
2908  errcode(ERRCODE_OUT_OF_MEMORY),
2909  errmsg("Could not deserialize raster")
2910  ));
2911  MemoryContextSwitchTo(oldcontext);
2912  SRF_RETURN_DONE(funcctx);
2913  }
2914 
2915  /* check that raster is not empty */
2916  /*
2917  if (rt_raster_is_empty(raster)) {
2918  elog(NOTICE, "Raster provided is empty");
2919  rt_raster_destroy(raster);
2920  PG_FREE_IF_COPY(pgraster, 0);
2921  MemoryContextSwitchTo(oldcontext);
2922  SRF_RETURN_DONE(funcctx);
2923  }
2924  */
2925 
2926  /* raster has bands */
2927  numbands = rt_raster_get_num_bands(raster);
2928  if (!numbands) {
2929  elog(NOTICE, "Raster provided has no bands");
2930  rt_raster_destroy(raster);
2931  PG_FREE_IF_COPY(pgraster, 0);
2932  MemoryContextSwitchTo(oldcontext);
2933  SRF_RETURN_DONE(funcctx);
2934  }
2935 
2936  /* initialize arg1 */
2937  arg1 = rtpg_dumpvalues_arg_init();
2938  if (arg1 == NULL) {
2939  rt_raster_destroy(raster);
2940  PG_FREE_IF_COPY(pgraster, 0);
2941  MemoryContextSwitchTo(oldcontext);
2942  elog(ERROR, "RASTER_dumpValues: Could not initialize argument structure");
2943  SRF_RETURN_DONE(funcctx);
2944  }
2945 
2946  /* nband, array */
2947  if (!PG_ARGISNULL(1)) {
2948  array = PG_GETARG_ARRAYTYPE_P(1);
2949  etype = ARR_ELEMTYPE(array);
2950  get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
2951 
2952  switch (etype) {
2953  case INT2OID:
2954  case INT4OID:
2955  break;
2956  default:
2958  rt_raster_destroy(raster);
2959  PG_FREE_IF_COPY(pgraster, 0);
2960  MemoryContextSwitchTo(oldcontext);
2961  elog(ERROR, "RASTER_dumpValues: Invalid data type for band indexes");
2962  SRF_RETURN_DONE(funcctx);
2963  break;
2964  }
2965 
2966  deconstruct_array(array, etype, typlen, typbyval, typalign, &e, &nulls, &(arg1->numbands));
2967 
2968  arg1->nbands = palloc(sizeof(int) * arg1->numbands);
2969  if (arg1->nbands == NULL) {
2971  rt_raster_destroy(raster);
2972  PG_FREE_IF_COPY(pgraster, 0);
2973  MemoryContextSwitchTo(oldcontext);
2974  elog(ERROR, "RASTER_dumpValues: Could not allocate memory for band indexes");
2975  SRF_RETURN_DONE(funcctx);
2976  }
2977 
2978  for (i = 0, j = 0; i < arg1->numbands; i++) {
2979  if (nulls[i]) continue;
2980 
2981  switch (etype) {
2982  case INT2OID:
2983  arg1->nbands[j] = DatumGetInt16(e[i]) - 1;
2984  break;
2985  case INT4OID:
2986  arg1->nbands[j] = DatumGetInt32(e[i]) - 1;
2987  break;
2988  }
2989 
2990  j++;
2991  }
2992 
2993  if (j < arg1->numbands) {
2994  arg1->nbands = repalloc(arg1->nbands, sizeof(int) * j);
2995  if (arg1->nbands == NULL) {
2997  rt_raster_destroy(raster);
2998  PG_FREE_IF_COPY(pgraster, 0);
2999  MemoryContextSwitchTo(oldcontext);
3000  elog(ERROR, "RASTER_dumpValues: Could not reallocate memory for band indexes");
3001  SRF_RETURN_DONE(funcctx);
3002  }
3003 
3004  arg1->numbands = j;
3005  }
3006 
3007  /* validate nbands */
3008  for (i = 0; i < arg1->numbands; i++) {
3009  if (!rt_raster_has_band(raster, arg1->nbands[i])) {
3010  elog(NOTICE, "Band at index %d not found in raster", arg1->nbands[i] + 1);
3012  rt_raster_destroy(raster);
3013  PG_FREE_IF_COPY(pgraster, 0);
3014  MemoryContextSwitchTo(oldcontext);
3015  SRF_RETURN_DONE(funcctx);
3016  }
3017  }
3018 
3019  }
3020  else {
3021  arg1->numbands = numbands;
3022  arg1->nbands = palloc(sizeof(int) * arg1->numbands);
3023 
3024  if (arg1->nbands == NULL) {
3026  rt_raster_destroy(raster);
3027  PG_FREE_IF_COPY(pgraster, 0);
3028  MemoryContextSwitchTo(oldcontext);
3029  elog(ERROR, "RASTER_dumpValues: Could not allocate memory for band indexes");
3030  SRF_RETURN_DONE(funcctx);
3031  }
3032 
3033  for (i = 0; i < arg1->numbands; i++) {
3034  arg1->nbands[i] = i;
3035  POSTGIS_RT_DEBUGF(4, "arg1->nbands[%d] = %d", arg1->nbands[i], i);
3036  }
3037  }
3038 
3039  arg1->rows = rt_raster_get_height(raster);
3040  arg1->columns = rt_raster_get_width(raster);
3041 
3042  /* exclude_nodata_value */
3043  if (!PG_ARGISNULL(2))
3044  exclude_nodata_value = PG_GETARG_BOOL(2);
3045  POSTGIS_RT_DEBUGF(4, "exclude_nodata_value = %d", exclude_nodata_value);
3046 
3047  /* allocate memory for each band's values and nodata flags */
3048  arg1->values = palloc(sizeof(Datum *) * arg1->numbands);
3049  arg1->nodata = palloc(sizeof(bool *) * arg1->numbands);
3050  if (arg1->values == NULL || arg1->nodata == NULL) {
3052  rt_raster_destroy(raster);
3053  PG_FREE_IF_COPY(pgraster, 0);
3054  MemoryContextSwitchTo(oldcontext);
3055  elog(ERROR, "RASTER_dumpValues: Could not allocate memory for pixel values");
3056  SRF_RETURN_DONE(funcctx);
3057  }
3058  memset(arg1->values, 0, sizeof(Datum *) * arg1->numbands);
3059  memset(arg1->nodata, 0, sizeof(bool *) * arg1->numbands);
3060 
3061  /* get each band and dump data */
3062  for (z = 0; z < arg1->numbands; z++) {
3063  /* shortcut if raster is empty */
3064  if (rt_raster_is_empty(raster))
3065  break;
3066 
3067  band = rt_raster_get_band(raster, arg1->nbands[z]);
3068  if (!band) {
3069  int nband = arg1->nbands[z] + 1;
3071  rt_raster_destroy(raster);
3072  PG_FREE_IF_COPY(pgraster, 0);
3073  MemoryContextSwitchTo(oldcontext);
3074  elog(ERROR, "RASTER_dumpValues: Could not get band at index %d", nband);
3075  SRF_RETURN_DONE(funcctx);
3076  }
3077 
3078  /* allocate memory for values and nodata flags */
3079  arg1->values[z] = palloc(sizeof(Datum) * arg1->rows * arg1->columns);
3080  arg1->nodata[z] = palloc(sizeof(bool) * arg1->rows * arg1->columns);
3081  if (arg1->values[z] == NULL || arg1->nodata[z] == NULL) {
3083  rt_raster_destroy(raster);
3084  PG_FREE_IF_COPY(pgraster, 0);
3085  MemoryContextSwitchTo(oldcontext);
3086  elog(ERROR, "RASTER_dumpValues: Could not allocate memory for pixel values");
3087  SRF_RETURN_DONE(funcctx);
3088  }
3089  memset(arg1->values[z], 0, sizeof(Datum) * arg1->rows * arg1->columns);
3090  memset(arg1->nodata[z], 0, sizeof(bool) * arg1->rows * arg1->columns);
3091 
3092  i = 0;
3093 
3094  /* shortcut if band is NODATA */
3095  if (rt_band_get_isnodata_flag(band)) {
3096  for (i = (arg1->rows * arg1->columns) - 1; i >= 0; i--)
3097  arg1->nodata[z][i] = TRUE;
3098  continue;
3099  }
3100 
3101  for (y = 0; y < arg1->rows; y++) {
3102  for (x = 0; x < arg1->columns; x++) {
3103  /* get pixel */
3104  if (rt_band_get_pixel(band, x, y, &val, &isnodata) != ES_NONE) {
3105  int nband = arg1->nbands[z] + 1;
3107  rt_raster_destroy(raster);
3108  PG_FREE_IF_COPY(pgraster, 0);
3109  MemoryContextSwitchTo(oldcontext);
3110  elog(ERROR, "RASTER_dumpValues: Could not pixel (%d, %d) of band %d", x, y, nband);
3111  SRF_RETURN_DONE(funcctx);
3112  }
3113 
3114  arg1->values[z][i] = Float8GetDatum(val);
3115  POSTGIS_RT_DEBUGF(5, "arg1->values[z][i] = %f", DatumGetFloat8(arg1->values[z][i]));
3116  POSTGIS_RT_DEBUGF(5, "clamped is?: %d", rt_band_clamped_value_is_nodata(band, val));
3117 
3118  if (exclude_nodata_value && isnodata) {
3119  arg1->nodata[z][i] = TRUE;
3120  POSTGIS_RT_DEBUG(5, "nodata = 1");
3121  }
3122  else
3123  POSTGIS_RT_DEBUG(5, "nodata = 0");
3124 
3125  i++;
3126  }
3127  }
3128  }
3129 
3130  /* cleanup */
3131  rt_raster_destroy(raster);
3132  PG_FREE_IF_COPY(pgraster, 0);
3133 
3134  /* Store needed information */
3135  funcctx->user_fctx = arg1;
3136 
3137  /* total number of tuples to be returned */
3138  funcctx->max_calls = arg1->numbands;
3139 
3140  /* Build a tuple descriptor for our result type */
3141  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
3142  MemoryContextSwitchTo(oldcontext);
3143  ereport(ERROR, (
3144  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3145  errmsg(
3146  "function returning record called in context "
3147  "that cannot accept type record"
3148  )
3149  ));
3150  }
3151 
3152  BlessTupleDesc(tupdesc);
3153  funcctx->tuple_desc = tupdesc;
3154 
3155  MemoryContextSwitchTo(oldcontext);
3156  }
3157 
3158  /* stuff done on every call of the function */
3159  funcctx = SRF_PERCALL_SETUP();
3160 
3161  call_cntr = funcctx->call_cntr;
3162  max_calls = funcctx->max_calls;
3163  tupdesc = funcctx->tuple_desc;
3164  arg2 = funcctx->user_fctx;
3165 
3166  /* do when there is more left to send */
3167  if (call_cntr < max_calls) {
3168  int values_length = 2;
3169  Datum values[values_length];
3170  bool nulls[values_length];
3171  HeapTuple tuple;
3172  Datum result;
3173  ArrayType *mdValues = NULL;
3174  int ndim = 2;
3175  int dim[2] = {arg2->rows, arg2->columns};
3176  int lbound[2] = {1, 1};
3177 
3178  POSTGIS_RT_DEBUGF(3, "call number %d", call_cntr);
3179  POSTGIS_RT_DEBUGF(4, "dim = %d, %d", dim[0], dim[1]);
3180 
3181  memset(nulls, FALSE, sizeof(bool) * values_length);
3182 
3183  values[0] = Int32GetDatum(arg2->nbands[call_cntr] + 1);
3184 
3185  /* info about the type of item in the multi-dimensional array (float8). */
3186  get_typlenbyvalalign(FLOAT8OID, &typlen, &typbyval, &typalign);
3187 
3188  /* if values is NULL, return empty raster */
3189  if (arg2->values[call_cntr] == NULL)
3190  ndim = 0;
3191 
3192  /* assemble 3-dimension array of values */
3193  mdValues = construct_md_array(
3194  arg2->values[call_cntr], arg2->nodata[call_cntr],
3195  ndim, dim, lbound,
3196  FLOAT8OID,
3197  typlen, typbyval, typalign
3198  );
3199  values[1] = PointerGetDatum(mdValues);
3200 
3201  /* build a tuple and datum */
3202  tuple = heap_form_tuple(tupdesc, values, nulls);
3203  result = HeapTupleGetDatum(tuple);
3204 
3205  SRF_RETURN_NEXT(funcctx, result);
3206  }
3207  /* do when there is no more left */
3208  else {
3210  SRF_RETURN_DONE(funcctx);
3211  }
3212 }
int rt_raster_get_num_bands(rt_raster raster)
Definition: rt_api.c:5677
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition: rt_api.c:5387
static rtpg_dumpvalues_arg rtpg_dumpvalues_arg_init()
Definition: rt_pg.c:2804
int rt_band_clamped_value_is_nodata(rt_band band, double val)
Compare clamped value to band's clamped NODATA value.
Definition: rt_api.c:3126
tuple band
Definition: ovdump.py:57
int rt_raster_has_band(rt_raster raster, int nband)
Return TRUE if the raster has a band of this number.
Definition: rt_api.c:8563
tuple raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
Definition: rtrowdump.py:123
static void rtpg_dumpvalues_arg_destroy(rtpg_dumpvalues_arg arg)
Definition: rt_pg.c:2824
int rt_band_get_isnodata_flag(rt_band band)
Get isnodata flag value.
Definition: rt_api.c:2042
char ** result
Definition: liblwgeom.h:218
#define POSTGIS_RT_DEBUG(level, msg)
Definition: rt_pg.h:58
tuple nband
Definition: pixval.py:52
rt_errorstate rt_band_get_pixel(rt_band band, int x, int y, double *value, int *nodata)
Get pixel value.
Definition: rt_api.c:2549
tuple x
Definition: pixval.py:53
uint16_t rt_raster_get_height(rt_raster raster)
Definition: rt_api.c:5434
rt_band rt_raster_get_band(rt_raster raster, int n)
Return Nth band, or NULL if unavailable.
Definition: rt_api.c:5686
#define FALSE
Definition: dbfopen.c:169
Struct definitions.
Definition: rt_api.h:2175
#define POSTGIS_RT_DEBUGF(level, msg,...)
Definition: rt_pg.h:62
int rt_raster_is_empty(rt_raster raster)
Return TRUE if the raster is empty.
Definition: rt_api.c:8550
rt_raster rt_raster_deserialize(void *serialized, int header_only)
Return a raster from a serialized form.
Definition: rt_api.c:8350
#define TRUE
Definition: dbfopen.c:170
tuple y
Definition: pixval.py:54
uint16_t rt_raster_get_width(rt_raster raster)
Definition: rt_api.c:5426

Here is the call graph for this function: