PostGIS  2.5.7dev-r@@SVN_REVISION@@

◆ RASTER_dumpValues()

Datum RASTER_dumpValues ( PG_FUNCTION_ARGS  )

Definition at line 203 of file rtpg_pixel.c.

204 {
205  FuncCallContext *funcctx;
206  TupleDesc tupdesc;
207  int call_cntr;
208  int max_calls;
209  int i = 0;
210  int x = 0;
211  int y = 0;
212  int z = 0;
213 
214  int16 typlen;
215  bool typbyval;
216  char typalign;
217 
218  rtpg_dumpvalues_arg arg1 = NULL;
219  rtpg_dumpvalues_arg arg2 = NULL;
220 
221  /* stuff done only on the first call of the function */
222  if (SRF_IS_FIRSTCALL()) {
223  MemoryContext oldcontext;
224  rt_pgraster *pgraster = NULL;
225  rt_raster raster = NULL;
226  rt_band band = NULL;
227  int numbands = 0;
228  int j = 0;
229  bool exclude_nodata_value = TRUE;
230 
231  ArrayType *array;
232  Oid etype;
233  Datum *e;
234  bool *nulls;
235 
236  double val = 0;
237  int isnodata = 0;
238 
239  POSTGIS_RT_DEBUG(2, "RASTER_dumpValues first call");
240 
241  /* create a function context for cross-call persistence */
242  funcctx = SRF_FIRSTCALL_INIT();
243 
244  /* switch to memory context appropriate for multiple function calls */
245  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
246 
247  /* Get input arguments */
248  if (PG_ARGISNULL(0)) {
249  MemoryContextSwitchTo(oldcontext);
250  SRF_RETURN_DONE(funcctx);
251  }
252  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
253 
254  raster = rt_raster_deserialize(pgraster, FALSE);
255  if (!raster) {
256  PG_FREE_IF_COPY(pgraster, 0);
257  ereport(ERROR, (
258  errcode(ERRCODE_OUT_OF_MEMORY),
259  errmsg("Could not deserialize raster")
260  ));
261  MemoryContextSwitchTo(oldcontext);
262  SRF_RETURN_DONE(funcctx);
263  }
264 
265  /* check that raster is not empty */
266  /*
267  if (rt_raster_is_empty(raster)) {
268  elog(NOTICE, "Raster provided is empty");
269  rt_raster_destroy(raster);
270  PG_FREE_IF_COPY(pgraster, 0);
271  MemoryContextSwitchTo(oldcontext);
272  SRF_RETURN_DONE(funcctx);
273  }
274  */
275 
276  /* raster has bands */
277  numbands = rt_raster_get_num_bands(raster);
278  if (!numbands) {
279  elog(NOTICE, "Raster provided has no bands");
281  PG_FREE_IF_COPY(pgraster, 0);
282  MemoryContextSwitchTo(oldcontext);
283  SRF_RETURN_DONE(funcctx);
284  }
285 
286  /* initialize arg1 */
287  arg1 = rtpg_dumpvalues_arg_init();
288  if (arg1 == NULL) {
290  PG_FREE_IF_COPY(pgraster, 0);
291  MemoryContextSwitchTo(oldcontext);
292  elog(ERROR, "RASTER_dumpValues: Could not initialize argument structure");
293  SRF_RETURN_DONE(funcctx);
294  }
295 
296  /* nband, array */
297  if (!PG_ARGISNULL(1)) {
298  array = PG_GETARG_ARRAYTYPE_P(1);
299  etype = ARR_ELEMTYPE(array);
300  get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
301 
302  switch (etype) {
303  case INT2OID:
304  case INT4OID:
305  break;
306  default:
309  PG_FREE_IF_COPY(pgraster, 0);
310  MemoryContextSwitchTo(oldcontext);
311  elog(ERROR, "RASTER_dumpValues: Invalid data type for band indexes");
312  SRF_RETURN_DONE(funcctx);
313  break;
314  }
315 
316  deconstruct_array(array, etype, typlen, typbyval, typalign, &e, &nulls, &(arg1->numbands));
317 
318  arg1->nbands = palloc(sizeof(int) * arg1->numbands);
319  if (arg1->nbands == NULL) {
322  PG_FREE_IF_COPY(pgraster, 0);
323  MemoryContextSwitchTo(oldcontext);
324  elog(ERROR, "RASTER_dumpValues: Could not allocate memory for band indexes");
325  SRF_RETURN_DONE(funcctx);
326  }
327 
328  for (i = 0, j = 0; i < arg1->numbands; i++) {
329  if (nulls[i]) continue;
330 
331  switch (etype) {
332  case INT2OID:
333  arg1->nbands[j] = DatumGetInt16(e[i]) - 1;
334  break;
335  case INT4OID:
336  arg1->nbands[j] = DatumGetInt32(e[i]) - 1;
337  break;
338  }
339 
340  j++;
341  }
342 
343  if (j < arg1->numbands) {
344  arg1->nbands = repalloc(arg1->nbands, sizeof(int) * j);
345  if (arg1->nbands == NULL) {
348  PG_FREE_IF_COPY(pgraster, 0);
349  MemoryContextSwitchTo(oldcontext);
350  elog(ERROR, "RASTER_dumpValues: Could not reallocate memory for band indexes");
351  SRF_RETURN_DONE(funcctx);
352  }
353 
354  arg1->numbands = j;
355  }
356 
357  /* validate nbands */
358  for (i = 0; i < arg1->numbands; i++) {
359  if (!rt_raster_has_band(raster, arg1->nbands[i])) {
360  elog(NOTICE, "Band at index %d not found in raster", arg1->nbands[i] + 1);
363  PG_FREE_IF_COPY(pgraster, 0);
364  MemoryContextSwitchTo(oldcontext);
365  SRF_RETURN_DONE(funcctx);
366  }
367  }
368 
369  }
370  /* no bands specified, return all bands */
371  else {
372  arg1->numbands = numbands;
373  arg1->nbands = palloc(sizeof(int) * arg1->numbands);
374 
375  if (arg1->nbands == NULL) {
378  PG_FREE_IF_COPY(pgraster, 0);
379  MemoryContextSwitchTo(oldcontext);
380  elog(ERROR, "RASTER_dumpValues: Could not allocate memory for band indexes");
381  SRF_RETURN_DONE(funcctx);
382  }
383 
384  for (i = 0; i < arg1->numbands; i++) {
385  arg1->nbands[i] = i;
386  POSTGIS_RT_DEBUGF(4, "arg1->nbands[%d] = %d", arg1->nbands[i], i);
387  }
388  }
389 
392 
393  /* exclude_nodata_value */
394  if (!PG_ARGISNULL(2))
395  exclude_nodata_value = PG_GETARG_BOOL(2);
396  POSTGIS_RT_DEBUGF(4, "exclude_nodata_value = %d", exclude_nodata_value);
397 
398  /* allocate memory for each band's values and nodata flags */
399  arg1->values = palloc(sizeof(Datum *) * arg1->numbands);
400  arg1->nodata = palloc(sizeof(bool *) * arg1->numbands);
401  if (arg1->values == NULL || arg1->nodata == NULL) {
404  PG_FREE_IF_COPY(pgraster, 0);
405  MemoryContextSwitchTo(oldcontext);
406  elog(ERROR, "RASTER_dumpValues: Could not allocate memory for pixel values");
407  SRF_RETURN_DONE(funcctx);
408  }
409  memset(arg1->values, 0, sizeof(Datum *) * arg1->numbands);
410  memset(arg1->nodata, 0, sizeof(bool *) * arg1->numbands);
411 
412  /* get each band and dump data */
413  for (z = 0; z < arg1->numbands; z++) {
414  /* shortcut if raster is empty */
416  break;
417 
418  band = rt_raster_get_band(raster, arg1->nbands[z]);
419  if (!band) {
420  int nband = arg1->nbands[z] + 1;
423  PG_FREE_IF_COPY(pgraster, 0);
424  MemoryContextSwitchTo(oldcontext);
425  elog(ERROR, "RASTER_dumpValues: Could not get band at index %d", nband);
426  SRF_RETURN_DONE(funcctx);
427  }
428 
429  /* allocate memory for values and nodata flags */
430  arg1->values[z] = palloc(sizeof(Datum) * arg1->rows * arg1->columns);
431  arg1->nodata[z] = palloc(sizeof(bool) * arg1->rows * arg1->columns);
432  if (arg1->values[z] == NULL || arg1->nodata[z] == NULL) {
435  PG_FREE_IF_COPY(pgraster, 0);
436  MemoryContextSwitchTo(oldcontext);
437  elog(ERROR, "RASTER_dumpValues: Could not allocate memory for pixel values");
438  SRF_RETURN_DONE(funcctx);
439  }
440  memset(arg1->values[z], 0, sizeof(Datum) * arg1->rows * arg1->columns);
441  memset(arg1->nodata[z], 0, sizeof(bool) * arg1->rows * arg1->columns);
442 
443  i = 0;
444 
445  /* shortcut if band is NODATA */
447  for (i = (arg1->rows * arg1->columns) - 1; i >= 0; i--)
448  arg1->nodata[z][i] = TRUE;
449  continue;
450  }
451 
452  for (y = 0; y < arg1->rows; y++) {
453  for (x = 0; x < arg1->columns; x++) {
454  /* get pixel */
455  if (rt_band_get_pixel(band, x, y, &val, &isnodata) != ES_NONE) {
456  int nband = arg1->nbands[z] + 1;
459  PG_FREE_IF_COPY(pgraster, 0);
460  MemoryContextSwitchTo(oldcontext);
461  elog(ERROR, "RASTER_dumpValues: Could not pixel (%d, %d) of band %d", x, y, nband);
462  SRF_RETURN_DONE(funcctx);
463  }
464 
465  arg1->values[z][i] = Float8GetDatum(val);
466  POSTGIS_RT_DEBUGF(5, "arg1->values[z][i] = %f", DatumGetFloat8(arg1->values[z][i]));
467  POSTGIS_RT_DEBUGF(5, "clamped is?: %d", rt_band_clamped_value_is_nodata(band, val));
468 
469  if (exclude_nodata_value && isnodata) {
470  arg1->nodata[z][i] = TRUE;
471  POSTGIS_RT_DEBUG(5, "nodata = 1");
472  }
473  else
474  POSTGIS_RT_DEBUG(5, "nodata = 0");
475 
476  i++;
477  }
478  }
479  }
480 
481  /* cleanup */
483  PG_FREE_IF_COPY(pgraster, 0);
484 
485  /* Store needed information */
486  funcctx->user_fctx = arg1;
487 
488  /* total number of tuples to be returned */
489  funcctx->max_calls = arg1->numbands;
490 
491  /* Build a tuple descriptor for our result type */
492  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
493  MemoryContextSwitchTo(oldcontext);
494  ereport(ERROR, (
495  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
496  errmsg(
497  "function returning record called in context "
498  "that cannot accept type record"
499  )
500  ));
501  }
502 
503  BlessTupleDesc(tupdesc);
504  funcctx->tuple_desc = tupdesc;
505 
506  MemoryContextSwitchTo(oldcontext);
507  }
508 
509  /* stuff done on every call of the function */
510  funcctx = SRF_PERCALL_SETUP();
511 
512  call_cntr = funcctx->call_cntr;
513  max_calls = funcctx->max_calls;
514  tupdesc = funcctx->tuple_desc;
515  arg2 = funcctx->user_fctx;
516 
517  /* do when there is more left to send */
518  if (call_cntr < max_calls) {
519  Datum values[VALUES_LENGTH];
520  bool nulls[VALUES_LENGTH];
521  HeapTuple tuple;
522  Datum result;
523  ArrayType *mdValues = NULL;
524  int ndim = 2;
525  int dim[2] = {arg2->rows, arg2->columns};
526  int lbound[2] = {1, 1};
527 
528  POSTGIS_RT_DEBUGF(3, "call number %d", call_cntr);
529  POSTGIS_RT_DEBUGF(4, "dim = %d, %d", dim[0], dim[1]);
530 
531  memset(nulls, FALSE, sizeof(bool) * VALUES_LENGTH);
532 
533  values[0] = Int32GetDatum(arg2->nbands[call_cntr] + 1);
534 
535  /* info about the type of item in the multi-dimensional array (float8). */
536  get_typlenbyvalalign(FLOAT8OID, &typlen, &typbyval, &typalign);
537 
538  /* if values is NULL, return empty array */
539  if (arg2->values[call_cntr] == NULL)
540  ndim = 0;
541 
542  /* assemble 3-dimension array of values */
543  mdValues = construct_md_array(
544  arg2->values[call_cntr], arg2->nodata[call_cntr],
545  ndim, dim, lbound,
546  FLOAT8OID,
547  typlen, typbyval, typalign
548  );
549  values[1] = PointerGetDatum(mdValues);
550 
551  /* build a tuple and datum */
552  tuple = heap_form_tuple(tupdesc, values, nulls);
553  result = HeapTupleGetDatum(tuple);
554 
555  SRF_RETURN_NEXT(funcctx, result);
556  }
557  /* do when there is no more left */
558  else {
560  SRF_RETURN_DONE(funcctx);
561  }
562 }
#define TRUE
Definition: dbfopen.c:169
#define FALSE
Definition: dbfopen.c:168
rt_errorstate rt_band_get_pixel(rt_band band, int x, int y, double *value, int *nodata)
Get pixel value.
Definition: rt_band.c:1221
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition: rt_raster.c:82
int rt_band_get_isnodata_flag(rt_band band)
Get isnodata flag value.
Definition: rt_band.c:714
int rt_raster_has_band(rt_raster raster, int nband)
Return TRUE if the raster has a band of this number.
Definition: rt_raster.c:1347
@ ES_NONE
Definition: librtcore.h:180
uint16_t rt_raster_get_num_bands(rt_raster raster)
Definition: rt_raster.c:372
uint16_t rt_raster_get_height(rt_raster raster)
Definition: rt_raster.c:129
uint16_t rt_raster_get_width(rt_raster raster)
Definition: rt_raster.c:121
int rt_band_clamped_value_is_nodata(rt_band band, double val)
Compare clamped value to band's clamped NODATA value.
Definition: rt_band.c:1798
rt_raster rt_raster_deserialize(void *serialized, int header_only)
Return a raster from a serialized form.
Definition: rt_serialize.c:725
int rt_raster_is_empty(rt_raster raster)
Return TRUE if the raster is empty.
Definition: rt_raster.c:1334
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
Definition: rt_raster.c:381
band
Definition: ovdump.py:57
nband
Definition: pixval.py:52
raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
Definition: rtrowdump.py:121
static void rtpg_dumpvalues_arg_destroy(rtpg_dumpvalues_arg arg)
Definition: rtpg_pixel.c:173
static rtpg_dumpvalues_arg rtpg_dumpvalues_arg_init()
Definition: rtpg_pixel.c:153
#define VALUES_LENGTH
Definition: rtpg_pixel.c:1606
#define POSTGIS_RT_DEBUG(level, msg)
Definition: rtpostgis.h:61
#define POSTGIS_RT_DEBUGF(level, msg,...)
Definition: rtpostgis.h:65
Struct definitions.
Definition: librtcore.h:2250

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, 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, VALUES_LENGTH, pixval::x, and pixval::y.

Here is the call graph for this function: