PostGIS  3.4.0dev-r@@SVN_REVISION@@

◆ RASTER_dumpValues()

Datum RASTER_dumpValues ( PG_FUNCTION_ARGS  )

Definition at line 402 of file rtpg_pixel.c.

403 {
404  FuncCallContext *funcctx;
405  TupleDesc tupdesc;
406  int call_cntr;
407  int max_calls;
408  int i = 0;
409  int x = 0;
410  int y = 0;
411  int z = 0;
412 
413  int16 typlen;
414  bool typbyval;
415  char typalign;
416 
417  rtpg_dumpvalues_arg arg1 = NULL;
418  rtpg_dumpvalues_arg arg2 = NULL;
419 
420  /* stuff done only on the first call of the function */
421  if (SRF_IS_FIRSTCALL()) {
422  MemoryContext oldcontext;
423  rt_pgraster *pgraster = NULL;
424  rt_raster raster = NULL;
425  rt_band band = NULL;
426  int numbands = 0;
427  int j = 0;
428  bool exclude_nodata_value = TRUE;
429 
430  ArrayType *array;
431  Oid etype;
432  Datum *e;
433  bool *nulls;
434 
435  double val = 0;
436  int isnodata = 0;
437 
438  POSTGIS_RT_DEBUG(2, "RASTER_dumpValues first call");
439 
440  /* create a function context for cross-call persistence */
441  funcctx = SRF_FIRSTCALL_INIT();
442 
443  /* switch to memory context appropriate for multiple function calls */
444  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
445 
446  /* Get input arguments */
447  if (PG_ARGISNULL(0)) {
448  MemoryContextSwitchTo(oldcontext);
449  SRF_RETURN_DONE(funcctx);
450  }
451  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
452 
453  raster = rt_raster_deserialize(pgraster, FALSE);
454  if (!raster) {
455  PG_FREE_IF_COPY(pgraster, 0);
456  ereport(ERROR, (
457  errcode(ERRCODE_OUT_OF_MEMORY),
458  errmsg("Could not deserialize raster")
459  ));
460  MemoryContextSwitchTo(oldcontext);
461  SRF_RETURN_DONE(funcctx);
462  }
463 
464  /* check that raster is not empty */
465  /*
466  if (rt_raster_is_empty(raster)) {
467  elog(NOTICE, "Raster provided is empty");
468  rt_raster_destroy(raster);
469  PG_FREE_IF_COPY(pgraster, 0);
470  MemoryContextSwitchTo(oldcontext);
471  SRF_RETURN_DONE(funcctx);
472  }
473  */
474 
475  /* raster has bands */
476  numbands = rt_raster_get_num_bands(raster);
477  if (!numbands) {
478  elog(NOTICE, "Raster provided has no bands");
480  PG_FREE_IF_COPY(pgraster, 0);
481  MemoryContextSwitchTo(oldcontext);
482  SRF_RETURN_DONE(funcctx);
483  }
484 
485  /* initialize arg1 */
486  arg1 = rtpg_dumpvalues_arg_init();
487  if (arg1 == NULL) {
489  PG_FREE_IF_COPY(pgraster, 0);
490  MemoryContextSwitchTo(oldcontext);
491  elog(ERROR, "RASTER_dumpValues: Could not initialize argument structure");
492  SRF_RETURN_DONE(funcctx);
493  }
494 
495  /* nband, array */
496  if (!PG_ARGISNULL(1)) {
497  array = PG_GETARG_ARRAYTYPE_P(1);
498  etype = ARR_ELEMTYPE(array);
499  get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
500 
501  switch (etype) {
502  case INT2OID:
503  case INT4OID:
504  break;
505  default:
508  PG_FREE_IF_COPY(pgraster, 0);
509  MemoryContextSwitchTo(oldcontext);
510  elog(ERROR, "RASTER_dumpValues: Invalid data type for band indexes");
511  SRF_RETURN_DONE(funcctx);
512  break;
513  }
514 
515  deconstruct_array(array, etype, typlen, typbyval, typalign, &e, &nulls, &(arg1->numbands));
516 
517  arg1->nbands = palloc(sizeof(int) * arg1->numbands);
518  if (arg1->nbands == NULL) {
521  PG_FREE_IF_COPY(pgraster, 0);
522  MemoryContextSwitchTo(oldcontext);
523  elog(ERROR, "RASTER_dumpValues: Could not allocate memory for band indexes");
524  SRF_RETURN_DONE(funcctx);
525  }
526 
527  for (i = 0, j = 0; i < arg1->numbands; i++) {
528  if (nulls[i]) continue;
529 
530  switch (etype) {
531  case INT2OID:
532  arg1->nbands[j] = DatumGetInt16(e[i]) - 1;
533  break;
534  case INT4OID:
535  arg1->nbands[j] = DatumGetInt32(e[i]) - 1;
536  break;
537  }
538 
539  j++;
540  }
541 
542  if (j < arg1->numbands) {
543  arg1->nbands = repalloc(arg1->nbands, sizeof(int) * j);
544  if (arg1->nbands == NULL) {
547  PG_FREE_IF_COPY(pgraster, 0);
548  MemoryContextSwitchTo(oldcontext);
549  elog(ERROR, "RASTER_dumpValues: Could not reallocate memory for band indexes");
550  SRF_RETURN_DONE(funcctx);
551  }
552 
553  arg1->numbands = j;
554  }
555 
556  /* validate nbands */
557  for (i = 0; i < arg1->numbands; i++) {
558  if (!rt_raster_has_band(raster, arg1->nbands[i])) {
559  elog(NOTICE, "Band at index %d not found in raster", arg1->nbands[i] + 1);
562  PG_FREE_IF_COPY(pgraster, 0);
563  MemoryContextSwitchTo(oldcontext);
564  SRF_RETURN_DONE(funcctx);
565  }
566  }
567 
568  }
569  /* no bands specified, return all bands */
570  else {
571  arg1->numbands = numbands;
572  arg1->nbands = palloc(sizeof(int) * arg1->numbands);
573 
574  if (arg1->nbands == NULL) {
577  PG_FREE_IF_COPY(pgraster, 0);
578  MemoryContextSwitchTo(oldcontext);
579  elog(ERROR, "RASTER_dumpValues: Could not allocate memory for band indexes");
580  SRF_RETURN_DONE(funcctx);
581  }
582 
583  for (i = 0; i < arg1->numbands; i++) {
584  arg1->nbands[i] = i;
585  POSTGIS_RT_DEBUGF(4, "arg1->nbands[%d] = %d", arg1->nbands[i], i);
586  }
587  }
588 
591 
592  /* exclude_nodata_value */
593  if (!PG_ARGISNULL(2))
594  exclude_nodata_value = PG_GETARG_BOOL(2);
595  POSTGIS_RT_DEBUGF(4, "exclude_nodata_value = %d", exclude_nodata_value);
596 
597  /* allocate memory for each band's values and nodata flags */
598  arg1->values = palloc(sizeof(Datum *) * arg1->numbands);
599  arg1->nodata = palloc(sizeof(bool *) * arg1->numbands);
600  if (arg1->values == NULL || arg1->nodata == NULL) {
603  PG_FREE_IF_COPY(pgraster, 0);
604  MemoryContextSwitchTo(oldcontext);
605  elog(ERROR, "RASTER_dumpValues: Could not allocate memory for pixel values");
606  SRF_RETURN_DONE(funcctx);
607  }
608  memset(arg1->values, 0, sizeof(Datum *) * arg1->numbands);
609  memset(arg1->nodata, 0, sizeof(bool *) * arg1->numbands);
610 
611  /* get each band and dump data */
612  for (z = 0; z < arg1->numbands; z++) {
613  /* shortcut if raster is empty */
615  break;
616 
617  band = rt_raster_get_band(raster, arg1->nbands[z]);
618  if (!band) {
619  int nband = arg1->nbands[z] + 1;
622  PG_FREE_IF_COPY(pgraster, 0);
623  MemoryContextSwitchTo(oldcontext);
624  elog(ERROR, "RASTER_dumpValues: Could not get band at index %d", nband);
625  SRF_RETURN_DONE(funcctx);
626  }
627 
628  /* allocate memory for values and nodata flags */
629  arg1->values[z] = palloc(sizeof(Datum) * arg1->rows * arg1->columns);
630  arg1->nodata[z] = palloc(sizeof(bool) * arg1->rows * arg1->columns);
631  if (arg1->values[z] == NULL || arg1->nodata[z] == NULL) {
634  PG_FREE_IF_COPY(pgraster, 0);
635  MemoryContextSwitchTo(oldcontext);
636  elog(ERROR, "RASTER_dumpValues: Could not allocate memory for pixel values");
637  SRF_RETURN_DONE(funcctx);
638  }
639  memset(arg1->values[z], 0, sizeof(Datum) * arg1->rows * arg1->columns);
640  memset(arg1->nodata[z], 0, sizeof(bool) * arg1->rows * arg1->columns);
641 
642  i = 0;
643 
644  /* shortcut if band is NODATA */
646  for (i = (arg1->rows * arg1->columns) - 1; i >= 0; i--)
647  arg1->nodata[z][i] = TRUE;
648  continue;
649  }
650 
651  for (y = 0; y < arg1->rows; y++) {
652  for (x = 0; x < arg1->columns; x++) {
653  /* get pixel */
654  if (rt_band_get_pixel(band, x, y, &val, &isnodata) != ES_NONE) {
655  int nband = arg1->nbands[z] + 1;
658  PG_FREE_IF_COPY(pgraster, 0);
659  MemoryContextSwitchTo(oldcontext);
660  elog(ERROR, "RASTER_dumpValues: Could not pixel (%d, %d) of band %d", x, y, nband);
661  SRF_RETURN_DONE(funcctx);
662  }
663 
664  arg1->values[z][i] = Float8GetDatum(val);
665  POSTGIS_RT_DEBUGF(5, "arg1->values[z][i] = %f", DatumGetFloat8(arg1->values[z][i]));
666  POSTGIS_RT_DEBUGF(5, "clamped is?: %d", rt_band_clamped_value_is_nodata(band, val));
667 
668  if (exclude_nodata_value && isnodata) {
669  arg1->nodata[z][i] = TRUE;
670  POSTGIS_RT_DEBUG(5, "nodata = 1");
671  }
672  else
673  POSTGIS_RT_DEBUG(5, "nodata = 0");
674 
675  i++;
676  }
677  }
678  }
679 
680  /* cleanup */
682  PG_FREE_IF_COPY(pgraster, 0);
683 
684  /* Store needed information */
685  funcctx->user_fctx = arg1;
686 
687  /* total number of tuples to be returned */
688  funcctx->max_calls = arg1->numbands;
689 
690  /* Build a tuple descriptor for our result type */
691  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
692  MemoryContextSwitchTo(oldcontext);
693  ereport(ERROR, (
694  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
695  errmsg(
696  "function returning record called in context "
697  "that cannot accept type record"
698  )
699  ));
700  }
701 
702  BlessTupleDesc(tupdesc);
703  funcctx->tuple_desc = tupdesc;
704 
705  MemoryContextSwitchTo(oldcontext);
706  }
707 
708  /* stuff done on every call of the function */
709  funcctx = SRF_PERCALL_SETUP();
710 
711  call_cntr = funcctx->call_cntr;
712  max_calls = funcctx->max_calls;
713  tupdesc = funcctx->tuple_desc;
714  arg2 = funcctx->user_fctx;
715 
716  /* do when there is more left to send */
717  if (call_cntr < max_calls) {
718  Datum values[VALUES_LENGTH];
719  bool nulls[VALUES_LENGTH];
720  HeapTuple tuple;
721  Datum result;
722  ArrayType *mdValues = NULL;
723  int ndim = 2;
724  int dim[2] = {arg2->rows, arg2->columns};
725  int lbound[2] = {1, 1};
726 
727  POSTGIS_RT_DEBUGF(3, "call number %d", call_cntr);
728  POSTGIS_RT_DEBUGF(4, "dim = %d, %d", dim[0], dim[1]);
729 
730  memset(nulls, FALSE, sizeof(bool) * VALUES_LENGTH);
731 
732  values[0] = Int32GetDatum(arg2->nbands[call_cntr] + 1);
733 
734  /* info about the type of item in the multi-dimensional array (float8). */
735  get_typlenbyvalalign(FLOAT8OID, &typlen, &typbyval, &typalign);
736 
737  /* if values is NULL, return empty array */
738  if (arg2->values[call_cntr] == NULL)
739  ndim = 0;
740 
741  /* assemble 3-dimension array of values */
742  mdValues = construct_md_array(
743  arg2->values[call_cntr], arg2->nodata[call_cntr],
744  ndim, dim, lbound,
745  FLOAT8OID,
746  typlen, typbyval, typalign
747  );
748  values[1] = PointerGetDatum(mdValues);
749 
750  /* build a tuple and datum */
751  tuple = heap_form_tuple(tupdesc, values, nulls);
752  result = HeapTupleGetDatum(tuple);
753 
754  SRF_RETURN_NEXT(funcctx, result);
755  }
756  /* do when there is no more left */
757  else {
759  SRF_RETURN_DONE(funcctx);
760  }
761 }
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition: cu_print.c:262
#define TRUE
Definition: dbfopen.c:73
#define FALSE
Definition: dbfopen.c:72
rt_errorstate rt_band_get_pixel(rt_band band, int x, int y, double *value, int *nodata)
Get pixel value.
Definition: rt_band.c:1376
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition: rt_raster.c:86
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:1375
@ ES_NONE
Definition: librtcore.h:182
uint16_t rt_raster_get_num_bands(rt_raster raster)
Definition: rt_raster.c:376
uint16_t rt_raster_get_height(rt_raster raster)
Definition: rt_raster.c:133
uint16_t rt_raster_get_width(rt_raster raster)
Definition: rt_raster.c:125
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:1955
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:1362
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
Definition: rt_raster.c:385
band
Definition: ovdump.py:58
nband
Definition: pixval.py:53
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:372
static rtpg_dumpvalues_arg rtpg_dumpvalues_arg_init()
Definition: rtpg_pixel.c:352
#define VALUES_LENGTH
Definition: rtpg_pixel.c:1811
#define POSTGIS_RT_DEBUG(level, msg)
Definition: rtpostgis.h:65
#define POSTGIS_RT_DEBUGF(level, msg,...)
Definition: rtpostgis.h:69
Struct definitions.
Definition: librtcore.h:2403

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

Here is the call graph for this function: